Curiosity is insubordination in its purest form. -Vladimir Nabokov

sábado, 23 de febrero de 2013

Tonel - basic stats&checks for stunnel

Un script que extrae estadisticas de conexiones POP/IMAP tunelizadas a traves de stunnel.

Este script hace tareas primitivas que siempre se repiten de un script a otro: parseo de logs, control de errores, regexps, etc etc asi que si alguien quiere aportar formas mejores de hacer las cosas... oh wait, perl XD es bienvenido.

Sample output HERE

Happy coding!!
#!/bin/bash
# script to get some useful POP/IMAP stats

TMPLOGFILE=$(mktemp -t stunnel.log-$$.$RANDOM)
TMPIPT_LOGFILE=$(mktemp -t iptables.log-$$.$RANDOM)
cleanup() {
  [ -f $TMPLOGFILE ] && rm $TMPLOGFILE
  [ -f $TMPIPT_LOGFILE ] && rm $TMPIPT_LOGFILE
  trap 0
  exit
}
trap cleanup 0 1 2 3 15

warn () {
  echo -e "$@"
}

die() {
  RC=$1 ; shift
  warn "$@"
  exit $RC
}

BANNER="Tonel ~ Basic stats&checks for stunnel / vlan7"
MY_NAME=${0##*/} #ie: tonel.sh
LOGFILE=/var/log/stunnel.log
#ROOT_UID=0
VERBOSE=0
IPT_PREFIX="POP/IMAP FLOOD"
IPT_LOGFILE=/var/log/iptables.log
BANNED_DBFILE=/proc/net/ipt_recent/BANNED
#FLOODERS_DBFILE=/proc/net/ipt_recent/FLOOD

TODAY=$(date +%u)

if [ $TODAY -eq 1 ]
then
# Today is Monday
  BEGIN_DATE="$(date -dmonday-7days +%Y.%m.%d)"
  END_DATE="$(date -dmonday +%Y.%m.%d)"
  WRITE_END_DATE="$(date -dmonday-1day +%Y.%m.%d)"  #dirty hack

  BEGIN_IPT_DATE="$(date -dmonday-7days +"%b %e")"
  END_IPT_DATE="$(date -dmonday +"%b %e")"
  WRITE_END_IPT_DATE="$(date -dmonday-1day +"%b %e")"  #dirty hack
else
  BEGIN_DATE="$(date -dlast-monday-7days +%Y.%m.%d)"
  END_DATE="$(date -dlast-monday +%Y.%m.%d)"
  WRITE_END_DATE="$(date -dlast-monday-1day +%Y.%m.%d)"  #dirty hack

  BEGIN_IPT_DATE="$(date -dlast-monday-7days +"%b %e")"
  END_IPT_DATE="$(date -dlast-monday +"%b %e")"
  WRITE_END_IPT_DATE="$(date -dlast-monday-1day +"%b %e")"  #dirty hack
fi

# Run as root, of course.
#[ "$UID" -eq "$ROOT_UID" ] || die 1 "Bad luck, only root can run this code!"

echo -e "$BANNER"

# Parse arguments
while getopts "vhHf:d:" opt; do
  case $opt in
    v)
      echo -e "\n[+] -v detected. Ok, let's verbose!"
      VERBOSE=1
      ;;
    h)
      echo -e "\n-v verbose output"
      echo -e "\n-f <logfile> specify your stunnel logfile DEFAULT=$LOGFILE"
      echo -e "\n-d <YYYYMMDD+DAYS> (Up to 9999 days) (DEFAULT=one week ago starting last monday)"
      echo -e "\n-h Welcome to help"
      echo -e "\n-H Help: Long description"
      exit
      ;;
    H)
      echo -e "\nEl script acepta varios switches. Esto es la ayuda larga. La ayuda corta es -h"
      echo -e "\nEsta desarrollado de tal forma que sin ningun parametro, calcula estadisticas de toda la semana anterior a la que nos encontramos. Es totalmente transparente al dia actual, sea lunes, jueves, domingo o cualquier dia."
      echo -e "\nEs decir, si estamos en cualquier dia de la semana del 4 al 10-2-2013, asi calcula estadisticas del 28-1-2013 al 3-2-2013, ambos inclusive:"
      echo -e "\n\tbash $MY_NAME"
      echo -e "\nSi necesitamos especificar rangos seria:"
      echo -e "\n\tbash $MY_NAME -d 20130114+15"
      echo -e "\nAsi calcularia desde 20130114 hasta 20130129, ambos inclusive"
      echo -e "\nSi deseamos especificar el archivo de log de stunnel (por defecto $LOGFILE), el script permite que le pasemos el switch -f seguido del archivo de log deseado."
      echo -e "\nSi deseamos mas nivel de Verbose, podemos pasar al script el parametro -v"
      exit
      ;;
    f)
      echo -e "\n[+] -f detected so logfile is now $OPTARG"
      LOGFILE=$OPTARG
      ;;
    d)
      DATE=${OPTARG:0:8}
      INC_OR_DEC=${OPTARG:8:1}
      DAYS=${OPTARG:9:4}

      # Basic parse of -d argument
      # Valid $DATE basic regexp!
      [[ $DATE =~ ^[1-9][0-9][0-9][0-9](0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01]) ]] || die 2 "ERROR! $DATE date detected. Must be YYYYMMDD format! Exiting now..."
      # $INC_OR_DEC Only + implemented
      [ "$INC_OR_DEC" == "+" ] || die 3 "ERROR! $INC_OR_DEC inc_char detected. Must be +"

      BEGIN_DATE="$(date -d $DATE +%Y.%m.%d)"
      END_DATE="$(date -d $DATE$INC_OR_DEC$[ $DAYS + 1 ]"days" +%Y.%m.%d)"
      WRITE_END_DATE="$(date -d $DATE$INC_OR_DEC$DAYS"days" +%Y.%m.%d)"   #dirty hack

      BEGIN_IPT_DATE="$(date -d $DATE +"%b %e")"
      END_IPT_DATE="$(date -d $DATE$INC_OR_DEC$[ $DAYS + 1 ]"days" +"%b %e")"
      WRITE_END_IPT_DATE="$(date -d $DATE$INC_OR_DEC$DAYS"days" +"%b %e")"  #dirty hack

