If you set the protocol to "any", the resulting iptables rule ignores the portspec

(Edit: this example makes reference to DHCP, because that was what I was looking at when I noticed it. Please ignore whether the rule makes any sense in the context of DHCP.)

I was slightly confused by this at first, but it makes sense once the mapping from the luci gui to the iptables rules is considered, but I think it's potentially opens the firewall more than intended.

If you create a rule like this;
Screenshot_2018-06-03_03-52-14

It generates /etc/config/firewall code like this...

config rule
        option target 'ACCEPT'
        option dest_port '67'
        option name 'DHCP-DISCOVERY'
        option family 'ipv4'
        option src '*'
        option src_port '68'
        option proto 'udp'

The resulting iptables rule is like this;

3 972 ACCEPT udp -- any any anywhere anywhere udp spt:bootpc dpt:bootps /* !fw3: DHCP-DISCOVERY */

All good.

However if you go and set the rule to use the any protocol option like so;

Screenshot_2018-06-03_15-17-12

The result looks like it would apply some form of fairly restrictive port filter to the rule...

Screenshot_2018-06-03_03-54-48
It looks like it's going to be filtered on src and dest port;

The generated /etc/config/firewall still looks OK....

config rule
        option target 'ACCEPT'
        option dest_port '67'
        option name 'DHCP-DISCOVERY'
        option family 'ipv4'
        option src '*'
        option src_port '68'
        option proto 'all'

But the final rule created ignores the port spec, (which makes sense, because iptables would need need the protocol to be specified as TCP or UDP to do anything useful with the port options);

63 6174 ACCEPT all -- any any anywhere anywhere /* !fw3: DHCP-DISCOVERY */

However the thing to notice is that it's now opened everything from anywhere into the router... which might not be what was intended or expected..

Possible the port spec fields need to be grayed out if the any protocol is used...

When a device sends a DHCP Discovery request in order to get an IP from a router, it does so by sending it via the broadcast address (255.255.255.255) because it can't know what subnet block to contact.

  • With that being said, that rule isn't necessary.
    • All the default OpenWrt firewall rules aren't necessary, and seem to be a holdover from before Chaos Calmer
    • The only rule that could potentially be necessary is the ESP packet rule, which allows IPSec traffic for IPSec VPNs.

  • I personally always recommend removing all the default firewall rules (just the firewall rules [config rule]), as:
    1. They're not necessary
    2. They allow ICMP pings from WAN
    3. IGMP and ISAKMP protocols are only relevant to users utilizing those functions, and I don't understand what use case IGMP would be allowed over WAN for.

The point of the post, as I read it, was not to discuss the validity of the intent of the rule, but to highlight that a LuCI-generated rule that one might reasonably write caused a significant security problem.

I'd file a bug report and/or bring it to the attention of the dev mailing list.

As the OP points out, for someone familiar with the intricacies of packet matching, yes, in retrospect it "makes sense" as not all protocols have ports, so you can't match on them. However, this isn't obvious to the "home" user and probably should be better managed in the UI. I'd suggest staying away from the Linux-isms of ip and ip6 as, to a non-expert, ip might easily be taken to mean both IPv4 and IPv6 (which is often what one wants to use for "deny" rules).

Edit: to clarify that the issue relates to the disconnect between what might be expected, and the generated iptables configuration, in a way that results in a less secure ruleset.

Yeah, I noticed those rules seem a bit random. (it turned out that the problem I was trying to solve was related to a dodgy lan cable, and nothing to do with the firewall...)

The point of this post is more related to the fact that a /etc/config/firewall directive like this;

config rule
        option target 'ACCEPT'
        option dest_port '9999'
        option name 'an-example-rule'
        option family 'ipv4'
        option src '*'
        option src_port '8888'
        option proto 'all'

produces an iptables rule like this;

63 6174 ACCEPT all -- any any anywhere anywhere /* !fw3: an-example-rule */

which you will notice has ignored the port spec. (if you choose "TCP+UDP", it correctly creates 2 rules, one for each tcp and udp on the chosen port)

The gui entry for that appears at first sight to be more restrictive than the end result;

Screenshot_2018-06-03_15-39-42

DHCP packets are always UDP, and never TCP.

  • To understand why that rule is necessary, you're going to want to research how DHCP occurs

Most of the other protocols like ICMP and GRE have no concept of port numbers.

It's not a LuCI generated rule, but the default rule in /etc/config/firewall, included in every single buildbot image (buildroot images as well if not using a custom /etc/config/firewall), since at least Barrier Breaker.

Which rule are you refering to?

@tolland, I verify the bug/vulnerability exists exactly as you described - on OpenWrt 18.06-SNAPSHOT r6918-ff8bde5!!!

The following rule:

config rule
	option enabled '1'
	option target 'ACCEPT'
	option proto 'all'
	option dest_port '33333'
	option name 'test'
	option family 'ipv4'
	option src '*'
	option src_port '44444'

Produces:

0 0.00 B ACCEPT all * * 0.0.0.0/0 0.0.0.0/0 /* !fw3: test */

(EDIT: Used magical regular powers to move this thread to Developers' section.)

Please post the output of: fw3 print | grep ACCEPT

  • Ensure it's sanitized of any custom port numbers for SSH, VPNs, etc.

No problem, it's just my test router (Linksys WRTSL54GS) with default (firewall) configs. Basically, I only added the test rule:

root@OpenWrt:~# fw3 print | grep ACCEPT
Warning: Unable to locate ipset utility, disabling ipset support
iptables -t filter -P INPUT ACCEPT
iptables -t filter -P OUTPUT ACCEPT
iptables -t filter -N zone_lan_src_ACCEPT
iptables -t filter -N zone_lan_dest_ACCEPT
iptables -t filter -N zone_wan_dest_ACCEPT
iptables -t filter -A INPUT -i lo -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A OUTPUT -o lo -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A zone_wan_input -p udp -m udp --dport 68 -m comment --comment "!fw3: Allow-DHCP-Renew" -j ACCEPT
iptables -t filter -A zone_wan_input -p icmp -m icmp --icmp-type 8 -m comment --comment "!fw3: Allow-Ping" -j ACCEPT
iptables -t filter -A zone_wan_input -p 2 -m comment --comment "!fw3: Allow-IGMP" -j ACCEPT
iptables -t filter -A zone_wan_forward -p esp -m comment --comment "!fw3: Allow-IPSec-ESP" -j zone_lan_dest_ACCEPT
iptables -t filter -A zone_wan_forward -p udp -m udp --dport 500 -m comment --comment "!fw3: Allow-ISAKMP" -j zone_lan_dest_ACCEPT
iptables -t filter -A INPUT -m comment --comment "!fw3: test" -j ACCEPT
iptables -t filter -A zone_lan_forward -m comment --comment "!fw3: Zone lan to wan forwarding policy" -j zone_wan_dest_ACCEPT
iptables -t filter -A zone_lan_input -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port redirections" -j ACCEPT
iptables -t filter -A zone_lan_forward -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port forwards" -j ACCEPT
iptables -t filter -A zone_lan_input -m comment --comment "!fw3" -j zone_lan_src_ACCEPT
iptables -t filter -A zone_lan_forward -m comment --comment "!fw3" -j zone_lan_dest_ACCEPT
iptables -t filter -A zone_lan_output -m comment --comment "!fw3" -j zone_lan_dest_ACCEPT
iptables -t filter -D zone_lan_src_ACCEPT -i br-lan -m conntrack --ctstate NEW,UNTRACKED -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A zone_lan_src_ACCEPT -i br-lan -m conntrack --ctstate NEW,UNTRACKED -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -D zone_lan_dest_ACCEPT -o br-lan -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A zone_lan_dest_ACCEPT -o br-lan -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A zone_wan_input -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port redirections" -j ACCEPT
iptables -t filter -A zone_wan_forward -m conntrack --ctstate DNAT -m comment --comment "!fw3: Accept port forwards" -j ACCEPT
iptables -t filter -A zone_wan_output -m comment --comment "!fw3" -j zone_wan_dest_ACCEPT
iptables -t filter -D zone_wan_dest_ACCEPT -o eth1 -m conntrack --ctstate INVALID -m comment --comment "!fw3: Prevent NAT leakage" -j DROP
iptables -t filter -A zone_wan_dest_ACCEPT -o eth1 -m conntrack --ctstate INVALID -m comment --comment "!fw3: Prevent NAT leakage" -j DROP
iptables -t filter -D zone_wan_dest_ACCEPT -o eth1 -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A zone_wan_dest_ACCEPT -o eth1 -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -D zone_wan_dest_ACCEPT -o eth1 -m conntrack --ctstate INVALID -m comment --comment "!fw3: Prevent NAT leakage" -j DROP
iptables -t filter -A zone_wan_dest_ACCEPT -o eth1 -m conntrack --ctstate INVALID -m comment --comment "!fw3: Prevent NAT leakage" -j DROP
iptables -t filter -D zone_wan_dest_ACCEPT -o eth1 -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A zone_wan_dest_ACCEPT -o eth1 -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -D zone_wan_dest_ACCEPT -o wlan0 -m conntrack --ctstate INVALID -m comment --comment "!fw3: Prevent NAT leakage" -j DROP
iptables -t filter -A zone_wan_dest_ACCEPT -o wlan0 -m conntrack --ctstate INVALID -m comment --comment "!fw3: Prevent NAT leakage" -j DROP
iptables -t filter -D zone_wan_dest_ACCEPT -o wlan0 -m comment --comment "!fw3" -j ACCEPT
iptables -t filter -A zone_wan_dest_ACCEPT -o wlan0 -m comment --comment "!fw3" -j ACCEPT

The written description is as follows:

A scripting error that parses the config at /etc/config/firewall will improperly produce an iptables INPUT ACCEPT rule for ANY protocol, from ANY source, to ANY destination - if a rule is created using the ALL protocol and specifying ports. Namely:


config rule
	option enabled '1'
	option target 'ACCEPT'
	option proto 'all'
	option dest_port '33333'
	option name 'test'
	option family 'ipv4'
	option src '*'
	option src_port '44444'

Will produce:

As @tolland states:

Those more savvy in networking and the OpenWrt manual should realize:

But the problem arises if someone is unfamiliar or inadvertently makes such a rule; they have unwittingly exposed their router on all ports and protocols.

1 Like

I also just observed that doing so with a Port Forward results silently in no rule(s) being created; but displaying TCP+UDP on LuCI. Specifying TCP+UDP creates the two rules as expected.

Why are these defaults included in the first place? Wouldn't it be better to have the device as locked down as possible in its default state?

ICMP messages are definitely nice to accept, in order to keep stuff like MTU path discovery working, right?

@Mushoz, I should be clear, the default rules are not causing the bug that the OP discovered.

Some rules are needed in a default configuration; and if some were not included, casual users may actually think they bricked their router. In essence, even with a wired client, I think it's wise for WAN to receive it's DHCP request, be ping-able; and be open on LAN. I close Ping on my WAN; but even some protocols and providers require I accept it from them.

For example: Many debates about the "usefulness" and "perceived vulnerabilities" of Ping arise over the years, in many forums, regarding many topics; nonetheless, it's assumed by RFC that an online host will respond to it.

From: https://tools.ietf.org/html/rfc1122

At present, pinging (i.e., using ICMP Echo messages) is the mechanism for gateway probing when absolutely required.

So it looks like the luci model/views handle dependent fields pretty well. So something like this can be used to mask out fields combinations that would produce nonsensical rules;
https://github.com/limepepper/luci/commit/afe0fecb6863afab5f215206ff439ce31240d0a0

So that will hide the port options if anything other than TCP, UDP or TCP+UDP is selected from the gui as the protocol... I've not had much of a chance to test it.... I will update when I have... seems to work ok.

2 Likes