Unbound’da RPZ ile DNS Tabanlı İçerik Filtreleme

DNS filtreleme deyince aklınıza ne geliyor? Çoğu sysadmin “Pi-hole kurarım olur biter” diye düşünür. Pi-hole harika bir araç, bunu tartışmıyorum. Ama kurumsal bir ortamda, özellikle kendi Unbound altyapınız varsa, RPZ (Response Policy Zones) ile çok daha esnek ve güçlü bir filtreleme mekanizması kurabilirsiniz. Bu yazıda size Unbound’da RPZ’yi nasıl yapılandıracağınızı, gerçek dünya senaryolarında nasıl kullanacağınızı ve olası tuzaklardan nasıl kaçınacağınızı anlatacağım.

RPZ Nedir ve Neden Önemlidir?

RPZ, DNS sunucunuzun belirli alan adlarına verdiği cevapları manipüle etmenize olanak tanıyan bir mekanizmadır. IETF tarafından standartlaştırılan bu yapı, önce BIND’da hayat buldu, Unbound ise 1.14.0 sürümüyle birlikte RPZ desteğini getirdi.

Klasik DNS filtreleme yaklaşımlarına göre RPZ’nin avantajları şunlardır:

  • Standart format: RPZ, DNS zone dosyası formatını kullandığı için farklı platformlar arasında taşınabilir
  • Merkezi yönetim: Tek bir zone dosyasını güncelleyerek tüm filtreleme kurallarınızı yönetebilirsiniz
  • Zengin aksiyon seçenekleri: Sadece “engelle” değil, yönlendir, NXDOMAIN döndür, NODATA döndür gibi farklı aksiyonlar tanımlayabilirsiniz
  • Otomatik güncelleme: Zone transfer mekanizmasıyla filtreleme listelerinizi otomatik olarak güncelleyebilirsiniz
  • Entegrasyon kolaylığı: Threat intelligence feed’leriyle doğrudan entegre edilebilir

Unbound’da RPZ Desteği: Ön Koşullar

Önce Unbound versiyonunuzu kontrol edin:

unbound -V | head -3

1.14.0 altındaki sürümlerde RPZ desteği yoktur. Eğer eski bir sürüm kullanıyorsanız, güncellemek zorundasınız. Ubuntu/Debian sistemlerde:

apt update && apt install unbound
unbound-checkconf

CentOS/RHEL sistemlerde EPEL reposunu etkinleştirmeniz gerekebilir:

dnf install epel-release
dnf update unbound

Unbound’un RPZ ile derlenip derlenmediğini doğrulamak için:

unbound -V | grep "rpz"

Bu komutun çıktısında rpz geçmiyorsa, Unbound’unuz RPZ desteği olmadan derlenmiş demektir. Bu durumda kaynaktan derleme ya da farklı bir repo kullanmak gerekir.

RPZ Zone Dosyası Yapısı

RPZ, standart bir DNS zone dosyasıdır. Fakat bazı özel kayıt türleri ve adlandırma kuralları içerir. Hadi sıfırdan bir RPZ zone dosyası oluşturalım:

mkdir -p /etc/unbound/rpz
cat > /etc/unbound/rpz/blocklist.rpz << 'EOF'
$ORIGIN rpz.local.
$TTL 300
@ SOA localhost. admin.localhost. (
    2024010101  ; Serial
    3600        ; Refresh
    900         ; Retry
    604800      ; Expire
    300 )       ; Minimum TTL

; Name Server kaydı
@ NS localhost.

; Engellenen alan adları - NXDOMAIN döndür
malware-site.com.rpz.local.  CNAME .
phishing-example.net.rpz.local. CNAME .
ads.tracker.io.rpz.local. CNAME .

; Wildcard ile tüm subdomain'leri engelle
*.malware-site.com.rpz.local. CNAME .

; NODATA döndür (alan adı var ama kayıt yok gibi davran)
analytics-heavy.com.rpz.local. CNAME *.

; Özel bir IP'ye yönlendir (walled garden)
blocked-content.org.rpz.local. A 192.168.1.100
EOF

Burada CNAME . (nokta) NXDOMAIN, CNAME *. ise NODATA aksiyonunu temsil eder. Bu RPZ’ye özgü sözleşmelerdir, normal DNS mantığıyla çalışmaz.

Unbound Yapılandırması

