drop.xmlをPostgreSQLで管理する

スパム、つまり、/home/user/Maildir/.Junk/cur/に分類されたファイルの送信元IPアドレスと、/var/log/maillogに’authentication failed’が記録されたアクセス元IPアドレスを、それぞれ違うスクリプトでfirewalldのDROPゾーンに追加してるんだけど、これが遅い。遅いのはfirewall-cmdというか、Pythonで逐次投入しているのが主な原因なのだけど、auth failのルールを処理する時間がどんどん長くなって、systemd.pathでトリガーされるスパムの処理が衝突するようになった。

根本的に書き直そうということで、

  • スパムとauth failからIPアドレスを抽出する
  • IPアドレスをPostgreSQLに保存する
  • PostgreSQLから全IPアドレスを持ってくる
  • 古いルールを待避する
  • 新しいルールを書き出す(drop.xml)
  • firewalldとpodman networkをreloadする

ようにした。IPアドレスは/32なので、既存のネットワークに含まれていないかのチェックはPostgreSQLにやってもらうようにした。

def ips_to_pgsql(ips):
    with psycopg2.connect('dbname=postgres host=localhost user=postgres') as con:
        con.autocommit = True
        with con.cursor() as cur:
            query = "INSERT INTO drop_ips (ipaddr) SELECT '{}/32' WHERE NOT EXISTS (SELECT 1 FROM drop_ips WHERE '{}/32' <<= drop_ips.ipaddr)"
            for ip in ips:
                try:
                    cur.execute(query.format(ip, ip))
                except Exception as exc:
                    print(exc)
            query = "SELECT ipaddr FROM drop_ips ORDER BY ipaddr"
            try:
                cur.execute(query)
                ips = []
                for row in cur.fetchall():
                    ips.append(row[0])
                return ips
            except Exception as exc:
                print(exc)

追記:従来のスクリプトを実行すると数分かかっていたのが数秒で完了するようになった。

追記2:プライマリのPostgreSQLをセカンダリに同期するようにした。参考:RHEL8とFlexible Server PostgreSQLでLogical Replicationする