#!/usr/bin/perl -w

use strict;

#########################################################################
# Script for monitoring IPSec VPN based on racoon IKE daemon			#
# Author: Pavel Mracek mrak(at)mrak(dot)cz								#
# Version: 0.1															#
#########################################################################

# For easy identification of peers must be added before every 
# remote in racoon.conf  description in the following format:
#
#	#description my_remote_office1
#	remote 85.207.181.237 {
#        	#exchange_mode main,aggressive,base;
#	        exchange_mode main;
#	.....
#

# If it be possible to restart the demon nonprivileged user,
# it is necessary to add the following into /etc/sudoers
#
#	Cmnd_Alias VPNADMIN = /sbin/service, /sbin/ip, /sbin/setkey
#	vpnadmin ALL=(ALL)      NOPASSWD: VPNADMIN 
#
# And of course to define users in the group vpnadmin
#	groupadd vpnadmin
# 	usermod -G user1,vpnadmin user1
#

my $r_cfg='/etc/racoon/racoon.conf';
my $s_cfg='/etc/racoon/setkey.conf';
my $setkey='sudo /sbin/setkey';
my $ip='sudo /sbin/ip';
my $restart_cmd='sudo /sbin/service racoon restart';
# my $racoonctl='sudo /usr/sbin/racoonctl';


#########################################################################
# This file may be distributed under the terms of the GNU General	#
# Public License.							#
#########################################################################

my ($remotes,$idcur,$action);
my ($loop)=1;
$SIG{INT} = sub {$loop = 0; };

sub get_conf($$){
  my ($r_cfg, $s_cfg)=@_;
  my ($desc)=0;
  my ($id)=1;
  my (%remotes);

  open(CFG,"$r_cfg") || die "ERR can't open: $r_cfg $!";
  while(<CFG>){
	if(/^#description\s+([\w\d]+)/){
		$desc=$1;
        }
	if(/^remote\s+(\d+\.\d+\.\d+\.\d+)/){
		$remotes{$id}{'desc'}=$desc;
		$remotes{$id}{'ip'}=$1;
		$desc=0;
		$id++;
		
 	}
  }
  close(CFG);
 return(\%remotes);
}


sub print_menu($){
	my ($remotes)=@_;
	my ($l,$num);
        do{
	  foreach $l (sort keys %$remotes){
		print "$l ) $remotes->{$l}{'desc'} \t\t$remotes->{$l}{'ip'}\n";
	  }
 	  print "R ) Restart racoon daemon\n";
 	  print "Q ) Quit\n";
	  $num=<STDIN>;
        }while($num !~ /^([\d+|Q|q|r|R])/);
	return $1;
}


sub monitor_remote($){
	my ($ip)=@_;
 	my ($parse, $out_head, $out_cur, $out, $spi, $reqid, $req_result, $return);
	open(SA,"$setkey -D|") || die "ERR:  can't execute $setkey -D $!\n";
	$out=''; $out_cur='';
	while(<SA>){
		if(/^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+$/){
			#print ("detekted: $1 a $2");
			if($1 eq $ip){
				$parse=1;
				$out.=$out_cur;	$out_cur='';
				$out_head="\n$1 --> $2";
			}elsif($2 eq $ip){
				$parse=1;
				$out.=$out_cur;	$out_cur='';
				$out_head="\n$2 <-- $1";
			}else{
				$out.=$out_cur;	$out_cur='';
				$parse=0;
			}
		}
		if($parse && /^\s*esp.+spi=(\d+).+reqid=(\d+)/){
			$spi=$1;
			$reqid=$2;
			$req_result=resolve_req($2);
			$out_cur="$out_head \t $req_result\n$out_cur";
		 }
		if($parse && /(diff)(:.*)\(s\)/){$out_cur.="  spi: $spi\t\ttime $1 $2\n"; }
		if($parse && /(current)(:.*)\(bytes\)/){ $out_cur.="  reqid: $reqid\t\t$1 data $2\n"; }
        }
	close(SA);
	$out.=$out_cur;	$out_cur='';
	print "\n\n$out Press Ctrl+C for exit\n";
}

sub resolve_req($){
	my ($req)=@_;
	my ($out)='';
	open(IP,"$ip xfrm policy|") || die "ERR: can't execute $ip xfrm policy $!\n";
	while(<IP>){
		if(/src\s+(\d+\.\d+\.\d+\.\d+\/\d+)\s+dst\s+(\d+\.\d+\.\d+\.\d+\/\d+)/){
			$out="src $1 dst $2";
		}
		if(/reqid (\d+) mode/ && $req eq $1){
			last; 		
		}
        }
	close(IP);
	return $out;

}
################# MAIN ##################

$remotes = get_conf($r_cfg,$s_cfg);



do{
  	$idcur = print_menu($remotes);
	if($idcur =~ /[rR]/){
		print "Restartuji racoon ...\n";
        	system("$restart_cmd");
	}elsif( exists($remotes->{$idcur}) ){ 
		# print statistic 
		while($loop){ 
			monitor_remote($remotes->{$idcur}{'ip'});
			sleep 2;
		}
		$loop=1;
	}
}while($idcur !~ /[qQ]/);