RPZ zone dosyanızı oluşturduktan sonra Unbound’a bunu tanıtmanız gerekiyor. /etc/unbound/unbound.conf dosyanıza ya da /etc/unbound/conf.d/ altına yeni bir dosya ekleyin:

cat > /etc/unbound/conf.d/rpz.conf << 'EOF'
rpz:
    name: "rpz.local."
    zonefile: "/etc/unbound/rpz/blocklist.rpz"
    rpz-action-override: nxdomain
    rpz-log: yes
    rpz-log-name: "blocklist"
    tags: ["default"]
EOF

Yapılandırmayı test edin ve servisi yeniden başlatın:

unbound-checkconf
systemctl restart unbound

Burada dikkat etmeniz gereken birkaç parametre var:

  • rpz-action-override: Zone dosyasındaki aksiyon ne olursa olsun bu değeri uygular, debug için kullanışlı
  • rpz-log: RPZ tarafından işlenen sorguları loglar
  • rpz-log-name: Log mesajlarında görünecek etiket, birden fazla RPZ zone’u varsa ayırt etmenizi sağlar

Gerçek Dünya Senaryosu 1: Reklam ve İzleyici Engelleme

Şirketteki kullanıcılardan gelen şikayetler tanıdık geliyordur: “İnternet yavaş, sayfalar geç açılıyor.” Çoğu durumda sorun reklam ağlarından gelen onlarca DNS sorgusu. RPZ ile bu sorguları DNS seviyesinde kesebilirsiniz.

Popüler reklam engelleme listelerini RPZ formatına çeviren bir betik yazalım:

#!/bin/bash
# hosts formatındaki listeleri RPZ formatına çevirir

HOSTS_URL="https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
RPZ_FILE="/etc/unbound/rpz/ads.rpz"
RPZ_ZONE="ads.rpz.local."
SERIAL=$(date +%Y%m%d%H)

# Geçici dosya
TMP=$(mktemp)

# Header yaz
cat > "$RPZ_FILE" << HEADER
$ORIGIN ${RPZ_ZONE}
$TTL 300
@ SOA localhost. admin.localhost. (
    ${SERIAL}
    3600
    900
    604800
    300 )
@ NS localhost.
HEADER

# Hosts dosyasını indirip çevir
curl -s "$HOSTS_URL" | 
    grep "^0.0.0.0" | 
    grep -v "0.0.0.0 0.0.0.0" | 
    awk '{print $2}' | 
    grep -v "^#" | 
    grep -v "^$" | 
    sort -u | 
    while read domain; do
        echo "${domain}.${RPZ_ZONE}  CNAME ."
    done >> "$RPZ_FILE"

echo "RPZ dosyası güncellendi: $(wc -l < $RPZ_FILE) satır"
rm -f "$TMP"

# Unbound'u yeniden yükle
unbound-control reload

Bu betiği cron’a ekleyin:

chmod +x /usr/local/bin/update-rpz-ads.sh
echo "0 3 * * * root /usr/local/bin/update-rpz-ads.sh >> /var/log/rpz-update.log 2>&1" > /etc/cron.d/rpz-update

Gerçek Dünya Senaryosu 2: Kurumsal Güvenlik Politikası

Bir finans şirketinde çalıştığınızı düşünün. Belirli kategorilerdeki siteleri engellemek zorunda olduğunuzu varsayalım: kumar siteleri, sosyal medya (mesai saatlerinde), veya bilinen zararlı yazılım dağıtım noktaları.

Burada farklı bir yaklaşım denenebilir: birden fazla RPZ zone’u tanımlamak ve öncelik sırasıyla çalıştırmak.

cat > /etc/unbound/conf.d/rpz-multi.conf << 'EOF'
# Öncelik 1: Güvenlik tehditleri - her zaman aktif
rpz:
    name: "security.rpz.local."
    zonefile: "/etc/unbound/rpz/security-threats.rpz"
    rpz-log: yes
    rpz-log-name: "security"

# Öncelik 2: Yasal zorunluluklar
rpz:
    name: "legal.rpz.local."
    zonefile: "/etc/unbound/rpz/legal-blocks.rpz"
    rpz-log: yes
    rpz-log-name: "legal"

# Öncelik 3: Kurumsal politika
rpz:
    name: "policy.rpz.local."
    zonefile: "/etc/unbound/rpz/corporate-policy.rpz"
    rpz-log: yes
    rpz-log-name: "policy"
EOF