# DEBUG line-
#     echo "#DATE#$DATE#INC_ORD_DEC#$INC_OR_DEC#DAYS#$DAYS#BEGIN_DATE#$BEGIN_DATE#END_DATE#$END_DATE#WRITE_END_DATE#$WRITE_END_DATE#BEGIN_IPT_DATE#$BEGIN_IPT_DATE#END_IPT_DATE#$END_IPT_DATE#WRITE_END_IPT_DATE#$WRITE_END_IPT_DATE<<EOL"
      echo -e "\n[+] -d detected so date range is now\n\t[from $BEGIN_DATE to $WRITE_END_DATE]"
      ;;
  esac
done

[ -f "$LOGFILE" ] && echo -e "\n[+] Log $LOGFILE starts on $(head -n 1 $LOGFILE |cut -d" " -f1,2)"
[ -f "$IPT_LOGFILE" ] && echo -e "\n[+] Log $IPT_LOGFILE starts on $(head -n 1 $IPT_LOGFILE |awk '{print $1,$2,$3}')"

echo -e "\n\t\t\t[+] [+] Now running some basic checks..."
echo -e "\t\t\t======================================"
echo -e "\n[+] Checking runnin' stunnel processes..."
ps -ef |grep [s]tunnel |grep -v $MY_NAME || die 4 "ERROR! stunnel is NOT running! Exiting now..."
echo -e "\n\t[OK!] Let's continue..."

echo -e "\n[+] Checking stunnel LISTEN sockets..."
##netstat -tnl |grep LISTEN |egrep ':110|:143|:993|:995'
##lsof -iTCP:143 -iTCP:110 -iTCP:993 -iTCP:995
lsof -iTCP:143 |grep LISTEN || die 5 "ERROR! IMAP is NOT listening! Exiting now..."
lsof -iTCP:110 |grep LISTEN || die 6 "ERROR! POP3 is NOT listening! Exiting now..."
lsof -iTCP:993 |grep LISTEN || die 7 "ERROR! IMAPS is NOT listening! Exiting now..."
lsof -iTCP:995 |grep LISTEN || die 8 "ERROR! POP3S is NOT listening! Exiting now..."

echo -e "\n\t[OK!] Let's continue..."

echo -e "\n\t\t\t[+] [+] Now parsing logfile [$LOGFILE] ..."
echo -e "\t\t\t==========================================="
[ -f "$LOGFILE" ] || die 9 "Fatal ERROR! log $LOGFILE NOT found. Exiting now..."

#BUFFER=$(awk '{ if ( $0 > "'"$BEGIN_DATE"'" && $0 < "'"$END_DATE"'" ) print $0 }' $LOGFILE)
#echo "$BUFFER"  # note the "" to respect \n chars

awk '{ if ( $0 > "'"$BEGIN_DATE"'" && $0 < "'"$END_DATE"'" ) print $0 }' $LOGFILE >$TMPLOGFILE
OUTTAGES=$(egrep -oc "Received signal| stunnel " $TMPLOGFILE)
echo -e "\n[+] stunnel outtages [from $BEGIN_DATE to $WRITE_END_DATE]: [$OUTTAGES]"
[ $OUTTAGES -ne 0 ] && [ $VERBOSE -ne 0 ] && echo -e "\t[+] Daemon stops:\n\t\t$(grep "Received signal" $TMPLOGFILE)"
[ $OUTTAGES -ne 0 ] && [ $VERBOSE -ne 0 ] && echo -e "\t[+] Daemon starts:\n\t\t$(grep " stunnel " $TMPLOGFILE)"

