ipset ile Linux Güvenlik Duvarında IP Kümesi Yönetimi ve Kara Liste Oluşturma

Yıllar önce bir müşterinin sunucusunda ilginç bir sorunla karşılaştım. Sunucu sürekli yavaşlıyor, iptables kuralları binlerce satıra ulaşmış ve her yeni bağlantıda kernel bu devasa kural listesini baştan sona taramak zorunda kalıyordu. Adam iyi niyetle her kötü IP’yi ayrı bir iptables kuralıyla engellemiş ama farkında olmadan sistemi felç etmişti. İşte o gün ipset’i ciddiye almaya başladım.

ipset Nedir ve Neden iptables’tan Farklıdır

iptables, kuralları sırayla işler. 10.000 IP adresinizi engellemek istiyorsanız, her gelen paket için kernel bu 10.000 kuralı tek tek kontrol eder. Bu, hem CPU hem de bellek açısından ciddi bir yük demektir. ipset ise bu problemi tamamen farklı bir yaklaşımla çözer.

ipset, kernel tarafında hash tabloları kullanarak IP adreslerini, ağ bloklarını, port kombinasyonlarını ve MAC adreslerini “küme” olarak depolar. Bir IP’nin bu kümede olup olmadığını kontrol etmek, kural sayısından bağımsız olarak O(1) karmaşıklığında gerçekleşir. Yani 10 IP’yi de 10 milyon IP’yi de pratik olarak aynı hızda sorgulayabilirsiniz.

iptables ile entegrasyon ise gayet zarif: Binlerce kural yerine tek bir kural yazarsınız ve bu kural tüm kümeye karşı kontrol yapar.

Kurulum ve Temel Başlangıç

Çoğu modern dağıtımda ipset paket depolarında hazır gelir:

# Debian/Ubuntu
sudo apt-get install ipset

# RHEL/CentOS/Rocky Linux
sudo yum install ipset
# veya
sudo dnf install ipset

# Arch Linux
sudo pacman -S ipset

Kurulumdan sonra kernel modülünü yükleyin:

sudo modprobe ip_set
sudo modprobe ip_set_hash_ip
sudo modprobe ip_set_hash_net
lsmod | grep ip_set

Modüller yüklendiyse artık başlayabiliriz.

Küme Tipleri ve Seçenekleri

ipset birkaç farklı küme tipi sunar. Hangisini kullanacağınız senaryonuza göre değişir:

  • hash:ip — Tekil IP adresleri için, en yaygın kullanılan tip
  • hash:net — CIDR notasyonuyla ağ blokları için (192.168.1.0/24 gibi)
  • hash:ip,port — IP ve port kombinasyonları için
  • hash:net,port — Ağ bloğu ve port kombinasyonları için
  • hash:mac — MAC adresleri için
  • list:set — Diğer kümeleri referans eden meta-kümeler için
  • bitmap:ip — Küçük IP aralıkları için, hash yerine bitmap kullanır

Kümeler oluştururken dikkat etmeniz gereken bazı parametreler var:

  • maxelem — Kümede tutulabilecek maksimum eleman sayısı, varsayılan 65536
  • timeout — Elemanların otomatik silineceği süre (saniye cinsinden), 0 ise sonsuz
  • hashsize — Hash tablosunun başlangıç boyutu, performansı etkiler
  • family inet — IPv4 adresleri için
  • family inet6 — IPv6 adresleri için

İlk Küme Oluşturma ve Temel İşlemler

Hemen pratiğe geçelim. Basit bir kara liste kümesi oluşturalım:

# Kara liste kümesi oluştur
sudo ipset create blacklist hash:ip maxelem 100000

# Kümeye IP ekle
sudo ipset add blacklist 192.168.1.100
sudo ipset add blacklist 10.0.0.5
sudo ipset add blacklist 203.0.113.45

# Kümenin içeriğini listele
sudo ipset list blacklist

