#!/bin/sh # If you got false positives, try a higher value BOGOTHRESH=200 # Note: for mail alarm, you need "ssmtp" installed and configured. # Example /etc/ssmtp/ssmtp.conf (debian/ubuntu) for GMX needs: # mailhub=mail.gmx.net:25 FromLineOverride=YES # AuthUser=$MAILFROM AuthPass=x UseSTARTTLS=YES MAILFROM=sender-address@domain.de MAILADDR=receiver-address@domain.de # Insert IPs you trust #TRUSTEDIP="$TRUSTEDIP 1.2.3.4" #TRUSTEDIP="$TRUSTEDIP 2.3.4.5" # 0: Do not save, 1: save conntrack if zapp DEBUGSAVE=0 # Empty: No log in /var/log/zapp/, otherwise string to prepend to saved bogothresh files DEBUGLOGS= #$(date "+%b%d %H:%M") # 0: Manual clear, or minutes until auto-clear blockade (5-1439) CLEARTIME=360 WEBSERVER=/www # --- END OF CONFIGURATION SETTINGS --- # This script uses case-esac for speed with busybox-ash. Current version under: # http://ff-firmware.cvs.sourceforge.net/viewvc/*checkout*/ff-firmware/ff-devel/freifunk-zapp/etc/init.d/S92zapp # When running via cron, the PATH is unset export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # We start a netcat-based webserver on this port if someone is blocked BLOCKPORT=8090 CRONUSR=root CRONDIR=/var/spool/cron/crontabs # First argument may be an input file CONN=${1:-/proc/net/ip_conntrack} # This script calls itself with the IP to analyze why its blocking DEBIP=$2 case $1 in '')DEBUG=false;;*)DEBUG=true;;esac case $DEBUGLOGS in "");;*)test -d /var/log/zapp || mkdir -p /var/log/zapp;;esac # Find out our IP that is used to connect to the Internet DEV=$(ip route get 1.1.1.1/1|sed -n '1{s/.* dev \([^ ]\+\).*/\1/;p}') ADR=$(ip -f inet addr list dev $DEV scope global|sed -n '2s/^.*inet \([0-9\.]\+\).*/\1/p') PAT=$(sed 's/\./_/g'<&1 | egrep -q '\-l\b' || NC_CMD= # 1=-I/-D 2=proto 3=srcip, 4=dport, 5=to portfw () { local to case $1 in "-D") to=$(iptables -t nat -nL PREROUTING|sed -n "s/^DNAT[[:space:]]\\+$2[[:space:]]\\+[^[:space:]]\\+[[:space:]]\\+$3[[:space:]]\\+![[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\+[[:space:]]\\+$2[[:space:]]\\+dpt:$4[[:space:]]\\+to://;tp;b;:p p;q") ;;esac to=${to:-$5} iptables -t nat $1 PREROUTING --proto $2 -s $3 ! -d ${to%:*} --dport $4 -j DNAT --to $to } netcatruns () { for pid in $(pidof $NC_CMD);do ppid=$(sed -n 's/^PPid: //p' /proc/$pid/status) case $(sed -n 's/^Name: //p' /proc/$ppid/status) in ${0##*/}) # Check netstat: release the IP currently grabbing our blocking page case "$1" in "GET /let-me-browse-again"*) le=$(printf "%02X%02X%02X%02X" $(echo ${ifip:-$ADR}|sed 's/\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)/\4 \3 \2 \1/')) be=$(printf "%02X%02X%02X%02X" $(echo ${ifip:-$ADR}|sed 's/\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)/\1 \2 \3 \4/')) eval $(sed -n '/^ *[0-9]\+: \+'$le':'$(printf '%04X' $BLOCKPORT)' \+[^ ]\+ \+01 \+/{s/^[^:]\+: \+[^ ]\+ \+\([^:][^:]\)\([^:][^:]\)\([^:][^:]\)\([^:][^:]\).*/ip=$(( 0x\4 )).$(( 0x\3 )).$(( 0x\2 )).$(( 0x\1 ))/;p;q};/^ *[0-9]\+: \+'$be':'$(printf '%04X' $BLOCKPORT)' \+[^ ]\+ \+01 \+/{s/^[^:]\+: \+[^ ]\+ \+\([^:][^:]\)\([^:][^:]\)\([^:][^:]\)\([^:][^:]\).*/ip=$(( 0x\1 )).$(( 0x\2 )).$(( 0x\3 )).$(( 0x\4 ))/;p;q}' /proc/net/tcp) portfw -D tcp $ip 80 ${ifip:-$ADR}:$BLOCKPORT 2>&- ;;esac return 0 ;;esac done return 1 } # Add (-I) or remove (-D) iptables rules block () { # Freifunk Firmware Configs which nvram && { ff_adm_mail=$(nvram get ff_adm_mail) ff_zapp_time=$(nvram get ff_zapp_time) ff_zapp_debug=$(nvram get ff_zapp_debug) ff_zapp_server=$(nvram get ff_zapp_server) ff_zapp_strict=$(nvram get ff_zapp_strict) MAILFROM=${ff_adm_mail:-$MAILFROM} MAILADDR=${ff_adm_mail:-$MAILADDR} CLEARTIME=${ff_zapp_time:-$CLEARTIME} DEBUGSAVE=${ff_zapp_debug:-$DEBUGSAVE} WEBSERVER=${ff_zapp_server:-$WEBSERVER} IFS=\; for i in $(nvram get ff_zapp_trusted); do TRUSTEDIP="$TRUSTEDIP $i" done unset IFS } for i in $TRUSTEDIP;do case $2 in $i) # Prevents re-blocking next run iptables $1 FORWARD -s $2 iptables $1 FORWARD -d $2 return ;;esac done # Note: FreifunkFW does not have REJECT out-of-the-box jump=DROP iptables -I OUTPUT -d 127.0.0.1 -j REJECT 2>&- && iptables -D OUTPUT -d 127.0.0.1 -j REJECT 2>&- && jump=REJECT iptables $1 FORWARD -s $2 -j $jump iptables $1 FORWARD -d $2 -j $jump # Allowing ping is always a good idea iptables $1 FORWARD -s $2 --proto icmp -j ACCEPT iptables $1 FORWARD -d $2 --proto icmp -j ACCEPT # Allow TCP up to port 1023 iptables $1 FORWARD -s $2 --proto tcp --dport :1023 -j ACCEPT iptables $1 FORWARD -d $2 --proto tcp --sport :1023 -j ACCEPT # Note: Freifunk FW does not have REDIRECT, use DNAT instead, # which needs the correct outgoing interface IP for redirection. ifip=$(ip route get $2|sed -n 's/^.* src \([^ ]\+\).*/\1/p') # Allow DNS, redirect to our local dnsmasq if applicable if pidof dnsmasq >&-; then portfw $1 udp $2 53 ${ifip:-$ADR}:53 portfw $1 tcp $2 53 ${ifip:-$ADR}:53 else iptables $1 FORWARD -s $2 --proto udp --dport 53 -j ACCEPT iptables $1 FORWARD -d $2 --proto udp --sport 53 -j ACCEPT fi # It's polite to tell a blocked user what's going on case $NC_CMD in "");;*) portfw $1 tcp $2 80 ${ifip:-$ADR}:$BLOCKPORT 2>&- case $1 in "-D") case $CLEARTIME in ""|0);;*)test -f $CRONDIR/$CRONUSR && { sed -i -e "/\/${0##*/} unblock $2\$/d" $CRONDIR/$CRONUSR echo $CRONUSR > $CRONDIR/cron.update };;esac if ! iptables -t nat -nL PREROUTING|egrep -q "\\bto:[^:]+:$BLOCKPORT\\b"; then netcatruns && (echo "Stopping netcat server" >&2;kill $ppid $pid) fi ;;*) case $CLEARTIME in ""|0);;*)test -f $CRONDIR/$CRONUSR && { min=$(date +%M) min=$(( $(date +%k ) * 60 + ${min#0} + $CLEARTIME )) me=$(echo $0|sed "s,^\\.\\.,$PWD/&,;s,^\\.,$PWD,") sed -i -e "\$a$(( $min % 60 )) $(( $min / 60 % 24 )) * * * $me unblock $2" $CRONDIR/$CRONUSR echo $CRONUSR > $CRONDIR/cron.update };;esac if ! netcatruns; then echo "Starting netcat server for $2" >&2 while true;do ($NC_CMD -l -p $BLOCKPORT < Sorry...

Zapped on $(uname -n) (${ifip:-$ADR})

Deutsch: siehe untenfrançais : voir ci-dessous


Hello! You are a victim of a filesharing blockade. Your PC opens too much connections to different Internet hosts. This may be caused by the VoIP program Skype, by a filesharing program or by another program with this unusual communication pattern. $(test -f $WEBSERVER/cgi-bin-skype.html && echo "For operating the Skype VoIP program please read this Information Page.")

TCP based services still work (ports up to 1023), but UDP based services are blocked now.

The blockade $(case $CLEARTIME in ""|0) echo "needs to be removed manually.";;*)echo "will be removed after $CLEARTIME minutes. Alternatively, the blockade can be removed manually.";;esac) For this, send an email to $MAILADDR.


Hallo! Du bist das Opfer einer Filesharing-Sperre geworden. Dein Rechner öffnet zuviele Verbindungen zu verschiedenen Internet-Rechnern. Dies kann ausgelöst werden durch das VoIP-Programm Skype, durch ein Filesharing-Programm oder durch ein anderes Programm welches dieses ungewöhnliche Kommunikationsmuster aufweist. $(test -f $WEBSERVER/cgi-bin-skype.html && echo "Zum Betrieb des VoIP-Programms Skype lies bitte diese Informationsseite.")

Hinweis: TCP-basierte Dienste (Ports bis 1023) funktionieren, aber UDP-basierte Dienste sind nun gesperrt.

Die Sperre $(case $CLEARTIME in ""|0)echo "muss manuell entfernt werden.";;*) echo "wird nach $CLEARTIME Minuten entfernt. Wahlweise kann die Sperre auch manuell entfernt werden.";;esac) Sende dazu eine Mail an $MAILADDR.


Bonjour! Vous êtes victime du mécanisme de blocage de partage de fichiers. Votre ordinateur ouvre trop de connexions simultanées vers trop d'hôtes Internet différents. Ceci peut venir du logiciel de communications Skype, d'un logiciel de partage de fichiers, ou d'un autre programme qui aurait ce même comportement inhabituel, comme certains virus. $(test -f $WEBSERVER/cgi-bin-skype.html && echo "Pour l'utilisation de Skype en voix sur IP (VoIP) merci de lire cette page d'informations.")

Précisions: Les services TCP restent fonctionnels (Ports jusqu'au n° 1023) mais les services UDP sont bloqués.

Le blocage $(case $CLEARTIME in ""|0)echo "doit être désactivé manuellement.";;*) echo "sera levé automatiquement dans $CLEARTIME minutes. Il est aussi possible de le faire manuellement.";;esac) en envoyant un mail à $MAILADDR.

EOF )|(read -r GET && netcatruns "$GET" && kill $pid) done >&- 2>&- & fi ;;esac ;;esac } zapp () { # Block an IP and send a mail to the admin ip=$(echo $1|sed -e 's/^[A-Z]\+_//;s/=.*//;s/_/./g') if $DEBUG; then # Prevent script recursion case $DEBIP in "") echo "Zapping $(ip route get $ip|sed -n 's/ dev .*//p') with $2 bogopoints at $(date)" echo $0 "$CONN" ${1%=*} ;;esac elif ! iptables -nL FORWARD | egrep -q "\\b$(echo $ip|sed 's/\./\\&/g')\\b";then echo "Zapping $(ip route get $ip|sed -n 's/ dev .*//p') with $2 bogopoints at $(date)" >> /var/log/zappfile.txt mac=$(sed -n 's/^'$(echo $ip|sed 's/\./\\./g')' \+\([^ ]\+ \+\)\{2\}\([^ ]\+\).*/\2/p' /proc/net/arp) # Disabled, because we cannot unblock this currently case 0 in 1)case $mac in '');;*) echo "Also zapping $mac at $(date)" >> /var/log/zappfile.txt iptables -I FORWARD -m mac --mac-source $mac -j $jump ;;esac;;esac block -I $ip case $DEBUGSAVE in 1) # Save current conntrack for later analysis cat "$CONN"|gzip -c>/var/log/zappfile-$ip-$(date).txt.gz ;;esac which ssmtp && cat|ssmtp $MAILADDR< $3:$4 (UNK=$UNK)";;esac ;; *) case $4 in 688*) eval "case \$UNK_$1 in \"\")UNK=\$(( \$UNK + 5 ));;esac" case $DEBIP in '');;*)echo "nak p2p $1:$2 -> $3:$4 (UNK=$UNK)";;esac ;; *) eval "case \$UNK_$1 in \"\")UNK=\$(( \$UNK + 1 ));;esac" case $DEBIP in '');;*)echo "nak udp $1:$2 -> $3:$4 (UNK=$UNK)";;esac ;; esac ;; esac eval "UNK_$1=\$(( \$UNK_$1 + 1 ))" ;;esac;;esac # We only count traffic generated by others case $3 in $PAT);;*) case $4 in # DNS: resolvers tend to open multiple connections 53) case ${10} in "[UNREPLIED]") eval "case \$UDP_$1_$3 in \"\")IP_$1=\$(( \$IP_$1 + 1 ));;esac";; *) eval "case \$UDP_$1_$3 in \"\")IP_$1=\$(( \$IP_$1 + 2 ));;esac";; esac case ${DEBIP#IP_} in $1)echo "udp ham $1:$2 $3:$4";;esac ;; # Punish traffic on ports 6880-6889 688*) case ${10} in "[UNREPLIED]") eval "case \$UDP_$1_$3 in \"\")IP_$1=\$(( \$IP_$1 + 10 ));;esac";; *) eval "case \$UDP_$1_$3 in \"\")IP_$1=\$(( \$IP_$1 + 20 ));;esac";; esac case ${DEBIP#IP_} in $1)echo "udp p2p $1:$2 $3:$4";;esac ;; # Everything else is normal udp *) case ${10} in "[UNREPLIED]") eval "case \$UDP_$1_$3 in \"\")IP_$1=\$(( \$IP_$1 + 3 ));;esac";; *) eval "case \$UDP_$1_$3 in \"\")IP_$1=\$(( \$IP_$1 + 4 ));;esac";; esac case ${DEBIP#IP_} in $1)echo "udp std $1:$2 $3:$4";;esac ;; esac eval "UDP_$1_$3=\$(( \$UDP_$1_$3 + 1 ))" ;;esac return 0 } case $1 in block) case $2 in "")echo "Add IP as second arg" 2>&-;exit 1;;esac block "-I" $2 exit 0 ;; unblock|clear) case $2 in "")echo "Add IP as second arg" 2>&-;exit 1;;esac block "-D" $2 exit 0 ;; start|stop) test ! -f $CRONDIR/$CRONUSR && (echo "No $CRONDIR/$CRONUSR" 2>&-;exit 1) if egrep -q "/${0##*/}" $CRONDIR/$CRONUSR; then case $1 in stop) echo "Removing ${0##*/} from cron" sed -i -e "/\/${0##*/}/d" $CRONDIR/$CRONUSR ;;esac else case $1 in start) case $BOGOTHRESH in 0);;*) echo "Adding ${0##*/} to cron" me=$(echo $0|sed "s,^\\.\\.,$PWD/&,;s,^\\.,$PWD,") sed -i -e "\$a*/1 * * * * $me" $CRONDIR/$CRONUSR ;;esac ;;esac fi echo $CRONUSR > $CRONDIR/cron.update exit 0 ;; status) echo "Firewall status:" iptables -nL FORWARD|egrep '^(DROP|REJECT)? +all +-- +[1-9][0-9\.]+ +0.0.0.0/0\b' || echo " No IPs blocked" egrep -q "/${0##*/}" $CRONDIR/$CRONUSR && echo "Running via cron" || echo "Not running via cron" exit 0 ;; -h|--help|help) cat<&2 echo "Use 'sysctl -w net.netfilter.nf_conntrack_acct=1'" >&2 exit 1 fi fi # Different kernels have differnt formats, script lines doubled to prevent too much compare operations REL=$(uname -r) case ${REL#2.4} in $REL) # Kernel 2.6 output has [STATUS] in different positions, shift to end sed 's/\./_/g;s/\( \[[^]]\+\]\)\(.*\)/\2\1/;$aeof' "$CONN"|while read l;do set $l case $1 in tcp) tcp ${5#src=} ${7#sport=} ${6#dst=} ${8#dport=} ${11#src=} ${13#sport=} ${12#dst=} ${14#dport=} $(( ${10#bytes=} + ${16#bytes=} )) $4 ;; udp) udp ${4#src=} ${6#sport=} ${5#dst=} ${7#dport=} ${10#src=} ${12#sport=} ${11#dst=} ${13#dport=} $(( ${9#bytes=}+${15#bytes=} )) ${19} ;; eof) # If probably no P2P client active double threshold test $UNK -lt 10 && BOGOTHRESH=$(( $BOGOTHRESH + $BOGOTHRESH )) set|sed -n "s/^\\(IP_[^=]\\+=\\)'*\\([^']\\+\\).*/\\1\\2/p"|while read i;do case $DEBIP in ${i%=*})echo "$i -gt $BOGOTHRESH";;esac case $DEBUGLOGS in "");;*)echo $DEBUGLOGS ${i#*=} >> /var/log/zapp/${i%=*};;esac test ${i#*=} -gt $BOGOTHRESH && zapp $i ${i#*=} done ;; esac done ;;*) # Kernel 2.4 output has [STATUS] in different positions, shift to end sed 's/\./_/g;s/\( \[[^]]\+\]\)\(.*\)/\2\1/;$aeof' "$CONN"|while read l;do set $l case $1 in tcp) tcp ${5#src=} ${7#sport=} ${6#dst=} ${8#dport=} ${9#src=} ${11#sport=} ${10#dst=} ${12#dport=} ${15#bytes=} $4 ;; udp) udp ${4#src=} ${6#sport=} ${5#dst=} ${7#dport=} ${8#src=} ${10#sport=} ${9#dst=} ${11#dport=} ${14#bytes=} ${15} ;; eof) # If probably no P2P client active double threshold test $UNK -lt 10 && BOGOTHRESH=$(( $BOGOTHRESH + $BOGOTHRESH )) set|sed -n "s/^\\(IP_[^=]\\+=\\)'*\\([^']\\+\\).*/\\1\\2/p"|while read i;do case $DEBIP in ${i%=*})echo "$i -gt $BOGOTHRESH";;esac case $DEBUGLOGS in "");;*)echo $DEBUGLOGS ${i#*=} >> /var/log/zapp/${i%=*};;esac test ${i#*=} -gt $BOGOTHRESH && zapp $i ${i#*=} done ;; esac done ;;esac exit 0