diff options
author | cy <cy@FreeBSD.org> | 2013-09-21 14:23:20 +0000 |
---|---|---|
committer | cy <cy@FreeBSD.org> | 2013-09-21 14:23:20 +0000 |
commit | 1f79bda80fc99a9bea37dc83f80019be39c33c5a (patch) | |
tree | 3915c70585141494037a8c4fd909db7ea85a2aac /contrib/ipfilter/perl/plog | |
parent | b3f0452e3485d31d295010234a8951b1129a6f0b (diff) | |
download | FreeBSD-src-1f79bda80fc99a9bea37dc83f80019be39c33c5a.zip FreeBSD-src-1f79bda80fc99a9bea37dc83f80019be39c33c5a.tar.gz |
Remove redundant files.
Approved by: glebius (mentor)
Approved by: re (blanket)
Diffstat (limited to 'contrib/ipfilter/perl/plog')
-rw-r--r-- | contrib/ipfilter/perl/plog | 1061 |
1 files changed, 0 insertions, 1061 deletions
diff --git a/contrib/ipfilter/perl/plog b/contrib/ipfilter/perl/plog deleted file mode 100644 index 208c6ea..0000000 --- a/contrib/ipfilter/perl/plog +++ /dev/null @@ -1,1061 +0,0 @@ -#!/usr/bin/perl -wT -# -# Author: Jefferson Ogata (JO317) <jogata@pobox.com> -# Date: 2000/04/22 -# Version: 0.10 -# -# Please feel free to use or redistribute this program if you find it useful. -# If you have suggestions, or even better, bits of new code, send them to me -# and I will add them when I have time. The current version of this script -# can always be found at the URL: -# -# http://www.antibozo.net/ogata/webtools/plog.pl -# http://pobox.com/~ogata/webtools/plog.txt -# -# Parse ipmon output into a coherent form. This program only handles the -# lines regarding filter actions. It does not parse nat and state lines. -# -# Present lines from ipmon to this program on standard input. -# -# EXAMPLES -# -# plog -AF block,log < /var/log/ipf -# -# Generate source and destination reports of all packets logged with -# block or log actions, and report TCP flags and keep state actions. -# -# plog -S -s ./services www.example.com < /var/log/ipf -# -# Generate a source report of traffic to or from www.example.com using -# the additional services defined in ./services. -# -# plog -nSA block < /var/log/ipf -# -# Generate a source report of all blocked packets with no hostname -# lookups. This is handy for an initial pass to identify portscans or -# other aggressive traffic. -# -# plog -SFp 192.168.0.0/24 www.example.com/24 < /var/log/ipf -# -# Generate a source report of all packets whose source or destination -# address is either in 192.168.0.0/24 or an address associated with -# the host www.example.com, report packet flags and perform paranoid -# hostname lookups. This is a handy usage for examining traffic more -# closely after identifying a potential attack. -# -# TODO -# -# - Handle output from ipmon -v. -# - Handle timestamps from other locales. Anyone with a timestamp problem -# please email me the format of your timestamps. -# - It looks as though short TCP or UDP packets will break things, but I -# haven't seen any yet. -# -# CHANGES -# -# 2000/04/22 (0.10): -# - Restructured host name and address caches. Hosts are now cached using -# packed addresses as keys. Conversion to IPv6 should be simple now. -# - Added paranoid hostname lookups. -# - Added netmask qualifications for address arguments. -# - Tweaked usage info. -# 2000/04/20: -# - Added parsing and tracking of TCP and state flags. -# 2000/04/12 (0.9): -# - Wasn't handling underscore in hostname,servicename fields; these may be -# logged using ipmon -n. Observation by <ark@eltex.ru>. -# - Hadn't properly attributed observation and fix for repetition counter in -# 0.8 change log. Added John Ladwig to attribution. Thanks, John. -# -# 2000/04/10 (0.8): -# - Service names can also have hyphens, dummy. I wasn't allowing these -# either. Observation and fix thanks to Taso N. Devetzis -# <devetzis@snet.net>. -# - IP Filter now logs a repetition counter. Observation and fixes (changed -# slightly) from Andy Kreiling <Andy@ntcs-inc.com> and John Ladwig -# <jladwig@nts.umn.edu>. -# - Added fix to handle new Solaris log format, e.g.: -# Nov 30 04:49:37 raoul ipmon[121]: [ID 702911 local0.warning] 04:49:36.420541 hme0 @0:34 b 205.152.16.6,58596 -> 204.60.220.24,113 PR tcp len 20 44 -# Fix thanks to Taso N. Devetzis <devetzis@SNET.Net>. -# - Added services map option. -# - Added options for generating only source/destination tables. -# - Added verbosity option. -# - Added option for reporting traffic for specific hosts. -# - Added some more ICMP unreachable codes, and made code and type names -# match the ones in IP Filter parse.c. -# - Condensed output format somewhat. -# - Various minor improvements, perhaps slight speed improvements. -# - Documented new options in usage() and tried to improve wording. -# -# 1999/08/02 (0.7): -# - Hostnames can have hyphens, dummy. I wasn't allowing them in the syslog -# line. Fix from Antoine Verheijen <antoine.verheijen@ualberta.ca>. -# -# 1999/05/05 (0.6): -# - IRIX syslog prefixes the hostname with a severity code. Handle it. Fix -# from John Ladwig <jladwig@nts.umn.edu>. -# -# 1999/05/05 (0.5): -# - Protocols other than TCP, UDP, or ICMP have packet lengths reported in -# parentheses for some reason. The script now handles this. Thanks to -# Dispatcher <dispatch@blackhelicopters.org>. -# - I had mixed up info-request and info-reply ICMP codes, and omitted the -# traceroute code. Sorted this out. I had also missed code 0 for type 6 -# (alternate address for host). Thanks to John Ladwig <jladwig@nts.umn.edu>. -# -# 1999/05/03: -# - Now accepts hostnames in the source and destination address fields, as -# well as port names in the port fields. This allows the people who are -# using ipmon -n to still use plog. Note that if you are logging -# hostnames, you are vulnerable to forgery of DNS information, modified -# DNS information, and your log files will be larger also. If you are -# using this program you can have it look up the names for you (still -# vulnerable to forgery) and keep your logged addresses all in numeric -# format, so that packets from the same source will always show the same -# source address regardless of what's up with DNS. Obviously, I don't -# favor using ipmon -n. Nevertheless, some people wanted this, so here it -# is. -# - Added S and n flags to %acts hash. Thanks to Stephen J. Roznowski -# <sjr@home.net>. -# - Stopped reporting host IPs twice when numeric output was requested. -# Thanks, yet again, to Stephen J. Roznowski <sjr@home.net>. -# - Number of minor tweaks that might speed it up a bit, and some comments. -# - Put the script back up on the web site. I had moved the site and -# forgotten to move the tool. -# -# 1999/02/04: -# - Changed log line parser to accept fully-qualified name in the logging -# host field. Thanks to Stephen J. Roznowski <sjr@home.net>. -# -# 1999/01/22: -# - Changed high port strategy to use 65536 for unknown high ports so that -# they are sorted last. -# -# 1999/01/21: -# - Moved icmp parsing to output loop. -# - Added parsing of icmp codes, and more types. -# - Changed packet sort routine to sort by port number rather than service -# name. -# -# 1999/01/20: -# - Fixed problem matching ipmon log lines. Sometimes they have "/ipmon" in -# them, sometimes just "ipmon". -# - Added numeric parse option to turn off hostname lookups. -# - Moved summary to usage() sub. - -use strict; -use Socket; -use IO::File; - -select STDOUT; $| = 1; - -my %hosts; - -my $me = $0; -$me =~ s/^.*\///; - -# Map of log codes for various actions. Not all of these can occur, but -# I've included everything in print_ipflog() from ipmon.c. -my %acts = ( - 'p' => 'pass', - 'P' => 'pass', - 'b' => 'block', - 'B' => 'block', - 'L' => 'log', - 'S' => 'short', - 'n' => 'nomatch', -); - -# Map of ICMP types and their relevant codes. -my %icmpTypeMap = ( - 0 => +{ - name => 'echorep', - codes => +{0 => undef}, - }, - 3 => +{ - name => 'unreach', - codes => +{ - 0 => 'net-unr', - 1 => 'host-unr', - 2 => 'proto-unr', - 3 => 'port-unr', - 4 => 'needfrag', - 5 => 'srcfail', - 6 => 'net-unk', - 7 => 'host-unk', - 8 => 'isolate', - 9 => 'net-prohib', - 10 => 'host-prohib', - 11 => 'net-tos', - 12 => 'host-tos', - 13 => 'filter-prohib', - 14 => 'host-preced', - 15 => 'preced-cutoff', - }, - }, - 4 => +{ - name => 'squench', - codes => +{0 => undef}, - }, - 5 => +{ - name => 'redir', - codes => +{ - 0 => 'net', - 1 => 'host', - 2 => 'tos', - 3 => 'tos-host', - }, - }, - 6 => +{ - name => 'alt-host-addr', - codes => +{ - 0 => 'alt-addr' - }, - }, - 8 => +{ - name => 'echo', - codes => +{0 => undef}, - }, - 9 => +{ - name => 'routerad', - codes => +{0 => undef}, - }, - 10 => +{ - name => 'routersol', - codes => +{0 => undef}, - }, - 11 => +{ - name => 'timex', - codes => +{ - 0 => 'in-transit', - 1 => 'frag-assy', - }, - }, - 12 => +{ - name => 'paramprob', - codes => +{ - 0 => 'ptr-err', - 1 => 'miss-opt', - 2 => 'bad-len', - }, - }, - 13 => +{ - name => 'timest', - codes => +{0 => undef}, - }, - 14 => +{ - name => 'timestrep', - codes => +{0 => undef}, - }, - 15 => +{ - name => 'inforeq', - codes => +{0 => undef}, - }, - 16 => +{ - name => 'inforep', - codes => +{0 => undef}, - }, - 17 => +{ - name => 'maskreq', - codes => +{0 => undef}, - }, - 18 => +{ - name => 'maskrep', - codes => +{0 => undef}, - }, - 30 => +{ - name => 'tracert', - codes => +{ }, - }, - 31 => +{ - name => 'dgram-conv-err', - codes => +{ }, - }, - 32 => +{ - name => 'mbl-host-redir', - codes => +{ }, - }, - 33 => +{ - name => 'ipv6-whereru?', - codes => +{ }, - }, - 34 => +{ - name => 'ipv6-iamhere', - codes => +{ }, - }, - 35 => +{ - name => 'mbl-reg-req', - codes => +{ }, - }, - 36 => +{ - name => 'mbl-reg-rep', - codes => +{ }, - }, -); - -# Arguments we will parse from argument list. -my $numeric = 0; # Don't lookup hostnames. -my $paranoid = 0; # Do paranoid hostname lookups. -my $verbosity = 0; # Bla' bla' bla'. -my $sTable = 0; # Generate source table. -my $dTable = 0; # Generate destination table. -my @services = (); # Preload services tables. -my $showFlags = 0; # Show TCP flag combinations. -my %selectAddrs; # Limit report to these hosts. -my %selectActs; # Limit report to these actions. - -# Parse argument list. -while (defined ($_ = shift)) -{ - if (s/^-//) - { - while (s/^([vnpSD\?hsAF])//) - { - my $flag = $1; - if ($flag eq 'v') - { - ++$verbosity; - } - elsif ($flag eq 'n') - { - $numeric = 1; - } - elsif ($flag eq 'p') - { - $paranoid = 1; - } - elsif ($flag eq 'S') - { - $sTable = 1; - } - elsif ($flag eq 'D') - { - $dTable = 1; - } - elsif ($flag eq 'F') - { - $showFlags = 1; - } - elsif (($flag eq '?') || ($flag eq 'h')) - { - &usage (0); - } - else - { - my $arg = shift; - defined ($arg) || &usage (1, qq{-$flag requires an argument}); - if ($flag eq 's') - { - push (@services, $arg); - } - elsif ($flag eq 'A') - { - my @acts = split (/,/, $arg); - my $a; - foreach $a (@acts) - { - my $aa; - my $match = 0; - foreach $aa (keys (%acts)) - { - if ($acts{$aa} eq $a) - { - ++$match; - $selectActs{$aa} = $a; - } - } - $match || &usage (1, qq{unknown action $a}); - } - } - } - } - - &usage (1, qq{unknown option: -$_}) if (length); - - next; - } - - # Add host to hash of hosts we're interested in. - (/^(.+)\/([\d+\.]+)$/) || (/^(.+)$/) || &usage (1, qq{invalid CIDR address $_}); - my ($addr, $mask) = ($1, $2); - my @addr = &hostAddrs ($addr); - (scalar (@addr)) || &usage (1, qq{cannot resolve hostname $_}); - if (!defined ($mask)) - { - $mask = (2 ** 32) - 1; - } - elsif (($mask =~ /^\d+$/) && ($mask <= 32)) - { - $mask = (2 ** 32) - 1 - ((2 ** (32 - $mask)) - 1); - } - elsif (defined ($mask = &isDottedAddr ($mask))) - { - $mask = &integerAddr ($mask); - } - else - { - &usage (1, qq{invalid CIDR address $_}); - } - foreach $addr (@addr) - { - # Save mask unless we already have a less specific one for this address. - my $a = &integerAddr ($addr) & $mask; - $selectAddrs{$a} = $mask unless (exists ($selectAddrs{$a}) && ($selectAddrs{$a} < $mask)); - } -} - -# Which tables will we generate? -$dTable = $sTable = 1 unless ($dTable || $sTable); -my @dirs; -push (@dirs, 'd') if ($dTable); -push (@dirs, 's') if ($sTable); - -# Are we interested in specific hosts? -my $selectAddrs = scalar (keys (%selectAddrs)); - -# Are we interested in specific actions? -if (scalar (keys (%selectActs)) == 0) -{ - %selectActs = %acts; -} - -# We use this hash to cache port name -> number and number -> name mappings. -# Isn't it cool that we can use the same hash for both? -my %pn; - -# Preload any services maps. -my $sm; -foreach $sm (@services) -{ - my $sf = new IO::File ($sm, "r"); - defined ($sf) || &quit (1, qq{cannot open services file $sm}); - - while (defined ($_ = $sf->getline ())) - { - my $text = $_; - chomp; - s/#.*$//; - s/\s+$//; - next unless (length); - my ($name, $spec, @aliases) = split (/\s+/); - ($spec =~ /^([\w\-]+)\/([\w\-]+)$/) - || &quit (1, qq{$sm:$.: invalid definition: $text}); - my ($pnum, $proto) = ($1, $2); - - # Enter service definition in pn hash both forwards and backwards. - my $port; - my $pname; - foreach $port ($name, @aliases) - { - $pname = "$pnum/$proto"; - $pn{$pname} = $port; - } - $pname = "$name/$proto"; - $pn{$pname} = $pnum; - } - - $sf->close (); -} - -# Cache for host name -> addr mappings. -my %ipAddr; - -# Cache for host addr -> name mappings. -my %ipName; - -# Hash for protocol number <--> name mappings. -my %pr; - -# Under IPv4 port numbers are unsigned shorts. The value below is higher -# than the maximum value of an unsigned short, and is used in place of -# high port numbers that don't correspond to known services. This makes -# high ports get sorted behind all others. -my $highPort = 0x10000; - -while (<STDIN>) -{ - chomp; - - # For ipmon output that came through syslog, we'll have an asctime - # timestamp, an optional severity code (IRIX), the hostname, - # "ipmon"[process id]: prefixed to the line. For output that was - # written directly to a file by ipmon, we'll have a date prefix as - # dd/mm/yyyy (no y2k problem here!). Both formats then have a packet - # timestamp and the log info. - my ($log); - if (s/^\w+\s+\d+\s+\d+:\d+:\d+\s+(?:\d\w:)?[\w\.\-]+\s+\S*ipmon\[\d+\]:\s+(?:\[ID\s+\d+\s+[\w\.]+\]\s+)?\d+:\d+:\d+\.\d+\s+//) - { - $log = $_; - } - elsif (s/^(?:\d+\/\d+\/\d+)\s+(?:\d+:\d+:\d+\.\d+)\s+//) - { - $log = $_; - } - else - { - # It don't look like no ipmon output to me, baby. - next; - } - next unless (defined ($log)); - - print STDERR "$log\n" if ($verbosity); - - # Parse the log line. We're expecting interface name, rule group and - # number, an action code, a source host name or IP with possible port - # name or number, a destination host name or IP with possible port - # number, "PR", a protocol name or number, "len", a header length, a - # packet length (which will be in parentheses for protocols other than - # TCP, UDP, or ICMP), and maybe some additional info. - my @fields = ($log =~ /^(?:(\d+)x)?\s*(\w+)\s+@(\d+):(\d+)\s+(\w)\s+([\w\-\.,]+)\s+->\s+([\w\-\.,]+)\s+PR\s+(\w+)\s+len\s+(\d+)\s+\(?(\d+)\)?\s*(.*)$/ox); - unless (scalar (@fields)) - { - print STDERR "$me:$.: cannot parse: $_\n"; - next; - } - my ($count, $if, $group, $rule, $act, $src, $dest, $proto, $hlen, $len, $more) = @fields; - - # Skip actions we're not interested in. - next unless (exists ($selectActs{$act})); - - # Packet count defaults to 1. - $count = 1 unless (defined ($count)); - - my ($sport, $dport, @flags); - - if ($proto eq 'icmp') - { - if ($more =~ s/^icmp (\d+)\/(\d+)\s*//) - { - # We save icmp type and code in both sport and dport. This - # allows us to sort icmp packets using the normal port-sorting - # code. - $dport = $sport = "$1.$2"; - } - else - { - $sport = ''; - $dport = ''; - } - } - else - { - if ($showFlags) - { - if (($proto eq 'tcp') && ($more =~ s/^\-([A-Z]+)\s*//)) - { - push (@flags, $1); - } - if ($more =~ s/^K\-S\s*//) - { - push (@flags, 'state'); - } - } - if ($src =~ s/,([\-\w]+)$//) - { - $sport = &portSimplify ($1, $proto); - } - else - { - $sport = ''; - } - if ($dest =~ s/,([\-\w]+)$//) - { - $dport = &portSimplify ($1, $proto); - } - else - { - $dport = ''; - } - } - - # Make sure addresses are numeric at this point. We want to sort by - # IP address later. If the hostname doesn't resolve, punt. If you - # must use ipmon -n, be ready for weirdness. Use only the first - # address returned. - my $x; - $x = (&hostAddrs ($src))[0]; - unless (defined ($x)) - { - print STDERR "$me:$.: cannot resolve hostname $src\n"; - next; - } - $src = $x; - $x = (&hostAddrs ($dest))[0]; - unless (defined ($x)) - { - print STDERR "$me:$.: cannot resolve hostname $dest\n"; - next; - } - $dest = $x; - - # Skip hosts we're not interested in. - if ($selectAddrs) - { - my ($a, $m); - my $s = &integerAddr ($src); - my $d = &integerAddr ($dest); - my $cute = 0; - while (($a, $m) = each (%selectAddrs)) - { - if ((($s & $m) == $a) || (($d & $m) == $a)) - { - $cute = 1; - last; - } - } - next unless ($cute); - } - - # Convert proto to proto number. - $proto = &protoNumber ($proto); - - sub countPacket - { - my ($host, $dir, $peer, $proto, $count, $packet, @flags) = @_; - - # Make sure host is in the hosts hash. - $hosts{$host} = - +{ - 'd' => +{ }, - 's' => +{ }, - } unless (exists ($hosts{$host})); - - # Get the source/destination traffic hash for the host in question. - my $trafficHash = $hosts{$host}->{$dir}; - - # Make sure there's a hash for the peer. - $trafficHash->{$peer} = +{ } unless (exists ($trafficHash->{$peer})); - - # Make sure the peer hash has a hash for the protocol number. - my $peerHash = $trafficHash->{$peer}; - $peerHash->{$proto} = +{ } unless (exists ($peerHash->{$proto})); - - # Make sure there's a counter for this packet type in the proto hash. - my $protoHash = $peerHash->{$proto}; - $protoHash->{$packet} = +{ '' => 0 } unless (exists ($protoHash->{$packet})); - - # Increment the counter and mark flags. - my $packetHash = $protoHash->{$packet}; - $packetHash->{''} += $count; - map { $packetHash->{$_} = undef; } (@flags); - } - - # Count the packet as outgoing traffic from the source address. - &countPacket ($src, 's', $dest, $proto, $count, "$sport:$dport:$if:$act", @flags) if ($sTable); - - # Count the packet as incoming traffic to the destination address. - &countPacket ($dest, 'd', $src, $proto, $count, "$dport:$sport:$if:$act", @flags) if ($dTable); -} - -my $dir; -foreach $dir (@dirs) -{ - my $order = ($dir eq 's' ? 'source' : 'destination'); - my $arrow = ($dir eq 's' ? '->' : '<-'); - - print "###\n"; - print "### Traffic by $order address:\n"; - print "###\n"; - - sub ipSort - { - &integerAddr ($a) <=> &integerAddr ($b); - } - - sub packetSort - { - my ($asport, $adport, $aif, $aact) = split (/:/, $a); - my ($bsport, $bdport, $bif, $bact) = split (/:/, $b); - $bact cmp $aact || $aif cmp $bif || $asport <=> $bsport || $adport <=> $bdport; - } - - my $host; - foreach $host (sort ipSort (keys %hosts)) - { - my $traffic = $hosts{$host}->{$dir}; - - # Skip hosts with no traffic. - next unless (scalar (keys (%{$traffic}))); - - if ($numeric) - { - print &dottedAddr ($host), "\n"; - } - else - { - print &hostName ($host), " \[", &dottedAddr ($host), "\]\n"; - } - - my $peer; - foreach $peer (sort ipSort (keys %{$traffic})) - { - my $peerHash = $traffic->{$peer}; - my $peerName = ($numeric ? &dottedAddr ($peer) : &hostName ($peer)); - my $proto; - foreach $proto (sort (keys (%{$peerHash}))) - { - my $protoHash = $peerHash->{$proto}; - my $protoName = &protoName ($proto); - - my $packet; - foreach $packet (sort packetSort (keys %{$protoHash})) - { - my ($sport, $dport, $if, $act) = split (/:/, $packet); - my $packetHash = $protoHash->{$packet}; - my $count = $packetHash->{''}; - $act = '?' unless (defined ($act = $acts{$act})); - if (($protoName eq 'tcp') || ($protoName eq 'udp')) - { - printf (" %-6s %7s %4d %4s %16s %2s %s.%s", $if, $act, $count, $protoName, &portName ($sport, $protoName), $arrow, $peerName, &portName ($dport, $protoName)); - } - elsif ($protoName eq 'icmp') - { - printf (" %-6s %7s %4d %4s %16s %2s %s", $if, $act, $count, $protoName, &icmpType ($sport), $arrow, $peerName); - } - else - { - printf (" %-6s %7s %4d %4s %16s %2s %s", $if, $act, $count, $protoName, '', $arrow, $peerName); - } - if ($showFlags) - { - my @flags = sort (keys (%{$packetHash})); - if (scalar (@flags)) - { - shift (@flags); - print ' (', join (',', @flags), ')' if (scalar (@flags)); - } - } - print "\n"; - } - } - } - } - - print "\n"; -} - -exit (0); - -# Translates a numeric port/named protocol to a port name. Reserved ports -# that do not have an entry in the services database are left numeric. High -# ports that do not have an entry in the services database are mapped -# to '<high>'. -sub portName -{ - my $port = shift; - my $proto = shift; - my $pname = "$port/$proto"; - unless (exists ($pn{$pname})) - { - my $name = getservbyport ($port, $proto); - $pn{$pname} = (defined ($name) ? $name : ($port <= 1023 ? $port : '<high>')); - } - return $pn{$pname}; -} - -# Translates a named port/protocol to a port number. -sub portNumber -{ - my $port = shift; - my $proto = shift; - my $pname = "$port/$proto"; - unless (exists ($pn{$pname})) - { - my $number = getservbyname ($port, $proto); - unless (defined ($number)) - { - # I don't think we need to recover from this. How did the port - # name get into the log file if we can't find it? Log file from - # a different machine? Fix /etc/services on this one if that's - # your problem. - die ("Unrecognized port name \"$port\" at $."); - } - $pn{$pname} = $number; - } - return $pn{$pname}; -} - -# Convert all unrecognized high ports to the same value so they are treated -# identically. The protocol should be by name. -sub portSimplify -{ - my $port = shift; - my $proto = shift; - - # Make sure port is numeric. - $port = &portNumber ($port, $proto) - unless ($port =~ /^\d+$/); - - # Look up port name. - my $portName = &portName ($port, $proto); - - # Port is an unknown high port. Return a value that is too high for a - # port number, so that high ports get sorted last. - return $highPort if ($portName eq '<high>'); - - # Return original port number. - return $port; -} - -# Translates a numeric address into a hostname. Pass only packed numeric -# addresses to this routine. -sub hostName -{ - my $ip = shift; - return $ipName{$ip} if (exists ($ipName{$ip})); - - # Do an inverse lookup on the address. - my $name = gethostbyaddr ($ip, AF_INET); - unless (defined ($name)) - { - # Inverse lookup failed, so map the IP address to its dotted - # representation and cache that. - $ipName{$ip} = &dottedAddr ($ip); - return $ipName{$ip}; - } - - # For paranoid hostname lookups. - if ($paranoid) - { - # If this address already matches, we're happy. - unless (exists ($ipName{$ip}) && (lc ($ipName{$ip}) eq lc ($name))) - { - # Do a forward lookup on the resulting name. - my @addr = &hostAddrs ($name); - my $match = 0; - - # Cache the forward lookup results for future inverse lookups, - # but don't stomp on inverses we've already cached, even if they - # are questionable. We want to generate consistent output, and - # the cache is growing incrementally. - foreach (@addr) - { - $ipName{$_} = $name unless (exists ($ipName{$_})); - $match = 1 if ($_ eq $ip); - } - - # Was this one of the addresses? If not, tack on a ?. - $name .= '?' unless ($match); - } - } - else - { - # Just believe it and cache it. - $ipName{$ip} = $name; - } - - return $name; -} - -# Translates a hostname or dotted address into a list of packed numeric -# addresses. -sub hostAddrs -{ - my $name = shift; - my $ip; - - # Check if it's a dotted representation. - return ($ip) if (defined ($ip = &isDottedAddr ($name))); - - # Return result from cache. - $name = lc ($name); - return @{$ipAddr{$name}} if (exists ($ipAddr{$name})); - - # Look up the addresses. - my @addr = gethostbyname ($name); - splice (@addr, 0, 4); - - unless (scalar (@addr)) - { - # Again, I don't think we need to recover from this gracefully. - # If we can't resolve a hostname that ended up in the log file, - # punt. We want to be able to sort hosts by IP address later, - # and letting hostnames through will snarl up that code. Users - # of ipmon -n will have to grin and bear it for now. The - # functions that get undef back should treat it as an error or - # as some default address, e.g. 0 just to make things work. - return (); - } - - $ipAddr{$name} = [ @addr ]; - return @{$ipAddr{$name}}; -} - -# If the argument is a valid dotted address, returns the corresponding -# packed numeric address, otherwise returns undef. -sub isDottedAddr -{ - my $addr = shift; - if ($addr =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) - { - my @a = (int ($1), int ($2), int ($3), int ($4)); - foreach (@a) - { - return undef if ($_ >= 256); - } - return pack ('C*', @a); - } - return undef; -} - -# Unpacks a packed numeric address and returns an integer representation. -sub integerAddr -{ - my $addr = shift; - return unpack ('N', $addr); - - # The following is for generalized IPv4/IPv6 stuff. For now, it's a - # lot faster to assume IPv4. - my @a = unpack ('C*', $addr); - my $a = 0; - while (scalar (@a)) - { - $a = ($a << 8) | shift (@a); - } - return $a; -} - -# Unpacks a packed numeric address into a dotted representation. -sub dottedAddr -{ - my $addr = shift; - my @a = unpack ('C*', $addr); - return join ('.', @a); -} - -# Translates a protocol number into a protocol name, or a number if no name -# is found in the protocol database. -sub protoName -{ - my $code = shift; - return $code if ($code !~ /^\d+$/); - unless (exists ($pr{$code})) - { - my $name = scalar (getprotobynumber ($code)); - if (defined ($name)) - { - $pr{$code} = $name; - } - else - { - $pr{$code} = $code; - } - } - return $pr{$code}; -} - -# Translates a protocol name or number into a protocol number. -sub protoNumber -{ - my $name = shift; - return $name if ($name =~ /^\d+$/); - unless (exists ($pr{$name})) - { - my $code = scalar (getprotobyname ($name)); - if (defined ($code)) - { - $pr{$name} = $code; - } - else - { - $pr{$name} = $name; - } - } - return $pr{$name}; -} - -sub icmpType -{ - my $typeCode = shift; - my ($type, $code) = split ('\.', $typeCode); - - return "?" unless (defined ($code)); - - my $info = $icmpTypeMap{$type}; - - return "\(type=$type/$code?\)" unless (defined ($info)); - - my $typeName = $info->{name}; - my $codeName; - if (exists ($info->{codes}->{$code})) - { - $codeName = $info->{codes}->{$code}; - $codeName = (defined ($codeName) ? "/$codeName" : ''); - } - else - { - $codeName = "/$code"; - } - return "$typeName$codeName"; -} - -sub quit -{ - my $ec = shift; - my $msg = shift; - - print STDERR "$me: $msg\n"; - exit ($ec); -} - -sub usage -{ - my $ec = shift; - my @msg = @_; - - if (scalar (@msg)) - { - print STDERR "$me: ", join ("\n", @msg), "\n\n"; - } - - print <<EOT; -usage: $me [-nSDF] [-s servicemap] [-A act1,...] [address...] - -Parses logging from ipmon and presents it in a comprehensible format. This -program generates two reports: one organized by source address and another -organized by destination address. For the first report, source addresses are -sorted by IP address. For each address, all packets originating at the address -are presented in a tabular form, where all packets with the same source and -destination address and port are counted as a single entry. Any port number -greater than 1023 that does not match an entry in the services table is treated -as a "high" port; all high ports are coalesced into the same entry. The fields -for the source address report are: - iface action packet-count proto src-port dest-host.dest-port \[\(flags\)\] -The fields for the destination address report are: - iface action packet-count proto dest-port src-host.src-port \[\(flags\)\] - -Options are: --n Disable hostname lookups, and report only IP addresses. --p Perform paranoid hostname lookups. --S Generate a source address report. --D Generate a destination address report. --F Show all flag combinations associated with packets. --s map Supply an alternate services map to be preloaded. The map should - be in the same format as /etc/services. Any service name not found - in the map will be looked for in the system services file. --A act1,... Limit the report to the specified actions. The possible actions - are pass, block, log, short, and nomatch. - -If any addresses are supplied on the command line, the report is limited to -these hosts. Addresses may be given as dotted IP addresses or hostnames, and -may be qualified with netmasks in CIDR \(/24\) or dotted \(/255.255.255.0\) format. -If a hostname resolves to multiple addresses, all addresses are used. - -If neither -S nor -D is given, both reports are generated. - -Note: if you are logging traffic with ipmon -n, ipmon will already have looked -up and logged addresses as hostnames where possible. This has an important side -effect: this program will translate the hostnames back into IP addresses which -may not match the original addresses of the logged packets because of numerous -DNS issues. If you care about where packets are really coming from, you simply -cannot rely on ipmon -n. An attacker with control of his reverse DNS can map -the reverse lookup to anything he likes. If you haven't logged the numeric IP -address, there's no way to discover the source of an attack reliably. For this -reason, I strongly recommend that you run ipmon without the -n option, and use -this or a similar script to do reverse lookups during analysis, rather than -during logging. -EOT - - exit ($ec); -} - |