Đầu tiên, tôi biết đây là một câu hỏi cũ nhưng ...
Tôi đã chạy máy chủ DNS có thẩm quyền, không đệ quy của mình trong nhiều thập kỷ, nhưng chưa bao giờ là nạn nhân trong bất kỳ cuộc tấn công DDoS dựa trên DNS nào - cho đến bây giờ, khi tôi chuyển sang ISP mới. Hàng ngàn truy vấn DNS giả mạo tràn ngập nhật ký của tôi và tôi thực sự khó chịu - không ảnh hưởng nhiều đến máy chủ của tôi, thay vào đó, thực tế là nó làm lộn xộn nhật ký của tôi và cảm giác khó chịu khi bị lạm dụng. Có vẻ như kẻ tấn công cố gắng sử dụng DNS của tôi trong một cuộc tấn công Máy chủ tên có thẩm quyền của nhà mạng .
Vì vậy, tôi đã hình dung rằng, mặc dù tôi giới hạn các truy vấn đệ quy vào mạng bên trong của mình (từ chối tất cả các truy vấn khác), tôi thà dành chu kỳ CPU của mình cho khớp chuỗi trong iptables hơn là gửi lại phản hồi tiêu cực cho các địa chỉ IP giả mạo (ít lộn xộn hơn trong nhật ký của tôi lưu lượng truy cập mạng và mức độ hài lòng cao hơn của riêng tôi).
Tôi đã bắt đầu bằng cách làm như mọi người khác dường như làm , tìm ra tên miền nào được truy vấn và tạo một chuỗi khớp trên tên miền đó với DROP mục tiêu. Nhưng tôi sớm nhận ra rằng tôi sẽ kết thúc với một số lượng lớn các quy tắc, mỗi quy tắc đều tiêu tốn chu kỳ CPU. Vậy lam gi? Vì tôi không chạy một máy chủ tên đệ quy, tôi đã hình dung rằng tôi có thể thực hiện việc khớp trên các khu vực thực tế mà tôi có thẩm quyền và bỏ mọi thứ khác.
Chính sách mặc định của tôi trong iptables là CHẤP NHẬN, nếu chính sách của bạn là DROP, có lẽ bạn cần thực hiện một số điều chỉnh nếu bạn muốn sử dụng giải pháp sau.
Tôi giữ cấu hình vùng của mình trong một tệp riêng (/etc/bind/named.conf.local), hãy sử dụng điều này làm ví dụ:
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;
};
Lưu ý nhận xét của // // riêng tư về hai vùng đầu tiên của tôi, tôi sử dụng đoạn mã này trong đoạn mã sau để loại trừ chúng khỏi danh sách các vùng hợp lệ.
#!/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";
Chạy đoạn script trên với tệp cấu hình vùng làm đối số.
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
Lưu đầu ra vào một tập lệnh, đặt nó vào một vỏ hoặc sao chép và dán nó vào thiết bị đầu cuối của bạn để tạo chuỗi mới và bắt đầu lọc tất cả các truy vấn DNS không hợp lệ.
run / sbin / iptables -L DNSvalidate -nvx
để xem các bộ đếm gói (và byte) trên mỗi quy tắc trong chuỗi mới (bạn có thể muốn di chuyển vùng có hầu hết các gói lên đầu danh sách để làm cho nó hiệu quả hơn).
Hy vọng rằng ai đó có thể tìm thấy điều này hữu ích :)