Date: Sun, 4 Sep 2022 19:18:02 -0700 From: "Dan Mahoney (Ports)" <freebsd@gushi.org> To: Ian Smith <smithi@nimnet.asn.au> Cc: questions@freebsd.org, kpn@neutralgood.org Subject: Re: Firewall rules in a directory Message-ID: <9BFB27DC-BA45-49B5-8EAD-B5BE7BC14E20@gushi.org> In-Reply-To: <DED6C218-0517-4A0D-8C7A-1FDBFFC84A3D@nimnet.asn.au> References: <3FAB82EC-2C82-4201-AA47-B1AA92B89677@gushi.org> <D666503D-E5E2-4B6D-A960-A362EEFE6F95@gushi.org> <DED6C218-0517-4A0D-8C7A-1FDBFFC84A3D@nimnet.asn.au>
next in thread | previous in thread | raw e-mail | index | archive | help
> On Aug 31, 2022, at 10:47 AM, Ian Smith <smithi@nimnet.asn.au> wrote: >=20 > On 30 August 2022 2:40:34 pm AEST, "Dan Mahoney (Ports)" = <freebsd@gushi.org> wrote: >> Note, this wasn=E2=80=99t intended to be =E2=80=9Chere=E2=80=99s a = diff, please put it in=E2=80=9D, >> just an illustration of how trivial an addition it is. >>=20 >>> On Aug 29, 2022, at 9:36 PM, Dan Mahoney (Ports) >> <freebsd@gushi.org> wrote: >>>=20 >>> All, >>>=20 >>> At the dayjob, we=E2=80=99ve taken to putting our ipfw rules into a >> directory using rcorder=E2=80=99able files. This way, each of our = puppet >> manifests can drop its own rules into place without having to manage >> a monolithic file. >>>=20 >>> It=E2=80=99s a simple patch to rc.firewall, where if you set = firewall_type >> to a file, it just runs it, but if it=E2=80=99s a directory, it would = treat >> it as such: >>>=20 >>> *) >>> if [ -r "${firewall_type}" ]; then >>> if [ -f "${firewall_type}" ]; then >>> ${fwcmd} ${firewall_flags} ${firewall_type} >>> else >>> if [ -d "${firewall_type}" ]; then >>> for fwfile in `rcorder $firewall_type/*` >>> do >>> ipfw -q $fwfile; >>> done >>> fi >>> fi >>>=20 >>> Is there a possibility of getting this into base? >>>=20 >>> -Dan >=20 > Getting code into rc.firewall has proven difficult over the years, for = me impossible. It even took julian@ a couple of years to get a sensible = use of tables into firewall_type 'simple' - but things may have changed. >=20 > I've tried rendering your code into the usual format below, saving a = level of indenting with 'elif', and noting that '-q' and path is = included in ${fwcmd} earlier in rc.firewall. >=20 > If it's really intended to launch multiple instances of ipfw, it may = win more favour - as a bug / feature request as Kevin suggests - if = you're sure how things like 'service ipfw status' or 'restart' handle = them in /etc/rc.d/ipfw? >=20 > Good Luck, Ian >=20 > <code> > *) > if [ -r "${firewall_type}" ]; then > if [ -f "${firewall_type}" ]; then > ${fwcmd} ${firewall_flags} ${firewall_type} > elif [ -d "${firewall_type}" ]; then > for fwfile in `rcorder ${firewall_type}/*` > do > ${fwcmd} ${firewall_flags} = ${fwfile} > done > fi > fi > ;; > </code> So, right now, there are two knobs you can tweak in /etc/rc.conf -- = firewall_type, and firewall_script. Firewall_script defaults to = /etc/rc.firewall which understands things like "open" or "client" or = "unknown", or a file. The last bit of the stock rc.firewall looks like = this: [Cc][Ll][Oo][Ss][Ee][Dd]) ${fwcmd} add 65000 deny ip from any to any ;; [Uu][Nn][Kk][Nn][Oo][Ww][Nn]) ;; *) if [ -r "${firewall_type}" ]; then ${fwcmd} ${firewall_flags} ${firewall_type} fi ;; esac Two problems there. 1) -r only checks for readability, not for it being = an actual file. and 2) For us, we *like* it being a directory. Here's an output of rcorder: rcorder /etc/ipfw.d/* /etc/ipfw.d/setup /etc/ipfw.d/production_networks /etc/ipfw.d/production_static /etc/ipfw.d/routing /etc/ipfw.d/services /etc/ipfw.d/snmp_agent /etc/ipfw.d/ssh_service /etc/ipfw.d/tftp_service /etc/ipfw.d/mosh_service /etc/ipfw.d/node_exporter_agent /etc/ipfw.d/nrpe_agent /etc/ipfw.d/ssh_vpn /etc/ipfw.d/outbound /etc/ipfw.d/local /etc/ipfw.d/krb5_client /etc/ipfw.d/dns_client /etc/ipfw.d/syslog_client /etc/ipfw.d/ntp_client /etc/ipfw.d/final And...as an example, here's some of /etc/ipfw.d/setup (note the PROVIDE = and BEFORE entries at top, like rcorder wants). # # PROVIDE: setup blocked bogons # BEFORE: services routing outbound final # # remove all existing tables table all destroy table blocked create # standard (non-service specific) tables table bogons create table bogons add 0.0.0.0/8 table bogons add 10.0.0.0/8 table bogons add 172.12.0.0/12 table bogons add 192.168.0.0/16 table bogons add 169.254.0.0/16 table bogons add 240.0.0.0/4 # permit existing TCP sessions add allow tcp from any to any established # permit existing stateful traffic add check-state :default // permit stateful traffic # permit internal loopback traffic add allow ip from any to any via lo0 add allow ip from any to any via lo1 # deny directed loopback traffic add deny ip from any to 127.0.0.0/8 in add deny ip from any to ::/64 in # deny unexpected sources add deny ip from table(bogons) to me in // unexpected sources # deny explicitly disabled (non-persistent) sources add deny ip from table(blocked) to me in // emergency (non-persistent) = blocklist # allow bsd-standard-port traceroutes add allow udp from me to any 33434-33600 // traceroute in add allow udp from any to me 33434-33600 // traceroute out # moderately permissive ICMPv4 add allow icmp from any to any icmptypes 0,3,8,11,13,14 // safe ICMPv4 # link-local ICMPv6 (RS, RA, NS, NA) - per FreeBSD standard rules add allow ipv6-icmp from :: to fe80::/10 // ICMPv6 DAD add allow ipv6-icmp from fe80::/10 to fe80::/10 // ICMPv6 NDP add allow ipv6-icmp from fe80::/10 to ff02::/16 // ICMPv6 NDP add allow ipv6-icmp from any to any icmp6types 1,2,3,128,129,135,136 // = safe ICMPv6 .... And here's a service entry... more /etc/ipfw.d/ssh_service # REQUIRE: services # PROVIDE: ssh_service ssh_clients # BEFORE: outbound table ssh_clients create table ssh_clients add 1.2.3.4 table ssh_clients add 2001:dead:beef:cafe::d00d add allow tcp from table(ssh_clients) to me 22 in setup // = inbound SSH =3D=3D Also unique to our setup: the "local" script is created by puppet but = not managed by it, so if you need to drop an emergency override in there = for something (i.e. block an attacker, or open a port that you haven't = added to automation yet, add a counter to debug an issue, you can, = quickly). Some of our scripts are placeholders, just existing as a no-op to anchor = things like BEFORE. If people wanted things to put in /usr/share/examples (say = /usr/share/examples/ipfw/client, or /usr/share/examples/ipfw/closed?) = that mimic'd the main setup, I'd be happy to contribute them. (I'm also not thrilled with the fact that the stock firewall script adds = rules before it determines what kind of firewall you want, and then = applies your rules...that could perhaps be a different bug though). If there's a diffferent list I should be posting this to, let me know. -Dan=
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9BFB27DC-BA45-49B5-8EAD-B5BE7BC14E20>