ADSLモデムのNATテーブル溢れで困る

古いADSL モデムで自宅サーバを立てている場合の話なので現代では役に立たないでしょうが健忘録として書いておきます．(光回線?圏外なのですorz)

環境

ADSLモデム-SV3
Hardware Revision: 0001
Software Version: 03.20 (Tue Jul 27 20:45:13 JST 2010)
Boot ROM Version: 01.00 (Thu Jun 3 17:07:20 JST 2004)
DSP Firmware Version: 42.20
VDSP Firmware Version: 9.1.60.12

最近よく家のネットワークで名前解決できなくなることがあります．
DNSが多段になっていて無駄が多いのでそのへんの問題かなと思ったのですが，直接ISP や 8.8.8.8 とか 1.1.1.1 とかの PublicDNS に問い合わせても引けません．

ISP — Unbound — PiHole — PC

ip 直なら繋がるだろうと試すとhttpもsshも駄目です．タイムアウトになります．

ルータを再起動すると直ることもあれば，直ってもすぐに元に戻ってしまうこともあります．

ルータのログみると tcp80 に大量のアクセスがあってそれで NAT table が溢れてしまって繋がらないということのようです．NAT table は 1024 しかないのですが，一度に 1 ipから200〜400回くらいのアクセスが来てこれが複数回来ると NAT table が溢れてしまい通信ができなくなるようです．
＃NAT table を増やす設定変更項目は見当たらない

とりあえずルータを再起動しなくてもNAT table をクリアすると一時的に通信できるようになります．でもどんどんこのアクセスが来てすぐに元に戻ります．おまけにこのアクセスは「有効期限(秒)」が9000とかになっているのでなかなかクリアされません．(ほかは60のよう)
＃有効期限の設定変更項目は見当たらない

ip を逆引きしてみると大抵は一般の利用者のようで名前が振られていないレンジや，ipアドレス-domain みたいな名前です．おそらく何かのウィルスに感染して攻撃をしているのではないかと思います．(Google Cloud とかもあったけど……)
幸い自宅サーバのtcp80はhttpsへのリダイレクトとテスト用なのでこれらのアクセスをブロックしてみました．
whois で inetnum を確認して，CIDR を計算して「パケットフィルタ設定」でこのネットワークの tcp80 へのアクセスを drop するように設定してNAT table クリアでドロップされるようにありました．ドロップは「セキュリティログ」で確認できます．

これを繰り返していたのですが設定は64個しか書けません．すぐに溢れました……．

別のアプローチを考えます．
このADSLモデムのweb管理画面はレガシーでcurlでアクセスできます．

NAT table の登録件数を求める

$ echo $(curl -s -u 'user:password' 'http://192.168.1.1/cgi-bin/main.cgi?mbg_webname=nattbl'|lynx -stdin -dump -width=256|grep -m1 '現在の登録件数'|sed -e 's/^.*：\(.*\)\/.*$/\1/')
308

NATクリアも同様に出来ます．

NATテーブル消去

$ curl -s -u 'user:password' -F 'mbg_webname=natclear' -F 'nat_clear=消去' 'http://192.168.1.1/cgi-bin/main.cgi' | lynx -stdin -dump
NATテーブル消去
[1]ヘルプ [2]help
-----

NATテーブルの消去を行いました。

戻る

参照

1. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear
2. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear

これを使って NAT table を確認して，溢れそうだったらクリアするscriptを用意してみました．

script の中に書きたくないので ID/PASSWORDは ~/.netrc に書いておきます．

// EDIT : wgetに怒られたので netrc の machine を ADSL ROUTER から ADSL_ROUTER に変更(scriptも)
// wget: /home/mk/.netrc:1: "ROUTER" は不明な区切り記号(token)です

~/.netrc に追記

$ echo 'machine ADSL_ROUTER
> login user
> password password
> ' | tee -a ~/.netrc
machine ADSL_ROUTER
login user
password password

適当な script を用意して，

nat_clear.bash

#!/bin/bash

# ~/.netrc 読み込み
usrinfo=(`awk 'c&&c--;/ADSL_ROUTER/{c=2}' $HOME/.netrc | awk '{printf "%s ", $2}'`)
USER=${usrinfo[0]}
PASS=${usrinfo[1]}

# NAT table 登録数確認
NAT_TABLE=$(curl -s -u "${USER}:${PASS}" 'http://192.168.1.1/cgi-bin/main.cgi?mbg_webname=nattbl'|lynx -stdin -dump -width=256|grep -m1 '現在の登録件数'|sed -e 's/^.*：\(.*\)\/.*$/\1/')

# NAT table が 750 より大きいとNAT table clear
if[ 750 -lt $NAT_TABLE ]; then
echo "NAT table clrar(${NAT_TABLE})"
# tcp:80 にアクセスしている ip を確認して表示
curl -s -u "${USER}:${PASS}" 'http://192.168.1.1/cgi-bin/main.cgi?mbg_webname=nattbl' | lynx -stdin -dump -width=256 | grep 192.168.1.102/80 | awk {'print $6'} | cut -f1 -d\/ | sort | uniq -c
# NAT table clear
curl -s -u "${USER}:${PASS}" -F 'mbg_webname=natclear' -F 'nat_clear=消去' 'http://192.168.1.1/cgi-bin/main.cgi' | lynx -stdin -dump
fi

実行権を付与．

$ chmod +x nat_clear.bash

crontab に登録して5分毎に呼ぶように設定．

// EDIT: 1024使い切ってからクリアが多いので3分毎に変更した

$ crontab -e
crontab: installing new crontab
$ crontab -l | grep nat_clear.bash
*/5 * * * * /home/mk/bin/nat_clear.bash

// EDIT: 実際に動作したときのログ追記

NAT table clrar(1024)
837 103.234.73.6
102 51.254.167.83
NATテーブル消去
[1]ヘルプ [2]help
-----

NATテーブルの消去を行いました。

戻る

References

1. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear
2. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear

とりあえずこれで様子見中です．しかし対処療法でアクセスが増えたら耐えられなくりますね……．
サーバ機能を引っ越して外部からのアクセスを遮断したらこの問題は解決するはずですが出来たら選びたくないです．
ADSLモデムを高機能なものに置き換えると設定でどうにかなるかもとか，しかしそもそもADSL自体が収束なので製品が存在するのか?

とか思いながら設定項目を見ていると「PPPoEブリッジ機能」というものがありました．これを使うとADSLモデムの裏のサーバ等からPPPoEで繋げそうな感じがします．それが出来たらn分以内にn回アクセスがあったらしばらく無視するとか柔軟な設定が出来るようになります．次はこれを試してみたいと思います．

＃光回線はよ……