1*bc4097aaSchristos#!/usr/local/bin/perl 2*bc4097aaSchristos# (C) Copyright 1998 Ivan S. Bishop (isb@notoryus.genmagic.com) 3*bc4097aaSchristos# 4*bc4097aaSchristos############### START SUBROUTINE DECLARATIONS ########### 5*bc4097aaSchristos 6*bc4097aaSchristos 7*bc4097aaSchristossub usage { 8*bc4097aaSchristos print "\n" x 24; 9*bc4097aaSchristos print "USAGE: ipfanalyze.pl -h [-p port# or all] [-g] [-s] [-v] [-o] portnum -t [target ip address] [-f] logfilename\n"; 10*bc4097aaSchristos print "\n arguments to -p -f -o REQUIRED\n"; 11*bc4097aaSchristos print "\n -h show this help\n"; 12*bc4097aaSchristos print "\n -p limit stats/study to this port number.(eg 25 not smtp)\n"; 13*bc4097aaSchristos print " -g make graphs, one per 4 hour interval called outN.gif 1<=N<=5\n"; 14*bc4097aaSchristos print " -s make security report only (no graphical or full port info generated) \n"; 15*bc4097aaSchristos print " -o lowest port number incoming traffic can talk to and be regarded as safe\n"; 16*bc4097aaSchristos print " -v verbose report with graphs and textual AND SECURITY REPORTS with -o 1024 set\n"; 17*bc4097aaSchristos print " -t the ip address of the inerface on which you collected data!\n"; 18*bc4097aaSchristos print " -f name ipfilter log file (compatible with V 3.2.9) [ipfilter.log]\n"; 19*bc4097aaSchristos print " \nExample: ./ipfanalyze.pl -p all -g -f log1\n"; 20*bc4097aaSchristos print "Will look at traffic to/from all ports and make graphs from file log1\n"; 21*bc4097aaSchristos print " \nExample2 ./ipfanalyze.pl -p 25 -g -f log2\n"; 22*bc4097aaSchristos print "Will look at SMTP traffic and make graphs from file log2\n"; 23*bc4097aaSchristos print " \nExample3 ./ipfanalyze.pl -p all -g -f log3 -o 1024\n"; 24*bc4097aaSchristos print "Will look at all traffic,make graphs from file log3 and log security info for anthing talking inwards below port 1024\n"; 25*bc4097aaSchristos print " \nExample4 ./ipfanalyze.pl -p all -f log3 -v \n"; 26*bc4097aaSchristos print "Report the works.....when ports below 1024 are contacted highlight (like -s -o 1024)\n"; 27*bc4097aaSchristos} 28*bc4097aaSchristos 29*bc4097aaSchristos 30*bc4097aaSchristos 31*bc4097aaSchristos 32*bc4097aaSchristossub makegifs { 33*bc4097aaSchristoslocal ($maxin,$maxout,$lookat,$xmax)=@_; 34*bc4097aaSchristos$YMAX=$maxin; 35*bc4097aaSchristos$XMAX=$xmax; 36*bc4097aaSchristos 37*bc4097aaSchristosif ($maxout > $maxin) 38*bc4097aaSchristos { $YMAX=$maxout;} 39*bc4097aaSchristos 40*bc4097aaSchristos($dateis,$junk)=split " " , @recs[0]; 41*bc4097aaSchristos($dayis,$monthis,$yearis)=split "/",$dateis; 42*bc4097aaSchristos$month=$months{$monthis}; 43*bc4097aaSchristos$dateis="$dayis " . "$month " . "$yearis "; 44*bc4097aaSchristos# split graphs in to 6 four hour spans for 24 hours 45*bc4097aaSchristos$numgraphs=int($XMAX/240); 46*bc4097aaSchristos 47*bc4097aaSchristos$junk=0; 48*bc4097aaSchristos$junk=$XMAX - 240*($numgraphs); 49*bc4097aaSchristosif($junk gt 0 ) 50*bc4097aaSchristos{ 51*bc4097aaSchristos$numgraphs++; 52*bc4097aaSchristos} 53*bc4097aaSchristos 54*bc4097aaSchristos$cnt1=0; 55*bc4097aaSchristos$end=0; 56*bc4097aaSchristos$loop=0; 57*bc4097aaSchristos 58*bc4097aaSchristoswhile ($cnt1++ < $numgraphs) 59*bc4097aaSchristos{ 60*bc4097aaSchristos $filename1="in$cnt1.dat"; 61*bc4097aaSchristos $filename2="out$cnt1.dat"; 62*bc4097aaSchristos $filename3="graph$cnt1.conf"; 63*bc4097aaSchristos open(OUTDATA,"> $filename2") || die "Couldnt open $filename2 for writing \n"; 64*bc4097aaSchristos open(INDATA,"> $filename1") || die "Couldnt open $filename1 for writing \n"; 65*bc4097aaSchristos 66*bc4097aaSchristos $loop=$end; 67*bc4097aaSchristos $end=($end + 240); 68*bc4097aaSchristos 69*bc4097aaSchristos# write all files as x time coord from 1 to 240 minutes 70*bc4097aaSchristos# set hour in graph via conf file 71*bc4097aaSchristos $arraycnt=0; 72*bc4097aaSchristos while ($loop++ < $end ) 73*bc4097aaSchristos { 74*bc4097aaSchristos $arraycnt++; 75*bc4097aaSchristos $val1=""; 76*bc4097aaSchristos $val2=""; 77*bc4097aaSchristos $val1=$inwards[$loop] [1]; 78*bc4097aaSchristos if($val1 eq "") 79*bc4097aaSchristos {$val1=0}; 80*bc4097aaSchristos $val2=$outwards[$loop] [1]; 81*bc4097aaSchristos if($val2 eq "") 82*bc4097aaSchristos {$val2=0}; 83*bc4097aaSchristos print INDATA "$arraycnt:$val1\n"; 84*bc4097aaSchristos print OUTDATA "$arraycnt:$val2\n"; 85*bc4097aaSchristos } 86*bc4097aaSchristos close INDATA; 87*bc4097aaSchristos close OUTDATA; 88*bc4097aaSchristos $gnum=($cnt1 - 1); 89*bc4097aaSchristos open(INCONFIG,"> $filename3") || die "Couldnt open ./graph.conf for writing \n"; 90*bc4097aaSchristos print INCONFIG "NUMBERYCELLGRIDSIZE:5\n"; 91*bc4097aaSchristos print INCONFIG "MAXYVALUE:$YMAX\n"; 92*bc4097aaSchristos print INCONFIG "MINYVALUE:0\n"; 93*bc4097aaSchristos print INCONFIG "XCELLGRIDSIZE:1.3\n"; 94*bc4097aaSchristos print INCONFIG "XMAX: 240\n"; 95*bc4097aaSchristos print INCONFIG "Bar:0\n"; 96*bc4097aaSchristos print INCONFIG "Average:0\n"; 97*bc4097aaSchristos print INCONFIG "Graphnum:$gnum\n"; 98*bc4097aaSchristos print INCONFIG "Title: port $lookat packets/minute to/from gatekeep on $dateis \n"; 99*bc4097aaSchristos print INCONFIG "Transparent:no\n"; 100*bc4097aaSchristos print INCONFIG "Rbgcolour:0\n"; 101*bc4097aaSchristos print INCONFIG "Gbgcolour:255\n"; 102*bc4097aaSchristos print INCONFIG "Bbgcolour:255\n"; 103*bc4097aaSchristos print INCONFIG "Rfgcolour:0\n"; 104*bc4097aaSchristos print INCONFIG "Gfgcolour:0\n"; 105*bc4097aaSchristos print INCONFIG "Bfgcolour:0\n"; 106*bc4097aaSchristos print INCONFIG "Rcolour:0\n"; 107*bc4097aaSchristos print INCONFIG "Gcolour:0\n"; 108*bc4097aaSchristos print INCONFIG "Bcolour:255\n"; 109*bc4097aaSchristos print INCONFIG "Racolour:255\n"; 110*bc4097aaSchristos print INCONFIG "Gacolour:255\n"; 111*bc4097aaSchristos print INCONFIG "Bacolour:0\n"; 112*bc4097aaSchristos print INCONFIG "Rincolour:100\n"; 113*bc4097aaSchristos print INCONFIG "Gincolour:100\n"; 114*bc4097aaSchristos print INCONFIG "Bincolour:60\n"; 115*bc4097aaSchristos print INCONFIG "Routcolour:60\n"; 116*bc4097aaSchristos print INCONFIG "Goutcolour:100\n"; 117*bc4097aaSchristos print INCONFIG "Boutcolour:100\n"; 118*bc4097aaSchristos close INCONFIG; 119*bc4097aaSchristos 120*bc4097aaSchristos} 121*bc4097aaSchristos 122*bc4097aaSchristos 123*bc4097aaSchristos$cnt1=0; 124*bc4097aaSchristoswhile ($cnt1++ < $numgraphs) 125*bc4097aaSchristos{ 126*bc4097aaSchristos $filename1="in$cnt1.dat"; 127*bc4097aaSchristos $out="out$cnt1.gif"; 128*bc4097aaSchristos $filename2="out$cnt1.dat"; 129*bc4097aaSchristos $filename3="graph$cnt1.conf"; 130*bc4097aaSchristos system( "cp ./$filename1 ./in.dat; 131*bc4097aaSchristos cp ./$filename2 ./out.dat; 132*bc4097aaSchristos cp ./$filename3 ./graph.conf"); 133*bc4097aaSchristos system( "./isbgraph -conf graph.conf;mv graphmaker.gif $out"); 134*bc4097aaSchristos system(" cp $out /isb/local/etc/httpd/htdocs/."); 135*bc4097aaSchristos 136*bc4097aaSchristos} 137*bc4097aaSchristos 138*bc4097aaSchristos} # end of subroutine make gifs 139*bc4097aaSchristos 140*bc4097aaSchristos 141*bc4097aaSchristos 142*bc4097aaSchristos 143*bc4097aaSchristossub packbytime { 144*bc4097aaSchristoslocal ($xmax)=@_; 145*bc4097aaSchristos$XMAX=$xmax; 146*bc4097aaSchristos# pass in the dest port number or get graph for all packets 147*bc4097aaSchristos# at 1 minute intervals 148*bc4097aaSchristos# @shortrecs has form 209.24.1.217 123 192.216.16.2 123 udp len 20 76 149*bc4097aaSchristos# @recs has form 27/07/1998 00:01:05.216596 le0 @0:2 L 192.216.21.16,2733 -> 192.216.16.2,53 PR udp len 20 62 150*bc4097aaSchristos# 151*bc4097aaSchristos# dont uses hashes to store how many packets per minite as they 152*bc4097aaSchristos# return random x coordinate order 153*bc4097aaSchristos@inwards=(); 154*bc4097aaSchristos@outwards=(); 155*bc4097aaSchristos$cnt=-1; 156*bc4097aaSchristos$value5=0; 157*bc4097aaSchristos$maxin=0; 158*bc4097aaSchristos$maxout=0; 159*bc4097aaSchristos$xpos=0; 160*bc4097aaSchristoswhile ($cnt++ <= $#recs ) 161*bc4097aaSchristos { 162*bc4097aaSchristos ($srcip,$srcport,$destip,$destport,$pro)= split " " , @shortrecs[$cnt]; 163*bc4097aaSchristos $bit=substr(@recs[$cnt],11); 164*bc4097aaSchristos ($bit,$junkit)= split " " , $bit ; 165*bc4097aaSchristos ($hour,$minute,$sec,$junk) = split ":", $bit; 166*bc4097aaSchristos# 167*bc4097aaSchristos# covert the time to decimal minutes and bucket to nearest minute 168*bc4097aaSchristos# 169*bc4097aaSchristos $xpos=($hour * 3600) + ($minute * 60) + ($sec) ; 170*bc4097aaSchristos# xpos is number of seconds since 00:00:00 on day...... 171*bc4097aaSchristos $xpos=int($xpos / 60); 172*bc4097aaSchristos# if we just want to see all packet in/out activity 173*bc4097aaSchristos if("$lookat" eq "all") 174*bc4097aaSchristos { 175*bc4097aaSchristos if("$destip" eq "$gatekeep") 176*bc4097aaSchristos { 177*bc4097aaSchristos# TO GATEKEEP port lookat 178*bc4097aaSchristos# print "to gatekeep at $xpos\n"; 179*bc4097aaSchristos $value5=$inwards[$xpos] [1]; 180*bc4097aaSchristos $value5++ ; 181*bc4097aaSchristos# $maxin = $value5 if $maxin < $value5 ; 182*bc4097aaSchristos 183*bc4097aaSchristos if($value5 > $maxin) 184*bc4097aaSchristos { 185*bc4097aaSchristos $maxin=$value5; 186*bc4097aaSchristos $timemaxin="$hour:$minute"; 187*bc4097aaSchristos } 188*bc4097aaSchristos $inwards[$xpos][1]=$value5; 189*bc4097aaSchristos } 190*bc4097aaSchristos else 191*bc4097aaSchristos { 192*bc4097aaSchristos# FROM GATEKEEP to port lookat 193*bc4097aaSchristos# print "from gatekeep at $xpos\n"; 194*bc4097aaSchristos $value4=$outwards[$xpos] [1]; 195*bc4097aaSchristos $value4++ ; 196*bc4097aaSchristos# $maxout = $value4 if $maxout < $value4 ; 197*bc4097aaSchristos if($value4 > $maxout) 198*bc4097aaSchristos { 199*bc4097aaSchristos $maxout=$value4; 200*bc4097aaSchristos $timemaxout="$hour:$minute"; 201*bc4097aaSchristos } 202*bc4097aaSchristos 203*bc4097aaSchristos $outwards[$xpos][1]=$value4; 204*bc4097aaSchristos } 205*bc4097aaSchristos } 206*bc4097aaSchristos 207*bc4097aaSchristos 208*bc4097aaSchristos 209*bc4097aaSchristos 210*bc4097aaSchristos if("$destport" eq "$lookat") 211*bc4097aaSchristos { 212*bc4097aaSchristos if("$destip" eq "$gatekeep") 213*bc4097aaSchristos { 214*bc4097aaSchristos# TO GATEKEEP port lookat 215*bc4097aaSchristos# print "to gatekeep at $xpos\n"; 216*bc4097aaSchristos $value5=$inwards[$xpos] [1]; 217*bc4097aaSchristos $value5++ ; 218*bc4097aaSchristos $maxin = $value5 if $maxin < $value5 ; 219*bc4097aaSchristos $inwards[$xpos][1]=$value5; 220*bc4097aaSchristos } 221*bc4097aaSchristos else 222*bc4097aaSchristos { 223*bc4097aaSchristos# FROM GATEKEEP to port lookat 224*bc4097aaSchristos# print "from gatekeep at $xpos\n"; 225*bc4097aaSchristos $value4=$outwards[$xpos] [1]; 226*bc4097aaSchristos $value4++ ; 227*bc4097aaSchristos $maxout = $value4 if $maxout < $value4 ; 228*bc4097aaSchristos $outwards[$xpos][1]=$value4; 229*bc4097aaSchristos } 230*bc4097aaSchristos } 231*bc4097aaSchristos } # end while 232*bc4097aaSchristos 233*bc4097aaSchristos# now call gif making stuff 234*bc4097aaSchristosif("$opt_g" eq "1") 235*bc4097aaSchristos{ 236*bc4097aaSchristos print "Making plots of in files outN.gif\n";; 237*bc4097aaSchristos makegifs($maxin,$maxout,$lookat,$#inwards); 238*bc4097aaSchristos} 239*bc4097aaSchristosif ("$timemaxin" ne "") 240*bc4097aaSchristos{print "\nTime of peak packets/minute in was $timemaxin\n";} 241*bc4097aaSchristosif ("$timemaxout" ne "") 242*bc4097aaSchristos{print "\nTime of peak packets/minute OUT was $timemaxout\n";} 243*bc4097aaSchristos 244*bc4097aaSchristos} # end of subroutine packets by time 245*bc4097aaSchristos 246*bc4097aaSchristos 247*bc4097aaSchristos 248*bc4097aaSchristos 249*bc4097aaSchristos 250*bc4097aaSchristossub posbadones { 251*bc4097aaSchristos 252*bc4097aaSchristos$safenam=""; 253*bc4097aaSchristos@dummy=$saferports; 254*bc4097aaSchristosforeach $it (split " ",$saferports) { 255*bc4097aaSchristosif ($it eq "icmp" ) 256*bc4097aaSchristos { 257*bc4097aaSchristos $safenam = $safenam . " icmp"; 258*bc4097aaSchristos } 259*bc4097aaSchristoselse 260*bc4097aaSchristos { 261*bc4097aaSchristos $safenam = $safenam . " $services{$it}" ; 262*bc4097aaSchristos } 263*bc4097aaSchristos 264*bc4097aaSchristos} 265*bc4097aaSchristosprint "\n\n########################################################################\n"; 266*bc4097aaSchristosprint "well known ports are 0->1023\n"; 267*bc4097aaSchristosprint "Registered ports are 1024->49151\n"; 268*bc4097aaSchristosprint "Dynamic/Private ports are 49152->65535\n\n"; 269*bc4097aaSchristosprint "Sites that contacted gatekeep on 'less safe' ports (<$ITRUSTABOVE)\n"; 270*bc4097aaSchristos 271*bc4097aaSchristosprint " 'safe' ports are $safenam \n"; 272*bc4097aaSchristosprint "\n variables saferports and safehosts hardwire what/who we trust\n"; 273*bc4097aaSchristosprint "########################################################################\n"; 274*bc4097aaSchristos 275*bc4097aaSchristos$loop=-1; 276*bc4097aaSchristoswhile ($loop++ <= $#recs ) 277*bc4097aaSchristos { 278*bc4097aaSchristos ($srcip,$srcport,$destip,$destport,$pro)= split " " , @shortrecs[$loop]; 279*bc4097aaSchristos if ("$destip" eq "$gatekeep") 280*bc4097aaSchristos { 281*bc4097aaSchristos if ($destport < $ITRUSTABOVE ) 282*bc4097aaSchristos { 283*bc4097aaSchristos# if index not found (ie < 0) then we have a low port attach to gatekeep 284*bc4097aaSchristos# that is not to a safer port (see top of this file) 285*bc4097aaSchristos# ie no ports 25 (smtp), 53 (dns) , 113 (ident), 123 (ntp), icmp 286*bc4097aaSchristos $where=index($saferports,$destport); 287*bc4097aaSchristos if ($where < 0) 288*bc4097aaSchristos { 289*bc4097aaSchristos $nameis=$services{$destport}; 290*bc4097aaSchristos if ("$nameis" eq "" ) 291*bc4097aaSchristos { 292*bc4097aaSchristos $nameis=$destport; 293*bc4097aaSchristos } 294*bc4097aaSchristos print " Warning: $srcip contacted gatekeep $nameis\n"; 295*bc4097aaSchristos } 296*bc4097aaSchristos } 297*bc4097aaSchristos } 298*bc4097aaSchristos } 299*bc4097aaSchristosprint "\n\n"; 300*bc4097aaSchristos} # end of subroutine posbadones 301*bc4097aaSchristos 302*bc4097aaSchristos 303*bc4097aaSchristos 304*bc4097aaSchristos 305*bc4097aaSchristossub toobusy_site { 306*bc4097aaSchristos$percsafe=1; 307*bc4097aaSchristosprint "\n\n########################################################################\n"; 308*bc4097aaSchristosprint "# Sites sending > $percsafe % of all packets to gatekeep MAY be attacking/probing\n"; 309*bc4097aaSchristosprint "Trusted hosts are $safehosts\n"; 310*bc4097aaSchristosprint "\nTOTAL packets were $#recs \n"; 311*bc4097aaSchristosprint "########################################################################\n"; 312*bc4097aaSchristoswhile(($ipadd,$numpacketsent)=each %numpacks) 313*bc4097aaSchristos{ 314*bc4097aaSchristos$perc=$numpacketsent/$#recs*100; 315*bc4097aaSchristosif ($perc > $percsafe) 316*bc4097aaSchristos# dont believe safehosts are attacking! 317*bc4097aaSchristos { 318*bc4097aaSchristos $where=index($safehosts,$ipadd); 319*bc4097aaSchristos# if not found (ie < 0 then the source host IP address 320*bc4097aaSchristos# isn't in the saferhosts list, a list we trust...... 321*bc4097aaSchristos if ($where < 0 ) 322*bc4097aaSchristos { 323*bc4097aaSchristos printf "$ipadd sent %4.1f (\045) of all packets to gatekeep\n",$perc; 324*bc4097aaSchristos } 325*bc4097aaSchristos } 326*bc4097aaSchristos} 327*bc4097aaSchristos 328*bc4097aaSchristosprint "\n\n"; 329*bc4097aaSchristos} # end of subroutine toobusy_site 330*bc4097aaSchristos 331*bc4097aaSchristos 332*bc4097aaSchristos############### END SUBROUTINE DECLARATIONS ########### 333*bc4097aaSchristos 334*bc4097aaSchristosuse Getopt::Std; 335*bc4097aaSchristos 336*bc4097aaSchristosgetopt('pfot'); 337*bc4097aaSchristos 338*bc4097aaSchristosif("$opt_t" eq "0") 339*bc4097aaSchristos {usage;print "\n---->ERROR: You must psecify the IP address of the interface that collected the data!\n"; 340*bc4097aaSchristosexit; 341*bc4097aaSchristos} 342*bc4097aaSchristos 343*bc4097aaSchristosif("$opt_h" eq "1") 344*bc4097aaSchristos {usage;exit 0}; 345*bc4097aaSchristosif("$opt_H" eq "1") 346*bc4097aaSchristos {usage;exit 0}; 347*bc4097aaSchristos 348*bc4097aaSchristosif("$opt_v" eq "1") 349*bc4097aaSchristos{ 350*bc4097aaSchristos$ITRUSTABOVE=1024; 351*bc4097aaSchristos$opt_s=1; 352*bc4097aaSchristos$opt_o=$ITRUSTABOVE; 353*bc4097aaSchristosprint "\n" x 5; 354*bc4097aaSchristosprint "NOTE: when the final section of the verbose report is generated\n"; 355*bc4097aaSchristosprint " every host IP address that contacted $gatekeep has \n"; 356*bc4097aaSchristosprint " a tally of how many times packets from a particular port on that host\n"; 357*bc4097aaSchristosprint " reached $gatekeep, and WHICH source port or source portname \n"; 358*bc4097aaSchristosprint " these packets originated from.\n"; 359*bc4097aaSchristosprint " Many non RFC obeying boxes do not use high ports and respond to requests from\n"; 360*bc4097aaSchristosprint " $gatekeep using reserved low ports... hence you'll see things like\n"; 361*bc4097aaSchristosprint " #### with 207.50.191.60 as the the source for packets ####\n"; 362*bc4097aaSchristosprint " 1 connections from topx to gatekeep\n\n\n\n"; 363*bc4097aaSchristos 364*bc4097aaSchristos} 365*bc4097aaSchristos 366*bc4097aaSchristosif("$opt_o" eq "") 367*bc4097aaSchristos {usage;print "\n---->ERROR: Must specify lowest safe port name for incoming trafic\n";exit 0} 368*bc4097aaSchristoselse 369*bc4097aaSchristos{ 370*bc4097aaSchristos$ITRUSTABOVE=$opt_o;$opt_s=1;} 371*bc4097aaSchristos 372*bc4097aaSchristosif("$opt_f" eq "") 373*bc4097aaSchristos {usage;print "\n---->ERROR: Must specify filename with -f \n";exit 0}; 374*bc4097aaSchristos$FILENAME=$opt_f; 375*bc4097aaSchristos 376*bc4097aaSchristosif("$opt_p" eq "") 377*bc4097aaSchristos {usage;print "\n---->ERROR: Must specify port number or 'all' with -p \n";exit 0}; 378*bc4097aaSchristos 379*bc4097aaSchristos# -p arg must be all or AN INTEGER in range 1<=N<=64K 380*bc4097aaSchristosif ("$opt_p" ne "all") 381*bc4097aaSchristos { 382*bc4097aaSchristos $_=$opt_p; 383*bc4097aaSchristos unless (/^[+-]?\d+$/) 384*bc4097aaSchristos { 385*bc4097aaSchristos usage; 386*bc4097aaSchristos print "\n---->ERROR: Must specify port number (1-64K) or 'all' with -p \n"; 387*bc4097aaSchristos exit 0; 388*bc4097aaSchristos } 389*bc4097aaSchristos } 390*bc4097aaSchristos 391*bc4097aaSchristos 392*bc4097aaSchristos# if we get here then the port option is either 'all' or an integer... 393*bc4097aaSchristos# good enough..... 394*bc4097aaSchristos$lookat=$opt_p; 395*bc4097aaSchristos 396*bc4097aaSchristos# -o arg must be all or AN INTEGER in range 1<=N<=64K 397*bc4097aaSchristos $_=$opt_o; 398*bc4097aaSchristos unless (/^[+-]?\d+$/) 399*bc4097aaSchristos { 400*bc4097aaSchristos usage; 401*bc4097aaSchristos print "\n---->ERROR: Must specify port number (1-64K) with -o \n"; 402*bc4097aaSchristos exit 0; 403*bc4097aaSchristos } 404*bc4097aaSchristos 405*bc4097aaSchristos 406*bc4097aaSchristos#--------------------------------------------------------------------- 407*bc4097aaSchristos 408*bc4097aaSchristos 409*bc4097aaSchristos%danger=(); 410*bc4097aaSchristos%numpacks=(); 411*bc4097aaSchristos 412*bc4097aaSchristos$saferports="25 53 113 123 icmp"; 413*bc4097aaSchristos$gatekeep="192.216.16.2"; 414*bc4097aaSchristos#genmagic is 192.216.25.254 415*bc4097aaSchristos$safehosts="$gatekeep 192.216.25.254"; 416*bc4097aaSchristos 417*bc4097aaSchristos 418*bc4097aaSchristos 419*bc4097aaSchristos# load hash with service numbers versus names 420*bc4097aaSchristos 421*bc4097aaSchristos# hash called $services 422*bc4097aaSchristosprint "Creating hash of service names / numbers \n"; 423*bc4097aaSchristos$SERV="./services"; 424*bc4097aaSchristosopen (INFILE, $SERV) || die "Cant open $SERV: $!n"; 425*bc4097aaSchristoswhile(<INFILE>) 426*bc4097aaSchristos{ 427*bc4097aaSchristos ($servnum,$servname,$junk)=split(/ /,$_); 428*bc4097aaSchristos# chop off null trailing..... 429*bc4097aaSchristos $servname =~ s/\n$//; 430*bc4097aaSchristos $services{$servnum}=$servname; 431*bc4097aaSchristos} 432*bc4097aaSchristosprint "Create hash of month numbers as month names\n"; 433*bc4097aaSchristos%months=("01","January","02","February","03","March","04","April","05","May","06","June","07","July","08","August","09","September","10","October","11","November","12","December"); 434*bc4097aaSchristos 435*bc4097aaSchristosprint "Reading log file into an array\n"; 436*bc4097aaSchristos#$FILENAME="./ipfilter.log"; 437*bc4097aaSchristosopen (REC, $FILENAME) || die "Cant open $FILENAME: \n"; 438*bc4097aaSchristos($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$junk)=stat REC; 439*bc4097aaSchristosprint "Log file $FILENAME is $size bytes in size\n"; 440*bc4097aaSchristos#each record is an element of array rec[] now 441*bc4097aaSchristoswhile(<REC>) 442*bc4097aaSchristos { 443*bc4097aaSchristos @recs[$numrec++]=$_; 444*bc4097aaSchristos } 445*bc4097aaSchristos 446*bc4097aaSchristos 447*bc4097aaSchristos# get list of UNIQUE source IP addresses now, records look like 448*bc4097aaSchristos# 192.216.25.254,62910 -> 192.216.16.2,113 PR tcp len 20 40 -R 449*bc4097aaSchristos# this is slow on big log files, about 1minute for every 2.5M log file 450*bc4097aaSchristosprint "Making list of unique source IP addresses (1minute for every 2M log parsed)\n"; 451*bc4097aaSchristos$loop=-1; 452*bc4097aaSchristos$where=-1; 453*bc4097aaSchristoswhile ($loop++ < $#recs ) 454*bc4097aaSchristos { 455*bc4097aaSchristos# get the LHS = source IP address, need fiddle as icmp rcords are logged oddly 456*bc4097aaSchristos $bit=substr(@recs[$loop],39); 457*bc4097aaSchristos $bit =~ s/,/ /g; 458*bc4097aaSchristos ($sourceip,$junkit)= split " " , $bit ; 459*bc4097aaSchristos 460*bc4097aaSchristos# NOTE the . is the string concat command NOT + .......!!!! 461*bc4097aaSchristos 462*bc4097aaSchristos $sourceip =~ split " ", $sourceip; 463*bc4097aaSchristos $where=index($allips,$sourceip); 464*bc4097aaSchristos# if not found (ie < 0, add it) 465*bc4097aaSchristos if ($where < 0 ) 466*bc4097aaSchristos { 467*bc4097aaSchristos $allips = $allips . "$sourceip " ; 468*bc4097aaSchristos } 469*bc4097aaSchristos } 470*bc4097aaSchristos 471*bc4097aaSchristosprint "Put all unique ip addresses into a 1D array\n"; 472*bc4097aaSchristos@allips=split " ", $allips; 473*bc4097aaSchristos 474*bc4097aaSchristos#set loop back to -1 as first array element in recs is element 0 NOT 1 !! 475*bc4097aaSchristosprint "Making compact array of logged entries\n"; 476*bc4097aaSchristos$loop=-1; 477*bc4097aaSchristos$icmp=" icmp "; 478*bc4097aaSchristos$ptr=" -> "; 479*bc4097aaSchristos$lenst=" len "; 480*bc4097aaSchristos$numpackets=0; 481*bc4097aaSchristos 482*bc4097aaSchristoswhile ($loop++ < $#recs ) 483*bc4097aaSchristos { 484*bc4097aaSchristos# this prints from 39 char to EOR 485*bc4097aaSchristos $a=substr(@recs[$loop],39); 486*bc4097aaSchristos ($srcip,$dummy,$destip,$dummy2,$dummy3,$dummy4,$lenicmp)= split " " , $a ; 487*bc4097aaSchristos# need to rewrite icmp ping records.... they dont have service numbers 488*bc4097aaSchristos $whereicmp=index($a,"PR icmp"); 489*bc4097aaSchristos if($whereicmp > 0 ) 490*bc4097aaSchristos { 491*bc4097aaSchristos $a = $srcip . $icmp . $ptr . $destip . $icmp . $icmp . $lenst . $lenicmp ; 492*bc4097aaSchristos } 493*bc4097aaSchristos 494*bc4097aaSchristos# dump the "->" and commas from logging 495*bc4097aaSchristos $a =~ s/->//g; 496*bc4097aaSchristos $a =~ s/PR//g; 497*bc4097aaSchristos $a =~ s/,/ /g; 498*bc4097aaSchristos# shortrec has records that look like 499*bc4097aaSchristos# 209.24.1.217 123 192.216.16.2 123 udp len 20 76 500*bc4097aaSchristos @shortrecs[$loop]= "$a"; 501*bc4097aaSchristos 502*bc4097aaSchristos# count number packets from each IP address into hash 503*bc4097aaSchristos ($srcip,$junk) = split " ","$a"; 504*bc4097aaSchristos $numpackets=$numpacks{"$srcip"}; 505*bc4097aaSchristos $numpackets++ ; 506*bc4097aaSchristos $numpacks{"$srcip"}=$numpackets; 507*bc4097aaSchristos 508*bc4097aaSchristos} 509*bc4097aaSchristos 510*bc4097aaSchristos 511*bc4097aaSchristos 512*bc4097aaSchristos# call sub to analyse packets by time 513*bc4097aaSchristos# @shortrecs has form 209.24.1.217 123 192.216.16.2 123 udp len 20 76 514*bc4097aaSchristos# @recs has form 27/07/1998 00:01:05.216596 le0 @0:2 L 192.216.21.16,2733 -> 192.216.16.2,53 PR udp len 20 62 515*bc4097aaSchristospackbytime($XMAX); 516*bc4097aaSchristos 517*bc4097aaSchristosif("$opt_s" eq "1") 518*bc4097aaSchristos{ 519*bc4097aaSchristos# call subroutine to scan for connections to ports on gatekeep 520*bc4097aaSchristos# other than those listed in saferports, connections to high 521*bc4097aaSchristos# ports are assumed OK..... 522*bc4097aaSchristosposbadones; 523*bc4097aaSchristos 524*bc4097aaSchristos# call subroutine to print out which sites had sent more than 525*bc4097aaSchristos# a defined % of packets to gatekeep 526*bc4097aaSchristostoobusy_site; 527*bc4097aaSchristos} 528*bc4097aaSchristos 529*bc4097aaSchristos 530*bc4097aaSchristos# verbose reporting? 531*bc4097aaSchristosif ("$opt_v" eq "1") 532*bc4097aaSchristos{ 533*bc4097aaSchristos$cnt=-1; 534*bc4097aaSchristos# loop over ALL unique IP source destinations 535*bc4097aaSchristoswhile ($cnt++ < $#allips) 536*bc4097aaSchristos{ 537*bc4097aaSchristos %tally=(); 538*bc4097aaSchristos %unknownsrcports=(); 539*bc4097aaSchristos $uniqip=@allips[$cnt]; 540*bc4097aaSchristos $loop=-1; 541*bc4097aaSchristos $value=0; 542*bc4097aaSchristos $value1=0; 543*bc4097aaSchristos $value2=0; 544*bc4097aaSchristos $value3=0; 545*bc4097aaSchristos $set="N"; 546*bc4097aaSchristos 547*bc4097aaSchristos while ($loop++ < $#recs ) 548*bc4097aaSchristos { 549*bc4097aaSchristos# get src IP num, src port number, 550*bc4097aaSchristos# destination IP num, destnation port number,protocol 551*bc4097aaSchristos ($srcip,$srcport,$destip,$destport,$pro)= split " " , @shortrecs[$loop]; 552*bc4097aaSchristos# loop over all records for the machine $uniqip 553*bc4097aaSchristos# NOTE THE STRINGS ARE COMPARED WITH eq NOT cmp and NOT = !!!! 554*bc4097aaSchristos if( "$uniqip" eq "$srcip") 555*bc4097aaSchristos { 556*bc4097aaSchristos# look up hash of service names to get key... IF ITS NOT THERE THEN WHAT??? 557*bc4097aaSchristos# its more than likely a request coming back in on a high port 558*bc4097aaSchristos# ....So... 559*bc4097aaSchristos# find out the destination port from the unknown (high) src port 560*bc4097aaSchristos# and tally these as they may be a port attack 561*bc4097aaSchristos if ("$srcport" eq "icmp") 562*bc4097aaSchristos { $srcportnam="icmp";} 563*bc4097aaSchristos else 564*bc4097aaSchristos { 565*bc4097aaSchristos $srcportnam=$services{$srcport}; 566*bc4097aaSchristos } 567*bc4097aaSchristos# try and get dest portname, if not there, leave it as the 568*bc4097aaSchristos# dest portnumber 569*bc4097aaSchristos if ("$destport" eq "icmp") 570*bc4097aaSchristos { $destportnam="icmp";} 571*bc4097aaSchristos else 572*bc4097aaSchristos { 573*bc4097aaSchristos $destportnam=$services{$destport}; 574*bc4097aaSchristos } 575*bc4097aaSchristos 576*bc4097aaSchristos if ($destportnam eq "") 577*bc4097aaSchristos { 578*bc4097aaSchristos $destportnam=$destport; 579*bc4097aaSchristos } 580*bc4097aaSchristos 581*bc4097aaSchristos if ($srcportnam eq "") 582*bc4097aaSchristos { 583*bc4097aaSchristos# increment number of times a (high)/unknown port has gone to destport 584*bc4097aaSchristos $value1=$unknownsrcports{$destportnam}; 585*bc4097aaSchristos $value1++ ; 586*bc4097aaSchristos $unknownsrcports{$destportnam}=$value1; 587*bc4097aaSchristos } 588*bc4097aaSchristos else 589*bc4097aaSchristos { 590*bc4097aaSchristos# want tally(srcport) counter to be increased by 1 591*bc4097aaSchristos $value3=$tally{$srcportnam}; 592*bc4097aaSchristos $value3++ ; 593*bc4097aaSchristos $tally{$srcportnam}=$value3; 594*bc4097aaSchristos } 595*bc4097aaSchristos } 596*bc4097aaSchristos 597*bc4097aaSchristos 598*bc4097aaSchristos } 599*bc4097aaSchristos# end of loop over ALL IP's 600*bc4097aaSchristos 601*bc4097aaSchristosif ($set eq "N") 602*bc4097aaSchristos{ 603*bc4097aaSchristos$set="Y"; 604*bc4097aaSchristos 605*bc4097aaSchristosprint "\n#### with $uniqip as the the source for packets ####\n"; 606*bc4097aaSchristoswhile(($key,$value)=each %tally) 607*bc4097aaSchristos { 608*bc4097aaSchristos if (not "$uniqip" eq "$gatekeep") 609*bc4097aaSchristos { 610*bc4097aaSchristos print "$value connections from $key to gatekeep\n"; 611*bc4097aaSchristos } 612*bc4097aaSchristos else 613*bc4097aaSchristos { 614*bc4097aaSchristos print "$value connections from gatekeep to $key\n"; 615*bc4097aaSchristos } 616*bc4097aaSchristos } 617*bc4097aaSchristos 618*bc4097aaSchristos 619*bc4097aaSchristos 620*bc4097aaSchristoswhile(($key2,$value2)=each %unknownsrcports) 621*bc4097aaSchristos { 622*bc4097aaSchristos if (not "$uniqip" eq "$gatekeep") 623*bc4097aaSchristos { 624*bc4097aaSchristos print "$value2 high port connections to $key2 on gatekeep\n"; 625*bc4097aaSchristos } 626*bc4097aaSchristos else 627*bc4097aaSchristos { 628*bc4097aaSchristos print "$value2 high port connections to $key2 from gatekeep\n"; 629*bc4097aaSchristos } 630*bc4097aaSchristos } 631*bc4097aaSchristos 632*bc4097aaSchristos} 633*bc4097aaSchristos# print if rests for UNIQIP IF flag is set to N then toggle flag 634*bc4097aaSchristos 635*bc4097aaSchristos} # end of all IPs loop 636*bc4097aaSchristos} # end of if verbose option set block 637*bc4097aaSchristos 638*bc4097aaSchristos 639*bc4097aaSchristos 640