Tűzfalak
(→Dinamikus hosztnevek IP-változásainak követése: update 2021) |
(→SSH-jelszópróbálgatók automatikus kitűzfalazása: update 2021) |
||
1 514. sor: | 1 514. sor: | ||
== SSH-jelszópróbálgatók automatikus kitűzfalazása == |
== SSH-jelszópróbálgatók automatikus kitűzfalazása == |
||
− | * Az ilyesmivel csak óvatosan, nehogy self-DoS legyen |
+ | * Az ilyesmivel csak óvatosan, nehogy self-DoS legyen. |
+ | * Az alábbi script párféle logfájlból ki tudja nyerni a hibás jelszavakkal próbálkozók IP-jét, és ki tudja őket tiltani. |
||
+ | * Hasonló célokat szolgál a jóval mainstreamebb fail2ban. |
||
<pre> |
<pre> |
||
1 520. sor: | 1 520. sor: | ||
# Needs to run as root because it invokes iptables |
# Needs to run as root because it invokes iptables |
||
exec 2>&1 |
exec 2>&1 |
||
+ | if [[ "$1" != "-P" ]]; then |
||
+ | exec chpst -P $0 -P |
||
+ | fi |
||
CONFIG=/etc/ssh-hammerblock/config |
CONFIG=/etc/ssh-hammerblock/config |
||
− | SSHLOG=/var/log/socklog/ssh/current |
+ | SSHLOG=/var/log/sv/socklog/ssh/current |
STATEDIR=/var/state/ssh-hammerblock |
STATEDIR=/var/state/ssh-hammerblock |
||
− | THRESHOLD=10 |
+ | THRESHOLD=12 |
TMPREAPER_TIME=1h |
TMPREAPER_TIME=1h |
||
− | RULE="-I INPUT -s __IP__ -j blacklisted" |
+ | FWCOMMAND=ipset |
+ | RULE=(-exist add blacklisted __IP__ timeout 86400 comment ssh-hammerblock) |
||
+ | # or perhaps: |
||
+ | #FWCOMMAND=iptables |
||
+ | #RULE=(-I INPUT -j blacklisted -s __IP__) |
||
[[ -r "$CONFIG" ]] && . "$CONFIG" |
[[ -r "$CONFIG" ]] && . "$CONFIG" |
||
mkdir -p $STATEDIR |
mkdir -p $STATEDIR |
||
chmod 700 $STATEDIR |
chmod 700 $STATEDIR |
||
+ | trap 'kill -QUIT -$$; kill -1 -$$' 15 |
||
+ | trap 'kill -QUIT -$$' EXIT |
||
xtail $SSHLOG 2>/dev/null \ |
xtail $SSHLOG 2>/dev/null \ |
||
− | | sed -nu '/Failed/{s/.*for .* from //;s/ .*//;p};/Invalid user/{s/.*Invalid user .* from //;p}' \ |
+ | | sed -nu ' |
+ | s/::ffff:// |
||
+ | /Failed/{ |
||
+ | s/.*for .* from // |
||
+ | s/ .*// |
||
+ | p |
||
+ | } |
||
+ | /Invalid user/{ |
||
+ | s/.*Invalid user .* from // |
||
+ | s/ .*// |
||
+ | p |
||
+ | } |
||
+ | /PAM: Authentication failure for .* from /{ |
||
+ | s/.* for .* from // |
||
+ | s/ .*// |
||
+ | p |
||
+ | } |
||
+ | /PAM [0-9][0-9]* more authentication failures; .* rhost=/{ |
||
+ | s/.*rhost=//;s/[[:space:]].*// |
||
+ | p |
||
+ | } |
||
+ | /Postponed keyboard-interactive for invalid user/{ |
||
+ | s/.* for .* from // |
||
+ | s/ .*// |
||
+ | p |
||
+ | } |
||
+ | /INFO: LOGIN FAILED, .*, ip=\[.*\]/{ |
||
+ | s/.*ip=\[// |
||
+ | s/\].*// |
||
+ | p |
||
+ | } |
||
+ | /authentication failure; .* rhost=.*/{ |
||
+ | s/.*rhost=//;s/[[:space:]].*// |
||
+ | p |
||
+ | } |
||
+ | /Connection reset by .* port .* \[preauth\]/{ |
||
+ | s/.*reset by // |
||
+ | s/ .*// |
||
+ | p |
||
+ | }' \ |
||
| while read IP; do |
| while read IP; do |
||
+ | [[ -r "$CONFIG" ]] && . "$CONFIG" # re-source config to make it possible to adjust most parameters without restarting the service |
||
tmpreaper $TMPREAPER_TIME $STATEDIR/./ |
tmpreaper $TMPREAPER_TIME $STATEDIR/./ |
||
− | COUNT=$(cat "$STATEDIR/$IP" 2>/dev/null) |
+ | if [[ -f "$STATEDIR/$IP" ]]; then |
+ | COUNT=${$(< "$STATEDIR/$IP"):-0} |
||
+ | else |
||
+ | COUNT=0 |
||
+ | fi |
||
((COUNT++)) |
((COUNT++)) |
||
echo -n "$COUNT" >"$STATEDIR/$IP" |
echo -n "$COUNT" >"$STATEDIR/$IP" |
||
if [[ "$COUNT" -ge "$THRESHOLD" ]]; then |
if [[ "$COUNT" -ge "$THRESHOLD" ]]; then |
||
− | iptables ${=RULE//__IP__/$IP} |
+ | $FWCOMMAND ${RULE//__IP__/$IP} 2>/dev/null |
rm -f "$STATEDIR/$IP" |
rm -f "$STATEDIR/$IP" |
||
fi |
fi |
A lap jelenlegi, 2021. április 9., 19:17-kori változata
Az iptables a Linux kernelben található Netfilter csomagszűrő userspace komponense; egy olyan program, amellyel a Netfilter beállításait kezelhetjük.
A továbbiakban nem teszünk éles különbséget az iptables és a Netfilter között; a szövegkörnyezetből mindig egyértelmű lesz, melyikről van szó.
Tartalomjegyzék[elrejtés] |
[szerkesztés] 1 Fogalmak
Az iptables működésének megértéséhez fontos tudni, mi a csomagszűrő (packet filter) és mi a kapcsolatkövető tűzfal (connection tracking firewall).
[szerkesztés] 1.1 Tűzfal
A tűzfal általánosságban egy olyan hálózati eszköz (általában router), amely kettő vagy több hálózatot köt össze és a rajta áthaladó forgalmat "jólformálttá" teszi annak érdekében, hogy az egyes interface-eihez tartozó hálózatokat kölcsönösen megvédje a többiből érkező "érvénytelen" (vagy legalábbis érdektelen), esetleg rossz szándékú kommunikációtól.
Különböző tűzfalmegoldásokkal más-más mértékű "jólformáltság" érhető el.
Tűzfalakkal kikényszeríthetjük a biztonsági/hálózati házirend betartását is.
[szerkesztés] 1.2 Csomagszűrő
A csomagszűrő minden egyes csomagról önmagában dönti el, hogy áthaladhat-e a tűzfalon. A döntéshez felhasználhat mindent, amit az adott csomagról tud, akár a tartalmát is, de általában a fejléc alapján születik a döntés.
Előnye, hogy állapotmentes, így elvileg akárhány kapcsolatot tud kezelni.
Hátránya, hogy buta és rugalmatlan: pl. nem tudja megállapítani, hogy egy új TCP-kapcsolat egy már fennálló FTP-kapcsolathoz tartozó adatkapcsolat-e, vagy hogy a 443-as porton SSH- vagy https-forgalom zajlik.
A Netfilterrel építhetünk ilyet, de általában jobb kapcsolatkövető tűzfalat csinálni (kivéve, ha a kapcsolatkövetés miatt keletkező többletterhelés túl nagy).
[szerkesztés] 1.3 Kapcsolatkövető csomagszűrő
Olyan tűzfal, amely nyomon követi a rajta keresztül felépített hálózati kapcsolatok állapotát, és ezt az információt is fel tudja használni a döntés során.
Az állapot-információ nyilvántartásához memóriára van szüksége; minél több kapcsolatot tart nyilván, annál több memóriára. Ezért aztán DoS-támadás indítható ellene úgy, hogy a támadó sok-sok kapcsolatot nyit; egy idő után vagy elfogy a tűzfal memóriája, vagy eldob új vagy régi kapcsolatokat, vagy - ha nem megfelelő adatszerkezetet használ - a használhatatlanságig lelassul.
[szerkesztés] 1.4 NAT, PAT
Network Address Translation, Port Address Translation: a tűzfalon átmenő kapcsolatokban átírja a cél- és/vagy forrásportot és/vagy -címet valami másra, az adott kapcsolathoz tartozó összes csomagban ugyanúgy.
A Linux összemossa a tűzfalfunkcióval.
[szerkesztés] 1.5 Proxy-alapú tűzfal
Olyan tűzfal, amely nem a hálózati, hanem az alkalmazási rétegben működik, és a rajta átmenő forgalmat is alkalmazásszinten képes vizsgálni/módosítani/szűrni.
Pl:
- A pop3-mal letöltött levelekből ki tudja szűrni a vírust/spamet.
- SSH-ban tudja tiltani a tunnelezést úgy, hogy az interaktív kapcsolatot viszont engedélyezi.
- Ki tudja kényszeríteni, hogy a kliensek csak olyan HTTPS-szerverrel tudjanak kommunikálni, amelynek a tanúsítványa valamilyen megadott szempontrendszer szerint "rendben van".
- Ez úgy működik, hogy a tűzfalban van egy hitelesítő hatóság (CA), amiben a kliens megbízik;
- a https-kapcsolatot a tűzfal TCP-szinten a saját IP-címére irányítja;
- mielőtt a kliensnek válaszolna, ő maga SSL handshake-et kezdeményez az eredeti célszerverrel;
- így megtudja, annak a tanúsítványában milyen Common Name attribútum szerepel;
- ellenőrzi, hogy a szerver tanúsítványa megfelel-e a helyi előírásoknak (nem vonták-e vissza, megbízható hatóság írta-e alá, nem járt-e le stb.);
- ha a szerver tanúsítványa megfelelő, akkor a tűzfal készít egy saját tanúsítványt, ami a távoli szerver nevére (Common Name) szól, és a saját CA-jával aláírja;
- ezt a tanúsítványt mutatja a kliensnek, amely el is fogadja, mivel a tűzfal CA-jában megbízik;
- ezután a titkosítás két különálló szakaszon valósul meg: a kliens és a tűzfal között ill. a tűzfal és a szerver között van egy-egy HTTPS session.
- Így a tűzfal az elvileg titkosítottan átvitt adatok belsejében is tud pl. vírust keresni.
- Ha a szerver tanúsítványa nem volt megfelelő, a proxy elutasítja a kapcsolat felépítését, és a kliens így járt.
- Ezt semmilyen alacsonyabb szinten működő proxy nem tudja megcsinálni.
- A Zorp biztosan tud ilyet; valószínűleg a Microsoft ISA is.
Hátrányok:
- minden alkalmazást (protokollt) külön kell támogatni;
- ide értve a nem szabványos megvalósításokat is;
- általában minden protokollhoz külön proxyt kell futtatni;
- ha fejlődik a protokoll, a proxyt külön fejleszteni kell;
- nagyobb összetettség -> több hibalehetőség (esetleg sebezhetőség);
[szerkesztés] 1.6 Fogalmak a Netfilter/iptables körül
Alulról felfelé haladva az iptables a következő fogalmakkal dolgozik:
- match (illesztés): egy feltétel, amelynek egy csomag meg kell, hogy feleljen. Pl.:
- forrás-IP
- protokoll
- célport
- a kapcsolat állapota
- melyik interface-en jön be vagy megy ki
- rengeteg más match van
- akció (target): döntés arról, hogy mi történjen egy csomaggal, pl.:
- engedélyezés
- eldobás
- visszautasítás (pl. TCP RST-vel vagy icmp admin-prohib üzenettel)
- ugrás másik láncra (l. lejjebb)
- van még jópár akció
- szabály (rule): ÉS kapcsolatban levő matchek és egy akció együttese. Ha minden match illeszkedik, az adott csomagon az adott akciót kell végrehajtani.
- lánc (chain): a szabályokat "láncokra" tudjuk felfűzni. Ha egy csomag eljut egy láncba, akkor a kernel sorban minden szabályt kiértékel, amíg az első olyat meg nem találja, amire a csomag illeszkedik. Ennek az akcióját végrehajtja, és a későbbi szabályokat figyelmen kívül hagyja (de van olyan akció is, ami nem "végleges", pl. a naplózás; ha ilyen volt az illeszkedő szabályban, akkor a lánc kiértékelése a következő szabállyal folytatódik).
- láncokat definiálhatunk mi is, de van néhány speciális, beépített lánc (l. később)
- a beépített láncoknak lehet "policy"-je, ami azt adja meg, mi történjen azokkal a csomagokkal, amelyekről egyetlen szabály sem rendelkezett
- tábla: láncok vannak benne. Bizonyos akciók csak bizonyos táblákban értelmezettek; pl. van nat tábla, amiben NATolhatunk. A csomagok meghatározott sorrendben járják be a táblákat.
A csomag útjának megértésében sokat segít a - sajnos nem feltétlenül naprakész, teljes és pontos, de ASCII-ban is nézhető - "Kernel Packet Traveling Diagram", vagy a valamivel frissebb, SVG-formátumú Netfilter Packet Flow Diagram.
[szerkesztés] 2 Táblák
- filter: INPUT, OUTPUT és FORWARD lánc; szűrésre való
- nat: PREROUTING, OUTPUT és POSTROUTING lánc; címfordításra való
- mangle: PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING lánc; bizonyos csomagmódosításokat lehet itt elvégezni
- raw: PREROUTING és OUTPUT lánc; megjelölhetjük benne azokat a csomagokat, amelyekre nem kérünk kapcsolatkövetést.
[szerkesztés] 3 Az iptables parancssora
- iptables [-t table] -A chain rule-specification [options]
- új szabály felvétele a lánc végén
- iptables [-t table] -D chain rule-specification [options]
- szabály törlése a láncból a törlendő szabály megadásával
- iptables [-t table] -D chain rulenum [options]
- szabály törlése a láncból a sorszáma megadásával
- iptables [-t table] -I chain [rulenum] rule-specification [options]
- szabály beszúrása a láncba (scriptben csak nagy körültekintéssel használjuk)
- iptables [-t table] -R chain rulenum rule-specification [options]
- szabály cseréje (scriptben csak nagy körültekintéssel használjuk)
- iptables [-t table] -L [chain] [options]
- lánc listázása
- iptables [-t table] -F [chain] [options]
- lánc törlése (flush)
- iptables [-t table] -Z [chain] [options]
- csomag- és byte-számlálók törlése
- iptables [-t table] -N chain
- új lánc létrehozása
- iptables [-t table] -X [chain]
- lánc törlése (csak, ha már nincs benne szabály, és rá se hivatkozik szabály)
- iptables [-t table] -P chain target [options]
- policy beállítása
- iptables [-t table] -E old-chain-name new-chain-name
- lánc átnevezése
Példa pár szabály felvételére:
iptables -A INPUT -p tcp --dport ssh -s 1.2.3.4 -j ACCEPT iptables -A INPUT -p tcp --dport ssh -j REJECT --reject-with tcp-reset iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
A -j-vel ugorhatunk más láncra is:
iptables -N ssh_input iptables -A INPUT -p tcp --dport ssh -j ssh_input iptables -A ssh_input -s 1.2.3.4 -j ACCEPT iptables -A ssh_input -s 2.3.4.5 -j ACCEPT iptables -A ssh_input -s 3.4.5.192/26 -j ACCEPT iptables -A ssh_input -m limit --limit 3/minute -j LOG --log-prefix "FW: ssh_input REJECT: " iptables -A ssh_input -p tcp -j REJECT --reject-with tcp-reset iptables -A ssh_input -j DROP
Itt -j ("jump") helyett írhattam volna -g-t ("goto") is; a különbség az, hogy -j esetén, ha a meghívott láncban nincs illeszkedő szabály, akkor a -j-s szabály után folytatódik a szabályok kiértékelése (tehát ez "gosub"), míg -g esetén, ha nincs egyezés, akkor az utolsó kiértékelt -j után. Mi van, ha beépített láncban használjuk a goto-t?
Sem a matchek, sem az akció megadása nem kötelező. Akciómentes szabályt használhatunk pl. forgalomszámolásra, mivel minden szabályhoz tartozik két számláló, amelyek az illeszkedő csomagokat ill. az általuk szállított byte-okat számolják.
[szerkesztés] 4 Kapcsolók
- -c: csomag- és byte-számlálók kézi beállítása
- -n: ne legyen reverse-DNS-feloldás a listázáskor (ott van helyette az adnsresfilter, ha muszáj)
- -v: szószátyárabb output (nemcsak listázásnál)
- -x: számlálók pontos értékkel, nem SI prefixekkel jelennek meg
- --line-numbers: minden szabály elé odaírja, hanyadik a láncban
- ez ugye az -I, -D, -R parancsok előtt hasznos...
[szerkesztés] 5 Match-ek
- -p, --protocol protokoll
- -s, --source cím[/maszk]: cím lehet hosztnév is; ha több IP tartozik hozzá, minden IP-hez külön szabály képződik
- -i, --in-interface név
- -o, --out-interface név
- -f, --fragment
- --icmp-type típus
- --sport, --dport port[:port]: tcp, udp forrás- ill. célport
- --tcp-flags vizsgálandók melyiklegyenbeállítva
- --syn == --tcp-flags SYN,RST,ACK,FIN SYN
- -m modulnév: bővített matchek. Ezek közül néhány érdekesebb:
- -m account: forgalomstatisztika, házi feladat; [1]
- -m addrtype: forrás- vagy célcím osztálya (UNICAST, BROADCAST, MULTICAST stb.)
- -m childlevel: "főkapcsolat" vagy "gyermekkapcsolat" (pl. ftp-data)
- -m comment: no-op, kommentálni lehet vele a szabályt: iptables -A INPUT -s 192.168.0.0/16 -m comment --comment "A privatized IP block" -j valahova
- -m condition: létrehoz nekünk egy file-t a /proc-ban, és attól függően illeszkedik vagy nem, hogy abba a file-ba egyest vagy nullát írunk
- -m connbytes: az adott kapcsolathoz tartozó adatforgalom nagysága alapján matchel (csomagszám, byte-szám vagy átlagos csomagméret)
- -m connlimit: kapcsolatok számának korlátozása. Példák:
# allow 2 telnet connections per client host iptables -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT # you can also match the other way around: iptables -p tcp --syn --dport 23 -m connlimit ! --connlimit-above 2 -j ACCEPT # limit the nr of parallel http requests to 16 per class C sized network (24 bit netmask) iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16 --connlimit-mask 24 -j REJECT
- -m connmark: a kapcsolatokat meg lehet jelölni a mangle táblában; ezzel a matchel vizsgáljuk, hogy egy adott kapcsolaton egy adott jelzés van-e
- -m connrate: a kapcsolat aktuális adatátviteli sebességét nézi
- -m conntrack: a kapcsolatkövető mechanizmus belső paraméterei alapján matchel. Értelmes felhasználás: házi feladat. :)
- -m ecn: explicit congestion notification, RFC3168: házi feladat
- -m fuzzy: fuzzy ratelimit. Értelmes felhasználás: házi feladat. :)
- -m hashlimit: rátalimit, de nem szabályonként, hanem szabályonként és cél- vagy forráscímenként vagy cél- vagy forrásportonként. "Egyetlen kliens se kapcsolódhasson másodpercenként 5-nél többször az SMTP-szerverre."
- -m iprange: net/maszk helyett ip1-ip2 alakban adható meg tartomány
- -m length: csomagméret
- -m limit: rátalimit. A szabály legfeljebb x alkalommal illeszkedik y idő alatt (lyukasvödörrel van megcsinálva, úgyhogy egy véges börsztöt is elfogad). Pl. logoláshoz jó.
- -m mac: ethernet-forráscím
- -m mark: a kapcsolatok megjelöléséhez hasonlóan egyes csomagokat is meg lehet jelölni, erre illeszthetünk ezzel a match-csel
- -m mport: több port sorolható fel
- -m multiport: majdnem ugyanaz, de a felsorolásban szerepelhet tartomány is
- -m nth: minden n. alkalommal illeszkedik (pl. minden n. csomagot logolunk, vagy a lakótárs minden 4. torrentcsomagját eldobjuk, hátha magától is leáll a torrentezéssel :)
- -m osf: passzív OS fingerprinting (pl. "csak linuxos gépek küldhessenek levelet"). Nem bombabiztos, inkább játék.
- -m owner: a csomagot küldő folyamat UID, GID, PID, SID (session ID) értékei, ill. a processz neve alapján illeszt
- -m physdev: bridge interface esetén a fizikai interface-re illeszt
- -m pkttype: adatkapcsolati rétegbeli címtípus (unicast|broadcast|multicast)
- -m psd: portscan-detektor. Nemigen van értelme.
- -m quota: forgalmi kvótát lehet csinálni vele (az adott szabályra illeszkedő csomagok csökkentik a byte-számlálót). Többprocesszoros rendszeren jelenleg nem működik.
- -m random: véletlenszerűen illeszkedik (vagy nem); pl. véletlen csomagvesztés szimulálására jó (vagy lakótárs torrentezési szokásainak megváltoztatására)
- -m recent: táblázatot csinálhatunk vele azokról az IP-kről, amelyeket valamilyen kontextusban "láttunk", aztán később vizsgálhatjuk, hogy elemei-e a táblázatnak; pl. primitív SMTP greylistingre jó, de sokminden másra is lehet használni: házi feladat
- -m ipset: egyetlen szabállyal több IP-re is illeszthetünk (ez pl. akkor jó, ha ACL-t akarunk csinálni); külön programmal, az ipset-tel lehet az egyes halmazokat adminisztrálni. L. később. Egyelőre sajnos nincs benne a hivatalos kernelben.
- -m state: a kapcsolat állapota
- -m string: a csomag tartalma
- -m time: dátumhoz ill. napszakhoz kötött illesztés
- -m tos
- -m ttl
[szerkesztés] 6 Akciók
- ACCEPT
- REJECT
- DROP
- LOG: naplóüzenetet generál, de folytatja a következő szabállyal
- MARK
- SNAT
- DNAT
- RETURN
- MASQUERADE
- CLASSIFY: forgalmi osztályba sorolás (aztán az osztálynak lehet sorbanállási prioritása, l. Linux Advanced Routing and Traffic Control HOWTO)
- CLUSTERIP: elvileg terheléselosztó clustert lehet vele csinálni. Házi feladat. :)
- CONNMARK: a kapcsolathoz tartozó jelölés beállítása
- IPMARK: a forrás-IP-címből számítja ki a csomagra illesztendő jelölést (akkor jó, ha rengeteg usernek egyéni sávszélességkorlátokat ill. saját várakozási sort szeretnénk csinálni)
- IPV4OPTSSTRIP: leszedi az opciókat az IPv4-es csomagokról - mikor van értelme?
- LOG: naplózza az illeszkedő csomagokat; a feldolgozás a következő szabálynál folytatódik.
- MARK: csomag megjelölése
- NETMAP: tömeges NAT, címtér-tömörítés nélkül (pl. egy /16-os hálózatot leképez egy másikra)
- QUEUE/NFQUEUE: átadja a csomagot egy userspace programnak (ami már fut és regisztrálta magát a kernelben)
- NOTRACK: az illeszkedő csomagokra nem kérünk kapcsolatkövetést. Erőforrást takarít meg; mondjuk beállíthatjuk a DNS-szerverünk felé menő 53/udp csomagokon.
- REDIRECT: átírja a célcímet a lokális gép címére, a portot megadhatjuk (pl. transzparens http-proxyhoz)
- ROUTE: routing-gányolás. Megadhatjuk, melyik interface-en menjen ki a csomag, vagy hogy melyiken jött be (!), vagy hogy melyik gatewayen át kell küldeni. Le is tudja másolni a csomagot, így lehet pl. monitoring portot eszkábálni linuxos switchre.
- SET: hozzáadja a forrás- vagy cél-IP-t vagy -portot egy ipset-hez, vagy törli belőle (l. később)
- TARPIT: tcp-s "szurokgödör"; váratja a túloldalt, a kapcsolatot nem hagyja lebontani (pl. féregterjedés lassítására ajánlják - de csak buta féreg ellen jó, ill. buta portscan ellen is)
- TRACE: bekapcsolja a nyomkövetést az adott csomagon. Naplóüzenet keletkezik, valahányszor a csomag illeszkedik egy szabályra.
- TTL: a TTL-mezőt állítgathatjuk vele - miért akarnánk ilyet csinálni?
- ULOG: összetett naplózás. Házi feladat.
- XOR: egyszerű "titkosítás". Közben, úgy tűnik, megszűnt.
[szerkesztés] 7 Tűzfalscriptek írása
Általános jótanács: ha nem ülünk a gép előtt, mindig hagyjunk egérutat új tűzfalkonfiguráció élesítésekor; nem jó egy elgépelés miatt utazni.
[szerkesztés] 7.1 Naiv módszer
- Rakjuk össze a szabályrendszert a parancssorból. Az iptables-save elmenti, utána rebootkor, vagy amikor kell, az iptables-restore-ral betölthetjük.
- Előnyök:
- Egyszerű
- Gyorsan megvan
- Újratöltéskor a szabályok betöltése atomi
- Viszonylag könnyű permanens módosításokat automatizálni
- Hátrányok:
- Karbantartás nehézkes
- Dinamikus szabályok készítése nehézkes (pl. dinamikus hostnevek IP-címeinek követése)
- Bár ipset-tel megoldható
- Kommentálni csak az egyes szabályok szintjén lehet; hosszabb magyarázatot nem tudunk elhelyezni közben
- Könnyen átláthatatlanná válik
- Nem választja el a "kódot" a konfigurációtól
- Nehéz a konfiguráció bizonyos részeit más gépen újrahasznosítani
- Nehéz nem azonos, de hasonló tűzfalakat szinkronban tartani
- Jogok részleges delegálása lehetetlen
Példa:
# iptables -t nat -A POSTROUTING -j MASQUERADE -o ppp0 -m comment --comment "Replace source address on outgoing packets" # iptables -A FORWARD -j ACCEPT -m comment --comment "Explicitly no filtering" # echo 1 > /proc/sys/net/ipv4/ip_forward # iptables-save >/etc/firewall/saved
Figyelem! Ez a példa nem jó!
- Ész nélkül mindent forwardol mindenhonnan mindenhova
- INPUT-szűrés sincs benne
- Ez kb. egy minimális ADSL-megosztási konfiguráció
- De legalább kommentezve van!
[szerkesztés] 7.2 Spagettiscript
- Írjunk egy monolitikus scriptet, ami először töröl minden szabályt, majd betölti a szükséges szabályokat
- Előnyök:
- Egyszerű
- Viszonylag gyorsan megvan
- Dinamikus szabályokat is megadhatunk (betöltéskor lesz DNS lookup)
- A script kommentálható
- Minimális mértékben elválasztható a kód és a konfiguráció (pl. a script elején shell-változókban beállíthatjuk a "konfigurációt")
- A script bizonyos részeit átvihetjük más gépre
- Hátrányok:
- Ha több dinamikus szabály is felhasználja ugyanazt a hosztnevet, feleslegesen lassú
- Különösen, ha az adott domain DNS-szerverei egyáltalán nem válaszolnak
- Könnyen átláthatatlanná válik
- Nehéz nem azonos, de hasonló tűzfalakat szinkronban tartani
- A tűzfalszabályok betöltése nem atomi
- Nehéz permanens módosításokat automatizálni
- Jogok részleges delegálása lehetetlen
- Ha több dinamikus szabály is felhasználja ugyanazt a hosztnevet, feleslegesen lassú
Példa:
#!/bin/sh # Remove any existing rules from all chains iptables -F iptables -F -t nat iptables -F -t mangle # Remove any pre-existing user-defined chains iptables -X iptables -X -t nat iptables -X -t mangle # Zero counters iptables -Z # Set the default policy to drop iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP # Allow unlimited traffic on the loopback interface iptables -A INPUT -j ACCEPT -i lo iptables -A OUTPUT -j ACCEPT -o lo iptables -A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED iptables -A INPUT -j ACCEPT -p tcp --dport ssh -s 1.2.3.4 iptables -A FORWARD -j ACCEPT -m state --state ESTABLISHED,RELATED iptables -A FORWARD -j ACCEPT -p tcp --dport www -d 2.3.4.5 iptables -A FORWARD -j ACCEPT -p tcp --dport https -d 2.3.4.5 iptables -A FORWARD -j ACCEPT -p tcp --dport smtp -d 2.3.4.6 iptables -A FORWARD -j ACCEPT -p tcp --dport www -s 2.3.4.7 # http proxy can talk to net iptables -A FORWARD -j ACCEPT -p tcp --dport https -s 2.3.4.7 # http proxy can talk to net iptables -A FORWARD -j ACCEPT -p tcp --dport smtp -s 2.3.4.6 # mailserver too # intranet clients can access DMZ iptables -A FORWARD -j ACCEPT -i eth2 -o eth1 -m state --state NEW iptables -A OUTPUT -j ACCEPT -m ESTABLISHED,RELATED iptables -A OUTPUT -j ACCEPT -d 1.2.3.4 iptables -A OUTPUT -j ACCEPT -o eth1 # firewall can access DMZ
- Ez sem igazán jó példa, inkább állatorvosi ló
- Ami követendő lehet belőle: előre írtam a rendelkező részt, és "táblázatszerűen" tagoltam a scriptet, így jobban olvasható, mint ömlesztve
[szerkesztés] 7.3 Strukturált script
- "Shell-tömbök" adják a konfiguráció ACL-jeit (pl. WEBSERVERS="192.168.1.2 192.168.1.3 192.168.1.4")
- Főként zsh-ban érdemes valódi tömböket használni: WEBSERVERS=(192.168.1.2 192.168.1.3 192.168.1.4)
- Shell-függvények felelősek bizonyos láncok összeállításáért (pl. ACCEPT() proto tcp from 0/0 to "$WEBSERVERS" srcport any dstport 80 parent INPUT)
- Vagy ha nem is függvények, legalább ciklusok
- A DNS-alapú szabályokhoz szükséges DNS-feloldásokat egyszer végezzük el, az eredményt tároljuk és újrafelhasználjuk
- Előnyök:
- Jól szétválasztja a kódot és a konfigurációt
- Átláthatóvá tehető
- Aránylag gyorsan lefut (bár sok szabály felvétele még mindig lassú)
- Hátrányok:
- A shell-függvényeket meg kell hozzá írni, és ez nem feltétlenül triviális (vagy: van kész megoldás?)
- A kódot rajtunk kívül senki sem érti majd
- A tűzfalszabályok betöltése nem atomi
- Nehéz (bár már könnyebb) nem azonos, de hasonló tűzfalakat szinkronban tartani
- Nehéz permanens módosításokat automatizálni
- Jogok részleges delegálása lehetetlen
- Megnehezíti az implementációt, ha olyan DNS-feloldásokat is cache-elni akarunk, amelyek egynél több címet adnak vissza
- Az ipset igazából sokkal elegánsabb megoldás, mint a shell-tömb, és 2021-ben már teljesen használható is
Példa (figyelem! nem jó!):
#!/bin/zsh LOCK=/var/run/firewall.lock [ -f $LOCK ] && exit 0 # Pozor! Ez így nem jó! Versenyhelyzet! Így nem lehet shellben kölcsönös kizárást csinálni! touch $LOCK myip=1.2.3.4 broadcast=1.2.3.255 function iptables() { /sbin/iptables "$@" || echo "failed: iptables $@" } for i in ip_tables iptable_filter ipt_limit ipt_mac ipt_owner ip_nat_ftp ip_nat_irc ipt_unclean ipt_REJECT ipt_REDIRECT; do modprobe $i 2>/dev/null >/dev/null done # # CHAINS: Ezeket a chaineket kell letrehozni # CHAINS=(trusted samba ftp squid printer icmpch telnet mysql fwdrop spoof icmpdrop trustrej xrej localrej ftprej fullban squidrej) # # LOCALONLY a csak localhostrol mukodo szolgaltatasok listaja # LOCALONLY=(mysql) # # TRUSTONLY: Ami csak a "trusted" gepekrol megy # TRUSTONLY=(samba printer telnet) # # TOTALBAN: Akiktol semmit nem fogadunk # TOTALBAN=( 2.3.4.5 3.4.5.0/24 ) # # A TRUSTED-ben azokat az ip-ket soroljuk fel, ahonnan a legtobb dolgot # engedjuk (pl. printert, sambat is). # TRUSTED=( 1.2.3.0/24 10.1.2.128/25 azengepem.dyndns.org ) iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X iptables -F iptables -X iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD DROP # Uj chain-ek letrehozasa for i in "$CHAINS[@]" ; do iptables -N $i done iptables -A fwdrop -m limit --limit 10/minute -j LOG --log-prefix "FORWARD DROP: " iptables -A fwdrop -j DROP iptables -A spoof -m limit --limit 10/minute -j LOG --log-prefix "spoofed packet: " iptables -A spoof -j DROP # Spoof protection iptables -A INPUT -i tap+ -j ACCEPT iptables -A OUTPUT -o tap+ -j ACCEPT iptables -A INPUT -i br+ -j ACCEPT iptables -A OUTPUT -o br+ -j ACCEPT # az etherneten fogadjuk a tolunk jovo broadcastokat es multicastokat iptables -A INPUT -i eth+ -s $myip -d $broadcast -j ACCEPT iptables -A INPUT -i eth+ -s $myip -d 224.0.0.0/4 -j ACCEPT # nem fogadjuk a .0 vegu cimre kuldott csomagokat, az nem hivatalos broadcast iptables -A INPUT -i eth+ -d 1.2.3.0/32 -j DROP # Az etheren nem fogadjuk a 127.0.0.akarhanyas IP-rol jovo csomagokat iptables -A INPUT -i eth+ -s 127.0.0.0/8 -j spoof # Az etheren nem fogadjuk a tolunk jovo csomagokat iptables -A INPUT -i eth+ -s $myip -j spoof # fogadjuk a nem-icmp jellegu teljes broadcastokat iptables -A INPUT -i eth+ -p ! icmp -d 255.255.255.255 -j ACCEPT # Trusted chain felepitese for i in "$TRUSTED[@]"; do iptables -A trusted -s $i -j ACCEPT done iptables -A trusted -i lo -j ACCEPT iptables -A trusted -j trustrej # Csak trusted hostokrol elerheto: for i in "$TRUSTONLY[@]"; do iptables -A $i -j trusted iptables -A $i -j trustrej done iptables -A trustrej -d $broadcast -j DROP iptables -A trustrej -m limit --limit 10/minute -j LOG --log-prefix "not trusted: " iptables -A trustrej -j REJECT --reject-with icmp-port-unreachable for i in "$LOCALONLY[@]"; do iptables -A $i -s $myip -j ACCEPT iptables -A $i -i lo -j ACCEPT iptables -A $i -j localrej done iptables -A localrej -m limit --limit 10/minute -j LOG --log-prefix "not local: " iptables -A localrej -j REJECT --reject-with icmp-port-unreachable for i in ftp telnet printer; do iptables -A INPUT -p tcp --dport $i -j $i done [...]
- Ez minden volt, csak átlátható nem, pedig fiatal korában olyannak indult
[szerkesztés] 7.4 Strukturált, modularizált script
- Mint fent, de rc.d mechanizmust használva szétszedjük sok kicsi file-ra
- Az ACL-ekhez használjunk felsorolás-file-okat (ha ezek include-olhatják egymást, az tovább csökkenti az adminisztrációs terheket)
- Előnyök:
- Teljesen szétválasztja a kódot és a konfigurációt
- Átláthatóvá tehető
- Könnyű nem azonos, de hasonló tűzfalakat szinkronban tartani
- Jogok részleges delegálása körülményes, de megoldható
- Hátrányok:
- A shell-függvényeket meg kell hozzá írni (bár van kész megoldás, az "iptablez" by yours truly)
- A kódot rajtunk kívül senki sem érti majd
- A tűzfalszabályok betöltése nem atomi
- További javítási lehetőség:
- Ne az iptables-t hívogassuk, hanem állítsunk elő iptables-restore formátumú szövegfile-t, majd a végén töltsük be azt; így atomivá válik a szabályok betöltése
Példa (ilyet használtam 2012 körül; ez az "iptablez"):
#!/bin/zsh #exec 2>/tmp/fw2.log #exec >/tmp/fw-out.log BASEDIR=/etc/firewall DEFAULTS=$BASEDIR/firewall-defaults [[ -r "$DEFAULTS" ]] && . $DEFAULTS # Itt a defaultokat nem előre állítjuk be, hogy aztán a config felülbírálja, # hanem utólag, ha a configban nem volt megadva semmi; így is lehet, csak # így a config nem állíthat változót üres sztringre CONFDIR=${CONFDIR:-$BASEDIR/conf.d} SCRIPTDIR=${SCRIPTDIR:-$BASEDIR/script.d} PREDIR=${PREDIR:-$BASEDIR/pre.d} POSTDIR=${POSTDIR:-$BASEDIR/post.d} ACLDIR=${ACLDIR:-$BASEDIR/acl.d} RESTOREDIR=$BASEDIR/restore [[ "$1" = "" ]] || DEBUG=$1 DEBUG=${DEBUG:-1} TRANSITIONAL_POLICY=${TRANSITIONAL_POLICY:-ACCEPT} # what to set policies to while the firewall is being initialized UNLOAD_MODULES=${UNLOAD_MODULES:-0} function debug() { if [[ "$DEBUG" -ge "$1" ]]; then shift echo "$@" fi } [[ -d "$PREDIR" ]] && for depth in {10..1}; do find "$PREDIR" -mindepth $depth -maxdepth $depth ! -type d \ | fgrep -v /.svn/ \ | sort \ | while read i; do PREFILES=($PREFILES $i) done done for script_i in $PREFILES[@]; do if [[ -r "$script_i" ]]; then debug 2 Sourcing "$script_i"... . "$script_i" else debug 1 WARNING: "$script_i" is unreadable. fi done debug 2 Sourcing functions... . "$BASEDIR/functions" iptables_init # Can't assume no sourced script will read from stdin, so assmble list of # files to source before sourcing first one: for dir in "$CONFDIR" "$SCRIPTDIR"; do for depth in {10..1}; do find "$dir" -mindepth $depth -maxdepth $depth ! -type d \ | fgrep -v /.svn/ \ | sort \ | while read i; do FILES=($FILES $i) done done done # Sourced files likely contain loops with "i" as the loop variable... for script_i in $FILES[@]; do if [[ -r "$script_i" ]]; then debug 2 Sourcing "$script_i"... . "$script_i" else debug 1 WARNING: "$script_i" is unreadable. fi done iptables_commit ret=$? [[ -d "$POSTDIR" ]] && for depth in {10..1}; do find "$POSTDIR" -mindepth $depth -maxdepth $depth ! -type d \ | fgrep -v /.svn/ \ | sort \ | while read i; do POSTFILES=($POSTFILES $i) done done for script_i in $POSTFILES[@]; do if [[ -r "$script_i" ]]; then debug 2 Sourcing "$script_i"... . "$script_i" else debug 1 WARNING: "$script_i" is unreadable. fi done exit $ret
Nézzük a functions file-t (ma már azért néhány dolgot másképp csinálnék, egyszer majd aktualizálom):
# # scriptlets to ease the construction of iptables firewalls # # readacl() # # returns non-comment lines from the ACL file $1 # supports includes; a line starting with ". " specifies a filename to # include, e.g.: ". $ACLDIR/other_file". Recursive including is supported; # be careful to avoid loops! Also, very deep include trees may exhaust file # descriptor limits. Shell variables in ACLs are expanded. # function readacl() { local i egrep -v '^[[:space:]#]*$|^#' "$1" \ | sed 's/[[:space:]]*#.*//' \ | while read -r i; do if [[ "$i" == "${i#. }" ]]; then echo "${(e)i}" else readacl "${(e)i#. }" fi done \ | egrep -v '^[[:space:]#]*$|^#' \ | sed 's/[[:space:]]*#.*//' } # reads 'ipset' commands from $IPSET_CONF (/etc/firewall/ipset.conf by # default) and executes them; supports shell variables and includes (since # it uses readacl()). ipset comments should appear at the end of the ipset # command line. Otherwise, ipset.conf is like 'ipset save' output. function restore-ipsets() { local -a args line readacl ${IPSET_CONF:-/etc/firewall/ipset.conf} | while read -rA line; do while [[ -n $line[1] ]]; do case $line[1] in # when reading comment, remove quotes and parse the rest of the line into a single word: comment) shift line; args=($args comment "${line//\"/}"); unset line;; *) args=($args $line[1]); shift line;; esac done if ! ipset $args; then echo "failing ipset command was: $args" >&2 fi unset args done } # # Stuff for the INPUT and OUTPUT chains (mostly anyway) # # buildchain(), buildtcpchain() and buildudpchain() # # buildchain() # # Usage: buildchain table PARENTCHAIN name parentselector childselector # ACLFILE action1 action2 message2 silentdropacl silentdropaction # # childselector can be empty, in which case it should prefix each line in # the ACLFILE. # # example: buildchain filter ssh INPUT "-p tcp --dport ssh" "-s" \ # /etc/firewall/acls/ssh_allow ACCEPT REJECT "FW: ssh REJECT: " # /etc/firewall/acls/sshprobes # # Will use LOGLIMIT, if set. If called with only one parameter, assumes it # is a config file and will source it. # function buildchain() { if [[ "$2" = "" ]]; then . "$1" else local TABLE="$1" local PARENT_CHAIN="$2" local CHAIN="$3" local PARENT_SELECTOR="$4" local CHILD_SELECTOR="$5" local ACLFILE="$6" local PRIMARY_ACTION="$7" local SECONDARY_ACTION="$8" local SECMESSAGE="$9" local SILENTACL="$10" local SILENTDROP="${11:-DROP}" fi local i=0 if iptables -t $TABLE -N $CHAIN; then # We only build the chain if it didn't already exist. readacl "$ACLFILE" | while read i; do iptables -t $TABLE -A $CHAIN ${=CHILD_SELECTOR} ${=i} -j ${=PRIMARY_ACTION} done [[ -n "$SILENTACL" ]] && readacl "$SILENTACL" | while read i; do iptables -t $TABLE -A $CHAIN ${=i} -j ${=SILENTDROP} done [[ -n "$SECMESSAGE" ]] && iptables -t $TABLE -A $CHAIN ${=LOGLIMIT} -j LOG --log-prefix "$SECMESSAGE" iptables -t $TABLE -A $CHAIN -j ${=SECONDARY_ACTION} fi iptables -t $TABLE -A $PARENT_CHAIN ${=PARENT_SELECTOR} -j $CHAIN # enable it in the parent chain } # buildtcpchain() # # Usage: buildtcpchain { servicename|portnumber } # # buildtcpchain ssh is equivalent to (a shorthand for): # # buildchain filter INPUT ssh_input "-p tcp --dport ssh" "-s" # $ACLDIR/ssh ACCEPT ${=REJECT} "FW: ssh DROP: " # function buildtcpchain() { local PORT="$1" local MYREJECT="${REJECT:-REJECT -p tcp --reject-with tcp-reset}" local MYACLDIR="${ACLDIR:-/etc/firewall/acl.d}" local CHAIN="${PORT}_input" local ACL="$MYACLDIR/${PORT}" local FRIENDLYNAME="${PORT}" local PARENT=INPUT shift while [[ ! "$1" = "" ]]; do case "$1" in "-c") shift local CHAIN="${1:-${PORT}_input}" shift ;; "-a") shift local ACL="${1:-$MYACLDIR/${PORT}}" shift ;; "-n") shift local FRIENDLYNAME="${1:-tcp/$PORT}" shift ;; "-p") shift local PARENT="$1" shift ;; *) debug 1 buildtcpchain ignoring unknown parameter \""$1"\". shift ;; esac done buildchain filter "$PARENT" "$CHAIN" \ "-p tcp --dport $PORT" "-s" \ "$ACL" \ ACCEPT "$MYREJECT" "FW: $FRIENDLYNAME DROP: " } # buildudpchain() # # Usage: buildudpchain { servicename|portnumber } # # buildudpchain ntp is equivalent to (a shorthand for): # # buildchain filter INPUT ntp_input "-p udp --dport ntp" "-s" # $ACLDIR/ntp ACCEPT ${=REJECT} "FW: ntp DROP: " # function buildudpchain() { local PORT="$1" local MYREJECT="${REJECT:-REJECT --reject-with tcp-reset}" local MYACLDIR="${ACLDIR:-/etc/firewall/acl.d}" local CHAIN="${PORT}_input" local ACL="$MYACLDIR/${PORT}" local FRIENDLYNAME="${PORT}" local PARENT=INPUT shift while [[ ! "$1" = "" ]]; do case "$1" in "-c") shift local CHAIN="${1:-${PORT}_input}" shift ;; "-a") shift local ACL="${1:-$MYACLDIR/${PORT}}" shift ;; "-n") shift local FRIENDLYNAME="${1:-udp/$PORT}" shift ;; "-p") shift local PARENT="$1" shift ;; *) debug 1 buildudpchain ignoring unknown parameter '"'"$1"'"'. shift ;; esac done buildchain filter "$PARENT" "$CHAIN" \ "-p udp --dport $PORT" "-s" \ "$ACL" \ ACCEPT "$MYREJECT" "FW: $FRIENDLYNAME DROP: " } # # Stuff for the FORWARD chain # # We need a function to police multipoint-multipoint traffic. pt-mpt, mpt-pt # and pt-pt are special cases (which could be handled specially, but # aren't). In fact, buildchain() can be used for these with an appropriately # chosen parentselector. # # build_multipoint_chain() is the most generic function. # # It will create two chains, like this: # # something_1: # -s sip1 -j something_2 # -s is childselector1 # -s sip2 -j something_2 # [...] # -j LOG --log-message "FW: something source DROP: " # message1 # -j REJECT # REJECT is action2 # # something_2: # -d dip1 -j ACCEPT # -d is childselector2 # -d dip2 -j ACCEPT # ACCEPT is action1 # [...] # -j LOG --log-message "FW: something destination DROP: " # message2 # -j REJECT # REJECT is action2 # # Usage: build_multipoint_chain table PARENTCHAIN name parentselector childselector1 # ACLFILE1 childselector2 ACLFILE2 action1 action2 message1 message2 # # This function performs an optimiziation based on the size of the ACLs # (it is faster to use the smaller one first). It is your responsibility to # not call it with chain names that already exist. function build_multipoint_chain() { if [[ "$2" = "" ]]; then . "$1" else local TABLE="$1" local PARENT_CHAIN="$2" local CHAIN_1="${3}_1" local CHAIN_2="${3}_2" local PARENT_SELECTOR="$4" local ACLFILE_1="$6" local ACLFILE_2="$8" local ACL_1_SIZE="$(readacl "$ACLFILE_1" | wc -l)" local ACL_2_SIZE="$(readacl "$ACLFILE_2" | wc -l)" if [[ "$ACL_1_SIZE" -le "$ACL_2_SIZE" ]]; then local CHILD_1_SELECTOR="$5" local CHILD_2_SELECTOR="$7" local MESSAGE_1="$11" local MESSAGE_2="$12" else local CHILD_1_SELECTOR="$7" local CHILD_2_SELECTOR="$5" local MESSAGE_1="$12" local MESSAGE_2="$11" ACLFILE_1="$8" ACLFILE_2="$6" fi local PRIMARY_ACTION="$9" local SECONDARY_ACTION="$10" fi local i=0 iptables -t $TABLE -N $CHAIN_1 iptables -t $TABLE -N $CHAIN_2 # build first chain readacl "$ACLFILE_1" | while read i; do iptables -t $TABLE -A $CHAIN_1 ${=CHILD_1_SELECTOR} ${=i} -j $CHAIN_2 done iptables -t $TABLE -A $CHAIN_1 ${=LOGLIMIT} -j LOG --log-prefix "$MESSAGE_1" iptables -t $TABLE -A $CHAIN_1 -j ${=SECONDAY_ACTION} # build second chain readacl "$ACLFILE_2" | while read i; do iptables -t $TABLE -A $CHAIN_2 ${=CHILD_2_SELECTOR} ${=i} -j ${=PRIMARY_ACTION} done iptables -t $TABLE -A $CHAIN_1 ${=LOGLIMIT} -j LOG --log-prefix "$MESSAGE_2" iptables -t $TABLE -A $CHAIN_1 -j ${=SECONDAY_ACTION} iptables -t $TABLE -A $PARENT_CHAIN ${=PARENT_SELECTOR} -j $CHAIN_1 # enable it in the parent chain } # # get_ports_of() # # Usage: get_ports_of {REGEX} {u|t} # # returns a comma-separated list of ports that a process matching REGEX # listens on (as displayed by netstat). u is for udp, t is for tcp. # REGEX is an extended regular expression. # function get_ports_of() { echo \ $(netstat -n${2}lp \ | egrep -- "$1" \ | cut -d: -f2\ | sed 's/[[:space:]].*//' \ ) \ | tr ' ' ',' } # Get first IP of hostname; optional 2nd argument specifies fallback IP to report function get_ip_of() { timeout -k 1 5 dnsip $1 | sed 's/[[:space:]].*//g' [[ $pipestatus[1] -gt 0 ]] && { echo "Failed to obtain IP of $1 via DNS.${2:+ Defaulting to $2.}" >&2 [[ -n "$2" ]] && echo -E "$2" } } # Get main IP of interface function ip_of_if() { if [[ -x /usr/bin/ifdata ]]; then ifdata -pa $1 | grep -v NON-IP else ifconfig $1 | sed -n '2s/ [^r]*..//gp' fi } # Get broadcast address of interface function get_if_broadcast() { if [[ -x /usr/bin/ifdata ]]; then ifdata -pb $1 | grep -v NON-IP else ifconfig $1 | grep 'inet addr:' | sed 's/.*Bcast://;s/ .*//' fi } # returns success if an interface exists, failure if it doesn't function if_exists() { if [[ -x /usr/bin/ifdata ]]; then ifdata -e $1 else grep -q "^[[:space:]]*$1: " /proc/net/dev fi } # returns success if an interface is 'up', failure if not function if_up() { if_exists $1 || return 1 if [[ -x /usr/bin/ifdata ]]; then ifdata -pf $1 | egrep -q '^On[[:space:]]+Up$' else ip link sh $1 | egrep -q "state UP " fi } # Does the interface exist and if yes, does it have an ipv4 IP? function has_ip() { ip addr sh dev $1 2>/dev/null | grep -q "^[[:space:]]*inet " } # # Don't actually call iptables; rather, build an iptables-restore compatible # text file. # function iptables() { debug 5 Executing /sbin/iptables "$@" local w if [[ "$1" == "-t" ]]; then TABLE=$2 shift shift else TABLE=filter fi if [[ "$1" == "-N" ]]; then iptables-save -c -t $TABLE | grep "^:$2 " >>"$RESTOREDIR/${TABLE}.chains" || echo ":$2 - [0:0]" >>"$RESTOREDIR/${TABLE}.chains" shift shift elif [[ "$1" == "-P" ]]; then iptables-save -c -t $TABLE | grep "^:$2 $3 " >>"$RESTOREDIR/${TABLE}.policies" || echo ":$2 $3 [0:0]" >>"$RESTOREDIR/${TABLE}.policies" else while [[ -n "$1" ]]; do case $1 in *\ *) echo -n " ${(qqq)1}"; shift;; # quote words with embedded spaces DNAT) echo -n " DNAT --to-destination"; shift 2;; # convert "DNAT --to" to "DNAT --to-destination" *) w=${1//\/minute//min}; w=${w//\/second//sec}; echo -n " $w"; shift;; # iptables-save only supports "min" and "sec", not "minute" and "second" esac done >>"$RESTOREDIR/${TABLE}.rules" echo >>"$RESTOREDIR/${TABLE}.rules" fi } # Set up the work directory. function iptables_init() { rm -rf "$RESTOREDIR" mkdir -p "$RESTOREDIR" } # Load the rules we created. function iptables_commit() { PWD="$(pwd)" cd "$RESTOREDIR" for table in filter nat mangle; do touch ${table}.policies if [[ (-e ${table}.chains) || (-e ${table}.policies) || (-e ${table}.rules) ]]; then echo '*'"$table" >>commit if [[ "$table" == "filter" ]]; then builtin="INPUT OUTPUT FORWARD" elif [[ "$table" == "nat" ]]; then builtin="PREROUTING POSTROUTING OUTPUT" elif [[ "$table" == "mangle" ]]; then builtin="PREROUTING INPUT FORWARD OUTPUT POSTROUTING" else echo "Unknown table $table!" return 1 fi for chain in "${=builtin}"; do grep ^:$chain ${table}.policies >>commit || iptables-save -c -t $table | grep "^:$chain " >>commit done [[ -e ${table}.chains ]] && cat ${table}.chains >>commit [[ -e ${table}.rules ]] && cat ${table}.rules >>commit echo COMMIT >>commit fi done iptables-restore <commit cd "$PWD" }
És nézzünk meg néhány konkrét scriptletet a script.d-ből:
- 200blacklisted:
iptables -N blacklisted # example: # REJECT_BEFORE_DROP=(-j REJECT --reject-with admin-prohib $ICMP_OUT_LIMIT -m set --match-set private_nets src -m comment --comment "Internal clients get a helpful ICMP error, subject to rate limiting") iptables -A blacklisted -j LOG --log-prefix "FW: blacklisted DROP: " $LOGLIMIT -m comment --comment "Log packets to and from blacklisted IPs with a rate limit" [[ -v REJECT_BEFORE_DROP ]] && iptables -A blacklisted $REJECT_BEFORE_DROP iptables -A blacklisted -j DROP -m comment --comment "In other cases, we just drop the packets with no ICMP"
- 200icmp_forward:
iptables -N icmp_forward iptables -N icmp_forward_limit iptables -A icmp_forward_limit $ICMP_FORWARD_LIMIT -j ACCEPT iptables -A icmp_forward_limit -j DROP readacl $ACLDIR/usefulicmp \ | while read i; do iptables -A icmp_forward -p icmp --icmp-type $i -j icmp_forward_limit done iptables -A icmp_forward $LOGLIMIT -j LOG --log-prefix "FW: offensive ICMP: " iptables -A icmp_forward -j DROP
- 200icmp_input:
iptables -N icmp_input iptables -N icmp_input_limit iptables -A icmp_input_limit $ICMP_IN_LIMIT -j ACCEPT iptables -A icmp_input_limit -j DROP readacl $ACLDIR/usefulicmp \ | while read i; do iptables -A icmp_input -p icmp --icmp-type $i -j icmp_input_limit done iptables -A icmp_input $LOGLIMIT -j LOG --log-prefix "FW: offensive ICMP: " iptables -A icmp_input -j DROP
- 200smtp (primitív greylisting):
iptables -N smtp_refused iptables -A smtp_refused $LOGLIMIT -j LOG --log-prefix "FW: SMTP greylist: " iptables -A smtp_refused -p tcp -j REJECT --reject-with tcp-reset iptables -A smtp_refused -j DROP iptables -N smtp readacl $ACLDIR/smtp-whitelist \ | while read i; do iptables -A smtp -s $i -j ACCEPT done # If first connection arrived in last 180 seconds, REJECT iptables -A smtp -m recent --rcheck --name SMTP_grey --seconds ${SMTP_GREYLIST_TIME:-180} -j smtp_refused # If first connection arrived earlier than 180 seconds, ACCEPT iptables -A smtp -m recent --rcheck --name SMTP_grey -j ACCEPT # If neither (new IP), remember IP and REJECT iptables -A smtp $LOGLIMIT -j LOG --log-prefix "FW: SMTP greylist: " iptables -A smtp -p tcp -m recent --set --name SMTP_grey -j REJECT --reject-with tcp-reset iptables -A smtp -j DROP
- 200tcp_rst_forward:
iptables -N tcp_rst_forward iptables -A tcp_rst_forward $TCP_RST_FORWARD_LIMIT -j ACCEPT iptables -A tcp_rst_forward $LOGLIMIT -j LOG --log-prefix "FW: tcp rst forward DROP: " iptables -A tcp_rst_forward -j DROP
- 500input:
iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -i tap+ -s 192.168.0.0/16 -j ACCEPT iptables -A INPUT -i br+ -s 192.168.0.0/16 -j ACCEPT iptables -A INPUT -p icmp -j icmp_input # Doesn't scale well for long blacklists/high traffic readacl $ACLDIR/blacklist \ | while read -A i; do iptables -A INPUT -s $i -j blacklisted done iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -s $ME -d $ETH_BROADCAST -j ACCEPT iptables -A INPUT -s $ME -d $TAP_BROADCAST -j ACCEPT iptables -A INPUT -s 0.0.0.0 -d 255.255.255.255 -p udp --sport 68 --dport 67 -j ACCEPT # dhcp iptables -A INPUT -s $DHCPSUBNET -d 255.255.255.255 -p udp --sport 68 --dport 67 -j ACCEPT # dhcp iptables -A INPUT -m pkttype --pkt-type multicast -j ACCEPT iptables -A INPUT -p igmp -j ACCEPT # maybe ratelimit? # Filter strange/spoofed packets readacl $ACLDIR/martian \ | while read -A i; do iptables -A INPUT $i -j martian done # Enable all public services (with no ACLs) readacl $ACLDIR/publicservices \ | while read -A i; do iptables -A INPUT $i -j ACCEPT done iptables -A INPUT -p tcp --dport 25 -m state --state NEW -j smtp # Simple TCP services buildtcpchain 8000 -c privoxy -a $ACLDIR/privoxy -n privoxy buildtcpchain pop3 -a $ACLDIR/plaintext buildtcpchain imap2 -a $ACLDIR/plaintext buildtcpchain munin buildtcpchain mysql buildtcpchain printer buildtcpchain rsync buildudpchain syslog # Simple UDP services buildudpchain ntp buildudpchain 5000 -c openvpn -a $ACLDIR/openvpn -n openvpn # DNS buildtcpchain domain -c dns -a $ACLDIR/dns -n dns iptables -A INPUT -p udp --dport domain -j dns # IPP (cups) buildtcpchain ipp iptables -A INPUT -p udp --dport ipp -j ipp_input # squid buildchain filter INPUT squid "-p tcp -m multiport --dports 3128,31280" "-s" $ACLDIR/squid \ ACCEPT "REJECT --reject-with admin-prohib" "FW: squid DROP: " iptables -A INPUT -p udp -m multiport --dports $(get_ports_of /squid u) -j squid # telnet, telnets buildtcpchain telnet -a $ACLDIR/plaintext buildtcpchain telnets -a $ACLDIR/trusted # rpc buildchain filter INPUT rpc_input "-p tcp --dport sunrpc" "-s" $ACLDIR/trusted ACCEPT DROP "FW: rpc DROP: " $ACLDIR/silent_rpc_drop DROP iptables -A INPUT -p tcp -m multiport --dports 2049,$(get_ports_of "/rpc|[[:space:]]-[[:space:]]*$" t) -j rpc_input iptables -A INPUT -p udp -m multiport --dports sunrpc,$(get_ports_of "/rpc|[[:space:]]-[[:space:]]*$" u) -j rpc_input # ident ban buildchain filter INPUT auth "-p tcp --dport auth" "-p tcp -s" $ACLDIR/identban \ "REJECT --reject-with tcp-reset" ACCEPT # samba buildchain filter INPUT samba "-p tcp -m multiport --dports 135,137,138,139,445" "-s" \ $ACLDIR/samba ACCEPT DROP "FW: samba DROP: " $ACLDIR/sambasilent DROP iptables -A INPUT -p udp -m multiport --dports 135,137,138,139,445 -j samba # Some stuff is too common to log, drop it silently readacl $ACLDIR/silentdrop \ | while read -A i; do iptables -A INPUT $i -j DROP done # Everything else, we drop noisily. iptables -A INPUT $LOGLIMIT -j LOG --log-prefix "FW: input catch-all: " iptables -A INPUT -j DROP
- 500forward:
iptables -A FORWARD -p icmp -j icmp_forward iptables -A FORWARD -p tcp --tcp-flags RST RST -j tcp_rst_forward iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A FORWARD -i tap+ -s 192.168.0.0/16 -j ACCEPT iptables -A FORWARD -i br+ -s 192.168.0.0/16 -j ACCEPT iptables -A FORWARD -o tap0 -j ACCEPT # anything with source addresses not in the above range is suspicious iptables -A FORWARD -i tap+ -j martian iptables -A FORWARD -i br+ -j martian readacl $ACLDIR/blacklist \ | while read -A i; do iptables -A FORWARD -s $i -j blacklisted done readacl $ACLDIR/martian \ | while read -A i; do iptables -A FORWARD $i -j martian done iptables -A FORWARD $LOGLIMIT -j LOG --log-prefix "FW: forward catch-all: " iptables -A FORWARD -j DROP
- Ez nem a teljes konfiguráció volt (pl. az OUTPUTban is az icmp_forward segítségével rátalimitáljuk a kiküldött icmp-ket)
- Látható, hogy a modularitásnak köszönhetően egyes modulok átvihetők más gépekre akár a többitől függetlenül is
- Annak ellenére, hogy látszólag az iptables-t hívja, iptables-restore-ral fogja betölteni a szabályokat, atomi módon
- Gond: hosszú ACL-ek kezelése nem hatékony, főleg, ha több nagy ACL direktszorzatára van szükség
- Pl. a tűzfal mögött van 32 db Lotus Domino-szerver, és ezeket 100 kliens érheti el => 3200 szabály
- Megoldás: ipset
[szerkesztés] 8 Dinamikus hosztnevek IP-változásainak követése
- Primitív "protoVPN", nem ad igazi biztonságot, de jobb, mint az egész Internetnek nyújtani egy nem nyilvános szolgáltatást
A következő script újratölti a tűzfalat, ha megváltozik egy figyelt dinamikus IP (és pl. runitből futtatható):
#!/bin/zsh # # This runit service is intended to adjust firewall rules whenever the address associated with a hostname changes. # # Two mechanisms are provided for this: # # 1. enumerate the hostnames to check in a static file (./dyndnshosts which # the DYNHOSTS variable you can set in /etc/default/<servicename> # overrides). # # For each of these names, the script checks whether the IP changed since # the last run. If so, it checks if the name is referenced in any file in # FWDIR (following symlinks). If yes, FWCOMMAND is called. # # This way the dyndnshosts file can be shared among hosts; only names that # are actually relevant for the firewall configuration will trigger a # reload. # # 2. In DYNHOSTDIR (./dynhostdir by default), each filename is treated as a # hostname. If the file is not executable, the name is handled as if it had # occurred in the DYNHOSTS file. If it is executable, then it will be run # (as root) on IP change, regardless of whether the firewall configuration # references it. The working directory where the file is called from is # unspecified. Its stdout and stderr go to the stdout of this script. # Scripts will be run in parallel and killed after $TRIGGER_TIMEOUT seconds. # They're responsible for implementing their own mutual exclusion if # necessary. # # The scripts can access $CURRENTIP and $OLDIP, which are space separated lists # of the new and old IPs of the hostname. # # This mechanism allows ipsets to be adjusted without reloading the entire # firewall ruleset. # # If the return code is 99 (overridable with ALSO_RUN_FWCOMMAND), the # $FWCOMMAND will be run in addition to the DYNHOSTDIR/hostname file; in all # other cases, $FWCOMMAND will not be run for hostnames where # DYNHOSTDIR/hostname exists and is executable. # # The script uses dnsip(1) from the djbdns/dbndns package to perform # lookups. Future versions may also support other lookup tools. # # Currently only ipv4 is supported. exec 2>&1 exit=0 _me=$PWD/$0 trap 'exit=1' TERM HUP trap handle_sigchld CHLD SVNAME=$(basename $(pwd)) CONFIG=/etc/default/"$SVNAME" INTERVAL=150 FWCOMMAND=(chpst -l /run/lock/firewall.lock tryto /etc/firewall/firewall) FWDIR=/etc/firewall DNSTIMEOUT=30 TRIGGER_TIMEOUT=30 STATEDIR=/run/dyndns-firewall-trigger OUTDIR=$STATEDIR/cmdoutput # used to serialize output of commands run in parallel OUTLOCK=$OUTDIR/.lock TRIGGER_FILE=$STATEDIR/.trigger ALSO_RUN_FWCOMMAND=99 export VERBOSE=1 typeset -U OLDIP CURRENTIP [[ -r ./dyndnshosts ]] && DYNHOSTS=$PWD/dyndnshosts [[ -d ./dynhostdir/. ]] && DYNHOSTDIR=$PWD/dynhostdir setopt extendedglob zmodload zsh/datetime zmodload zsh/system zmodload zsh/zselect zmodload zsh/stat LASTMOD_RUN=$(stat +mtime $_me) if [[ -r "$CONFIG" ]]; then . "$CONFIG" NOCONFIG=0 LASTMOD_CONFIG=$(stat +mtime $CONFIG) else NOCONFIG=1 fi if [[ ! -d "$STATEDIR" ]]; then install -d -m 700 $STATEDIR $OUTDIR fi LASTRUN=${LASTRUN:-$EPOCHSECONDS} # On startup, pretend that processing just occurred, so we start with sleeping for $INTERVAL. We do this because we assume that on boot, the firewall rules were reloaded anyway. The config can override using LASTRUN=0 if desired. function host_changed_ip() { # returns true if the IP changed, false if not [[ -f $STATEDIR/$1 ]] || : >$STATEDIR/$1 OLDIP=(${(s: :n)$(< $STATEDIR/$1)}) CURRENTIP=(${(s: :n)$(timeout -k 3 $DNSTIMEOUT chpst -u nobody dnsip $1)}) if [[ ! ${(n)OLDIP[@]} == ${(n)CURRENTIP[@]} ]] && [[ "$CURRENTIP[1]" =~ "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" ]]; then echo "${(n)CURRENTIP}" >$STATEDIR/$1 ((VERBOSE)) && echo "INFO: IP of $1 changed from \"${(n)OLDIP}\" to \"${(n)CURRENTIP}\"". return 0 else ((VERBOSE)) && echo "INFO: IP of $1 unchanged: $CURRENTIP." return 1 fi } function should_exit() { # Returns true if we should exit, e.g. because the run file changed, the config file changed, or exit=1 (set by TERM or HUP signal). This ensures a timely exit after "sv stop" or "sv down". ((exit)) && return 0 [[ "$(stat +mtime $_me)" = "$LASTMOD_RUN" ]] || return 0 if ((NOCONFIG)); then [[ -r $CONFIG ]] && return 0 # if there was no configfile on startup but there is one now, we should read it -> exit and be restarted by runit else [[ "$(stat +mtime $CONFIG)" = "$LASTMOD_CONFIG" ]] || return 0 fi return 1 } function delay() { # Delays for $INTERVAL seconds, one second at a time. Returns successfully if further delay is necessary, unsuccessfully if not. We wait one second at a time to be able to react to signals. if [[ $[EPOCHSECONDS-LASTRUN] -le $INTERVAL ]]; then zselect -t 100 return 0 fi LASTRUN=$EPOCHSECONDS return 1 } function handle_sigchld() { # output serialization for children run in parallel local i lockfd lockfd2 [[ /. -ef $OUTDIR/. ]] && { echo "FATAL: OUTDIR appears to be unset or point to the root directory. Refusing to continue."; exec sv down ${_me:h} } : >>$OUTLOCK zsystem flock -f lockfd "$OUTLOCK" for i in $OUTDIR/*(#q-N); do : >>$OUTDIR/.lock.${i:t} if zsystem flock -f lockfd2 -t 0 $OUTDIR/.lock.${i:t} 2>/dev/null; then # check that we're no longer writing to this file cat $i rm -f $i zsystem flock -u $lockfd2 fi done zsystem flock -u $lockfd } typeset -A lockfds function subshell_boilerplate() { # handles locking and unsetting traps; args: <pre|post> <outfilename> local lockfd if [[ $1 = pre ]]; then trap - # subshells don't need special signal handlers : >>$OUTLOCK # make sure the lockfile exists before trying to lock it zsystem flock -f lockfd "$OUTLOCK" # we need the whole-directory lock because we'll create a new file in it and need to lock that before the sigchld handler has a chance to : >>$OUTDIR/.lock.$2 # the file should really already exist, because this subshell's output is written to it; but make absolutely sure zsystem flock -f lockfds\[$2\] $OUTDIR/.lock.$2 zsystem flock -u $lockfd # release the whole-directory lock now that we have the specific one else zsystem flock -u $lockfds[$2] fi } function check_for_ip_changes() { local host="" local ret=0 local -U plainhosts [[ /. -ef $OUTDIR/. ]] && { echo "FATAL: OUTDIR appears to be unset or point to the root directory. Refusing to continue."; exec sv down ${_me:h} } rm -f $TRIGGER_FILE rm -f $OUTDIR/*(N) [[ -v DYNHOSTS ]] && [[ -r $DYNHOSTS ]] && plainhosts=($(<$DYNHOSTS)) if [[ -v DYNHOSTDIR ]] && [[ -d $DYNHOSTDIR ]]; then pushd $DYNHOSTDIR plainhosts=($plainhosts *(#qN-^*)) # append list of (symlinks to) non-executable files to plainhosts array for host in *(#qN-*); do # iterate over executable files (or symlinks to files) should_exit && { wait; return } ( subshell_boilerplate pre $host { if host_changed_ip $host; then echo "INFO: running $DYNHOSTDIR/$host" OLDIP="$OLDIP[@]" CURRENTIP="$CURRENTIP[@]" timeout -k 3 $TRIGGER_TIMEOUT ./$host ret=$? [[ $ret = $ALSO_RUN_FWCOMMAND ]] && : >>$TRIGGER_FILE [[ $ret = 124 ]] && echo "WARNING: $DYNHOSTDIR/$host timed out and was terminated" [[ $ret = 137 ]] && echo "WARNING: $DYNHOSTDIR/$host timed out and was killed" fi } >>$OUTDIR/$host 2>&1 subshell_boilerplate post $host ) & done popd fi if [[ -n $plainhosts ]]; then for host in $plainhosts; do should_exit && { wait; return } if ! [[ -x $DYNHOSTDIR/$host ]] && grep -w -R -q "$host" $FWDIR 2>/dev/null; then ( subshell_boilerplate pre $host.plain { host_changed_ip $host && : >>$TRIGGER_FILE } >>$OUTDIR/$host.plain 2>&1 subshell_boilerplate post $host.plain ) & fi done fi wait handle_sigchld # I'm not sure no race conditions are possible that leave an output file around. Process them all once we have no children anyomre. if [[ -f $TRIGGER_FILE ]]; then echo "NOTICE: Reloading firewall." $FWCOMMAND else ((VERBOSE)) && echo "INFO: Not reloading firewall." fi } while ! should_exit; do delay || check_for_ip_changes done
[szerkesztés] 9 SSH-jelszópróbálgatók automatikus kitűzfalazása
- Az ilyesmivel csak óvatosan, nehogy self-DoS legyen.
- Az alábbi script párféle logfájlból ki tudja nyerni a hibás jelszavakkal próbálkozók IP-jét, és ki tudja őket tiltani.
- Hasonló célokat szolgál a jóval mainstreamebb fail2ban.
#!/bin/zsh # Needs to run as root because it invokes iptables exec 2>&1 if [[ "$1" != "-P" ]]; then exec chpst -P $0 -P fi CONFIG=/etc/ssh-hammerblock/config SSHLOG=/var/log/sv/socklog/ssh/current STATEDIR=/var/state/ssh-hammerblock THRESHOLD=12 TMPREAPER_TIME=1h FWCOMMAND=ipset RULE=(-exist add blacklisted __IP__ timeout 86400 comment ssh-hammerblock) # or perhaps: #FWCOMMAND=iptables #RULE=(-I INPUT -j blacklisted -s __IP__) [[ -r "$CONFIG" ]] && . "$CONFIG" mkdir -p $STATEDIR chmod 700 $STATEDIR trap 'kill -QUIT -$$; kill -1 -$$' 15 trap 'kill -QUIT -$$' EXIT xtail $SSHLOG 2>/dev/null \ | sed -nu ' s/::ffff:// /Failed/{ s/.*for .* from // s/ .*// p } /Invalid user/{ s/.*Invalid user .* from // s/ .*// p } /PAM: Authentication failure for .* from /{ s/.* for .* from // s/ .*// p } /PAM [0-9][0-9]* more authentication failures; .* rhost=/{ s/.*rhost=//;s/[[:space:]].*// p } /Postponed keyboard-interactive for invalid user/{ s/.* for .* from // s/ .*// p } /INFO: LOGIN FAILED, .*, ip=\[.*\]/{ s/.*ip=\[// s/\].*// p } /authentication failure; .* rhost=.*/{ s/.*rhost=//;s/[[:space:]].*// p } /Connection reset by .* port .* \[preauth\]/{ s/.*reset by // s/ .*// p }' \ | while read IP; do [[ -r "$CONFIG" ]] && . "$CONFIG" # re-source config to make it possible to adjust most parameters without restarting the service tmpreaper $TMPREAPER_TIME $STATEDIR/./ if [[ -f "$STATEDIR/$IP" ]]; then COUNT=${$(< "$STATEDIR/$IP"):-0} else COUNT=0 fi ((COUNT++)) echo -n "$COUNT" >"$STATEDIR/$IP" if [[ "$COUNT" -ge "$THRESHOLD" ]]; then $FWCOMMAND ${RULE//__IP__/$IP} 2>/dev/null rm -f "$STATEDIR/$IP" fi done
- xtail helyett használhattuk volna az svlogd-nak azt a képességét, hogy bizonyos sorokat a standard errorra tud írni
- az stderr lehetett volna egy fifoba irányítva, amiből ez a script olvas
- gyorsabb lett volna (nem kell regexp-illesztés)
- de kevésbé robusztus, mert ha a scriptünk elszáll, blokkolódik a logolás stb.
[szerkesztés] 10 Ajánlott irodalom
A Skype-pal kapcsolatban:
- Wikipedia szócikk
- Silver Needle in the Skype, egy prezentáció a Skype visszafejtéséről
[szerkesztés] 11 Potenciális zh-kérdések
- Mit jelent a tűzfalak kontextusában a "zónaszemlélet", és miért érdemes a "zónásításra" törekedni?
- Mi a különbség az egyszerű csomagszűrő és a kapcsolatkövető tűzfal között?
- Milyen különböző összetettségű tűzfalmegoldásokat ismer? Mindegyiket jellemezze néhány szóban!
- Mi a NAT? Mikor szokták használni?
- Mikor lehet értelme az olyan NATnak, ami egy címteret egy vele azonos méretű másikra képez le?
- Milyen keretet ad a Netfilter a tűzfalszabályoknak? (Táblák, láncok...)
- Milyen problémákat okozhat, ha nem IP-címekkel, hanem hosztnevekkel adunk meg tűzfalszabályokat?
- Hogyan lehet atomi művelettel kicserélni az összes tűzfalszabályt a Netfilterben, és miért fontos ez?
- Hasonlítsa össze a DROP és a REJECT iptables-akció működését! Mikor és miért érdemes az egyiket vagy a másikat használni?
- Milyen esetekben érdemes a Netfilterben rátalimitet használni és miért?
- Miért várjuk a Netfilter ipset nevű bővítését, mint a messiást? Milyen problémá(k)ra lesz megoldás?
- Ismertesse egy tűzfalrendszer tervezésével kapcsolatos legfontosabb szempontokat, és ahol lehet, az előadáson megismert megoldásokat értékelje ezen szempontok szerint! Mire célszerű ügyelni a tűzfalszabályok megtervezése során annak érdekében, hogy lehetőleg ne DoS-oljuk saját magunkat?
- Mi a különbség a szabályalapú és a szignatúraalapú IDS között?
A zh második részéhez (ahol egy darab a4-es lapnyi segédeszközt szabad használni):
- Adott az alábbi tűzfalscript. Milyen problémákra számíthatunk, ha ezt használjuk?
- Adott az iptables dokumentációjának releváns része. Írjon olyan tűzfalszabályokat, amelyek - teszemazt - minden hálózati kapcsolat első ezer byte-ját kiküldik a tűzfal monitoring-portján! (Nem kell, hogy 100%-ig tökéletes legyen; az elv legyen jó.)