Created
June 6, 2014 09:57
-
-
Save booo/ea0f42f3d1754b4237aa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# If you got false positives, try a higher value | |
BOGOTHRESH=1500 | |
# Defines how much unsoliced incoming udp is accepted | |
BOGOIGRESS=20 | |
# 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 | |
[email protected] | |
[email protected] | |
# Insert IPs you trust | |
TRUSTEDIP="${TRUSTEDIP} 1.2.3.4" | |
# Insert IPs you don't trust | |
UNTRUSTEDIP="${TRUSTEDIP} 1.2.3.4" | |
# 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= | |
# DEBUGLOGS=$(date "+%b%d %H:%M") | |
# 0: Manual clear, or minutes until auto-clear blockade (5-1439) | |
CLEARTIME=240 | |
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}') | |
MY_ADR=$(ip -f inet addr list dev ${DEV} scope global|sed -n '2s/^.*inet \([0-9\.]\+\).*/\1/p') | |
MY_PAT=$(echo ${MY_ADR}|sed 's/\./_/g') | |
MY_UIN=0 | |
XOR_PAT=${MY_PAT} | |
XOR_VAL=$(cat /var/run/roulette-xor.txt 2>&-) | |
case ${XOR_VAL} in "");;*) | |
# Special: We run on the VPN03 server with multiple IPs mapped through | |
# some XOR pattern. Note: currently works only up to /24 network size. | |
XOR_PAT="77_87_49_*" | |
;;esac | |
which () { | |
# Note: do not unset IFS (busybox ash and bash are different here) | |
for p in $(echo ${PATH}|sed 's/:/ /g');do | |
test -x ${p}/${1} && return 0 | |
done | |
return 1 | |
} | |
# Freifunk Firmware Configs | |
which nvram && { | |
ff_zapp_thresh=$(nvram get ff_zapp_thresh) | |
BOGOTHRESH=${ff_zapp_thresh:-${BOGOTHRESH}} | |
} | |
case ${BOGOTHRESH} in ""|0)exit 0;;esac | |
NC_CMD= | |
which nc && NC_CMD=nc | |
which nc-hobbit && NC_CMD=nc-hobbit | |
which netcat && NC_CMD=netcat | |
which nc6 && NC_CMD=nc6 | |
# Note: busybox nc unusable, "-q" only Debian, GNU netcat "-c" unusable | |
${NC_CMD} -h 2>&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:-${MY_ADR}}|sed 's/\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)\.\([0-9]\+\)/\4 \3 \2 \1/')) | |
be=$(printf "%02X%02X%02X%02X" $(echo ${ifip:-${MY_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:-${MY_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:-${MY_ADR}}:53 | |
portfw ${1} tcp ${2} 53 ${ifip:-${MY_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 "");;*) | |
#sven-ola: funzt ned...!? portfw ${1} tcp ${2} 80 ${ifip:-${MY_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 && 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 | |
while true;do (${NC_CMD} -l -p ${BLOCKPORT} <<EOF | |
HTTP/1.0 200 OK | |
Expires: -1 | |
Pragma: no-cache | |
Cache-Control: no-cache | |
Content-Type: text/html; charset=utf-8 | |
<HTML> | |
<HEAD><TITLE>Sorry...</TITLE> | |
<META HTTP-EQUIV="Expires" CONTENT="-1"> | |
<META HTTP-EQUIV="Pragma" CONTENT="no-cache"> | |
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache"> | |
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8"> | |
<STYLE TYPE="text/css"></STYLE> | |
</HEAD> | |
<BODY ONLOAD="if ('/let-me-browse-again' == window.location.pathname)location.href=document.referrer"> | |
<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!-- | |
function addrule(selector, rule) | |
{ | |
if (null!=document.styleSheets && 0<document.styleSheets.length) | |
{ | |
if (null!=document.styleSheets[0].cssRules) | |
{ | |
document.styleSheets[0].insertRule(selector+"{"+rule+"}", 0); | |
} | |
else if (null!=document.styleSheets[0].rules) | |
{ | |
document.styleSheets[0].addRule(selector, rule); | |
} | |
} | |
} | |
if (null != navigator.language && "de" == navigator.language || | |
null != navigator.browserLanguage && "de" == navigator.browserLanguage) | |
{ | |
addrule(".de", "display:block"); | |
addrule(".fr", "display:none"); | |
addrule(".en", "display:none"); | |
} | |
else if (null != navigator.language && "fr" == navigator.language || | |
null != navigator.browserLanguage && "fr" == navigator.browserLanguage) | |
{ | |
addrule(".de", "display:none"); | |
addrule(".fr", "display:block"); | |
addrule(".en", "display:none"); | |
} | |
else | |
{ | |
addrule(".de", "display:none"); | |
addrule(".fr", "display:none"); | |
addrule(".en", "display:block"); | |
} | |
//--></SCRIPT> | |
<H1>Zapped on $(uname -n) (${ifip:-${MY_ADR}})</H1> | |
<DIV CLASS="en"> | |
<P><SMALL CLASS="de">Deutsch: siehe unten</SMALL><SMALL CLASS="fr">français : voir ci-dessous</SMALL></P> | |
<HR> | |
<P>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 | |
<A HREF='http://${ifip}/cgi-bin-skype.html'>Information Page</A>.") | |
</P> | |
<P>TCP based services still work (ports up to 1023), but UDP based services are blocked now.</P> | |
<FORM ACTION='/let-me-browse-again' METHOD='GET'><INPUT | |
VALUE='I have read this page and stopped the respective program. Please restore access to the Web.' | |
TYPE='submit'></FORM> | |
<P>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 <A HREF="mailto:${MAILADDR}">${MAILADDR}</A>. | |
</P> | |
</DIV> | |
<DIV CLASS="de"> | |
<HR> | |
<P>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 | |
<A HREF='http://${ifip}/cgi-bin-skype.html'>Informationsseite</A>.") | |
</P> | |
<P><B>Hinweis:</B> TCP-basierte Dienste (Ports bis 1023) funktionieren, aber UDP-basierte Dienste sind nun gesperrt.</P> | |
<FORM ACTION='/let-me-browse-again' METHOD='GET'><INPUT | |
VALUE='Ich habe verstanden und das entsprechende Programm beendet. Bitte Web-Zugang freigeben.' | |
TYPE='submit'></FORM> | |
<P>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 | |
<A HREF="mailto:${MAILADDR}">${MAILADDR}</A>. | |
</P> | |
</DIV> | |
<DIV CLASS="fr"> | |
<HR> | |
<P>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 | |
<A HREF='http://${ifip}/cgi-bin-skype.html'>page d'informations</A>.") | |
</P> | |
<P><B>Précisions:</B> Les services TCP restent fonctionnels (Ports jusqu'au n° 1023) mais les | |
services UDP sont bloqués. | |
<FORM ACTION='/let-me-browse-again' METHOD='GET'><INPUT | |
VALUE='J‘ai lu cette page et j‘ai arrêté les programmes suspectés. Lever le blocage!' | |
TYPE='submit'></FORM> | |
<P>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 à | |
<A HREF="mailto:${MAILADDR}">${MAILADDR}</A>. | |
</P> | |
</DIV> | |
</BODY> | |
<HEAD> | |
<META HTTP-EQUIV="Pragma" CONTENT="no-cache"> | |
<META HTTP-EQUIV="Expires" CONTENT="-1"> | |
</HEAD> | |
</HTML> | |
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}<<EOF | |
To: ${MAILADDR} | |
From: ${MAILFROM} | |
Subject: Zappfile extended on $(uname -n) | |
The following IP exeeded the conntrack limit and was added to the zappfile: | |
IP: ${ip} | |
MAC: ${mac} | |
Date: $(date) | |
Bogopoints: ${2} | |
Threshold: ${BOGOTHRESH} | |
The forwarding firewall now has the following rules: | |
$(iptables -nL FORWARD) | |
EOF | |
fi | |
} | |
# TCP rules: | |
# * Bittorrent opens and uses lots of TCP connections | |
# * BT also uses a higher bandwidth, especially on port 688x | |
# * General: lots of TCP traffic from/to different peers (!port 80) | |
conn_tcp () { | |
# We only count traffic generated by others | |
case ${3} in ${MY_PAT}|${XOR_PAT});;*) | |
case "${10}" in | |
# We count unreplied connection attempts because | |
# lots of P2P peers may not have correct portfw | |
# as well as currently active transfers | |
SYN_SENT|SYN_RECV|ESTABLISHED) | |
case ${4} in | |
# HTTP, HTTPS: browsers tend to open multiple connections | |
80|443) | |
case ${9} in | |
?????) | |
eval "case \${TCP_${1}_${3}} in \"\")IP_${1}=\$(( \${IP_${1}} + 1 ));;esac" | |
;; | |
*) | |
eval "case \${TCP_${1}_${3}} in \"\")IP_${1}=\$(( \${IP_${1}} + 2 ));;esac" | |
;; | |
esac | |
case ${DEBIP#IP_} in ${1})echo "tcp ham ${1}:${2} ${3}:${4}";;esac | |
;; | |
# Punish traffic on ports 6880-6889 | |
688*) | |
case ${9} in | |
?????) | |
eval "case \${TCP_${1}_${3}} in \"\")IP_${1}=\$(( \${IP_${1}} + 10 ));;esac" | |
;; | |
*) | |
eval "case \${TCP_${1}_${3}} in \"\")IP_${1}=\$(( \${IP_${1}} + 20 ));;esac" | |
;; | |
esac | |
case ${DEBIP#IP_} in ${1})echo "tcp p2p ${1}:${2} ${3}:${4}";;esac | |
;; | |
# Everything else is normal tcp | |
*) | |
case ${9} in | |
?????) | |
eval "case \${TCP_${1}_${3}} in \"\")IP_${1}=\$(( \${IP_${1}} + 3 ));;esac" | |
;; | |
*) | |
eval "case \${TCP_${1}_${3}} in \"\")IP_${1}=\$(( \${IP_${1}} + 4 ));;esac" | |
;; | |
esac | |
case ${DEBIP#IP_} in ${1})echo "tcp std ${1}:${2} ${3}:${4}";;esac | |
;; | |
esac | |
eval "TCP_${1}_${3}=\$(( \${TCP_${1}_${3}} + 1 ))" | |
;; | |
esac | |
;;esac | |
return 0 | |
} | |
# UDP rules: | |
# * Bittorrent DHT feature got us unreplied incoming UDP from diverse IPs (sport likely 688x) | |
# * P2P-user with DHT: incoming UDP dport(unreplied) is port the P2P-user configured for DHT | |
# * P2P-user none DHT: Peers seeking DHT, we have a P2P-user currently, lower tolerance | |
# * General: lots of UDP traffic from/to different peers(!port 53) | |
conn_udp () { | |
case ${10} in "[UNREPLIED]") | |
case ${3} in ${MY_PAT}) | |
# We are contacted by incoming UDP (without reason). If that is the case | |
# it is likely that we have at least one P2P user now. Especially if that | |
# peer sends us from his port 688x which is the default for Bittorrent. | |
case ${2} in | |
668*) | |
eval "case \${UIN_${1}} in \"\")MY_UIN=\$(( \${MY_UIN} + 3 ));;esac" | |
case ${DEBIP} in '');;*)echo "nak p2p ${1}:${2} -> ${3}:${4} (MY_UIN=${MY_UIN})";;esac | |
;; | |
*) | |
case ${4} in | |
688*) | |
eval "case \${UIN_${1}} in \"\")MY_UIN=\$(( \${MY_UIN} + 3 ));;esac" | |
case ${DEBIP} in '');;*)echo "nak p2p ${1}:${2} -> ${3}:${4} (MY_UIN=${MY_UIN})";;esac | |
;; | |
*) | |
eval "case \${UIN_${1}} in \"\")MY_UIN=\$(( \${MY_UIN} + 1 ));;esac" | |
case ${DEBIP} in '');;*)echo "nak udp ${1}:${2} -> ${3}:${4} (MY_UIN=${MY_UIN})";;esac | |
;; | |
esac | |
;; | |
esac | |
eval "UIN_${1}=\$(( \${UIN_${1}} + 1 ))" | |
;;${XOR_PAT}) | |
# Same as above, but for a net range associated with our interface | |
case ${2} in | |
668*) | |
eval "case \${XIN_${1}_${3##*_}} in \"\")MY_XIN_${3##*_}=\$(( \${MY_XIN_${3##*_}} + 3 ));;esac" | |
case ${DEBIP} in '');;*)eval echo "nak p2p \${1}\:\${2} -\> \${3}:\${4} \(MY_XIN_${3##*_}=\${MY_XIN_${3##*_}}\)";;esac | |
;; | |
*) | |
case ${4} in | |
688*) | |
eval "case \${XIN_${1}_${3##*_}} in \"\")MY_XIN_${3##*_}=\$(( \${MY_XIN_${3##*_}} + 3 ));;esac" | |
case ${DEBIP} in '');;*)eval echo "nak p2p \${1}\:\${2} -\> \${3}:\${4} \(MY_XIN_${3##*_}=\${MY_XIN_${3##*_}}\)";;esac | |
;; | |
*) | |
eval "case \${XIN_${1}_${3##*_}} in \"\")MY_XIN_${3##*_}=\$(( \${MY_XIN_${3##*_}} + 1 ));;esac" | |
case ${DEBIP} in '');;*)eval echo "nak udp \${1}\:\${2} -\> \${3}:\${4} \(MY_XIN_${3##*_}=\${MY_XIN_${3##*_}}\)";;esac | |
;; | |
esac | |
;; | |
esac | |
eval "XIN_${1}_${3##*_}=\$(( \${XIN_${1}_${3##*_}} + 1 ))" | |
;;esac | |
;;esac | |
# We only count traffic generated by others | |
case ${3} in ${MY_PAT}|${XOR_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 | |
} | |
work_eof () { | |
# If probably no P2P client active double threshold | |
if [ -z "${MY_UIN}" ];then | |
uin=${BOGOIGRESS} | |
elif [ ${MY_UIN} -ge ${BOGOIGRESS} ];then | |
uin=0 | |
else | |
uin=$(( ${BOGOIGRESS} - ${MY_UIN} )) | |
fi | |
thr=$(( ${BOGOTHRESH} * ( ${BOGOIGRESS} + ${uin} ) / ${BOGOIGRESS} )) | |
set|sed -n "s/^\\(IP_[^=]\\+=\\)'*\\([^']\\+\\).*/\\1\\2/p"|while read i;do | |
case ${XOR_VAL} in "");;*) | |
j=${i%=*} | |
j=$(( ${j##*_} % 64 ^ ${XOR_VAL} )) | |
eval "j=\${MY_XIN_${j}}" | |
if [ -z "${j}" ];then | |
uin=${BOGOIGRESS} | |
elif [ ${j} -ge ${BOGOIGRESS} ];then | |
uin=0 | |
else | |
uin=$(( ${BOGOIGRESS} - ${j} )) | |
fi | |
thr=$(( ${BOGOTHRESH} * ( ${BOGOIGRESS} + ${uin} ) / ${BOGOIGRESS} )) | |
;;esac | |
case ${DEBIP} in ${i%=*})echo "${i} -gt ${thr}";;esac | |
case ${DEBUGLOGS} in "");;*)echo ${DEBUGLOGS} ${i#*=} >> /var/log/zapp/${i%=*};;esac | |
test ${i#*=} -gt ${thr} && zapp ${i} ${i#*=} | |
done | |
} | |
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<<EOF | |
This script examines the kernel conntrack table and blocks a source IP if | |
it detects a filesharing application. Read the script file for details. | |
Usage: ${0} {start|stop|block [IP]|unblock [IP]|help|[file]} | |
start add this scipt as cron job | |
stop remove this script from cron | |
status show a list of blocked IPs | |
block manually block an IP | |
unblock manually unblock an IP | |
[file] parse [file] instead /proc/net/ip_conntrack (for testing) | |
No args normal function, e.g. called by cron without arguments | |
Note1: if netcat is installed, this script tries to inform a blocked user | |
by starting a simple web server. If also ssmtp is installed, this script | |
informs you by e-mail about the filesharing and blocking incidents. If | |
someone is blocked, this is recorded in /var/log/zapp* files for later | |
analysis. To analyze, unpack the gzipped conntrack file of the incident | |
and start this script by supplying the filename. | |
Note2: to install on Freifunk-FW copy this script to /etc/init.d/ and | |
restart the router. On other systems it shoud be sufficient to start | |
this script with "${0} start". | |
EOF | |
exit 0 | |
;; | |
esac | |
if ! ${DEBUG}; then | |
if [ -f /proc/sys/net/netfilter/nf_conntrack_acct ] && | |
[ 0 = $(cat /proc/sys/net/netfilter/nf_conntrack_acct) ] | |
then | |
# Kernel-2.6 needs accounting=on for correct ip_conntrack format | |
echo "Kernel accounting not enabled, which is required." >&2 | |
echo "Use 'sysctl -w net.netfilter.nf_conntrack_acct=1'" >&2 | |
exit 1 | |
fi | |
fi | |
# Note: IP addresses ignored below belong to Microsoft's skype service | |
SED=' | |
$aeof | |
/^tcp[[:space:]]\+[[:digit:]]\+[[:space:]]\+[[:digit:]]\+[[:space:]]\+TIME_WAIT[[:space:]]/d | |
/=\(111\.221\.74\|111\.221\.77\|157\.55\.130\|157\.55\.235\|157\.55\.56\|157\.56\.52\|213\.199\.179\|63\.245\.217\|64\.4\.23\|65\.55\.223\)\./d | |
s/\./_/g | |
s/\( \[[^]]\+\]\)\(.*\)/\2\1/' | |
# 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 "${SED}" "${CONN}"|while read l;do | |
set ${l} | |
case ${1} in | |
tcp) | |
conn_tcp ${5#src=} ${7#sport=} ${6#dst=} ${8#dport=} ${11#src=} ${13#sport=} ${12#dst=} ${14#dport=} $(( ${10#bytes=} + ${16#bytes=} )) ${4} | |
;; | |
udp) | |
conn_udp ${4#src=} ${6#sport=} ${5#dst=} ${7#dport=} ${10#src=} ${12#sport=} ${11#dst=} ${13#dport=} $(( ${9#bytes=}+${15#bytes=} )) ${19} | |
;; | |
eof) | |
work_eof | |
;; | |
esac | |
done | |
;;*) | |
# Kernel 2.4 output has [STATUS] in different positions, shift to end | |
sed "${SED}" "${CONN}"|while read l;do | |
set ${l} | |
case ${1} in | |
tcp) | |
conn_tcp ${5#src=} ${7#sport=} ${6#dst=} ${8#dport=} ${9#src=} ${11#sport=} ${10#dst=} ${12#dport=} ${15#bytes=} ${4} | |
;; | |
udp) | |
conn_udp ${4#src=} ${6#sport=} ${5#dst=} ${7#dport=} ${8#src=} ${10#sport=} ${9#dst=} ${11#dport=} ${14#bytes=} ${15} | |
;; | |
eof) | |
work_eof | |
;; | |
esac | |
done | |
;;esac | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment