Gentooにファイアウォールを入れる

前置き

iptablesによるパケットフィルタリングの設定を紹介します。いろんなサイトのサンプルをアレンジさせて頂きました。

本文

まずは使用準備から。emergeして起動してrc-updateします。

 # emerge net-firewall/iptables
 # /etc/init.d/iptables start
 # rc-update add iptables default

iptablesは、端末に出入りするパケットを監視して、設定に応じてDROP/ACCEPTします。私の環境の場合、フィルタリングの方針は以下の通りです。

  • 入力(INPUT)と転送(FORWARD)はデフォルトでDROP
  • 出力(OUTPUT)はデフォルトでACCEPT
  • LAN内部からのINPUTはACCEPT
  • SYN以外で始まるCONNECT要求はDROP
  • 特定の国からのINPUTは有無を言わさずDROP
  • LAN外部からのINPUTは、http/httpsのみをACCEPT

運用手順は以下の通りです。

  • シェルスクリプトを使ってiptablesを実行する
  • シェルスクリプトはcronにより、定期的に再実行する
  • 設定内容は /etc/init.d/iptables save しておき、システム起動時に自動ロードさせる

で、シェルスクリプトの内容は、下記のような感じです。

  • firewall.sh
 #!/bin/sh

 # ----------------------------------------
 # 環境変数
 IPTABLES="/sbin/iptables"
 WGET="/usr/bin/wget"
 RM="/bin/rm"
 R_FROMLAN="-i eth0 -s 192.168.1.0/24"   # LAN内端末からのパケット
 R_NEW="-m state --state NEW"            # コネクションの最初のパケット

 # ----------------------------------------
 # マクロ

 # 国別IPアドレスリストから、指定した国からのアクセスをDROPする
 DROP_COUNTRY() {
   for IP in `cat $1 | grep "$2|$3|ipv4|"`
   do
     ADDR=`echo $IP |cut -d "|" -f 4`
     TEMP=`echo $IP |cut -d "|" -f 5`
     CIDR=32
     while [ $TEMP -ne 1 ];
     do
       TEMP=`expr "$TEMP" / 2`
       CIDR=`expr "$CIDR" - 1`
     done
     $IPTABLES -A INPUT -s $ADDR/$CIDR -j DROP
   done
 }

 # ----------------------------------------
 # ルールをクリア
 $IPTABLES -F
 $IPTABLES -X
 $IPTABLES -Z

 # ----------------------------------------
 # ポリシー(デフォルト)
 $IPTABLES -P INPUT DROP
 $IPTABLES -P FORWARD DROP
 $IPTABLES -P OUTPUT ACCEPT

 # ----------------------------------------
 # 基本設定

 # ローカルループ
 $IPTABLES -A INPUT -i lo -j ACCEPT

 # LAN内ホストから
 $IPTABLES -A INPUT $R_FROMLAN -j ACCEPT

 # TCPで、最初(NEW)のパケットがSYN以外
 $IPTABLES -A INPUT -p tcp ! --syn $R_NEW -j DROP

 # TCPやICMPで、コネクト済みのセッション(ESTABLISHED)か、
 # それに関連する別セッション開始(RELATED)
 $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

 # ----------------------------------------
 # 上記までで、外部からのパケットに関しては
 # 最初のSYNだけが通り抜けているはず
 # ----------------------------------------

 # ----------------------------------------
 # 国別設定

 # 国別IPアドレスリスト取得
 $WGET -q http://ftp.apnic.net/stats/apnic/delegated-apnic-latest
 $WGET -q ftp://ftp.arin.net/pub/stats/arin/delegated-arin-latest

 # 国別に拒否
 DROP_COUNTRY delegated-apnic-latest apnic CN
 DROP_COUNTRY delegated-arin-latest arin CN
                       # CN以外にも、アタックが多い国は拒否します。

 # 国別IPアドレスリスト削除
 $RM delegated-apnic-latest
 $RM delegated-arin-latest

 # ----------------------------------------
 # プロトコルごとに、開ける
 $IPTABLES -A INPUT -p tcp $R_NEW --dport 80 -j ACCEPT  # http
 $IPTABLES -A INPUT -p tcp $R_NEW --dport 443 -j ACCEPT # https
 #  $IPTABLES -A INPUT -p tcp $R_NEW --dport 22 -j ACCEPT  # ssh
 #  $IPTABLES -A INPUT -p tcp $R_NEW --dport 20 -j ACCEPT  # ftp(data)
 #  $IPTABLES -A INPUT -p tcp $R_NEW --dport 21 -j ACCEPT  # ftp(control)

 # ----------------------------------------
 # ログの設定
 $IPTABLES -N LOGRULES
 $IPTABLES -A LOGRULES -j LOG --log-level warning --log-prefix "DROP:"
 $IPTABLES -A LOGRULES -j DROP
 $IPTABLES -A INPUT -j LOGRULES
 $IPTABLES -A FORWARD -j LOGRULES

 # ----------------------------------------
 # Save settings that would be re-loaded at /etc/init.d/iptables start.
 /etc/init.d/iptables save

