diff -cr ip_fil3.3.12/HISTORY ip_fil3.3.13/HISTORY *** ip_fil3.3.12/HISTORY Thu Mar 16 01:08:15 2000 --- ip_fil3.3.13/HISTORY Wed Apr 26 02:21:51 2000 *************** *** 20,25 **** --- 20,35 ---- # and especially those who have found the time to port IP Filter to new # platforms. # + 3.3.13 26/04/2000 - Released + + Fix parsing of "range" with "portmap" + + Relax checking of ftp replies, slightly. + + Fix NAT timeouts for ICMP packets + + SunOS4 patches for ICMP redirects from Jurgen Keil (jk@tools.de) + 3.3.12 16/03/2000 - Released tighten up ftp proxy behaviour. sigh. yuck. hate. diff -cr ip_fil3.3.12/SunOS4/ip_input.c ip_fil3.3.13/SunOS4/ip_input.c *** ip_fil3.3.12/SunOS4/ip_input.c Tue Feb 18 21:54:10 1997 --- ip_fil3.3.13/SunOS4/ip_input.c Thu Mar 23 00:19:01 2000 *************** *** 67,73 **** extern int ip_forwarding, ip_dirbroadcast; int ipprintfs = 0; int in_interfaces; ! int ipsendredirects; #if defined(IPFILTER_LKM) || defined(IPFILTER) int (*fr_checkp)() = NULL, fr_check(); #endif --- 67,73 ---- extern int ip_forwarding, ip_dirbroadcast; int ipprintfs = 0; int in_interfaces; ! extern int ip_sendredirects; #if defined(IPFILTER_LKM) || defined(IPFILTER) int (*fr_checkp)() = NULL, fr_check(); #endif *************** *** 672,677 **** --- 672,678 ---- register struct in_ifaddr *ia; int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; struct in_addr *sin; + struct in_addr dest; n_time ntime; cp = (u_char *)(ip + 1); *************** *** 840,846 **** } return (0); bad: ! icmp_error(ip, type, code, ifp); return (1); } --- 841,848 ---- } return (0); bad: ! dest.s_addr = 0; ! icmp_error(ip, type, code, ifp, dest); return (1); } *************** *** 1032,1041 **** register struct rtentry *rt; int error, type = 0, code; struct mbuf *mcopy; ! n_long dest; ! struct ifnet *destifp; ! dest = 0; if (in_canforward(ip->ip_dst) == 0) { ipstat.ips_cantforward++; m_freem(m); --- 1034,1042 ---- register struct rtentry *rt; int error, type = 0, code; struct mbuf *mcopy; ! struct in_addr dest; ! dest.s_addr = 0; if (in_canforward(ip->ip_dst) == 0) { ipstat.ips_cantforward++; m_freem(m); *************** *** 1043,1049 **** } /* HTONS(ip->ip_id); */ if (ip->ip_ttl <= IPTTLDEC) { ! icmp_error(ip, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, ifp, 0); return; } ip->ip_ttl -= IPTTLDEC; --- 1044,1050 ---- } /* HTONS(ip->ip_id); */ if (ip->ip_ttl <= IPTTLDEC) { ! icmp_error(ip, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, ifp, dest); return; } ip->ip_ttl -= IPTTLDEC; *************** *** 1061,1067 **** rtalloc(&ipforward_rt); if (ipforward_rt.ro_rt == 0) { icmp_error(ip, ICMP_UNREACH, ICMP_UNREACH_HOST, ! ifp, 0); return; } rt = ipforward_rt.ro_rt; --- 1062,1068 ---- rtalloc(&ipforward_rt); if (ipforward_rt.ro_rt == 0) { icmp_error(ip, ICMP_UNREACH, ICMP_UNREACH_HOST, ! ifp, dest); return; } rt = ipforward_rt.ro_rt; *************** *** 1085,1102 **** if (rt->rt_ifp == ifp && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && satosin(&rt->rt_dst)->sin_addr.s_addr != 0 && ! ipsendredirects && !srcrt) { struct in_ifaddr *ia = ifptoia(ifp); u_long src = ntohl(ip->ip_src.s_addr); if (ia && (src & ia->ia_subnetmask) == ia->ia_subnet) { if (rt->rt_flags & RTF_GATEWAY) ! dest = satosin(&rt->rt_gateway)->sin_addr.s_addr; else ! dest = ip->ip_dst.s_addr; /* Router requirements says to only send host redirects */ type = ICMP_REDIRECT; code = ICMP_REDIRECT_HOST; } } --- 1086,1105 ---- if (rt->rt_ifp == ifp && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && satosin(&rt->rt_dst)->sin_addr.s_addr != 0 && ! ip_sendredirects && !srcrt) { struct in_ifaddr *ia = ifptoia(ifp); u_long src = ntohl(ip->ip_src.s_addr); if (ia && (src & ia->ia_subnetmask) == ia->ia_subnet) { if (rt->rt_flags & RTF_GATEWAY) ! dest = satosin(&rt->rt_gateway)->sin_addr; else ! dest = ip->ip_dst; /* Router requirements says to only send host redirects */ type = ICMP_REDIRECT; code = ICMP_REDIRECT_HOST; + if (ipprintfs) + printf("ip_forward: redirect (%d) to %x\n", code, dest.s_addr); } } *************** *** 1116,1122 **** } if (mcopy == NULL) return; - destifp = NULL; switch (error) { --- 1119,1124 ---- *************** *** 1137,1143 **** type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; if (ipforward_rt.ro_rt) ! destifp = ipforward_rt.ro_rt->rt_ifp; break; case ENOBUFS: --- 1139,1145 ---- type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; if (ipforward_rt.ro_rt) ! ifp = ipforward_rt.ro_rt->rt_ifp; break; case ENOBUFS: *************** *** 1145,1151 **** code = 0; break; } ! icmp_error(mtod(mcopy, struct ip *), type, code, destifp, dest); } #ifdef RSVP_ISI --- 1147,1153 ---- code = 0; break; } ! icmp_error(mtod(mcopy, struct ip *), type, code, ifp, dest); } #ifdef RSVP_ISI diff -cr ip_fil3.3.12/SunOS5/pkginfo ip_fil3.3.13/SunOS5/pkginfo *** ip_fil3.3.12/SunOS5/pkginfo Thu Mar 16 01:08:17 2000 --- ip_fil3.3.13/SunOS5/pkginfo Sat Apr 15 14:43:18 2000 *************** *** 5,11 **** PKG=ipf NAME=IP Filter ARCH=sparc,i386 ! VERSION=3.3.12 CATEGORY=system DESC=This package contains tools for building a firewall VENDOR=Darren Reed --- 5,11 ---- PKG=ipf NAME=IP Filter ARCH=sparc,i386 ! VERSION=3.3.13 CATEGORY=system DESC=This package contains tools for building a firewall VENDOR=Darren Reed diff -cr ip_fil3.3.12/fil.c ip_fil3.3.13/fil.c *** ip_fil3.3.12/fil.c Sat Mar 4 01:51:16 2000 --- ip_fil3.3.13/fil.c Wed Apr 26 02:21:09 2000 *************** *** 7,13 **** */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.17 2000/03/03 14:51:16 darrenr Exp $"; #endif #include --- 7,13 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.18 2000/04/25 16:21:09 darrenr Exp $"; #endif #include *************** *** 19,25 **** defined(_KERNEL) # include "opt_ipfilter_log.h" #endif ! #if defined(KERNEL) && defined(__FreeBSD_version) && \ (__FreeBSD_version >= 220000) # include # include --- 19,25 ---- defined(_KERNEL) # include "opt_ipfilter_log.h" #endif ! #if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \ (__FreeBSD_version >= 220000) # include # include *************** *** 1189,1195 **** * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 ! * $Id: fil.c,v 2.3.2.17 2000/03/03 14:51:16 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, --- 1189,1195 ---- * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 ! * $Id: fil.c,v 2.3.2.18 2000/04/25 16:21:09 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, diff -cr ip_fil3.3.12/ip_auth.c ip_fil3.3.13/ip_auth.c *** ip_fil3.3.12/ip_auth.c Sun Jan 16 21:12:14 2000 --- ip_fil3.3.13/ip_auth.c Wed Apr 26 02:21:12 2000 *************** *** 6,12 **** * to the original author and the contributors. */ #if !defined(lint) ! static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.1.2.2 2000/01/16 10:12:14 darrenr Exp $"; #endif #include --- 6,12 ---- * to the original author and the contributors. */ #if !defined(lint) ! static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.1.2.3 2000/04/25 16:21:12 darrenr Exp $"; #endif #include *************** *** 19,25 **** # include # include #endif ! #if defined(KERNEL) && (__FreeBSD_version >= 220000) # include # include #else --- 19,25 ---- # include # include #endif ! #if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include #else diff -cr ip_fil3.3.12/ip_compat.h ip_fil3.3.13/ip_compat.h *** ip_fil3.3.12/ip_compat.h Tue Feb 15 19:02:43 2000 --- ip_fil3.3.13/ip_compat.h Wed Apr 26 02:21:11 2000 *************** *** 6,12 **** * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 ! * $Id: ip_compat.h,v 2.1.2.5 2000/02/15 08:02:43 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ --- 6,12 ---- * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 ! * $Id: ip_compat.h,v 2.1.2.6 2000/04/25 16:21:11 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ *************** *** 208,214 **** #define IPOPT_FINN 205 /* FINN */ ! #if defined(__FreeBSD__) && defined(KERNEL) # if __FreeBSD__ < 3 # include # endif --- 208,214 ---- #define IPOPT_FINN 205 /* FINN */ ! #if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) # if __FreeBSD__ < 3 # include # endif diff -cr ip_fil3.3.12/ip_fil.c ip_fil3.3.13/ip_fil.c *** ip_fil3.3.12/ip_fil.c Wed Mar 8 01:41:39 2000 --- ip_fil3.3.13/ip_fil.c Wed Apr 19 02:31:27 2000 *************** *** 7,13 **** */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.4.2.19 2000/03/07 14:41:39 darrenr Exp $"; #endif #ifndef SOLARIS --- 7,13 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.4.2.20 2000/04/18 16:31:27 darrenr Exp $"; #endif #ifndef SOLARIS *************** *** 725,736 **** } if (!f) { ! if (req != SIOCINAFR && req != SIOCINIFR) ! while ((f = *ftail)) ! ftail = &f->fr_next; ! else { if (fp->fr_hits) { - ftail = fprev; while (--fp->fr_hits && (f = *ftail)) ftail = &f->fr_next; } --- 725,733 ---- } if (!f) { ! if (req == SIOCINAFR || req == SIOCINIFR) { ! ftail = fprev; if (fp->fr_hits) { while (--fp->fr_hits && (f = *ftail)) ftail = &f->fr_next; } diff -cr ip_fil3.3.12/ip_ftp_pxy.c ip_fil3.3.13/ip_ftp_pxy.c *** ip_fil3.3.12/ip_ftp_pxy.c Thu Mar 16 00:56:30 2000 --- ip_fil3.3.13/ip_ftp_pxy.c Sun Mar 26 01:23:49 2000 *************** *** 15,23 **** #define IPF_MAXPORTLEN 30 #define IPF_MIN227LEN 39 #define IPF_MAX227LEN 51 ! #define IPF_FTPBUFSZ MAX(68,IPF_MAX227LEN) /* This *MUST* be >= 51! */ ! /* 68 is chosen as the minimum datagram size for */ ! /* an unfragmented packet */ int ippr_ftp_init __P((void)); --- 15,21 ---- #define IPF_MAXPORTLEN 30 #define IPF_MIN227LEN 39 #define IPF_MAX227LEN 51 ! #define IPF_FTPBUFSZ MAX(96,IPF_MAX227LEN) /* This *MUST* be >= 51! */ int ippr_ftp_init __P((void)); *************** *** 206,211 **** --- 204,210 ---- */ if (ippr_ftp_complete(portbuf, dlen)) return 0; + ftp = nat->nat_aps->aps_data; switch (ftp->ftp_passok) { *************** *** 431,445 **** * Don't put the switch in one common function because one side * should only see numeric responses and the other commands. */ ! if (ippr_ftp_complete(portbuf, dlen)) ! return 0; ftp = nat->nat_aps->aps_data; switch (ftp->ftp_passok) { case 1 : if (!strncmp(portbuf, "331", 3)) ftp->ftp_passok = 2; ! else if (!strncmp(portbuf, "520", 3)) ftp->ftp_passok = 0; break; case 3 : --- 430,443 ---- * Don't put the switch in one common function because one side * should only see numeric responses and the other commands. */ ! ftp = nat->nat_aps->aps_data; switch (ftp->ftp_passok) { case 1 : if (!strncmp(portbuf, "331", 3)) ftp->ftp_passok = 2; ! else if (!strncmp(portbuf, "530", 3)) ftp->ftp_passok = 0; break; case 3 : *************** *** 450,457 **** break; } ! if (ftp->ftp_passok != 4) return 0; /* * Check for PASV reply message. */ --- 448,456 ---- break; } ! if (ippr_ftp_complete(portbuf, dlen) || (ftp->ftp_passok != 4)) return 0; + /* * Check for PASV reply message. */ diff -cr ip_fil3.3.12/ip_nat.c ip_fil3.3.13/ip_nat.c *** ip_fil3.3.12/ip_nat.c Thu Mar 9 01:17:26 2000 --- ip_fil3.3.13/ip_nat.c Wed Apr 26 02:21:13 2000 *************** *** 9,15 **** */ #if !defined(lint) static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.2.2.13 2000/03/08 14:17:26 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) --- 9,15 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.2.2.15 2000/04/25 16:21:13 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) *************** *** 30,36 **** # include # include #endif ! #if defined(KERNEL) && (__FreeBSD_version >= 220000) # include # include #else --- 30,36 ---- # include # include #endif ! #if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include #else *************** *** 1439,1444 **** --- 1439,1446 ---- if (udp->uh_sum) csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; } if (csump) { if (nat->nat_dir == NAT_OUTBOUND) *************** *** 1619,1624 **** --- 1621,1628 ---- if (udp->uh_sum) csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; } if (csump) { if (nat->nat_dir == NAT_OUTBOUND) diff -cr ip_fil3.3.12/ip_sfil.c ip_fil3.3.13/ip_sfil.c *** ip_fil3.3.12/ip_sfil.c Sun Jan 16 21:12:44 2000 --- ip_fil3.3.13/ip_sfil.c Wed Apr 19 02:31:30 2000 *************** *** 9,15 **** */ #if !defined(lint) static const char sccsid[] = "%W% %G% (C) 1993-1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_sfil.c,v 2.1.2.6 2000/01/16 10:12:44 darrenr Exp $"; #endif #include --- 9,15 ---- */ #if !defined(lint) static const char sccsid[] = "%W% %G% (C) 1993-1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_sfil.c,v 2.1.2.7 2000/04/18 16:31:30 darrenr Exp $"; #endif #include *************** *** 498,507 **** } if (!f) { ! if (req != SIOCINAFR && req != SIOCINIFR) ! while ((f = *ftail)) ! ftail = &f->fr_next; ! else { if (fp->fr_hits) { ftail = fprev; while (--fp->fr_hits && (f = *ftail)) --- 498,505 ---- } if (!f) { ! if (req == SIOCINAFR || req == SIOCINIFR) { ! ftail = fprev; if (fp->fr_hits) { ftail = fprev; while (--fp->fr_hits && (f = *ftail)) diff -cr ip_fil3.3.12/ip_state.c ip_fil3.3.13/ip_state.c *** ip_fil3.3.12/ip_state.c Thu Feb 24 02:23:24 2000 --- ip_fil3.3.13/ip_state.c Wed Apr 26 02:21:16 2000 *************** *** 7,13 **** */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.22 2000/02/23 15:23:24 darrenr Exp $"; #endif #include --- 7,13 ---- */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.23 2000/04/25 16:21:16 darrenr Exp $"; #endif #include *************** *** 28,34 **** # include # endif #endif ! #if defined(KERNEL) && (__FreeBSD_version >= 220000) # include # include # if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) --- 28,34 ---- # include # endif #endif ! #if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include # if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) diff -cr ip_fil3.3.12/ipl.h ip_fil3.3.13/ipl.h *** ip_fil3.3.12/ipl.h Thu Mar 16 01:08:16 2000 --- ip_fil3.3.13/ipl.h Sat Apr 15 14:43:17 2000 *************** *** 11,16 **** #ifndef __IPL_H__ #define __IPL_H__ ! #define IPL_VERSION "IP Filter: v3.3.12" #endif --- 11,16 ---- #ifndef __IPL_H__ #define __IPL_H__ ! #define IPL_VERSION "IP Filter: v3.3.13" #endif diff -cr ip_fil3.3.12/natparse.c ip_fil3.3.13/natparse.c *** ip_fil3.3.12/natparse.c Sun Nov 21 09:50:30 1999 --- ip_fil3.3.13/natparse.c Sat Mar 25 11:37:37 2000 *************** *** 53,59 **** #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: natparse.c,v 1.2.2.1 1999/11/20 22:50:30 darrenr Exp $"; #endif --- 53,59 ---- #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; ! static const char rcsid[] = "@(#)$Id: natparse.c,v 1.2.2.2 2000/03/25 00:37:37 darrenr Exp $"; #endif *************** *** 536,556 **** return NULL; ipn.in_outmsk = n_hostmask(snetm); if (!(s = strtok(NULL, " \t"))) { ! ipn.in_flags = IPN_TCP; /* XXX- TCP only by default */ proto = "tcp"; } else { if (!strcasecmp(s, "tcp")) ! ipn.in_flags = IPN_TCP; else if (!strcasecmp(s, "udp")) ! ipn.in_flags = IPN_UDP; else if (!strcasecmp(s, "tcp/udp")) ! ipn.in_flags = IPN_TCPUDP; else if (!strcasecmp(s, "tcpudp")) ! ipn.in_flags = IPN_TCPUDP; else if (!strcasecmp(s, "ip")) ! ipn.in_flags = IPN_ANY; else { ! ipn.in_flags = IPN_ANY; if ((pr = getprotobyname(s))) ipn.in_p = pr->p_proto; else --- 536,556 ---- return NULL; ipn.in_outmsk = n_hostmask(snetm); if (!(s = strtok(NULL, " \t"))) { ! ipn.in_flags |= IPN_TCP; /* XXX- TCP only by default */ proto = "tcp"; } else { if (!strcasecmp(s, "tcp")) ! ipn.in_flags |= IPN_TCP; else if (!strcasecmp(s, "udp")) ! ipn.in_flags |= IPN_UDP; else if (!strcasecmp(s, "tcp/udp")) ! ipn.in_flags |= IPN_TCPUDP; else if (!strcasecmp(s, "tcpudp")) ! ipn.in_flags |= IPN_TCPUDP; else if (!strcasecmp(s, "ip")) ! ipn.in_flags |= IPN_ANY; else { ! ipn.in_flags |= IPN_ANY; if ((pr = getprotobyname(s))) ipn.in_p = pr->p_proto; else *************** *** 649,661 **** if (!(s = strtok(NULL, " \t"))) return NULL; if (!strcasecmp(s, "tcp")) ! ipn.in_flags = IPN_TCP; else if (!strcasecmp(s, "udp")) ! ipn.in_flags = IPN_UDP; else if (!strcasecmp(s, "tcpudp")) ! ipn.in_flags = IPN_TCPUDP; else if (!strcasecmp(s, "tcp/udp")) ! ipn.in_flags = IPN_TCPUDP; else { fprintf(stderr, "%d: expected protocol name - got \"%s\"\n", --- 649,661 ---- if (!(s = strtok(NULL, " \t"))) return NULL; if (!strcasecmp(s, "tcp")) ! ipn.in_flags |= IPN_TCP; else if (!strcasecmp(s, "udp")) ! ipn.in_flags |= IPN_UDP; else if (!strcasecmp(s, "tcpudp")) ! ipn.in_flags |= IPN_TCPUDP; else if (!strcasecmp(s, "tcp/udp")) ! ipn.in_flags |= IPN_TCPUDP; else { fprintf(stderr, "%d: expected protocol name - got \"%s\"\n", diff -cr ip_fil3.3.12/perl/plog ip_fil3.3.13/perl/plog *** ip_fil3.3.12/perl/plog Wed May 5 13:03:47 1999 --- ip_fil3.3.13/perl/plog Wed Apr 26 02:20:43 2000 *************** *** 1,8 **** #!/usr/bin/perl -wT # ! # Author: Jefferson Ogata ! # Date: 1998/11/01 ! # Version: 0.4 # # 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 --- 1,8 ---- #!/usr/bin/perl -wT # ! # Author: Jefferson Ogata (JO317) ! # Date: 2000/04/10 ! # Version: 0.8 # # 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 *************** *** 14,30 **** # 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. One way I ! # often use is: ! # grep ' b ' logfile | plog ! # since a ' b ' sequence indicates a blocked packet. # - # TODO: # - Handle output from ipmon -v. # - Handle timestamps from other locales. Anyone with a timestamp problem # please email me the format of your timestamps. # - # CHANGES: # 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 --- 14,92 ---- # 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 -A block,log < /var/log/ipf ! # ! # Generate source and destination reports of all packets logged with ! # block or log 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. ! # ! # 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/12 (0.9): + # - Wasn't handling underscore in hostname,servicename fields; these may be + # logged using ipmon -n. Observation by . + # - 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 + # . + # - IP Filter now logs a repetition counter. Observation and fixes (changed + # slightly) from Andy Kreiling and John Ladwig + # . + # - 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.420 + 541 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 . + # - 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 . + # + # 1999/05/05 (0.6): + # - IRIX syslog prefixes the hostname with a severity code. Handle it. Fix + # from John Ladwig . + # + # 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 . + # - 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 . # # 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 *************** *** 32,59 **** # 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 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. Nevertheless, some people ! # wanted this, so here it is. # - Added S and n flags to %acts hash. Thanks to Stephen J. Roznowski # . # - Stopped reporting host IPs twice when numeric output was requested. # Thanks, yet again, to Stephen J. Roznowski . # - Number of minor tweaks that might speed it up a bit, and some comments. ! # - Put the script back up on the web site. I moved the site and forgot 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 . # 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". --- 94,126 ---- # 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 # . # - Stopped reporting host IPs twice when numeric output was requested. # Thanks, yet again, to Stephen J. Roznowski . # - 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 . + # # 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". *************** *** 62,306 **** use strict; use Socket; ! select STDOUT ; $| = 1 ; my %hosts; my $me = $0; ! $me =~ s/^([^\/]*\/)*//; ! ! my $numeric = 0; ! ! # Under IPv4 port numbers are unsigned shorts. The value below is higher ! # than the maximum value of an unsigned port, 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; # 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', ); while (defined ($_ = shift)) { if (s/^-//) { ! $numeric += s/n//g; ! &usage (0) if (s/[h\?]//g); ! &usage (1) if (length ($_)); ! next; } ! &usage (1); } while () { chomp; # For ipmon output that came through syslog, we'll have an asctime ! # timestamp, 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 ($time, $log); ! if (/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+([\w\.]+)\s+\S*ipmon\[\d+\]:\s+(\d+:\d+:\d+\.\d+)\s+(.+)/) { ! my ($logtime, $loghost); ! ($logtime, $loghost, $time, $log) = ($1, $2, $3, $4); } ! elsif (/^(\d+\/\d+\/\d+)\s+(\d+:\d+:\d+\.\d+)\s+(.+)$/) { ! my $logdate; ! ($logdate, $time, $log) = ($1, $2, $3); } else { ! # It don't look like no ipmon output to me, baby. ! next; } next unless (defined ($log)); # 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, and maybe some additional info. ! $log =~ /^(\w+)\s+@(\d+):(\d+)\s+(\w)\s+([a-zA-Z0-9\-\.,]+)\s+->\s+([a-zA-Z0-9\-\.,]+)\s+PR\s+(\w+)\s+len\s+(\d+)\s+(\d+)\s*(.*)$/; ! my ($if, $group, $rule, $act, $src, $dest, $proto, $hlen, $len, $more) ! = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10); ! unless (defined ($len)) ! { ! warn ("Bad input line at $.: \"$_\""); ! next; } my ($sport, $dport); if ($proto eq 'icmp') { ! if ($more =~ s/^icmp (\d+)\/(\d+)\s*//) ! { ! # We save icmp type and code in both sport and dport. ! $dport = $sport = "$1.$2"; ! } ! else ! { ! $sport = ''; ! $dport = ''; ! } } else { ! $sport = (($src =~ s/,(\w+)$//) ? &portSimplify ($1, $proto) : ''); ! $dport = (($dest =~ s/,(\w+)$//) ? &portSimplify ($1, $proto) : ''); } # Make sure addresses are numeric at this point. We want to sort by # IP address later. This has got to do some weird things, but if you # want to use ipmon -n, be ready for weirdness. ! $src = &hostNumber ($src); ! $dest = &hostNumber ($dest); # Convert proto to proto number. $proto = &protoNumber ($proto); sub countPacket { ! my ($host, $dir, $peer, $proto, $packet) = @_; ! # Make sure host is in the hosts hash. ! $hosts{$host} = ! +{ ! 'out' => +{ }, ! 'in' => +{ }, ! } unless (exists ($hosts{$host})); ! ! # Get the incoming/outgoing 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. ! ++$protoHash->{$packet}; } # Count the packet as outgoing traffic from the source address. ! &countPacket ($src, 'out', $dest, $proto, "$sport:$dport:$if:$act"); # Count the packet as incoming traffic to the destination address. ! &countPacket ($dest, 'in', $src, $proto, "$dport:$sport:$if:$act"); } my $dir; ! foreach $dir (qw(out in)) { ! my $order = ($dir eq 'out' ? 'source' : 'destination'); ! my $arrow = ($dir eq 'out' ? '->' : '<-'); print "### Traffic by $order address:\n"; sub ipSort { ! my @a = split (/\./, $a); ! my @b = split (/\./, $b); ! $a[0] != $b[0] ? $a[0] <=> $b[0] ! : $a[1] != $b[1] ? $a[1] <=> $b[1] ! : $a[2] != $b[2] ? $a[2] <=> $b[2] ! : $a[3] != $b[3] ? $a[3] <=> $b[3] ! : 0; } 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 " $host\n"; ! } ! else ! { ! print " ", &hostName ($host), " \[$host\]\n"; ! } ! ! my $peer; ! foreach $peer (sort ipSort (keys %{$traffic})) ! { ! my $peerHash = $traffic->{$peer}; ! my $peerName = &hostName ($peer); ! my $proto; ! foreach $proto (sort (keys (%{$peerHash}))) ! { ! my $protoHash = $peerHash->{$proto}; ! my $protoName = &protoName ($proto); ! ! sub packetSort ! { ! my ($asport, $adport, $aif, $aact) = split (/:/, $a); ! my ($bsport, $bdport, $bif, $bact) = split (/:/, $b); ! return $bact cmp $aact if ($aact ne $bact); ! return $aif cmp $bif if ($aif ne $bif); ! return $asport <=> $bsport if ($asport != $bsport); ! return $adport <=> $bdport if ($adport != $bdport); ! } ! ! my $packet; ! foreach $packet (sort packetSort (keys %{$protoHash})) ! { ! my ($sport, $dport, $if, $act) = split (/:/, $packet); ! my $count = $protoHash->{$packet}; ! $act = '?' unless (defined ($act = $acts{$act})); ! if (($protoName eq 'tcp') || ($protoName eq 'udp')) ! { ! printf (" %-6s %7s %5d %6s %14s %2s %s.%s\n", $if, $act, $count, $protoName, &portName ($sport, $protoName), $arrow, $peerName, &portName ($dport, $protoName)); ! } ! elsif ($protoName eq 'icmp') ! { ! printf (" %-6s %7s %5d %6s %14s %2s %s\n", $if, $act, $count, $protoName, &icmpType ($sport), $arrow, $peerName); ! } ! else ! { ! printf (" %-6s %7s %5d %6s %14s %2s %s\n", $if, $act, $count, $protoName, '', $arrow, $peerName); ! } ! } ! } ! } } ! print "\n\n"; } exit (0); - # We use this hash to cache port name -> number and number -> name mappings. - # Isn't is cool that we can use the same hash for both? - my %pn; - # 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 ''. sub portName { --- 129,668 ---- 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 $verbosity = 0; # Bla' bla' bla'. + my $sTable = 0; # Generate source table. + my $dTable = 0; # Generate destination table. + my $services = undef; # Preload services table. + my %selectHosts; # Limit report to these hosts. + my %selectActs; # Limit report to these actions. + + # Parse argument list. while (defined ($_ = shift)) { if (s/^-//) { ! while (s/^([nSD\?hsA])//) ! { ! my $flag = $1; ! if ($flag eq 'v') ! { ! ++$verbosity; ! } ! elsif ($flag eq 'n') ! { ! $numeric = 1; ! } ! elsif ($flag eq 'S') ! { ! $sTable = 1; ! } ! elsif ($flag eq 'D') ! { ! $dTable = 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') ! { ! defined ($services) && &usage (1, qq{too many service maps} ! ); ! $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. ! my $addr = &hostNumber ($_); ! defined ($addr) || &usage (1, qq{cannot resolve hostname $_}); ! $selectHosts{$addr} = undef; ! } ! ! # 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 $selectHosts = scalar (keys (%selectHosts)); ! ! # 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 map. ! if (defined ($services)) ! { ! my $sf = new IO::File ($services, "r"); ! defined ($sf) || &quit (1, qq{cannot open services file $services}); ! ! 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{$services:$.: 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 (); } + # Again, we can use the same hash for both host name -> IP mappings and + # IP -> name mappings. + my %ip; + + # 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 () { 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, $mo + re) = @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); 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 ($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. This has got to do some weird things, but if you # want to use ipmon -n, be ready for weirdness. ! my $x; ! $x = &hostNumber ($src); ! unless (defined ($x)) ! { ! print STDERR "$me:$.: cannot resolve hostname $src\n"; ! next; ! } ! $src = $x; ! $x = &hostNumber ($dest); ! unless (defined ($x)) ! { ! print STDERR "$me:$.: cannot resolve hostname $dest\n"; ! next; ! } ! $dest = $x; ! ! # Skip hosts we're not interested in. ! next if ($selectHosts && !(exists ($selectHosts{$src}) || exists ($selectHo ! sts{$dest}))); # Convert proto to proto number. $proto = &protoNumber ($proto); sub countPacket { ! my ($host, $dir, $peer, $proto, $count, $packet) = @_; ! # 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. ! $protoHash->{$packet} += $count; } # Count the packet as outgoing traffic from the source address. ! &countPacket ($src, 's', $dest, $proto, $count, "$sport:$dport:$if:$act") i ! f ($sTable); # Count the packet as incoming traffic to the destination address. ! &countPacket ($dest, 'd', $src, $proto, $count, "$dport:$sport:$if:$act") i ! f ($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 { ! my @a = split (/\./, $a); ! my @b = split (/\./, $b); ! $a[0] <=> $b[0] || $a[1] <=> $b[1] || $a[2] <=> $b[2] || $a[3] <=> $b[3 ! ]; ! } ! ! 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 "$host\n"; ! } ! else ! { ! print &hostName ($host), " \[$host\]\n"; ! } ! ! my $peer; ! foreach $peer (sort ipSort (keys %{$traffic})) ! { ! my $peerHash = $traffic->{$peer}; ! my $peerName = &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 $count = $protoHash->{$packet}; ! $act = '?' unless (defined ($act = $acts{$act})); ! if (($protoName eq 'tcp') || ($protoName eq 'udp')) ! { ! printf (" %-6s %7s %4d %4s %16s %2s %s.%s\n", $if, $ ! act, $count, $protoName, &portName ($sport, $protoName), $arrow, $peerName, &po ! rtName ($dport, $protoName)); ! } ! elsif ($protoName eq 'icmp') ! { ! printf (" %-6s %7s %4d %4s %16s %2s %s\n", $if, $act ! , $count, $protoName, &icmpType ($sport), $arrow, $peerName); ! } ! else ! { ! printf (" %-6s %7s %4d %4s %16s %2s %s\n", $if, $act ! , $count, $protoName, '', $arrow, $peerName); ! } ! } ! } ! } } ! 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 ''. sub portName { *************** *** 309,316 **** my $pname = "$port/$proto"; unless (exists ($pn{$pname})) { ! my $name = getservbyport ($port, $proto); ! $pn{$pname} = (defined ($name) ? $name : ($port <= 1023 ? $port : '')); } return $pn{$pname}; } --- 671,679 ---- my $pname = "$port/$proto"; unless (exists ($pn{$pname})) { ! my $name = getservbyport ($port, $proto); ! $pn{$pname} = (defined ($name) ? $name : ($port <= 1023 ? $port : '')); } return $pn{$pname}; } *************** *** 323,338 **** 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}; } --- 686,701 ---- 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}; } *************** *** 346,352 **** # Make sure port is numeric. $port = &portNumber ($port, $proto) ! unless ($port =~ /^\d+$/); # Look up port name. my $portName = &portName ($port, $proto); --- 709,715 ---- # Make sure port is numeric. $port = &portNumber ($port, $proto) ! unless ($port =~ /^\d+$/); # Look up port name. my $portName = &portName ($port, $proto); *************** *** 359,368 **** return $port; } - # Again, we can use the same hash for both host name -> IP mappings and - # IP -> name mappings. - my %ip; - # Translates a dotted quad into a hostname. Don't pass names to this # function. sub hostName --- 722,727 ---- *************** *** 371,390 **** return $ip if ($numeric); unless (exists ($ip{$ip})) { ! my $addr = inet_aton ($ip); ! my $name = gethostbyaddr ($addr, AF_INET); ! if (defined ($name)) ! { ! $ip{$ip} = $name; ! ! # While we're at it, cache the forward lookup. ! $ip{$name} = $ip; ! } ! else ! { ! # Just map the IP address to itself. There's no reverse. ! $ip{$ip} = $ip; ! } } return $ip{$ip}; } --- 730,749 ---- return $ip if ($numeric); unless (exists ($ip{$ip})) { ! my $addr = inet_aton ($ip); ! my $name = gethostbyaddr ($addr, AF_INET); ! if (defined ($name)) ! { ! $ip{$ip} = $name; ! ! # While we're at it, cache the forward lookup. ! $ip{$name} = $ip; ! } ! else ! { ! # Just map the IP address to itself. There's no reverse. ! $ip{$ip} = $ip; ! } } return $ip{$ip}; } *************** *** 395,428 **** my $name = shift; if ($name =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) { ! # Return original value for dotted quads. ! my $or = int ($1) | int ($2) | int ($3) | int ($4); ! return $name if ($or == ($or & 0xff)); } unless (exists ($ip{$name})) { ! my $addr = inet_aton ($name); ! unless (defined ($addr)) ! { ! # Again, I don't think we need to recover from this. 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. ! die ("Unable to resolve host \"$name\" at $."); ! } ! my $ip = inet_ntoa ($addr); ! $ip{$name} = $ip; ! # While we're at it, cache the reverse lookup. ! $ip{$ip} = $name; } return $ip{$name}; } - # Hash for protocol number <--> name mappings. - my %pr; - # Translates a protocol number into a protocol name, or a number if no name # is found in the protocol database. sub protoName --- 754,784 ---- my $name = shift; if ($name =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) { ! # Return original value for dotted quads. ! my $or = int ($1) | int ($2) | int ($3) | int ($4); ! return $name if ($or == ($or & 0xff)); } unless (exists ($ip{$name})) { ! my $addr = inet_aton ($name); ! unless (defined ($addr)) ! { ! # Again, I don't think we need to recover from this. 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. ! return undef; ! } ! my $ip = inet_ntoa ($addr); ! $ip{$name} = $ip; ! # While we're at it, cache the reverse lookup. ! $ip{$ip} = $name; } return $ip{$name}; } # Translates a protocol number into a protocol name, or a number if no name # is found in the protocol database. sub protoName *************** *** 431,445 **** 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}; } --- 787,801 ---- 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}; } *************** *** 451,594 **** 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 %icmp = ( - 0 => +{ - name => 'echo-reply', - codes => +{0 => undef}, - }, - 3 => +{ - name => 'dest-unr', - codes => +{ - 0 => 'net', - 1 => 'host', - 2 => 'proto', - 3 => 'port', - 4 => 'need-frag', - 5 => 'no-sroute', - 6 => 'net-unk', - 7 => 'host-unk', - 8 => 'shost-isol', - 9 => 'net-proh', - 10 => 'host-proh', - 11 => 'net-tos', - 12 => 'host-tos', - }, - }, - 4 => +{ - name => 'src-quench', - codes => +{0 => undef}, - }, - 5 => +{ - name => 'redirect', - codes => +{ - 0 => 'net', - 1 => 'host', - 2 => 'tos', - 3 => 'tos-host', - }, - }, - 6 => +{ - name => 'alt-host-addr', - codes => +{0 => undef}, - }, - 8 => +{ - name => 'echo', - codes => +{0 => undef}, - }, - 9 => +{ - name => 'rtr-advert', - codes => +{0 => undef}, - }, - 10 => +{ - name => 'rtr-select', - codes => +{0 => undef}, - }, - 11 => +{ - name => 'time-excd', - codes => +{ - 0 => 'in-transit', - 1 => 'frag-assy', - }, - }, - 12 => +{ - name => 'param-prob', - codes => +{ - 0 => 'ptr-err', - 1 => 'miss-opt', - 2 => 'bad-len', - }, - }, - 13 => +{ - name => 'time', - codes => +{0 => undef}, - }, - 14 => +{ - name => 'time-reply', - codes => +{0 => undef}, - }, - 15 => +{ - name => 'info', - codes => +{0 => undef}, - }, - 16 => +{ - name => 'info-req', - codes => +{0 => undef}, - }, - 17 => +{ - name => 'mask-req', - codes => +{0 => undef}, - }, - 18 => +{ - name => 'mask-reply', - codes => +{0 => undef}, - }, - 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 => +{ }, - }, - ); - my $typeCode = shift; my ($type, $code) = split ('\.', $typeCode); return "?" unless (defined ($code)); ! my $info = $icmp{$type}; return "\(type=$type/$code?\)" unless (defined ($info)); --- 807,833 ---- 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)); *************** *** 596,653 **** my $codeName; if (exists ($info->{codes}->{$code})) { ! $codeName = $info->{codes}->{$code}; ! $codeName = (defined ($codeName) ? "/$codeName" : ''); } else { ! $codeName = "/$code"; } return "$typeName$codeName"; } ! sub usage { my $ec = shift; ! print STDERR <{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 STDERR <