BIND DNS Sunucusunda Rate Limiting ile DDoS ve DNS Amplification Saldırılarına Karşı Koruma

DNS sunucunuza gelen sorgu trafiğini hiç gerçekten analiz ettiniz mi? Çoğu sysadmin bunu yapmaz ve bir gün log dosyalarına baktığında binlerce satır aynı IP’den gelen sorgu görür. İşte o an “keşke rate limiting kurmuş olsaydım” demeye başlarsınız. BIND DNS sunucusunda rate limiting, hem DDoS saldırılarına karşı hem de DNS amplification saldırılarında sunucunuzun silah olarak kullanılmasını engellemek için kritik bir savunma katmanıdır. Bu yazıda sıfırdan yapılandırmayı, gerçek senaryoları ve ince ayarları ele alacağız.

DNS Amplification Saldırısı Nedir ve Neden Önemli?

Önce tehdidin ne olduğunu anlayalım. DNS amplification saldırısında saldırgan, kaynak IP adresini kurbanın IP’si olarak sahteleyerek (spoofing) DNS sunucunuza küçük sorgular gönderir. Sunucunuz ise çok daha büyük yanıtlar üretir ve bunları kurbanın IP’sine gönderir. Örneğin 40 baytlık bir ANY sorgusu, 4000 baytlık bir yanıt üretebilir. Bu 100 kat amplification faktörü demektir.

Peki buradaki asıl problem nedir? Sizin sunucunuz kurban değil, saldırı aracı haline gelir. Hem bant genişliğinizi tüketir hem de başkasına zarar vermiş olursunuz. ISP’ler bu tür trafiği fark ettiğinde sunucunuzun bağlantısını kesebildiği gibi, kötü durumlarda hukuki sorunlar da çıkabilir.

DDoS saldırılarında ise senaryo farklıdır. Saldırgan doğrudan sizin sunucunuzu hedef alır, binlerce bot ile saniyede milyonlarca sorgu gönderir ve sunucunuzun kaynaklarını tüketir. Rate limiting burada da devreye girerek kötü aktörleri throttle eder.

BIND’de Rate Limiting Mekanizması: RRL (Response Rate Limiting)

BIND 9.9.0 sürümüyle birlikte Response Rate Limiting (RRL) özelliği geldi. RRL, belirli bir istemcinin belirli bir zaman diliminde alabileceği yanıt sayısını sınırlar. Eğer limit aşılırsa BIND ya yanıtı siler (drop) ya da yanıt yerine SLIP döndürür, yani her N yanıttan birini gerçekten gönderir.

BIND versiyonunuzu kontrol edelim önce:

named -v
# veya
named --version
# Çıktı: BIND 9.16.x veya üzeri olmalı

RRL için BIND 9.9+ yeterli olsa da, 9.16 ve üzeri sürümlerde ek özellikler ve daha stabil davranış görürsünüz. CentOS/RHEL 8+ ve Ubuntu 20.04+ kullanıyorsanız zaten uygun versiyonu kurulu bulacaksınız.

Temel RRL Yapılandırması

RRL yapılandırması named.conf dosyasındaki options bloğuna eklenir. Önce minimal bir yapılandırmayla başlayalım:

# /etc/named.conf veya /etc/bind/named.conf
options {
    directory "/var/named";
    
    rate-limit {
        # Saniyede istemci başına izin verilen yanıt sayısı
        responses-per-second 10;
        
        # Saniyede istemci başına NXDOMAIN yanıt sayısı
        errors-per-second 5;
        
        # Saniyede istemci başına NODATA yanıt sayısı
        nodata-per-second 5;
        
        # Referral yanıtları için limit
        referrals-per-second 5;
        
        # Slip oranı: Her 2 limiti aşan yanıttan biri gönderilir
        slip 2;
        
        # Log sadece ilk X paketi logla (log flooding'i önler)
        log-only no;
    };
};

Yapılandırmayı uygulamadan önce syntax kontrolü yapın:

named-checkconf /etc/named.conf
# Hata yoksa sessizce çıkar
# Sonra servisi yeniden başlatın
systemctl restart named
# veya
systemctl reload named

