3 # Author: Jefferson Ogata (JO317) <jogata@pobox.com>
7 # Please feel free to use or redistribute this program if you find it useful.
8 # If you have suggestions, or even better, bits of new code, send them to me
9 # and I will add them when I have time. The current version of this script
10 # can always be found at the URL:
12 # http://www.antibozo.net/ogata/webtools/plog.pl
13 # http://pobox.com/~ogata/webtools/plog.txt
15 # Parse ipmon output into a coherent form. This program only handles the
16 # lines regarding filter actions. It does not parse nat and state lines.
18 # Present lines from ipmon to this program on standard input.
22 # plog -AF block,log < /var/log/ipf
24 # Generate source and destination reports of all packets logged with
25 # block or log actions, and report TCP flags and keep state actions.
27 # plog -S -s ./services www.example.com < /var/log/ipf
29 # Generate a source report of traffic to or from www.example.com using
30 # the additional services defined in ./services.
32 # plog -nSA block < /var/log/ipf
34 # Generate a source report of all blocked packets with no hostname
35 # lookups. This is handy for an initial pass to identify portscans or
36 # other aggressive traffic.
38 # plog -SFp 192.168.0.0/24 www.example.com/24 < /var/log/ipf
40 # Generate a source report of all packets whose source or destination
41 # address is either in 192.168.0.0/24 or an address associated with
42 # the host www.example.com, report packet flags and perform paranoid
43 # hostname lookups. This is a handy usage for examining traffic more
44 # closely after identifying a potential attack.
48 # - Handle output from ipmon -v.
49 # - Handle timestamps from other locales. Anyone with a timestamp problem
50 # please email me the format of your timestamps.
51 # - It looks as though short TCP or UDP packets will break things, but I
52 # haven't seen any yet.
57 # - Restructured host name and address caches. Hosts are now cached using
58 # packed addresses as keys. Conversion to IPv6 should be simple now.
59 # - Added paranoid hostname lookups.
60 # - Added netmask qualifications for address arguments.
61 # - Tweaked usage info.
63 # - Added parsing and tracking of TCP and state flags.
65 # - Wasn't handling underscore in hostname,servicename fields; these may be
66 # logged using ipmon -n. Observation by <ark@eltex.ru>.
67 # - Hadn't properly attributed observation and fix for repetition counter in
68 # 0.8 change log. Added John Ladwig to attribution. Thanks, John.
71 # - Service names can also have hyphens, dummy. I wasn't allowing these
72 # either. Observation and fix thanks to Taso N. Devetzis
73 # <devetzis@snet.net>.
74 # - IP Filter now logs a repetition counter. Observation and fixes (changed
75 # slightly) from Andy Kreiling <Andy@ntcs-inc.com> and John Ladwig
76 # <jladwig@nts.umn.edu>.
77 # - Added fix to handle new Solaris log format, e.g.:
78 # 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
79 # Fix thanks to Taso N. Devetzis <devetzis@SNET.Net>.
80 # - Added services map option.
81 # - Added options for generating only source/destination tables.
82 # - Added verbosity option.
83 # - Added option for reporting traffic for specific hosts.
84 # - Added some more ICMP unreachable codes, and made code and type names
85 # match the ones in IP Filter parse.c.
86 # - Condensed output format somewhat.
87 # - Various minor improvements, perhaps slight speed improvements.
88 # - Documented new options in usage() and tried to improve wording.
91 # - Hostnames can have hyphens, dummy. I wasn't allowing them in the syslog
92 # line. Fix from Antoine Verheijen <antoine.verheijen@ualberta.ca>.
95 # - IRIX syslog prefixes the hostname with a severity code. Handle it. Fix
96 # from John Ladwig <jladwig@nts.umn.edu>.
99 # - Protocols other than TCP, UDP, or ICMP have packet lengths reported in
100 # parentheses for some reason. The script now handles this. Thanks to
101 # Dispatcher <dispatch@blackhelicopters.org>.
102 # - I had mixed up info-request and info-reply ICMP codes, and omitted the
103 # traceroute code. Sorted this out. I had also missed code 0 for type 6
104 # (alternate address for host). Thanks to John Ladwig <jladwig@nts.umn.edu>.
107 # - Now accepts hostnames in the source and destination address fields, as
108 # well as port names in the port fields. This allows the people who are
109 # using ipmon -n to still use plog. Note that if you are logging
110 # hostnames, you are vulnerable to forgery of DNS information, modified
111 # DNS information, and your log files will be larger also. If you are
112 # using this program you can have it look up the names for you (still
113 # vulnerable to forgery) and keep your logged addresses all in numeric
114 # format, so that packets from the same source will always show the same
115 # source address regardless of what's up with DNS. Obviously, I don't
116 # favor using ipmon -n. Nevertheless, some people wanted this, so here it
118 # - Added S and n flags to %acts hash. Thanks to Stephen J. Roznowski
120 # - Stopped reporting host IPs twice when numeric output was requested.
121 # Thanks, yet again, to Stephen J. Roznowski <sjr@home.net>.
122 # - Number of minor tweaks that might speed it up a bit, and some comments.
123 # - Put the script back up on the web site. I had moved the site and
124 # forgotten to move the tool.
127 # - Changed log line parser to accept fully-qualified name in the logging
128 # host field. Thanks to Stephen J. Roznowski <sjr@home.net>.
131 # - Changed high port strategy to use 65536 for unknown high ports so that
132 # they are sorted last.
135 # - Moved icmp parsing to output loop.
136 # - Added parsing of icmp codes, and more types.
137 # - Changed packet sort routine to sort by port number rather than service
141 # - Fixed problem matching ipmon log lines. Sometimes they have "/ipmon" in
142 # them, sometimes just "ipmon".
143 # - Added numeric parse option to turn off hostname lookups.
144 # - Moved summary to usage() sub.
150 select STDOUT
; $| = 1;
157 # Map of log codes for various actions. Not all of these can occur, but
158 # I've included everything in print_ipflog() from ipmon.c.
169 # Map of ICMP types and their relevant codes.
173 codes
=> +{0 => undef},
191 13 => 'filter-prohib',
193 15 => 'preced-cutoff',
198 codes
=> +{0 => undef},
210 name
=> 'alt-host-addr',
217 codes
=> +{0 => undef},
221 codes
=> +{0 => undef},
225 codes
=> +{0 => undef},
244 codes
=> +{0 => undef},
248 codes
=> +{0 => undef},
252 codes
=> +{0 => undef},
256 codes
=> +{0 => undef},
260 codes
=> +{0 => undef},
264 codes
=> +{0 => undef},
271 name
=> 'dgram-conv-err',
275 name
=> 'mbl-host-redir',
279 name
=> 'ipv6-whereru?',
283 name
=> 'ipv6-iamhere',
287 name
=> 'mbl-reg-req',
291 name
=> 'mbl-reg-rep',
296 # Arguments we will parse from argument list.
297 my $numeric = 0; # Don't lookup hostnames.
298 my $paranoid = 0; # Do paranoid hostname lookups.
299 my $verbosity = 0; # Bla' bla' bla'.
300 my $sTable = 0; # Generate source table.
301 my $dTable = 0; # Generate destination table.
302 my @services = (); # Preload services tables.
303 my $showFlags = 0; # Show TCP flag combinations.
304 my %selectAddrs; # Limit report to these hosts.
305 my %selectActs; # Limit report to these actions.
307 # Parse argument list.
308 while (defined ($_ = shift))
312 while (s/^([vnpSD\?hsAF])//)
339 elsif (($flag eq '?') || ($flag eq 'h'))
346 defined ($arg) || &usage
(1, qq{-$flag requires an argument
});
349 push (@services, $arg);
353 my @acts = split (/,/, $arg);
359 foreach $aa (keys (%acts))
361 if ($acts{$aa} eq $a)
364 $selectActs{$aa} = $a;
367 $match || &usage
(1, qq{unknown action
$a});
373 &usage
(1, qq{unknown option
: -$_}) if (length);
378 # Add host to hash of hosts we're interested in.
379 (/^(.+)\/([\d
+\
.]+)$/) || (/^(.+)$/) || &usage
(1, qq{invalid CIDR address
$_});
380 my ($addr, $mask) = ($1, $2);
381 my @addr = &hostAddrs
($addr);
382 (scalar (@addr)) || &usage
(1, qq{cannot resolve hostname
$_});
383 if (!defined ($mask))
385 $mask = (2 ** 32) - 1;
387 elsif (($mask =~ /^\d+$/) && ($mask <= 32))
389 $mask = (2 ** 32) - 1 - ((2 ** (32 - $mask)) - 1);
391 elsif (defined ($mask = &isDottedAddr
($mask)))
393 $mask = &integerAddr
($mask);
397 &usage
(1, qq{invalid CIDR address
$_});
399 foreach $addr (@addr)
401 # Save mask unless we already have a less specific one for this address.
402 my $a = &integerAddr
($addr) & $mask;
403 $selectAddrs{$a} = $mask unless (exists ($selectAddrs{$a}) && ($selectAddrs{$a} < $mask));
407 # Which tables will we generate?
408 $dTable = $sTable = 1 unless ($dTable || $sTable);
410 push (@dirs, 'd') if ($dTable);
411 push (@dirs, 's') if ($sTable);
413 # Are we interested in specific hosts?
414 my $selectAddrs = scalar (keys (%selectAddrs));
416 # Are we interested in specific actions?
417 if (scalar (keys (%selectActs)) == 0)
422 # We use this hash to cache port name -> number and number -> name mappings.
423 # Isn't it cool that we can use the same hash for both?
426 # Preload any services maps.
428 foreach $sm (@services)
430 my $sf = new IO
::File
($sm, "r");
431 defined ($sf) || &quit
(1, qq{cannot
open services file
$sm});
433 while (defined ($_ = $sf->getline ()))
439 next unless (length);
440 my ($name, $spec, @aliases) = split (/\s+/);
441 ($spec =~ /^([\w\-]+)\/([\w\
-]+)$/)
442 || &quit
(1, qq{$sm:$.: invalid definition
: $text});
443 my ($pnum, $proto) = ($1, $2);
445 # Enter service definition in pn hash both forwards and backwards.
448 foreach $port ($name, @aliases)
450 $pname = "$pnum/$proto";
453 $pname = "$name/$proto";
460 # Cache for host name -> addr mappings.
463 # Cache for host addr -> name mappings.
466 # Hash for protocol number <--> name mappings.
469 # Under IPv4 port numbers are unsigned shorts. The value below is higher
470 # than the maximum value of an unsigned short, and is used in place of
471 # high port numbers that don't correspond to known services. This makes
472 # high ports get sorted behind all others.
473 my $highPort = 0x10000;
479 # For ipmon output that came through syslog, we'll have an asctime
480 # timestamp, an optional severity code (IRIX), the hostname,
481 # "ipmon"[process id]: prefixed to the line. For output that was
482 # written directly to a file by ipmon, we'll have a date prefix as
483 # dd/mm/yyyy (no y2k problem here!). Both formats then have a packet
484 # timestamp and the log info.
486 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+//)
490 elsif (s/^(?:\d+\/\d+\/\d
+)\s
+(?
:\d
+:\d
+:\d
+\
.\d
+)\s
+//)
496 # It don't look like no ipmon output to me, baby.
499 next unless (defined ($log));
501 print STDERR
"$log\n" if ($verbosity);
503 # Parse the log line. We're expecting interface name, rule group and
504 # number, an action code, a source host name or IP with possible port
505 # name or number, a destination host name or IP with possible port
506 # number, "PR", a protocol name or number, "len", a header length, a
507 # packet length (which will be in parentheses for protocols other than
508 # TCP, UDP, or ICMP), and maybe some additional info.
509 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);
510 unless (scalar (@fields))
512 print STDERR
"$me:$.: cannot parse: $_\n";
515 my ($count, $if, $group, $rule, $act, $src, $dest, $proto, $hlen, $len, $more) = @fields;
517 # Skip actions we're not interested in.
518 next unless (exists ($selectActs{$act}));
520 # Packet count defaults to 1.
521 $count = 1 unless (defined ($count));
523 my ($sport, $dport, @flags);
525 if ($proto eq 'icmp')
527 if ($more =~ s/^icmp (\d+)\/(\d+)\s*//)
529 # We save icmp type and code in both sport and dport. This
530 # allows us to sort icmp packets using the normal port-sorting
532 $dport = $sport = "$1.$2";
544 if (($proto eq 'tcp') && ($more =~ s/^\-([A-Z]+)\s*//))
548 if ($more =~ s/^K\-S\s*//)
550 push (@flags, 'state');
553 if ($src =~ s/,([\-\w]+)$//)
555 $sport = &portSimplify
($1, $proto);
561 if ($dest =~ s/,([\-\w]+)$//)
563 $dport = &portSimplify
($1, $proto);
571 # Make sure addresses are numeric at this point. We want to sort by
572 # IP address later. If the hostname doesn't resolve, punt. If you
573 # must use ipmon -n, be ready for weirdness. Use only the first
576 $x = (&hostAddrs
($src))[0];
577 unless (defined ($x))
579 print STDERR
"$me:$.: cannot resolve hostname $src\n";
583 $x = (&hostAddrs
($dest))[0];
584 unless (defined ($x))
586 print STDERR
"$me:$.: cannot resolve hostname $dest\n";
591 # Skip hosts we're not interested in.
595 my $s = &integerAddr
($src);
596 my $d = &integerAddr
($dest);
598 while (($a, $m) = each (%selectAddrs))
600 if ((($s & $m) == $a) || (($d & $m) == $a))
609 # Convert proto to proto number.
610 $proto = &protoNumber
($proto);
614 my ($host, $dir, $peer, $proto, $count, $packet, @flags) = @_;
616 # Make sure host is in the hosts hash.
621 } unless (exists ($hosts{$host}));
623 # Get the source/destination traffic hash for the host in question.
624 my $trafficHash = $hosts{$host}->{$dir};
626 # Make sure there's a hash for the peer.
627 $trafficHash->{$peer} = +{ } unless (exists ($trafficHash->{$peer}));
629 # Make sure the peer hash has a hash for the protocol number.
630 my $peerHash = $trafficHash->{$peer};
631 $peerHash->{$proto} = +{ } unless (exists ($peerHash->{$proto}));
633 # Make sure there's a counter for this packet type in the proto hash.
634 my $protoHash = $peerHash->{$proto};
635 $protoHash->{$packet} = +{ '' => 0 } unless (exists ($protoHash->{$packet}));
637 # Increment the counter and mark flags.
638 my $packetHash = $protoHash->{$packet};
639 $packetHash->{''} += $count;
640 map { $packetHash->{$_} = undef; } (@flags);
643 # Count the packet as outgoing traffic from the source address.
644 &countPacket
($src, 's', $dest, $proto, $count, "$sport:$dport:$if:$act", @flags) if ($sTable);
646 # Count the packet as incoming traffic to the destination address.
647 &countPacket
($dest, 'd', $src, $proto, $count, "$dport:$sport:$if:$act", @flags) if ($dTable);
653 my $order = ($dir eq 's' ?
'source' : 'destination');
654 my $arrow = ($dir eq 's' ?
'->' : '<-');
657 print "### Traffic by $order address:\n";
662 &integerAddr
($a) <=> &integerAddr
($b);
667 my ($asport, $adport, $aif, $aact) = split (/:/, $a);
668 my ($bsport, $bdport, $bif, $bact) = split (/:/, $b);
669 $bact cmp $aact || $aif cmp $bif || $asport <=> $bsport || $adport <=> $bdport;
673 foreach $host (sort ipSort
(keys %hosts))
675 my $traffic = $hosts{$host}->{$dir};
677 # Skip hosts with no traffic.
678 next unless (scalar (keys (%{$traffic})));
682 print &dottedAddr
($host), "\n";
686 print &hostName
($host), " \[", &dottedAddr
($host), "\]\n";
690 foreach $peer (sort ipSort
(keys %{$traffic}))
692 my $peerHash = $traffic->{$peer};
693 my $peerName = ($numeric ?
&dottedAddr
($peer) : &hostName
($peer));
695 foreach $proto (sort (keys (%{$peerHash})))
697 my $protoHash = $peerHash->{$proto};
698 my $protoName = &protoName
($proto);
701 foreach $packet (sort packetSort
(keys %{$protoHash}))
703 my ($sport, $dport, $if, $act) = split (/:/, $packet);
704 my $packetHash = $protoHash->{$packet};
705 my $count = $packetHash->{''};
706 $act = '?' unless (defined ($act = $acts{$act}));
707 if (($protoName eq 'tcp') || ($protoName eq 'udp'))
709 printf (" %-6s %7s %4d %4s %16s %2s %s.%s", $if, $act, $count, $protoName, &portName
($sport, $protoName), $arrow, $peerName, &portName
($dport, $protoName));
711 elsif ($protoName eq 'icmp')
713 printf (" %-6s %7s %4d %4s %16s %2s %s", $if, $act, $count, $protoName, &icmpType
($sport), $arrow, $peerName);
717 printf (" %-6s %7s %4d %4s %16s %2s %s", $if, $act, $count, $protoName, '', $arrow, $peerName);
721 my @flags = sort (keys (%{$packetHash}));
725 print ' (', join (',', @flags), ')' if (scalar (@flags));
739 # Translates a numeric port/named protocol to a port name. Reserved ports
740 # that do not have an entry in the services database are left numeric. High
741 # ports that do not have an entry in the services database are mapped
747 my $pname = "$port/$proto";
748 unless (exists ($pn{$pname}))
750 my $name = getservbyport ($port, $proto);
751 $pn{$pname} = (defined ($name) ?
$name : ($port <= 1023 ?
$port : '<high>'));
756 # Translates a named port/protocol to a port number.
761 my $pname = "$port/$proto";
762 unless (exists ($pn{$pname}))
764 my $number = getservbyname ($port, $proto);
765 unless (defined ($number))
767 # I don't think we need to recover from this. How did the port
768 # name get into the log file if we can't find it? Log file from
769 # a different machine? Fix /etc/services on this one if that's
771 die ("Unrecognized port name \"$port\" at $.");
773 $pn{$pname} = $number;
778 # Convert all unrecognized high ports to the same value so they are treated
779 # identically. The protocol should be by name.
785 # Make sure port is numeric.
786 $port = &portNumber
($port, $proto)
787 unless ($port =~ /^\d+$/);
790 my $portName = &portName
($port, $proto);
792 # Port is an unknown high port. Return a value that is too high for a
793 # port number, so that high ports get sorted last.
794 return $highPort if ($portName eq '<high>');
796 # Return original port number.
800 # Translates a numeric address into a hostname. Pass only packed numeric
801 # addresses to this routine.
805 return $ipName{$ip} if (exists ($ipName{$ip}));
807 # Do an inverse lookup on the address.
808 my $name = gethostbyaddr ($ip, AF_INET
);
809 unless (defined ($name))
811 # Inverse lookup failed, so map the IP address to its dotted
812 # representation and cache that.
813 $ipName{$ip} = &dottedAddr
($ip);
817 # For paranoid hostname lookups.
820 # If this address already matches, we're happy.
821 unless (exists ($ipName{$ip}) && (lc ($ipName{$ip}) eq lc ($name)))
823 # Do a forward lookup on the resulting name.
824 my @addr = &hostAddrs
($name);
827 # Cache the forward lookup results for future inverse lookups,
828 # but don't stomp on inverses we've already cached, even if they
829 # are questionable. We want to generate consistent output, and
830 # the cache is growing incrementally.
833 $ipName{$_} = $name unless (exists ($ipName{$_}));
834 $match = 1 if ($_ eq $ip);
837 # Was this one of the addresses? If not, tack on a ?.
838 $name .= '?' unless ($match);
843 # Just believe it and cache it.
844 $ipName{$ip} = $name;
850 # Translates a hostname or dotted address into a list of packed numeric
857 # Check if it's a dotted representation.
858 return ($ip) if (defined ($ip = &isDottedAddr
($name)));
860 # Return result from cache.
862 return @
{$ipAddr{$name}} if (exists ($ipAddr{$name}));
864 # Look up the addresses.
865 my @addr = gethostbyname ($name);
866 splice (@addr, 0, 4);
868 unless (scalar (@addr))
870 # Again, I don't think we need to recover from this gracefully.
871 # If we can't resolve a hostname that ended up in the log file,
872 # punt. We want to be able to sort hosts by IP address later,
873 # and letting hostnames through will snarl up that code. Users
874 # of ipmon -n will have to grin and bear it for now. The
875 # functions that get undef back should treat it as an error or
876 # as some default address, e.g. 0 just to make things work.
880 $ipAddr{$name} = [ @addr ];
881 return @
{$ipAddr{$name}};
884 # If the argument is a valid dotted address, returns the corresponding
885 # packed numeric address, otherwise returns undef.
889 if ($addr =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)
891 my @a = (int ($1), int ($2), int ($3), int ($4));
894 return undef if ($_ >= 256);
896 return pack ('C*', @a);
901 # Unpacks a packed numeric address and returns an integer representation.
905 return unpack ('N', $addr);
907 # The following is for generalized IPv4/IPv6 stuff. For now, it's a
908 # lot faster to assume IPv4.
909 my @a = unpack ('C*', $addr);
913 $a = ($a << 8) | shift (@a);
918 # Unpacks a packed numeric address into a dotted representation.
922 my @a = unpack ('C*', $addr);
923 return join ('.', @a);
926 # Translates a protocol number into a protocol name, or a number if no name
927 # is found in the protocol database.
931 return $code if ($code !~ /^\d+$/);
932 unless (exists ($pr{$code}))
934 my $name = scalar (getprotobynumber ($code));
947 # Translates a protocol name or number into a protocol number.
951 return $name if ($name =~ /^\d+$/);
952 unless (exists ($pr{$name}))
954 my $code = scalar (getprotobyname ($name));
969 my $typeCode = shift;
970 my ($type, $code) = split ('\.', $typeCode);
972 return "?" unless (defined ($code));
974 my $info = $icmpTypeMap{$type};
976 return "\(type=$type/$code?\)" unless (defined ($info));
978 my $typeName = $info->{name
};
980 if (exists ($info->{codes
}->{$code}))
982 $codeName = $info->{codes
}->{$code};
983 $codeName = (defined ($codeName) ?
"/$codeName" : '');
987 $codeName = "/$code";
989 return "$typeName$codeName";
997 print STDERR
"$me: $msg\n";
1008 print STDERR
"$me: ", join ("\n", @msg), "\n\n";
1012 usage: $me [-nSDF] [-s servicemap] [-A act1,...] [address...]
1014 Parses logging from ipmon and presents it in a comprehensible format. This
1015 program generates two reports: one organized by source address and another
1016 organized by destination address. For the first report, source addresses are
1017 sorted by IP address. For each address, all packets originating at the address
1018 are presented in a tabular form, where all packets with the same source and
1019 destination address and port are counted as a single entry. Any port number
1020 greater than 1023 that does not match an entry in the services table is treated
1021 as a "high" port; all high ports are coalesced into the same entry. The fields
1022 for the source address report are:
1023 iface action packet-count proto src-port dest-host.dest-port \[\(flags\)\]
1024 The fields for the destination address report are:
1025 iface action packet-count proto dest-port src-host.src-port \[\(flags\)\]
1028 -n Disable hostname lookups, and report only IP addresses.
1029 -p Perform paranoid hostname lookups.
1030 -S Generate a source address report.
1031 -D Generate a destination address report.
1032 -F Show all flag combinations associated with packets.
1033 -s map Supply an alternate services map to be preloaded. The map should
1034 be in the same format as /etc/services. Any service name not found
1035 in the map will be looked for in the system services file.
1036 -A act1,... Limit the report to the specified actions. The possible actions
1037 are pass, block, log, short, and nomatch.
1039 If any addresses are supplied on the command line, the report is limited to
1040 these hosts. Addresses may be given as dotted IP addresses or hostnames, and
1041 may be qualified with netmasks in CIDR \(/24\) or dotted \(/255.255.255.0\) format.
1042 If a hostname resolves to multiple addresses, all addresses are used.
1044 If neither -S nor -D is given, both reports are generated.
1046 Note: if you are logging traffic with ipmon -n, ipmon will already have looked
1047 up and logged addresses as hostnames where possible. This has an important side
1048 effect: this program will translate the hostnames back into IP addresses which
1049 may not match the original addresses of the logged packets because of numerous
1050 DNS issues. If you care about where packets are really coming from, you simply
1051 cannot rely on ipmon -n. An attacker with control of his reverse DNS can map
1052 the reverse lookup to anything he likes. If you haven't logged the numeric IP
1053 address, there's no way to discover the source of an attack reliably. For this
1054 reason, I strongly recommend that you run ipmon without the -n option, and use
1055 this or a similar script to do reverse lookups during analysis, rather than