wgetで取得している国別IPアドレスリストは不定期に更新されます。定期的にcronでシェルスクリプトを再実行するのはそのためです。

シェルスクリプト実行後に設定内容を確認するには、nLオプションを使います。

 # iptables -nL

余談

DROPしたパケットはログに残ります。こんな感じ。

 Jun 20 05:22:12 myhost kernel: [1579993.374453] DROP:IN=eth0 OUT= MAC=MMMMM \
   SRC=XXXXX DST=YYYYY LEN=44 TOS=0x00 PREC=0x00 TTL=101 ID=18282 \
   PROTO=TCP SPT=22 DPT=22 WINDOW=32422 RES=0x00 SYN URGP=0

あるとき、同一アドレスからのICMPパケットをDROPしたログが大量に出力されていることに気付きました。何か攻撃されてる? と不安に思ったのですが、良く見るとログの形式がいつもと違います。

 Jun 26 11:05:47 myhost kernel: [2118985.503264] DROP:IN=eth0 OUT= MAC=MMMMM \
   SRC=XXXXX DST=YYYYY LEN=104 TOS=0x00 PREC=0x00 TTL=41 ID=6296 \
   PROTO=ICMP TYPE=3 CODE=3 [SRC=YYYYY DST=XXXXX LEN=76 TOS=0x00 PREC=0x00 \
   TTL=41 ID=0 DF PROTO=UDP SPT=123 DPT=123 LEN=56 ]

いつものログ形式の後ろに、ブラケット[]で囲まれた別のパケット情報が付いてますね。おそらく、言いだしっぺは[]内のパケットで、そのレスポンスをDROPしたんだと思います。上記のケースでは、NTPサーバへのリクエスト(UDPの123番ポート)に対して、ポート閉鎖(CODE=3)による到達不可(TYPE=3)を知らせるICMPパケットが返ってきたわけです。どうやらNTPの設定を変えたときに、使えないNTPサーバを選んでしまったのかもしれません。

追記

sshを開ける場合、頻繁な不正ログインの試みをDROPできると良いですね。recentというモジュールを使いましょう。

 $IPTABLES -A INPUT -p tcp $R_NEW --dport 22 -m recent --set --name SSH_ATTEMPT
 $IPTABLES -A INPUT -p tcp $R_NEW --dport 22 -m recent --update --seconds 10 --hitcount 5 --name SSH_ATTEMPT -j DROP
 $IPTABLES -A INPUT -p tcp $R_NEW --dport 22 -j ACCEPT

ただsshを開けるだけなら、3行目のみ。上の2行を加えると、10秒間に5回以上の接続を試みたIPアドレスをDROPします。SSH_ATTEMPTには任意の名前を指定可能です。2行目には、--rttlというオプションも付けた方が良いかもしれません(IPアドレスを毎回変えてくるアタッカーに有効)。

ちなみに、gentoo kernelのrecentモジュールは、デフォルトではdisableされてます。なので、kernel configで、Netfilterのページの"Advanced netfilter configuration"をenableし、さらに"Core Netfilter Configuration"の中から"recent match support"をenableしてビルドする必要があります。

Last modified:2011/01/03 22:26:00
Keyword(s):
References:[サーバ管理・Linux関連] [Gentooにftpサーバを入れる]
This page is frozen.