core() {
  echo -e "\n[+] Numero conexiones $1 OK / IP origen: [from $BEGIN_DATE to $WRITE_END_DATE]"
  CORE_TOTAL=$(grep -c "$1 connected from" $TMPLOGFILE)
  [ $CORE_TOTAL -ne 0 ] && grep "$1 connected from" $TMPLOGFILE |cut -d" " -f7 |cut -d":" -f1 |sort |uniq -c |sort -rn |sed -e 's/^[ ]*//' |awk '{print NR, $0}' |tr ' ' \\t
  echo -e "\n\t[+] Total conexiones: [$CORE_TOTAL]"
  [ $CORE_TOTAL -ne 0 ] && [ $VERBOSE -ne 0 ] && echo -e "\t[+] Primera conexion:\n\t\t$(grep "$1 connected from" $TMPLOGFILE |head -n 1 |cut -d" " -f1,2,4-7)"
  [ $CORE_TOTAL -ne 0 ] && echo -e "\t[+] Ultima conexion:\n\t\t$(grep "$1 connected from" $TMPLOGFILE |tail -n 1 |cut -d" " -f1,2,4-7)"
}

CONNS_TOTAL=0
core "IMAP" ; CONNS_TOTAL=$(($CONNS_TOTAL+$CORE_TOTAL))
core "POP3" ; CONNS_TOTAL=$(($CONNS_TOTAL+$CORE_TOTAL))
core "IMAPS" ; CONNS_TOTAL=$(($CONNS_TOTAL+$CORE_TOTAL))
core "POP3S" ; CONNS_TOTAL=$(($CONNS_TOTAL+$CORE_TOTAL))
echo -e "\n[+] Total conexiones (IMAP && POP3 && IMAPS && POP3S): [$CONNS_TOTAL]"

echo -e "\n\t\t\t[+] [+] Now checking bad guys..."
echo -e "\t\t\t===================================="

# Code below relays on Wietse's TCP-Wrappers
echo -e "\n[+] NO autorizados: Conexiones rechazadas / IP origen [from $BEGIN_DATE to $WRITE_END_DATE]"
REFUSED_TOTAL=$(grep -c "REFUSED" $TMPLOGFILE)
[ $REFUSED_TOTAL -ne 0 ] && grep REFUSED $TMPLOGFILE |cut -d" " -f6 |cut -d":" -f1 |sort |uniq -c |sort -rn |sed -e 's/^[ ]*//' |awk '{print NR, $0}' |tr ' ' \\t
echo -e "\n\t[+] Total conexiones rechazadas (NO autorizados): [$REFUSED_TOTAL]\n"

# Code below relays on some anti-DoS custom iptables rules
echo -e "\n[+] POP/IMAP FLOODERS: Conexiones rechazadas / IP origen [from $BEGIN_IPT_DATE to $WRITE_END_IPT_DATE]"
[ -f $IPT_LOGFILE ] || warn "[!] WARNING! $IPT_LOGFILE NOT found! Skipping this test and continuing anyway..."
[ -f $IPT_LOGFILE ] && awk '{ if ( $0 > "'"$BEGIN_IPT_DATE"'" && $0 < "'"$END_IPT_DATE"'" ) print $0 }' $IPT_LOGFILE >$TMPIPT_LOGFILE
[ -f $IPT_LOGFILE ] && FLOODERS_TOTAL=$(grep -c "$IPT_PREFIX" $TMPIPT_LOGFILE)
[ -f $IPT_LOGFILE ] && [ $FLOODERS_TOTAL -ne 0 ] && grep "$IPT_PREFIX" $TMPIPT_LOGFILE |grep -Eo "SRC=[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" |cut -d= -f2 |sort |uniq -c |sort -rn |sed -e 's/^[ ]*//' |awk '{print NR, $0}' |tr ' ' \\t
echo -e "\n\t[+] Total conexiones rechazadas (FLOODERS): [$FLOODERS_TOTAL]\n"

echo -e "\n[+] FLOODERS actualmente BANEADOS [dbfile $BANNED_DBFILE]"
[ -f $BANNED_DBFILE ] || warn "[!] WARNING! $BANNED_DBFILE NOT found! Skipping this test and continuing anyway..."
[ -f $BANNED_DBFILE ] && BANNED_TOTAL=$(cat $BANNED_DBFILE |wc -l)
[ -f $BANNED_DBFILE ] && [ $BANNED_TOTAL -ne 0 ] && cut -d" " -f1 $BANNED_DBFILE |cut -d= -f2
echo -e "\n\t[+] Total IPs actualmente BANEADAS: [$BANNED_TOTAL]\n"

PATH_TO_ME=${0}
FULL_ARGS=${@}
echo -e "\nLast run on $(hostname) at $(date) with\n$PATH_TO_ME $FULL_ARGS\nNow exiting - Have a nice day...\n"
[ $VERBOSE -eq 0 ] && echo -e "Do you wanna verbose output? just rerun me with -v switch!\n"

exit 0

Related Posts by Categories



0 comentarios :