IP setleri tekrar ziyaret edildi
IP setlerinden bahseden bir cevap zaten var. Bununla birlikte, klasik kurallar üzerinden elde edilen performansa odaklanması ve IP setlerinin CIDR notasyonunda kolayca bir alt ağ olarak ifade edilemeyecek birçok bireysel IP adresi olan sorunu hafifletmesi gerçeği bir boyutludur.
Aşağıda kullanılan gösterim
Çünkü ipsetyazım tarafından okunan ipset restoreve yazılan gösterimi kullanacağım ipset save.
Buna göre iptables(ve ip6tables) kurallar için gösterimi, okuduğu iptables-restoreve yazdığı şekilde kullanacağım iptables-save. Bu, daha kısa bir gösterim sağlar ve potansiyel IPv4-sadece (önek -4) veya IPv6-sadece (önek -6) kurallarını vurgulamama izin verir .
Bazı örneklerde paket akışını başka bir zincire yönlendireceğiz. Bu noktada zincirin olduğu varsayılır, bu nedenle zincirleri oluşturan satırlar üretilmez (sonunda tablo adı veya belirtilen komutlar da belirtilmez COMMIT).
Gelişmiş IP setleri
IP setleri diğer cevaplarda belirtilenden çok daha fazlasını yapabilir ve buradaki kısa girişin yanı sıra IP set belgelerini ( ipset(8)) kesinlikle okumanız gerekir iptables-extensions(8).
Mesela ben esas olarak üç set üzerinde duralım: hash:ip, hash:netve list:setfakat daha fazlası var ve hepsi geçerli kullanım durumları var.
Örneğin , yalnızca IP adreslerini değil, port numaralarını da eşleştirebilirsiniz .
Kaydetme ve ile IP kümelerini geri iptables-saveveiptables-restore
IP seti bildirimlerini toplu olarak oluşturabilir ve içine aktararak içe aktarabilirsiniz ipset restore. Komutunuzu mevcut girişlere karşı daha esnek hale getirmek istiyorsanız, kullanın ipset -exist restore.
Kurallarınız denilen bir dosyadaysa, default.setşunları kullanırsınız:
ipset -exist restore < default.set
Bunun gibi bir dosya, createkümelere ve addiçine girdiler için girdiler içerebilir . Ancak genellikle komut satırındaki komutların çoğunun dosyalarda karşılık gelen bir sürümü var gibi görünmektedir. Örnek (bir dizi DNS sunucusu oluşturma):
create dns4 hash:ip family inet
create dns6 hash:ip family inet6
# Google DNS servers
add dns4 8.8.8.8
add dns4 8.8.4.4
add dns6 2001:4860:4860::8888
add dns6 2001:4860:4860::8844
Burada IPv4 ( dns4) için bir tane ve IPv6 ( dns6) için bir set oluşturulur .
IP setlerinde zaman aşımları
IP setlerindeki zaman aşımları, set başına ve ayrıca giriş başına varsayılan olarak ayarlanabilir. Bu, birini geçici olarak engellemek istediğiniz senaryolar için çok yararlıdır (örneğin port taraması veya SSH sunucunuzu kaba şekilde zorlama girişiminde bulunmak için).
Bunun çalışması şu şekildedir (IP kümelerinin oluşturulması sırasında varsayılan):
create ssh_loggedon4 hash:ip family inet timeout 5400
create ssh_loggedon6 hash:ip family inet6 timeout 5400
create ssh_dynblock4 hash:ip family inet timeout 1800
create ssh_dynblock6 hash:ip family inet6 timeout 1800
Aşağıda bu belirli kümelere ve neden oldukları gibi belirlenmelerinin gerekçesine geri döneceğiz.
Zaman aşımınızı belirli bir IP adresi için ayarlamak isterseniz, şunu söyleyebilirsiniz:
add ssh_dynblock4 1.2.3.4 timeout 7200
IP 1.2.3.4'ü (ayarlanan) varsayılan yarım saat yerine iki saat süreyle engellemek için.
ipset save ssh_dynblock4Kısa bir süre sonra buna bakarsanız, aşağıdaki satırlarda bir şeyler görürsünüz:
create ssh_dynblock4 hash:ip family inet hashsize 1024 maxelem 65536 timeout 1800
add ssh_dynblock4 1.2.3.4 timeout 6954
Zaman aşımı uyarıları
- zaman aşımları verilen herhangi bir sette bulunan bir özelliktir. Set zaman aşımı desteği ile oluşturulmadıysa bir hata alırsınız (örn.
Kernel error received: Unknown error -1).
- zaman aşımları saniye cinsinden verilir. Örneğin, dakikadan saniyeye ulaşmak için Bash aritmetik ifadelerini kullanın. Örneğin:
sudo ipset add ssh_dynblock4 1.2.3.4 timeout $((120*60))
Bir girişin belirli bir IP setinde olup olmadığını kontrol etme
Komut dosyalarınızın içinde bir girişin var olup olmadığını görmek yararlı olabilir. Bu ipset test, giriş varsa sıfırı döndürür, aksi takdirde sıfır saymazsa başarılabilir . Böylece normal kontroller bir betiğe uygulanabilir:
if ipset test dns4 8.8.8.8; then
echo "Google DNS is in the set"
fi
Bununla birlikte, çoğu durumda -existanahtarı, ipsetmevcut girişler hakkında şikayet etmemek için yönlendirmek amacıyla kullanmak isteyeceksiniz .
IP kümelerini iptableskurallardan doldurma
Bu, benim görüşüme göre, IP setlerinin katil özelliklerinden biridir. Bir IP setinin girişleriyle eşleşmekle kalmaz, mevcut bir IP setine de yeni girişler ekleyebilirsiniz.
Örneğin, bu sorunun cevabında sizde:
-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT
... hız sınırı bağlantısı amacıyla SSH'ye çalışmayı deniyor (TCP port 22). Kullanılan modül recentson bağlantı girişimlerini takip eder. Bununla birlikte , statemodül yerine, modülü tercih ederim conntrack.
# Say on your input chain of the filter table you have
-A INPUT -i eth+ -p tcp --dport ssh -j SSH
# Then inside the SSH chain you can
# 1. create an entry in the recent list on new connections
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
# 2. check whether 3 connection attempts were made within 2 minutes
# and if so add or update an entry in the ssh_dynblock4 IP set
-4 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock4 src --exist
-6 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock6 src --exist
# 3. last but not least reject the packets if the source IP is in our
# IP set
-4 -A SSH -m set --match-set ssh_dynblock4 src -j REJECT
-6 -A SSH -m set --match-set ssh_dynblock6 src -j REJECT
Bu durumda , her bir kural için SSHkendimi tekrar etmek zorunda kalmayacağım şekilde akışı zincire yönlendiriyorum -p tcp --dport ssh.
Tekrarlamak için:
-m setyapar iptablesbiz gelen anahtarları kullanıyoruz farkında set(hangi IP setlerini kolları) modülü
--match-set ssh_dynblock4 srcsource ( ) adresi ile belirtilen set ( )
iptablesile eşleşmesini söylersrcssh_dynblock4
- bu, karşılık gelir
sudo ipset test ssh_dynblock4 $IP( $IPpaket için kaynak IP adresini içeren)
-j SET --add-set ssh_dynblock4 src --existpaketteki source ( src) adresini IP setine ekler veya günceller ssh_dynblock4. Bir giriş varsa ( --exist) sadece güncellenir.
- bu, karşılık gelir
sudo ipset -exist add ssh_dynblock4 $IP( $IPpaket için kaynak IP adresini içeren)
Bunun yerine hedef / hedef adresiyle eşleştirmek istiyorsanız, dstyerine kullanırsınız src. Daha fazla seçenek için kılavuza bakın.
Kümeleri
IP kümeleri başka kümeler içerebilir. Şimdi makaleyi buraya kadar izlerseniz, kümeleri birleştirmenin mümkün olup olmadığını merak etmişsinizdir. Ve elbette öyle. Yukarıdaki IP kümeleri için iki ortak küme oluşturabiliriz ssh_dynblockve ssh_loggedonsırasıyla sadece IPv4 ve sadece IPv6 kümelerini içeririz:
create ssh_loggedon4 hash:ip family inet timeout 5400
create ssh_loggedon6 hash:ip family inet6 timeout 5400
create ssh_dynblock4 hash:ip family inet timeout 1800
create ssh_dynblock6 hash:ip family inet6 timeout 1800
# Sets of sets
create ssh_loggedon list:set
create ssh_dynblock list:set
# Populate the sets of sets
add ssh_loggedon ssh_loggedon4
add ssh_loggedon ssh_loggedon6
add ssh_dynblock ssh_dynblock4
add ssh_dynblock ssh_dynblock6
Ve aklınızda bulunması gereken bir sonraki soru, IP setlerini agnostik bir şekilde IP setleriyle eşleştirip manipüle etmemize izin verip vermeyeceğidir .
Ve bunun cevabı bir yankılandı: EVET! (ne yazık ki, bu son kontrol ettiğimde açıkça belgelenmedi)
Sonuç olarak, önceki bölümdeki kurallar okumak için yeniden yazılabilir:
-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT
Bu çok daha özlü. Ve evet, bu denenmiş ve test edilmiş ve bir cazibe gibi çalışıyor.
Hepsini bir araya getirmek: SSH kaba kuvvet savunması
Sunucularımda cron, bir sürü ana bilgisayar adı alan ve bunları IP adreslerine çözen, ardından "güvenilir ana bilgisayarlar" için ayarlanan IP'ye besleyen bir iş olarak çalışan bir komut dosyası var . Buradaki fikir, güvenilir ana makinelerin sunucuya giriş yapmak için daha fazla girişimde bulunmaları ve mutlaka başka hiç kimse tarafından engellenmemeleri gerektiğidir.
Bunun tersine, tüm ülkelerin SSH sunucuma bağlanmalarını engelledim, güvenilir ana bilgisayarların (potansiyel kurallar dışında) (potansiyel) istisnasıyla.
Ancak, bu okuyucu için bir egzersiz olarak bırakılmıştır. Burada ssh_loggedon, sonraki bağlantı girişimlerinin gerçekleştirilebilmesini ve diğer paketlerle aynı incelemeye tabi tutulmamasını sağlamak için sette bulunan setleri kullanacak temiz bir çözüm eklemek istiyorum .
Aşağıdaki kurallara bakarken, 90 dakikalık ssh_loggedonve 30 dakikalık varsayılan zaman aşımlarını hatırlamak önemlidir :ssh_dynblockiptables
-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m set --match-set ssh_loggedon src -j ACCEPT
-A SSH -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT
Şimdiye kadar kendinize, bağlı IP adresinin ssh_loggedonalt kümelerde nasıl sona erdiğini sormalısınız . Öyleyse okumaya devam et ...
Bonus: SSH oturumu sırasında giriş yaptığınız IP'yi eklemek
sshrcArkadaşlarınızla ve deneyimleriniz varsa , onun eksikliklerini öğrendiniz. Ancak PAM kurtarmaya gelir. Adlı modül pam_exec.so, kullanıcının kabul edildiğini bildiğimiz bir noktada SSH oturumu sırasında bir komut dosyası çağırmamızı sağlar.
In /etc/pam.d/sshdaşağıda pam_envve pam_selinuxgirişleri aşağıdaki satırı ekleyin:
session optional pam_exec.so stdout /path/to/your/script
ve betiğin ( /path/to/your/scriptyukarıdaki) sürümünün var olduğundan ve çalıştırılabilir olduğundan emin olun .
PAM, olup bitenleri iletmek için ortam değişkenlerini kullanır, böylece bunun gibi basit bir komut dosyası kullanabilirsiniz:
#!/bin/bash
# When called via pam_exec.so ...
SETNAME=ssh_loggedon
if [[ "$PAM_TYPE" == "open_session" ]] && [[ -n "$PAM_RHOST" ]]; then
[[ "x$PAM_RHOST" != "x${PAM_RHOST//:/}" ]] && SETNAME="${SETNAME}6" || SETNAME="${SETNAME}4"
ipset -exist add $SETNAME "$PAM_RHOST"
fi
Maalesef, ipsetyardımcı programın yerleşik netfilter akıllıları görünmüyor. Bu yüzden, girişimizi eklerken IPv4 ve IPv6 IP setlerini ayırt etmemiz gerekir. Aksi takdirde , IP yerine kümelere ipsetbaşka bir küme eklemek istediğimizi varsayacağız . Ve elbette, IP adresinden sonra bir set olması pek mümkün değildir :)
Bu yüzden :IP adresini kontrol ederiz ve 6bu durumda set adını 4ekleriz.
Son.