Gelişmiş RRL Parametreleri

Gerçek dünyada minimal yapılandırma yetmez. Her ortamın kendine özgü trafiği vardır. İşte tüm parametreler ve açıklamaları:

rate-limit {
    # Temel yanıt limitleri
    responses-per-second 15;
    errors-per-second 5;
    nodata-per-second 5;
    referrals-per-second 5;
    nxdomains-per-second 5;
    
    # Slip değeri: Throttling sırasında kaçta bir yanıt gönderilsin
    # slip 2 = her 2 paketten biri gönderilir (önerilen değer)
    # slip 1 = throttling yok, hepsi gönderilir
    # slip 0 = hiç gönderilmez (drop)
    slip 2;
    
    # Pencere boyutu (saniye cinsinden)
    # Rate limiting istatistiklerinin tutulduğu süre
    window 15;
    
    # Log dosyasında tutulacak maksimum farklı yanıt sayısı
    # Bellek kullanımını sınırlar
    max-table-size 20000;
    min-table-size 500;
    
    # IPv4 için prefix uzunluğu
    # Aynı /24 bloğundaki IP'ler grup olarak sayılır
    ipv4-prefix-length 24;
    
    # IPv6 için prefix uzunluğu
    ipv6-prefix-length 56;
    
    # Belirli IP'leri veya ağları hariç tut
    exempt-clients {
        127.0.0.1;
        ::1;
        192.168.1.0/24;  # İç ağınız
        10.0.0.0/8;      # Diğer güvenilir ağlar
    };
    
    # Sadece log modunda çalıştır (test için)
    log-only no;
};

responses-per-second: Normal istemciler için saniyedeki maksimum yanıt sayısı. Bunu çok düşük ayarlarsanız meşru kullanıcılar etkilenir. 10-20 arası genellikle güvenli bir başlangıç noktasıdır.

slip: Bu parametre çok kritiktir. slip 2 ile her iki throttled paketten biri gerçekten iletilir. Bu sayede meşru istemciler yavaşlasa da tamamen kesilmez. SERVFAIL döndürmek yerine geciktirilmiş yanıt alırlar.

ipv4-prefix-length: Saldırganlar tek IP yerine birden fazla IP kullanabilir. Bu parametre ile aynı /24 bloğunu tek kaynak gibi değerlendirirsiniz.

Log-Only Modu ile Test

Üretim ortamında hemen aktif moda geçmek risklidir. Önce log-only modunda çalıştırın ve trafiğinizi analiz edin:

rate-limit {
    responses-per-second 15;
    errors-per-second 5;
    nodata-per-second 5;
    slip 2;
    window 15;
    
    # Sadece log yaz, engelleme yapma
    log-only yes;
    
    exempt-clients {
        127.0.0.1;
        ::1;
        192.168.0.0/16;
    };
};

Bu modda BIND, rate limit aşılsaydı ne yapacağını log’a yazar ama gerçekten engellemez. Birkaç gün bu şekilde çalıştırın ve logları inceleyin:

# BIND loglarını takip et
tail -f /var/log/named/named.log | grep "rate limit"

# veya syslog kullanıyorsanız
journalctl -u named -f | grep -i "rate"

# Log dosyasındaki rate limit olaylarını say
grep "rate limit" /var/log/named/named.log | wc -l

# En çok rate limit yiyen IP'leri bul
grep "rate limit" /var/log/named/named.log | 
    awk '{print $7}' | sort | uniq -c | sort -rn | head -20

Logging Yapılandırması

RRL’nin etkili olması için düzgün logging şarttır. named.conf‘a logging bloğu ekleyin:

logging {
    channel rate_limit_log {
        file "/var/log/named/rate_limit.log" versions 5 size 50m;
        severity info;
        print-time yes;
        print-severity yes;
        print-category yes;
    };
    
    channel general_log {
        file "/var/log/named/named.log" versions 10 size 100m;
        severity dynamic;
        print-time yes;
        print-severity yes;
        print-category yes;
    };
    
    # Rate limiting olaylarını ayrı dosyaya yaz
    category rate-limit { rate_limit_log; };
    
    # Genel DNS sorgu logları
    category queries { general_log; };
    category default { general_log; };
};

Log dizinini oluşturun ve izinleri ayarlayın:

mkdir -p /var/log/named
chown named:named /var/log/named
chmod 750 /var/log/named

# SELinux kullanıyorsanız (RHEL/CentOS)
semanage fcontext -a -t named_log_t "/var/log/named(/.*)?"
restorecon -R /var/log/named

Saldırı Tespiti ve Analizi

Gerçek bir saldırı senaryosunda ne görürsünüz? Rate limit logları şöyle görünür:

23-Jun-2024 14:32:15.123 rate-limit: info: client 203.0.113.45#54321: rate limit drop response to 8.8.8.8#53 for example.com A
23-Jun-2024 14:32:15.124 rate-limit: info: client 203.0.113.45#54321: rate limit drop response to 8.8.8.8#53 for example.com ANY

Bu logları analiz etmek için basit bir bash scripti yazalım:

#!/bin/bash
# /usr/local/bin/analyze-ratelimit.sh
# Rate limit log analiz scripti

LOG_FILE="/var/log/named/rate_limit.log"
THRESHOLD=100  # Şüpheli kabul edeceğimiz minimum olay sayısı

echo "=== DNS Rate Limit Analiz Raporu ==="
echo "Tarih: $(date)"
echo ""

echo "--- Son 1 saatteki en aktif IP'ler ---"
grep "$(date -d '1 hour ago' '+%d-%b-%Y %H')" "$LOG_FILE" 2>/dev/null | 
    grep "rate limit" | 
    grep -oP 'client K[d.]+' | 
    sort | uniq -c | sort -rn | head -10

echo ""
echo "--- Toplam drop edilen paket sayısı ---"
grep "rate limit drop" "$LOG_FILE" | wc -l

echo ""
echo "--- En çok sorgulanan domain'ler ---"
grep "rate limit" "$LOG_FILE" | 
    awk '{print $NF}' | 
    sort | uniq -c | sort -rn | head -10

echo ""
echo "--- Şüpheli IP'ler (>$THRESHOLD olay) ---"
grep "rate limit" "$LOG_FILE" | 
    grep -oP 'client K[d.]+' | 
    sort | uniq -c | sort -rn | 
    awk -v threshold="$THRESHOLD" '$1 > threshold {print $2 " - " $1 " olay"}'
chmod +x /usr/local/bin/analyze-ratelimit.sh
# Cron'a ekleyin - saatlik çalışsın
echo "0 * * * * root /usr/local/bin/analyze-ratelimit.sh >> /var/log/named/analysis.log 2>&1" >> /etc/crontab

Firewall ile Entegrasyon

Rate limiting tek başına yeterli değildir. Ciddi saldırılarda BIND’ın işlemesi için paketlerin sunucuya ulaşması bile kaynak tüketir. Firewall katmanında da önlem alın:

# firewalld kullanıyorsanız (RHEL/CentOS/Fedora)
# DNS için rate limiting kuralı
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 
    -p udp --dport 53 -m state --state NEW 
    -m recent --set --name dns_limit

firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 1 
    -p udp --dport 53 -m state --state NEW 
    -m recent --update --seconds 60 --hitcount 100 
    --name dns_limit -j DROP

firewall-cmd --reload

# iptables kullanıyorsanız (Ubuntu/Debian eski sistemler)
# Saniyede 20'den fazla DNS UDP paketi gönderen IP'yi engelle
iptables -A INPUT -p udp --dport 53 -m hashlimit 
    --hashlimit-name dns 
    --hashlimit-above 20/sec 
    --hashlimit-burst 50 
    --hashlimit-mode srcip 
    -j DROP

# TCP DNS için de benzer kural
iptables -A INPUT -p tcp --dport 53 -m hashlimit 
    --hashlimit-name dns_tcp 
    --hashlimit-above 10/sec 
    --hashlimit-burst 20 
    --hashlimit-mode srcip 
    -j DROP

