それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

nftablesでiptables recentと同等の処理をする(ipset利用で動的ファイアウォール)

nftablesでiptables xt_recent を使えない

iptables でrecent モジュールを使って、閾値を設けることができる。

iptables -I INPUT -i eth2 -m conntrack --ctstate NEW -m recent --name fromList --set 
iptables -I INPUT -i eth2 -m recent --name fromList --second 5 --hitcount 1 --rcheck --reap -j REJECT

このような、モジュールによるマッチングと閾値処理をnftable ではどうするのか。

nftables ではrecent モジュールでマッチングができない。

そこでかわりに ipset を使って記録をする。

この目的に、nftablesで set 機能が使える・

(xt_recentは強引につかえなくもない、別記事に記載)

送信元IPアドレスを記録する

NTBL=sample-dymamic
NSET=recent

nft delete table $NTBL
nft add table $NTBL
nft add set $NTBL $NSET { type ipv4_addr\; flags timeout\; timeout 10m \; }
nft add chain $NTBL prerouting { type filter hook prerouting priority mangle \; }
nft add rule  $NTBL prerouting set add ip saddr @$NSET
nft list set $NTBL $NSET

timeout 10mを入れているので、最終通信から10min で削除される。

prerouting で通信にhook し、rule は prerouting 通過で add saddr する。

一定数以上に接続があると止める。

単位時間あたり接続が、閾値を超えたら止めることができる。

nft add rule ip $NTBL prerouting ip saddr @recent limit rate over 1/minute  drop

さらに、NEW に限定する

nft add rule ip $NTBL prerouting ct state new ip saddr @recent limit rate over 1/minute drop

カウントもしておく

nft add rule ip $NTBL prerouting ct state new ip saddr @recent limit rate over 1/minute counter drop

単位は、second minitute hour など

timeout / expires の違い

  • timeout: 非アクティブがN秒続いたら削除
  • expires: 登録してN秒経過したら無効・削除

プログラミングっぽく書くと

言い換えると次の判定である。

# Timeout
if ( last_seen.timestamp + timeout.delta ) {
 delete entry 
}

# Expires 
if ( registerd.timestamp + expires.delta ){
{
 delete entry 
}

リストを使って過去に記録のある通信だけ通す。

recent リスト(SET)を使って、記録された通信だけを通す。

nft add rule ip $NTBL postrouting ip daddr @recent mark set $MARK_VALUE
nft add rule ip $NTBL postrouting meta mark != $MARK_VALUE drop

iptables recent と違って、ipset ( set ) を使うのため、利用方法がipset準拠である。特別なことはなにもない。

listen 0.0.0.0 している場合

ローカルプロセスで、listen 0.0.0.0 の場合はどのIPアドレスをSRC指定で応答するかよくわからない。そこで、Ingressなインタフェースにパケットを返すために、ソースIPを書き換える。

nft add chain myt mychain { type route hook output priority -150\; }
nft add rule myt mychain meta mark 0x00000320 ip saddr set $eth1_address udp sport set $listen_port

このようにして、ソースIPを書き換えて、確実にパケットを応答すればいい。

TCPだとConnectionのSyn/ACKでみれるが、UDPだと上記のような応答書き換えを行う必要がある。OpenVPNやWiregaurdのようなソフトウェアを0.0.0.0でリッスンしている場合に有効な設定である。

まとめ

ipset に動的に追加削除できるのでとても便利である。

ipset のリストのメンテナンスできるWEB管理画面を作ってしまえば、WEB上からSSH許可を申請するなどの運用もできるわけで。そのリストの更新をパケットで単位で識別できる。

これで、SSHの通信が疎通した(特定の通信が通った)ら通信を許可できる。とても柔軟にグレートなファイアウォールが作れる。ipset 組み合わせでIPレイヤであれば今まで難しかったことが、可能になる。専用機でやっていたことや専用アプリライアスに不可能なことを可能にする、なんでもできる神機能ファイアウォールが作れる。