#!/bin/sh
#############################################################################
## Script de déconexion/reconnexion automatique pour virus de type blaster ##
##                                                                         ##
## Principe :                                                              ##
##      -> détection des attaques grâce aux logs du firewall               ##
##         lecture par *_scan.awk                                          ##
##      -> à partir du nombre d'attaques et de l'heure de dernière attaque ##
##         déconnecte ou reconnecte des machines                           ##
##                                                                         ##
## Frédéric Pauget 02/2003                                                 ##
## 07/2004 adaptation pour scan de plusieurs types d'attaques              ##
#############################################################################

is_up() {
    # Supression de la machine dans la table arp
    /usr/sbin/arp -d $1 2> /dev/null

    # Teste si la machine founie est up
    if fping -c1 $1 > /dev/null 2>&1 ; then
       # Elle a répondu au ping
       return 0
    fi
    if /usr/sbin/arp $1 2>/dev/null | egrep -q '(no entry|incomplete)' ; then
       # Elle n'est pas dans la table ARP
       return 1
    else 
       # Elle est dans la table ARP
       return 0
    fi
}
     

if [[ $1 ]] && [[ $1 = "--real-run" ]]; then
    dry=false
else
    dry=true
fi

BLACKLIST_FINAL='/tmp/virus_blacklist'

# Logs du firewall
FW_LOGS=/var/log/firewall/filtre.log

# Prétraitement logs
tail -7200 $FW_LOGS > /tmp/fw_logs_light

# Fonction utile : retourne l'IP d'une machine
ip() {
   echo $(host $1 2>/dev/null | awk '{print $3}')
}

# Fonction principale
scan() {
# signification des arguments :
# 1 : nombre d'attaques pour être considéré infecté
# 2 : nombre de secondes sans attaques pour être considéré sain
# 3 : script de scan
# 4 : repertoire de stockage fichiers
nb_att=$1
nb_sec=$2
SCRIPT=$3

# Liste des attaques
INFECTES=$4/infectes
# Machines décontaminées
RECO=$4/reconectes

# Machines blacklistées
BLACKLIST=$4/blacklist

# Fichiers temporaires supplémentaires
DIFF=/tmp/virus_diff
TMPFILE=/tmp/virus_scan

# Doit exister, même vides
touch $RECO
touch $BLACKLIST

if ! [[ -e  $INFECTES ]]; then
    dry=true
    echo "dry-run mode forcé (fichier absent)"
    touch $INFECTES
fi

# Test préliminaire
if [[ ! -e $SCRIPT ]] ; then
   echo "Erreur : $SCRIPT non trouvé"
   exit 255
fi

# Conversion blacklist hostname -> IPs
if [[ "$(head -1 $BLACKLIST)" == "komaz" ]]; then
    echo "Ancienne blackliste vide"
    touch $BLACKLIST.ip
else
    echo "Conversion blackliste..."
    for i in $(cat $BLACKLIST | sort | uniq)
    do
        ip $i
    done > $BLACKLIST.ip
fi

echo "Détection des infectés..."
$SCRIPT $BLACKLIST.ip /tmp/fw_logs_light  > $TMPFILE
# sort un fichier du type :
#   Mois Jour Heure hostname nb d'attaques depuis les dernier logrotate

echo "Traitement..."
mv $INFECTES $INFECTES.old
sort -r $TMPFILE > $INFECTES
echo -n "" >  $TMPFILE

# Différencee entre le fichier obtenu la au dernier lancement et le nouveau
diff -U 1000 $INFECTES.old $INFECTES | egrep  -v '\-\-\-|\+\+\+|@@' > $DIFF

if ! [[ -s $DIFF ]]; then
    echo "Aucun changement par rapport au dernier scan."
    cp $INFECTES $DIFF
fi

# Traitement par host
for host in $(awk '{print $4}' $DIFF | sort | uniq)
do
   if grep -q "\+.* $host " $DIFF && grep -q "\-.* $host " $DIFF ; then
      # En + et - : variation
      nb=$(echo $(awk '$4=="'$host'" {print $5}' $INFECTES) - $(awk '$4=="'$host'" {print $5}' $INFECTES.old) | bc)
      echo -ne "Variation ($nb) "
      if grep -q "^$host$" $BLACKLIST ; then 
           # Déja blacklisté, on remet
	   echo -ne "\033[1;31m(RESTE) "
	    echo $host >> $TMPFILE
      elif [[ $nb -gt $nb_att ]] ; then
            # Nouveau
	    echo -ne "\033[1;31m(NOUVEAU) "
	    echo $host >> $TMPFILE
      else
	   # Pas assez de tentatives
	   echo -n "(PASSE) "
      fi

   
   elif grep -q "\+.* $host " $DIFF ; then
      # Que en + donc c'est un nouveau
      nb=$(awk '$4=="'$host'" {print $5}' $INFECTES)
      if [[ $nb -gt $nb_att ]] ; then
          echo -ne "\033[1;31mNOUVEAU ($nb) "
          echo $host >> $TMPFILE
      else 
         echo -ne "PASSE ($nb) "
      fi
      
   elif grep -q "\-.* $host " $DIFF ; then
      # Que en -, c'est un coup de logrotate, on remet les blacklistés.
      if grep -q "^$host$" $BLACKLIST ; then 
	 echo "RESTE : $host"
         echo $host >> $TMPFILE
      else
         echo "Vieux : $host"
      fi
   
   else
      # Pas de variation
      if grep -q "^$host$" $BLACKLIST ; then 
        echo -n "Pas de variation "
        # UP or not ?
        if is_up $host ; then
          # UP
	  last=$(date -d "$(awk '$4=="'$host'" {print $1" "$2" "$3}' $INFECTES)" +%s 2>/dev/null)
	  # Cas ou c'est vraiment trop vieux
	  if [[ -z $last ]] ; then
	     last=0
	  fi
	  now=$(date +%s)
	  t=$(echo "$now-$last" | bc)
	  if [[ $t -gt $nb_sec ]] ; then
	     # Reconexions automatique
	     echo -n " reconnexion"
	     echo $host >> $RECO
	  else
             echo $host >> $TMPFILE
	  fi
	
        else
          # Down
          echo -ne "\033[1;41m(NO_PING)"
	  echo $host >> $TMPFILE
        fi
      
        echo -ne "\033[0m : "
       else 
        echo -n "Reste connecté "
       fi
     fi
   echo -ne "\033[0m"
   awk '$4=="'$host'" {print $1" "$2" "$3" "$4}' $INFECTES
done

# Opérations finales
sort $TMPFILE > $BLACKLIST
}

