
Linux Debian Bookworm を使用します。
問題
特定の国からサーバーへのすべての着信接続をブロックしたい。
編集
コメントで誰かが指摘したように、iptables でこれを行うべきではありません。ブロックする IP アドレスのリストが管理できないサイズ (IP アドレスが数千個など) に大きくなると、サーバーが停止してしまうからです。代わりに、ipset
(範囲全体をブロックするには) を使用する必要があります。その問題は、定期的にダウンロードする必要があるリストに依存していることです。できれば、一度設定すれば済むものが欲しいです。
では、特定の国からの接続を停止するにはどうすればよいでしょうか?中国とロシアからのトラフィック (時にはブルート フォース攻撃) が手に負えなくなってきています。私のサーバーは定期的にダウンしています。robots.txt ファイルに従わず、非常に積極的にサイトをクロールします (数百、時には数千の接続が同時に行われます)。本当にこれを止めなければなりません。私の推測では、私のサーバーが処理するトラフィックの 90% 以上が悪意のある/不正な形式です。
編集2
私はいくつかのオンラインチュートリアルを見つけました(このように) でやり方を知りましたが、これらのチュートリアルはかなり古いようです。また、いくつかのモジュールをダウンロードしてコンパイル/インストールする必要があります。将来的にこれが機能しなくなる (他のパッケージやディストリビューションを更新/アップグレードする場合) か、将来的にセキュリティ リスクになるのではないかと心配しています。私はサーバーを最新の状態に保っています (apt-get update / apt-get upgrade / apt-get dist-upgrade を定期的に実行)。
オリジナルメッセージ
ネット上で、確立された接続の IP アドレスのリストを毎秒取得し、geoiplookup を使用して IP アドレスの国を取得するスクリプトを見つけました。国がブロックしたい国のリストに含まれている場合、iptables を使用して IP アドレスをファイアウォール フィルターに追加します。スクリプトに若干の変更を加えました (より読みやすくするためと、IP アドレスをブロックするたびにこのスクリプトから電子メールが送信されることには興味がなかったためです)。このスクリプトは、crontab を通じて毎分実行されます。
#!/bin/bash
# Script found on lautenbacher.io"
end=$((SECONDS+55))
while [ $SECONDS -lt $end ]; do
echo $SECONDS
netstat -ant | egrep ':.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > testcc.txt
sed 's/^[ t]*//' -i testcc.txt
sed '/^$/d' -i testcc.txt
while read c d; do
if [[ $c > "0" ]]; then
bGF1dGVuYmFjaGVyLmlv=$(geoiplookup $d | awk -v ip="$d" '{FS=" "} {if($4 == "RU," || $4 == "CN," || $4 == "BLR,") {print 1}}')
if [[ $bGF1dGVuYmFjaGVyLmlv = "1" ]]; then
echo "running geolookup"
echo checking ip $d
geoiplookup $d
isCloudflare=0
# The original script made an exception for CLOUDFLARE. I don't want that exception
# bGF1dGVuYmFjaGVyLmlX=$(whois $d)
# if [[ "$bGF1dGVuYmFjaGVyLmlX" == *"CLOUDFLARE "* ]]; then
# isCloudflare=1
# echo Cloudflare detected
# fi
if [[ "$isCloudflare" != 1 ]]; then
echo try to add ip $d to blocklist
sudo iptables -I INPUT -s $d -j DROP
### I would like to sever the connection here ###
fi
fi
fi
done < testcc.txt
sleep 1
:
done
ところで、スクリプトの作成者がなぜこのような奇妙な変数名 ("bGF1dGVuYmFjaGVyLmlv") を使用しているのかはわかりません。
とにかく、問題は、禁止された国のIPアドレスとの接続を見つけるたびに、
sudo iptables -I INPUT -s $d -j DROP
IP アドレスについて。これはすべて問題ありませんが、これらの接続のほとんどはある程度永続的であり、1 秒後に同じ IP アドレスが見つかり、iptables を使用して再度追加されます。何が起こるかはわかりません (重複したルールが作成されますか?) が、iptables を使用して IP アドレスが追加された後、すぐに接続を切断したいと思います。
つまり、IP アドレスを持つすべての接続を切断するにはどうすればよいでしょうか?
答え1
数年前からLinuxカーネルには、IPソケットの状態に関係なく、既存のIPソケットを強制的に削除するAPIがあります。これは、ss
コマンドとそのフィルター構文:
-K
、--kill
ソケットを強制的に閉じようとします。このオプションは、正常に閉じられたソケットを表示し、カーネルが閉じることをサポートしていないソケットを黙ってスキップします。IPv4 および IPv6 ソケットのみをサポートします。
以下を置き換えることができます:
### I would like to sever the connection here ###
と:
ss --kill -n dst = "$d"
のフィルター( dst = ...
) が必要です。このコマンドは、表示されるソケットをすべて強制終了するためです。フィルターがなければ、要求以上のものになります。ローカル プロセスは、ソケットで などのまれなエラーを受け取る可能性がありますECONNABORTED
。これを防ぐために OUTPUT ルールも (一時的に) 追加されない限り、リモート ノードには TCP RST が通知される可能性があります。
このQ/Aも参照してください(私が回答しました):UbuntuですべてのTCP接続(ESTABLISHED、RELATED)をドロップするOPは攻撃から身を守ろうとするが、ipset(また、古い接続やステートフル ファイアウォールの問題もあります)。