# Belirli bir IP'nin kümede olup olmadığını test et
sudo ipset test blacklist 192.168.1.100
# "192.168.1.100 is in set blacklist." çıktısını verir

# IP'yi kümeden sil
sudo ipset del blacklist 10.0.0.5

# Tüm kümeleri listele
sudo ipset list -n

Şimdi bu kümeyi iptables ile bağlayalım:

# Kara listedeki tüm IP'lerden gelen trafiği engelle
sudo iptables -I INPUT -m set --match-set blacklist src -j DROP

# Kara listedeki IP'lere giden trafiği de engelle
sudo iptables -I OUTPUT -m set --match-set blacklist dst -j DROP

# Sadece belirli bir porta gelen trafiği engelle
sudo iptables -I INPUT -p tcp --dport 80 -m set --match-set blacklist src -j DROP

Ağ Blokları ile Çalışmak

Ülke bazlı engelleme veya belirli ASN bloklarını engellemek istediğinizde hash:net tipi devreye girer:

# Ağ blokları için küme oluştur
sudo ipset create country_block hash:net maxelem 500000

# Ağ bloklarını ekle
sudo ipset add country_block 185.220.0.0/16
sudo ipset add country_block 45.142.0.0/16
sudo ipset add country_block 194.165.16.0/22

# iptables kuralı
sudo iptables -I INPUT -m set --match-set country_block src -j DROP

Ülke bazlı engelleme için MaxMind GeoIP veritabanlarını veya ipdeny.com gibi kaynakları kullanabilirsiniz. Şöyle bir script işinizi görecektir:

#!/bin/bash
# Belirli bir ülkenin IP bloklarını ipset'e yükle
# Örnek: Çin IP bloklarını engelle

COUNTRY="cn"
IPSET_NAME="country_cn"
TMP_FILE="/tmp/${COUNTRY}_cidr.txt"

# Önceki kümeyi temizle veya oluştur
ipset flush $IPSET_NAME 2>/dev/null || ipset create $IPSET_NAME hash:net maxelem 500000

# IP bloklarını indir
wget -q "https://www.ipdeny.com/ipblocks/data/countries/${COUNTRY}.zone" -O "$TMP_FILE"

if [ $? -ne 0 ]; then
    echo "IP bloklari indirilemedi!" >&2
    exit 1
fi

# Bloklari kume ye yukle
while IFS= read -r network; do
    [ -z "$network" ] && continue
    ipset add $IPSET_NAME "$network" 2>/dev/null
done < "$TMP_FILE"

echo "$(wc -l < $TMP_FILE) network blogu yuklendi."
rm -f "$TMP_FILE"

Timeout ile Dinamik Kara Liste

Gerçek dünyada en sık kullandığım özelliklerden biri timeout mekanizması. Bir IP belirli bir süre sonra otomatik olarak kara listeden düşer. Bu özellikle Fail2ban tarzı dinamik engelleme senaryolarında mükemmel çalışır:

# Timeout destekli küme oluştur (varsayılan 86400 saniye = 1 gün)
sudo ipset create dynamic_blacklist hash:ip timeout 86400 maxelem 100000

# IP'yi 1 saatlik timeout ile ekle
sudo ipset add dynamic_blacklist 192.168.1.200 timeout 3600

# IP'yi kalıcı olarak ekle (timeout=0)
sudo ipset add dynamic_blacklist 10.20.30.40 timeout 0

# Mevcut bir IP'nin timeout'unu güncelle
sudo ipset add dynamic_blacklist 192.168.1.200 timeout 7200 -exist

Bu yapıyı fail2ban alternatifi olarak kullanabilirsiniz. Şu script SSH brute-force saldırılarını anlık olarak tespit edip engelleyebilir:

#!/bin/bash
# SSH brute force tespit ve engelleme
# /usr/local/bin/ssh-guardian.sh olarak kaydedin

