ก่อนอื่นฉันรู้ว่านี่เป็นคำถามเก่า แต่ ...
ฉันใช้เซิร์ฟเวอร์ DNS ที่เชื่อถือได้และไม่ต้องทำซ้ำมานานหลายทศวรรษ แต่ไม่เคยตกเป็นเหยื่อของการโจมตี DDoS ที่ใช้ DNS เลยจนกระทั่งตอนนี้เมื่อฉันเปลี่ยนไปใช้ ISP ใหม่ การสืบค้น DNS ปลอมแปลงหลายพันรายการทำให้บันทึกของฉันท่วมท้นและฉันรำคาญมาก - ไม่มากเกี่ยวกับผลกระทบต่อเซิร์ฟเวอร์ของฉัน แต่ความจริงแล้วมันรกแฟ้มบันทึกของฉัน ดูเหมือนว่าผู้โจมตีพยายามที่จะใช้ DNS ของฉันในการ " โจมตีเซิร์ฟเวอร์ชื่อที่มีสิทธิ์ "
ดังนั้นฉันจึงคิดว่าแม้ว่าฉันจะ จำกัด เคียวรีแบบเรียกซ้ำภายในเครือข่ายของฉัน (ปฏิเสธทั้งหมด) ฉันก็ใช้วงจรของ CPU ในการจับคู่สตริงใน iptables มากกว่าส่งการตอบกลับเชิงลบไปยังที่อยู่ IP ที่ปลอมแปลง (ถ่วงน้อยลงในบันทึกของฉัน ปริมาณการใช้เครือข่ายและระดับความพึงพอใจที่สูงขึ้นของฉัน)
ฉันเริ่มต้นด้วยการทำเหมือนคนอื่น ๆ ทำค้นหาชื่อโดเมนที่มีการสอบถามและสร้างสตริงที่ตรงกับโดเมนที่มีเป้าหมาย DROP แต่ในไม่ช้าฉันก็รู้ว่าฉันจะจบลงด้วยกฎจำนวนมากแต่ละอันใช้เวลาในการประมวลผลของ CPU ดังนั้นจะทำอย่างไร? เนื่องจากฉันไม่ได้เรียกใช้เซิร์ฟเวอร์ชื่อซ้ำฉันคิดว่าฉันอาจทำการจับคู่ในโซนจริงฉันมีสิทธิ์และวางทุกอย่างอื่น
นโยบายเริ่มต้นของฉันใน iptables คือยอมรับหากนโยบายของคุณเป็น 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;
};
หมายเหตุความคิดเห็น“ // ส่วนตัว” ในสองโซนแรกของฉันฉันใช้สิ่งนี้ในสคริปต์ต่อไปนี้เพื่อแยกพวกเขาออกจากรายการของโซนที่ถูกต้อง
#!/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 ที่ไม่ถูกต้องทั้งหมด
run / sbin / iptables -L DNSvalidate -nvx
เพื่อดูเคาน์เตอร์แพ็คเก็ต (และไบต์) ในแต่ละกฎในเชนใหม่ (คุณอาจต้องการย้ายโซนด้วยแพ็กเก็ตส่วนใหญ่ไปด้านบนของรายการเพื่อให้มีประสิทธิภาพมากขึ้น)
ด้วยความหวังว่าบางคนอาจพบว่ามีประโยชน์นี้ :)