Pertama, saya tahu ini adalah pertanyaan lama tapi ...
Saya telah menjalankan server DNS saya sendiri yang otoritatif, non rekursif, selama beberapa dekade, tetapi belum pernah menjadi korban dalam serangan DDoS berbasis DNS - sampai sekarang, ketika saya beralih ke ISP baru. Ribuan kueri DNS palsu membanjiri log saya dan saya benar-benar kesal - tidak begitu banyak tentang dampak pada server saya, melainkan fakta itu mengacaukan log saya dan perasaan tidak nyaman disalahgunakan. Tampaknya penyerang mencoba menggunakan DNS saya dalam " serangan Server Nama Resmi ".
Jadi saya pikir, meskipun saya membatasi permintaan rekursif ke jaringan internal saya (menyangkal semua lainnya), saya lebih suka menghabiskan siklus CPU saya pada pencocokan string di iptables daripada mengirim kembali tanggapan negatif ke alamat IP palsu (kurang berantakan di log saya, kurang lalu lintas jaringan dan tingkat kepuasan saya yang lebih tinggi).
Saya mulai dengan melakukan seperti yang dilakukan semua orang , mencari tahu nama domain yang ditanyakan dan membuat kecocokan string pada domain tersebut dengan DROP target. Tetapi saya segera menyadari bahwa saya akan berakhir dengan sejumlah besar aturan, masing-masing dari mereka mengkonsumsi siklus CPU. Jadi, apa yang harus dilakukan? Karena saya tidak menjalankan server nama rekursif, saya pikir saya dapat melakukan pencocokan pada zona yang sebenarnya. Saya berwenang untuk dan membuang semua yang lain.
Kebijakan default saya di iptables adalah MENERIMA, jika kebijakan Anda adalah DROP, Anda mungkin perlu melakukan beberapa penyesuaian jika Anda ingin menggunakan solusi berikut.
Saya menyimpan konfigurasi zona saya di file terpisah (/etc/bind/named.conf.local), mari kita gunakan ini sebagai contoh:
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;
};
Perhatikan komentar "// Pribadi" di dua zona pertama saya, saya menggunakan ini dalam skrip berikut untuk mengecualikan mereka dari daftar zona yang valid.
#!/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";
Jalankan skrip di atas dengan file konfigurasi zona sebagai argumen.
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
Simpan output ke skrip, kirimkan ke shell atau salin dan tempel di terminal Anda untuk membuat rantai baru dan mulai filter semua permintaan DNS yang tidak valid.
jalankan / sbin / iptables -L DNSvalidate -nvx
untuk melihat penghitung paket (dan byte) pada setiap aturan dalam rantai baru (Anda mungkin ingin memindahkan zona dengan sebagian besar paket ke bagian atas daftar untuk membuatnya lebih efisien).
Dengan harapan seseorang mungkin menemukan ini berguna :)