[Bug 256410] pf: Add pf_default_rules option
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 256410] pf: Add pf_default_rules option"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 256410] pf: Add pf_default_rules option"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 256410] pf: Add pf_default_rules option"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 256410] pf: Add pf_default_rules option"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 256410] pf: Add pf_default_rules option"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 04 Jun 2021 09:53:17 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=256410 Bug ID: 256410 Summary: pf: Add pf_default_rules option Product: Base System Version: Unspecified Hardware: amd64 OS: Any Status: New Severity: Affects Some People Priority: --- Component: misc Assignee: bugs@FreeBSD.org Reporter: thomas@gibfest.dk Created attachment 225540 --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=225540&action=edit The patch for /etc/rc.d/pf and /etc/defaults/rc.conf Out of the three firewalls in FreeBSD pf is the only one without a way to make it default to deny everything: - IPFW has "65535 deny ip from any to any" unless IPFIREWALL_DEFAULT_TO_ACCEPT is set. - ipfilter has something called IPFILTER_DEFAULT_BLOCK, I think. I don't really know anything about ipfilter. With pf, if no rules are loaded all traffic is permitted. This can be considered a feature or a problem, recently it was a very big problem in my end. I propose the attached patch for /etc/rc.d/pf and a couple of new rc.conf variables pf_default_rules_enable and pf_default_rules to improve this situation. The patch simply checks the exit code of the pfctl command which loads the pf.conf ruleset, and if the exit code is 1 and pf_default_rules_enable is set to YES, then it loads the rules in pf_default_rules, which defaults to a single rule: "block drop log all". BACKGROUND: A little backstory might help clear up why I think this is a valuable and neccesary change. We (our company) had ended up with a pf.conf with a typo in it. The typo was that the leading "$" sign of a macro was missing. This makes pf treat it as a hostname instead of a macro, so it does a DNS lookup to process the firewall rule. The typo could have been a missing quote or something else too, the central point is the pf.conf was invalid, and it had been missed (humans being human and all that). The server in question was then rebooted, and suddently no firewall rules were loaded, permitting all traffic to the networks behind it, leading to some bad times at the office before it was discovered. In the postmortem clean-up it was determined that since /etc/rc.d/pf had failed to load the ruleset during bootup, and there being no "default block functionality", there was 0 rules loaded so it of course permitted everything. On these particular firewall machines it would have been MUCH better to have a non-functional firewall than a fully open one. YMMV, and the default in my patch is to keep the status quo, of course. With this patch and pf_default_rules_enable set to YES I would have discovered the issue much sooner and with no security incidents, which is vastly preferable in this situation. THE PATCH: Mostly it is just a new "if" block around the pfctl -f call inside pf_start(). I included some warnings (for both cases) while here. The only files touched are /etc/rc.d/pf and /etc/defaults/rc.conf. EXAMPLE: Note: All of these examples are with the attached patch applied. I made two simple pf.conf files where one has small but significant typo: [tykling@nuc2 ~]$ cat /etc/pf.conf foo="192.0.2.42" pass in quick on em0 from any to $foo [tykling@nuc2 ~]$ cat /etc/pf-typo.conf foo="192.0.2.42" pass in quick on em0 from any to foo [tykling@nuc2 ~]$ Note how "foo" is missing the leading $ sign meaning pf interprets it as a hostname, which can't be resolved in this case. First the default behaviour with no changes in rc.conf and a valid ruleset: [tykling@nuc2 ~]$ sudo sysrc pf_default_rules_enable pf_default_rules_enable: NO [tykling@nuc2 ~]$ sudo sysrc pf_default_rules pf_default_rules: block drop log all [tykling@nuc2 ~]$ sysrc pf_rules pf_rules: /etc/pf.conf [tykling@nuc2 ~]$ sudo service pf restart Password: Enabling pf. [tykling@nuc2 ~]$ sudo pfctl -s rules | wc -l 1 [tykling@nuc2 ~]$ sudo pfctl -s rules pass in quick on em0 inet from any to 192.0.2.42 flags S/SA keep state [tykling@nuc2 ~]$ All is well, it loaded the one rule in the ruleset. Now an example with an invalid ruleset, still with the above defaults in place: [tykling@nuc2 ~]$ sudo service pf restart Disabling pf. Enabling pfno IP address found for foo /etc/pf-typo.conf:2: could not parse host specification pfctl: Syntax error in config file: pf rules not loaded /etc/rc.d/pf: WARNING: Unable to load pf.conf, and pf_default_rules_enable is NO. /etc/rc.d/pf: WARNING: No pf rules are loaded, this means all traffic is permitted. . [tykling@nuc2 ~]$ sudo pfctl -s rules [tykling@nuc2 ~]$ The behaviour is the same as always, but a couple of new warn() calls informs the admin about what happened so they might spot it in /var/log/messages. Now the same setup but with the new feature enabled: [tykling@nuc2 ~]$ sudo sysrc pf_default_rules_enable="YES" pf_default_rules_enable: NO -> YES [tykling@nuc2 ~]$ The valid ruleset behaves as always: [tykling@nuc2 ~]$ sudo sysrc pf_rules="/etc/pf.conf" pf_rules: /etc/pf.conf -> /etc/pf.conf [tykling@nuc2 ~]$ sudo service pf restart Disabling pf. Enabling pf. [tykling@nuc2 ~]$ sudo pfctl -s rules | wc -l 1 [tykling@nuc2 ~]$ With the invalid ruleset the pf_default_rules are loaded: [tykling@nuc2 ~]$ sudo sysrc pf_default_rules_enable="YES" pf_default_rules_enable: NO -> YES [tykling@nuc2 ~]$ sudo service pf restart Disabling pf. Enabling pfno IP address found for foo /etc/pf-typo.conf:2: could not parse host specification pfctl: Syntax error in config file: pf rules not loaded /etc/rc.d/pf: WARNING: Unable to load pf.conf, and pf_default_rules_enable is set to YES. /etc/rc.d/pf: WARNING: Loading pf_default_rules: block drop log all . [tykling@nuc2 ~]$ sudo pfctl -s rules block drop log all [tykling@nuc2 ~]$ Say I wanted a way in, a management backdoor in case this happens, I could for example choose to pass traffic on a management interface only: [tykling@nuc2 ~]$ sudo sysrc pf_default_rules pf_default_rules: block drop log all\npass quick on em0 [tykling@nuc2 ~]$ sudo service pf restart Enabling pfno IP address found for foo /etc/pf-typo.conf:2: could not parse host specification pfctl: Syntax error in config file: pf rules not loaded /etc/rc.d/pf: WARNING: Unable to load pf.conf, and pf_default_rules_enable is set to YES. /etc/rc.d/pf: WARNING: Loading pf_default_rules: block drop log all\npass quick on em0 . [tykling@nuc2 ~]$ sudo pfctl -s rules block drop log all pass quick on em0 all flags S/SA keep state [tykling@nuc2 ~]$ I guess that is all. I hope it made sense and that the feature will find its way into FreeBSD. I know I will be running with it locally until such a time. Apologies in advance if I messed up the patch, I don't do this often, and I don't have a phabricator account (yet). Have a lovely weekend :) ps. I know about it being FreeBSDs job to ensure a reliable delivery of bullet from gun to foot. But I feel like an exception is warranted here, especially given that the two other firewalls have similar functionality. -- You are receiving this mail because: You are the assignee for the bug.