hosts.allow で sshd への接続を日本国内のみに制限する

スポンサーリンク

以前の記事で、iptables を用いて特定のポートへの接続を日本国内のみに制限するスクリプトを書いたが、BlueOnyx では勝手に iptables がリセットされて、ファイアウォールが全開になっていることがたまにあった。これでは危険なので、hosts.allow を用いて、せめて sshd だけでも塞いでおくことにした。

複数の CIDR ブロックを集約 (aggregation) するために、aggregate というプログラムを RPM でインストールする。

# mkdir /usr/local/rpm
# cd /usr/local/rpm
# wget "http://sourceforge.jp/frs/g_redir.php?m=jaist&f=%2Fcnsubnetlookup%2Faggregate-1.6-4.el5.i386.rpm"
# rpm -ivh aggregate-1.6-4.el5.i386.rpm

各ファイルを格納するためのディレクトリを作成する。

# mkdir /root/countryfilter

各国の IP アドレスの割当リストから日本のものを取り出し、10 進数表記に変換する Perl スクリプトを作成する。

# vi conv.pl
#!/usr/bin/perl

use strict;

while (<STDIN>) {
    chomp;
    my ($registry, $cc, $type, $start, $value, undef, $status) = split(/\|/);

    unless ($type eq 'ipv4' && ($status eq 'allocated' || $status eq 'assigned')) { next; }
    #unless ($cc eq 'JP') { next; }

    my $SubnetMaskBin = sprintf('%b', scalar($value));
    if ($SubnetMaskBin !~ /^1(0+)$/) {
        # CIDR 表記できない
        next;
    }
    my $prefix = 32 - length($1);

    my $num;
    $num = ($num << 8) + $_ foreach (split(/\./, $start));

    if (($num % $value) != 0) {
        # 分割しなければならない
        next;
    }

    print $start.'/'.$prefix."\t".$cc."\n";
}

日本国内の IP アドレスリスト (jp.txt) を生成して hosts.allow に書き込むシェルスクリプト (update.sh) を作成する。

# vi update.sh
#!/bin/sh

DIR=$(cd $(dirname $0); pwd)
cd $DIR

# aggregate がインストールされているかチェック
aggregate=`which aggregate 2> /dev/null | wc -l`
if [ $aggregate -ne 1 ]; then
        echo "aggregate: command not found" >&2
        exit 1
fi

# 各 RIP から IP アドレスの割当リストを取得
rm -f ./delegated-*
wget ftp://ftp.arin.net/pub/stats/arin/delegated-arin-latest > /dev/null 2>&1
wget ftp://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-latest > /dev/null 2>&1
wget ftp://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest > /dev/null 2>&1
wget ftp://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest > /dev/null 2>&1
wget ftp://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-latest > /dev/null 2>&1

if [ ! -f delegated-apnic-latest ]; then
        echo "delegated-apnic-latest was not found." >&2
        exit 1
fi

# 日本国内のもののみを取り出して集約
cat delegated-* | perl ./conv.pl | grep -E 'JP$' | sort -n | aggregate -q > jp.txt

# CIDR 表記をサブネットマスク表記に変換
sed -i 's/\/8$/\/255.0.0.0 /' ./jp.txt
sed -i 's/\/9$/\/255.128.0.0 /' ./jp.txt
sed -i 's/\/10$/\/255.192.0.0 /' ./jp.txt
sed -i 's/\/11$/\/255.224.0.0 /' ./jp.txt
sed -i 's/\/12$/\/255.240.0.0 /' ./jp.txt
sed -i 's/\/13$/\/255.248.0.0 /' ./jp.txt
sed -i 's/\/14$/\/255.252.0.0 /' ./jp.txt
sed -i 's/\/15$/\/255.254.0.0 /' ./jp.txt
sed -i 's/\/16$/\/255.255.0.0 /' ./jp.txt
sed -i 's/\/17$/\/255.255.128.0 /' ./jp.txt
sed -i 's/\/18$/\/255.255.192.0 /' ./jp.txt
sed -i 's/\/19$/\/255.255.224.0 /' ./jp.txt
sed -i 's/\/20$/\/255.255.240.0 /' ./jp.txt
sed -i 's/\/21$/\/255.255.248.0 /' ./jp.txt
sed -i 's/\/22$/\/255.255.252.0 /' ./jp.txt
sed -i 's/\/23$/\/255.255.254.0 /' ./jp.txt
sed -i 's/\/24$/\/255.255.255.0 /' ./jp.txt
sed -i 's/\/25$/\/255.255.255.128 /' ./jp.txt
sed -i 's/\/26$/\/255.255.255.192 /' ./jp.txt
sed -i 's/\/27$/\/255.255.255.224 /' ./jp.txt
sed -i 's/\/28$/\/255.255.255.240 /' ./jp.txt

# /etc/hosts.allow をリセット
sed -i -e '/#countryfilter/d' /etc/hosts.allow

# 日本国内の IP アドレスリストを書込
cat ./jp.txt | awk '{print "sshd: "$1" #countryfilter"}' >> /etc/hosts.allow

hosts.deny を編集して、sshd へのアクセスを原則禁止とする。

# vi /etc/hosts.deny
sshd: ALL

※ ssh で作業している場合、この時点で切断すると再接続できなくなるので注意。

ローカルホストからのアクセスは許可するために、hosts.allow の先頭に次の1行を追加する。

# vi /etc/hosts.allow
ALL: 127.0.0.1
  :

作成したシェルスクリプトに実行権を与えて、実行する。

# chmod 700 update.sh
# ./update.sh

cron で一週間ごとに実行するように設定する。

# ln -s /root/countryfilter/update.sh /etc/cron.weekly/

以上で sshd への接続は日本国内のみに制限された。

コメント

タイトルとURLをコピーしました