💾 Archived View for thrig.me › blog › 2024 › 05 › 01 › firewall-rules-etiquette.gmi captured on 2024-05-26 at 14:47:44. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-05-10)

-=-=-=-=-=-=-

Firewall Rules Etiquette

Firewalls may end up with, for one reason or many thousands of ongoing reasons, a "blacklist" or "violations" table. There are various advantages and drawbacks to blocking naughty IP addresses, even if only temporarily. A particular disadvantage is that your own presumably good addresses may accidentally or otherwise end up in the blacklist.

Hence it may be a good idea to either screen what gets added to the blacklists so they cannot include good IP addresses, or to have a distinct list of allowed hosts that is checked prior to the blacklist. In fact, it may be good to both have a list of good addresses in the firewall, and to screen additions to the badhosts list against the good addresses, and warn if something tries to add a known good host to a blacklist. This may be very important if an external blacklist is used: that external source could maliciously or accidentally add one of your good IP addresses and lock you out.

The rules here are for Packet Filter on OpenBSD.

    table <bad> persist file "/etc/badhosts"
    table <good> persist file "/etc/goodhosts"

    block drop on vio0 from <bad>
    pass in on $ext_if proto tcp from <good> to any port 22
    pass in on $ext_if proto udp from <good> to any port 4433
    ...

These rules allow connections from the good hosts before blocking anything from a bad host. There are alternate means of ensuring that certain addresses never end up in a blacklist, for example by turning off the firewall or allowing all traffic over a particular interface.

    set skip on lo
    pass quick on wg0

Still, one may want to throw an error should, say, 127.0.0.1 or some other good or unexpected address ever be considered for a bad hosts list. This is sort of like a cavalry brigade showing up for submarine duty: that does not make sense, block it and flag it for review. Usually you can find a library for this, though the "good" list may need to be more dynamic in some environments:

    #!/usr/bin/env perl
    # noblock.pl - example non-blocking of particular addresses
    use NetAddr::IP qw[:lower];
    my $addr = $ARGV[0];
    my $ip   = NetAddr::IP->new($addr) or die "unparseable '$addr'\n";
    for my $net (qw[127.0.0.0/8 fe80::/10 ::1]) {
        if ( $ip->within( NetAddr::IP->new($net) ) ) {
            die "will not blacklist $addr inside $net\n";
        }
    }
    system qw[echo would blacklist], $addr;

Invalid addresses are excluded as who know what a firewall will turn random text into: maybe the firewall throws an error, or maybe 0.0.0.0/0 gets banned, and I'd rather not risk the latter.

    $ perl noblock.pl cats
    unparseable 'cats'
    $ perl noblock.pl 127.254.85.83
    will not blacklist 127.254.85.83 inside 127.0.0.0/8
    $ perl noblock.pl 192.0.2.42
    would blacklist 192.0.2.42

Preserving access

One may also want to have multiple ways into the system—direct SSH, via wireguard, configuration management that uses some other protocol, console access, or the firewall could pull configuration from elsewhere. This may allow a system to be fixed even if the firewall or SSH breaks. On the other hand having too many ways in may be a gift to an attacker, especially if some not- or poorly-documented interface is left dangling around. Another trick here is to apply the new firewall rules with a 30 second timeout; if things break the old rules should be reverted to after a short period of time. However a rollback does not usually apply when random IP addresses are getting added to some blacklist or the other via log scanning or by other means.

P.S. Packet Filter is "last match wins, unless 'quick'", in the event you were wondering about the block appearing before the pass and the pass rule applying.