# Kuralları kalıcı hale getir
iptables-save > /etc/iptables/rules.v4

Yinelemeli Sorgu Güvenliği (Recursive Query Lockdown)

DNS amplification saldırılarında en büyük risk, sunucunuzun açık resolver (open resolver) olmasıdır. Eğer dünyadaki herhangi bir IP sizin sunucunuza recursive sorgu gönderebiliyorsa, amplification saldırılarında kullanılmaya açıksınız demektir:

options {
    # Recursive sorguya izin verilecek istemciler
    allow-recursion {
        127.0.0.1;
        ::1;
        192.168.0.0/16;    # İç ağınız
        10.0.0.0/8;        # Özel ağlarınız
        172.16.0.0/12;
        # ASLA 'any' yazmayın!
    };
    
    # Sorgu gönderebilecek istemciler (authoritative için)
    allow-query {
        any;  # Authoritative server ise herkese açık olabilir
    };
    
    # Cache'e erişim
    allow-query-cache {
        127.0.0.1;
        ::1;
        192.168.0.0/16;
    };
    
    # Recursive server mısınız? Değilseniz kapatın
    recursion yes;  # Sadece iç ağa hizmet ediyorsanız
    # recursion no;  # Authoritative-only server için
};

Performans İzleme ve Metrikler

BIND’ın kendi istatistik kanalı aracılığıyla rate limiting performansını izleyebilirsiniz:

# named.conf'a statistics kanalı ekleyin
statistics-channels {
    inet 127.0.0.1 port 8080 allow { 127.0.0.1; };
};

İstatistikleri çekmek için:

# rndc ile istatistik dump
rndc stats
cat /var/named/named_stats.txt | grep -A 20 "Rate Limiting"

# HTTP istatistik kanalından XML çek
curl -s http://127.0.0.1:8080/ | grep -i "rate"

# rndc ile anlık durum
rndc status

# Sorgu istatistiklerini göster
rndc querylog on
# Bir süre bekleyin sonra
rndc querylog off

Prometheus ile izleme yapıyorsanız prometheus-bind-exporter kullanabilirsiniz:

# bind_exporter kurulumu
wget https://github.com/prometheus-community/bind_exporter/releases/latest/download/bind_exporter-linux-amd64.tar.gz
tar xvf bind_exporter-linux-amd64.tar.gz
mv bind_exporter /usr/local/bin/

# Systemd service dosyası
cat > /etc/systemd/system/bind-exporter.service << 'EOF'
[Unit]
Description=BIND Exporter for Prometheus
After=network.target

[Service]
User=nobody
ExecStart=/usr/local/bin/bind_exporter 
    --bind.stats-url=http://localhost:8080/
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now bind-exporter

Gerçek Saldırı Senaryosu ve Müdahale

Diyelim ki bir sabah monitoring’inizden alarm geldi. DNS sunucunuz normalin 50 katı traffic alıyor. Adım adım müdahale:

# 1. Adım: Mevcut bağlantıları kontrol et
ss -nup sport = :53 | awk '{print $5}' | cut -d: -f1 | 
    sort | uniq -c | sort -rn | head -20

# 2. Adım: BIND istatistiklerini kontrol et
rndc stats && tail -50 /var/named/named_stats.txt

# 3. Adım: En yoğun sorgulanan domain'leri bul
tcpdump -i eth0 -n port 53 -l 2>/dev/null | 
    grep -oP 'A? K[w.]+' | 
    sort | uniq -c | sort -rn | head -20 &
TCPDUMP_PID=$!
sleep 30
kill $TCPDUMP_PID

# 4. Adım: Saldırgan IP'yi geçici olarak engelle
# (Log analizinden 203.0.113.0/24 bulduğunuzu varsayalım)
iptables -I INPUT -s 203.0.113.0/24 -p udp --dport 53 -j DROP

# 5. Adım: Rate limiting parametrelerini sıkılaştır (çalışan named'e)
# named.conf'u düzenle, sonra reload
sed -i 's/responses-per-second 15/responses-per-second 5/' /etc/named.conf
rndc reload