IPSET_NAME="ssh_bruteforce"
LOG_FILE="/var/log/auth.log"
THRESHOLD=5
TIME_WINDOW=300  # 5 dakika
BAN_DURATION=86400  # 1 gun

# Küme yoksa oluştur
ipset list $IPSET_NAME &>/dev/null || 
    ipset create $IPSET_NAME hash:ip timeout $BAN_DURATION maxelem 50000

# iptables kuralı ekle (yoksa)
iptables -C INPUT -m set --match-set $IPSET_NAME src -j DROP 2>/dev/null || 
    iptables -I INPUT -m set --match-set $IPSET_NAME src -j DROP

# Son 5 dakikadaki başarısız girişleri analiz et
current_time=$(date +%s)
window_start=$(date -d "@$((current_time - TIME_WINDOW))" '+%b %d %H:%M:%S' 2>/dev/null || 
    date -r $((current_time - TIME_WINDOW)) '+%b %d %H:%M:%S')

grep "Failed password" $LOG_FILE | 
grep -oP '(?<=from )d+.d+.d+.d+' | 
sort | uniq -c | 
while read count ip; do
    if [ "$count" -ge "$THRESHOLD" ]; then
        if ! ipset test $IPSET_NAME $ip 2>/dev/null; then
            ipset add $IPSET_NAME $ip timeout $BAN_DURATION
            logger -t ssh-guardian "Engellendi: $ip ($count basarisiz giris)"
            echo "$(date): $ip engellendi - $count giris denemesi"
        fi
    fi
done

Kümeleri Kaydetme ve Yükleme

ipset kuralları sistem yeniden başlatıldığında kaybolur. Bunu çözmenin birkaç yolu var:

# Mevcut tüm kümeleri dosyaya kaydet
sudo ipset save > /etc/ipset.rules

# Belirli bir kümeyi kaydet
sudo ipset save blacklist > /etc/ipset-blacklist.rules

# Kaydedilmiş kümeleri yükle
sudo ipset restore < /etc/ipset.rules

# Çakışma varsa mevcut elemanları atla
sudo ipset restore -exist < /etc/ipset.rules

Systemd ile kalıcı hale getirmek için bir servis oluşturalım:

# /etc/systemd/system/ipset-persistent.service
cat << 'EOF' | sudo tee /etc/systemd/system/ipset-persistent.service
[Unit]
Description=ipset Persistent Rules
Before=network.target
Before=iptables.service
ConditionFileNotEmpty=/etc/ipset.rules

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/ipset restore -exist -file /etc/ipset.rules
ExecStop=/sbin/ipset save -file /etc/ipset.rules

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable ipset-persistent
sudo systemctl start ipset-persistent

Atomik Kural Güncellemesi: swap Komutu

Büyük bir kara listeyi güncellerken hizmet kesintisi yaşamamak kritik öneme sahiptir. ipset’in swap komutu bu sorunu zarif şekilde çözer. İki kümeyi atomik olarak takas eder, yani güncelleme sırasında tek bir paket bile kaçmaz:

#!/bin/bash
# Kara listeyi kesintisiz güncelle

ACTIVE_SET="blacklist"
TEMP_SET="blacklist_new"
SOURCE_URL="https://example.com/blacklist.txt"

# Yeni kümeyi oluştur
ipset create $TEMP_SET hash:ip maxelem 200000