Unbound, RPZ zone’larını yapılandırma dosyasında göründükleri sıraya göre değerlendirir. İlk eşleşen kural uygulanır. Bu nedenle güvenlik kurallarını her zaman önce tanımlayın.

Walled Garden: Engellenen Siteleri Özel Sayfaya Yönlendirme

NXDOMAIN döndürmek bazen kullanıcı deneyimi açısından kötü olabilir. Kullanıcı “Bu site neden açılmıyor, DNS mi bozuldu?” diye düşünebilir. Daha profesyonel bir yaklaşım, engellenen siteleri bir açıklama sayfasına yönlendirmektir.

Bunun için önce engelleme sunucunuzda bir web servisi kurmanız gerekiyor:

# Nginx ile basit bir engel sayfası
apt install nginx

cat > /etc/nginx/sites-available/blocked << 'EOF'
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    root /var/www/blocked;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}
EOF

mkdir -p /var/www/blocked
cat > /var/www/blocked/index.html << 'HTML'
<!DOCTYPE html>
<html>
<head><title>Erişim Engellendi</title></head>
<body>
<h1>Bu içeriğe erişim kurumsal politika gereği engellenmiştir.</h1>
<p>Bilgi için IT departmanıyla iletişime geçin.</p>
</body>
</html>
HTML

ln -s /etc/nginx/sites-available/blocked /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

Şimdi RPZ zone dosyanızda A kaydıyla bu sunucuya yönlendirin:

cat > /etc/unbound/rpz/policy-walled.rpz << 'EOF'
$ORIGIN policy.rpz.local.
$TTL 300
@ SOA localhost. admin.localhost. (
    2024010101
    3600
    900
    604800
    300 )
@ NS localhost.

; Engellenen siteler walled garden'a yönlenir
social-media-site.com.policy.rpz.local. A 192.168.1.200
*.social-media-site.com.policy.rpz.local. A 192.168.1.200
EOF

RPZ Loglarını İzleme ve Analiz

RPZ ne kadar iş yapıyor? Hangi domainler en çok engelleniyor? Bu soruların cevaplarını bulmak için log analizini otomatikleştirmek işinizi kolaylaştırır:

#!/bin/bash
# RPZ engelleme istatistikleri
# Çalıştırma: ./rpz-stats.sh [son kaç saat]

HOURS=${1:-24}
LOG_FILE="/var/log/unbound/unbound.log"
SINCE=$(date -d "${HOURS} hours ago" "+%b %e %H:%M:%S" 2>/dev/null || 
        date -v-${HOURS}H "+%b %e %H:%M:%S")

echo "=== Son ${HOURS} saat RPZ İstatistikleri ==="
echo ""

echo "En çok engellenen 10 domain:"
grep "rpz applied" "$LOG_FILE" | 
    grep -v "^$" | 
    awk '{print $NF}' | 
    sort | uniq -c | sort -rn | head -10

echo ""
echo "Zone bazında engelleme sayıları:"
grep "rpz applied" "$LOG_FILE" | 
    grep -oP 'rpz-log-name: K[^,]+' | 
    sort | uniq -c | sort -rn

echo ""
echo "Saatlik engelleme grafiği:"
grep "rpz applied" "$LOG_FILE" | 
    awk '{print $1, $2, substr($3,1,2)}' | 
    sort | uniq -c | 
    awk '{printf "%s %s %s:00 -> %d engellemen", $2, $3, $4, $1}'

Zone Transfer ile Merkezi RPZ Yönetimi

Büyük ortamlarda her sunucuda ayrı ayrı RPZ dosyası güncellemek pratik değil. BIND ile birlikte kullanarak zone transfer mekanizmasından yararlanabilirsiniz. Master BIND sunucusu RPZ zone’unu barındırır, Unbound slave olarak çeker.

BIND tarafında (master):

# named.conf içine eklenecek zone tanımı
zone "rpz.example.com" {
    type master;
    file "/var/named/rpz.example.com.zone";
    allow-transfer { 192.168.1.10; 192.168.1.11; };  # Unbound sunucularının IP'leri
    notify yes;
};

Unbound tarafında zone transfer ayarları:

cat >> /etc/unbound/conf.d/rpz.conf << 'EOF'

rpz:
    name: "rpz.example.com."
    master: 192.168.1.1        # BIND master sunucusu
    allow-notify: 192.168.1.1
    rpz-log: yes
    rpz-log-name: "central-rpz"
    fallback-enabled: yes       # RPZ erişilemezse normal çözümlemeye dön
