Bir sunucunun dışarıya açık tek bir IP adresi var, ama içeride birden fazla servis çalışıyor. Bu klasik bir senaryo ve çözümü de klasik: DNAT ile port yönlendirme. iptables’ın NAT tablosu bu işi son derece temiz yapıyor, ama doğru yapılandırmazsanız paketler kaybolup gidiyor ve siz saatlerce neden bağlanamadığınızı düşünüp duruyorsunuz. Bu yazıda DNAT’ın nasıl çalıştığını, hangi chain’lerde ne yapmanız gerektiğini ve gerçek dünya senaryolarında nasıl uygulayacağınızı anlatacağım.
DNAT Nedir ve Neden Gereklidir?
DNAT (Destination NAT), gelen bir paketin hedef IP adresini veya portunu değiştirme işlemidir. Yani dışarıdan gelen bir istek “şu IP’nin 80 portuna git” diye yola çıkıyor, ama siz bunu yakalayıp “hayır, şu iç IP’nin 8080 portuna git” diyorsunuz. Paket farklı bir hedefe yönlendirilmiş oluyor.
Bu nerede işe yarar?
- Tek public IP’niz var, ama DMZ’de birden fazla sunucu çalıştırıyorsunuz
- Bir uygulama privileged olmayan bir portta çalışıyor (örneğin 8080), ama dışarıya 80 olarak sunmak istiyorsunuz
- VPN sunucunuz arkasında kalan bir makineye dışarıdan erişim açmak istiyorsunuz
- Load balancer olmadan basit bir trafik dağıtımı yapmak istiyorsunuz
iptables’da DNAT işlemleri nat tablosunun PREROUTING chain’inde yapılır. Neden PREROUTING? Çünkü routing kararı verilmeden önce hedef adresi değiştirmeniz gerekiyor. Eğer paket routing tablosuna girdikten sonra değiştirmeye çalışırsanız, çok geç olmuş olur.
iptables NAT Tablosunun Genel Yapısı
Devam etmeden önce NAT tablosunun chain yapısını netleştirelim:
- PREROUTING: Paket sisteme girdiğinde, routing kararından önce. DNAT burada yapılır.
- POSTROUTING: Paket sistemden çıkmadan hemen önce. SNAT/MASQUERADE burada yapılır.
- OUTPUT: Yerel süreçlerden gelen paketler için. Lokal DNAT gerekiyorsa burada kullanılır.
DNAT için neredeyse her zaman PREROUTING kullanacaksınız. Bunu aklınızın bir köşesine yazın.
Ayrıca DNAT tek başına yetmez. Eğer yönlendirdiğiniz trafik başka bir makineye gidiyorsa, IP forwarding’i de etkinleştirmeniz gerekir:
# Geçici olarak etkinleştir
echo 1 > /proc/sys/net/ipv4/ip_forward
# Kalıcı olarak etkinleştir
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
Bu adımı atlamak, insanların DNAT kurulumunda yaptığı en yaygın hatadır. Kural yazıldı, sözdizimi doğru, ama paketler iç sunucuya ulaşmıyor. Sebebi genellikle IP forwarding’in kapalı olmasıdır.
Temel DNAT Sözdizimi
iptables -t nat -A PREROUTING
-p <protokol>
--dport <hedef-port>
-j DNAT
--to-destination <iç-ip>:<iç-port>
Buradaki parametreleri açıklayalım:
- -t nat: nat tablosunu kullanacağımızı belirtir
- -A PREROUTING: PREROUTING chain’ine kural ekler
- -p: Protokol (tcp veya udp)
- –dport: Dışarıdan gelen isteğin hedef portu
- -j DNAT: DNAT hedefini kullan
- –to-destination: Yeni hedef IP ve port
Şimdi gerçek örneklere geçelim.
Senaryo 1: Dışarıdan Gelen HTTP Trafiğini İç Sunucuya Yönlendirme
Diyelim ki firewall’unuzun public IP’si 203.0.113.10, iç ağınızda bir web sunucusu 192.168.1.100 IP’sinde 80 portunda çalışıyor. Dışarıdan gelen HTTP isteklerini bu sunucuya yönlendirmek istiyorsunuz:
# Dışarıdan gelen 80 portunu iç web sunucusuna yönlendir
iptables -t nat -A PREROUTING
-d 203.0.113.10
-p tcp
--dport 80
-j DNAT
--to-destination 192.168.1.100:80
# FORWARD chain'inde bu trafiğe izin ver
iptables -A FORWARD
-p tcp
-d 192.168.1.100
--dport 80
-j ACCEPT
# İç sunucudan dönen cevaplara da izin ver
iptables -A FORWARD
-p tcp
-s 192.168.1.100
--sport 80
-j ACCEPT
Burada önemli bir nokta var: DNAT kuralı yazdıktan sonra FORWARD chain’inde de izin vermeniz gerekiyor. Pek çok kişi bunu unutur. DNAT sadece hedef adresi değiştirir, paketin geçişine izin vermez. FORWARD chain’i varsayılan olarak DROP politikasındaysa, paketi DNAT ile yönlendirdiniz ama ardından FORWARD engelledi.
Senaryo 2: Port Değiştirerek Yönlendirme
Bu sefer biraz farklı bir durum: Uygulamanız 8443 portunda çalışıyor ama dışarıya 443 olarak sunmak istiyorsunuz:
# Dışarıdan 443'e gelen istekleri iç sunucunun 8443'üne yönlendir
iptables -t nat -A PREROUTING
-p tcp
--dport 443
-j DNAT
--to-destination 192.168.1.50:8443
# FORWARD kuralı
iptables -A FORWARD
-p tcp
-d 192.168.1.50
--dport 8443
-j ACCEPT
# Bağlantı durumuna göre dönüş trafiğini izin ver (daha temiz yöntem)
iptables -A FORWARD
-m state
--state ESTABLISHED,RELATED
-j ACCEPT
Son kural dikkatinizi çekti mi? -m state --state ESTABLISHED,RELATED kullanmak, her servis için ayrı ayrı dönüş kuralı yazmaktan çok daha temiz ve güvenlidir. Eğer zaten bu genel kuralınız varsa, her DNAT için tekrar dönüş kuralı yazmanıza gerek yok.
Senaryo 3: Belirli Bir Kaynak IP’den Gelen Trafiği Yönlendirme
Sadece belirli bir IP bloğundan gelen istekleri yönlendirmek isteyebilirsiniz. Örneğin ofis ağınızdan gelen SSH trafiğini iç bir jump host’a yönlendirmek:
# Sadece ofis ağından gelen SSH'ı iç jump host'a yönlendir
iptables -t nat -A PREROUTING
-s 10.20.30.0/24
-p tcp
--dport 22
-j DNAT
--to-destination 192.168.1.200:22
# FORWARD izni
iptables -A FORWARD
-s 10.20.30.0/24
-d 192.168.1.200
-p tcp
--dport 22
-j ACCEPT
Bu yaklaşım güvenlik açısından çok daha sağlam. Belirli bir kaynak IP’ye kısıtlayarak saldırı yüzeyini minimize ediyorsunuz.
Senaryo 4: Birden Fazla Portu Tek Seferde Yönlendirme
iptables, port aralığı belirlemenize de izin veriyor. Örneğin bir FTP sunucusu için kontrol portu ve pasif port aralığını yönlendirmeniz gerekebilir:
# FTP kontrol portu
iptables -t nat -A PREROUTING
-p tcp
--dport 21
-j DNAT
--to-destination 192.168.1.150:21
# FTP pasif port aralığı (50000-51000)
iptables -t nat -A PREROUTING
-p tcp
--dport 50000:51000
-j DNAT
--to-destination 192.168.1.150:50000-51000
# FORWARD izinleri
iptables -A FORWARD
-d 192.168.1.150
-p tcp
-m multiport
--dports 21,50000:51000
-j ACCEPT
Port aralığı yönlendirmede kaynak ve hedef port sayısının eşleşmesi gerekir. 50000:51000‘i 50000-51000‘e yönlendirdiğinizde iptables bunu otomatik olarak eşleştirir.
Senaryo 5: Yerel Makineye Port Yönlendirme (Loopback Sorunu)
Bu senaryo biraz farklı ve sık sık kafaları karıştırır. Diyelim ki firewall makinesinin kendisinde çalışan bir servise dışarıdan farklı bir porttan erişmek istiyorsunuz. Örneğin 8080’de çalışan uygulamayı 80 olarak sunmak:
# Dışarıdan gelen 80'i localhost 8080'e yönlendir
iptables -t nat -A PREROUTING
-p tcp
--dport 80
-j REDIRECT
--to-port 8080
Burada DNAT yerine REDIRECT kullandım. REDIRECT, DNAT’ın özel bir halidir ve hedefi otomatik olarak localhost yapar. Aynı makinedeki port yönlendirmeleri için çok daha temizdir.
Ama şimdi şunu düşünün: Aynı makinede çalışan bir uygulama veya local bir kullanıcı bu servise http://localhost ile erişmeye çalışırsa ne olur? PREROUTING chain’i sadece dışarıdan gelen paketler için çalışır, yerel trafiğe uygulanmaz. Bu durumda OUTPUT chain’inde de bir kural gerekir:
# Yerel trafiği de yönlendir
iptables -t nat -A OUTPUT
-p tcp
-d 127.0.0.1
--dport 80
-j REDIRECT
--to-port 8080
Kurallari Kalici Hale Getirme
iptables kuralları yeniden başlatmada silinir. Bunları kalıcı hale getirmenin birkaç yolu var:
Debian/Ubuntu için:
# iptables-persistent kur
apt-get install iptables-persistent
# Mevcut kuralları kaydet
netfilter-persistent save
# Veya manuel olarak
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
RHEL/CentOS için:
# Kuralları kaydet
service iptables save
# Veya
iptables-save > /etc/sysconfig/iptables
Systemd service olarak kaydetmek için:
# Kuralları bir dosyaya kaydet
iptables-save > /etc/iptables.rules
# Restore scripti oluştur
cat > /etc/network/if-pre-up.d/iptables << 'EOF'
#!/bin/bash
iptables-restore < /etc/iptables.rules
EOF
chmod +x /etc/network/if-pre-up.d/iptables
Mevcut DNAT Kurallarını Görüntüleme ve Yönetme
Kuralları ekledikçe ne olduğunu takip etmek önemli. NAT tablosunu görüntülemek için:
# NAT tablosundaki tüm kuralları listele
iptables -t nat -L -n -v
# PREROUTING chain'ini özellikle görüntüle
iptables -t nat -L PREROUTING -n -v --line-numbers
# Kural numaralarıyla birlikte tüm tabloları göster
iptables -t nat -S
--line-numbers parametresi önemli, çünkü belirli bir kuralı silmek istediğinizde satır numarasına ihtiyaç duyuyorsunuz:
# 3 numaralı PREROUTING kuralını sil
iptables -t nat -D PREROUTING 3
# Veya kuralın kendisini yazarak sil (-A yerine -D)
iptables -t nat -D PREROUTING
-p tcp
--dport 80
-j DNAT
--to-destination 192.168.1.100:80
Sorun Giderme
DNAT çalışmıyorsa sistematik bir kontrol listesi şöyle olmalı:
1. IP forwarding kontrolü:
cat /proc/sys/net/ipv4/ip_forward
# 1 döndürmeli, 0 ise aktif değil
2. NAT kuralının doğru yazıldığını kontrol et:
iptables -t nat -L PREROUTING -n -v
# Hit sayacının artıp artmadığına bak
3. FORWARD chain’ini kontrol et:
iptables -L FORWARD -n -v
# İlgili port için DROP veya REJECT var mı?
4. Paket izleme ile canlı debug:
# conntrack ile bağlantıları izle
conntrack -L | grep <port>
# iptables LOG target ile debug
iptables -t nat -A PREROUTING
-p tcp
--dport 80
-j LOG
--log-prefix "DNAT-DEBUG: "
--log-level 4
# Log'u izle
tail -f /var/log/syslog | grep "DNAT-DEBUG"
5. Hedef sunucunun paketleri alıp almadığını kontrol et:
# Hedef sunucuda tcpdump çalıştır
tcpdump -i eth0 -n port 80
# Paketler geliyorsa ama cevap gitmiyorsa, hedef sunucunun
# default gateway'ini kontrol et. Cevap paketleri doğru
# yoldan çıkmazsa asimetrik routing sorunu yaşarsınız.
Asimetrik routing önemli bir nokta. Hedef sunucunun cevap paketlerini firewall üzerinden göndermesi gerekiyor, yoksa client SYN gönderdi ama SYN-ACK farklı bir yoldan geldi ve bağlantı kurulamadı. Hedef sunucunun default gateway’i mutlaka firewall/router makineniz olmalı.
Hairpin NAT (Loopback NAT) Sorunu
Bu bir baş ağrısıdır ve mutlaka bahsetmem gerekiyor. Diyelim ki iç ağdaki bir makine (192.168.1.50), public IP üzerinden iç bir sunucuya erişmeye çalışıyor. Yani 203.0.113.10:80‘e istek gönderiyor, siz bunu 192.168.1.100:80‘e yönlendirdiniz. Ama istek yine de iç ağdan geliyor.
Bu durumda PREROUTING çalışır, paketi 192.168.1.100‘e yönlendirir. Ama 192.168.1.100 cevabı doğrudan 192.168.1.50‘ye gönderir çünkü aynı subnet’teler. Client ise cevabın 203.0.113.10‘dan gelmesini bekliyor. Bağlantı kopuyor.
Çözümü MASQUERADE kullanmak:
# İç ağdan public IP'ye giden ve DNAT'lanan trafik için MASQUERADE ekle
iptables -t nat -A POSTROUTING
-s 192.168.1.0/24
-d 192.168.1.100
-p tcp
--dport 80
-j MASQUERADE
Bu kural sayesinde iç ağdan gelen ve DNAT ile yönlendirilen istekler, firewall’un iç IP’si üzerinden gidiyormuş gibi görünür. Hedef sunucu cevabı firewall’a gönderir, firewall da doğru client’a iletir.
Güvenlik Notları
DNAT güçlü bir araç ama dikkatli kullanılmazsa güvenlik açıkları yaratabilir:
- En az ayrıcalık prensibi: Sadece gerekli portları açın. “Sonra kapatırım” diyerek açtığınız portlar genellikle sonsuza kadar açık kalır.
- Kaynak IP kısıtlaması: Mümkünse
-sparametresiyle kaynak IP’yi kısıtlayın. - Rate limiting ekleyin: Açık portlara brute force saldırılarını önlemek için
-m limitveya-m recentkullanın. - Log tutun: Kritik portlara gelen bağlantıları loglayın, anormal trafik erken fark edilsin.
- Düzenli audit: Periyodik olarak
iptables -t nat -L -n -vçıktısını gözden geçirin. Unutulmuş kurallar birikerek güvenlik riski oluşturur.
Sonuç
DNAT, iptables’ın en pratik özelliklerinden biri. Tek public IP’ye sahip küçük bir ağdan kurumsal DMZ mimarisine kadar pek çok senaryoda hayat kurtarıyor. Ama doğru çalışması için üç şeyi aklınızda tutun: IP forwarding açık olmalı, FORWARD chain’inde ilgili trafiğe izin verilmeli ve hedef sunucunun default gateway’i doğru ayarlanmış olmalı. Bu üçü yerli yerindeyse DNAT genellikle sorunsuz çalışır.
Asimetrik routing ve hairpin NAT gibi edge case’ler bazen sinir bozucu olabiliyor, ama sistematik bir debug yaklaşımıyla bunları da çözmek mümkün. conntrack -L ve tcpdump bu süreçte en iyi dostlarınız olacak.
Son olarak, production ortamına kuralı uygulamadan önce her zaman test ortamında deneyin ve kuralları mutlaka kalıcı hale getirmeyi unutmayın. Yeniden başlatmada kaybolan bir DNAT kuralı, gece yarısı telefon almak anlamına gelebilir.