2010年11月28日日曜日

iptablesで日本のみアクセス許可

またまた時間がすっとんでいますが、玄箱ProのDebianが
おかしくなっていたので再セットアップ完了してWebサーバ・ファイルサーバ・プリントサーバとしての
機能が復帰しました。


その際SSHで外部アクセスを可能にしたいのですが、それをすると
だいたい海外からSSHのアタックが定期的にやってきます。
非常にうざったいので日本以外からのアクセスをはじいてしまおうと
いろいろと調べていました。

基本的には
guro_chanの日記
のページの記事を参考にしております。

本来は元記事の通りに行えば問題ないのですが、APNICのアドレス割り当ての
データが変更されているらしく、このままではiptablesのチェインに組み込めません。

まあそれらしい他のサイトも見つからなかったので、参考記事のスクリプトを元に
現在(2010/11)のAPNICの提供データからJPに割り当てられている
アドレス帯を抽出し、iptablesのインバウンドのルールに組み込むスクリプトを
作成しました。

 
// JPonly-rules.sh

 #!/bin/bash
   if [ -e "/tmp/Addresstable.txt" ]; then
     \rm /tmp/Addresstable.txt
   fi

 touch /tmp/Addresstable.txt

 iptables -F
 iptables -P INPUT ACCEPT
 iptables -P OUTPUT ACCEPT
 iptables -P FORWARD DROP
 iptables -X

 iptables -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
 iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT
 iptables -A INPUT -s 127.0.0.1 -j ACCEPT

 APNIC='http://ftp.apnic.net/stats/apnic/delegated-apnic-latest'
 DUMPFILE=`w3m -dump "$APNIC"`
 CIDR=`echo "$DUMPFILE" | awk --field-separator="|" \
    ' $1 !~ /^#/ && $2 == "JP" && $3 == "ipv4" {print $4} '`

 ADDRNG=`echo "$DUMPFILE" | awk --field-separator="|" \
  ' $1 !~ /^#/ && $2 == "JP" && $3 == "ipv4"  {print $5;}'`

 echo "APNIC Delegated Table Dumped"
 i=1
 for TEMP in $CIDR
 do
    if [ $TEMP == "" ]; then
      break
    fi
    ARRCIDR[$i]=$TEMP
    i=`expr $i + 1`
 done

 TEMP=""

 echo "Changing AddressRange into NetMask"
 echo "$i Addresses to Change..."
 i=1
 for TEMP in $ADDRNG
 do
   if [ $TEMP == "" ]; then
     break
   fi
   PRFX=`echo "print (Math.log($TEMP)/Math.log(2)).prec_i" | ruby`
   PRFX=`expr 32 - $PRFX`
   echo "${ARRCIDR[$i]}/${PRFX}" >> /tmp/Addresstable.txt
   i=`expr $i + 1`
 done

 ADDRESS=`cat /tmp/Addresstable.txt`
 echo "Table Analysing Completed."

 for STATE in $ADDRESS
 do
   iptables -A INPUT -i eth0 -p tcp --dport 80  -s "$STATE" -j ACCEPT
   iptables -A INPUT -i eth0 -p tcp --dport 443 -s "$STATE" -j ACCEPT
 done

 iptables -P INPUT DROP



こんな具合です。
APNICのデータはCIDRマスクではなく開始アドレス+アドレス数で記載されて
いるので、ここではrubyを使ってアドレス数→ビット変換→CIDRマスクにするという
形をとっています。
今回はWebサーバを公開するということでhttp,httpsのルールにしています。
sshやftpを公開したい場合は適宜dportだけ変えて追加すればいいです。

今回はrubyでマスク値を算出して追加するというスクリプトにしましたが
せいぜい8ビット~16ビット程度のパターンなのでcase文を使ったほうが
効率がいいかもしれません。
終了までに玄箱Pro/Debian Lennyだと20分くらいかかります。
とくにARMプロセッサだとlogのような浮動小数点演算が遅いので、2000個も
処理していると結構な時間がかかります。
またrubyプロセスを都度呼び出ししているのもパフォーマンス低下の
原因に思えます。

あるいは前処理は高速なx86機に任せて、ルールの読み込みだけさせるのも
いいかもしれません。

あとの課題は、スーパーネッティングを一切考慮していないので、
ルール数がえらく多くなってしまっていることでしょうか。
楽をするためにrubyのlogを使っているので、case文を使ったときの
パフォーマンス比較もしてみたいですね。

0 件のコメント:

コメントを投稿