#!/usr/local/bin/perl # Mark Fullmer # maf+@osu.edu # ipreport: # Use this to generate human readable reports from the arpmon script require "getopts.pl"; # should be the same as arpmon require "paths.pl"; $options = join(' ', @ARGV); &Getopts('pmf:lkhrnbd'); if ($opt_h) { print "usage: ipreport pmf:lkh\n"; print " -p *attempt to ping each host\n"; print " -m only print hosts with more than one hw address\n"; print " -f filter. eg -f 128\.146\.109\..* for only hosts in subnet 109\n"; print " -l only list new entries (looks at $lasttime)\n"; print " -k Kill -HUP the arpmon process before starting\n"; print " -n don't resolve hostnames\n"; print " -r only print arp replies\n"; print " -b only print arp requests (broadcasts)\n"; print " -d don't print header/footer in report\n"; print "\n\n"; exit 0; } if (($opt_r) && ($opt_b)) { print STDERR "-r and -b that makes no sense!\n"; print STDERR "input error user dumped.\n"; exit 1; } # if we got the -l option, get the time from $lasttime if ($opt_l) { if (open (LASTFILE, "<$lasttime")) { $testtime = (stat(LASTFILE))[9]; } close LASTFILE; # `touch` it open (LASTFILE, ">$lasttime") || warn "Can't update $lasttime\n"; print LASTFILE "\n"; close LASTFILE; } # if we got -k option, ask the running arpmon to dump its data # first create a file that arpmon will delete to signal us we're done # but if we can't signal it, just ignore that file (later down in the read # database routine) if ($opt_k) { open (LOCKFILE, ">$lockfile") || die "Can't create $lockfile\n"; print LOCKFILE "$$\n"; close LOCKFILE; open(PIDFILE, "<$pidfile") || die "No $pidfile\n"; $pid = ; if (!kill 1, $pid) { print STDERR "Can't SIGHUP $pid\n"; $dontwait = 1; } } else { $dontwait = 1; } # read the ethernet manufactures file. open (ENETFILE, "< $enetmans") || warn "Can't open $enetmans\n"; while () { # oops, these are hex, the dec AA00000? weren't getting read. # next if (! /^\d/); # skip comments, etc chop; ($addr, $man) = split('\s+', $_, 2); $enetmans{$addr} = $man; } # read our current database file...can't use DBM because 4k is just too # small for key/value pairs (machines doing proxy arp would cause problems # for just 1 example) # wait for file to dissappear (signal from arpmon that it's done dumping) while (1) { last if ($dontwait == 1); # arpmon wasn't running last if (!(-e $lockfile)); sleep 3; if (++$retries > 10) { print STDERR "Giving up on lock of $lockfile -- check arpmon\n"; exit 1; } } open (DBFILE, "< $dbasefile") || die "Can't open $dbasefile\n"; while () { chop; ($ipaddr, @enets) = split(' '); $val = join(' ', @enets); $netlist{$ipaddr} = $val; } close DBFILE; # a header if (!$opt_d) { ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdsy) = localtime(time); $mon += 1; $curdate = "$hour:$min:$sec $mon/$mday/$year"; print "Arpmon report started $curdate as $options\n\n"; } # loop through each ip address, printing enet adddress(s)/times/etc as we go $hostname = ''; foreach $ipaddr (sort(keys(%netlist))) { next if (($opt_f) && ((!($ipaddr =~ /$opt_f/)))); $ping = ""; @temp = split(' ', $netlist{$ipaddr}); # if we need to restrict ourselves, do it here if ($opt_m) { $atype1 = 0; $atype2 = 0; foreach $entry (@temp) { ($atype) = split('-', $entry); # too simple to waste an expensive eval if ($atype == 1) { $atype1 ++; } elsif ($atype == 2) { $atype2 ++; } } next if (($atype1 < 2) && ($atype2 < 2)); } if (($opt_l) || ($opt_b) || ($opt_r)){ $dontskip = 0; foreach $entry (@temp) { ($atype, $nseen, $ltime, $ftime) = split('-', $entry); if ($opt_l) { if ($ftime > $testtime) { $dontskip = 1; last; } } elsif ($opt_r) { if ($atype == 2){ $dontskip = 1; last; } } elsif ($opt_b) { if ($atype == 1){ $dontskip = 1; last; } } } next if (!$dontskip); } if (!$opt_n) { $hostname = (gethostbyaddr(pack('C4', split('\.', $ipaddr)), 2))[0]; $hostname = 'Not-Resolved' unless ($hostname); } $~ = STDOUT; write; foreach $cur (@temp){ ($atype, $nseen, $ltime, $ftime, $hw, $laddr) = split('-', $cur); next if (($opt_b) && ($atype != 1)); next if (($opt_r) && ($atype != 2)); if ($atype == 1) { $~ = BROADCAST; } elsif ($atype == 2) { $~ = REPLY; } else { die "Unknown arp packet type @temp\n"; } $hw =~ y/a-z/A-Z/; @man = split(':', $hw); foreach $octet (@man) { if (length($octet) < 2) { $octet = "0$octet"; } } $man = "@man[0]@man[1]@man[2]"; $hw = join(':', @man); $hw .= " ($enetmans{$man})"; ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdsy) = localtime($ltime); $mon += 1; $lseen = "$hour:$min:$sec $mon/$mday/$year"; ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdsy) = localtime($ftime); $mon += 1; $fseen = "$hour:$min:$sec $mon/$mday/$year"; write; } # foreach } #foreach if (!$opt_d) { ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdsy) = localtime(time); $mon += 1; $curdate = "$hour:$min:$sec $mon/$mday/$year"; print "Arpmon report ended $curdate as $options\n\n"; } format STDOUT = IP: @<<<<<<<<<<<<<<<@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@<<<<@<<<<<<<<<<<<<<<<<< $ipaddr, $hostname, $ping, $inaddr . format BROADCAST = Hardware Address: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $hw Number of Arp broadcasts: @<<<<<<<<<<<< $nseen First Seen: @<<<<<<<<<<<<<<<<< $fseen Last Seen: @<<<<<<<<<<<<<<<<< Asking For @<<<<<<<<<<<<<<<< $lseen $laddr . format REPLY = Hardware Address: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $hw Number of Arp Replies: @<<<<<<<<<<<< $nseen First Seen: @<<<<<<<<<<<<<<<<< $fseen Last Seen: @<<<<<<<<<<<<<<<<< Replying To @<<<<<<<<<<<<<<<< $lseen $laddr .