From 7595d5ffce4a14f32ac605d21cbd61fbe85057e2 Mon Sep 17 00:00:00 2001 From: darrenr Date: Thu, 26 Oct 2000 12:45:54 +0000 Subject: Import IP Filter 3.4.12 --- contrib/ipfilter/BNF | 4 +- contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 | 61 ++ contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 | 63 ++ contrib/ipfilter/FreeBSD-4.0/kinstall | 8 +- contrib/ipfilter/FreeBSD-4.0/unkinstall | 3 +- contrib/ipfilter/HISTORY | 52 +- contrib/ipfilter/Makefile | 16 +- contrib/ipfilter/common.c | 2 +- contrib/ipfilter/fil.c | 61 +- contrib/ipfilter/ip_auth.h | 4 +- contrib/ipfilter/ip_compat.h | 38 +- contrib/ipfilter/ip_fil.c | 39 +- contrib/ipfilter/ip_frag.c | 23 +- contrib/ipfilter/ip_frag.h | 4 +- contrib/ipfilter/ip_ftp_pxy.c | 24 +- contrib/ipfilter/ip_nat.c | 439 ++++++++++-- contrib/ipfilter/ip_nat.h | 14 +- contrib/ipfilter/ip_raudio_pxy.c | 4 +- contrib/ipfilter/ip_sfil.c | 30 +- contrib/ipfilter/ip_state.c | 144 ++-- contrib/ipfilter/ip_state.h | 3 +- contrib/ipfilter/ipf.c | 13 +- contrib/ipfilter/ipl.h | 4 +- contrib/ipfilter/ipmon.c | 4 +- contrib/ipfilter/ipsend/44arp.c | 2 +- contrib/ipfilter/man/ipf.4 | 30 +- contrib/ipfilter/man/ipf.5 | 4 +- contrib/ipfilter/man/ipmon.8 | 2 +- contrib/ipfilter/man/ipnat.4 | 6 +- contrib/ipfilter/mlf_ipl.c | 2 + contrib/ipfilter/mlfk_ipl.c | 4 +- contrib/ipfilter/perl/plog | 998 ++++++++++++++++------------ contrib/ipfilter/rules/BASIC.NAT | 11 +- 33 files changed, 1449 insertions(+), 667 deletions(-) create mode 100755 contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 create mode 100644 contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 diff --git a/contrib/ipfilter/BNF b/contrib/ipfilter/BNF index cfa5423..556171d 100644 --- a/contrib/ipfilter/BNF +++ b/contrib/ipfilter/BNF @@ -11,7 +11,7 @@ proto = "proto" protocol . ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . group = [ "head" decnumber ] [ "group" decnumber ] . -block = "block" [ icmp [return-code] | "return-rst" ] . +block = "block" [ reutrn-icmp[return-code] | "return-rst" ] . auth = "auth" | "preauth" . log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . call = "call" [ "now" ] function-name . @@ -22,7 +22,7 @@ protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . srcdst = "all" | fromto . fromto = "from" object "to" object . -icmp = "return-icmp" | "return-icmp-as-dest" . +reutrn-icmp = "return-icmp" | "return-icmp-as-dest" . loglevel = facility"."priority | priority . object = addr [ port-comp | port-range ] . addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . diff --git a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 new file mode 100755 index 0000000..c232b2c --- /dev/null +++ b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 @@ -0,0 +1,61 @@ +*** ip6_input.c.orig Sun Feb 13 14:32:01 2000 +--- ip6_input.c Wed Apr 26 22:31:34 2000 +*************** +*** 121,126 **** +--- 121,127 ---- + + extern struct domain inet6domain; + extern struct ip6protosw inet6sw[]; ++ extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); + + u_char ip6_protox[IPPROTO_MAX]; + static int ip6qmaxlen = IFQ_MAXLEN; +*************** +*** 302,307 **** +--- 303,317 ---- + ip6stat.ip6s_badvers++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); + goto bad; ++ } ++ ++ if (fr_checkp) { ++ struct mbuf *m1 = m; ++ ++ if ((*fr_checkp)(ip6, sizeof(*ip6), m->m_pkthdr.rcvif, ++ 0, &m1) || !m1) ++ return; ++ ip6 = mtod(m = m1, struct ip6_hdr *); + } + + ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; +*** ip6_output.c.orig Fri Mar 10 01:57:16 2000 +--- ip6_output.c Wed Apr 26 22:34:34 2000 +*************** +*** 108,113 **** +--- 108,115 ---- + #include + #endif + ++ extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); ++ + static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options"); + + struct ip6_exthdrs { +*************** +*** 754,759 **** +--- 756,770 ---- + ip6->ip6_src.s6_addr16[1] = 0; + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) + ip6->ip6_dst.s6_addr16[1] = 0; ++ } ++ ++ if (fr_checkp) { ++ struct mbuf *m1 = m; ++ ++ if ((error = (*fr_checkp)(ip6, sizeof(*ip6), ifp, 1, &m1)) || ++ !m1) ++ goto done; ++ ip6 = mtod(m = m1, struct ip6_hdr *); + } + + #ifdef IPV6FIREWALL diff --git a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 new file mode 100644 index 0000000..90dac19 --- /dev/null +++ b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 @@ -0,0 +1,63 @@ +*** ip6_input.c.orig Sat Jul 15 07:14:34 2000 +--- ip6_input.c Thu Oct 19 17:14:37 2000 +*************** +*** 120,125 **** +--- 120,127 ---- + + extern struct domain inet6domain; + extern struct ip6protosw inet6sw[]; ++ extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, ++ struct mbuf **)); + + u_char ip6_protox[IPPROTO_MAX]; + static int ip6qmaxlen = IFQ_MAXLEN; +*************** +*** 289,294 **** +--- 291,305 ---- + ip6stat.ip6s_badvers++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); + goto bad; ++ } ++ ++ if (fr_checkp) { ++ struct mbuf *m1 = m; ++ ++ if ((*fr_checkp)(ip6, sizeof(*ip6), m->m_pkthdr.rcvif, ++ 0, &m1) || !m1) ++ return; ++ ip6 = mtod(m = m1, struct ip6_hdr *); + } + + ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; + +*** ip6_output.c.orig Sat Jul 15 07:14:35 2000 +--- ip6_output.c Thu Oct 19 17:13:53 2000 +*************** +*** 106,111 **** +--- 106,113 ---- + #include + #endif + ++ extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)); ++ + static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options"); + + struct ip6_exthdrs { +*************** +*** 787,792 **** +--- 789,803 ---- + ip6->ip6_src.s6_addr16[1] = 0; + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) + ip6->ip6_dst.s6_addr16[1] = 0; ++ } ++ ++ if (fr_checkp) { ++ struct mbuf *m1 = m; ++ ++ if ((error = (*fr_checkp)(ip6, sizeof(*ip6), ifp, 1, &m1)) || ++ !m1) ++ goto done; ++ ip6 = mtod(m = m1, struct ip6_hdr *); + } + + #ifdef IPV6FIREWALL diff --git a/contrib/ipfilter/FreeBSD-4.0/kinstall b/contrib/ipfilter/FreeBSD-4.0/kinstall index cb3c3da..7e663d2 100755 --- a/contrib/ipfilter/FreeBSD-4.0/kinstall +++ b/contrib/ipfilter/FreeBSD-4.0/kinstall @@ -2,6 +2,7 @@ # set dir=`pwd` set karch=`uname -m` +set krev=`uname -r|sed -e 's/\([0-9\.]*\)-.*/\1/'` if ( -d /sys/arch/$karch ) set archdir="/sys/arch/$karch" if ( -d /sys/$karch ) set archdir="/sys/$karch" set confdir="$archdir/conf" @@ -21,7 +22,7 @@ ln -s /usr/include/osreldate.h /sys/sys/osreldate.h echo "" echo "Patching ip6_input.c and ip6_output.c" -cat FreeBSD-4.0/ipv6-patch | (cd /sys/netinet6; patch) +cat FreeBSD-4.0/ipv6-patch-$krev | (cd /sys/netinet6; patch) set config=`(cd $confdir; /bin/ls -1t [0-9A-Z_]*) | head -1` echo -n "Kernel configuration to update [$config] " @@ -31,6 +32,11 @@ if ( "$newconfig" != "" ) then else set newconfig=$config endif +grep -q IPFILTER $confdir/$newconfig +if ($status == 0) then + echo "IPFilter already configured in kernel config file" + exit 0 +endif echo "Rewriting $newconfig..." if ( -f $confdir/$newconfig ) then mv $confdir/$newconfig $confdir/$newconfig.bak diff --git a/contrib/ipfilter/FreeBSD-4.0/unkinstall b/contrib/ipfilter/FreeBSD-4.0/unkinstall index d43ac4a..4e9caaa 100755 --- a/contrib/ipfilter/FreeBSD-4.0/unkinstall +++ b/contrib/ipfilter/FreeBSD-4.0/unkinstall @@ -3,6 +3,7 @@ # set dir=`pwd` set karch=`uname -m` +set krev=`uname -r|sed -e 's/\([0-9\.]*\)-.*/\1/'` if ( -d /sys/arch/$karch ) set archdir="/sys/arch/$karch" if ( -d /sys/$karch ) set archdir="/sys/$karch" set confdir="$archdir/conf" @@ -21,7 +22,7 @@ echo "Removing link from /usr/include/osreldate.h to /sys/sys/osreldate.h" rm /sys/sys/osreldate.h echo "Removing patch to ip6_input.c and ip6_output.c" -cat FreeBSD-4.0/ipv6-patch | (cd /sys/netinet6; patch -R) +cat FreeBSD-4.0/ipv6-patch-$krev | (cd /sys/netinet6; patch -R) set config=`(cd $confdir; /bin/ls -1t [0-9A-Z_]*) | head -1` echo -n "Kernel configuration to update [$config] " diff --git a/contrib/ipfilter/HISTORY b/contrib/ipfilter/HISTORY index da1594d..09f21ee 100644 --- a/contrib/ipfilter/HISTORY +++ b/contrib/ipfilter/HISTORY @@ -6,9 +6,11 @@ # in providing a very available location for the IP Filter home page and # distribution center. # -# Thanks to Tel.Net Media for allowing me to maintain and further develop -# IP Filter as part of my job and supplying Sun equipment for testing the -# move to 64bits and Gigabit Ethernet. +# Thanks to Hewlett Packard for making it possible to port IP Filter to +# HP-UX 11.00. +# +# Thanks to Tel.Net Media for supplying me with equipment to ensure that +# IP Filter continues to work on Solaris/sparc64. # # Thanks to BSDI for providing object files for BSD/OS 3.1 and the means # to further support development of IP Filter under BSDI. @@ -20,6 +22,50 @@ # and especially those who have found the time to port IP Filter to new # platforms. # +3.4.12 26/10/2000 - Released + +fix installing into FreeBSD-4.1 + +fix FTP proxy bug where it'd hang and make NAT slightly more efficient + +fix general compiling errors/warnings on various platforms + +don't access ICMP data fields that aren't there + +3.4.11 09/10/2000 - Released + +return NULL for IPv6 access control lists if it is disabled rather than +random garbage. + +fix for getting protocol & packet length for IPv6 packets for pullup. + +update plog script from version 0.8 to version 0.10 + +patch from Frank Volf adding fix_datacksum() to NAT code, enhancing the +capabilities for "fixing" checksums. + +3.4.10 03/09/2000 - Released + +merge patch from Frank Volf for ICMP nat handling of TCP/UDP data `errors' + +getline() adjusts linenum now + +add tcphalfclosed timeout + +fill in icmp_nextmtu field if it is defined on the platform + +RST generation fix from guido + +force 32bit compile for gcc on solaris if it can't generate 64bit code + +encase logging when fr_chksrc == 2 in #ifdef IPFILTER_LOG + +fix up line wrap problems in plog script + +fix ICMP packet handling to not drop valid ICMP errors + +freebsd 5.0 compat changes + 3.4.9 08/08/2000 - Released implement new aging mechanism in fr_tcp_age() diff --git a/contrib/ipfilter/Makefile b/contrib/ipfilter/Makefile index 947c3b6..e79eb12 100644 --- a/contrib/ipfilter/Makefile +++ b/contrib/ipfilter/Makefile @@ -5,7 +5,7 @@ # provided that this notice is preserved and due credit is given # to the original author and the contributors. # -# $Id: Makefile,v 2.11.2.3 2000/08/05 14:50:00 darrenr Exp $ +# $Id: Makefile,v 2.11.2.4 2000/10/19 15:42:56 darrenr Exp $ # BINDEST=/usr/local/bin SBINDEST=/sbin @@ -16,7 +16,7 @@ CC=gcc -Wstrict-prototypes -Wmissing-prototypes #CC=cc -Dconst= DEBUG=-g TOP=../.. -CFLAGS=-I$$(TOP) -g +CFLAGS=-I$$(TOP) CPU=`uname -m` CPUDIR=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m` # @@ -169,8 +169,8 @@ bsdi bsdos: include irix IRIX: include make setup "TARGOS=IRIX" "CPUDIR=$(CPUDIR)" - (cd IRIX/$(CPUDIR); smake build TOP=../.. $(DEST) $(MFLAGS); cd ..) - (cd IRIX/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(DEST) $(MFLAGS); cd ..) + -(SMAKE=`which smake >/dev/null 2>&1; if [ $$? -ne 0 ] ; then echo make -f Makefile.std; else echo smake; fi`; cd IRIX/$(CPUDIR); $${SMAKE} build TOP=../.. $(DEST) $(MFLAGS); cd ..) + -(SMAKE=`which smake >/dev/null 2>&1; if [ $$? -ne 0 ] ; then echo make -f Makefile.ipsend.std; else echo smake -f Makefile.ipsend; fi`; cd IRIX/$(CPUDIR); $${SMAKE} TOP=../.. $(DEST) $(MFLAGS); cd ..) linux: include make setup "TARGOS=Linux" "CPUDIR=$(CPUDIR)" @@ -184,6 +184,14 @@ setup: -if [ ! -d $(TARGOS)/$(CPUDIR) ] ; then mkdir $(TARGOS)/$(CPUDIR); fi -rm -f $(TARGOS)/$(CPUDIR)/Makefile $(TARGOS)/$(CPUDIR)/Makefile.ipsend -ln -s ../Makefile $(TARGOS)/$(CPUDIR)/Makefile + -if [ ! -f $(TARGOS)/$(CPUDIR)/Makefile.std -a \ + -f $(TARGOS)/Makefile.std ] ; then \ + ln -s ../Makefile.std $(TARGOS)/$(CPUDIR)/Makefile.std; \ + fi + -if [ ! -f $(TARGOS)/$(CPUDIR)/Makefile.ipsend.std -a \ + -f $(TARGOS)/Makefile.ipsend.std ] ; then \ + ln -s ../Makefile.ipsend.std $(TARGOS)/$(CPUDIR)/Makefile.ipsend.std; \ + fi -ln -s ../Makefile.ipsend $(TARGOS)/$(CPUDIR)/Makefile.ipsend clean: clean-include diff --git a/contrib/ipfilter/common.c b/contrib/ipfilter/common.c index 935f3fb..d7706bd 100644 --- a/contrib/ipfilter/common.c +++ b/contrib/ipfilter/common.c @@ -274,7 +274,7 @@ int linenum; return 0; if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) { (*seg)++; - if (isdigit(***seg) && *(*seg + 2)) { + if (isalnum(***seg) && *(*seg + 2)) { if (portnum(**seg, pp, linenum) == 0) return -1; (*seg)++; diff --git a/contrib/ipfilter/fil.c b/contrib/ipfilter/fil.c index 91b5108..b85dcf4 100644 --- a/contrib/ipfilter/fil.c +++ b/contrib/ipfilter/fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $"; #endif #include @@ -274,6 +274,16 @@ fr_info_t *fin; int minicmpsz = sizeof(struct icmp); icmphdr_t *icmp; + if (fin->fin_dlen > 1) + fin->fin_data[0] = *(u_short *)tcp; + + if ((!(plen >= hlen + minicmpsz) && !off) || + (off && off < sizeof(struct icmp))) { + fi->fi_fl |= FI_SHORT; + if (fin->fin_dlen < 2) + break; + } + icmp = (icmphdr_t *)tcp; if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || @@ -291,11 +301,6 @@ fr_info_t *fin; icmp->icmp_type == ICMP_MASKREPLY)) minicmpsz = 12; - if ((!(plen >= hlen + minicmpsz) && !off) || - (off && off < sizeof(struct icmp))) - fi->fi_fl |= FI_SHORT; - if (fin->fin_dlen > 1) - fin->fin_data[0] = *(u_short *)tcp; break; } case IPPROTO_TCP : @@ -740,6 +745,7 @@ int out; #ifdef _KERNEL mb_t *mc = NULL; + int p, len; # if !defined(__SVR4) && !defined(__svr4__) # ifdef __sgi char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; @@ -764,13 +770,26 @@ int out; } # endif /* CSUM_DELAY_DATA */ +# ifdef USE_INET6 + if (v == 6) { + len = ntohs(((ip6_t*)ip)->ip6_plen); + p = ((ip6_t *)ip)->ip6_nxt; + } else +# endif + { + p = ip->ip_p; + len = ip->ip_len; + } - if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || - ip->ip_p == IPPROTO_ICMP)) { + if ((p == IPPROTO_TCP || p == IPPROTO_UDP || p == IPPROTO_ICMP +# ifdef USE_INET6 + || (v == 6 && p == IPPROTO_ICMPV6) +# endif + )) { int plen = 0; - if ((ip->ip_off & IP_OFFMASK) == 0) - switch(ip->ip_p) + if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0) + switch(p) { case IPPROTO_TCP: plen = sizeof(tcphdr_t); @@ -780,10 +799,13 @@ int out; break; /* 96 - enough for complete ICMP error IP header */ case IPPROTO_ICMP: +# ifdef USE_INET6 + case IPPROTO_ICMPV6 : +# endif plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); break; } - up = MIN(hlen + plen, ip->ip_len); + up = MIN(hlen + plen, len); if (up > m->m_len) { # ifdef __sgi @@ -830,8 +852,8 @@ int out; ip->ip_id = ntohs(ip->ip_id); changed = 0; - fin->fin_v = v; fin->fin_ifp = ifp; + fin->fin_v = v; fin->fin_out = out; fin->fin_mp = mp; fr_makefrip(hlen, ip, fin); @@ -1376,7 +1398,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $ + * $Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1855,7 +1877,7 @@ size_t c; int err; #if SOLARIS - if (copyin(a, &ca, sizeof(ca))) + if (copyin(a, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(a, &ca, sizeof(ca)); @@ -1875,7 +1897,7 @@ size_t c; int err; #if SOLARIS - if (copyin(b, &ca, sizeof(ca))) + if (copyin(b, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(b, &ca, sizeof(ca)); @@ -1969,6 +1991,15 @@ friostat_t *fiop; fiop->f_acctin6[1] = ipacct6[0][1]; fiop->f_acctout6[0] = ipacct6[1][0]; fiop->f_acctout6[1] = ipacct6[1][1]; +#else + fiop->f_fin6[0] = NULL; + fiop->f_fin6[1] = NULL; + fiop->f_fout6[0] = NULL; + fiop->f_fout6[1] = NULL; + fiop->f_acctin6[0] = NULL; + fiop->f_acctin6[1] = NULL; + fiop->f_acctout6[0] = NULL; + fiop->f_acctout6[1] = NULL; #endif fiop->f_active = fr_active; fiop->f_froute[0] = ipl_frouteok[0]; diff --git a/contrib/ipfilter/ip_auth.h b/contrib/ipfilter/ip_auth.h index b543318..681a6e5 100644 --- a/contrib/ipfilter/ip_auth.h +++ b/contrib/ipfilter/ip_auth.h @@ -5,7 +5,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_auth.h,v 2.3.2.1 2000/05/22 10:26:11 darrenr Exp $ + * $Id: ip_auth.h,v 2.3.2.2 2000/10/19 15:38:44 darrenr Exp $ * */ #ifndef __IP_AUTH_H__ @@ -46,8 +46,6 @@ typedef struct fr_authstat { extern frentry_t *ipauth; extern struct fr_authstat fr_authstats; extern int fr_defaultauthage; -extern int fr_authstart; -extern int fr_authend; extern int fr_authsize; extern int fr_authused; extern int fr_auth_lock; diff --git a/contrib/ipfilter/ip_compat.h b/contrib/ipfilter/ip_compat.h index ba9e014..2369cf0 100644 --- a/contrib/ipfilter/ip_compat.h +++ b/contrib/ipfilter/ip_compat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.26.2.4 2000/08/13 03:51:03 darrenr Exp $ + * $Id: ip_compat.h,v 2.26.2.6 2000/10/19 15:39:05 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -263,6 +263,12 @@ union i6addr { #if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) +# ifdef IPFILTER_LKM +# include +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include +# endif # if __FreeBSD__ < 3 # include # else @@ -288,6 +294,19 @@ union i6addr { # define ATOMIC_DEC32 ATOMIC_DEC # define ATOMIC_DEC16 ATOMIC_DEC #endif +#ifdef __sgi +# define hz HZ +# include +# define IPF_LOCK_PL plhi +# include +#undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; +# undef MUTEX_INIT +# undef MUTEX_DESTROY +#endif #ifdef KERNEL # if SOLARIS # if SOLARIS2 >= 6 @@ -337,8 +356,8 @@ union i6addr { # define MUTEX_DESTROY(x) mutex_destroy(x) # define MUTEX_EXIT(x) mutex_exit(x) # define MTOD(m,t) (t)((m)->b_rptr) -# define IRCOPY(a,b,c) copyin((a), (b), (c)) -# define IWCOPY(a,b,c) copyout((a), (b), (c)) +# define IRCOPY(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) # define IRCOPYPTR ircopyptr # define IWCOPYPTR iwcopyptr # define FREE_MB_T(m) freemsg(m) @@ -383,15 +402,6 @@ extern ill_t *get_unit __P((char *, int)); # define IFNAME(x) ((ill_t *)x)->ill_name # else /* SOLARIS */ # if defined(__sgi) -# define hz HZ -# include -# define IPF_LOCK_PL plhi -# include -#undef kmutex_t -typedef struct { - lock_t *l; - int pl; -} kmutex_t; # define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ (x)++; MUTEX_EXIT(&ipf_rw); } # define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ @@ -404,8 +414,8 @@ typedef struct { # define MUTEX_DOWNGRADE(x) ; # define RWLOCK_EXIT(x) MUTEX_EXIT(x) # define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); -# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) -# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l) +# define MUTEX_INIT(x,y,z) (x)->l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->l) # else /* __sgi */ # define ATOMIC_INC(x) (x)++ # define ATOMIC_DEC(x) (x)-- diff --git a/contrib/ipfilter/ip_fil.c b/contrib/ipfilter/ip_fil.c index 2e8af26..9253775 100644 --- a/contrib/ipfilter/ip_fil.c +++ b/contrib/ipfilter/ip_fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.15 2000/08/05 14:49:08 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.17 2000/10/19 15:39:42 darrenr Exp $"; #endif #ifndef SOLARIS @@ -171,6 +171,9 @@ struct callout_handle ipfr_slowtimer_ch; # include struct callout ipfr_slowtimer_ch; #endif +#if defined(__sgi) && defined(_KERNEL) +toid_t ipfr_slowtimer_ch; +#endif #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include @@ -318,7 +321,7 @@ pfil_error: callout_init(&ipfr_slowtimer_ch); callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); # else -# if (__FreeBSD_version >= 300000) && defined(_KERNEL) +# if (__FreeBSD_version >= 300000) || defined(__sgi) ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); # else timeout(ipfr_slowtimer, NULL, hz/2); @@ -348,7 +351,7 @@ int ipldetach() untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); # else # ifdef __sgi - untimeout(ipfr_slowtimer); + untimeout(ipfr_slowtimer_ch); # else untimeout(ipfr_slowtimer, NULL); # endif @@ -975,8 +978,10 @@ fr_info_t *fin; if (m == NULL) return -1; - if (tcp->th_flags & TH_SYN) - tlen = 1; + tlen = oip->ip_len - fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + #ifdef USE_INET6 hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); #else @@ -997,11 +1002,16 @@ fr_info_t *fin; tcp2->th_sport = tcp->th_dport; tcp2->th_dport = tcp->th_sport; - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); + if (tcp->th_flags & TH_ACK) { + tcp2->th_seq = tcp->th_ack; + tcp2->th_flags = TH_RST; + } else { + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_flags = TH_RST|TH_ACK; + } tcp2->th_off = sizeof(*tcp2) >> 2; - tcp2->th_flags = TH_RST|TH_ACK; # ifdef USE_INET6 if (fin->fin_v == 6) { ip6->ip6_plen = htons(sizeof(struct tcphdr)); @@ -1143,7 +1153,12 @@ int dst; m_freem(m); return ENOBUFS; } +# ifdef M_TRAILINGSPACE + m->m_len = 0; + avail = M_TRAILINGSPACE(m); +# else avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; +# endif xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), avail - hlen - sizeof(*icmp) - max_linkhdr); if (dst == 0) { @@ -1177,6 +1192,12 @@ int dst; icmp->icmp_type = type; icmp->icmp_code = fin->fin_icode; icmp->icmp_cksum = 0; +#ifdef icmp_nextmtu + if (type == ICMP_UNREACH && + fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) + icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu); +#endif + if (avail) { bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); avail -= MIN(ohlen, avail); diff --git a/contrib/ipfilter/ip_frag.c b/contrib/ipfilter/ip_frag.c index 5019c60..1cb86c1 100644 --- a/contrib/ipfilter/ip_frag.c +++ b/contrib/ipfilter/ip_frag.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.4 2000/06/06 15:49:15 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.5 2000/10/19 15:39:58 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) @@ -214,7 +214,7 @@ u_int pass; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); RWLOCK_EXIT(&ipf_frag); @@ -231,7 +231,7 @@ nat_t *nat; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_natfrag); ipf = ipfr_new(ip, fin, pass, ipfr_nattab); if (ipf != NULL) { @@ -328,13 +328,16 @@ fr_info_t *fin; ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { nat = ipf->ipfr_data; - /* - * This is the last fragment for this packet. - */ - if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { - nat->nat_data = NULL; - ipf->ipfr_data = NULL; - } + if (nat->nat_ifp == fin->fin_ifp) { + /* + * This is the last fragment for this packet. + */ + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + nat->nat_data = NULL; + ipf->ipfr_data = NULL; + } + } else + nat = NULL; } else nat = NULL; RWLOCK_EXIT(&ipf_natfrag); diff --git a/contrib/ipfilter/ip_frag.h b/contrib/ipfilter/ip_frag.h index 6a3bd2c..61b88aa 100644 --- a/contrib/ipfilter/ip_frag.h +++ b/contrib/ipfilter/ip_frag.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.4 2000/03/13 22:10:21 darrenr Exp $ + * $Id: ip_frag.h,v 2.4.2.1 2000/10/19 15:40:13 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -60,6 +60,6 @@ extern void ipfr_slowtimer __P((void *)); # endif #else extern int ipfr_slowtimer __P((void)); -#endif +#endif /* (BSD >= 199306) || SOLARIS */ #endif /* __IP_FIL_H__ */ diff --git a/contrib/ipfilter/ip_ftp_pxy.c b/contrib/ipfilter/ip_ftp_pxy.c index 84dc8b9..ffa7c1b 100644 --- a/contrib/ipfilter/ip_ftp_pxy.c +++ b/contrib/ipfilter/ip_ftp_pxy.c @@ -2,7 +2,7 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.13 2000/08/07 12:35:27 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.7.2.17 2000/10/19 15:40:40 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -146,6 +146,7 @@ int dlen; } else return 0; a5 >>= 8; + a5 &= 0xff; /* * Calculate new address parts for PORT command */ @@ -214,7 +215,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif ip->ip_len += inc; } @@ -441,7 +442,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif /* SOLARIS || defined(__sgi) */ ip->ip_len += inc; } @@ -670,15 +671,18 @@ int rv; while ((rptr < wptr) && (*rptr != '\r')) rptr++; - if ((*rptr == '\r') && (rptr + 1 < wptr)) { - if (*(rptr + 1) == '\n') { - rptr += 2; - f->ftps_junk = 0; + if (*rptr == '\r') { + if (rptr + 1 < wptr) { + if (*(rptr + 1) == '\n') { + rptr += 2; + f->ftps_junk = 0; + } else + rptr++; } else - rptr++; + break; } - f->ftps_rptr = rptr; } + f->ftps_rptr = rptr; if (rptr == wptr) { rptr = wptr = f->ftps_buf; @@ -762,5 +766,7 @@ char **ptr; j += c - '0'; } *ptr = s; + i &= 0xff; + j &= 0xff; return (i << 8) | j; } diff --git a/contrib/ipfilter/ip_nat.c b/contrib/ipfilter/ip_nat.c index bbcff77..d52f48d 100644 --- a/contrib/ipfilter/ip_nat.c +++ b/contrib/ipfilter/ip_nat.c @@ -9,7 +9,7 @@ */ #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.37.2.21 2000/08/12 07:32:40 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.25 2000/10/25 10:38:47 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -118,6 +118,7 @@ u_int ipf_nattable_sz = NAT_TABLE_SZ; u_int ipf_natrules_sz = NAT_SIZE; u_int ipf_rdrrules_sz = RDR_SIZE; u_int ipf_hostmap_sz = HOSTMAP_SIZE; +int nat_wilds = 0; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; ipnat_t **nat_rules = NULL; @@ -143,6 +144,7 @@ static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t)); +static void nat_tabmove __P((nat_t *, u_int)); static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, struct in_addr)); @@ -300,10 +302,9 @@ struct hostmap *hm; } -void fix_outcksum(sp, n , len) +void fix_outcksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -326,10 +327,9 @@ int len; } -void fix_incksum(sp, n , len) +void fix_incksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -357,6 +357,38 @@ int len; /* + * fix_datacksum is used *only* for the adjustments of checksums in the data + * section of an IP packet. + * + * The only situation in which you need to do this is when NAT'ing an + * ICMP error message. Such a message, contains in its body the IP header + * of the original IP packet, that causes the error. + * + * You can't use fix_incksum or fix_outcksum in that case, because for the + * kernel the data section of the ICMP error is just data, and no special + * processing like hardware cksum or ntohs processing have been done by the + * kernel on the data section. + */ +void fix_datacksum(sp, n) +u_short *sp; +u_32_t n; +{ + register u_short sumshort; + register u_32_t sum1; + + if (!n) + return; + + sum1 = (~ntohs(*sp)) & 0xffff; + sum1 += (n); + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + /* Again */ + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + sumshort = ~(u_short)sum1; + *(sp) = htons(sumshort); +} + +/* * How the NAT is organised and works. * * Inside (interface y) NAT Outside (interface x) @@ -856,8 +888,8 @@ caddr_t data; /* * Initialize all these so that nat_delete() doesn't cause a crash. */ - nat->nat_hstart[0] = NULL; - nat->nat_hstart[1] = NULL; + nat->nat_phnext[0] = NULL; + nat->nat_phnext[1] = NULL; fr = nat->nat_fr; nat->nat_fr = NULL; aps = nat->nat_aps; @@ -969,22 +1001,16 @@ junkput: static void nat_delete(natd) struct nat *natd; { - register struct nat **natp, *nat; struct ipnat *ipn; - for (natp = natd->nat_hstart[0]; natp && (nat = *natp); - natp = &nat->nat_hnext[0]) - if (nat == natd) { - *natp = nat->nat_hnext[0]; - break; - } - - for (natp = natd->nat_hstart[1]; natp && (nat = *natp); - natp = &nat->nat_hnext[1]) - if (nat == natd) { - *natp = nat->nat_hnext[1]; - break; - } + if (natd->nat_flags & FI_WILDP) + nat_wilds--; + if (natd->nat_hnext[0]) + natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; + *natd->nat_phnext[0] = natd->nat_hnext[0]; + if (natd->nat_hnext[1]) + natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; + *natd->nat_phnext[1] = natd->nat_hnext[1]; if (natd->nat_fr != NULL) { ATOMIC_DEC32(natd->nat_fr->fr_ref); @@ -1029,7 +1055,7 @@ static int nat_flushtable() { register nat_t *nat, **natp; register int j = 0; - + /* * ALL NAT mappings deleted, so lets just make the deletions * quicker. @@ -1121,6 +1147,8 @@ int direction; bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; + if (flags & FI_WILDP) + nat_wilds++; /* * Search the current table for a match. */ @@ -1443,16 +1471,22 @@ nat_t *nat; nat->nat_next = nat_instances; nat_instances = nat; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, ipf_nattable_sz); natp = &nat_table[0][hv]; - nat->nat_hstart[0] = natp; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, ipf_nattable_sz); natp = &nat_table[1][hv]; - nat->nat_hstart[1] = natp; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; @@ -1560,12 +1594,16 @@ int dir; u_32_t sum1, sum2, sumd; struct in_addr in; icmphdr_t *icmp; + udphdr_t *udp; nat_t *nat; ip_t *oip; int flags = 0; if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) return NULL; + /* + * nat_icmplookup() will return NULL for `defective' packets. + */ if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) return NULL; *nflags = IPN_ICMPERR; @@ -1575,16 +1613,33 @@ int dir; flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) flags = IPN_UDP; + udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); /* * Need to adjust ICMP header to include the real IP#'s and * port #'s. Only apply a checksum change relative to the - * IP address change is it will be modified again in ip_natout + * IP address change as it will be modified again in ip_natout * for both address and port. Two checksum changes are * necessary for the two header address changes. Be careful * to only modify the checksum once for the port # and twice * for the IP#. */ + /* + * Step 1 + * Fix the IP addresses in the offending IP packet. You also need + * to adjust the IP header checksum of that offending IP packet + * and the ICMP checksum of the ICMP error message itself. + * + * Unfortunately, for UDP and TCP, the IP addresses are also contained + * in the pseudo header that is used to compute the UDP resp. TCP + * checksum. So, we must compensate that as well. Even worse, the + * change in the UDP and TCP checksums require yet another + * adjustment of the ICMP checksum of the ICMP error message. + * + * For the moment we forget about TCP, because that checksum is not + * in the first 8 bytes, so it will not be available in most cases. + */ + if (nat->nat_dir == NAT_OUTBOUND) { sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); in = nat->nat_inip; @@ -1600,19 +1655,117 @@ int dir; CALC_SUMD(sum1, sum2, sumd); if (nat->nat_dir == NAT_OUTBOUND) { - fix_incksum(&oip->ip_sum, sumd, 0); + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set. + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + } +#endif } else { - fix_outcksum(&oip->ip_sum, sumd, 0); + + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); + +/* XXX FV : without having looked at Solaris source code, it seems unlikely + * that SOLARIS would compensate this in the kernel (a body of an IP packet + * in the data section of an ICMP packet). I have the feeling that this should + * be unconditional, but I'm not in a position to check. + */ #if !SOLARIS && !defined(__sgi) - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_incksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + }; +#endif + #endif } @@ -1623,23 +1776,98 @@ int dir; * XXX - what if this is bogus hl and we go off the end ? * In this case, nat_icmpinlookup() will have returned NULL. */ - tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); + tcp = (tcphdr_t *)udp; + + /* + * Step 2 : + * For offending TCP/UDP IP packets, translate the ports as + * well, based on the NAT specification. Of course such + * a change must be reflected in the ICMP checksum as well. + * + * Advance notice : Now it becomes complicated :-) + * + * Since the port fields are part of the TCP/UDP checksum + * of the offending IP packet, you need to adjust that checksum + * as well... but, if you change, you must change the icmp + * checksum *again*, to reflect that change. + * + * To further complicate: the TCP checksum is not in the first + * 8 bytes of the offending ip packet, so it most likely is not + * available (we might have to fix that if the encounter a + * device that returns more than 8 data bytes on icmp error) + */ if (nat->nat_dir == NAT_OUTBOUND) { if (tcp->th_sport != nat->nat_inport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_sport); sum2 = ntohs(nat->nat_inport); CALC_SUMD(sum1, sum2, sumd); tcp->th_sport = nat->nat_inport; - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + fix_outcksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP packet + * flows the other direction compared to the + * ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to + * compensate UDP checksum + * adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } } } else { + if (tcp->th_dport != nat->nat_outport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_dport); sum2 = ntohs(nat->nat_outport); CALC_SUMD(sum1, sum2, sumd); tcp->th_dport = nat->nat_outport; - fix_incksum(&icmp->icmp_cksum, sumd, 0); + fix_incksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP + * packet flows the other direction compared + * to the ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate + * UDP checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } } } } @@ -1664,30 +1892,92 @@ register u_int flags, p; struct in_addr src , mapdst; u_32_t ports; { - register u_short sport, mapdport; + register u_short sport, dport; register nat_t *nat; register int nflags; + register u_32_t dst; u_int hv; - mapdport = ports >> 16; + dst = mapdst.s_addr; + dport = ports >> 16; sport = ports & 0xffff; flags &= IPN_TCPUDP; - hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz); + hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; if ((!ifp || ifp == nat->nat_ifp) && nat->nat_oip.s_addr == src.s_addr && - nat->nat_outip.s_addr == mapdst.s_addr && + nat->nat_outip.s_addr == dst && (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && - ((nat->nat_outport == mapdport) || - (nflags & FI_W_SPORT))))) + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[1][hv]; + for (; nat; nat = nat->nat_hnext[1]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if (nat->nat_oip.s_addr != src.s_addr || + nat->nat_outip.s_addr != dst) + continue; + if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; +} + + +static void nat_tabmove(nat, hv) +nat_t *nat; +u_int hv; +{ + nat_t **natp; + + /* + * Remove the NAT entry from the old location + */ + if (nat->nat_hnext[0]) + nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; + *nat->nat_phnext[0] = nat->nat_hnext[0]; + + if (nat->nat_hnext[1]) + nat->nat_hnext[0]->nat_phnext[1] = nat->nat_phnext[1]; + *nat->nat_phnext[1] = nat->nat_hnext[1]; + + natp = &nat_table[0][hv]; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; + nat->nat_hnext[0] = *natp; + *natp = nat; + + /* + * Add into the NAT table in the new position + */ + natp = &nat_table[1][hv]; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; + nat->nat_hnext[1] = *natp; + *natp = nat; } @@ -1706,19 +1996,21 @@ u_32_t ports; register u_short sport, dport; register nat_t *nat; register int nflags; + u_32_t srcip; u_int hv; sport = ports & 0xffff; dport = ports >> 16; flags &= IPN_TCPUDP; + srcip = src.s_addr; - hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz); + hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_inip.s_addr == src.s_addr && + nat->nat_inip.s_addr == srcip && nat->nat_oip.s_addr == dst.s_addr && (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || @@ -1726,7 +2018,32 @@ u_32_t ports; (nat->nat_oport == dport || nflags & FI_W_DPORT)))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[0][hv]; + for (; nat; nat = nat->nat_hnext[0]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if ((nat->nat_inip.s_addr != srcip) || + (nat->nat_oip.s_addr != dst.s_addr)) + continue; + if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } @@ -1862,6 +2179,7 @@ fr_info_t *fin; nat->nat_outport = sport; nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -1942,16 +2260,16 @@ maskloop: CALC_SUMD(s1, s2, sumd); if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, sumd, 0); + fix_incksum(&ip->ip_sum, sumd); else - fix_outcksum(&ip->ip_sum, sumd, 0); + fix_outcksum(&ip->ip_sum, sumd); } #if SOLARIS || defined(__sgi) else { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); } #endif ip->ip_src = nat->nat_outip; @@ -1995,11 +2313,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_outcksum(csump, nat->nat_sumd[1]); else - fix_incksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_incksum(csump, nat->nat_sumd[1]); } } @@ -2076,6 +2392,7 @@ fr_info_t *fin; nat->nat_outport = dport; nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -2153,9 +2470,9 @@ maskloop: */ #if SOLARIS || defined(__sgi) if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); #endif if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { @@ -2196,11 +2513,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, nat->nat_sumd[0], - 0); + fix_incksum(csump, nat->nat_sumd[0]); else - fix_outcksum(csump, nat->nat_sumd[0], - 0); + fix_outcksum(csump, nat->nat_sumd[0]); } } ATOMIC_INCL(nat_stats.ns_mapped[0]); diff --git a/contrib/ipfilter/ip_nat.h b/contrib/ipfilter/ip_nat.h index 26fed25..c2ff100 100644 --- a/contrib/ipfilter/ip_nat.h +++ b/contrib/ipfilter/ip_nat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.17.2.6 2000/07/15 14:50:06 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.9 2000/10/19 15:44:04 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -81,7 +81,7 @@ typedef struct nat { struct hostmap *nat_hm; struct nat *nat_next; struct nat *nat_hnext[2]; - struct nat **nat_hstart[2]; + struct nat **nat_phnext[2]; void *nat_ifp; int nat_dir; char nat_ifname[IFNAMSIZ]; @@ -141,6 +141,11 @@ typedef struct ipnat { #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) #define NAT_MAPBLK 0x04 +/* 0x100 reserved for FI_W_SPORT */ +/* 0x200 reserved for FI_W_DPORT */ +/* 0x400 reserved for FI_W_SADDR */ +/* 0x800 reserved for FI_W_DADDR */ +/* 0x1000 reserved for FI_W_NEWFR */ #define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ #define USABLE_PORTS (65536 - MAPBLK_MINPORT) @@ -293,7 +298,8 @@ extern int ip_natout __P((ip_t *, fr_info_t *)); extern int ip_natin __P((ip_t *, fr_info_t *)); extern void ip_natunload __P((void)), ip_natexpire __P((void)); extern void nat_log __P((struct nat *, u_int)); -extern void fix_incksum __P((u_short *, u_32_t, int)); -extern void fix_outcksum __P((u_short *, u_32_t, int)); +extern void fix_incksum __P((u_short *, u_32_t)); +extern void fix_outcksum __P((u_short *, u_32_t)); +extern void fix_datacksum __P((u_short *, u_32_t)); #endif /* __IP_NAT_H__ */ diff --git a/contrib/ipfilter/ip_raudio_pxy.c b/contrib/ipfilter/ip_raudio_pxy.c index 18ca474..d801410 100644 --- a/contrib/ipfilter/ip_raudio_pxy.c +++ b/contrib/ipfilter/ip_raudio_pxy.c @@ -1,5 +1,5 @@ /* - * $Id: ip_raudio_pxy.c,v 1.7.2.1 2000/05/06 11:19:33 darrenr Exp $ + * $Id: ip_raudio_pxy.c,v 1.7.2.2 2000/09/03 00:23:12 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -171,8 +171,8 @@ nat_t *nat; tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; struct in_addr swa, swb; - u_int a1, a2, a3, a4; int off, dlen, slen; + int a1, a2, a3, a4; u_short sp, dp; fr_info_t fi; tcp_seq seq; diff --git a/contrib/ipfilter/ip_sfil.c b/contrib/ipfilter/ip_sfil.c index 38e5e3e..7d4ea2d 100644 --- a/contrib/ipfilter/ip_sfil.c +++ b/contrib/ipfilter/ip_sfil.c @@ -9,7 +9,7 @@ */ #if !defined(lint) static const char sccsid[] = "%W% %G% (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_sfil.c,v 2.23.2.6 2000/08/07 12:36:19 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_sfil.c,v 2.23.2.8 2000/10/19 15:42:10 darrenr Exp $"; #endif #include @@ -441,7 +441,7 @@ caddr_t data; } group = fp->fr_group; - if (group != NULL) { + if (group != 0) { fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL); if (fg == NULL) { error = ESRCH; @@ -613,7 +613,7 @@ caddr_t data; fixskip(fprev, f, 1); f->fr_grp = NULL; group = f->fr_grhead; - if (group != NULL) + if (group != 0) fg = fr_addgroup(group, f, unit, set); } else error = ENOMEM; @@ -688,7 +688,7 @@ ip_t *oip; fr_info_t *fin; { tcphdr_t *tcp, *tcp2; - int tlen = 0, hlen; + int tlen, hlen; mblk_t *m; #ifdef USE_INET6 ip6_t *ip6, *oip6 = (ip6_t *)oip; @@ -698,8 +698,7 @@ fr_info_t *fin; tcp = (struct tcphdr *)fin->fin_dp; if (tcp->th_flags & TH_RST) return -1; - if (tcp->th_flags & TH_SYN) - tlen = 1; + tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; #ifdef USE_INET6 if (fin->fin_v == 6) hlen = sizeof(ip6_t); @@ -717,8 +716,15 @@ fr_info_t *fin; tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); tcp2->th_dport = tcp->th_sport; tcp2->th_sport = tcp->th_dport; - tcp2->th_ack = htonl(ntohl(tcp->th_seq) + tlen); - tcp2->th_seq = tcp->th_ack; + if (tcp->th_flags & TH_ACK) { + tcp2->th_seq = tcp->th_ack; + tcp2->th_flags = TH_RST|TH_ACK; + } else { + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_flags = TH_RST; + } tcp2->th_off = sizeof(struct tcphdr) >> 2; tcp2->th_flags = TH_RST|TH_ACK; @@ -791,8 +797,9 @@ int dst; struct icmp *icmp; mblk_t *m, *mb; int hlen, code; - qif_t *qif; + qif_t *qif; u_short sz; + ill_t *il; #ifdef USE_INET6 ip6_t *ip6, *oip6; #endif @@ -851,6 +858,11 @@ int dst; icmp->icmp_type = type; icmp->icmp_code = code; icmp->icmp_cksum = 0; +#ifdef icmp_nextmtu + if (type == ICMP_UNREACH && (il = qif->qf_ill) && + fin->fin_icode == ICMP_UNREACH_NEEDFRAG) + icmp->icmp_nextmtu = htons(il->ill_max_frag); +#endif #ifdef USE_INET6 if (oip->ip_v == 6) { diff --git a/contrib/ipfilter/ip_state.c b/contrib/ipfilter/ip_state.c index f05c887..4f7460e 100644 --- a/contrib/ipfilter/ip_state.c +++ b/contrib/ipfilter/ip_state.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.17 2000/08/08 16:01:03 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.22 2000/10/26 10:41:29 darrenr Exp $"; #endif #include @@ -106,6 +106,7 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.17 2000/08/08 16:01:03 static ipstate_t **ips_table = NULL; static ipstate_t *ips_list = NULL; static int ips_num = 0; +static int ips_wild = 0; static ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern KRWLOCK_T ipf_state, ipf_mutex; @@ -123,6 +124,7 @@ static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); static void fr_delstate __P((ipstate_t *)); static int fr_state_remove __P((caddr_t)); +static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int)); int fr_stputent __P((caddr_t)); int fr_stgetent __P((caddr_t)); void fr_stinsert __P((ipstate_t *)); @@ -135,7 +137,8 @@ u_long fr_tcpidletimeout = FIVE_DAYS, fr_tcpclosewait = 2 * TCP_MSL, fr_tcplastack = 2 * TCP_MSL, fr_tcptimeout = 2 * TCP_MSL, - fr_tcpclosed = 1, + fr_tcpclosed = 120, + fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */ fr_udptimeout = 240, fr_icmptimeout = 120; int fr_statemax = IPSTATE_MAX, @@ -240,9 +243,12 @@ caddr_t data; for (sp = ips_list; sp; sp = sp->is_next) if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && - !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) && - !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) && - !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) { + !bcmp((char *)&sp->is_src, (char *)&st.is_src, + sizeof(st.is_src)) && + !bcmp((char *)&sp->is_dst, (char *)&st.is_src, + sizeof(st.is_dst)) && + !bcmp((char *)&sp->is_ps, (char *)&st.is_ps, + sizeof(st.is_ps))) { WRITE_ENTER(&ipf_state); #ifdef IPFILTER_LOG ipstate_log(sp, ISL_REMOVE); @@ -590,8 +596,8 @@ u_int flags; hv += tcp->th_dport; hv += tcp->th_sport; } - is->is_send = ntohl(tcp->th_seq) + ip->ip_len - - fin->fin_hlen - (tcp->th_off << 2) + + is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - + (tcp->th_off << 2) + ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); is->is_maxsend = is->is_send; @@ -660,6 +666,8 @@ u_int flags; is->is_flags = fin->fin_fi.fi_fl & FI_CMP; is->is_flags |= FI_CMP << 4; is->is_flags |= flags & (FI_WILDP|FI_WILDA); + if (flags & (FI_WILDP|FI_WILDA)) + ips_wild++; is->is_ifp[1 - out] = NULL; is->is_ifp[out] = fin->fin_ifp; #ifdef _KERNEL @@ -718,6 +726,7 @@ tcphdr_t *tcp; ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); + MUTEX_ENTER(&is->is_lock); if (fdata->td_end == 0) { /* * Must be a (outgoing) SYN-ACK in reply to a SYN. @@ -783,12 +792,11 @@ tcphdr_t *tcp; /* * Nearing end of connection, start timeout. */ - MUTEX_ENTER(&is->is_lock); /* source ? 0 : 1 -> !source */ fr_tcp_age(&is->is_age, is->is_state, fin, !source); - MUTEX_EXIT(&is->is_lock); ret = 1; } + MUTEX_EXIT(&is->is_lock); return ret; } @@ -892,6 +900,7 @@ tcphdr_t *tcp; is->is_maxdend = is->is_dend + 1; } is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); + ips_wild--; } ret = -1; @@ -983,7 +992,7 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with * an ICMP error header. */ - if (((ip->ip_v != 4) && (ip->ip_hl != 5)) || + if (((ip->ip_v != 4) || (ip->ip_hl != 5)) || (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; ic = (struct icmp *)fin->fin_dp; @@ -1037,8 +1046,8 @@ fr_info_t *fin; * the IP6EQ and IP6NEQ macros produce the wrong results because * of the 'junk' in the unused part of the union */ - bzero(&src, sizeof(src)); - bzero(&dst, sizeof(dst)); + bzero((char *)&src, sizeof(src)); + bzero((char *)&dst, sizeof(dst)); if (oip->ip_p == IPPROTO_ICMP) { icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); @@ -1158,6 +1167,38 @@ fr_info_t *fin; return NULL; } + +static void fr_ipsmove(isp, is, hv) +ipstate_t **isp, *is; +u_int hv; +{ + u_int hvm; + + hvm = is->is_hv; + /* + * Remove the hash from the old location... + */ + if (is->is_hnext) + is->is_hnext->is_phnext = isp; + *isp = is->is_hnext; + if (ips_table[hvm] == NULL) + ips_stats.iss_inuse--; + + /* + * ...and put the hash in the new one. + */ + hvm = hv % fr_statesize; + isp = &ips_table[hvm]; + if (*isp) + (*isp)->is_phnext = &is->is_hnext; + else + ips_stats.iss_inuse++; + is->is_phnext = isp; + is->is_hnext = *isp; + *isp = is; +} + + /* * Check if a packet has a registered state. */ @@ -1240,7 +1281,7 @@ fr_info_t *fin; break; case IPPROTO_TCP : { - register u_short dport = tcp->th_dport, sport = tcp->th_sport; + register u_short dport, sport; register int i; i = tcp->th_flags; @@ -1250,57 +1291,42 @@ fr_info_t *fin; if ((i & TH_RST) && ((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST)) break; + case IPPROTO_UDP : + dport = tcp->th_dport; + sport = tcp->th_sport; tryagain = 0; -retry_tcp: - hvm = hv % fr_statesize; - WRITE_ENTER(&ipf_state); - for (isp = &ips_table[hvm]; (is = *isp); - isp = &is->is_hnext) - - - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, tcp)) { - if (fr_tcpstate(is, fin, ip, tcp)) - break; - is = NULL; - break; - } - if (is != NULL) - break; - RWLOCK_EXIT(&ipf_state); hv += dport; hv += sport; - if (tryagain == 0) { - tryagain = 1; - goto retry_tcp; - } - break; - } - case IPPROTO_UDP : - { - register u_short dport = tcp->th_dport, sport = tcp->th_sport; - - tryagain = 0; -retry_udp: - hvm = hv % fr_statesize; - /* - * Nothing else to match on but ports. and IP#'s - */ READ_ENTER(&ipf_state); - for (is = ips_table[hvm]; is; is = is->is_hnext) +retry_tcpudp: + hvm = hv % fr_statesize; + for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) if ((is->is_p == pr) && (is->is_v == v) && fr_matchsrcdst(is, src, dst, fin, tcp)) { - is->is_age = fr_udptimeout; + if ((pr == IPPROTO_TCP)) { + if (!fr_tcpstate(is, fin, ip, tcp)) { + continue; + } + } break; } - if (is != NULL) + if (is != NULL) { + if (tryagain && + !(is->is_flags & (FI_WILDP|FI_WILDA))) { + hv += dport; + hv += sport; + fr_ipsmove(isp, is, hv); + MUTEX_DOWNGRADE(&ipf_state); + } break; + } RWLOCK_EXIT(&ipf_state); - hv += dport; - hv += sport; - if (tryagain == 0) { + if (!tryagain && ips_wild) { + hv -= dport; + hv -= sport; tryagain = 1; - goto retry_udp; + WRITE_ENTER(&ipf_state); + goto retry_tcpudp; } break; } @@ -1357,6 +1383,8 @@ ipstate_t *is; { frentry_t *fr; + if (is->is_flags & (FI_WILDP|FI_WILDA)) + ips_wild--; if (is->is_next) is->is_next->is_pnext = is->is_pnext; *is->is_pnext = is->is_next; @@ -1566,7 +1594,7 @@ int dir; * SYN_RECEIVED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; /* or fr_tcptimeout? */ + *age = fr_tcpidletimeout; } break; @@ -1578,7 +1606,7 @@ int dir; * ESTABLISHED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (flags & TH_ACK) { /* an ACK, should we exclude other flags here? */ if (ostate == TCPS_FIN_WAIT_1) { @@ -1590,7 +1618,7 @@ int dir; * a half-closed connection */ state[dir] = TCPS_CLOSE_WAIT; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (ostate < TCPS_CLOSE_WAIT) /* * Still a fully established connection, @@ -1614,7 +1642,7 @@ int dir; * closed already and we did not close our side yet; * reset timeout */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } break; @@ -1638,7 +1666,7 @@ int dir; * other side is still active (ESTABLISHED/CLOSE_WAIT); * continue with this half-closed connection */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; break; case TCPS_CLOSING: /* 7 */ diff --git a/contrib/ipfilter/ip_state.h b/contrib/ipfilter/ip_state.h index a5643af..1d1bc00 100644 --- a/contrib/ipfilter/ip_state.h +++ b/contrib/ipfilter/ip_state.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 2.13.2.1 2000/07/08 02:15:35 darrenr Exp $ + * $Id: ip_state.h,v 2.13.2.2 2000/08/23 11:01:31 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ @@ -173,6 +173,7 @@ extern u_long fr_tcpclosewait; extern u_long fr_tcplastack; extern u_long fr_tcptimeout; extern u_long fr_tcpclosed; +extern u_long fr_tcphalfclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; extern int fr_state_lock; diff --git a/contrib/ipfilter/ipf.c b/contrib/ipfilter/ipf.c index 36448b4..355c42a 100644 --- a/contrib/ipfilter/ipf.c +++ b/contrib/ipfilter/ipf.c @@ -43,7 +43,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipf.c,v 2.10.2.3 2000/08/07 14:54:05 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipf.c,v 2.10.2.5 2000/10/25 10:37:11 darrenr Exp $"; #endif #if SOLARIS @@ -71,7 +71,7 @@ static void set_state __P((u_int)), showstats __P((friostat_t *)); static void packetlogon __P((char *)), swapactive __P((void)); static int opendevice __P((char *)); static void closedevice __P((void)); -static char *getline __P((char *, size_t, FILE *)); +static char *getline __P((char *, size_t, FILE *, int *)); static char *ipfname = IPL_NAME; static void usage __P((void)); static void showversion __P((void)); @@ -252,8 +252,7 @@ char *name, *file; exit(1); } - while (getline(line, sizeof(line), fp)) { - linenum++; + while (getline(line, sizeof(line), fp, &linenum)) { /* * treat CR as EOL. LF is converted to NUL by getline(). */ @@ -335,10 +334,11 @@ char *name, *file; * Similar to fgets(3) but can handle '\\' and NL is converted to NUL. * Returns NULL if error occured, EOF encounterd or input line is too long. */ -static char *getline(str, size, file) +static char *getline(str, size, file, linenum) register char *str; size_t size; FILE *file; +int *linenum; { char *p; int s, len; @@ -356,6 +356,7 @@ FILE *file; p[len] = '\0'; break; } + (*linenum)++; p[len - 1] = '\0'; if (len < 2 || p[len - 2] != '\\') break; @@ -568,7 +569,7 @@ static void showversion() } if (ioctl(vfd, SIOCGETFS, &fiop)) { - perror("ioctl(SIOCGETFS"); + perror("ioctl(SIOCGETFS)"); close(vfd); return; } diff --git a/contrib/ipfilter/ipl.h b/contrib/ipfilter/ipl.h index 866d34d..cfec734 100644 --- a/contrib/ipfilter/ipl.h +++ b/contrib/ipfilter/ipl.h @@ -6,12 +6,12 @@ * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.10 2000/08/07 15:10:09 darrenr Exp $ + * $Id: ipl.h,v 2.15.2.13 2000/10/25 11:08:41 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.9" +#define IPL_VERSION "IP Filter: v3.4.12" #endif diff --git a/contrib/ipfilter/ipmon.c b/contrib/ipfilter/ipmon.c index bb7e75f..5f9db0b 100644 --- a/contrib/ipfilter/ipmon.c +++ b/contrib/ipfilter/ipmon.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipmon.c,v 2.12.2.4 2000/08/07 12:32:22 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipmon.c,v 2.12.2.5 2000/10/19 15:41:41 darrenr Exp $"; #endif #ifndef SOLARIS @@ -692,7 +692,7 @@ int blen; p = (u_short)ip->ip_p; s = (u_32_t *)&ip->ip_src; d = (u_32_t *)&ip->ip_dst; - plen = ntohs(ip->ip_len); + plen = ip->ip_len; } else { goto printipflog; } diff --git a/contrib/ipfilter/ipsend/44arp.c b/contrib/ipfilter/ipsend/44arp.c index f19fe5f..7a16c5a 100644 --- a/contrib/ipfilter/ipsend/44arp.c +++ b/contrib/ipfilter/ipsend/44arp.c @@ -67,7 +67,7 @@ char *addr, *eaddr; struct sockaddr_dl *sdl; #ifdef IPSEND - if (arp_getipv4(ip, ether) == 0) + if (arp_getipv4(addr, ether) == 0) return 0; #endif diff --git a/contrib/ipfilter/man/ipf.4 b/contrib/ipfilter/man/ipf.4 index 4549855..0e080a0 100644 --- a/contrib/ipfilter/man/ipf.4 +++ b/contrib/ipfilter/man/ipf.4 @@ -11,33 +11,33 @@ To add and delete rules to the filter list, three 'basic' ioctls are provided for use. The ioctl's are called as: .LP .nf - ioctl(fd, SIOCADDFR, struct frentry *) - ioctl(fd, SIOCDELFR, struct frentry *) + ioctl(fd, SIOCADDFR, struct frentry **) + ioctl(fd, SIOCDELFR, struct frentry **) ioctl(fd, SIOCIPFFL, int *) .fi .PP However, the full complement is as follows: .LP .nf - ioctl(fd, SIOCADAFR, struct frentry *) (same as SUICADDFR) - ioctl(fd, SIOCRMAFR, struct frentry *) (same as SUICDELFR) - ioctl(fd, SIOCADIFR, struct frentry *) - ioctl(fd, SIOCRMIFR, struct frentry *) - ioctl(fd, SIOCINAFR, struct frentry *) - ioctl(fd, SIOCINIFR, struct frentry *) + ioctl(fd, SIOCADAFR, struct frentry **) (same as SIOCADDFR) + ioctl(fd, SIOCRMAFR, struct frentry **) (same as SIOCDELFR) + ioctl(fd, SIOCADIFR, struct frentry **) + ioctl(fd, SIOCRMIFR, struct frentry **) + ioctl(fd, SIOCINAFR, struct frentry **) + ioctl(fd, SIOCINIFR, struct frentry **) ioctl(fd, SIOCSETFF, u_int *) ioctl(fd, SIOGGETFF, u_int *) - ioctl(fd, SIOCGETFS, struct friostat *) + ioctl(fd, SIOCGETFS, struct friostat **) ioctl(fd, SIOCIPFFL, int *) ioctl(fd, SIOCIPFFB, int *) ioctl(fd, SIOCSWAPA, u_int *) ioctl(fd, SIOCFRENB, u_int *) ioctl(fd, SIOCFRSYN, u_int *) - ioctl(fd, SIOCFRZST, struct friostat *) - ioctl(fd, SIOCZRLST, struct frentry *) - ioctl(fd, SIOCAUTHW, struct fr_info *) - ioctl(fd, SIOCAUTHR, struct fr_info *) - ioctl(fd, SIOCATHST, struct fr_authstat *) + ioctl(fd, SIOCFRZST, struct friostat **) + ioctl(fd, SIOCZRLST, struct frentry **) + ioctl(fd, SIOCAUTHW, struct fr_info **) + ioctl(fd, SIOCAUTHR, struct fr_info **) + ioctl(fd, SIOCATHST, struct fr_authstat **) .fi .PP The variations, SIOCADAFR vs. SIOCADIFR, allow operation on the two lists, @@ -107,7 +107,7 @@ filter list, the number of the rule which it is to be inserted before must be put in the "fr_hits" field (the first rule is number 0). .LP .PP -Flags which are recognised in fr_pass: +Flags which are recognised in fr_flags: .nf FR_BLOCK 0x000001 /* do not allow packet to pass */ diff --git a/contrib/ipfilter/man/ipf.5 b/contrib/ipfilter/man/ipf.5 index 478d672..243edac 100644 --- a/contrib/ipfilter/man/ipf.5 +++ b/contrib/ipfilter/man/ipf.5 @@ -31,7 +31,7 @@ proto = "proto" protocol . ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . group = [ "head" decnumber ] [ "group" decnumber ] . -block = "block" [ icmp[return-code] | "return-rst" ] . +block = "block" [ return-icmp[return-code] | "return-rst" ] . auth = "auth" | "preauth" . log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . call = "call" [ "now" ] function-name . @@ -42,7 +42,7 @@ protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . srcdst = "all" | fromto . fromto = "from" [ "!" ] object "to" [ "!" ] object . -icmp = "return-icmp" | "return-icmp-as-dest" . +return-icmp = "return-icmp" | "return-icmp-as-dest" . object = addr [ port-comp | port-range ] . addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . port-comp = "port" compare port-num . diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8 index 61d6575..7cd98f6 100644 --- a/contrib/ipfilter/man/ipmon.8 +++ b/contrib/ipfilter/man/ipmon.8 @@ -149,7 +149,7 @@ show the packet data in hex. show the log header record data in hex. .SH DIAGNOSTICS \fBipmon\fP expects data that it reads to be consistent with how it should be -saved and will abort if it fails an assertion which detects an anomoly in the +saved and will abort if it fails an assertion which detects an anomaly in the recorded data. .SH FILES /dev/ipl diff --git a/contrib/ipfilter/man/ipnat.4 b/contrib/ipfilter/man/ipnat.4 index ee385b7..6cba7b6 100644 --- a/contrib/ipfilter/man/ipnat.4 +++ b/contrib/ipfilter/man/ipnat.4 @@ -15,8 +15,10 @@ To add and delete rules to the NAT list, two 'basic' ioctls are provided for use. The ioctl's are called as: .LP .nf - ioctl(fd, SIOCADNAT, struct ipnat *) - ioctl(fd, SIOCRMNAT, struct ipnat *) + ioctl(fd, SIOCADNAT, struct ipnat **) + ioctl(fd, SIOCRMNAT, struct ipnat **) + ioctl(fd, SIOCGNATS, struct natstat **) + ioctl(fd, SIOCGNATL, struct natlookup **) .fi .PP Unlike \fBipf(4)\fP, there is only a single list supported by the kernel NAT diff --git a/contrib/ipfilter/mlf_ipl.c b/contrib/ipfilter/mlf_ipl.c index f12e989..f6e7ad4 100644 --- a/contrib/ipfilter/mlf_ipl.c +++ b/contrib/ipfilter/mlf_ipl.c @@ -95,6 +95,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW, &fr_tcpidletimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, + &fr_tcphalfclosed, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW, &fr_tcpclosewait, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW, diff --git a/contrib/ipfilter/mlfk_ipl.c b/contrib/ipfilter/mlfk_ipl.c index f869149..f96c57e 100644 --- a/contrib/ipfilter/mlfk_ipl.c +++ b/contrib/ipfilter/mlfk_ipl.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mlfk_ipl.c,v 2.1.2.3 2000/08/13 03:42:42 darrenr Exp $ + * $Id: mlfk_ipl.c,v 2.1.2.4 2000/08/23 11:02:33 darrenr Exp $ */ @@ -65,6 +65,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, &fr_tcptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, &fr_tcpclosed, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, + &fr_tcphalfclosed, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, &fr_udptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, diff --git a/contrib/ipfilter/perl/plog b/contrib/ipfilter/perl/plog index b251b0c..208c6ea 100644 --- a/contrib/ipfilter/perl/plog +++ b/contrib/ipfilter/perl/plog @@ -1,14 +1,15 @@ #!/usr/bin/perl -wT # # Author: Jefferson Ogata (JO317) -# Date: 2000/04/10 -# Version: 0.8 +# 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 @@ -18,10 +19,10 @@ # # EXAMPLES # -# plog -A block,log < /var/log/ipf +# plog -AF block,log < /var/log/ipf # # Generate source and destination reports of all packets logged with -# block or log actions. +# block or log actions, and report TCP flags and keep state actions. # # plog -S -s ./services www.example.com < /var/log/ipf # @@ -34,6 +35,14 @@ # 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. @@ -44,6 +53,14 @@ # # 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 . @@ -58,8 +75,7 @@ # 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 +# 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 . # - Added services map option. # - Added options for generating only source/destination tables. @@ -141,219 +157,251 @@ $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', + '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}, + 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', - }, + 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}, + 4 => +{ + name => 'squench', + codes => +{0 => undef}, }, - 5 => +{ - name => 'redir', - codes => +{ - 0 => 'net', - 1 => 'host', - 2 => 'tos', - 3 => 'tos-host', - }, + 5 => +{ + name => 'redir', + codes => +{ + 0 => 'net', + 1 => 'host', + 2 => 'tos', + 3 => 'tos-host', + }, }, - 6 => +{ - name => 'alt-host-addr', - codes => +{ - 0 => 'alt-addr' - }, + 6 => +{ + name => 'alt-host-addr', + codes => +{ + 0 => 'alt-addr' + }, }, - 8 => +{ - name => 'echo', - codes => +{0 => undef}, + 8 => +{ + name => 'echo', + codes => +{0 => undef}, }, - 9 => +{ - name => 'routerad', - codes => +{0 => undef}, + 9 => +{ + name => 'routerad', + codes => +{0 => undef}, }, - 10 => +{ - name => 'routersol', - codes => +{0 => undef}, + 10 => +{ + name => 'routersol', + codes => +{0 => undef}, }, - 11 => +{ - name => 'timex', - codes => +{ - 0 => 'in-transit', - 1 => 'frag-assy', - }, + 11 => +{ + name => 'timex', + codes => +{ + 0 => 'in-transit', + 1 => 'frag-assy', + }, }, - 12 => +{ - name => 'paramprob', - codes => +{ - 0 => 'ptr-err', - 1 => 'miss-opt', - 2 => 'bad-len', - }, + 12 => +{ + name => 'paramprob', + codes => +{ + 0 => 'ptr-err', + 1 => 'miss-opt', + 2 => 'bad-len', + }, }, - 13 => +{ - name => 'timest', - codes => +{0 => undef}, + 13 => +{ + name => 'timest', + codes => +{0 => undef}, }, - 14 => +{ - name => 'timestrep', - codes => +{0 => undef}, + 14 => +{ + name => 'timestrep', + codes => +{0 => undef}, }, - 15 => +{ - name => 'inforeq', - codes => +{0 => undef}, + 15 => +{ + name => 'inforeq', + codes => +{0 => undef}, }, - 16 => +{ - name => 'inforep', - codes => +{0 => undef}, + 16 => +{ + name => 'inforep', + codes => +{0 => undef}, }, - 17 => +{ - name => 'maskreq', - codes => +{0 => undef}, + 17 => +{ + name => 'maskreq', + codes => +{0 => undef}, }, - 18 => +{ - name => 'maskrep', - codes => +{0 => undef}, + 18 => +{ + name => 'maskrep', + codes => +{0 => undef}, }, - 30 => +{ - name => 'tracert', - codes => +{ }, + 30 => +{ + name => 'tracert', + codes => +{ }, }, - 31 => +{ - name => 'dgram-conv-err', - codes => +{ }, + 31 => +{ + name => 'dgram-conv-err', + codes => +{ }, }, - 32 => +{ - name => 'mbl-host-redir', - codes => +{ }, + 32 => +{ + name => 'mbl-host-redir', + codes => +{ }, }, - 33 => +{ - name => 'ipv6-whereru?', - codes => +{ }, + 33 => +{ + name => 'ipv6-whereru?', + codes => +{ }, }, - 34 => +{ - name => 'ipv6-iamhere', - codes => +{ }, + 34 => +{ + name => 'ipv6-iamhere', + codes => +{ }, }, - 35 => +{ - name => 'mbl-reg-req', - codes => +{ }, + 35 => +{ + name => 'mbl-reg-req', + codes => +{ }, }, - 36 => +{ - name => 'mbl-reg-rep', - 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. +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/^([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; + 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. - my $addr = &hostNumber ($_); - defined ($addr) || &usage (1, qq{cannot resolve hostname $_}); - $selectHosts{$addr} = undef; + (/^(.+)\/([\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? @@ -363,7 +411,7 @@ push (@dirs, 'd') if ($dTable); push (@dirs, 's') if ($sTable); # Are we interested in specific hosts? -my $selectHosts = scalar (keys (%selectHosts)); +my $selectAddrs = scalar (keys (%selectAddrs)); # Are we interested in specific actions? if (scalar (keys (%selectActs)) == 0) @@ -375,42 +423,45 @@ if (scalar (keys (%selectActs)) == 0) # Isn't it cool that we can use the same hash for both? my %pn; -# Preload any services map. -if (defined ($services)) +# Preload any services maps. +my $sm; +foreach $sm (@services) { - my $sf = new IO::File ($services, "r"); - defined ($sf) || &quit (1, qq{cannot open services file $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{$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; + 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 (); } -# Again, we can use the same hash for both host name -> IP mappings and -# IP -> name mappings. -my %ip; +# Cache for host name -> addr mappings. +my %ipAddr; + +# Cache for host addr -> name mappings. +my %ipName; # Hash for protocol number <--> name mappings. my %pr; @@ -434,16 +485,16 @@ while () 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 = $_; + $log = $_; } elsif (s/^(?:\d+\/\d+\/\d+)\s+(?:\d+:\d+:\d+\.\d+)\s+//) { - $log = $_; + $log = $_; } else { - # It don't look like no ipmon output to me, baby. - next; + # It don't look like no ipmon output to me, baby. + next; } next unless (defined ($log)); @@ -455,11 +506,11 @@ while () # 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); + 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; + print STDERR "$me:$.: cannot parse: $_\n"; + next; } my ($count, $if, $group, $rule, $act, $src, $dest, $proto, $hlen, $len, $more) = @fields; @@ -469,102 +520,131 @@ while () # Packet count defaults to 1. $count = 1 unless (defined ($count)); - my ($sport, $dport); + 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 = ''; - } + 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 = ''; - } + 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. This has got to do some weird things, but if you - # want to use ipmon -n, be ready for weirdness. + # 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 = &hostNumber ($src); + $x = (&hostAddrs ($src))[0]; unless (defined ($x)) { - print STDERR "$me:$.: cannot resolve hostname $src\n"; - next; + print STDERR "$me:$.: cannot resolve hostname $src\n"; + next; } $src = $x; - $x = &hostNumber ($dest); + $x = (&hostAddrs ($dest))[0]; unless (defined ($x)) { - print STDERR "$me:$.: cannot resolve hostname $dest\n"; - next; + 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 ($selectHosts{$dest}))); + 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) = @_; + my ($host, $dir, $peer, $proto, $count, $packet, @flags) = @_; - # Make sure host is in the hosts hash. - $hosts{$host} = - +{ - 'd' => +{ }, - 's' => +{ }, - } unless (exists ($hosts{$host})); + # 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}; + # 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 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 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})); + # 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; + # 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") if ($sTable); + &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") if ($dTable); + &countPacket ($dest, 'd', $src, $proto, $count, "$dport:$sport:$if:$act", @flags) if ($dTable); } my $dir; @@ -579,67 +659,76 @@ foreach $dir (@dirs) 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]; + &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 ($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, &portName ($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); - } - } - } - } + 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"; @@ -658,8 +747,8 @@ sub portName my $pname = "$port/$proto"; unless (exists ($pn{$pname})) { - my $name = getservbyport ($port, $proto); - $pn{$pname} = (defined ($name) ? $name : ($port <= 1023 ? $port : '')); + my $name = getservbyport ($port, $proto); + $pn{$pname} = (defined ($name) ? $name : ($port <= 1023 ? $port : '')); } return $pn{$pname}; } @@ -672,16 +761,16 @@ sub portNumber 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; + 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}; } @@ -695,7 +784,7 @@ sub portSimplify # Make sure port is numeric. $port = &portNumber ($port, $proto) - unless ($port =~ /^\d+$/); + unless ($port =~ /^\d+$/); # Look up port name. my $portName = &portName ($port, $proto); @@ -708,61 +797,130 @@ sub portSimplify return $port; } -# Translates a dotted quad into a hostname. Don't pass names to this -# function. +# Translates a numeric address into a hostname. Pass only packed numeric +# addresses to this routine. sub hostName { my $ip = shift; - 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}; + 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 quad into a dotted quad. -sub hostNumber +# Translates a hostname or dotted address into a list of packed numeric +# addresses. +sub hostAddrs { 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}; + 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 @@ -773,15 +931,15 @@ sub protoName return $code if ($code !~ /^\d+$/); unless (exists ($pr{$code})) { - my $name = scalar (getprotobynumber ($code)); - if (defined ($name)) - { - $pr{$code} = $name; - } - else - { - $pr{$code} = $code; - } + my $name = scalar (getprotobynumber ($code)); + if (defined ($name)) + { + $pr{$code} = $name; + } + else + { + $pr{$code} = $code; + } } return $pr{$code}; } @@ -793,15 +951,15 @@ sub protoNumber return $name if ($name =~ /^\d+$/); unless (exists ($pr{$name})) { - my $code = scalar (getprotobyname ($name)); - if (defined ($code)) - { - $pr{$name} = $code; - } - else - { - $pr{$name} = $name; - } + my $code = scalar (getprotobyname ($name)); + if (defined ($code)) + { + $pr{$name} = $code; + } + else + { + $pr{$name} = $name; + } } return $pr{$name}; } @@ -821,12 +979,12 @@ sub icmpType my $codeName; if (exists ($info->{codes}->{$code})) { - $codeName = $info->{codes}->{$code}; - $codeName = (defined ($codeName) ? "/$codeName" : ''); + $codeName = $info->{codes}->{$code}; + $codeName = (defined ($codeName) ? "/$codeName" : ''); } else { - $codeName = "/$code"; + $codeName = "/$code"; } return "$typeName$codeName"; } @@ -847,11 +1005,11 @@ sub usage if (scalar (@msg)) { - print STDERR "$me: ", join ("\n", @msg), "\n\n"; + print STDERR "$me: ", join ("\n", @msg), "\n\n"; } - print STDERR < a.b.c.d/32 proxy port ftp ftp/tcp +# +# For normal TCP/UDP and other IP protocols +# map ppp0 w.x.y.z/24 -> a.b.c.d/32 portmap tcp/udp 40000:60000 map ppp0 w.x.y.z/24 -> a.b.c.d/32 # @@ -38,8 +44,3 @@ map ppp0 w.x.y.z/24 -> a.b.c.d/32 #map ppp0 w.x.y.q/32 -> a.b.c.J/32 #map ppp0 w.x.y.p/32 -> a.b.c.K/32 portmap tcp/udp 40000:60000 #map ppp0 w.x.y.p/32 -> a.b.c.K/32 -# -# To make ftp work, using the internal ftp proxy, use: -# -map ppp0 w.x.y.z/24 -> a.b.c.d/32 proxy port ftp ftp/tcp -# -- cgit v1.1