# 6. Adım: Durumu izle
watch -n 5 'rndc stats && grep "rate limit" /var/named/named_stats.txt'

Yapılandırmayı Test Etme

Rate limiting’in gerçekten çalıştığını doğrulamak için test yapın:

# dig ile yoğun sorgu testi (başka bir makineden)
for i in $(seq 1 100); do
    dig @your-dns-server example.com A +short &
done
wait

# dnsperf aracı ile load test (paket kurulumu gerekebilir)
# Ubuntu/Debian
apt-get install -y dnsperf

# Test için sorgu dosyası oluştur
cat > /tmp/dns_queries.txt << 'EOF'
example.com A
example.com MX
example.com NS
test.example.com A
mail.example.com A
EOF

# 60 saniye boyunca saniyede 100 sorgu gönder
dnsperf -s your-dns-server -d /tmp/dns_queries.txt 
    -c 10 -Q 100 -l 60

# Rate limit'in devreye girip girmediğini kontrol et
grep "rate limit" /var/log/named/rate_limit.log | tail -20

Önerilen Üretim Yapılandırması

Tüm öğrendiklerimizi bir araya getiren tam yapılandırma:

options {
    directory "/var/named";
    
    # Temel güvenlik
    allow-recursion {
        127.0.0.1;
        ::1;
        192.168.0.0/16;
        10.0.0.0/8;
    };
    
    allow-query { any; };
    allow-query-cache { 192.168.0.0/16; 10.0.0.0/8; 127.0.0.1; };
    
    # ANY sorgu tipi genellikle amplification'da kullanılır
    # Minimal yanıt döndür
    minimal-responses yes;
    
    # Response Rate Limiting
    rate-limit {
        responses-per-second 15;
        errors-per-second 5;
        nodata-per-second 5;
        nxdomains-per-second 5;
        referrals-per-second 5;
        
        # Saldırı altındaysanız bu değeri düşürün
        slip 2;
        
        window 15;
        
        max-table-size 20000;
        min-table-size 500;
        
        ipv4-prefix-length 24;
        ipv6-prefix-length 56;
        
        exempt-clients {
            127.0.0.1;
            ::1;
            192.168.0.0/16;
            10.0.0.0/8;
        };
        
        log-only no;
    };
    
    # İstatistik kanalı
    statistics-channels {
        inet 127.0.0.1 port 8080 allow { 127.0.0.1; };
    };
    
    # DNSSEC doğrulama
    dnssec-validation auto;
    
    # Version bilgisini gizle
    version "DNS Server";
};

Sonuç

BIND’da rate limiting kurmak, birkaç satır yapılandırma gibi görünse de arkasında ciddi bir düşünce süreci yatıyor. Değerlerinizi körü körüne kopyalamak yerine kendi trafiğinizi analiz edin. Her ortam farklıdır; bir e-ticaret sitesinin DNS sunucusu ile bir kurumsal iç ağ resolver’ının trafiği birbirinden çok farklı profillere sahiptir.

Yapmanız gerekenleri özetlemek gerekirse: Önce log-only modda en az bir hafta çalıştırıp kendi trafik profilinizi çıkarın. Sonra responses-per-second değerini normal pik trafiğinizin biraz üzerinde ayarlayın. Güvenilir iç ağlarınızı exempt-clients‘a ekleyin. Firewall katmanında hashlimit kuralları ile BIND öncesinde ilk filtrelemeyi yapın. Son olarak da monitoring entegrasyonunu tamamlayıp anomali tespitini otomatikleştirin.

DNS amplification ve DDoS saldırıları giderek daha sofistike hale geliyor. Rate limiting bu savaşta tek silahınız değil ama en temel ve en etkili savunma katmanlarından biri. Sunucunuzu hem saldırının kurbanı olmaktan hem de başkasına yapılan saldırıda araç olarak kullanılmaktan korumak sizin sorumluluğunuz. Bu yapılandırmayı bugün yapın, yarın bunu aramanız için bir neden olmasın.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir