Revision history for ddosDotSh
Additions:
Please note the following code has been deprecated in favor of a more robust [[ddosDotPl|Perl script]].
Revision [2847]
Edited on 2012-03-16 11:52:47 by JeffTaylor [DSTMask allows monitoring only incoming packets]Additions:
#DST=10.0.0.211
## Destination interfaces to monitor (required)
## Source interfaces to monitor (optional)
if [ "$DSTDEV" ]; then
DSTMask=$( ifconfig $DSTDEV | grep "inet addr:" | awk '{split($3,ip,":"); split($4,mask,":"); split(ip[2],ip,"."); split(mask[2],mask,"."); bits=8; for(x=255; x>=0; x-=2^i++) map[x]=bits--; for(i=1; i<=4;i++) { subnet+=map[mask[i]]; ip[i]==mask[5-i]?cidr=cidr".0":cidr=cidr"."ip[i]; } print substr(cidr,2)"/"subnet }' )
DSTMask="not src net ${DSTMask} and"
DSTDEV="-i $DSTDEV"
dumpCount=50
#echo "tcpdump -pnt $DSTDEV $DST $DSTMask udp port 53 and '(ip[2:2] != 0)' -c$dumpCount"
tcpdump="tcpdump -pnt $DSTDEV $DST $DSTMask udp port 53 and '(ip[2:2] != 0)' -c$dumpCount 2>/dev/null"
#logger -t $NAME -- iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
## Destination interfaces to monitor (required)
## Source interfaces to monitor (optional)
if [ "$DSTDEV" ]; then
DSTMask=$( ifconfig $DSTDEV | grep "inet addr:" | awk '{split($3,ip,":"); split($4,mask,":"); split(ip[2],ip,"."); split(mask[2],mask,"."); bits=8; for(x=255; x>=0; x-=2^i++) map[x]=bits--; for(i=1; i<=4;i++) { subnet+=map[mask[i]]; ip[i]==mask[5-i]?cidr=cidr".0":cidr=cidr"."ip[i]; } print substr(cidr,2)"/"subnet }' )
DSTMask="not src net ${DSTMask} and"
DSTDEV="-i $DSTDEV"
dumpCount=50
#echo "tcpdump -pnt $DSTDEV $DST $DSTMask udp port 53 and '(ip[2:2] != 0)' -c$dumpCount"
tcpdump="tcpdump -pnt $DSTDEV $DST $DSTMask udp port 53 and '(ip[2:2] != 0)' -c$dumpCount 2>/dev/null"
#logger -t $NAME -- iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
Deletions:
## Interfaces to monitor (optional)
if [ "$DSTDEV" ]; then DSTDEV="-i $DSTDEV"; fi
dumpCount=30
tcpdump="tcpdump -pnt $DSTDEV $DST udp port 53 and '(ip[2:2] != 0)' -c$dumpCount 2>/dev/null"
Revision [2846]
Edited on 2012-03-16 02:27:33 by JeffTaylor [Added auto-restart and filter out IPv6]Additions:
## Updated 2012-03-15
## This script is intended to be run by root. Attempts to run under sudo
## have not always been successful and cannot be guarenteed.
## Destination IP (address of your DNS server)(optional)
## Interfaces to monitor (optional)
DSTDEV=eth0
TEMPFILE="${BLOCKFILE}.tmp"
dumpCount=30
tcpdump="tcpdump -pnt $DSTDEV $DST udp port 53 and '(ip[2:2] != 0)' -c$dumpCount 2>/dev/null"
scriptdir=$(pwd) ; scriptname=$(basename $0) ; self="$scriptdir/$scriptname"
scriptDate=$( stat -c %Y $self )
rule=$( iptables -nL INPUT | grep "\-s $IP/" )
echo "$END $IP $PORT $multi `date \"+(%x %T)\" -d @$END`" >> $BLOCKFILE
eval iptables -I INPUT --source $IP $SRCDEV -p udp --sport $PORT -j DROP
eval iptables -I FORWARD --source $IP $SRCDEV -p udp --sport $PORT -j DROP
multi=$( echo $multi | sed 's/\s.*//' )
eval iptables -D INPUT --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/dev/null
eval iptables -D FORWARD --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/dev/null
echo "$END #$IP $PORT $multi `date \"+(%x %T)\" -d @$END`" >> $BLOCKFILE
## Check if script has changed
if [ $scriptDate != $( stat -c %Y $self ) ]; then
logger -t $NAME Restarting $scriptname
$self "$@" &
exit 0
## This script is intended to be run by root. Attempts to run under sudo
## have not always been successful and cannot be guarenteed.
## Destination IP (address of your DNS server)(optional)
## Interfaces to monitor (optional)
DSTDEV=eth0
TEMPFILE="${BLOCKFILE}.tmp"
dumpCount=30
tcpdump="tcpdump -pnt $DSTDEV $DST udp port 53 and '(ip[2:2] != 0)' -c$dumpCount 2>/dev/null"
scriptdir=$(pwd) ; scriptname=$(basename $0) ; self="$scriptdir/$scriptname"
scriptDate=$( stat -c %Y $self )
rule=$( iptables -nL INPUT | grep "\-s $IP/" )
echo "$END $IP $PORT $multi `date \"+(%x %T)\" -d @$END`" >> $BLOCKFILE
eval iptables -I INPUT --source $IP $SRCDEV -p udp --sport $PORT -j DROP
eval iptables -I FORWARD --source $IP $SRCDEV -p udp --sport $PORT -j DROP
multi=$( echo $multi | sed 's/\s.*//' )
eval iptables -D INPUT --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/dev/null
eval iptables -D FORWARD --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/dev/null
echo "$END #$IP $PORT $multi `date \"+(%x %T)\" -d @$END`" >> $BLOCKFILE
## Check if script has changed
if [ $scriptDate != $( stat -c %Y $self ) ]; then
logger -t $NAME Restarting $scriptname
$self "$@" &
exit 0
Deletions:
## This script is intended to be run by root.
## Destination IP (address of your DNS server) (optional)
## Interface to monitor (optional)
#DSTDEV=eth0
TEMPFILE="/root/ddos.block.tmp"
## Name of iptables chain and method for adding new entries
## If you run script from the DNS server, CHAIN="INPUT"
## If you run script from a firewall, CHAIN="FORWARD"
addCHAIN="-I"
CHAIN="INPUT"
dumpCount=35
tcpdump="tcpdump -pnt $DSTDEV $DST udp port 53 -c$dumpCount 2>/dev/null"
rule=$( iptables -nL $CHAIN | grep "\-s $IP/" )
echo "$END $IP $PORT $multi" >> $BLOCKFILE
eval iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
#logger -t $NAME -- iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
eval iptables -D $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/dev/null
echo "$END #$IP $PORT $multi" >> $BLOCKFILE
Revision [2788]
Edited on 2012-02-18 11:08:51 by JeffTaylor [Adjust code for older versions of bash]Additions:
## Updated 2012-02-17
#SRCDEV=wan0
#DSTDEV=eth0
if [ "$DST" ]; then DST="dst $DST and"; fi
if [ "$SRCDEV" ]; then SRCDEV="-i $SRCDEV"; fi
if [ "$DSTDEV" ]; then DSTDEV="-i $DSTDEV"; fi
if [ $TIMER -lt 1 ]; then TIMER=225; fi
rule=$( iptables -nL $CHAIN | grep "\-s $IP/" )
if [ "${timeout:0:1}" != "#" ]; then
#SRCDEV=wan0
#DSTDEV=eth0
if [ "$DST" ]; then DST="dst $DST and"; fi
if [ "$SRCDEV" ]; then SRCDEV="-i $SRCDEV"; fi
if [ "$DSTDEV" ]; then DSTDEV="-i $DSTDEV"; fi
if [ $TIMER -lt 1 ]; then TIMER=225; fi
rule=$( iptables -nL $CHAIN | grep "\-s $IP/" )
if [ "${timeout:0:1}" != "#" ]; then
Deletions:
SRCDEV=wan0
DSTDEV=eth0
if [[ $DST ]]; then DST="dst $DST and"; fi
if [[ $SRCDEV ]]; then SRCDEV="-i $SRCDEV"; fi
if [[ $DSTDEV ]]; then DSTDEV="-i $DSTDEV"; fi
if [[ $TIMER < 1 ]]; then TIMER=225; fi
rule=$( iptables --list-rules FORWARD | grep "\-s $IP/" )
#echo ${INFO[$i]}
if [[ ! "$timeout" =~ ^# ]]; then
Revision [2787]
Edited on 2012-02-17 07:42:34 by JeffTaylor [Adjust code for older versions of bash]Additions:
## Updated 2012-02-16
Deletions:
Additions:
eval iptables -D $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/dev/null
Deletions:
Additions:
## ddos.sh - Written by Jeff Taylor (Shdwdrgn)
## Updated 2012-02-15
## To use this script, you must have iptables and tcpdump installed.
## awk, sed, and logger need to be in the path of the user running this script.
## This script is intended to be run by root.
## Destination IP (address of your DNS server) (optional)
#DST=10.0.0.10
## Interface to monitor (optional)
SRCDEV=wan0
DSTDEV=eth0
BLOCKFILE="/root/ddos.block"
TEMPFILE="/root/ddos.block.tmp"
## Name of iptables chain and method for adding new entries
## If you run script from the DNS server, CHAIN="INPUT"
## If you run script from a firewall, CHAIN="FORWARD"
addCHAIN="-I"
## Time (in seconds) to keep an IP address blocked (Default is 225)
TIMER=225
if [ "$(pidof -xo $$ $(basename $0))" ]; then exit 1 ; fi
if [ ! -f "$BLOCKFILE" ]; then
echo "#Expires #IP Address #Port #Multiplier" > $BLOCKFILE
fi
if [[ $DST ]]; then DST="dst $DST and"; fi
if [[ $SRCDEV ]]; then SRCDEV="-i $SRCDEV"; fi
if [[ $DSTDEV ]]; then DSTDEV="-i $DSTDEV"; fi
if [[ $TIMER < 1 ]]; then TIMER=225; fi
origIFS=$IFS
dumpCount=35
matches=7
tcpdump="tcpdump -pnt $DSTDEV $DST udp port 53 -c$dumpCount 2>/dev/null"
tcpdump="$tcpdump | awk '{"
tcpdump="$tcpdump n=split(\$2,ip,\".\");"
tcpdump="$tcpdump if (n<3) split(ip[1],ipv6,\":\");"
tcpdump="$tcpdump if (ip[1]!=10) {"
tcpdump="$tcpdump if (n>2) printf \"%s.%s.%s.%s %s \",ip[1],ip[2],ip[3],ip[4],ip[5];"
tcpdump="$tcpdump else printf \"%s %s \",ip[1],ip[2];"
tcpdump="$tcpdump if(\$6!=\"[1au]\") printf \"%s \",\$6;"
tcpdump="$tcpdump print \$7,\$8,\$9"
tcpdump="$tcpdump } }'"
tcpdump="$tcpdump | sort | uniq -c"
tcpdump="$tcpdump | awk '{ if (\$1>=$matches) print \$0 }'"
IFS=$'\n'
unset PKT
unset cPKT
INFO=( $( eval $tcpdump ) )
## If any particular packets exceed our threshold, block that IP address
now=$( date "+%s" )
num=${#INFO[@]}
for (( i=0; i<$num; i++ )); do
IP=$( echo ${INFO[$i]} | awk '{ print $2 }' )
PORT=$( echo ${INFO[$i]} | awk '{ print $3 }' )
URL=$( echo ${INFO[$i]} | awk '{ print $5 }' )
multi=1
marked=$( grep "[[:space:]]$IP" $BLOCKFILE )
rule=$( iptables --list-rules FORWARD | grep "\-s $IP/" )
if [ ! "$marked" ] || [ ! "$rule" ]; then
#echo ${INFO[$i]}
if [ $PORT -gt 1023 ]; then
last=$( grep \#$IP $BLOCKFILE )
if [ "$last" ]; then
multi=$( echo $last | awk '{ print $4 }' )
if [ ! "$multi" ]; then multi=1 ; fi
multi=$(( $multi * 2 ))
sed "/\#$IP/d" $BLOCKFILE > $TEMPFILE
mv -f $TEMPFILE $BLOCKFILE
fi
END=$(( $now + ( $TIMER * $multi )))
echo "$END $IP $PORT $multi" >> $BLOCKFILE
eval iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
logger -t $NAME \(x$multi\) $IP:$PORT @ $URL
#logger -t $NAME -- iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
IFS=$origIFS
while read timeout ip PORT multi ; do
if [[ ! "$timeout" =~ ^# ]]; then
IP=${ip#\#}
if [ ! "$multi" ]; then multi=1 ; fi
if [ $timeout -lt $now ] ; then
eval iptables -D $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/d$
sed "/$IP/d" $BLOCKFILE > $TEMPFILE
mv -f $TEMPFILE $BLOCKFILE
if [ "$ip" == "$IP" ]; then
logger -t $NAME Removed $IP
END=$(( $now + ( $TIMER * $multi )))
echo "$END #$IP $PORT $multi" >> $BLOCKFILE
fi
fi
## Updated 2012-02-15
## To use this script, you must have iptables and tcpdump installed.
## awk, sed, and logger need to be in the path of the user running this script.
## This script is intended to be run by root.
## Destination IP (address of your DNS server) (optional)
#DST=10.0.0.10
## Interface to monitor (optional)
SRCDEV=wan0
DSTDEV=eth0
BLOCKFILE="/root/ddos.block"
TEMPFILE="/root/ddos.block.tmp"
## Name of iptables chain and method for adding new entries
## If you run script from the DNS server, CHAIN="INPUT"
## If you run script from a firewall, CHAIN="FORWARD"
addCHAIN="-I"
## Time (in seconds) to keep an IP address blocked (Default is 225)
TIMER=225
if [ "$(pidof -xo $$ $(basename $0))" ]; then exit 1 ; fi
if [ ! -f "$BLOCKFILE" ]; then
echo "#Expires #IP Address #Port #Multiplier" > $BLOCKFILE
fi
if [[ $DST ]]; then DST="dst $DST and"; fi
if [[ $SRCDEV ]]; then SRCDEV="-i $SRCDEV"; fi
if [[ $DSTDEV ]]; then DSTDEV="-i $DSTDEV"; fi
if [[ $TIMER < 1 ]]; then TIMER=225; fi
origIFS=$IFS
dumpCount=35
matches=7
tcpdump="tcpdump -pnt $DSTDEV $DST udp port 53 -c$dumpCount 2>/dev/null"
tcpdump="$tcpdump | awk '{"
tcpdump="$tcpdump n=split(\$2,ip,\".\");"
tcpdump="$tcpdump if (n<3) split(ip[1],ipv6,\":\");"
tcpdump="$tcpdump if (ip[1]!=10) {"
tcpdump="$tcpdump if (n>2) printf \"%s.%s.%s.%s %s \",ip[1],ip[2],ip[3],ip[4],ip[5];"
tcpdump="$tcpdump else printf \"%s %s \",ip[1],ip[2];"
tcpdump="$tcpdump if(\$6!=\"[1au]\") printf \"%s \",\$6;"
tcpdump="$tcpdump print \$7,\$8,\$9"
tcpdump="$tcpdump } }'"
tcpdump="$tcpdump | sort | uniq -c"
tcpdump="$tcpdump | awk '{ if (\$1>=$matches) print \$0 }'"
IFS=$'\n'
unset PKT
unset cPKT
INFO=( $( eval $tcpdump ) )
## If any particular packets exceed our threshold, block that IP address
now=$( date "+%s" )
num=${#INFO[@]}
for (( i=0; i<$num; i++ )); do
IP=$( echo ${INFO[$i]} | awk '{ print $2 }' )
PORT=$( echo ${INFO[$i]} | awk '{ print $3 }' )
URL=$( echo ${INFO[$i]} | awk '{ print $5 }' )
multi=1
marked=$( grep "[[:space:]]$IP" $BLOCKFILE )
rule=$( iptables --list-rules FORWARD | grep "\-s $IP/" )
if [ ! "$marked" ] || [ ! "$rule" ]; then
#echo ${INFO[$i]}
if [ $PORT -gt 1023 ]; then
last=$( grep \#$IP $BLOCKFILE )
if [ "$last" ]; then
multi=$( echo $last | awk '{ print $4 }' )
if [ ! "$multi" ]; then multi=1 ; fi
multi=$(( $multi * 2 ))
sed "/\#$IP/d" $BLOCKFILE > $TEMPFILE
mv -f $TEMPFILE $BLOCKFILE
fi
END=$(( $now + ( $TIMER * $multi )))
echo "$END $IP $PORT $multi" >> $BLOCKFILE
eval iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
logger -t $NAME \(x$multi\) $IP:$PORT @ $URL
#logger -t $NAME -- iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP
IFS=$origIFS
while read timeout ip PORT multi ; do
if [[ ! "$timeout" =~ ^# ]]; then
IP=${ip#\#}
if [ ! "$multi" ]; then multi=1 ; fi
if [ $timeout -lt $now ] ; then
eval iptables -D $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP 2>/d$
sed "/$IP/d" $BLOCKFILE > $TEMPFILE
mv -f $TEMPFILE $BLOCKFILE
if [ "$ip" == "$IP" ]; then
logger -t $NAME Removed $IP
END=$(( $now + ( $TIMER * $multi )))
echo "$END #$IP $PORT $multi" >> $BLOCKFILE
fi
fi
Deletions:
BLOCKFILE="/etc/ddos.block"
TEMPFILE="/tmp/ddos.tmp"
## Which file does your DNS service log query info in (full path required)
LOGFILE="/var/log/named/filter"
## Name of the iptables chain (Default is "INPUT")
## Time (in seconds) to keep an IP address blocked (Default is 600)
TIMER=600
## Network device which receives DNS queries
NETDEV="eth0"
## Source port that the queries are coming in on
SPORT=25345
## Offending query string being sent to DNS
QUERY="$SPORT: view net: query: isc.org IN ANY +ED"
if [ ! -f "$BLOCKFILE" ]; then touch $BLOCKFILE ; fi
LAST="-n100"
## Generate a list of IP addresses that have performed the offending query
FILTER=`tail $LAST $LOGFILE | grep "$QUERY" | awk '{ print $6 }' | cut -d\# -f1 | sort | uniq`
now=`date "+%s"`
## Check all IP addresses and block as needed
for IP in $FILTER ; do
if [ "`grep $IP $BLOCKFILE`" == "" ] ; then
COUNT=`tail $LAST $LOGFILE | grep "$QUERY" | grep $IP | wc -l`
if [ $COUNT -ge 10 ] ; then
iptables -A $CHAIN -i $NETDEV -s $IP -p udp --sport $SPORT -j DROP
END=$(($now + $TIMER))
echo "$END $IP" >> $BLOCKFILE
logger -t $NAME Blocked $IP
while read timeout IP ; do
if [ $timeout -lt $now ] ; then
iptables -D $CHAIN -i $NETDEV -s $IP -p udp --sport $SPORT -j DROP 2>/dev/null
sed "/$IP/d" $BLOCKFILE > $TEMPFILE
mv -f $TEMPFILE $BLOCKFILE
logger -t $NAME Removed $IP
LAST="-c+`stat -c%s $LOGFILE`"