Please note the following code has been deprecated in favor of a more robust [[ddosDotPl|Perl script]]. %%#!/bin/bash ## ddos.sh - Written by Jeff Taylor (Shdwdrgn) ## Updated 2012-03-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. Attempts to run under sudo ## have not always been successful and cannot be guarenteed. ## Destination IP (address of your DNS server)(optional) #DST=10.0.0.211 ## Destination interfaces to monitor (required) DSTDEV=eth0 ## Source interfaces to monitor (optional) #SRCDEV=wan0 ## A string to identify this program's actions in syslog NAME="DNS_Filter" ## Where to store the block file (full path required) BLOCKFILE="/root/ddos.block" ## Where to store the temp file (full path required) TEMPFILE="${BLOCKFILE}.tmp" ## Time (in seconds) to keep an IP address blocked (Default is 225) TIMER=225 ##----- Do not edit beyond this point -----## 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 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" fi if [ $TIMER -lt 1 ]; then TIMER=225; fi origIFS=$IFS dumpCount=50 matches=7 #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" 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 }'" scriptdir=$(pwd) ; scriptname=$(basename $0) ; self="$scriptdir/$scriptname" scriptDate=$( stat -c %Y $self ) while true ; do 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 -nL INPUT | grep "\-s $IP/" ) if [ ! "$marked" ] || [ ! "$rule" ]; then 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 `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 logger -t $NAME \(x$multi\) $IP:$PORT @ $URL #logger -t $NAME -- iptables $addCHAIN $CHAIN --source $IP $SRCDEV -p udp --sport $PORT -j DROP fi fi done ## Check if an IPs timer has expired, and remove the block IFS=$origIFS if [ -f "$BLOCKFILE" ] ; then while read timeout ip PORT multi ; do multi=$( echo $multi | sed 's/\s.*//' ) if [ "${timeout:0:1}" != "#" ]; then IP=${ip#\#} if [ ! "$multi" ]; then multi=1 ; fi if [ $timeout -lt $now ] ; then 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 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 `date \"+(%x %T)\" -d @$END`" >> $BLOCKFILE fi fi fi done < $BLOCKFILE fi sleep 1 ## Check if script has changed if [ $scriptDate != $( stat -c %Y $self ) ]; then logger -t $NAME Restarting $scriptname $self "$@" & exit 0 fi done%%