Firewall and iptables and default policy

I had an issue with acme, but thought it was a firewall issue (it wasn't) so I spent time today going through the actual iptables that are generated in OpenWRT. Can someone give me a sanity check? Running 18.06.4 on a Linksys WRT1900ACS with luci.

Here's what I think I know:

The luci interface firewall option configures something called fw3, which writes config to /etc/config/firewall, which something during boot turns into iptables/netfilter entries. So if I look at iptables directly I see what's generated. These are supplemented by things I can add to the custom rules section (I have a few for openvpn).

So I went through the generated iptables, and it made sense, but I noticed that INPUT and OUTPUT both had a default policy of ACCEPT, which surprised me especially for INPUT.

So I put a logging statement on the fall-through for INPUT and got a ton of stuff, for example DNS queries, my own SSH session. The path it builds (INPUT -> zone_lan_input -> input_lan_rule (empty) -> zone_lan_src_ACCEPT misses a lot (namely anything not ctstate=new/untracked), falls through and is accepted anyway.

Did I break this in some fashion, or is this the default?

I see a GUI option to reset this (at least I think it will) but then worry that I will be missing explicit rules for basic stuff, like SSH access, HTTP access, DNS, etc. I guess I had assumed installing these features somehow were setting up rules, but it looks like they fall through under the default policy for INPUT. I can see interface limits on SSH for example, but have no idea what else is getting through (though if I dig a lot in this log I can find it).

Can someone speak to the philosophy of how this normally works?

For a secure system, should I have started by changing all the ACCEPTS to DROP and then allowing what I can't make work? (Or did I actually somehow change it to ACCEPT myself)?

Sadly I'm more of a Cisco ASA person, so can somewhat get by with IPTABLES, but only vaguely starting to understand this process (what's the proper name, "fw3"?), so apologies if this is all fairly obvious.

Incidentally I looked at this page:

https://openwrt.org/docs/guide-user/firewall/firewall_configuration

which I'm hoping is the most recent, and got confused down at the bottom where it says that the "defaults" section as accept for input/output, but then right under it says the default for all is reject, so short of wiping my system to defaults I'm not quite sure how to tell what the "default" really is.

1 Like

This is pretty much it in a nutshell... if it's from the LAN and new or untracked just let it through...

Cisco philosophy is traditionally a "permissive" based ruleset... with openwrt it's "zones" are fundamentally by default restrictive ( allow unless specified ) at the intra-zone level. If traffic has no intra-zone default matches ( leaf chain flow inclusive as you've discussed above )... that's when the global default permissive policy ( disallow everything ) comes into play...

The trick is to adopt the restrictive mindset ( what to block ) at a zone level, although technically what might make more sense given your background/goals is to restructure ( per-zone ) the individual rules so that the logic overall behaves more like what your familiar with.

The zone default policies ( not to be confused with the global default ) are more of a "fall through" and ACCEPT catches many people up Its structured this way for performance and simplified management. And switching to a default DENY zone stance is in effect asking the majority of users to manage more complex rulesets or encourage them to add insecure broad rules.

Thank you. One reason this came up is that I have numerous LAN zones that I want to start restricting (e.g. one for automation, one for video, etc.). I'm not sure that

with openwrt it's "zones" are fundamentally by default restrictive ( allow unless specified )

Applies with multiple inside zones, unless I somehow changed it, they appear to have been by default permissive between all inside zones. I think I can work those out fine. What's bothering me (as I may not have a good idea what is needed) is INPUT for accessing the router, notably as IPv6 is involved with its announcements, and ... well, whatever it is I don't know about.

I take it -j LOG with limit isn't available; I've crashed it several times trying to log all the traffic not explicitly handled. :frowning:

But I think I can keep working it that way, explicitly allowing things until my log is clean and then default to drop.

But at least I'm understanding. I'll try doing it in the gui first, and see what changes in IPTABLES. I don't really want to use IPTABLES so much as its output is more clear (at least to me).

Thank you.

1 Like

general logging sample ( basic and inefficient ) but shows enough to get started...

iptables -N mylog
################################################################################## LOGonlynewtcpconnections-reasonablelimit
#iptables -A mylog -p tcp --syn -m limit --limit 3/s --limit-burst 10 -j LOG
#iptables -A mylog -p tcp --syn -j LOG --log-prefix "mylog-tcp-new " --log-level $myloglevel
##    OPTIONAL depending on logic    ####       iptables -A mylog -p tcp -j RETURN
################################################################ SSH
#iptables -A mylog -p tcp -m tcp -s 0/0 --dport 22 -j RETURN
#iptables -A mylog -p tcp -m tcp -s 0/0 --sport 22 -j RETURN
################################################################ SSH-limited-wprefix
#iptables -A mylog -m limit --limit 1/min \
#	-p tcp -m tcp -s 0/0 --dport 22 -j LOG --log-prefix "mylog-ssh-dst " --log-level $myloglevel
#iptables -A mylog -m limit --limit 1/min \
#	-p tcp -m tcp -s 0/0 --sport 22 -j LOG --log-prefix "mylog-ssh-src " --log-level $myloglevel


################################################################ DHCP
#iptables -A mylog -p udp --dport 67:68 --sport 67:68 -j RETURN
#iptables -A mylog -p udp --dport 67:68 --sport 67:68 -j LOG --log-prefix "mylog-dhcp " --log-level $myloglevel

################################################################ ICMP
#iptables -A mylog -p tcp --syn -m limit --limit 5/s --limit-burst 11 -j ACCEPT
iptables -A mylog -m limit --limit 15/min \
	-p icmp -j LOG --log-prefix "mylog-icmp " --log-level $myloglevel

##################################################################################### FINAL LOGALLorRETURN
#iptables -A mylog -j LOG
#iptables -A mylog -j LOG --log-prefix "mylog-other " --log-level $myloglevel
iptables -A mylog -j RETURN

iptables -I input_rule 1 -j mylog
iptables -I forwarding_rule 1 -j mylog
iptables -I output_rule 1 -j mylog

You might use something like this but jump to it at the end/start of your chains etc. or munge it into a "log-drop" handler... i'm sure someone else can explain things better than I did... but I came from a background similar to yours so I needed to see it that way before I could half understand things... :female_detective:

Yeah, that could make sense ( had LAN <> WAN in mind at the time i.e. state-full natted )... in effect the ZONE<>ZONE gui "forwarding" construct implements the underlying rules/tables/jumplogix referred to... so most typical users would add a zone per network... then as a sane default enable intra-zone forwarding (allow) between all internal networks.

If you have a simple example, you can post an iptables-save ( using code tags ^ < / > ) and it might be an easier way to advise on where/how to best hook-in... ( the iptables -I rules in my example above are not ideal )

Ah, thank you, I was about to respond that limit didn't work, but I checked more carefully and I had screwed up the syntax, which is why I wasn't using it. Now that I have that, I think I'm golden. I thought it was a OpenWRT limitation.

Thank you.

1 Like