# Yeni listeyi yükle
wget -q "$SOURCE_URL" -O - | while read ip; do
    [[ "$ip" =~ ^#.*$ ]] && continue  # yorumları atla
    [ -z "$ip" ] && continue
    ipset add $TEMP_SET "$ip" 2>/dev/null
done

# Aktif küme yoksa oluştur
ipset list $ACTIVE_SET &>/dev/null || ipset create $ACTIVE_SET hash:ip maxelem 200000

# Atomik takas
ipset swap $TEMP_SET $ACTIVE_SET

# Eski (artık temp olan) kümeyi temizle
ipset destroy $TEMP_SET

echo "Kara liste guncellendi: $(ipset list $ACTIVE_SET | grep 'Number of entries' | awk '{print $NF}') eleman"

Birden Fazla Kümeyi Birleştirmek: list:set

Karmaşık güvenlik politikalarında farklı kategorilerdeki IP’leri ayrı kümelerde tutmak, yönetimi kolaylaştırır. list:set tipi bu kümeleri tek bir üst kümede birleştirir:

# Alt kümeleri oluştur
sudo ipset create tor_exit_nodes hash:ip maxelem 10000
sudo ipset create known_attackers hash:net maxelem 50000
sudo ipset create spam_sources hash:ip maxelem 100000

# Meta-küme oluştur
sudo ipset create all_threats list:set

# Alt kümeleri meta-kümeye bağla
sudo ipset add all_threats tor_exit_nodes
sudo ipset add all_threats known_attackers
sudo ipset add all_threats spam_sources

# Tek kural ile tüm tehditleri engelle
sudo iptables -I INPUT -m set --match-set all_threats src -j DROP

Artık tor_exit_nodes, known_attackers veya spam_sources kümelerinden herhangi birine eklediğiniz IP, otomatik olarak all_threats kapsamına girer. iptables kuralına dokunmanıza gerek kalmaz.

Gerçek Dünya Senaryosu: Web Sunucusu Saldırı Mitigasyonu

Bir e-ticaret sitesinin web sunucusunda uyguladığım kapsamlı bir koruma sistemini paylaşayım. Bu senaryo, bot trafiğini, kötü amaçlı tarayıcıları ve bilinen saldırı kaynaklarını katmanlı olarak engeller:

#!/bin/bash
# /usr/local/bin/firewall-setup.sh
# Web sunucusu için katmanli koruma sistemi

set -e

# Küme tanımları
declare -A SETS=(
    ["web_blacklist"]="hash:ip maxelem 500000"
    ["web_ratelimit"]="hash:ip maxelem 100000 timeout 60"
    ["trusted_sources"]="hash:net maxelem 1000"
    ["cdn_ranges"]="hash:net maxelem 5000"
)

echo "[*] Kumeler olusturuluyor..."
for set_name in "${!SETS[@]}"; do
    ipset list "$set_name" &>/dev/null && ipset flush "$set_name" || 
        ipset create "$set_name" ${SETS[$set_name]}
    echo "  - $set_name hazir"
done

# Güvenilen kaynaklara izin ver
ipset add trusted_sources 10.0.0.0/8    # Iç ağ
ipset add trusted_sources 172.16.0.0/12 # Docker/K8s
ipset add cdn_ranges 103.21.244.0/22    # Cloudflare

# iptables kuralları
echo "[*] iptables kurallari uygulanıyor..."

# Güvenilen kaynaklara her zaman izin ver
iptables -I INPUT -m set --match-set trusted_sources src -j ACCEPT

# CDN'den gelenlere izin ver
iptables -I INPUT -p tcp -m multiport --dports 80,443 
    -m set --match-set cdn_ranges src -j ACCEPT

# Kara listeyi engelle
iptables -I INPUT -m set --match-set web_blacklist src -j DROP

# Rate limiting ile rate_limit kümesine ekle
iptables -A INPUT -p tcp --dport 80 
    -m hashlimit --hashlimit-above 100/min 
    --hashlimit-burst 200 
    --hashlimit-mode srcip 
    --hashlimit-name web_rate 
    -m set ! --match-set web_ratelimit src 
    -j SET --add-set web_ratelimit src

iptables -A INPUT -p tcp --dport 80 
    -m set --match-set web_ratelimit src -j DROP

echo "[+] Kurulum tamamlandi!"
ipset list -n

İzleme ve Hata Ayıklama

Günlük operasyonlarda ipset’in durumunu takip etmek için kullandığım komutlar:

# Küme istatistikleri
sudo ipset list blacklist | head -20

# Eleman sayısını öğren
sudo ipset list blacklist | grep "Number of entries"

# Tüm kümelerin özetini göster
sudo ipset list -n | while read set; do
    count=$(ipset list $set | grep "Number of entries" | awk '{print $NF}')
    echo "$set: $count eleman"
done

# Kernel boyutunu kontrol et
cat /proc/net/ip_set

# Belirli bir IP'yi tüm kümelerde ara
for set in $(ipset list -n); do
    if ipset test $set 192.168.1.100 2>/dev/null; then
        echo "$set kümesinde bulundu: 192.168.1.100"
    fi
done

nftables ile Kullanım

Modern sistemlerde nftables, iptables’ın yerini almaya başlıyor. ipset’in nftables ekvivalenti olan named sets yapısı benzer işlevi görür, ancak eski sistemlerle uyumluluk için ipset + iptables kombinasyonu hâlâ yaygın. Eğer nftables kullanıyorsanız şu şekilde entegre edebilirsiniz:

# nftables içinde ipset referansı
nft add rule inet filter input 
    ip saddr @blacklist counter drop

# Alternatif: nftables'ın kendi set yapısı
nft add set inet filter blacklist { type ipv4_addr ; flags dynamic ; }
nft add element inet filter blacklist { 192.168.1.100, 10.0.0.5 }

Performans Optimizasyonu

Büyük ölçekli dağıtımlar için dikkat edilmesi gereken noktalar:

  • hashsize değeri — Hash boyutunu eleman sayısının yaklaşık yarısına ayarlayın. 100.000 eleman için hashsize 65536 iyi bir başlangıç noktasıdır
  • maxelem sınırı — Yeterince büyük tutun ama gereğinden büyük de ayarlamayın. Her eleman bellek tüketir
  • Düzenli temizlik — Timeout kullanmıyorsanız eski girişleri periyodik olarak temizleyin
  • Küme bölümleme — Milyonlarca IP için tek bir büyük küme yerine birden fazla orta boyutlu küme daha iyi performans verir
  • ipset save periyodu — Çok dinamik kümelerde her değişikliği diske yazmak yerine belirli aralıklarla kaydedin
# Optimum hashsize hesaplama
# maxelem'in 2'de 1'ine en yakın 2'nin kuvvetini bul
python3 -c "
import math
maxelem = 100000
hashsize = 2 ** math.ceil(math.log2(maxelem / 2))
print(f'Önerilen hashsize: {hashsize}')
"

Sonuç

ipset, Linux güvenlik altyapısının gerçekten göz ardı edilemeyecek bir parçası. iptables ile birlikte düzgün yapılandırıldığında on binlerce IP’yi neredeyir sıfır performans kaybıyla yönetebilirsiniz. Özellikle dinamik tehdit ortamlarında, swap ile kesintisiz güncelleme ve timeout ile otomatik temizleme özellikleri büyük fark yaratır.

Kendi deneyimlerimden şunu söyleyebilirim: Küçük bir projede bile en baştan ipset ile başlamak, ileride “neden iptables kural listesi 5.000 satıra ulaştı?” sorusunu sormaktan kurtarır. Kara liste yönetimini script’lerle otomatize edin, düzenli olarak küme istatistiklerini izleyin ve timeout mekanizmasını aggressive kullanmaktan çekinmeyin. Yanlışlıkla engellenen bir IP, timeout süresi dolduğunda zaten kendiliğinden çözülür.

Bir sonraki adım olarak bu yapıyı Ansible playbook’larınıza taşımanızı öneririm. Infrastructure as Code yaklaşımıyla tüm güvenlik duvarı kümelerinizi versiyon kontrolünde tutabilirsiniz.

Bir yanıt yazın

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