OpenBSD PacketFilter

The proposed way to ban IPs using openBSD pf uses one t_reaction table. We first need to create this table on our main /etc/pf.conf file.

table <t_reaction> persist

The IPs are banned on all ports, meaning banned IPs won't be able to connect on any service.

Start/Stop

There is no specific action taken on start. On stop, all IP address contained in 't_reaction' will be flushed

  start: [
  ],
  stop: [
    ['pfctl', '-t', 't_reaction', '-T',  'flush', '<ip>'],
  ],

Ban/Unban

Then, in reaction.conf file, we need to specify pfctl behaviour and alter ban and unban command

local iptables(args) = [ 'pfctl'] + args;
local banFor(time) = {
  ban: {
    cmd: ['pfctl', '-t', 't_reaction', '-T',  'add', '<ip>'],
  },
  unban: {
    after: time,
    cmd: ['pfctl', '-t', 't_reaction', '-T',  'del', '<ip>'],
  },
};

See how to merge different actions in JSONnet FAQ

Real-world example

local banFor(time) = {
  ban: {
    cmd: ['pfctl', '-t', 't_reaction', '-T',  'add', '<ip>'],
  },
  unban: {
    after: time,
    cmd: ['pfctl', '-t', 't_reaction', '-T',  'del', '<ip>'],
  },
};
{
  patterns: {
    ip: {
      regex: @'(?:(?:[ 0-9 ]{1,3}\.){3}[0-9]{1,3})|(?:[0-9a-fA-F:]{2,90})',
    },
  },
  start: [
  ],
  stop: [
    ['pfctl', '-t', 't_reaction', '-T',  'flush', '<ip>'],
  ],
  streams: {
    ssh: {
      cmd: [ 'tail', '-n0', '-f', '/var/log/authlog' ],
      filters: {
        failedlogin: {
          regex: [
            // Auth fail
            @'Failed password for invalid user .* from <ip>',
            // Client disconnects during authentication
            @'Disconnected from invalid user .* <ip>',
          ],  
          retry: 3,
          retryperiod: '6h',
          actions: banFor('48h'),
        },
      },
    },
  },
}