まず、これは古い質問ですが、...
私は何十年もの間、独自の権威ある非再帰的なDNSサーバーを運用してきましたが、DNSベースのDDoS攻撃の被害者になったことはありませんでした。何千ものスプーフィングされたDNSクエリがログに殺到し、本当にイライラしました。サーバーへの影響についてではなく、むしろログが乱雑であるという事実と悪用の不快感です。攻撃者は「権限のあるネームサーバー攻撃」で私のDNSを使用しようとしているようです。
そのため、内部ネットワークへの再帰クエリを制限する(他のすべてを拒否する)にもかかわらず、スプーフィングされたIPアドレスに否定的な応答を返送するよりも、CPUサイクルをiptablesの文字列照合に費やすと考えました(ログの乱雑さを減らし、ネットワークトラフィックと私自身のより高い満足度)。
私は、他のすべての人がそうであるように始めて、どのドメイン名がクエリされているかを見つけ、ターゲットDROPでそのドメインに文字列一致を作成することから始めました。しかし、すぐに、膨大な量のルールが作成され、それぞれがCPUサイクルを消費することに気付きました。じゃあ何をすればいいの?再帰的なネームサーバーを実行していないため、権限がある実際のゾーンでマッチングを行い、他のすべてをドロップする可能性があると考えました。
iptablesの私のデフォルトポリシーはACCEPTです。ポリシーがDROPである場合、次のソリューションを使用する場合はおそらく調整する必要があります。
ゾーン構成を別のファイル(/etc/bind/named.conf.local)に保存します。これを例として使用してみましょう。
zone "1.168.192.in-addr.arpa" { // Private
type master;
allow-query { 192.168.1.0/24; 127.0.0.1; };
allow-transfer { 127.0.0.1; };
file "/etc/bind/db.192.168.1";
};
zone "home.example.net" { // Private
type master;
allow-query { 192.168.1.0/24; 127.0.0.1; };
allow-transfer { 127.0.0.1; };
file "/etc/bind/pri/db.home.example.net";
};
zone "example.net" {
type master;
file "/etc/bind/pri/db.example.net";
allow-transfer { 127.0.0.1; 8.8.8.8; };
};
zone "example.com" {
type slave;
masters { 8.8.8.8; };
file "sec.example.com";
allow-transfer { 127.0.0.1; };
notify no;
};
zone "subdomain.of.example.nu" {
type slave;
masters { 8.8.8.8; };
file "sec.subdomain.of.example.nu";
allow-transfer { 127.0.0.1; };
notify no;
};
最初の2つのゾーンの「// Private」コメントに注意してください。次のスクリプトでこれを使用して、有効なゾーンのリストからそれらを除外します。
#!/usr/bin/perl
# zone2iptables - Richard Lithvall, april 2014
#
# Since we want to match not only example.net, but also (for example)
# www.example.net we need to set a reasonable maximum value for a domain
# name in our zones - 100 character should be more that enough for most people
# and 255 is the absolute maximum allowed in rfc1034.
# Set it to 0 (zero) if you would like the script to fetch each zone (axfr)
# to get the actual max value.
$maxLengthOfQueryName=255;
$externalInterface="eth1";
print "# first time you run this, you will get error on the 3 first commands.\n";
print "# It's here to make it safe/possible to periodically run this script.\n";
print "/sbin/iptables -D INPUT -i $externalInterface -p udp --dport 53 -j DNSvalidate\n";
print "/sbin/iptables -F DNSvalidate\n";
print "/sbin/iptables -X DNSvalidate\n";
print "#\n";
print "# now, create the chain (again)\n";
print "/sbin/iptables -N DNSvalidate\n";
print "# and populate it with your zones\n";
while(<>){
if(/^zone\s+"(.+)"\s+\{$/){
$zone=$1;
if($maxLengthOfQueryName){
$max=$maxLengthOfQueryName;
} else {
open(DIG,"dig -t axfr +nocmd +nostats $zone |");
$max=0;
while(<DIG>){
if(/^(.+?)\.\s/){
$max=(length($1)>$max)?length($1):$max;
}
}
close(DIG);
}
printf("iptables -A DNSvalidate -m string --from 40 --to %d --hex-string \"",($max+42));
foreach $subdomain (split('\.',$zone)){
printf("|%02X|%s",length($subdomain),$subdomain);
}
print("|00|\" --algo bm -j RETURN -m comment --comment \"$zone\"\n");
}
}
print "# and end the new chain with a drop\n";
print "/sbin/iptables -A DNSvalidate -j DROP\n";
print "# And, at last, make the new chain active (on UDP/53)\n";
print "/sbin/iptables -A INPUT -i $externalInterface -p udp --dport 53 -j DNSvalidate\n";
ゾーン構成ファイルを引数として上記のスクリプトを実行します。
root:~/tmp/# ./zone2iptables.pl /etc/bind/named.conf.local
# first time you run this, you will get error on the 3 first commands.
# It's here to make it safe/possible to periodically run this script.
/sbin/iptables -D INPUT -i eth1 -p udp --dport 53 -j DNSvalidate
/sbin/iptables -F DNSvalidate
/sbin/iptables -X DNSvalidate
#
# now, create the chain (again)
/sbin/iptables -N DNSvalidate
# and populate it with your zones
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|07|example|03|net|00|" --algo bm -j RETURN -m comment --comment "example.net"
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|07|example|03|com|00|" --algo bm -j RETURN -m comment --comment "example.com"
iptables -A DNSvalidate -m string --from 40 --to 297 --hex-string "|09|subdomain|02|of|07|example|02|nu|00|" --algo bm -j RETURN -m comment --comment "subdomain.of.example.nu"
# and end the new chain with a drop
/sbin/iptables -A DNSvalidate -j DROP
# And, at last, make the new chain active (on UDP/53)
/sbin/iptables -A INPUT -i eth1 -p udp --dport 53 -j DNSvalidate
出力をスクリプトに保存し、シェルにパイプするか、ターミナルにコピーして貼り付けて新しいチェーンを作成し、無効なDNSクエリをすべて除外します。
/ sbin / iptables -L DNSvalidate -nvx
を実行して、新しいチェーンの各ルールのパケット(およびバイト)カウンターを表示します(より効率的にするために、ほとんどのパケットを持つゾーンをリストの一番上に移動することができます)。
誰かがこれが便利だと思うことを願って:)