EOF

fallback-enabled parametresine dikkat edin. Bu, RPZ zone’u güncellenemediğinde ya da bağlantı koptuğunda DNS çözümlemesinin tamamen durmasını önler. Kurumsal ortamlarda bu parametreyi mutlaka aktif edin.

Sık Karşılaşılan Sorunlar ve Çözümleri

Sorun 1: RPZ kuralları uygulanmıyor

İlk kontrol noktanız her zaman yapılandırma doğrulaması olmalı:

unbound-checkconf /etc/unbound/unbound.conf

# RPZ'nin aktif olup olmadığını kontrol et
unbound-control status | grep rpz

# Test sorgusu
dig @127.0.0.1 engellenmesi-gereken-site.com

Eğer hala çalışmıyorsa, zone dosyanızın söz dizimini kontrol edin. En yaygın hata, alan adlarının sonuna nokta koymamak ya da zone origin’i yanlış belirtmek.

Sorun 2: Meşru siteler engelleniyor (False Positive)

RPZ zone’unuza whitelist mekanizması ekleyebilirsiniz. Unbound’da RPZ zone’ları öncelik sırasına göre işlenir, bu nedenle en yüksek öncelikli zone’a izin verilen domainleri passthru aksiyonuyla ekleyin:

# whitelist.rpz dosyasına ekle
legitimate-but-blocked.com.whitelist.rpz.local. CNAME rpz-passthru.

rpz-passthru özel bir CNAME değeridir. Bu aksiyonla eşleşen domain diğer RPZ kurallarından muaf tutulur ve normal DNS çözümlemesine tabi olur.

Sorun 3: Yüksek CPU kullanımı

Çok büyük RPZ zone dosyaları (100.000+ kayıt) Unbound’un bellek ve CPU kullanımını artırabilir. Bu durumda:

  • Zone dosyasını mantıksal parçalara bölün
  • Wildcard kurallarını optimize edin, gereksiz subdomain listelerinden kaçının
  • Unbound’un num-threads değerini artırın
  • msg-cache-size ve rrset-cache-size değerlerini gözden geçirin

Güvenlik Notları

RPZ güçlü bir araç ama yanlış ellerde sorun çıkarabilir. Zone dosyalarınıza erişimi kısıtlayın:

chown root:unbound /etc/unbound/rpz/
chmod 750 /etc/unbound/rpz/
chown root:unbound /etc/unbound/rpz/*.rpz
chmod 640 /etc/unbound/rpz/*.rpz

Zone transfer kullanıyorsanız TSIG anahtarları ile kimlik doğrulama ekleyin. Açık zone transfer, saldırganlara hangi siteleri engellediğiniz hakkında değerli bilgi verir.

Ayrıca RPZ’nin DNS over HTTPS veya DNS over TLS kullanan istemcileri etkilemeyeceğini unutmayın. Kurumsal ortamlarda bu alternatifleri engellemek ya da kendi DoH/DoT sunucunuzu kurmak gerekebilir.

Sonuç

Unbound’da RPZ ile DNS tabanlı içerik filtreleme, basit hosts dosyası tabanlı yaklaşımların çok ötesinde bir esneklik sunar. Birden fazla zone, farklı aksiyon türleri, merkezi yönetim ve otomatik güncellemeler ile kurumsal ölçekte güvenilir bir filtreleme altyapısı kurabilirsiniz.

Pratikte gördüğüm en yaygın kullanım senaryosu şu şekilde oluyor: tehdit istihbarat servisleri (örneğin abuse.ch, Spamhaus) zaten RPZ formatında feed sağlıyor, bunları doğrudan Unbound’a bağlayarak sıfır elle müdahaleyle güncel bir güvenlik katmanı elde ediyorsunuz. Buna kurumsal politika kurallarınızı, reklam engelleyicilerinizi ve whitelist’lerinizi ekleyince oldukça sağlam bir yapı ortaya çıkıyor.

Başlarken küçük tutun: tek bir zone, birkaç yüz kural, önce test ortamında. Logları inceleyin, false positive oranını sıfıra yaklaştırdıktan sonra production’a alın. DNS filtreleme, yanlış yapılandırıldığında kullanıcıları meşru sitelere erişemez hale getirebilir. fallback-enabled ve whitelist mekanizmalarını ihmal etmeyin.

Bir yanıt yazın

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