첫째, 나는 이것이 오래된 질문이라는 것을 알고 있지만 ...
저는 수십 년 동안 저만의 정식 비 재귀 DNS 서버를 운영해 왔지만 지금까지 새로운 ISP로 전환 할 때까지 DNS 기반 DDoS 공격의 희생자는 없었습니다. 수천 개의 스푸핑 된 DNS 쿼리가 내 로그를 쇄도했고 서버에 미치는 영향이 아니라 내 로그를 어지럽히고 불쾌한 악용을 느꼈다는 사실에 대해 짜증이났습니다. 침입자는 " 권한있는 이름 서버 공격 " 에서 내 DNS를 사용하려고합니다 .
따라서 재귀 쿼리를 내부 네트워크 (다른 모든 거부)로 제한하더라도 스푸핑 된 IP 주소에 부정적인 응답을 다시 보내는 것보다 iptables의 문자열 일치에 CPU주기를 소비한다고 생각했습니다. 네트워크 트래픽 및 내 자신의 높은 만족도).
다른 사람들이하는 것처럼 시작하여 시작한 도메인 이름을 찾아 해당 도메인에서 대상 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;
};
첫 두 영역에 대한“// 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
를 실행 하여 새 체인의 각 규칙에서 패킷 (및 바이트) 카운터를 봅니다 (대부분의 패킷이있는 영역을 목록의 맨 위로 이동하여 더 효율적으로 만들 수 있음).
누군가가 이것을 유용하게 사용할 수 있기를 바랍니다. :)