Robot pro omezení zahlcujícího provozu
Postaveno na http://ipband.sourceforge.net/
Vyžaduje adresář /var/lib/kladivo - zrobíme snadno:
# mkdir /var/lib/kladivo
Potřebný záznam pro běh v crontabu:
*/5 * * * * /root/kladivo.sh cronjob
Někde v init skriptech je záhodno nastartovat sledování pomocí:
/root/kladivo.sh startwatch
nebo skript přímo nalinkovat do startovacích adresářů (rcX.d). Na debianu to lze udělat takto:
cd /etc/init.d ln -s /root/kladivo.sh update-rc.d kladivo.sh defaults
Skript /root/kladivo.sh:
(proměnné v hlavičce si račte upravit k obrazu svému, nezapomenout do sledovanych sítí přidat i veřejné IP)
<bash>#!/bin/sh
- Verze 1.06 -> doplnujte aktualni verzi
- autor pavkriz@hkfree.org
- iptables rules kendy@hkfree.org
- detekce casoveho useku jezz@hkfree.org
- rychlostni limit v kB/s
LIMIT=70
- maximalni doba na jakou lze prekrocit limit (minut)
MAXOVERTIME=15
- doba, na jakou danou IP zabanujeme (minut)
BANTIME=180
- interface ktery sledujeme
WATCHIF=eth2
- podsite ktere sledujeme
WATCHNET=10.107.12.0/24:10.107.42.0/24
- jak je definovana denni doba (7:00-23:00)
- muze se prehoupnout pres pulnoc, pak je prvni cislo vetsi nez druhe (700-200)
- v noci se banovani vypina (bany bezi casove dal, ale nejsou "provadeny")
DAYTIME="700-2300"
KLADIVO=/root/kladivo.sh LISTDIR=/var/lib/kladivo
IPTABLES=/sbin/iptables IPBAND=/usr/sbin/ipband
case "$1" in
report) # ziskame obsah reportu do tempfile TMPF=`mktemp -t kladivo.XXXXXX` cat - > "$TMPF" # ziskame IP ktere se report tyka IP=`awk '/Network: / { print $2 }' $TMPF` # ziskame cas z reportu (jak dlouho presahuje limit) - jako desetinne cislo v minutach OVERTIME=`awk '/exceeded for: / { print $7 }' $TMPF` # odsekneme desetinnou cast OVERTIME="${OVERTIME%%.*}" # debug ###echo $IP $OVERTIME if [ "$OVERTIME" -gt "$MAXOVERTIME" ]; then # limit prekrocen na dobu delsi nez je povolena -> zabanovat FILE="$LISTDIR/$IP" if [ ! -e "$FILE" ]; then # pokud jeste neni zabanovan, tak zalozime soubor se znackou pro zabanovani # vypocteme timestamp do kdy budem IP banovat NOW="`date +%s`" BANTOTIME="$(($BANTIME * 60 + $NOW))" # zapiseme timestamp do souboru echo "$BANTOTIME" > "$FILE" # zapiseme report na jehoz zaklade ban vznikl echo "" >> "$FILE" cat "$TMPF" >> "$FILE" fi fi rm "$TMPF" exit 0 ;;
cronjob) # vyprazdnit chain $IPTABLES -F SOSACI &> /dev/null NOW="`date +%s`" NOWTIME="`date +%k%M`" DAYTIME1="${DAYTIME%%-*}" DAYTIME2="${DAYTIME##*-}" # projit vsechny zabanovane for FILE in $LISTDIR/* ; do if [ -e "$FILE" ]; then BANTO="`head -n 1 "$FILE"`" if [ "$BANTO" -lt "$NOW" ]; then # uz vyprsel ban # smazat znacku o zabanovani (casem asi presunout do nejakeho archivu) rm "$FILE" else # je-li stale zabanovan, obnovit banovani BANME='no' if [ "$DAYTIME1" -gt "$DAYTIME2" ]; then [ "$NOWTIME" -ge "$DAYTIME1" -o "$NOWTIME" -lt "$DAYTIME2" ] \ && BANME='yes' elif [ "$NOWTIME" -ge "$DAYTIME1" -a "$NOWTIME" -lt "$DAYTIME2" ]; then BANME='yes' fi
if [ "$BANME" = 'yes' ]; then IP="${FILE##*/}" $IPTABLES -I SOSACI -p ! icmp -s $IP -m limit --limit 10/s -j ACCEPT $IPTABLES -I SOSACI 2 -p ! icmp -s $IP -j DROP $IPTABLES -I SOSACI -p ! icmp -d $IP -m limit --limit 10/s -j ACCEPT $IPTABLES -I SOSACI 2 -p ! icmp -d $IP -j DROP fi fi fi done exit 0 ;; startwatch|start) # vytvorit chain kam strkame banovaci pravidla $IPTABLES -N SOSACI && $IPTABLES -I FORWARD -j SOSACI # spustit sledovaci ipband, ktery nam bude posilat reporty a detekovanych prekroceni $IPBAND -F -L $WATCHNET -m 32 -b $LIMIT -a 60 -r 240 -t 5 -M root@localhost -T "$KLADIVO report" $WATCHIF exit 0 ;;
stopwatch|stop) killall $IPBAND # smazat iptables pravidla (chyby ignorovat, pokud neexistuji) $IPTABLES -F SOSACI &> /dev/null $IPTABLES -D FORWARD -j SOSACI &> /dev/null $IPTABLES -X SOSACI &> /dev/null exit 0 ;;
restart) $0 stop $0 start exit 0 ;;
*) echo "usage: $0 startwatch|stopwatch|start|stop|restart|report|cronjob" exit 1 ;;
esac </bash>
CGI skript pro sledování stavu černé listiny:
<bash>#!/bin/sh
- Verze 1.01
- Autor PavKriz
LISTDIR=/var/lib/kladivo
SEP="--------------------------------------------" echo "Content-type: text/plain" echo "" TODAY=`date` echo "Report k datu: $TODAY" echo $SEP NOW=`date +%s`
for FILE in $LISTDIR/* ; do echo "$FILE" | grep archive &>/dev/null && continue if [ -e "$FILE" ]; then IP=`basename $FILE` HOST=`host $IP | awk "{ print \\$5 }"` BANTO=`head -n 1 $FILE` UNBAN=`expr $BANTO - $NOW` UNBAN=`expr $UNBAN / 60` # print report echo "Host: $HOST ($IP)" echo "Minutes to unban: $UNBAN" echo "Ban-causing report:" tail +8 $FILE echo fi done
</bash>
TCP/IP rozhrani na dotazy do userdb pro prevod IP adresy na e-mail HKfree clena bezi na brita (brita.lhota.hkfree.org, 10.107.15.17) na portu 10107.
Priklady:
uspesny dotaz:
23:13:30 Lhota3-JZD:~# echo 10.107.12.88 | nc 10.107.15.17 10107 caryInvalidaddresSfukhk@tiscInvaliddomaiNali.cz
neuspesny dotaz (ip adresa v userdb neni)
23:15:36 Lhota3-JZD:~# echo 10.107.12.888 | nc 10.107.15.17 10107 23:15:46 Lhota3-JZD:~#
chybova hlaska:
23:15:46 Lhota3-JZD:~# echo 10.107.12.8888 | nc 10.107.15.17 10107 ip2mail: [10.107.12.8888] does not look like IPv4 address.
Rozhrani je vhodne k pouziti v kladivu - poslu clenovi mail hned jak na nej kladivo "spadne"
Kladivo na node d-network
- integrace se shaperem od martink, vyuziva se htb a imq
- zavedeny 2 rychlostni urovne
- drobna uprava - po vytvoreni banovaciho reportu se ihned spusti cronjob (zabanovani se projevi driv)
co je treba dodelat:
- mozna ve vychozim stavu si skript vystaci s -m limit --limit XX; mel by tedy asi tak byt publikovany zde na wiki (staci zakomentovat moje iptables pravidla a odkomentovat ty puvodni)
- pokud jde o htb, aby ve vychozim stavu vsichni shaper obchazeli (nebyli omezeni), je vyuzito znacky -j MARK --set-mark 3, ktera je vicemene interni funkci unishaperu; bylo by dobre, kdyby se default trida v unishaperu mohla nastavit jako neshapovana... neni to ale kriticke
kladivo.sh:
<bash>#!/bin/sh
- Verze 1.07 -> doplnujte aktualni verzi
- autor pavkriz@hkfree.org
- iptables rules kendy@hkfree.org
- detekce casoveho useku jezz@hkfree.org
- vzorova integrace s unishaperem od martink@hkfree.org a lowlimit lada@hkfree.org
- rychlostni limit v kB/s
LIMIT=200
- limit pod kterym musi sosac byt, aby doslo k odblokovani
- pokud funkce nema byt vyuzita, zakomentovat
LOWLIMIT=50
- maximalni doba na jakou lze prekrocit limit (minut)
MAXOVERTIME=2
- doba, na jakou danou IP zabanujeme (minut)
BANTIME=10
- interface ktery sledujeme
WATCHIF=eth5
- podsite ktere sledujeme
WATCHNET=10.107.3.32/27:10.107.3.96/27:10.107.3.128/25:10.107.103.0/28:10.107.103.32/27:85.132.161.218/32:85.132.160.163/32:85.132.160.172/32:85.132.160.170/32:85.132.160.168/32:85.132.160.169/32:85.132.161.219/32
- 10.107.12.0/24:10.107.42.0/24
- jak je definovana denni doba (7:00-23:00)
- muze se prehoupnout pres pulnoc, pak je prvni cislo vetsi nez druhe (700-200)
- v noci se banovani vypina (bany bezi casove dal, ale nejsou "provadeny")
DAYTIME="700-2300"
KLADIVO=/root/kladivo.sh LISTDIR=/var/lib/kladivo
IPTABLES=/usr/local/sbin/iptables IPBAND=/usr/local/bin/ipband
case "$1" in
report) # ziskame obsah reportu do tempfile TMPF=`mktemp -t kladivo.XXXXXX` cat - > "$TMPF" # ziskame IP ktere se report tyka IP=`awk '/Network: / { print $2 }' $TMPF` # ziskame cas z reportu (jak dlouho presahuje limit) - jako desetinne cislo v minutach OVERTIME=`awk '/exceeded for: / { print $7 }' $TMPF` # odsekneme desetinnou cast OVERTIME="${OVERTIME%%.*}" # ziskame jaka byla prekrocena rychlost SPEED=`awk '/threshold: / { print $3 }' $TMPF` SPEED="${SPEED%%.*}" # debug ###echo $IP $OVERTIME
BANME=no MAKEBANFILE=no if [ "$OVERTIME" -gt "$MAXOVERTIME" ]; then # pokud byl limit prekrocen delsi dobu nez je limit FILE="$LISTDIR/$IP" if [ "$SPEED" == "$LIMIT" ]; then # jde o vysokou rychlost, vytvorit take prvni report MAKEBANFILE=yes BANME=yes fi if [ "$SPEED" == "$LOWLIMIT" ]; then # pokud byla prekrocena nizsi rychlost, banuj pouze pokud existuje prvni report if [ -e "$FILE.ban" ]; then BANME=yes
fi
fi if [ "$BANME" == "yes" ]; then # limit prekrocen, banovat NOW="`date +%s`" BANTOTIME="$(($BANTIME * 60 + $NOW))" # zapiseme timestamp do souboru echo "$BANTOTIME" > "$FILE.current" # zapiseme report na jehoz zaklade ban vznikl echo "" >> "$FILE.current" cat "$TMPF" >> "$FILE.current" fi if [ "$MAKEBANFILE" == "yes" ]; then # vytvorit prvni banovaci report. existujici neprepisovat [ ! -e "$FILE.ban" ] && cp "$FILE.current" "$FILE.ban"
# spustime cronjob, aby zabanovani bylo okamzite $KLADIVO cronjob
fi fi rm "$TMPF" exit 0 ;; cronjob) # vyprazdnit chain $IPTABLES -t mangle -F SOSACI_pre &> /dev/null $IPTABLES -t mangle -F SOSACI_post &> /dev/null
# co ma znacku 3 v unishaperu shaper obchazi $IPTABLES -t mangle -A SOSACI_pre -i $WATCHIF -j MARK --set-mark 3 $IPTABLES -t mangle -A SOSACI_post -o $WATCHIF -j MARK --set-mark 3
#$IPTABLES -F SOSACI &> /dev/null
NOW="`date +%s`" NOWTIME="`date +%k%M`" DAYTIME1="${DAYTIME%%-*}" DAYTIME2="${DAYTIME##*-}" # projit vsechny zabanovane for FILE in $LISTDIR/*.current ; do if [ -e "$FILE" ]; then BANTO="`head -n 1 "$FILE"`" if [ "$BANTO" -lt "$NOW" ]; then # uz vyprsel ban # smazat znacku o zabanovani (casem asi presunout do nejakeho archivu) rm "$FILE"
# smazat taky soubor s priponou .ban rm "${FILE%.current}.ban"
else # je-li stale zabanovan, obnovit banovani BANME=no if [ "$DAYTIME1" -gt "$DAYTIME2" ]; then [ "$NOWTIME" -ge "$DAYTIME1" -o "$NOWTIME" -lt "$DAYTIME2" ] \ && BANME=yes elif [ "$NOWTIME" -ge "$DAYTIME1" -a "$NOWTIME" -lt "$DAYTIME2" ]; then BANME=yes fi if [ "$BANME" = yes ]; then IP="${FILE##*/}"
IP="${IP%.current}" $IPTABLES -t mangle -p ! icmp -A SOSACI_pre -i $WATCHIF -s $IP -j unishaper_pre $IPTABLES -t mangle -p ! icmp -A SOSACI_post -o $WATCHIF -d $IP -j unishaper_post
#$IPTABLES -I SOSACI -p ! icmp -s $IP -m limit --limit 10/s -j ACCEPT #$IPTABLES -I SOSACI 2 -p ! icmp -s $IP -j DROP #$IPTABLES -I SOSACI -p ! icmp -d $IP -m limit --limit 10/s -j ACCEPT #$IPTABLES -I SOSACI 2 -p ! icmp -d $IP -j DROP fi fi fi done exit 0 ;; startwatch|start) # spustit omezovaci shaper unishaper.sh # umravnit shaper $IPTABLES -t mangle -D PREROUTING -j unishaper_pre $IPTABLES -t mangle -D POSTROUTING -j unishaper_post $IPTABLES -t mangle -D INPUT -j unishaper_in $IPTABLES -t mangle -D OUTPUT -j unishaper_out $IPTABLES -t mangle -D FORWARD -j unishaper_fw # vytvorit chain kam strkame banovaci pravidla $IPTABLES -t mangle -N SOSACI_pre && $IPTABLES -t mangle -I PREROUTING -j SOSACI_pre $IPTABLES -t mangle -N SOSACI_post && $IPTABLES -t mangle -I POSTROUTING -j SOSACI_post # co ma znacku 3 v unishaperu shaper obchazi $IPTABLES -t mangle -A SOSACI_pre -i $WATCHIF -j MARK --set-mark 3 $IPTABLES -t mangle -A SOSACI_post -o $WATCHIF -j MARK --set-mark 3
#$IPTABLES -N SOSACI && $IPTABLES -I FORWARD -j SOSACI
# spustit sledovaci ipband, ktery nam bude posilat reporty a detekovanych prekroceni $IPBAND -F -L $WATCHNET -m 32 -b $LIMIT -a 60 -r 180 -t 5 -M root@localhost -T "$KLADIVO report" $WATCHIF if [ "$LOWLIMIT" != "" ]; then $IPBAND -F -L $WATCHNET -m 32 -b $LOWLIMIT -a 60 -r 240 -t 5 -M root@localhost -T "$KLADIVO report" $WATCHIF fi exit 0 ;; stopwatch|stop) killall $IPBAND # smazat iptables pravidla (chyby ignorovat, pokud neexistuji) $IPTABLES -t mangle -F SOSACI_pre &> /dev/null $IPTABLES -t mangle -F SOSACI_post &> /dev/null
$IPTABLES -t mangle -D PREROUTING -j SOSACI_pre &> /dev/null $IPTABLES -t mangle -D POSTROUTING -j SOSACI_post &> /dev/null
$IPTABLES -t mangle -X SOSACI_pre &> /dev/null $IPTABLES -t mangle -X SOSACI_post &> /dev/null unishaper.sh -s #$IPTABLES -F SOSACI &> /dev/null #$IPTABLES -D FORWARD -j SOSACI &> /dev/null #$IPTABLES -X SOSACI &> /dev/null exit 0 ;; restart) $0 stop $0 start exit 0 ;; *) echo "usage: $0 startwatch|stopwatch|start|stop|restart|report|cronjob" exit 1 ;;
esac </bash>
vypis kladiva:
<bash>#!/bin/sh
- Verze 1.02
- Autor PavKriz
- modifikace Lada JNet
LISTDIR=/var/lib/kladivo
SEP="--------------------------------------------" echo "Content-type: text/plain" echo "" TODAY=`date` ping -c 1 -w 1 10.107.15.17 &> /dev/null && SHOWMAIL=yes echo "Report k datu: $TODAY" echo $SEP NOW=`date +%s`
for FILE in $LISTDIR/*.current ; do echo "$FILE" | grep archive &>/dev/null && continue if [ -e "$FILE" ]; then
FILE="${FILE%.current}"
IP=`basename $FILE`
[ "$SHOWMAIL" == "yes" ] && MAIL=`echo "$IP" | nc -w 2 10.107.15.17 10107`
HOST=`host $IP | awk "{ print \\$5 }"` BANTO=`head -n 1 $FILE.current` UNBAN=`expr $BANTO - $NOW` UNBAN=`expr $UNBAN / 60` # print report echo "Adresa: $HOST ($IP)"
[ "$SHOWMAIL" == "yes" ] && echo "Email: $MAIL"
echo "Bude smazano za: $UNBAN minut" echo "Omezeni spusteno kvuli:" tail +8 $FILE.ban
echo "Omezeni udrzovano kvuli:" tail +8 $FILE.current
echo fi done
</bash>
mensi pokus o prevod kladiva do html:
<nowiki>#!/bin/sh # #Verze 1.02 #Autor PavKriz # # modifikace Lada JNet LISTDIR=/var/lib/kladivo #SEP="--------------------------------------------" echo "Content-type: text/html" echo "" cat << EoF <HTML> <TITLE>Kladivo</TITLE> <BODY> <img src="http://d-network.hkfree.org/logo.gif"><br> EoF TODAY=`date` ping -c 1 -w 1 10.107.15.17 &> /dev/null && SHOWMAIL=yes echo "<font size=+1><b> Report k datu: $TODAY </b></font><br><br>" NOW=`date +%s` for FILE in $LISTDIR/*.current ; do echo "$FILE" | grep archive &>/dev/null && continue if [ -e "$FILE" ]; then FILE="${FILE%.current}" IP=`basename $FILE` [ "$SHOWMAIL" == "yes" ] && MAIL=`echo "$IP" | nc -w 2 10.107.15.17 10107` HOST=`host $IP | awk "{ print \\$5 }"` BANTO=`head -n 1 $FILE.current` UNBAN=`expr $BANTO - $NOW` UNBAN=`expr $UNBAN / 60` # print report echo "Adresa: $HOST ($IP)<br>" [ "$SHOWMAIL" == "yes" ] && echo "Email: $MAIL <br>" echo "Bude smazano za: $UNBAN minut<br>" echo "<b>Omezeni spusteno kvuli:</b><br>" echo "<pre>" tail +8 $FILE.ban echo "
"
echo "Omezeni udrzovano kvuli:"
echo "
" tail +8 $FILE.current echo "
" echo "
"
echo fi done
cat << EoF </BODY> </HTML> EoF
</nowiki>
Unishaper
Unishaper uz neni oficialne vubec podporovan. Jednu z poslednich verzi, kterou pouzivam, muzete stahnout spolu s ostatnimi soubory d-network kladiva na
http://d-network.hkfree.org/kladivo2/
10.3.2007 jsem tam nahral poupravene soubory tak, jak je pouzivam. Dejte ale pozor na to, ze jsem tam dobastlil napriklad shaper pro SVM, takze je potreba skript trochu ucesat pro vase potreby.
unishaper.conf na dnetw: <bash>#!/bin/sh # jen kvuli zvyrazneni syntaxe ve vimu :)
tc=/sbin/tc iptables=/usr/local/sbin/iptables ip=/sbin/ip modprobe=/sbin/modprobe
iface0() {
iface="eth5"
- ve zkratce, co znamenaji parametry:
- root_rate maximalni rychlost vsech dohromady - lze rict, kolik "kladivouni" smi urvat dohromady
- rate - garance; musi byt nad 12, je potreba aby garance vsech nepresahla root_rate
- ceil - maximalni rychlost v ramci jedne tridy (rychlost uzivatele)
- dist - yes/no znamena, jestli je v routru iface vzdaleny od uzivatele, nebo je-li na nej napojen uzivatel primo
- pouziva se pouze, pokud nemame imq a vime, kudy potecou odchozi data uzivatele
- upload uzivatelu
upload="yes" up_dist="no" up_unit="kbit"
- kolik muzou udelat vsichni dohromady
up_root_rate="15000"
- default trida - tu nepouzivame; sem jde vse, co neni oznackovano
up_ceil="300" up_rate="25"
- jak se pisou subnety je skvele vysvetleno v ukazkovem konfiguraku
- ve zkratce:
- 10.107.3.1-5 vytvori 5 samostatnych trid (pro 5 ruznych uzivatelu)
- 10.107.3.1,10.107.3.2,10.107.3.3 vytvori 1 tridu pro 3 adresy (1 user vlastni vsechny adresy)
- 10.107.3.0/27 vytvori 1 tridu pro cely rozsah (cely rozsah patri jednomu uzivateli)
- wireless rexornet weetek,bloque jenda rexor
A="10.107.3.130-222 10.107.3.34-46 10.107.3.97-102 85.132.161.218,10.107.3.112/29 10.107.3.14,10.107.3.34,10.107.3.35,85.132.160.163"
- yanda radekN&tomask bazina bazina_subnet jaja&kamil mirra&spol
B="10.107.3.147,85.132.160.172 10.107.103.50-51 10.107.3.58,10.107.3.59,10.107.3.60 10.107.3.61-62 10.107.3.122-123 10.107.103.34,85.132.160.170 10.107.103.35,85.132.160.168 10.107.103.36,85.132.160.169"
- honya honya_subnet sa dave
C="10.107.3.50,10.107.3.51,85.132.161.219 10.107.3.52-54 10.107.3.104/29 10.107.103.42-43"
- A B a C pouzivam jenom, aby se nejak dalo vyznat v tech komentarich
- koho shapujem
up_1_range="$A $B $C"
- garance
up_1_rate="25"
- strop
up_1_ceil="300"
- pokud nejaky uzivatel hodne zlobi, lze mu tady vytvorit individualni rychlost, na kterou ho kladivo srazi, napr:
- pri individualni hranici je ale treba dbat na to, aby uzivatel mohl prekrocit LOWLIMIT v kladivo.sh,
- jinak bude neustale odblokovavan a zablokovavan
- up_2_range="10.107.3.1"
- up_2_rate="25"
- up_2_ceil="100"
- download uzivatelu
download="yes" dl_dist="no" dl_unit="kbit"
- celkova rychlost
dl_root_rate="15000"
- default trida - nepouzivame
dl_ceil="1024" dl_rate="25"
- tridy uzivatelu
dl_1_range="$up_1_range" dl_1_ceil="800" dl_1_rate="25"
- dl_2_range="$up_2_range"
- dl_2_ceil="450"
- dl_2_rate="25"
}
tests="yes" </bash>