xref: /netbsd-src/external/bsd/ipf/dist/perl/Ipfanaly.pl (revision bc4097aacfdd9307c19b7947c13c6ad6982527a9)
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