#######################################################################

# Scan des attaques sur le 135 :
#   10 tentatives pour être considéré infecté
#   1h sans attaque pour être considéré désinfecté
echo -e "\033[1;33m###############################\nScan attaques port 135 ou 6667\033[1;0m"
scan 10 3600 /usr/scripts/analyse_komaz/rpc_scan.awk /var/tmp/rpc

# Scan des floods :
#   100 tentatives pour être considéré infecté
#   1h sans attaque pour être considéré désinfecté
echo -e "\033[1;33m###############################\nScan floods\033[1;0m"
scan 100 3600 /usr/scripts/analyse_komaz/flood_scan.awk /var/tmp/flood

# Constitution de la blackliste finale
cat /var/tmp/rpc/blacklist /var/tmp/flood/blacklist | sort | uniq > $BLACKLIST_FINAL.new

if ! [[ -s $BLACKLIST_FINAL.new ]]; then 
    # Il n'y a personne, il faut au moins une machine sinon squid aime pas.
    echo 'komaz' > $BLACKLIST_FINAL.new
fi

if ! $dry ; then 
    if diff -q $BLACKLIST_FINAL $BLACKLIST_FINAL.new ; then
      echo "Pas de changement dans la blackliste"
    else
      # Synchro blacklist
      /usr/bin/rsync -C -a -e "ssh -i /usr/scripts/analyse_komaz/keys/synchro_virus" $BLACKLIST_FINAL.new root@sila.crans.org:/etc/squid/blacklist_infectes
      # Reload de squid
      /usr/bin/ssh -o StrictHostKeyChecking=no -i /usr/scripts/analyse_komaz/keys/reload_squid root@sila.crans.org squid reload
    fi
else 
    echo "Dry mode : blackliste non copiée sur sila et squid non relancé"
    echo "Utiliser l'option --real-run pour tout faire."
fi

# On ne garde que la dernière version de la blacklist
mv $BLACKLIST_FINAL.new $BLACKLIST_FINAL
