diff options
author | darrenr <darrenr@FreeBSD.org> | 2000-05-24 02:14:22 +0000 |
---|---|---|
committer | darrenr <darrenr@FreeBSD.org> | 2000-05-24 02:14:22 +0000 |
commit | dda6755c7b3b3b5d3e9111b7d0c39a7d8b5f3e12 (patch) | |
tree | 8658a81b1c1fcbbbec3b1df568cc198dd98d44ee /contrib | |
parent | 1fa4f6782a7e92a232e56892d8bce7920d49292e (diff) | |
download | FreeBSD-src-dda6755c7b3b3b5d3e9111b7d0c39a7d8b5f3e12.zip FreeBSD-src-dda6755c7b3b3b5d3e9111b7d0c39a7d8b5f3e12.tar.gz |
Import IP Filter 3.4.4 into FreeBSD-current
Diffstat (limited to 'contrib')
92 files changed, 10166 insertions, 3309 deletions
diff --git a/contrib/ipfilter/BSD/Makefile b/contrib/ipfilter/BSD/Makefile index 7718a81..f34acdd 100644 --- a/contrib/ipfilter/BSD/Makefile +++ b/contrib/ipfilter/BSD/Makefile @@ -40,16 +40,18 @@ INSTALL=install MODOBJS=ip_fil.o fil_k.o ml_ipl.o ip_nat.o ip_frag.o ip_state.o ip_proxy.o \ ip_auth.o ip_log.o DFLAGS=$(IPFLKM) $(IPFLOG) $(DEF) $(DLKM) -IPF=ipf.o parse.o opt.o facpri.o -IPT=ipt.o parse.o fil.o ipft_sn.o ipft_ef.o ipft_td.o ipft_pc.o opt.o \ - ipft_tx.o misc.o ip_frag_u.o ip_state_u.o ip_nat_u.o ip_proxy_u.o \ +IPF=ipf.o parse.o common.o opt.o facpri.o +IPT=ipt.o parse.o common.o fil.o ipft_sn.o ipft_ef.o ipft_td.o ipft_pc.o \ + opt.o ipft_tx.o misc.o ip_frag_u.o ip_state_u.o ip_nat_u.o ip_proxy_u.o \ ip_auth_u.o ipft_hx.o ip_fil_u.o natparse.o facpri.o -FILS=fils.o parse.o kmem.o opt.o facpri.o +IPNAT=ipnat.o kmem.o natparse.o common.o +FILS=fils.o parse.o kmem.o opt.o facpri.o common.o -build all: ipf ipfstat ipftest ipmon ipnat $(LKM) +build all: ipf ipfs ipfstat ipftest ipmon ipnat $(LKM) ipfstat: $(FILS) - $(CC) $(DEBUG) $(CFLAGS) $(FILS) -o $@ $(LIBS) + $(CC) $(DEBUG) $(CFLAGS) $(STATETOP_CFLAGS) $(STATETOP_INC) $(FILS) \ + -o $@ $(LIBS) $(STATETOP_LIB) ipf: $(IPF) $(CC) $(DEBUG) $(CFLAGS) $(IPF) -o $@ $(LIBS) @@ -61,20 +63,29 @@ ipftest: $(IPT) /bin/rm -f $(TOP)/ipftest ln -s `pwd`/ipftest $(TOP) -ipnat: ipnat.o kmem.o natparse.o - $(CC) $(DEBUG) $(CFLAGS) ipnat.o kmem.o natparse.o -o $@ $(LIBS) +ipnat: $(IPNAT) + $(CC) $(DEBUG) $(CFLAGS) $(IPNAT) -o $@ $(LIBS) + +ipfs: ipfs.o + $(CC) $(DEBUG) $(CFLAGS) ipfs.o -o $@ $(LIBS) tests: (cd test; make ) fils.o: $(TOP)/fils.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_frag.h \ - $(TOP)/ip_compat.h $(TOP)/ip_state.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/fils.c -o $@ + $(TOP)/ip_compat.h $(TOP)/ip_state.h $(TOP)/ip_nat.h + $(CC) $(DEBUG) $(CFLAGS) $(STATETOP_CFLAGS) $(STATETOP_INC) \ + -c $(TOP)/fils.c -o $@ + +ipfs.o: $(TOP)/ipfs.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_state.h \ + $(TOP)/ip_nat.h + $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipfs.c -o $@ fil.o: $(TOP)/fil.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_compat.h $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/fil.c -o $@ -fil_k.o: $(TOP)/fil.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_compat.h +fil_k.o: $(TOP)/fil.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_compat.h \ + $(TOP)/ipl.h $(CC) $(DEBUG) $(CFLAGS) $(POLICY) $(DFLAGS) -c $(TOP)/fil.c -o $@ ipf.o: $(TOP)/ipf.c $(TOP)/ip_fil.h $(TOP)/ipf.h @@ -92,7 +103,8 @@ opt.o: $(TOP)/opt.c $(TOP)/ip_fil.h $(TOP)/ipf.h ipnat.o: $(TOP)/ipnat.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_nat.h $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipnat.c -o $@ -natparse.o: $(TOP)/natparse.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_nat.h +natparse.o: $(TOP)/natparse.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_nat.h \ + $(TOP)/ip_compat.h $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/natparse.c -o $@ ipft_sn.o: $(TOP)/ipft_sn.c $(TOP)/ipt.h $(TOP)/ipf.h $(TOP)/ip_fil.h \ @@ -126,7 +138,7 @@ ip_frag_u.o: $(TOP)/ip_frag.c $(TOP)/ip_frag.h $(TOP)/ip_compat.h \ $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_frag.c -o $@ ip_state_u.o: $(TOP)/ip_state.c $(TOP)/ip_state.h $(TOP)/ip_compat.h \ - $(TOP)/ip_fil.h + $(TOP)/ip_fil.h $(TOP)/ip_nat.h $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_state.c -o $@ ip_auth_u.o: $(TOP)/ip_auth.c $(TOP)/ip_auth.h $(TOP)/ip_compat.h \ @@ -140,6 +152,12 @@ if_ipl.o: $(MODOBJS) ld -r $(MODOBJS) -o $(LKM) ${RM} -f if_ipl +ipf.ko ipl.ko: $(MODOBJS) + gensetdefs $(MODOBJS) + $(CC) $(DEBUG) $(CFLAGS) -c setdef0.c + $(CC) $(DEBUG) $(CFLAGS) -c setdef1.c + ld -Bshareable -o $(LKM) setdef0.o $(MODOBJS) setdef1.o + ip_nat.o: $(TOP)/ip_nat.c $(TOP)/ip_nat.h $(TOP)/ip_compat.h $(TOP)/ip_fil.h $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/ip_nat.c -o $@ @@ -147,7 +165,7 @@ ip_frag.o: $(TOP)/ip_frag.c $(TOP)/ip_frag.h $(TOP)/ip_compat.h $(TOP)/ip_fil.h $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/ip_frag.c -o $@ ip_state.o: $(TOP)/ip_state.c $(TOP)/ip_state.h $(TOP)/ip_compat.h \ - $(TOP)/ip_fil.h + $(TOP)/ip_fil.h $(TOP)/ip_nat.h $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/ip_state.c -o $@ ip_proxy.o: $(TOP)/ip_proxy.c $(TOP)/ip_proxy.h $(TOP)/ip_compat.h \ @@ -181,6 +199,9 @@ kmem.o: $(TOP)/kmem.c parse.o: $(TOP)/parse.c $(TOP)/ip_fil.h $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/parse.c -o $@ +common.o: $(TOP)/common.c $(TOP)/ip_fil.h + $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/common.c -o $@ + facpri.o: $(TOP)/facpri.c $(TOP)/facpri.h $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/facpri.c -o $@ @@ -189,7 +210,9 @@ ipmon: $(TOP)/ipmon.c clean: ${RM} -f *.core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl ipnat \ - vnode_if.h $(LKM) ioconf.h + vnode_if.h $(LKM) ioconf.h *.ko setdef1.c setdef0.c setdefs.h \ + y.tab.? lex.yy.c ipfs + ${MAKE} -f Makefile.ipsend ${MFLAGS} clean -(for i in *; do \ if [ -d $${i} -a -f $${i}/Makefile ] ; then \ @@ -205,9 +228,10 @@ install: -if [ -d /lkm -a -f if_ipl.o ] ; then \ cp if_ipl.o /lkm; \ fi - -$(INSTALL) -cs -g wheel -m 755 -o root ipfstat ipf ipnat $(SBINDEST) - -$(INSTALL) -cs -g wheel -m 755 -o root ipmon ipftest $(BINDEST) - -$(INSTALL) -cs -g wheel -m 755 -o root ipftest ipftest $(BINDEST) - -$(INSTALL) -cs -g wheel -m 755 -o root ipf ipftest $(SBINDEST) - -$(INSTALL) -cs -g wheel -m 755 -o root ipnat ipftest $(SBINDEST) + -$(INSTALL) -cs -g wheel -m 755 -o root ipf $(SBINDEST) + -$(INSTALL) -cs -g wheel -m 755 -o root ipfs $(SBINDEST) + -$(INSTALL) -cs -g wheel -m 755 -o root ipnat $(SBINDEST) + -$(INSTALL) -cs -g wheel -m 755 -o root ipfstat $(SBINDEST) + -$(INSTALL) -cs -g wheel -m 755 -o root ipmon $(BINDEST) + -$(INSTALL) -cs -g wheel -m 755 -o root ipftest $(BINDEST) (cd $(TOP)/man; make INSTALL=$(INSTALL) MANDIR=$(MANDIR) install; cd $(TOP)) diff --git a/contrib/ipfilter/BSD/Makefile.ipsend b/contrib/ipfilter/BSD/Makefile.ipsend index e9c4a10..94a3c7a 100644 --- a/contrib/ipfilter/BSD/Makefile.ipsend +++ b/contrib/ipfilter/BSD/Makefile.ipsend @@ -1,3 +1,11 @@ +# +# $Id: Makefile.ipsend,v 2.2 2000/02/28 08:27:51 darrenr Exp $ +# + +BINDEST=/usr/sbin +SBINDEST=/sbin +MANDIR=/usr/share/man + OBJS=ipsend.o ip.o ipsopt.o y.tab.o lex.yy.o IPFTO=ipft_ef.o ipft_hx.o ipft_pc.o ipft_sn.o ipft_td.o ipft_tx.o ROBJS=ipresend.o ip.o resend.o $(IPFTO) opt.o diff --git a/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 b/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 index 8c7b8ef..6c68dbb 100644 --- a/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 +++ b/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 @@ -1,4 +1,4 @@ -To build a kernel with the IP filter, follow these steps: +To build a kernel with the IP filter, follow these seven steps: 1. do "make freebsd3" diff --git a/contrib/ipfilter/FreeBSD-3/unkinstall b/contrib/ipfilter/FreeBSD-3/unkinstall index aa39c5b..687ebc6 100755 --- a/contrib/ipfilter/FreeBSD-3/unkinstall +++ b/contrib/ipfilter/FreeBSD-3/unkinstall @@ -1,5 +1,6 @@ #!/bin/csh -f # +# set dir=`pwd` set karch=`uname -m` if ( -d /sys/arch/$karch ) set archdir="/sys/arch/$karch" diff --git a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch new file mode 100755 index 0000000..c232b2c --- /dev/null +++ b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch @@ -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 <netinet6/ip6_fw.h> + #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/kinstall b/contrib/ipfilter/FreeBSD-4.0/kinstall new file mode 100755 index 0000000..cb3c3da --- /dev/null +++ b/contrib/ipfilter/FreeBSD-4.0/kinstall @@ -0,0 +1,50 @@ +#!/bin/csh -f +# +set dir=`pwd` +set karch=`uname -m` +if ( -d /sys/arch/$karch ) set archdir="/sys/arch/$karch" +if ( -d /sys/$karch ) set archdir="/sys/$karch" +set confdir="$archdir/conf" + +if ( $dir =~ */FreeBSD* ) cd .. +echo -n "Installing " +foreach i (ip_fil.[ch] ip_nat.[ch] ip_frag.[ch] ip_state.[ch] fil.c \ + ip_proxy.[ch] ip_{ftp,rcmd,raudio}_pxy.c mlf_ipl.c ipl.h \ + ip_compat.h ip_auth.[ch] ip_log.c) + echo -n "$i "; + cp $i /sys/netinet + chmod 644 /sys/netinet/$i +end +echo "" +echo "Linking /usr/include/osreldate.h to /sys/sys/osreldate.h" +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) + +set config=`(cd $confdir; /bin/ls -1t [0-9A-Z_]*) | head -1` +echo -n "Kernel configuration to update [$config] " +set newconfig=$< +if ( "$newconfig" != "" ) then + set config="$confdir/$newconfig" +else + set newconfig=$config +endif +echo "Rewriting $newconfig..." +if ( -f $confdir/$newconfig ) then + mv $confdir/$newconfig $confdir/$newconfig.bak +endif +if ( -d $archdir/../compile/$newconfig ) then + set bak=".bak" + set dot=0 + while ( -d $archdir/../compile/${newconfig}.${bak} ) + set bak=".bak.$dot" + set dot=`expr 1 + $dot` + end + mv $archdir/../compile/$newconfig $archdir/../compile/${newconfig}.${bak} +endif +awk '{print $0;if($2=="INET"){print"options IPFILTER\noptions IPFILTER_LOG"}}'\ + $confdir/$newconfig.bak > $confdir/$newconfig +echo "You will now need to run config on $newconfig and build a new kernel." +exit 0 diff --git a/contrib/ipfilter/FreeBSD-4.0/unkinstall b/contrib/ipfilter/FreeBSD-4.0/unkinstall new file mode 100755 index 0000000..d43ac4a --- /dev/null +++ b/contrib/ipfilter/FreeBSD-4.0/unkinstall @@ -0,0 +1,48 @@ +#!/bin/csh -f +# +# +set dir=`pwd` +set karch=`uname -m` +if ( -d /sys/arch/$karch ) set archdir="/sys/arch/$karch" +if ( -d /sys/$karch ) set archdir="/sys/$karch" +set confdir="$archdir/conf" + +if ( $dir =~ */FreeBSD* ) cd .. +echo -n "Uninstalling " +foreach i (ip_fil.[ch] ip_nat.[ch] ip_frag.[ch] ip_state.[ch] fil.c \ + ip_auth.[ch] ip_proxy.[ch] ip_{ftp,rcmd,raudio}_pxy.c ip_compat.h \ + ip_log.c mlf_ipl.c ipl.h) + echo -n "$i "; + /bin/rm -f /sys/netinet/$i +end +echo "" + +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) + +set config=`(cd $confdir; /bin/ls -1t [0-9A-Z_]*) | head -1` +echo -n "Kernel configuration to update [$config] " +set newconfig=$< +if ( "$newconfig" != "" ) then + set config="$confdir/$newconfig" +else + set newconfig=$config +endif +if ( -f $confdir/$newconfig ) then + mv $confdir/$newconfig $confdir/$newconfig.bak +endif +if ( -d $archdir/../compile/$newconfig ) then + set bak=".bak" + set dot=0 + while ( -d $archdir/../compile/${newconfig}.${bak} ) + set bak=".bak.$dot" + set dot=`expr 1 + $dot` + end + mv $archdir/../compile/$newconfig $archdir/../compile/${newconfig}.${bak} +endif +egrep -v IPFILTER $confdir/$newconfig.bak > $confdir/$newconfig +echo 'You will now need to run "config" and build a new kernel.' +exit 0 diff --git a/contrib/ipfilter/HISTORY b/contrib/ipfilter/HISTORY index 49f7ace..ea2f478 100644 --- a/contrib/ipfilter/HISTORY +++ b/contrib/ipfilter/HISTORY @@ -20,6 +20,159 @@ # and especially those who have found the time to port IP Filter to new # platforms. # +3.4.4 23/05/2000 - Released + +don't add TCP state if it is an RST packet and (attempt) to send out +RST/ICMP packets in a manner that bypasses IP Filter. + +add patch to work with 4.0_STABLE delayed checksums + +3.4.3 20/05/2000 - Released + +fix ipmon -F + +don't truncate IPv6 packets on Solaris + +fix keep state for ICMP ECHO + +add some NAT stats and use def_nat_age rather than DEF_NAT_AGE + +don't make ftp proxy drop packets + +use MCLISREFERENCED() in tandem with M_EXT to check if IP fields need to be +swapped back. + +fix up RST generation for non-Solaris + +get "short" flag right for IPv6 + +3.4.2 - 10/5/2000 - Released + +Fix bug in dealing with "hlen == 1 and opt > 1" - Itojun + +ignore previous NAT mappings for 0/0 and 0/32 rules + +bring in a completely new ftp proxy + +allow NAT to cause packets to be dropped. + +add NetBSD callout support for 1.4-current + +3.4.1 - 30/4/2000 - Released + +add ratoui() and fix parsing of group numbers to allow 0 - UINT_MAX + +don't include opt_inet6.h for FreeBSD if KLD_MODULE is defined + +Solaris must use copyin() for all types of ioctl() args + +fix up screen/tty when leaving "top mode" of ipfstat + +linked list for maptable not setup correctly in nat_hostmap() + +check for maptable rather than nat_table[1] to see if malloc for maptable +succeeded in nat_init + +fix handling of map NAT rules with "from/to" host specs + +fix printout out of source address when using "from/to" with map rules + +convert ip_len back to network byte order, not plen, for solaris as ip_len +may have been changed by NAT and plen won't reflect this + +3.4 - 27/4/2000 - Released + +source address spoofing can be turned on (fr_chksrc) without using +filter rules + +group numbers are now 32bits in size, up from 16bits + +IPv6 filtering available + +add frank volf's state-top patches + +add load splitting and round-robin attribute to redirect rules + +FreeBSD-4.0 support (including KLD) + +add top-style operation mode for ipfstat (-t) + +add save/restore of IP Filter state/NAT information (ipfs) + +further ftp proxy security checks + +support for adding and removing proxies at runtime + +3.3.13 26/04/2000 - Released + +Fix parsing of "range" with "portmap" + +Relax checking of ftp replies, slightly. + +Fix NAT timeouts for ICMP packets + +SunOS4 patches for ICMP redirects from Jurgen Keil (jk@tools.de) + +3.3.12 16/03/2000 - Released + +tighten up ftp proxy behaviour. sigh. yuck. hate. + +fix bug in range check for NAT where the last IP# was not used. + +fix problem with icmp codes > 127 in filter rules caused bad things to +happen and in particular, where #18 caused the rule to be printed +erroneously. + +fix bug with the spl level not being reset when returning EIO from +iplioctl due to ipfilter not being initialized yet. + +3.3.11 04/03/2000 - Released + +make "or-block" work with lines that start with "log" + +fix up parsing and printing of rules with syslog levels in them + +fix from Cy Schubert for calling of apr_fini only if non-null + + +3.3.10 24/02/2000 - Released + +* fix back from guido for state tracking interfaces + +* update for NetBSD pfil interface changes + +* if attaching fails and we can abort, then cleanup when doing so. + +julian@computer.org: +* solaris.c (fr_precheck): After calling freemsg on mt, set it point to *mp. +* ipf.c (packetlogon): use flag to store the return value from get_flags. +* ipmon.c (init_tabs): General cleanup so we do not have to cast + an int s->s_port to u_int port and try to check if the u_int port + is less than zero. + +3.3.9 15/02/2000 - Released + +fix scheduling of bad locking in fr_addstate() used when we attach onto +a filter rule. + +fix up ip_statesync() with storing interface names in ipstate_t + +fix fr_running for LKM's - Eugene Polovnikov + +junk using pullupmsg() for solaris - it's next to useless for what we +need to do here anyway - and implement what we require. + +don't call fr_delstate() in fr_checkstate(), when compiled for a user +program, early but when we're finished with it (got fr & pass) + +ipnat(5) fix from Guido + +on solaris2, copy message and use that with filter if there is another +copy if it being used (db_ref > 1). bad for performance, but better +than causing a crash. + +patch for solaris8-fcs compile from Casper Dik + 3.3.8 01/02/2000 - Released fix state handling of SYN packets. @@ -85,11 +238,6 @@ fix yet another problem with real audio. 3.3.4 4/12/1999 - Released -patches from Guido: fix panic in ip_state:fr_checkicmpmatchingstate(), fix -byte order problem in ip_id (host order when called from ip_input(), vs -network byte order when called from ip_output()) and fix a problem where the -fragment cache was never timedout early. - fix up the real audio proxy to properly setup state information and NAT entries, thanks to Laine Stump for testing/advice/fixes. diff --git a/contrib/ipfilter/IPF.KANJI b/contrib/ipfilter/IPF.KANJI new file mode 100644 index 0000000..85af5ce --- /dev/null +++ b/contrib/ipfilter/IPF.KANJI @@ -0,0 +1,465 @@ +IP filter $B%7%g!<%H%,%$%I(B Dec, 1999 + +$B%[!<%`%Z!<%8(B: http://coombs.anu.edu.au/~avalon/ip-filter.html +FTP: ftp://coombs.anu.edu.au/pub/net/ip-filter/ + + $B30;3(B $B=c@8(B <sumio@is.s.u-tokyo.ac.jp> + $B;3K\(B $BBY1'(B <ymmt@is.s.u-tokyo.ac.jp> + +----- +$B$O$8$a$K(B + +IP filter $B$r(B gateway $B%^%7%s$K%$%s%9%H!<%k$9$k$3$H$G%Q%1%C%H%U%#(B +$B%k%?%j%s%0$r9T$&$3$H$,$G$-$^$9!#(B + +$B%$%s%9%H!<%k$NJ}K!$O!"(BINSTALL$B$K=q$$$F$"$k$N$G!"$=$A$i$r;2>H$7$F(B +$B$/$@$5$$!#(BIP filter $B$N%P!<%8%g%s(B 3.3.5 $B$O!"(B + Solaris/Solaris-x86 2.3 - 8 (early access) + SunOS 4.1.1 - 4.1.4 + NetBSD 1.0 - 1.4 + FreeBSD 2.0.0 - 2.2.8 + BSD/OS-1.1 - 4 + IRIX 6.2 +$B$GF0:n$9$k$3$H$,3NG'$5$l$F$$$^$9!#(B + +$B$J$*!"(B64 bit kernel $B$NAv$C$F$k(B Solaris7 $B%^%7%s$G$O!"(Bgcc $B$H$+$G%3(B +$B%s%Q%$%k$7$?(B kernel driver $B$OF0:n$7$^$;$s!#(B + +$B$=$N$h$&$J>l9g$K$O!"(Bprecompiled binary $B$r(B +ftp://coombs.anu.edu.au/pub/net/ip-filter/ip_fil3.3.2-sparcv9.pkg.gz +(1999$BG/(B12$B7n(B14$BF|8=:_!"$^$@(B3.3.5$B$O%Q%C%1!<%8$K$J$C$F$$$^$;$s(B) +$B$+$i<h$C$F$/$k$+!"(BWorkshop Compiler 5.0 $B$G%3%s%Q%$%k$7$F(B 64bit +driver $B$r:n$C$F$/$@$5$$!#(B + +----- +$B@_Dj%U%!%$%k$N5-=RJ}K!(B + +IP filter$B$N@_Dj$O!V$I$N%"%I%l%9!W$N!V$I$N%]!<%H!W$+$i!V$I$N%"%I(B +$B%l%9!W$N!V$I$N%]!<%H!W$X$N%Q%1%C%H$r(B block $B$9$k$+(B pass $B$9$k$+!"(B +$B$r;XDj$9$k$3$H$G9T$$$^$9!#(B + +$B0J2<$NNc$G$O!"2f!9$,4IM}$7$F$$$k%5%V%M%C%H$h$j30$+$iFb$N%"%/%;%9(B +$B$O!"0lIt$N%^%7%s$r=|$$$F$OA4$F%V%m%C%/$7!"Fb$+$i30$X$N%"%/%;%9$O!"(B +$B86B'$H$7$FA4$FAGDL$7$9$k%]%j%7!<$G5-=R$5$l$F$$$^$9!#(B + +$B0J2<!"4IM}$7$F$$$k%5%V%M%C%H$r(B + 123.45.1.0/24 +$B$H$7$FNc$r<($7$^$9!#(B24$B$O%5%V%M%C%H%^%9%/$G$9!#(B + +$B$^$?!"(Bgateway $B$O(B + 123.45.1.111 (hme0) +$B$,(B LAN$BB&$N%$%s%?!<%U%'!<%9!"(B + 123.45.2.10 (hme1) +$B$,30B&$N%$%s%?!<%U%'!<%9$H$7$^$9!#(B + + +===================== $B$3$3$+$i(B ==================== +########## quickly deny malicious packets +# +block in quick from any to any with short +block in log quick from any to any with ipopts +===================== $B$3$3$^$G(B ==================== + +$B$^$:$O$3$N%k!<%k$G!"IT@5$J%Q%1%C%H$r$O$M$^$9!#(Bblock $B$O(B block $B$9(B +$B$k0UL#$G!"H?BP$KDL$9>l9g$O(B pass $B$H$J$j$^$9!#(B + +log $B$H$$$&$N$O!"$3$N%k!<%k$K%^%C%A$9$k%Q%1%C%H$N%m%0$r<h$k;X<($G(B +$B$9!#%m%0$O(B /dev/ipl $B$H$$$&%G%P%$%9%U%!%$%k$+$i%"%/%;%9$G$-$^$9$,!"(B +$B$3$N%G%P%$%9$O(B bounded buffer $B$J$N$G!"$"$kDxEY0J>e$N%m%0$O>C$($F(B +$B$7$^$$$^$9!#(B + +/dev/ipl $B$NFbMF$rFI$_=P$9$K$O(B ipmon $B$H$$$&%W%m%0%i%`$r;H$$$^$9!#(B +ipmon $B$O(B stdout, syslog, $B$b$7$/$ODL>o$N%U%!%$%k$K%m%0$r=PNO$7$^(B +$B$9!#5/F0;~$K(B ipmon $B$rN)$A>e$2$k$J$i!"<!$N$h$&$J9T$r(B rc $B%U%!%$%k(B +$B$K=q$/$H$h$$$G$7$g$&!#(B + +ipmon -n -o I ${IPMONLOG} < /dev/null > /dev/null 2>&1 & + +${IPMONLOG} $B$OE,Ev$J%U%!%$%kL>$KCV49$7$F$/$@$5$$!#(Bsyslog $B$K=PNO(B +$B$9$k>l9g$O!"(B-s $B%*%W%7%g%s$rIU$1$^$9!#(Bsyslog $B$K=PNO$9$k>l9g!"(B +local0.info $B$r5-O?$9$k$h$&$K(B syslog.conf $B$rJT=8$7$F$/$@$5$$!#(B +$BNc$($P!"(B + +local0.info ifdef(`LOGHOST', /var/log/syslog, @loghost) + + +quick $B$H$$$&$N$O!"$3$N%k!<%k$K%^%C%A$7$?%Q%1%C%H$O0J9_$N%k!<%k$r(B +$BD4$Y$:$K!"%"%/%7%g%s(B(block or pass)$B$K=>$o$;$k$H$$$&$b$N$G$9!#$?(B +$B$@$7!"Nc30$,$"$j$^$9!#8e=R$7$^$9!#(B + + +===================== $B$3$3$+$i(B ==================== +########## group setup +# +block in on hme1 all head 100 +block out on hme1 all head 150 +pass in quick on hme0 all +pass out quick on hme0 all +===================== $B$3$3$^$G(B ==================== + +$B<!$K@)8f$r$+$1$k%$%s%?!<%U%'!<%9Kh$K%Q%1%C%H$KE,MQ$9$k%k!<%k$rJ,(B +$BN`$7$^$9!#(Bhme0 $B$O(B LAN $BB&$N%$%s%?!<%U%'!<%9$J$N$G!"B(:B$K5v2D(B +(pass quick)$B$7$F$$$^$9!#(B + +all $B$H$$$&$N$O!"(Bfrom any to any $B$N>JN,7A$G$9!#(B + +$B30It$H$N%$%s%?!<%U%'!<%9$G$"$k(B hme1 $B$O(B incoming $B$H(B outgoing $B$G!"(B +$B$=$l$>$l(B group 100 $BHV$H(B 150 $BHV$KJ,N`$7$^$9!#(Bhead $B$H$$$&$N$O!"$3(B +$B$N%k!<%k$K%^%C%A$7$?%Q%1%C%H$r<!$NHV9f$N%0%k!<%W$KJ,N`$9$k$H$$$&(B +$B0UL#$G$9!#(B + + +===================== $B$3$3$+$i(B ==================== +########## deny IP spoofing +# +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from 123.45.2.10/32 to any group 100 +block in log quick from 123.45.1.111/24 to any group 100 +# +########## deny reserved addresses +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +===================== $B$3$3$^$G(B ==================== + +IP $B%"%I%l%9$r2~cb$7$?%Q%1%C%H$rB(:B$K5qH]$7$F$$$^$9!#KvHx$N(B +group 100 $B$H$$$&$N$O(B head 100 $B$GJ,N`$5$l$?%Q%1%C%H$K$N$_%^%C%A$9(B +$B$k%k!<%k$H$$$&0UL#$G$9!#(B + +----- +$B$3$3$^$G$G!"4pK\E*$K(BLAN$BFb$NDL?.$OAGDL$7$@$,30It$H$NDL?.$O%G%U%)(B +$B%k%H$G0l@Z6X;_$H$$$&@_Dj$K$J$j$^$9!#0J9_$G$O!"$=$N%G%U%)%k%H$KBP(B +$B$9$kNc30$H$$$&7A$G!"DL$7$?$$%Q%1%C%H$r5-=R$7$F$$$-$^$9!#(B + +$B$^$:!"FbIt$+$i30It$X$N@\B3$K4X$9$k@_Dj$r$7$^$9!#(B +===================== $B$3$3$+$i(B ==================== +########## OUTGOING +# +## allow ping out +# +pass out quick proto icmp from any to any keep state group 150 +# +## allow all outgoing UDP packets except for netbios ports (137-139). +# +pass out quick proto udp from any to any keep state head 160 group 150 +block out log quick proto udp from any to any port 136 >< 140 group 160 +# +## pass all TCP connection setup packets except for netbios ports (137-139). +# +pass out quick proto tcp from any to any flags S/SAFR keep state head 170 group 150 +block out log quick proto tcp from any to any port 136 >< 140 group 170 +===================== $B$3$3$^$G(B ==================== + +$B$3$l$O4pK\E*$KA4$F$N%Q%1%C%H$r5v$9%k!<%k$G$9!#$7$+$7!"(Bnetbios +(137-139/udp, tcp)$B$N%]!<%H$@$1$O6X;_$7$F$$$^$9!#(Bnetbios$B$O(B Windows +$B$N%U%!%$%k6&M-$G;H$o$l$k%]!<%H$G!"$3$N%]!<%H$,3+$$$F$$$k$H!"(B +Windows$B$N@_Dj$K$h$C$F$O!"@$3&Cf$+$i%U%!%$%k$rFI$_=q$-$G$-$k(B +$B62$l$,$"$j$^$9!#(B + +$B$3$3$G!"4JC1$K=q<0$r8+$F$*$/$H!"(B +* $B:G=i$NC18l$G!"(Bblock$B$9$k$+(Bpass$B$9$k$+;XDj$9$k(B +* proto $B$N8e$NC18l$G!"(Bprotocol$B$r;XDj$9$k(B(udp, tcp, icmp, etc.)$B!#(B +* from A to B $B$G!"$I$3$+$i$I$3$X$N%Q%1%C%H$+$r;XDj$9$k(B +* head XXX$B$r;XDj$9$k$H!"$=$N9T$G;XDj$5$l$"$?%Q%1%C%H$O!"(Bgroup + XXX$B$H$7$F;2>H$G$-$k(B +* group$B$r;XDj$9$k$3$H$G!"5,B'$rE,MQ$9$k8uJd$r(B($BM=$a(Bhead$B$G@_Dj$7$?(B) + group$B$K8BDj$G$-$k!#(B + +$B$^$?!"(Bfrom A to B$B$N(BA$B$d(BB$B$O!"(BIP$B%"%I%l%9$H(Bport$B$r=q$/$3$H$,$G$-$^$9!#(B + from any to any port 136 >< 140 +$B$H$$$&$N$O!"(B + $B!VG$0U$N%]!<%H$NG$0U$N%"%I%l%9$+$i!"(B137$BHV$+$i(B139$BHV%]!<%H$NG$0U$N(B + $B%"%I%l%9$X$N%Q%1%C%H!W(B +$B;XDj$7$F$$$k$3$H$K$J$j$^$9!#$^$?!"HV9f$NBe$o$j$K(B/etc/service$B$K5-(B +$B=R$5$l$F$$$k%5!<%S%9L>$r5-=R$9$k$3$H$b$G$-$^$9!#(B +$B$?$H$($P(B + from any to any port = telnet +$B$H(B + from any to any port = 23 +$B$OF1$80UL#$H$J$j$^$9!#(B + +$B$5$F!"$3$3$G(B quick $B$NNc30$r@bL@$7$F$*$-$^$9!#(Bquick $B$NIU$$$?(B +rule $B$,(B head $B$G?7$?$J%0%k!<%W$r:n$k>l9g!"=hM}$O$^$@$3$N;~E@(B +$B$G$O3NDj$7$^$;$s!#0J9_!"!V(Bhead $B$G@k8@$5$l$?%0%k!<%W$N%k!<%k!W(B +$B$N$_=hM}$9$k$H$$$&0UL#$K$J$j$^$9!#$G$9$+$i>e$N!"(B + +pass out quick proto udp from any to any keep state head 160 group 150 +block out log quick proto udp from any to any port 136 >< 140 group 160 + +$B$O!"$^$:(B 150$BHV%0%k!<%W$K%^%C%A$9$k(B UDP $B%Q%1%C%H$OAGDL$7(B +$B$9$k!"$,!"0J2<$N(B 160$BHV$KB0$9$k%k!<%k$r$^$@=hM}$9$k!#(B +$B$=$7$F(B2$B9TL\$G(B 160$BHV%0%k!<%W$KBP$7$F(B netbios packet $B$r(B +block $B$7$F$$$kLu$G$9!#(B +$B0l9TL\$K%^%C%A$7$?%Q%1%C%H$O0J2<$K$b$7(B150$BHV$N%0%k!<%W$N(B +$B%k!<%k$,$"$C$?$H$7$F$b!"L5;k$9$k$3$H$KCm0U$7$F$/$@$5$$!#(B + +---------- +$B<!$K!"30It$+$iFbIt$X$N%"%/%;%9$N@_Dj$r$7$^$9!#(B + +* $B%k!<%F%#%s%0>pJs(B(RIP)$B$N%Q%1%C%H$O!"A4It5v$7$^$9!#(B +pass in quick proto udp from any to any port = 520 keep state group 100 + +* ICMP$B$N%Q%1%C%H$OA4It5v$7$^$9!#(B +pass in quick proto icmp from any to any group 100 + +* $BFbIt$+$i30It$X$N(Bftp$B$r5v$9$?$a$K!"(Bftp-data port$B$+$i0lHL%]!<%H$X(B + $B$NG$0U$N@\B3$r<u$1IU$1$^$9!#$3$l$O(Bpassive mode$B$G$J$$(BFTP$B$N5sF0(B + $B$G$9!#(B +pass in quick proto tcp from any port = ftp-data to any port > 1023 flags S/SA keep state group 100 + + $B$7$+$7!"$3$l$O0lHL$K8@$C$FB?>/4m81$J9T0Y$G$9!#@\B3$G$-$k$N$,(B + 1024$BHV0J9_$N0lHL%]!<%H$K8BDj$O$5$l$^$9$,!"$"$^$j$*4+$a$G$-$^$;$s!#(B + $B$3$N9T$r2C$($:$K!"(Bpassive mode (ftp $B$G(B pasv $B%3%^%s%I$GF~$l$k(B) + $B$G(B FTP $B$r$9$k$3$H$r4+$a$^$9!#$J$*!":G6a$N(B FTP client $B$O:G=i(B + $B$+$i(B passive mode $B$KL5>r7o$G$7$F$7$^$&$b$N$,B?$$$h$&$G$9!#(B + +* sendmail$B$d(Bftpd$B$K7R$0$H!"Aj<j$,(Bident$B%]!<%H$X%"%/%;%9$7$F$/$k$3(B + $B$H$,$"$k$N$G!"(Bident port$B$r3+$1$^$9!#(Bident $B$ODL>o$O5/F0$5$l$F$$(B + $B$J$$(B daemon $B$J$N$G!"AGDL$7$7$F$b%;%-%e%j%F%#%[!<%k$K$J$k$3$H$O$"(B + $B$j$^$;$s(B(connection refused$B$K$J$k$@$1$G$9(B)$B!#$3$l$r3+$1$J$$$H!"(B + $BAj<jB&$O(B timeout $B$9$k$^$G@h$K?J$^$J$$$N$G!"(BFTP $B$d(B mail $B$NAw?.(B + $B$,$d$?$i$KCY$/$J$k$3$H$,$"$j$^$9!#(B + $B$b$7(B 113 $BHV%]!<%H$K@\B3$G$-$k$h$&$J$i!"$=$N%5!<%S%9$OB(:B$K(B + $BDd;_$9$k$3$H$r4+$a$^$9!#(B +pass in quick proto tcp from any to any port = 113 flags S/SA keep state group 100 + +------ +$B<!$K!"30It$+$i(B firewall $B$X$N%"%/%;%9$r5v$9%5!<%S%9$r5-=R$7$F$$$-(B +$B$^$9!#$^$:$O!"30It$+$i$N@\B3$r5v$7$?$$%[%9%H$K$D$$$F!"%0%k!<%WHV(B +$B9f$r$D$1$^$9!#(B + +===================== $B$3$3$+$i(B ==================== +## grouping by host +block in log quick proto tcp from any to 123.45.1.X flags S/SA head 110 group 100 +block in log quick proto tcp from any to 123.45.1.Y flags S/SA head 111 group 100 +===================== $B$3$3$^$G(B ==================== + +$B$3$l$G!"(B + $B30It$+$i(B 123.45.1.X $B$X$N@\B3$O(B group 110 + $B30It$+$i(B 123.45.1.Y $B$X$N@\B3$O(B group 111 +$B$G;2>H$9$k$3$H$,$G$-$^$9!#(B + +$BB>$K$b5v$7$?$$%[%9%H$rA}$d$7$?$$$H$-$O!">e$HF1MM$K$7$F!"(Bhead$B$N8e(B +$B$K!"?7$7$$?t;z(B(112, 113$B$J$I(B)$B$r3d$jEv$F$F$/$@$5$$!#(B + +$B$b$&0lEYCm0U$7$F$*$-$^$9$,!"(Bquick $B$H(B head $B$,F1;~$K8=$l$k%k!<%k(B +$B0J9_$G$O!"(Bhead $B$G@k8@$5$l$?%0%k!<%W$N%k!<%k$7$+E,MQ$5$l$J$/$J$j(B +$B$^$9!#$G$9$+$i!">e$N(B ident $B$d(B ftp data-port $B$N$h$&$K!"FbIt$N(B +$BA4$F$N%[%9%H$K%^%C%A$9$k%k!<%k$O!"$3$N%[%9%H$K$h$k%0%k!<%WJ,$1(B +$B$NA0$KCV$/I,MW$,$"$j$^$9!#(B + + +X$B$X$O!"(Btelnet, ftp, ssh $B$r!"(BY$B$X$O!"(Bftp, http, smtp, pop $B$r5v$9$3(B +$B$H$K$7$^$9!#(B + +* X(group 110)$B$X$N(Btelnet$B$r5v$7$^$9(B +pass in quick proto tcp from any to any port = telnet keep state group 110 + +* X$B$X$N(Bftp$B$r5v$7$^$9!#(Bftp-data port $B$b3+$1$F$*$-$^$9!#(B + ($BI,MW$,$"$k$+$I$&$+3NG'$O$7$F$$$^$;$s$,!"3+$1$F$$$F$b0BA4$G$7$g$&(B)$B!#(B +pass in quick proto tcp from any to any port = ftp keep state group 110 +pass in quick proto tcp from any to any port = ftp-data keep state group 110 + +* X$B$X$N(Bssh$B$r5v$7$^$9!#(B +pass in quick proto tcp from any to any port = 22 keep state group 110 + +* Y$B$X$N(Bftp$B$r5v$7$^$9!#(B +pass in quick proto tcp from any to any port = ftp keep state group 111 +pass in quick proto tcp from any to any port = ftp-data keep state group 111 +pass in quick proto tcp from any to any port 2999 >< 3100 keep state group 111 + + Y$B$O(B anonoymous ftp $B%5!<%P$r1?1D$7$F$$$k$?$a(B wu-ftpd $B$r;H$C$F$$(B + $B$^$9!#(Bwu-ftpd $B$O(B passive mode $B$N(BFTP$B$K$bBP1~$7$F$$$^$9$N$G!"$I(B + $B$N%]!<%H$r(BPASV$BMQ$K;H$&$+!"(Bwu-ftpd $B$N@_Dj$K=q$$$F$*$/I,MW$,$"$j(B + $B$^$9!#$3$3$G$O(B3000$B$+$i(B3099$BHV%]!<%H$r;HMQ$9$k$h$&$K!"(Bwu-ftpd $B$r(B + $B@_Dj$7$F$$$^$9!#(B + + passive FTP $B$K$D$$$F2r@b$7$^$9!#(Bpassive FTP $B$O!"%/%i%$%"%s%H$,(B + $B%U%!%$%"%&%)!<%k$NFbB&$K$$$k>l9g$N$?$a$K3+H/$5$l$?%W%m%H%3%k$G(B + $B$9!#%G%U%)%k%H$G$O>e$G@bL@$7$?$h$&$K!"%G!<%?E>Aw$N$?$a!"%5!<%P(B + $B$N(B ftp-data port $B$+$i%/%i%$%"%s%H$K@\B3$,$$$-$^$9!#(B + + passive FTP $B$G$O!"%G!<%?E>Aw$b(B client $B$+$i%5!<%P$K@\B3$9$k$h$&(B + $B$K$J$j$^$9!#$=$N:]!"%5!<%P$OE,Ev$J%]!<%HHV9f$r3d$j?6$C$F!"$=$3(B + $B$K%/%i%$%"%s%H$,@\B3$9$k$h$&;X<($7$^$9!#(B + + $B$3$N$?$a!"%5!<%P$,%U%!%$%"%&%)!<%kFb$K$$$k>l9g!"E,Ev$J%]!<%HHV(B + $B9f$O%U%!%$%"%&%)!<%k$G$O$M$i$l$F$7$^$$$^$9!#$=$3$G!"(Bwu-ftpd $B$N(B + $B@_Dj$G!"3d$j?6$k%]!<%HHV9f$NHO0O$r8BDj$7$F!"$=$3$@$1%U%!%$%"(B + $B%&%)!<%k$K7j$r3+$1$F$$$k$o$1$G$9!#(Bwu-ftpd $B$N>l9g$O!"(Bftpaccess + $B$H$$$&%U%!%$%k$K(B + + # passive ports <cidr> <min> <max> + passive ports 0.0.0.0/0 3000 3099 + + $B$HDI2C$9$k$3$H$G@_Dj$G$-$^$9!#(Bftpaccess(5)$B$r;2>H$7$F$/$@$5$$!#(B + +* Y$B$X$N(Bhttp$B$r5v$7$^$9!#(B +pass in quick proto tcp from any to any port = 80 keep state group 111 + +* Y$B$X$N(Bsmtp$B$r5v$7$^$9!#(B +pass in quick proto tcp from any to any port = smtp keep state group 111 + +* Y$B$X$N(Bpop$B$r5v$7$^$9!#(B +pass in quick proto tcp from any to any port = 110 keep state group 111 + +$B0J>e$N@_Dj$K$h$j!"(BX, Y $B0J30$N%^%7%s$X$N!"30It$+$i$N@\B3$O!"0l@Z(B +$B9T$($J$/$J$j$^$9$N$G!"(Bremote exploit $BBP:v$O!"(BX, Y $B$K$N$_9T$($P$h(B +$B$/$J$j!"4IM}$N<j4V$,7Z8:$G$-$^$9!#(B + +$BB>$N%W%m%H%3%k$rDL$9>l9g$b!">e$r;29M$K$7$FDL$7$?$$%]!<%HHV9f$r=q(B +$B$/$@$1$G$9$,!"$$$/$D$+Cm0UE@$,$"$j$^$9!#0J2<$bL\$rDL$7$F$/$@$5$$!#(B + +----- +$B$=$NB>$NCm0U(B + +1) gateway $B%^%7%s$N$h$&$K!"J#?t$N(BIP$B%"%I%l%9$r;}$D%^%7%s$G%5!<%S(B +$B%9$rN)$A>e$2$k>l9g$O!"$=$l$>$l$N(BIP$B%"%I%l%9$KBP$7$F!"(Bport $B$r3+$/(B +$BI,MW$,$"$j$^$9!#Nc$($P(B X $B$,(B IP:a $B$H(B IP:b $B$r;}$D$J$i!"(Bgroup $B$O(B a, +b $B$=$l$>$lMQ0U$7$F!"N>J}$N%0%k!<%WMQ$K(B rule $B$rDI2C$9$kI,MW$,$"$j(B +$B$^$9!#0J2<$NNc$G$O!"%2!<%H%&%'%$%^%7%s(B(123.45.2.10$B$H(B123.45.1.111 +$B$N(BIP$B$r;}$D(B)$B$K(BNNTP$B%5!<%P$rN)$F$F$$$^$9!#(B + +($BNc(B) +#### grouping by host +block in log quick proto tcp from any to 123.45.2.10 flags S/SA head 112 group 100 +block in log quick proto tcp from any to 123.45.1.111 flags S/SA head 113 group 100 +#### allow NNTP +pass in quick proto tcp from any to any port = nntp keep state group 112 +pass in quick proto tcp from any to any port = nntp keep state group 113 + +gateway $B$,(B2$B$D0J>e$"$k%M%C%H%o!<%/$G$O!"N>J}$N(B gateway $B$K(B IP +filter $B$,I,MW$K$J$j!"@_Dj$O99$KJ#;($K$J$j$^$9!#$=$N$h$&$J4D6-$N(B +$B>l9g$K$O!"%^%K%e%"%k$rFI$s$G8!F$$7$F$/$@$5$$!#(B + +2) NFS$B$H(Brsh$B$O%W%m%H%3%k$N4X78>e!"(Bfirewall$BD6$($OIT2DG=$G$9!#(B + NFS$B$NBeBX$K$D$$$F$OITL@$G$9$,!"(Brsh$B$NBeBX$H$7$F$O(Bssh$B$,;H$($^$9!#(B + +3) $B30It$N(BX client $B$r!"%U%!%$%"%&%)!<%kFb$N(BX$B%5!<%P$K@\B3$5$;$?$$!"(B + $B$H$$$&$N$O(B FAQ $B$N0l$D$G$9!#$*4+$a$N2r7h:v$O!"(Bssh $B$N(B X forwarding + $B5!9=$r;H$&$3$H$G$9!#(Bssh$B$G@\B3$G$-$k$J$i$P!"$3$l$O40A4$K(B secure + $B$GHFMQE*$JJ}K!$G$9!#(B + +$B$=$l$,=PMh$J$$>l9g$O!"2f!9$O@\B3$5$;$?$$%[%9%H$N%Z%"$r%f!<%6$KJs(B +$B9p$7$F$b$i$C$F!"0J2<$N$h$&$J%k!<%k$rDI2C$7$F$$$^$9!#(B +# X:0 $B$O(B tcp:6000 $BHV$K$J$j$^$9!#(B + +# 123.45.1.Z:0 (server) <-> A.B.C.D (client) +pass in quick proto tcp from A.B.C.D port > 1023 to 123.45.1.Z port = 6000 flags S/SA keep state group 100 + +----- +$B:G8e$K!";D$k%Q%1%C%H$OA4$F%V%m%C%/$5$l$kLu$G$9$,!"$=$l$K$D$$$F$N(B +$BA4$F$N%m%0$r;D$9$3$H$r4uK>$9$k>l9g!"<!$N%k!<%k$r!VI,$::G8e$K!W2C(B +$B$($^$9!#(B + +## log blocked packets +block in log quick from any to 123.45.1.111/24 group 100 +block in log quick from any to 123.45.2.10 group 100 + +------ +$B:#Kx$N@_Dj$r$R$H$D$K$^$H$a$?%U%!%$%k$r:G8e$KE:IU$7$^$9!#(B + +===================== $B$3$3$+$i(B ==================== +########## Packet Filtering Rules for 123.45.1. ########## +# +# The following routes should be configured, if not already: +# +# route add 123.45.1.111 localhost 0 (hme0) (LAN) +# route add 123.45.2.10 localhost 0 (hme1) (upstream) +# +########## quickly deny malicious packets +# +block in quick from any to any with short +block in log quick from any to any with ipopts +# +########## group setup +# +block in on hme1 all head 100 +block out on hme1 all head 150 +pass in quick on hme0 all +pass out quick on hme0 all +# +########## deny IP spoofing +# +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from 123.45.2.10/32 to any group 100 +block in log quick from 123.45.1.111/24 to any group 100 +# +########## deny reserved addresses +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +########## OUTGOING +# +## allow ping out +pass out quick proto icmp from any to any keep state group 150 +# +## allow all outgoing UDP packets except for netbios ports (137-139). +# +pass out quick proto udp from any to any keep state head 160 group 150 +block out log quick proto udp from any to any port 136 >< 140 group 160 +# +## pass all TCP connection setup packets except for netbios ports (137-139). +# +pass out quick proto tcp from any to any flags S/SAFR keep state head 170 group 150 +block out log quick proto tcp from any to any port 136 >< 140 group 170 +# +######### INCOMING +## ICMP +pass in quick proto icmp from any to any group 100 +## RIP +pass in quick proto udp from any to any port = 520 keep state group 100 +## FTP +pass in quick proto tcp from any port = ftp-data to any port > 1023 flags S/SA keep state group 100 +## IDENT +pass in quick proto tcp from any to any port = 113 flags S/SA keep state group 100 +# +## grouping by host (112 & 113 is the gateway address) +block in log quick proto tcp from any to 123.45.1.X flags S/SA head 110 group 100 +block in log quick proto tcp from any to 123.45.1.Y flags S/SA head 111 group 100 +block in log quick proto tcp from any to 123.45.2.10 flags S/SA head 112 group 100 +block in log quick proto tcp from any to 123.45.1.111 flags S/SA head 113 group 100 +# +## telnet, ftp, ssh, www, smtp, pop +pass in quick proto tcp from any to any port = telnet keep state group 110 +pass in quick proto tcp from any to any port = ftp keep state group 110 +pass in quick proto tcp from any to any port = ftp-data keep state group 110 +pass in quick proto tcp from any to any port = 22 keep state group 110 +pass in quick proto tcp from any to any port = ftp keep state group 111 +pass in quick proto tcp from any to any port = ftp-data keep state group 111 +pass in quick proto tcp from any to any port 2999 >< 3100 keep state group 111 +pass in quick proto tcp from any to any port = 80 keep state group 111 +pass in quick proto tcp from any to any port = smtp keep state group 111 +pass in quick proto tcp from any to any port = 110 keep state +group 111 +# +## allow NNTP on the gateway +pass in quick proto tcp from any to any port = nntp keep state group 112 +pass in quick proto tcp from any to any port = nntp keep state group 113 +# +## X connections +# 123.45.1.Z:0 (server) <-> A.B.C.D (client) +pass in quick proto tcp from A.B.C.D port > 1023 to 123.45.1.Z port = 6000 flags S/SA keep state group 100 +# +## log blocked packets +## THIS MUST BE THE LAST RULE! +block in log quick from any to 123.45.1.111/24 group 100 +block in log quick from any to 123.45.2.10 group 100 +===================== $B$3$3$^$G(B ==================== + +---- +$B$3$NJ8=q$N<h$j07$$$K$D$$$F(B +Copyright (C) 1999 TOYAMA Sumio <sumio@is.s.u-tokyo.ac.jp> + and YAMAMOTO Hirotaka <ymmt@is.s.u-tokyo.ac.jp> + +THIS DOCUMENT IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +Permission to modify this document and to distribute it is hereby +granted, as long as above notices and copyright notice are retained. diff --git a/contrib/ipfilter/LICENCE b/contrib/ipfilter/LICENCE index 903e886..f4cc8ee 100644 --- a/contrib/ipfilter/LICENCE +++ b/contrib/ipfilter/LICENCE @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * The author accepts no responsibility for the use of this software and * provides it on an ``as is'' basis without express or implied warranty. diff --git a/contrib/ipfilter/Makefile b/contrib/ipfilter/Makefile index a71aa57..050aac6 100644 --- a/contrib/ipfilter/Makefile +++ b/contrib/ipfilter/Makefile @@ -1,11 +1,11 @@ # -# Copyright (C) 1993-1998 by Darren Reed. +# Copyright (C) 1993-2000 by Darren Reed. # # Redistribution and use in source and binary forms are permitted # provided that this notice is preserved and due credit is given # to the original author and the contributors. # -# $Id: Makefile,v 2.2 1999/08/04 17:29:52 darrenr Exp $ +# $Id: Makefile,v 2.11.2.1 2000/04/26 12:14:58 darrenr Exp $ # BINDEST=/usr/local/bin SBINDEST=/sbin @@ -15,7 +15,7 @@ CC=gcc -Wstrict-prototypes -Wmissing-prototypes #CC=gcc #CC=cc -Dconst= DEBUG=-g -CFLAGS=-I$$(TOP) +CFLAGS=-I$$(TOP) -g CPU=`uname -m` CPUDIR=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m` # @@ -30,6 +30,26 @@ IPFLOG=-DIPFILTER_LOG # The facility you wish to log messages from ipmon to syslogd with. # LOGFAC=-DLOGFAC=LOG_LOCAL0 + +# +# Uncomment the next 3 lines if you want to view the state table a la top(1) +# (requires that you have installed ncurses). +#STATETOP_CFLAGS=-DSTATETOP +# +# Where to find the ncurses include files (if not in default path), +# +#STATETOP_INC= +#STATETOP_INC=-I/usr/local/include +# +# How to link the ncurses library +# +#STATETOP_LIB=-lncurses +#STATETOP_LIB=-L/usr/local/lib -lncurses + +# +# Uncomment this when building IPv6 capability. +# +#INET6=-DUSE_INET6 # # For packets which don't match any pass rules or any block rules, set either # FR_PASS or FR_BLOCK (respectively). It defaults to FR_PASS if left @@ -39,11 +59,12 @@ LOGFAC=-DLOGFAC=LOG_LOCAL0 # POLICY=-DIPF_DEFAULT_PASS=FR_PASS # -MFLAGS1="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" \ - 'CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2)' \ +MFLAGS1='CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2) $(INET6)' \ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \ - "CPUDIR=$(CPUDIR)" + "CPUDIR=$(CPUDIR)" 'STATETOP_CFLAGS=$(STATETOP_CFLAGS)' \ + 'STATETOP_INC=$(STATETOP_INC)' 'STATETOP_LIB=$(STATETOP_LIB)' +DEST="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" MFLAGS=$(MFLAGS1) "IPFLKM=$(IPFLKM)" # SHELL=/bin/sh @@ -65,6 +86,7 @@ all: @echo "freebsd - compile for FreeBSD 2.0, 2.1 or earlier" @echo "freebsd22 - compile for FreeBSD-2.2 or greater" @echo "freebsd3 - compile for FreeBSD-3.x" + @echo "freebsd4 - compile for FreeBSD-4.x" @echo "bsd - compile for generic 4.4BSD systems" @echo "bsdi - compile for BSD/OS" @echo "irix - compile for SGI IRIX" @@ -103,6 +125,11 @@ freebsd22: include fi make freebsd +freebsd4: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko" "DLKM=-DKLD_MODULE"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS1); cd ..) + freebsd3 freebsd30: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS1) "ML=mlf_ipl.c" LKM= ; cd ..) @@ -135,16 +162,16 @@ bsdi bsdos: include irix IRIX: include make setup "TARGOS=IRIX" "CPUDIR=$(CPUDIR)" - (cd IRIX/$(CPUDIR); smake build TOP=../.. $(MFLAGS); cd ..) - (cd IRIX/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd IRIX/$(CPUDIR); smake build TOP=../.. $(DEST) $(MFLAGS); cd ..) + (cd IRIX/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(DEST) $(MFLAGS); cd ..) linux: include make setup "TARGOS=Linux" "CPUDIR=$(CPUDIR)" ./buildlinux linuxrev: - (cd Linux/$(CPUDIR); make build TOP=../.. $(MFLAGS) LKM= ; cd ..) - (cd Linux/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd Linux/$(CPUDIR); make build TOP=../.. $(DEST) $(MFLAGS) LKM= ; cd ..) + (cd Linux/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(DEST) $(MFLAGS); cd ..) setup: -if [ ! -d $(TARGOS)/$(CPUDIR) ] ; then mkdir $(TARGOS)/$(CPUDIR); fi @@ -155,8 +182,8 @@ setup: clean: clean-include ${RM} -f core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl \ vnode_if.h $(LKM) *~ - if [ "`uname -s`" = "SunOS" ]; then (cd SunOS4; make clean); fi - if [ "`uname -s`" = "SunOS" ]; then (cd SunOS5; make clean); fi + (cd SunOS4; make clean) + (cd SunOS5; make clean) (cd BSD; make clean) (cd Linux; make clean) if [ "`uname -s`" = "IRIX" ]; then (cd IRIX; make clean); fi @@ -196,20 +223,20 @@ get: done sunos4 solaris1: - (cd SunOS4; make build TOP=.. "CC=$(CC)" $(MFLAGS); cd ..) - (cd SunOS4; make -f Makefile.ipsend "CC=$(CC)" TOP=.. $(MFLAGS); cd ..) + (cd SunOS4; make build TOP=.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) + (cd SunOS4; make -f Makefile.ipsend "CC=$(CC)" TOP=.. $(DEST) $(MFLAGS); cd ..) sunos5 solaris2: - (cd SunOS5/$(CPUDIR); make build TOP=../.. "CC=$(CC)" $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Dsparc -D__sparc__"; cd ..) - (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend TOP=../.. "CC=$(CC)" $(MFLAGS); cd ..) + (cd SunOS5/$(CPUDIR); make build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Dsparc -D__sparc__"; cd ..) + (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) sunos5x86 solaris2x86: - (cd SunOS5/$(CPUDIR); make build TOP=../.. "CC=$(CC)" $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Di86pc -Di386 -D__i386__"; cd ..) - (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend TOP=../.. "CC=$(CC)" $(MFLAGS); cd ..) + (cd SunOS5/$(CPUDIR); make build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Di86pc -Di386 -D__i386__"; cd ..) + (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) install-linux: - (cd Linux/$(CPUDIR); make install "TOP=../.." $(MFLAGS); cd ..) - (cd Linux/$(CPUDIR); make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(MFLAGS); cd ..) + (cd Linux/$(CPUDIR); make install "TOP=../.." $(DEST) $(MFLAGS); cd ..) + (cd Linux/$(CPUDIR); make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(DEST) $(MFLAGS); cd ..) install-bsd: (cd BSD/$(CPUDIR); make install "TOP=../.." $(MFLAGS); cd ..) @@ -222,7 +249,7 @@ install-sunos5: solaris (cd SunOS5; $(MAKE) "CPU=$(CPU) TOP=.." install) install-irix: irix - (cd IRIX; smake install "CPU=$(CPU) TOP=.." $(MFLAGS)) + (cd IRIX; smake install "CPU=$(CPU) TOP=.." $(DEST) $(MFLAGS)) rcsget: -@for i in ipf.c ipt.h solaris.c ipf.h kmem.c ipft_ef.c linux.h \ diff --git a/contrib/ipfilter/common.c b/contrib/ipfilter/common.c new file mode 100644 index 0000000..935f3fb --- /dev/null +++ b/contrib/ipfilter/common.c @@ -0,0 +1,595 @@ +/* + * Copyright (C) 1993-2000 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + */ +#include <sys/types.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#else +#include <sys/byteorder.h> +#endif +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <ctype.h> +#include <syslog.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ipf.h" +#include "facpri.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 darrenr Exp $"; +#endif + +extern struct ipopt_names ionames[], secclass[]; +extern int opts; +#ifdef USE_INET6 +extern int use_inet6; +#endif + + +char *proto = NULL; +char flagset[] = "FSRPAU"; +u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG }; + +#ifdef USE_INET6 +void fill6bits __P((int, u_32_t *)); +int count6bits __P((u_32_t *)); +#endif + +static char thishost[MAXHOSTNAMELEN]; + + +void initparse() +{ + gethostname(thishost, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; +} + + +int genmask(msk, mskp) +char *msk; +u_32_t *mskp; +{ + char *endptr = NULL; +#ifdef USE_INET6 + u_32_t addr; +#endif + int bits; + + if (index(msk, '.') || index(msk, 'x') || index(msk, ':')) { + /* possibly of the form xxx.xxx.xxx.xxx + * or 0xYYYYYYYY */ +#ifdef USE_INET6 + if (use_inet6) { + if (inet_pton(AF_INET6, msk, &addr) != 1) + return -1; + } else +#endif + if (inet_aton(msk, (struct in_addr *)mskp) == 0) + return -1; + } else { + /* + * set x most significant bits + */ + bits = (int)strtol(msk, &endptr, 0); +#ifdef USE_INET6 + if ((*endptr != '\0') || + ((bits > 32) && !use_inet6) || (bits < 0) || + ((bits > 128) && use_inet6)) +#else + if (*endptr != '\0' || bits > 32 || bits < 0) +#endif + return -1; +#ifdef USE_INET6 + if (use_inet6) + fill6bits(bits, mskp); + else +#endif + if (bits == 0) + *mskp = 0; + else + *mskp = htonl(0xffffffff << (32 - bits)); + } + return 0; +} + + + +#ifdef USE_INET6 +void fill6bits(bits, msk) +int bits; +u_32_t *msk; +{ + int i; + + for (i = 0; bits >= 32 && i < 4 ; ++i, bits -= 32) + msk[i] = 0xffffffff; + + if (bits > 0 && i < 4) + msk[i++] = htonl(0xffffffff << (32 - bits)); + + while (i < 4) + msk[i++] = 0; +} +#endif + + +/* + * returns -1 if neither "hostmask/num" or "hostmask mask addr" are + * found in the line segments, there is an error processing this information, + * or there is an error processing ports information. + */ +int hostmask(seg, sa, msk, pp, cp, tp, linenum) +char ***seg; +u_32_t *sa, *msk; +u_short *pp, *tp; +int *cp; +int linenum; +{ + struct in_addr maskaddr; + char *s; + + /* + * is it possibly hostname/num ? + */ + if ((s = index(**seg, '/')) || + ((s = index(**seg, ':')) && !index(s + 1, ':'))) { + *s++ = '\0'; + if (genmask(s, msk) == -1) { + fprintf(stderr, "%d: bad mask (%s)\n", linenum, s); + return -1; + } + if (hostnum(sa, **seg, linenum) == -1) { + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); + return -1; + } + *sa &= *msk; + (*seg)++; + return ports(seg, pp, cp, tp, linenum); + } + + /* + * look for extra segments if "mask" found in right spot + */ + if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) { + if (hostnum(sa, **seg, linenum) == -1) { + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); + return -1; + } + (*seg)++; + (*seg)++; + if (inet_aton(**seg, &maskaddr) == 0) { + fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg); + return -1; + } + *msk = maskaddr.s_addr; + (*seg)++; + *sa &= *msk; + return ports(seg, pp, cp, tp, linenum); + } + + if (**seg) { + if (hostnum(sa, **seg, linenum) == -1) { + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); + return -1; + } + (*seg)++; +#ifdef USE_INET6 + if (use_inet6) { + u_32_t k = 0; + if (sa[0] || sa[1] || sa[2] || sa[3]) + k = 0xffffffff; + msk[0] = msk[1] = msk[2] = msk[3] = k; + } + else +#endif + *msk = *sa ? 0xffffffff : 0; + return ports(seg, pp, cp, tp, linenum); + } + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); + return -1; +} + +/* + * returns an ip address as a long var as a result of either a DNS lookup or + * straight inet_addr() call + */ +int hostnum(ipa, host, linenum) +u_32_t *ipa; +char *host; +int linenum; +{ + struct hostent *hp; + struct netent *np; + struct in_addr ip; + + if (!strcasecmp("any", host)) + return 0; +#ifdef USE_INET6 + if (use_inet6) { + if (inet_pton(AF_INET6, host, ipa) == 1) + return 0; + else + return -1; + } +#endif + if (isdigit(*host) && inet_aton(host, &ip)) { + *ipa = ip.s_addr; + return 0; + } + + if (!strcasecmp("<thishost>", host)) + host = thishost; + + if (!(hp = gethostbyname(host))) { + if (!(np = getnetbyname(host))) { + fprintf(stderr, "%d: can't resolve hostname: %s\n", + linenum, host); + return -1; + } + *ipa = htonl(np->n_net); + return 0; + } + *ipa = *(u_32_t *)hp->h_addr; + return 0; +} + + +/* + * check for possible presence of the port fields in the line + */ +int ports(seg, pp, cp, tp, linenum) +char ***seg; +u_short *pp, *tp; +int *cp; +int linenum; +{ + int comp = -1; + + if (!*seg || !**seg || !***seg) + return 0; + if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) { + (*seg)++; + if (isdigit(***seg) && *(*seg + 2)) { + if (portnum(**seg, pp, linenum) == 0) + return -1; + (*seg)++; + if (!strcmp(**seg, "<>")) + comp = FR_OUTRANGE; + else if (!strcmp(**seg, "><")) + comp = FR_INRANGE; + else { + fprintf(stderr, + "%d: unknown range operator (%s)\n", + linenum, **seg); + return -1; + } + (*seg)++; + if (**seg == NULL) { + fprintf(stderr, "%d: missing 2nd port value\n", + linenum); + return -1; + } + if (portnum(**seg, tp, linenum) == 0) + return -1; + } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq")) + comp = FR_EQUAL; + else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne")) + comp = FR_NEQUAL; + else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt")) + comp = FR_LESST; + else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt")) + comp = FR_GREATERT; + else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le")) + comp = FR_LESSTE; + else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge")) + comp = FR_GREATERTE; + else { + fprintf(stderr, "%d: unknown comparator (%s)\n", + linenum, **seg); + return -1; + } + if (comp != FR_OUTRANGE && comp != FR_INRANGE) { + (*seg)++; + if (portnum(**seg, pp, linenum) == 0) + return -1; + } + *cp = comp; + (*seg)++; + } + return 0; +} + + +/* + * find the port number given by the name, either from getservbyname() or + * straight atoi(). Return 1 on success, 0 on failure + */ +int portnum(name, port, linenum) +char *name; +u_short *port; +int linenum; +{ + struct servent *sp, *sp2; + u_short p1 = 0; + int i; + + if (isdigit(*name)) { + if (ratoi(name, &i, 0, USHRT_MAX)) { + *port = (u_short)i; + return 1; + } + fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name); + return 0; + } + if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) { + sp = getservbyname(name, proto); + if (sp) { + *port = ntohs(sp->s_port); + return 1; + } + fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name); + return 0; + } + sp = getservbyname(name, "tcp"); + if (sp) + p1 = sp->s_port; + sp2 = getservbyname(name, "udp"); + if (!sp || !sp2) { + fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n", + linenum, name); + return 0; + } + if (p1 != sp2->s_port) { + fprintf(stderr, "%d: %s %d/tcp is a different port to ", + linenum, name, p1); + fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port); + return 0; + } + *port = ntohs(p1); + return 1; +} + + +u_char tcp_flags(flgs, mask, linenum) +char *flgs; +u_char *mask; +int linenum; +{ + u_char tcpf = 0, tcpfm = 0, *fp = &tcpf; + char *s, *t; + + if (*flgs == '0') { + s = strchr(flgs, '/'); + if (s) + *s++ = '\0'; + tcpf = strtol(flgs, NULL, 0); + fp = &tcpfm; + } else + s = flgs; + + for (; *s; s++) { + if (*s == '/' && fp == &tcpf) { + fp = &tcpfm; + if (*(s + 1) == '0') + break; + continue; + } + if (!(t = index(flagset, *s))) { + fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s); + return 0; + } + *fp |= flags[t - flagset]; + } + + if (s && *s == '0') + tcpfm = strtol(s, NULL, 0); + + if (!tcpfm) + tcpfm = 0xff; + *mask = tcpfm; + return tcpf; +} + + +/* + * count consecutive 1's in bit mask. If the mask generated by counting + * consecutive 1's is different to that passed, return -1, else return # + * of bits. + */ +int countbits(ip) +u_32_t ip; +{ + u_32_t ipn; + int cnt = 0, i, j; + + ip = ipn = ntohl(ip); + for (i = 32; i; i--, ipn *= 2) + if (ipn & 0x80000000) + cnt++; + else + break; + ipn = 0; + for (i = 32, j = cnt; i; i--, j--) { + ipn *= 2; + if (j > 0) + ipn++; + } + if (ipn == ip) + return cnt; + return -1; +} + + +#ifdef USE_INET6 +int count6bits(msk) +u_32_t *msk; +{ + int i = 0, k; + u_32_t j; + + for (k = 3; k >= 0; k--) + if (msk[k] == 0xffffffff) + i += 32; + else { + for (j = msk[k]; j; j <<= 1) + if (j & 0x80000000) + i++; + } + return i; +} +#endif + + +char *portname(pr, port) +int pr, port; +{ + static char buf[32]; + struct protoent *p = NULL; + struct servent *sv = NULL, *sv1 = NULL; + + if (pr == -1) { + if ((sv = getservbyport(htons(port), "tcp"))) { + strncpy(buf, sv->s_name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + sv1 = getservbyport(htons(port), "udp"); + sv = strncasecmp(buf, sv->s_name, strlen(buf)) ? + NULL : sv1; + } + if (sv) + return buf; + } else if (pr && (p = getprotobynumber(pr))) { + if ((sv = getservbyport(htons(port), p->p_name))) { + strncpy(buf, sv->s_name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + return buf; + } + } + + (void) sprintf(buf, "%d", port); + return buf; +} + + +int ratoi(ps, pi, min, max) +char *ps; +int *pi, min, max; +{ + int i; + char *pe; + + i = (int)strtol(ps, &pe, 0); + if (*pe != '\0' || i < min || i > max) + return 0; + *pi = i; + return 1; +} + + +int ratoui(ps, pi, min, max) +char *ps; +u_int *pi, min, max; +{ + u_int i; + char *pe; + + i = (u_int)strtol(ps, &pe, 0); + if (*pe != '\0' || i < min || i > max) + return 0; + *pi = i; + return 1; +} + + +void printhostmask(v, addr, mask) +int v; +u_32_t *addr, *mask; +{ + struct in_addr ipa; + int ones; + +#ifdef USE_INET6 + if (v == 6) { + ones = count6bits(mask); + if (ones == 0 && !addr[0] && !addr[1] && !addr[2] && !addr[3]) + printf("any"); + else { + char ipbuf[64]; + printf("%s/%d", + inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf)), + ones); + } + } + else +#endif + if (!*addr && !*mask) + printf("any"); + else { + ipa.s_addr = *addr; + printf("%s", inet_ntoa(ipa)); + if ((ones = countbits(*mask)) == -1) { + ipa.s_addr = *mask; + printf("/%s", inet_ntoa(ipa)); + } else + printf("/%d", ones); + } +} + + +void printportcmp(pr, frp) +int pr; +frpcmp_t *frp; +{ + static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=", + "<>", "><"}; + + if (frp->frp_cmp == FR_INRANGE || frp->frp_cmp == FR_OUTRANGE) + printf(" port %d %s %d", frp->frp_port, + pcmp1[frp->frp_cmp], frp->frp_top); + else + printf(" port %s %s", pcmp1[frp->frp_cmp], + portname(pr, frp->frp_port)); +} + + +void printbuf(buf, len, zend) +char *buf; +int len, zend; +{ + char *s, c; + int i; + + for (s = buf, i = len; i; i--) { + c = *s++; + if (isprint(c)) + putchar(c); + else + printf("\\%03o", c); + if ((c == '\0') && zend) + break; + } +} diff --git a/contrib/ipfilter/facpri.c b/contrib/ipfilter/facpri.c index 510f3be..f851918 100644 --- a/contrib/ipfilter/facpri.c +++ b/contrib/ipfilter/facpri.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -19,7 +19,7 @@ #include "facpri.h" #if !defined(lint) -static const char rcsid[] = "@(#)$Id: facpri.c,v 1.2 1999/08/01 11:10:45 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: facpri.c,v 1.3 2000/03/13 22:10:18 darrenr Exp $"; #endif typedef struct table { diff --git a/contrib/ipfilter/facpri.h b/contrib/ipfilter/facpri.h index d39a159..b80dbe8 100644 --- a/contrib/ipfilter/facpri.h +++ b/contrib/ipfilter/facpri.h @@ -1,10 +1,10 @@ /* - * Copyright (C) 1999 by Darren Reed. + * Copyright (C) 1999-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. - * $Id: facpri.h,v 1.2 1999/08/01 11:10:46 darrenr Exp $ + * $Id: facpri.h,v 1.3 2000/03/13 22:10:18 darrenr Exp $ */ #ifndef __FACPRI_H__ diff --git a/contrib/ipfilter/fil.c b/contrib/ipfilter/fil.c index f527bdb..258f76e 100644 --- a/contrib/ipfilter/fil.c +++ b/contrib/ipfilter/fil.c @@ -1,15 +1,19 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darrenr Exp $"; +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.8 2000/05/22 10:26:09 darrenr Exp $"; #endif +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif #include <sys/errno.h> #include <sys/types.h> #include <sys/param.h> @@ -19,7 +23,7 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darre defined(_KERNEL) # include "opt_ipfilter_log.h" #endif -#if defined(KERNEL) && defined(__FreeBSD_version) && \ +#if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \ (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> @@ -68,6 +72,12 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darre #include <netinet/udp.h> #include <netinet/ip_icmp.h> #include "netinet/ip_compat.h" +#ifdef USE_INET6 +# include <netinet/icmp6.h> +# if !SOLARIS && defined(_KERNEL) +# include <netinet6/in6_var.h> +# endif +#endif #include <netinet/tcpip.h> #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" @@ -91,18 +101,10 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darre # include "ipt.h" extern int opts; -# define FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; \ - second; } -# define FR_IFDEBUG(ex,second,verb_pr) if (ex) { debug verb_pr; \ - second; } # define FR_VERBOSE(verb_pr) verbose verb_pr # define FR_DEBUG(verb_pr) debug verb_pr -# define SEND_RESET(ip, qif, if, m, fin) send_reset(ip, if) # define IPLLOG(a, c, d, e) ipllog() -# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) #else /* #ifndef _KERNEL */ -# define FR_IFVERBOSE(ex,second,verb_pr) ; -# define FR_IFDEBUG(ex,second,verb_pr) ; # define FR_VERBOSE(verb_pr) # define FR_DEBUG(verb_pr) # define IPLLOG(a, c, d, e) ipflog(a, c, d, e) @@ -114,27 +116,24 @@ extern kmutex_t ipf_rw; # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, \ ip, qif) # define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip, qif) -# define ICMP_ERROR(b, ip, t, c, if, dst) \ - icmp_error(ip, t, c, if, dst) # else /* SOLARIS */ # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) -# ifdef linux -# define SEND_RESET(ip, qif, if, fin) send_reset(ip, ifp) -# define ICMP_ERROR(b, ip, t, c, if, dst) icmp_send(b,t,c,0,if) -# else -# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip) -# define ICMP_ERROR(b, ip, t, c, if, dst) \ - send_icmp_err(ip, t, c, if, dst) -# endif /* linux */ +# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip) # endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}}; struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } }, +#ifdef USE_INET6 + *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } }, + *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } }, +#endif *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }; struct frgroup *ipfgroups[3][2]; -int fr_flags = IPF_LOGGING, fr_active = 0; +int fr_flags = IPF_LOGGING; +int fr_active = 0; +int fr_chksrc = 0; #if defined(IPFILTER_DEFAULT_BLOCK) int fr_pass = FR_NOMATCH|FR_BLOCK; #else @@ -144,7 +143,6 @@ char ipfilter_version[] = IPL_VERSION; fr_info_t frcache[2]; -static int fr_tcpudpchk __P((frentry_t *, fr_info_t *)); static int frflushlist __P((int, minor_t, int *, frentry_t **)); #ifdef _KERNEL static void frsynclist __P((frentry_t *)); @@ -201,12 +199,12 @@ int hlen; ip_t *ip; fr_info_t *fin; { - struct optlist *op; - tcphdr_t *tcp; - fr_ip_t *fi = &fin->fin_fi; u_short optmsk = 0, secmsk = 0, auth = 0; - int i, mv, ol, off; + int i, mv, ol, off, p, plen, v; + fr_ip_t *fi = &fin->fin_fi; + struct optlist *op; u_char *s, opt; + tcphdr_t *tcp; fin->fin_rev = 0; fin->fin_fr = NULL; @@ -215,25 +213,59 @@ fr_info_t *fin; fin->fin_data[1] = 0; fin->fin_rule = -1; fin->fin_group = -1; - fin->fin_id = ip->ip_id; #ifdef _KERNEL fin->fin_icode = ipl_unreach; #endif - fi->fi_v = ip->ip_v; - fi->fi_tos = ip->ip_tos; + v = fin->fin_v; + fi->fi_v = v; fin->fin_hlen = hlen; - fin->fin_dlen = ip->ip_len - hlen; - tcp = (tcphdr_t *)((char *)ip + hlen); + if (v == 4) { + fin->fin_id = ip->ip_id; + fi->fi_tos = ip->ip_tos; + off = (ip->ip_off & IP_OFFMASK) << 3; + tcp = (tcphdr_t *)((char *)ip + hlen); + (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); + fi->fi_src.i6[1] = 0; + fi->fi_src.i6[2] = 0; + fi->fi_src.i6[3] = 0; + fi->fi_dst.i6[1] = 0; + fi->fi_dst.i6[2] = 0; + fi->fi_dst.i6[3] = 0; + fi->fi_saddr = ip->ip_src.s_addr; + fi->fi_daddr = ip->ip_dst.s_addr; + p = ip->ip_p; + fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; + if (ip->ip_off & 0x3fff) + fi->fi_fl |= FI_FRAG; + plen = ip->ip_len; + fin->fin_dlen = plen - hlen; + } +#ifdef USE_INET6 + else if (v == 6) { + ip6_t *ip6 = (ip6_t *)ip; + + off = 0; + p = ip6->ip6_nxt; + fi->fi_p = p; + fi->fi_ttl = ip6->ip6_hlim; + tcp = (tcphdr_t *)(ip6 + 1); + fi->fi_src.in6 = ip6->ip6_src; + fi->fi_dst.in6 = ip6->ip6_dst; + fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff); + fi->fi_tos = 0; + fi->fi_fl = 0; + plen = ntohs(ip6->ip6_plen); + fin->fin_dlen = plen; + } +#endif + else + return; + + fin->fin_off = off; + fin->fin_plen = plen; fin->fin_dp = (void *)tcp; - (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); - fi->fi_src.s_addr = ip->ip_src.s_addr; - fi->fi_dst.s_addr = ip->ip_dst.s_addr; - - fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; - off = (ip->ip_off & IP_OFFMASK) << 3; - if (ip->ip_off & 0x3fff) - fi->fi_fl |= FI_FRAG; - switch (ip->ip_p) + + switch (p) { case IPPROTO_ICMP : { @@ -245,13 +277,19 @@ fr_info_t *fin; if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || icmp->icmp_type == ICMP_ECHO)) minicmpsz = ICMP_MINLEN; - if (!off && (icmp->icmp_type == ICMP_TSTAMP || - icmp->icmp_type == ICMP_TSTAMPREPLY)) - minicmpsz = 20; /* type(1) + code(1) + cksum(2) + id(2) + seq(2) + 3*timestamp(3*4) */ - if (!off && (icmp->icmp_type == ICMP_MASKREQ || - icmp->icmp_type == ICMP_MASKREPLY)) - minicmpsz = 12; /* type(1) + code(1) + cksum(2) + id(2) + seq(2) + mask(4) */ - if ((!(ip->ip_len >= hlen + minicmpsz) && !off) || + + /* type(1) + code(1) + cksum(2) + id(2) seq(2) + + * 3*timestamp(3*4) */ + else if (!off && (icmp->icmp_type == ICMP_TSTAMP || + icmp->icmp_type == ICMP_TSTAMPREPLY)) + minicmpsz = 20; + + /* type(1) + code(1) + cksum(2) + id(2) seq(2) + mask(4) */ + else if (!off && (icmp->icmp_type == ICMP_MASKREQ || + 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) @@ -260,17 +298,33 @@ fr_info_t *fin; } case IPPROTO_TCP : fi->fi_fl |= FI_TCPUDP; - if ((!IPMINLEN(ip, tcphdr) && !off) || - (off && off < sizeof(struct tcphdr))) - fi->fi_fl |= FI_SHORT; +#ifdef USE_INET6 + if (v == 6) { + if (plen < sizeof(struct tcphdr)) + fi->fi_fl |= FI_SHORT; + } else +#endif + if (v == 4) { + if ((!IPMINLEN(ip, tcphdr) && !off) || + (off && off < sizeof(struct tcphdr))) + fi->fi_fl |= FI_SHORT; + } if (!(fi->fi_fl & FI_SHORT) && !off) fin->fin_tcpf = tcp->th_flags; goto getports; case IPPROTO_UDP : fi->fi_fl |= FI_TCPUDP; - if ((!IPMINLEN(ip, udphdr) && !off) || - (off && off < sizeof(struct udphdr))) - fi->fi_fl |= FI_SHORT; +#ifdef USE_INET6 + if (v == 6) { + if (plen < sizeof(struct udphdr)) + fi->fi_fl |= FI_SHORT; + } else +#endif + if (v == 4) { + if ((!IPMINLEN(ip, udphdr) && !off) || + (off && off < sizeof(struct udphdr))) + fi->fi_fl |= FI_SHORT; + } getports: if (!off && (fin->fin_dlen > 3)) { fin->fin_data[0] = ntohs(tcp->th_sport); @@ -281,14 +335,28 @@ getports: break; } +#ifdef USE_INET6 + if (v == 6) { + fi->fi_optmsk = 0; + fi->fi_secmsk = 0; + fi->fi_auth = 0; + return; + } +#endif - for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen; ) { + for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { opt = *s; if (opt == '\0') break; - ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1); - if (opt > 1 && (ol < 2 || ol > hlen)) - break; + else if (opt == IPOPT_NOP) + ol = 1; + else { + if (hlen < 2) + break; + ol = (int)*(s + 1); + if (ol < 2 || ol > hlen) + break; + } for (i = 9, mv = 4; mv >= 0; ) { op = ipopts + i; if (opt == (u_char)op->ol_val) { @@ -335,8 +403,8 @@ getports: /* * check an IP packet for TCP/UDP characteristics such as ports and flags. */ -static int fr_tcpudpchk(fr, fin) -frentry_t *fr; +int fr_tcpudpchk(ft, fin) +frtuc_t *ft; fr_info_t *fin; { register u_short po, tup; @@ -349,8 +417,8 @@ fr_info_t *fin; * * compare destination ports */ - if ((i = (int)fr->fr_dcmp)) { - po = fr->fr_dport; + if ((i = (int)ft->ftu_dcmp)) { + po = ft->ftu_dport; tup = fin->fin_data[1]; /* * Do opposite test to that required and @@ -369,17 +437,17 @@ fr_info_t *fin; else if (!--i && tup < po) /* GT or EQ */ err = 0; else if (!--i && /* Out of range */ - (tup >= po && tup <= fr->fr_dtop)) + (tup >= po && tup <= ft->ftu_dtop)) err = 0; else if (!--i && /* In range */ - (tup <= po || tup >= fr->fr_dtop)) + (tup <= po || tup >= ft->ftu_dtop)) err = 0; } /* * compare source ports */ - if (err && (i = (int)fr->fr_scmp)) { - po = fr->fr_sport; + if (err && (i = (int)ft->ftu_scmp)) { + po = ft->ftu_sport; tup = fin->fin_data[0]; if (!--i && tup != po) err = 0; @@ -394,10 +462,10 @@ fr_info_t *fin; else if (!--i && tup < po) err = 0; else if (!--i && /* Out of range */ - (tup >= po && tup <= fr->fr_stop)) + (tup >= po && tup <= ft->ftu_stop)) err = 0; else if (!--i && /* In range */ - (tup <= po || tup >= fr->fr_stop)) + (tup <= po || tup >= ft->ftu_stop)) err = 0; } @@ -409,14 +477,14 @@ fr_info_t *fin; */ if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { if (fin->fin_fi.fi_fl & FI_SHORT) - return !(fr->fr_tcpf | fr->fr_tcpfm); + return !(ft->ftu_tcpf | ft->ftu_tcpfm); /* * Match the flags ? If not, abort this match. */ - if (fr->fr_tcpfm && - fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) { + if (ft->ftu_tcpfm && + ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) { FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, - fr->fr_tcpfm, fr->fr_tcpf)); + ft->ftu_tcpfm, ft->ftu_tcpf)); err = 0; } } @@ -443,7 +511,10 @@ void *m; fin->fin_fr = NULL; fin->fin_rule = 0; fin->fin_group = 0; - off = ip->ip_off & IP_OFFMASK; + if (fin->fin_v == 4) + off = ip->ip_off & IP_OFFMASK; + else + off = 0; pass |= (fi->fi_fl << 24); if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) @@ -487,23 +558,77 @@ void *m; lip = (u_32_t *)fi; lm = (u_32_t *)&fr->fr_mip; ld = (u_32_t *)&fr->fr_ip; - i = ((lip[0] & lm[0]) != ld[0]); - FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n", - lip[0], lm[0], ld[0])); - i |= ((lip[1] & lm[1]) != ld[1]) << 19; + i = ((*lip & *lm) != *ld); + FR_DEBUG(("0. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + continue; + /* + * We now know whether the packet version and the + * rule version match, along with protocol, ttl and + * tos. + */ + lip++, lm++, ld++; + /* + * Unrolled loops (4 each, for 32 bits). + */ + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } i ^= (fr->fr_flags & FR_NOTSRCIP); - FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n", - lip[1], lm[1], ld[1])); - i |= ((lip[2] & lm[2]) != ld[2]) << 20; + if (i) + continue; + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } i ^= (fr->fr_flags & FR_NOTDSTIP); - FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n", - lip[2], lm[2], ld[2])); - i |= ((lip[3] & lm[3]) != ld[3]); - FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n", - lip[3], lm[3], ld[3])); - i |= ((lip[4] & lm[4]) != ld[4]); - FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n", - lip[4], lm[4], ld[4])); + if (i) + continue; + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("4. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); if (i) continue; } @@ -516,7 +641,7 @@ void *m; fr->fr_tcpfm)) continue; if (fi->fi_fl & FI_TCPUDP) { - if (!fr_tcpudpchk(fr, fin)) + if (!fr_tcpudpchk(&fr->fr_tuc, fin)) continue; } else if (fr->fr_icmpm || fr->fr_icmp) { if ((fi->fi_p != IPPROTO_ICMP) || off || @@ -540,16 +665,18 @@ void *m; #ifdef IPFILTER_LOG if ((passt & FR_LOGMASK) == FR_LOG) { if (!IPLLOG(passt, ip, fin, m)) { - ATOMIC_INC(frstats[fin->fin_out].fr_skip); + if (passt & FR_LOGORBLOCK) + passt |= FR_BLOCK|FR_QUICK; + ATOMIC_INCL(frstats[fin->fin_out].fr_skip); } - ATOMIC_INC(frstats[fin->fin_out].fr_pkl); + ATOMIC_INCL(frstats[fin->fin_out].fr_pkl); logged = 1; } #endif /* IPFILTER_LOG */ if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG) pass = passt; FR_DEBUG(("pass %#x\n", pass)); - ATOMIC_INC(fr->fr_hits); + ATOMIC_INCL(fr->fr_hits); if (pass & FR_ACCOUNT) fr->fr_bytes += (U_QUAD_T)ip->ip_len; else @@ -599,8 +726,8 @@ int out; */ fr_info_t frinfo, *fc; register fr_info_t *fin = &frinfo; - frentry_t *fr = NULL; - int changed, error = EHOSTUNREACH; + int changed, error = EHOSTUNREACH, v = ip->ip_v; + frentry_t *fr = NULL, *list; u_32_t pass, apass; #if !SOLARIS || !defined(_KERNEL) register mb_t *m = *mp; @@ -622,6 +749,16 @@ int out; */ m->m_flags &= ~M_CANFASTFWD; # endif /* M_CANFASTFWD */ +# ifdef CSUM_DELAY_DATA + /* + * disable delayed checksums. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } +# endif /* CSUM_DELAY_DATA */ + if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_ICMP)) { @@ -647,19 +784,19 @@ int out; # ifdef __sgi /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */ if ((up > sizeof(hbuf)) || (m_length(m) < up)) { - ATOMIC_INC(frstats[out].fr_pull[1]); + ATOMIC_INCL(frstats[out].fr_pull[1]); return -1; } m_copydata(m, 0, up, hbuf); - ATOMIC_INC(frstats[out].fr_pull[0]); + ATOMIC_INCL(frstats[out].fr_pull[0]); ip = (ip_t *)hbuf; # else /* __ sgi */ # ifndef linux if ((*mp = m_pullup(m, up)) == 0) { - ATOMIC_INC(frstats[out].fr_pull[1]); + ATOMIC_INCL(frstats[out].fr_pull[1]); return -1; } else { - ATOMIC_INC(frstats[out].fr_pull[0]); + ATOMIC_INCL(frstats[out].fr_pull[0]); m = *mp; ip = mtod(m, ip_t *); } @@ -678,24 +815,43 @@ int out; fin->fin_qfm = m; fin->fin_qif = qif; # endif +# ifdef USE_INET6 + if (v == 6) { + ATOMIC_INCL(frstats[0].fr_ipv6[out]); + } else +# endif + if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { + ATOMIC_INCL(frstats[0].fr_badsrc); +# if !SOLARIS + m_freem(m); +# endif + return error; + } #endif /* _KERNEL */ - + /* * Be careful here: ip_id is in network byte order when called * from ip_output() */ - if (out) + if ((out) && (v == 4)) ip->ip_id = ntohs(ip->ip_id); - fr_makefrip(hlen, ip, fin); + + changed = 0; + fin->fin_v = v; fin->fin_ifp = ifp; fin->fin_out = out; fin->fin_mp = mp; + fr_makefrip(hlen, ip, fin); pass = fr_pass; + if (fin->fin_fi.fi_fl & FI_SHORT) { + ATOMIC_INCL(frstats[out].fr_short); + } + READ_ENTER(&ipf_mutex); if (fin->fin_fi.fi_fl & FI_SHORT) - ATOMIC_INC(frstats[out].fr_short); + ATOMIC_INCL(frstats[out].fr_short); /* * Check auth now. This, combined with the check below to see if apass @@ -707,10 +863,16 @@ int out; apass = fr_checkauth(ip, fin); if (!out) { +#ifdef USE_INET6 + if (v == 6) + list = ipacct6[0][fr_active]; + else +#endif + list = ipacct[0][fr_active]; changed = ip_natin(ip, fin); - if (!apass && (fin->fin_fr = ipacct[0][fr_active]) && + if (!apass && (fin->fin_fr = list) && (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INC(frstats[0].fr_acct); + ATOMIC_INCL(frstats[0].fr_acct); } } @@ -729,19 +891,25 @@ int out; * earlier. */ bcopy((char *)fc, (char *)fin, FI_COPYSIZE); - ATOMIC_INC(frstats[out].fr_chit); + ATOMIC_INCL(frstats[out].fr_chit); if ((fr = fin->fin_fr)) { - ATOMIC_INC(fr->fr_hits); + ATOMIC_INCL(fr->fr_hits); pass = fr->fr_flags; } } else { - if ((fin->fin_fr = ipfilter[out][fr_active])) +#ifdef USE_INET6 + if (v == 6) + list = ipfilter6[out][fr_active]; + else +#endif + list = ipfilter[out][fr_active]; + if ((fin->fin_fr = list)) pass = fr_scanlist(fr_pass, ip, fin, m); if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE))) bcopy((char *)fin, (char *)fc, FI_COPYSIZE); if (pass & FR_NOMATCH) { - ATOMIC_INC(frstats[out].fr_nom); + ATOMIC_INCL(frstats[out].fr_nom); } } fr = fin->fin_fr; @@ -754,7 +922,7 @@ int out; * then pretend we've dropped it already. */ if ((pass & FR_AUTH)) - if (FR_NEWAUTH(m, fin, ip, qif) != 0) + if (fr_newauth((mb_t *)m, fin, ip) != 0) #ifdef _KERNEL m = *mp = NULL; #else @@ -765,9 +933,9 @@ int out; READ_ENTER(&ipf_auth); if ((fin->fin_fr = ipauth) && (pass = fr_scanlist(0, ip, fin, m))) { - ATOMIC_INC(fr_authstats.fas_hits); + ATOMIC_INCL(fr_authstats.fas_hits); } else { - ATOMIC_INC(fr_authstats.fas_miss); + ATOMIC_INCL(fr_authstats.fas_miss); } RWLOCK_EXIT(&ipf_auth); } @@ -776,19 +944,19 @@ int out; if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { if (fin->fin_fi.fi_fl & FI_FRAG) { if (ipfr_newfrag(ip, fin, pass) == -1) { - ATOMIC_INC(frstats[out].fr_bnfr); + ATOMIC_INCL(frstats[out].fr_bnfr); } else { - ATOMIC_INC(frstats[out].fr_nfr); + ATOMIC_INCL(frstats[out].fr_nfr); } } else { - ATOMIC_INC(frstats[out].fr_cfr); + ATOMIC_INCL(frstats[out].fr_cfr); } } if (pass & FR_KEEPSTATE) { if (fr_addstate(ip, fin, 0) == NULL) { - ATOMIC_INC(frstats[out].fr_bads); + ATOMIC_INCL(frstats[out].fr_bads); } else { - ATOMIC_INC(frstats[out].fr_ads); + ATOMIC_INCL(frstats[out].fr_ads); } } } else if (fr != NULL) { @@ -805,9 +973,15 @@ int out; * interface. */ if (out && (pass & FR_PASS)) { - if ((fin->fin_fr = ipacct[1][fr_active]) && +#ifdef USE_INET6 + if (v == 6) + list = ipacct6[0][fr_active]; + else +#endif + list = ipacct[0][fr_active]; + if ((fin->fin_fr = list) && (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INC(frstats[1].fr_acct); + ATOMIC_INCL(frstats[1].fr_acct); } fin->fin_fr = fr; changed = ip_natout(ip, fin); @@ -819,22 +993,22 @@ int out; if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { pass |= FF_LOGNOMATCH; - ATOMIC_INC(frstats[out].fr_npkl); + ATOMIC_INCL(frstats[out].fr_npkl); goto logit; } else if (((pass & FR_LOGMASK) == FR_LOGP) || ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) { if ((pass & FR_LOGMASK) != FR_LOGP) pass |= FF_LOGPASS; - ATOMIC_INC(frstats[out].fr_ppkl); + ATOMIC_INCL(frstats[out].fr_ppkl); goto logit; } else if (((pass & FR_LOGMASK) == FR_LOGB) || ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) { if ((pass & FR_LOGMASK) != FR_LOGB) pass |= FF_LOGBLOCK; - ATOMIC_INC(frstats[out].fr_bpkl); + ATOMIC_INCL(frstats[out].fr_bpkl); logit: if (!IPLLOG(pass, ip, fin, m)) { - ATOMIC_INC(frstats[out].fr_skip); + ATOMIC_INCL(frstats[out].fr_skip); if ((pass & (FR_PASS|FR_LOGORBLOCK)) == (FR_PASS|FR_LOGORBLOCK)) pass ^= FR_PASS|FR_BLOCK; @@ -843,7 +1017,7 @@ logit: } #endif /* IPFILTER_LOG */ - if (out) + if ((out) && (v == 4)) ip->ip_id = htons(ip->ip_id); #ifdef _KERNEL @@ -864,9 +1038,9 @@ logit: # endif #endif if (pass & FR_PASS) { - ATOMIC_INC(frstats[out].fr_pass); + ATOMIC_INCL(frstats[out].fr_pass); } else if (pass & FR_BLOCK) { - ATOMIC_INC(frstats[out].fr_block); + ATOMIC_INCL(frstats[out].fr_block); /* * Should we return an ICMP packet to indicate error * status passing through the packet filter ? @@ -878,37 +1052,31 @@ logit: if (!out) { #ifdef _KERNEL if (pass & FR_RETICMP) { - struct in_addr dst; + int dst; if ((pass & FR_RETMASK) == FR_FAKEICMP) - dst = ip->ip_dst; + dst = 1; else - dst.s_addr = 0; -# if SOLARIS - ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode, - qif, dst); -# else - ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode, - ifp, dst); -# endif - ATOMIC_INC(frstats[0].fr_ret); + dst = 0; + send_icmp_err(ip, ICMP_UNREACH, fin, dst); + ATOMIC_INCL(frstats[0].fr_ret); } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { - if (SEND_RESET(ip, qif, ifp, fin) == 0) { - ATOMIC_INC(frstats[1].fr_ret); + if (send_reset(ip, fin) == 0) { + ATOMIC_INCL(frstats[1].fr_ret); } } #else if ((pass & FR_RETMASK) == FR_RETICMP) { verbose("- ICMP unreachable sent\n"); - ATOMIC_INC(frstats[0].fr_ret); + ATOMIC_INCL(frstats[0].fr_ret); } else if ((pass & FR_RETMASK) == FR_FAKEICMP) { verbose("- forged ICMP unreachable sent\n"); - ATOMIC_INC(frstats[0].fr_ret); + ATOMIC_INCL(frstats[0].fr_ret); } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { verbose("- TCP RST sent\n"); - ATOMIC_INC(frstats[1].fr_ret); + ATOMIC_INCL(frstats[1].fr_ret); } #endif } else { @@ -924,6 +1092,10 @@ logit: * Once we're finished return to our caller, freeing the packet if * we are dropping it (* BSD ONLY *). */ + if ((changed == -1) && (pass & FR_PASS)) { + pass &= ~FR_PASS; + pass |= FR_BLOCK; + } #if defined(_KERNEL) # if !SOLARIS # if !defined(linux) @@ -1187,7 +1359,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.3.2.16 2000/01/27 08:49:37 darrenr Exp $ + * $Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1287,8 +1459,7 @@ out: frgroup_t *fr_findgroup(num, flags, which, set, fgpp) -u_int num; -u_32_t flags; +u_32_t num, flags; minor_t which; int set; frgroup_t ***fgpp; @@ -1317,7 +1488,7 @@ frgroup_t ***fgpp; frgroup_t *fr_addgroup(num, fp, which, set) -u_int num; +u_32_t num; frentry_t *fp; minor_t which; int set; @@ -1329,7 +1500,7 @@ int set; KMALLOC(fg, frgroup_t *); if (fg) { - fg->fg_num = num & 0xffff; + fg->fg_num = num; fg->fg_next = *fgp; fg->fg_head = fp; fg->fg_start = &fp->fr_grp; @@ -1340,8 +1511,7 @@ int set; void fr_delgroup(num, flags, which, set) -u_int num; -u_32_t flags; +u_32_t num, flags; minor_t which; int set; { @@ -1379,11 +1549,11 @@ frentry_t **listp; MUTEX_EXIT(&ipf_rw); } - ATOMIC_DEC(fp->fr_ref); + ATOMIC_DEC32(fp->fr_ref); if (fp->fr_grhead) { - fr_delgroup((u_int)fp->fr_grhead, fp->fr_flags, + fr_delgroup(fp->fr_grhead, fp->fr_flags, unit, set); - fp->fr_grhead = NULL; + fp->fr_grhead = 0; } if (fp->fr_ref == 0) { KFREE(fp); @@ -1412,10 +1582,18 @@ int flags; set = 1 - set; if (flags & FR_OUTQUE) { +#ifdef USE_INET6 + (void) frflushlist(set, unit, &flushed, &ipfilter6[1][set]); + (void) frflushlist(set, unit, &flushed, &ipacct6[1][set]); +#endif (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]); (void) frflushlist(set, unit, &flushed, &ipacct[1][set]); } if (flags & FR_INQUE) { +#ifdef USE_INET6 + (void) frflushlist(set, unit, &flushed, &ipfilter6[0][set]); + (void) frflushlist(set, unit, &flushed, &ipacct6[0][set]); +#endif (void) frflushlist(set, unit, &flushed, &ipfilter[0][set]); (void) frflushlist(set, unit, &flushed, &ipacct[0][set]); } @@ -1494,10 +1672,14 @@ u_32_t ip; /* * return the first IP Address associated with an interface */ -int fr_ifpaddr(ifptr, inp) +int fr_ifpaddr(v, ifptr, inp) +int v; void *ifptr; struct in_addr *inp; { +# ifdef USE_INET6 + struct in6_addr *inp6 = NULL; +# endif # if SOLARIS ill_t *ill = ifptr; # else @@ -1506,13 +1688,30 @@ struct in_addr *inp; struct in_addr in; # if SOLARIS - in.s_addr = ill->ill_ipif->ipif_local_addr; +# ifdef USE_INET6 + if (v == 6) { + struct in6_addr in6; + + /* + * First is always link local. + */ + if (ill->ill_ipif->ipif_next) + in6 = ill->ill_ipif->ipif_next->ipif_v6lcl_addr; + else + bzero((char *)&in6, sizeof(in6)); + bcopy((char *)&in6, (char *)inp, sizeof(in6)); + } else +# endif + { + in.s_addr = ill->ill_ipif->ipif_local_addr; + *inp = in; + } # else /* SOLARIS */ # if linux ; # else /* linux */ - struct ifaddr *ifa; struct sockaddr_in *sin; + struct ifaddr *ifa; # if (__FreeBSD_version >= 300000) ifa = TAILQ_FIRST(&ifp->if_addrhead); @@ -1531,8 +1730,17 @@ struct in_addr *inp; sin = (struct sockaddr_in *)&ifa->ifa_addr; # else sin = (struct sockaddr_in *)ifa->ifa_addr; - while (sin && ifa && - sin->sin_family != AF_INET) { + while (sin && ifa) { + if ((v == 4) && (sin->sin_family == AF_INET)) + break; +# ifdef USE_INET6 + if ((v == 6) && (sin->sin_family == AF_INET6)) { + inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; + if (!IN6_IS_ADDR_LINKLOCAL(inp6) && + !IN6_IS_ADDR_LOOPBACK(inp6)) + break; + } +# endif # if (__FreeBSD_version >= 300000) ifa = TAILQ_NEXT(ifa, ifa_link); # else @@ -1550,10 +1758,17 @@ struct in_addr *inp; if (sin == NULL) return -1; # endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ - in = sin->sin_addr; +# ifdef USE_INET6 + if (v == 6) + bcopy((char *)inp6, (char *)inp, sizeof(*inp6)); + else +# endif + { + in = sin->sin_addr; + *inp = in; + } # endif /* linux */ # endif /* SOLARIS */ - *inp = in; return 0; } @@ -1563,7 +1778,7 @@ register frentry_t *fr; { for (; fr; fr = fr->fr_next) { if (fr->fr_ifa != NULL) { - fr->fr_ifa = GETUNIT(fr->fr_ifname); + fr->fr_ifa = GETUNIT(fr->fr_ifname, fr->fr_ip.fi_v); if (fr->fr_ifa == NULL) fr->fr_ifa = (void *)-1; } @@ -1575,9 +1790,9 @@ register frentry_t *fr; void frsync() { +# if !SOLARIS register struct ifnet *ifp; -# if !SOLARIS # if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \ (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) # if (NetBSD >= 199905) || defined(__OpenBSD__) @@ -1599,19 +1814,197 @@ void frsync() frsynclist(ipacct[1][fr_active]); frsynclist(ipfilter[0][fr_active]); frsynclist(ipfilter[1][fr_active]); +#ifdef USE_INET6 + frsynclist(ipacct6[0][fr_active]); + frsynclist(ipacct6[1][fr_active]); + frsynclist(ipfilter6[0][fr_active]); + frsynclist(ipfilter6[1][fr_active]); +#endif RWLOCK_EXIT(&ipf_mutex); } + +/* + * In the functions below, bcopy() is called because the pointer being + * copied _from_ in this instance is a pointer to a char buf (which could + * end up being unaligned) and on the kernel's local stack. + */ +int ircopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + int err; + +#if SOLARIS + copyin(a, &ca, sizeof(ca)); #else + bcopy(a, &ca, sizeof(ca)); +#endif + err = copyin(ca, b, c); + return err; +} + + +int iwcopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + int err; + +#if SOLARIS + copyin(b, &ca, sizeof(ca)); +#else + bcopy(b, &ca, sizeof(ca)); +#endif + err = copyout(a, ca, c); + return err; +} + +#else /* _KERNEL */ /* * return the first IP Address associated with an interface */ -int fr_ifpaddr(ifptr, inp) +int fr_ifpaddr(v, ifptr, inp) +int v; void *ifptr; struct in_addr *inp; { return 0; } -#endif + + +int ircopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + + bcopy(a, &ca, sizeof(ca)); + bcopy(ca, b, c); + return 0; +} + + +int iwcopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + + bcopy(b, &ca, sizeof(ca)); + bcopy(a, ca, c); + return 0; +} + + +#endif + + +int fr_lock(data, lockp) +caddr_t data; +int *lockp; +{ + int arg, error; + + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (!error) { + error = IWCOPY((caddr_t)lockp, data, sizeof(*lockp)); + if (!error) + *lockp = arg; + } + return error; +} + + +void fr_getstat(fiop) +friostat_t *fiop; +{ + bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2); + fiop->f_locks[0] = fr_state_lock; + fiop->f_locks[1] = fr_nat_lock; + fiop->f_locks[2] = fr_frag_lock; + fiop->f_locks[3] = fr_auth_lock; + fiop->f_fin[0] = ipfilter[0][0]; + fiop->f_fin[1] = ipfilter[0][1]; + fiop->f_fout[0] = ipfilter[1][0]; + fiop->f_fout[1] = ipfilter[1][1]; + fiop->f_acctin[0] = ipacct[0][0]; + fiop->f_acctin[1] = ipacct[0][1]; + fiop->f_acctout[0] = ipacct[1][0]; + fiop->f_acctout[1] = ipacct[1][1]; +#ifdef USE_INET6 + fiop->f_fin6[0] = ipfilter6[0][0]; + fiop->f_fin6[1] = ipfilter6[0][1]; + fiop->f_fout6[0] = ipfilter6[1][0]; + fiop->f_fout6[1] = ipfilter6[1][1]; + fiop->f_acctin6[0] = ipacct6[0][0]; + fiop->f_acctin6[1] = ipacct6[0][1]; + fiop->f_acctout6[0] = ipacct6[1][0]; + fiop->f_acctout6[1] = ipacct6[1][1]; +#endif + fiop->f_active = fr_active; + fiop->f_froute[0] = ipl_frouteok[0]; + fiop->f_froute[1] = ipl_frouteok[1]; + + fiop->f_running = fr_running; + fiop->f_groups[0][0] = ipfgroups[0][0]; + fiop->f_groups[0][1] = ipfgroups[0][1]; + fiop->f_groups[1][0] = ipfgroups[1][0]; + fiop->f_groups[1][1] = ipfgroups[1][1]; + fiop->f_groups[2][0] = ipfgroups[2][0]; + fiop->f_groups[2][1] = ipfgroups[2][1]; +#ifdef IPFILTER_LOG + fiop->f_logging = 1; +#else + fiop->f_logging = 0; +#endif + fiop->f_defpass = fr_pass; + strncpy(fiop->f_version, ipfilter_version, sizeof(fiop->f_version)); +} + + +#ifdef USE_INET6 +int icmptoicmp6types[ICMP_MAXTYPE+1] = { + ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ + -1, /* 1: UNUSED */ + -1, /* 2: UNUSED */ + ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ + -1, /* 4: ICMP_SOURCEQUENCH */ + ND_REDIRECT, /* 5: ICMP_REDIRECT */ + -1, /* 6: UNUSED */ + -1, /* 7: UNUSED */ + ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ + -1, /* 9: UNUSED */ + -1, /* 10: UNUSED */ + ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ + ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ + -1, /* 13: ICMP_TSTAMP */ + -1, /* 14: ICMP_TSTAMPREPLY */ + -1, /* 15: ICMP_IREQ */ + -1, /* 16: ICMP_IREQREPLY */ + -1, /* 17: ICMP_MASKREQ */ + -1, /* 18: ICMP_MASKREPLY */ +}; + + +int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { + ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ + ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ + -1, /* 2: ICMP_UNREACH_PROTOCOL */ + ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ + -1, /* 4: ICMP_UNREACH_NEEDFRAG */ + ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ + ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ + ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ + -1, /* 8: ICMP_UNREACH_ISOLATED */ + ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ + ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ + -1, /* 11: ICMP_UNREACH_TOSNET */ + -1, /* 12: ICMP_UNREACH_TOSHOST */ + ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ +}; +#endif diff --git a/contrib/ipfilter/fils.c b/contrib/ipfilter/fils.c index 713691d..761f905 100644 --- a/contrib/ipfilter/fils.c +++ b/contrib/ipfilter/fils.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -17,11 +17,18 @@ #include <sys/time.h> #include <sys/param.h> #include <sys/file.h> +#if defined(STATETOP) && defined(sun) && !defined(__svr4__) && !defined(__SVR4) +#include <sys/select.h> +#endif #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <stddef.h> #include <nlist.h> +#ifdef STATETOP +#include <ctype.h> +#include <ncurses.h> +#endif #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> @@ -36,6 +43,10 @@ #include <arpa/nameser.h> #include <resolv.h> #include <netinet/tcp.h> +#if defined(STATETOP) && !defined(linux) +# include <netinet/ip_var.h> +# include <netinet/tcp_fsm.h> +#endif #include "netinet/ip_compat.h" #include "netinet/ip_fil.h" #include "ipf.h" @@ -44,14 +55,17 @@ #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_auth.h" +#ifdef STATETOP +#include "netinet/ipl.h" +#endif #include "kmem.h" #if defined(__NetBSD__) || (__OpenBSD__) # include <paths.h> #endif #if !defined(lint) -static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fils.c,v 2.2.2.5 2000/01/27 08:49:40 darrenr Exp $"; +static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: fils.c,v 2.21.2.4 2000/05/22 12:47:38 darrenr Exp $"; #endif extern char *optarg; @@ -65,6 +79,34 @@ static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", "ipacct(in)", "ipacct(out)" }; int opts = 0; +#ifdef USE_INET6 +int use_inet6 = 0; +#endif + +#ifdef STATETOP +#define STSTRSIZE 80 +#define STGROWSIZE 16 + +#define STSORT_PR 0 +#define STSORT_PKTS 1 +#define STSORT_BYTES 2 +#define STSORT_TTL 3 +#define STSORT_MAX STSORT_TTL +#define STSORT_DEFAULT STSORT_BYTES + + +typedef struct statetop { + union i6addr st_src; + union i6addr st_dst; + u_short st_sport; + u_short st_dport; + u_char st_p; + u_char st_state[2]; + U_QUAD_T st_pkts; + U_QUAD_T st_bytes; + u_long st_age; +} statetop_t; +#endif extern int main __P((int, char *[])); static void showstats __P((int, friostat_t *)); @@ -76,12 +118,49 @@ static void showgroups __P((friostat_t *)); static void Usage __P((char *)); static void printlist __P((frentry_t *)); static char *get_ifname __P((void *)); +static char *hostname __P((int, void *)); +static void parse_ipportstr __P((const char *, struct in_addr *, int *)); +#ifdef STATETOP +static void topipstates __P((int, struct in_addr, struct in_addr, int, int, int, int, int)); +static char *ttl_to_string __P((long)); +static int sort_p __P((const void *, const void *)); +static int sort_pkts __P((const void *, const void *)); +static int sort_bytes __P((const void *, const void *)); +static int sort_ttl __P((const void *, const void *)); +#endif + +static char *hostname(v, ip) +int v; +void *ip; +{ +#ifdef USE_INET6 + static char hostbuf[MAXHOSTNAMELEN+1]; +#endif + struct in_addr ipa; + + if (v == 4) { + ipa.s_addr = *(u_32_t *)ip; + return inet_ntoa(ipa); + } +#ifdef USE_INET6 + (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); + hostbuf[MAXHOSTNAMELEN] = '\0'; + return hostbuf; +#else + return "IPv6"; +#endif +} static void Usage(name) char *name; { +#ifdef USE_INET6 + fprintf(stderr, "Usage: %s [-6aAfhIinosv] [-d <device>]\n", name); +#else fprintf(stderr, "Usage: %s [-aAfhIinosv] [-d <device>]\n", name); +#endif + fprintf(stderr, " %s -t [-S source address] [-D destination address] [-P protocol] [-T refreshtime] [-C] [-d <device>]\n", name); exit(1); } @@ -91,11 +170,25 @@ int argc; char *argv[]; { fr_authstat_t frauthst; + fr_authstat_t *frauthstp = &frauthst; friostat_t fio; + friostat_t *fiop=&fio; ips_stat_t ipsst; + ips_stat_t *ipsstp = &ipsst; ipfrstat_t ifrst; + ipfrstat_t *ifrstp = &ifrst; char *name = NULL, *device = IPL_NAME; int c, fd; + struct protoent *proto; + + int protocol = -1; /* -1 = wild card for any protocol */ + int refreshtime = 1; /* default update time */ + int sport = -1; /* -1 = wild card for any source port */ + int dport = -1; /* -1 = wild card for any dest port */ + int topclosed = 0; /* do not show closed tcp sessions */ + struct in_addr saddr, daddr; + saddr.s_addr = INADDR_ANY; /* default any source addr */ + daddr.s_addr = INADDR_ANY; /* default any dest addr */ if (openkmem() == -1) exit(-1); @@ -103,19 +196,30 @@ char *argv[]; (void)setuid(getuid()); (void)setgid(getgid()); - while ((c = getopt(argc, argv, "aAfghIinosvd:")) != -1) + while ((c = getopt(argc, argv, "6aACfghIilnostvd:D:P:S:T:")) != -1) { switch (c) { +#ifdef USE_INET6 + case '6' : + use_inet6 = 1; + break; +#endif case 'a' : opts |= OPT_ACCNT|OPT_SHOWLIST; break; case 'A' : opts |= OPT_AUTHSTATS; break; + case 'C' : + topclosed = 1; + break; case 'd' : device = optarg; break; + case 'D' : + parse_ipportstr(optarg, &daddr, &dport); + break; case 'f' : opts |= OPT_FRSTATES; break; @@ -131,15 +235,50 @@ char *argv[]; case 'I' : opts |= OPT_INACTIVE; break; + case 'l' : + opts |= OPT_SHOWLIST; + break; case 'n' : opts |= OPT_SHOWLINENO; break; case 'o' : opts |= OPT_OUTQUE|OPT_SHOWLIST; break; + case 'P' : + if ((proto = getprotobyname(optarg)) != NULL) { + protocol = proto->p_proto; + } else if (!sscanf(optarg, "%ud", &protocol) || + (protocol < 0)) { + fprintf(stderr, "%s : Invalid protocol: %s\n", + argv[0], optarg); + exit(-2); + } + break; case 's' : opts |= OPT_IPSTATES; break; + case 'S' : + parse_ipportstr(optarg, &saddr, &sport); + break; + case 't' : +#ifdef STATETOP + opts |= OPT_STATETOP; + break; +#else + fprintf(stderr, + "%s : state top facility not compiled in\n", + argv[0]); + exit(-2); +#endif + case 'T' : + if (!sscanf(optarg, "%d", &refreshtime) || + (refreshtime <= 0)) { + fprintf(stderr, + "%s : Invalid refreshtime < 1 : %s\n", + argv[0], optarg); + exit(-2); + } + break; case 'v' : opts |= OPT_VERBOSE; break; @@ -158,8 +297,8 @@ char *argv[]; bzero((char *)&ipsst, sizeof(ipsst)); bzero((char *)&ifrst, sizeof(ifrst)); - if (ioctl(fd, SIOCGETFS, &fio) == -1) { - perror("ioctl(SIOCGETFS)"); + if (ioctl(fd, SIOCGETFS, &fiop) == -1) { + perror("ioctl(ipf:SIOCGETFS)"); exit(-1); } if ((opts & OPT_IPSTATES)) { @@ -169,13 +308,13 @@ char *argv[]; perror("open"); exit(-1); } - if ((ioctl(sfd, SIOCGIPST, &ipsst) == -1)) { - perror("ioctl(SIOCGIPST)"); + if ((ioctl(sfd, SIOCGETFS, &ipsstp) == -1)) { + perror("ioctl(state:SIOCGETFS)"); exit(-1); } close(sfd); } - if ((opts & OPT_FRSTATES) && (ioctl(fd, SIOCGFRST, &ifrst) == -1)) { + if ((opts & OPT_FRSTATES) && (ioctl(fd, SIOCGFRST, &ifrstp) == -1)) { perror("ioctl(SIOCGFRST)"); exit(-1); } @@ -184,24 +323,29 @@ char *argv[]; PRINTF("opts %#x name %s\n", opts, name ? name : "<>"); if ((opts & OPT_AUTHSTATS) && - (ioctl(fd, SIOCATHST, &frauthst) == -1)) { + (ioctl(fd, SIOCATHST, &frauthstp) == -1)) { perror("ioctl(SIOCATHST)"); exit(-1); } - if (opts & OPT_SHOWLIST) { + if (opts & OPT_IPSTATES) { + showipstates(fd, ipsstp); + } else if (opts & OPT_SHOWLIST) { showlist(&fio); if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ opts &= ~OPT_OUTQUE; showlist(&fio); } } else { - if (opts & OPT_IPSTATES) - showipstates(fd, &ipsst); - else if (opts & OPT_FRSTATES) - showfrstates(fd, &ifrst); + if (opts & OPT_FRSTATES) + showfrstates(fd, ifrstp); +#ifdef STATETOP + else if (opts & OPT_STATETOP) + topipstates(fd, saddr, daddr, sport, dport, + protocol, refreshtime, topclosed); +#endif else if (opts & OPT_AUTHSTATS) - showauthstates(fd, &frauthst); + showauthstates(fd, frauthstp); else if (opts & OPT_GROUPS) showgroups(&fio); else @@ -234,6 +378,12 @@ struct friostat *fp; fp->f_st[0].fr_notip, fp->f_st[1].fr_notip); PRINTF(" bad packets:\t\tin %lu\tout %lu\n", fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); + PRINTF("copied messages:\tin %lu\tout %lu\n", + fp->f_st[0].fr_copy, fp->f_st[1].fr_copy); +#endif +#ifdef USE_INET6 + PRINTF(" IPv6 packets:\t\tin %lu out %lu\n", + fp->f_st[0].fr_ipv6[0], fp->f_st[0].fr_ipv6[1]); #endif PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu", fp->f_st[0].fr_block, fp->f_st[0].fr_pass, @@ -263,6 +413,7 @@ struct friostat *fp; fp->f_st[1].fr_ads, fp->f_st[1].fr_bads); PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n", fp->f_st[0].fr_ret, fp->f_st[1].fr_ret); + PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc); PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n", fp->f_st[0].fr_chit, fp->f_st[1].fr_chit); PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n", @@ -302,15 +453,15 @@ frentry_t *fp; fp->fr_flags |= FR_OUTQUE; if (opts & (OPT_HITS|OPT_VERBOSE)) #ifdef USE_QUAD_T - PRINTF("%qd ", fp->fr_hits); + PRINTF("%qu ", (unsigned long long) fp->fr_hits); #else - PRINTF("%ld ", fp->fr_hits); + PRINTF("%lu ", fp->fr_hits); #endif if (opts & (OPT_ACCNT|OPT_VERBOSE)) #ifdef USE_QUAD_T - PRINTF("%qd ", fp->fr_bytes); + PRINTF("%qu ", (unsigned long long) fp->fr_bytes); #else - PRINTF("%ld ", fp->fr_bytes); + PRINTF("%lu ", fp->fr_bytes); #endif if (opts & OPT_SHOWLINENO) PRINTF("@%d ", n); @@ -346,14 +497,25 @@ struct friostat *fiop; FPRINTF(stderr, "No -i or -o given with -a\n"); return; } - } else if (opts & OPT_OUTQUE) { - i = F_OUT; - fp = (struct frentry *)fiop->f_fout[set]; - } else if (opts & OPT_INQUE) { - i = F_IN; - fp = (struct frentry *)fiop->f_fin[set]; - } else - return; + } else { +#ifdef USE_INET6 + if ((use_inet6) && (opts & OPT_OUTQUE)) { + i = F_OUT; + fp = (struct frentry *)fiop->f_fout6[set]; + } else if ((use_inet6) && (opts & OPT_INQUE)) { + i = F_IN; + fp = (struct frentry *)fiop->f_fin6[set]; + } else +#endif + if (opts & OPT_OUTQUE) { + i = F_OUT; + fp = (struct frentry *)fiop->f_fout[set]; + } else if (opts & OPT_INQUE) { + i = F_IN; + fp = (struct frentry *)fiop->f_fin[set]; + } else + return; + } if (opts & OPT_VERBOSE) FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); @@ -373,126 +535,433 @@ int fd; ips_stat_t *ipsp; { ipstate_t *istab[IPSTATE_SIZE], ips; - int i; - PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", - ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); - PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, ipsp->iss_miss); - PRINTF("\t%lu maximum\n\t%lu no memory\n\tbuckets in use\t%lu\n", - ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse); - PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n", - ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin); + if (!(opts & OPT_SHOWLIST)) { + PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", + ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); + PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, + ipsp->iss_miss); + PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n", + ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse); + PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n", + ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin); + return; + } + if (kmemcpy((char *)istab, (u_long)ipsp->iss_table, sizeof(istab))) return; - for (i = 0; i < IPSTATE_SIZE; i++) { - while (istab[i]) { - if (kmemcpy((char *)&ips, (u_long)istab[i], - sizeof(ips)) == -1) - break; - PRINTF("%s -> ", inet_ntoa(ips.is_src)); - PRINTF("%s ttl %ld pass %#x pr %d state %d/%d\n", - inet_ntoa(ips.is_dst), ips.is_age, - ips.is_pass, ips.is_p, ips.is_state[0], - ips.is_state[1]); + + while (ipsp->iss_list) { + if (kmemcpy((char *)&ips, (u_long)ipsp->iss_list, sizeof(ips))) + break; + ipsp->iss_list = ips.is_next; + PRINTF("%s -> ", hostname(ips.is_v, &ips.is_src.in4)); + PRINTF("%s ttl %ld pass %#x pr %d state %d/%d\n", + hostname(ips.is_v, &ips.is_dst.in4), + ips.is_age, ips.is_pass, ips.is_p, + ips.is_state[0], ips.is_state[1]); #ifdef USE_QUAD_T - PRINTF("\tpkts %qd bytes %qd", - ips.is_pkts, ips.is_bytes); + PRINTF("\tpkts %qu bytes %qu", + (unsigned long long) ips.is_pkts, + (unsigned long long) ips.is_bytes); #else - PRINTF("\tpkts %ld bytes %ld", - ips.is_pkts, ips.is_bytes); + PRINTF("\tpkts %ld bytes %ld", ips.is_pkts, ips.is_bytes); #endif - if (ips.is_p == IPPROTO_TCP) + if (ips.is_p == IPPROTO_TCP) #if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ (__FreeBSD_version >= 220000) || defined(__OpenBSD__) - PRINTF("\t%hu -> %hu %x:%x %hu:%hu", - ntohs(ips.is_sport), - ntohs(ips.is_dport), - ips.is_send, ips.is_dend, - ips.is_maxswin, ips.is_maxdwin); + PRINTF("\t%hu -> %hu %x:%x %hu:%hu", + ntohs(ips.is_sport), ntohs(ips.is_dport), + ips.is_send, ips.is_dend, + ips.is_maxswin, ips.is_maxdwin); #else - PRINTF("\t%hu -> %hu %lx:%lx %hu:%hu", - ntohs(ips.is_sport), - ntohs(ips.is_dport), - ips.is_send, ips.is_dend, - ips.is_maxswin, ips.is_maxdwin); + PRINTF("\t%hu -> %hu %x:%x %hu:%hu", + ntohs(ips.is_sport), ntohs(ips.is_dport), + ips.is_send, ips.is_dend, + ips.is_maxswin, ips.is_maxdwin); #endif - else if (ips.is_p == IPPROTO_UDP) - PRINTF(" %hu -> %hu", ntohs(ips.is_sport), - ntohs(ips.is_dport)); - else if (ips.is_p == IPPROTO_ICMP) - PRINTF(" %hu %hu %d", ips.is_icmp.ics_id, - ips.is_icmp.ics_seq, - ips.is_icmp.ics_type); - - PRINTF("\n\t"); - - if (ips.is_pass & FR_PASS) { - PRINTF("pass"); - } else if (ips.is_pass & FR_BLOCK) { - PRINTF("block"); - switch (ips.is_pass & FR_RETMASK) - { - case FR_RETICMP : - PRINTF(" return-icmp"); - break; - case FR_FAKEICMP : - PRINTF(" return-icmp-as-dest"); - break; - case FR_RETRST : - PRINTF(" return-rst"); - break; - default : - break; - } - } else if ((ips.is_pass & FR_LOGMASK) == FR_LOG) { - PRINTF("log"); - if (ips.is_pass & FR_LOGBODY) - PRINTF(" body"); - if (ips.is_pass & FR_LOGFIRST) - PRINTF(" first"); - } else if (ips.is_pass & FR_ACCOUNT) - PRINTF("count"); - - if (ips.is_pass & FR_OUTQUE) - PRINTF(" out"); - else - PRINTF(" in"); - - if ((ips.is_pass & FR_LOG) != 0) { - PRINTF(" log"); - if (ips.is_pass & FR_LOGBODY) - PRINTF(" body"); - if (ips.is_pass & FR_LOGFIRST) - PRINTF(" first"); - if (ips.is_pass & FR_LOGORBLOCK) - PRINTF(" or-block"); + else if (ips.is_p == IPPROTO_UDP) + PRINTF(" %hu -> %hu", ntohs(ips.is_sport), + ntohs(ips.is_dport)); + else if (ips.is_p == IPPROTO_ICMP +#ifdef USE_INET6 + || ips.is_p == IPPROTO_ICMPV6 +#endif + ) + PRINTF(" %hu %hu %d", ips.is_icmp.ics_id, + ips.is_icmp.ics_seq, ips.is_icmp.ics_type); + + PRINTF("\n\t"); + + if (ips.is_pass & FR_PASS) { + PRINTF("pass"); + } else if (ips.is_pass & FR_BLOCK) { + PRINTF("block"); + switch (ips.is_pass & FR_RETMASK) + { + case FR_RETICMP : + PRINTF(" return-icmp"); + break; + case FR_FAKEICMP : + PRINTF(" return-icmp-as-dest"); + break; + case FR_RETRST : + PRINTF(" return-rst"); + break; + default : + break; } - if (ips.is_pass & FR_QUICK) - PRINTF(" quick"); - if (ips.is_pass & FR_KEEPFRAG) - PRINTF(" keep frags"); - /* a given; no? */ - if (ips.is_pass & FR_KEEPSTATE) - PRINTF(" keep state"); - PRINTF("\n"); - - PRINTF("\tpkt_flags & %x(%x) = %x,\t", - ips.is_flags & 0xf, ips.is_flags, - ips.is_flags >> 4); - PRINTF("\tpkt_options & %x = %x\n", ips.is_optmsk, - ips.is_opt); - PRINTF("\tpkt_security & %x = %x, pkt_auth & %x = %x\n", - ips.is_secmsk, ips.is_sec, ips.is_authmsk, - ips.is_auth); - istab[i] = ips.is_next; - PRINTF("interfaces: in %s[%p] ", - get_ifname(ips.is_ifpin), ips.is_ifpin); - PRINTF("out %s[%p]\n", - get_ifname(ips.is_ifpout), ips.is_ifpout); + } else if ((ips.is_pass & FR_LOGMASK) == FR_LOG) { + PRINTF("log"); + if (ips.is_pass & FR_LOGBODY) + PRINTF(" body"); + if (ips.is_pass & FR_LOGFIRST) + PRINTF(" first"); + } else if (ips.is_pass & FR_ACCOUNT) + PRINTF("count"); + + if (ips.is_pass & FR_OUTQUE) + PRINTF(" out"); + else + PRINTF(" in"); + + if ((ips.is_pass & FR_LOG) != 0) { + PRINTF(" log"); + if (ips.is_pass & FR_LOGBODY) + PRINTF(" body"); + if (ips.is_pass & FR_LOGFIRST) + PRINTF(" first"); + if (ips.is_pass & FR_LOGORBLOCK) + PRINTF(" or-block"); } + if (ips.is_pass & FR_QUICK) + PRINTF(" quick"); + if (ips.is_pass & FR_KEEPFRAG) + PRINTF(" keep frags"); + /* a given; no? */ + if (ips.is_pass & FR_KEEPSTATE) + PRINTF(" keep state"); + PRINTF("\tIPv%d", ips.is_v); + PRINTF("\n"); + + PRINTF("\tpkt_flags & %x(%x) = %x,\t", + ips.is_flags & 0xf, ips.is_flags, + ips.is_flags >> 4); + PRINTF("\tpkt_options & %x = %x\n", ips.is_optmsk, + ips.is_opt); + PRINTF("\tpkt_security & %x = %x, pkt_auth & %x = %x\n", + ips.is_secmsk, ips.is_sec, ips.is_authmsk, + ips.is_auth); + PRINTF("interfaces: in %s[%p] ", + get_ifname(ips.is_ifpin), ips.is_ifpin); + PRINTF("out %s[%p]\n", + get_ifname(ips.is_ifpout), ips.is_ifpout); } } +#ifdef STATETOP +static void topipstates(fd, saddr, daddr, sport, dport, protocol, + refreshtime, topclosed) +int fd; +struct in_addr saddr; +struct in_addr daddr; +int sport; +int dport; +int protocol; +int refreshtime; +int topclosed; +{ + char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; + int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; + int i, j, sfd, winx, tsentry, maxx, maxy, redraw = 0; + ipstate_t *istab[IPSTATE_SIZE], ips; + ips_stat_t ipsst, *ipsstp = &ipsst; + statetop_t *tstable = NULL, *tp; + struct timeval selecttimeout; + struct protoent *proto; + fd_set readfd; + char c = '\0'; + time_t t; + + /* open state device */ + if ((sfd = open(IPL_STATE, O_RDONLY)) == -1) { + perror("open"); + exit(-1); + } + + /* init ncurses stuff */ + initscr(); + cbreak(); + noecho(); + nodelay(stdscr, 1); + + /* repeat until user aborts */ + while ( 1 ) { + + /* get state table */ + bzero((char *)&ipsst, sizeof(&ipsst)); + if ((ioctl(sfd, SIOCGETFS, &ipsstp) == -1)) { + perror("ioctl(SIOCGETFS)"); + exit(-1); + } + if (kmemcpy((char *)istab, (u_long)ipsstp->iss_table, + sizeof(ips))) + return; + + /* clear the history */ + tsentry = -1; + + /* read the state table and store in tstable */ + while (ipsstp->iss_list) { + if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, + sizeof(ips))) + break; + ipsstp->iss_list = ips.is_next; + + if (((saddr.s_addr == INADDR_ANY) || + (saddr.s_addr == ips.is_saddr)) && + ((daddr.s_addr == INADDR_ANY) || + (daddr.s_addr == ips.is_daddr)) && + ((protocol < 0) || (protocol == ips.is_p)) && + (((ips.is_p != IPPROTO_TCP) && + (ips.is_p != IPPROTO_UDP)) || + (((sport < 0) || + (htons(sport) == ips.is_sport)) && + ((dport < 0) || + (htons(dport) == ips.is_dport)))) && + (topclosed || (ips.is_p != IPPROTO_TCP) || + (ips.is_state[0] < TCPS_CLOSE_WAIT) || + (ips.is_state[1] < TCPS_CLOSE_WAIT))) { + /* + * if necessary make room for this state + * entry + */ + tsentry++; + if (!maxtsentries || + (tsentry == maxtsentries)) { + + maxtsentries += STGROWSIZE; + tstable = realloc(tstable, maxtsentries * sizeof(statetop_t)); + if (!tstable) { + perror("malloc"); + exit(-1); + } + } + + /* fill structure */ + tp = tstable + tsentry; + tp->st_src = ips.is_src; + tp->st_dst = ips.is_dst; + tp->st_p = ips.is_p; + tp->st_state[0] = ips.is_state[0]; + tp->st_state[1] = ips.is_state[1]; + tp->st_pkts = ips.is_pkts; + tp->st_bytes = ips.is_bytes; + tp->st_age = ips.is_age; + if ((ips.is_p == IPPROTO_TCP) || + (ips.is_p == IPPROTO_UDP)) { + tp->st_sport = ips.is_sport; + tp->st_dport = ips.is_dport; + } + + } + } + + + /* sort the array */ + if (tsentry != -1) + switch (sorting) + { + case STSORT_PR: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_p); + break; + case STSORT_PKTS: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_pkts); + break; + case STSORT_BYTES: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_bytes); + break; + case STSORT_TTL: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_ttl); + break; + default: + break; + } + + /* print title */ + erase(); + getmaxyx(stdscr, maxy, maxx); + attron(A_BOLD); + winx = 0; + move(winx,0); + sprintf(str1, "%s - state top", IPL_VERSION); + for(j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) + printw(" "); + printw("%s", str1); + attroff(A_BOLD); + + /* just for fun add a clock */ + move(winx, maxx - 8); + t = time(NULL); + strftime(str1, 80, "%T", localtime(&t)); + printw("%s\n", str1); + + /* + * print the display filters, this is placed in the loop, + * because someday I might add code for changing these + * while the programming is running :-) + */ + if (sport >= 0) + sprintf(str1, "%s,%d", inet_ntoa(saddr), sport); + else + sprintf(str1, "%s", inet_ntoa(saddr)); + + if (dport >= 0) + sprintf(str2, "%s,%d", inet_ntoa(daddr), dport); + else + sprintf(str2, "%s", inet_ntoa(daddr)); + + if (protocol < 0) + strcpy(str3, "any"); + else if ((proto = getprotobynumber(protocol)) != NULL) + sprintf(str3, "%s", proto->p_name); + else + sprintf(str3, "%d", protocol); + + switch (sorting) + { + case STSORT_PR: + sprintf(str4, "proto"); + break; + case STSORT_PKTS: + sprintf(str4, "# pkts"); + break; + case STSORT_BYTES: + sprintf(str4, "# bytes"); + break; + case STSORT_TTL: + sprintf(str4, "ttl"); + break; + default: + sprintf(str4, "unknown"); + break; + } + + if (reverse) + strcat(str4, " (reverse)"); + + winx += 2; + move(winx,0); + printw("Src = %s Dest = %s Proto = %s Sorted by = %s\n\n", + str1, str2, str3, str4); + + /* print column description */ + winx += 2; + move(winx,0); + attron(A_BOLD); + printw("%-21s %-21s %3s %4s %7s %9s %9s\n", "Source IP", + "Destination IP", "ST", "PR", "#pkts", "#bytes", "ttl"); + attroff(A_BOLD); + + /* print all the entries */ + tp = tstable; + if (reverse) + tp += tsentry; + + for(i = 0; i <= tsentry; i++) { + /* print src/dest and port */ + if ((tp->st_p == IPPROTO_TCP) || + (tp->st_p == IPPROTO_UDP)) { + sprintf(str1, "%s,%hu", + inet_ntoa(tp->st_src.in4), + ntohs(tp->st_sport)); + sprintf(str2, "%s,%hu", + inet_ntoa(tp->st_dst.in4), + ntohs(tp->st_dport)); + } else { + sprintf(str1, "%s", inet_ntoa(tp->st_src.in4)); + sprintf(str2, "%s", inet_ntoa(tp->st_dst.in4)); + } + winx++; + move(winx, 0); + printw("%-21s %-21s", str1, str2); + + /* print state */ + sprintf(str1, "%d/%d", tp->st_state[0], + tp->st_state[1]); + printw(" %3s", str1); + + /* print proto */ + proto = getprotobynumber(tp->st_p); + if (proto) { + strncpy(str1, proto->p_name, 4); + str1[4] = '\0'; + } else { + sprintf(str1, "%d", tp->st_p); + } + printw(" %4s", str1); + /* print #pkt/#bytes */ +#ifdef USE_QUAD_T + printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, + (unsigned long long) tp->st_bytes); +#else + printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); +#endif + printw(" %9s", ttl_to_string(tp->st_age)); + + if (reverse) + tp--; + else + tp++; + } + + /* screen data structure is filled, now update the screen */ + if (redraw) + clearok(stdscr,1); + + refresh(); + if (redraw) { + clearok(stdscr,0); + redraw = 0; + } + + /* wait for key press or a 1 second time out period */ + selecttimeout.tv_sec = refreshtime; + selecttimeout.tv_usec = 0; + FD_ZERO(&readfd); + FD_SET(0, &readfd); + select(1, &readfd, NULL, NULL, &selecttimeout); + + /* if key pressed, read all waiting keys */ + if (FD_ISSET(0, &readfd)) + while ((c = wgetch(stdscr)) != ERR) { + if (tolower(c) == 'l') { + redraw = 1; + } else if (tolower(c) == 'q') { + nocbreak(); + endwin(); + exit(0); + } else if (tolower(c) == 'r') { + reverse = !reverse; + } else if (tolower(c) == 's') { + sorting++; + if (sorting > STSORT_MAX) + sorting = 0; + } + } + } /* while */ + + close(sfd); + + printw("\n"); + nocbreak(); + endwin(); +} +#endif static void showfrstates(fd, ifsp) int fd; @@ -514,12 +983,12 @@ ipfrstat_t *ifsp; if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], sizeof(ifr)) == -1) break; - PRINTF("%s -> ", inet_ntoa(ifr.ipfr_src)); + PRINTF("%s -> ", hostname(4, &ifr.ipfr_src)); if (kmemcpy((char *)&fr, (u_long)ifr.ipfr_rule, sizeof(fr)) == -1) break; PRINTF("%s %d %d %d %#02x = %#x\n", - inet_ntoa(ifr.ipfr_dst), ifr.ipfr_id, + hostname(4, &ifr.ipfr_dst), ifr.ipfr_id, ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_tos, fr.fr_flags); ipfrtab[i] = ifr.ipfr_next; @@ -534,8 +1003,9 @@ fr_authstat_t *asp; frauthent_t *frap, fra; #ifdef USE_QUAD_T - printf("Authorisation hits: %qd\tmisses %qd\n", asp->fas_hits, - asp->fas_miss); + printf("Authorisation hits: %qu\tmisses %qu\n", + (unsigned long long) asp->fas_hits, + (unsigned long long) asp->fas_miss); #else printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits, asp->fas_miss); @@ -640,3 +1110,131 @@ struct friostat *fiop; printf("%hu\n", grp.fg_num); } } + +static void parse_ipportstr(argument, ip, port) +const char *argument; +struct in_addr *ip; +int *port; +{ + + char *s, *comma; + + /* make working copy of argument, Theoretically you must be able + * to write to optarg, but that seems very ugly to me.... + */ + if ((s = malloc(strlen(argument) + 1)) == NULL) + perror("malloc"); + strcpy(s, argument); + + /* get port */ + if ((comma = strchr(s, ',')) != NULL) { + if (!strcasecmp(s, "any")) { + *port = -1; + } else if (!sscanf(comma + 1, "%d", port) || + (*port < 0) || (*port > 65535)) { + fprintf(stderr, "Invalid port specfication in %s\n", + argument); + exit(-2); + } + *comma = '\0'; + } + + + /* get ip address */ + if (!strcasecmp(s, "any")) { + ip->s_addr = INADDR_ANY; + } else if (!inet_aton(s, ip)) { + fprintf(stderr, "Invalid IP address: %s\n", s); + exit(-2); + } + + /* free allocated memory */ + free(s); +} + + +#ifdef STATETOP +static char ttlbuf[STSTRSIZE]; + +static char *ttl_to_string(ttl) +long int ttl; +{ + + int hours, minutes, seconds; + + /* ttl is in half seconds */ + ttl /= 2; + + hours = ttl / 3600; + ttl = ttl % 3600; + minutes = ttl / 60; + seconds = ttl % 60; + + if (hours > 0 ) + sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds); + else + sprintf(ttlbuf, "%2d:%02d", minutes, seconds); + return ttlbuf; +} + + +static int sort_pkts(a, b) +const void *a; +const void *b; +{ + + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_pkts == bp->st_pkts) + return 0; + else if (ap->st_pkts < bp->st_pkts) + return 1; + return -1; +} + + +static int sort_bytes(a, b) +const void *a; +const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_bytes == bp->st_bytes) + return 0; + else if (ap->st_bytes < bp->st_bytes) + return 1; + return -1; +} + + +static int sort_p(a, b) +const void *a; +const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_p == bp->st_p) + return 0; + else if (ap->st_p < bp->st_p) + return 1; + return -1; +} + + +static int sort_ttl(a, b) +const void *a; +const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_age == bp->st_age) + return 0; + else if (ap->st_age < bp->st_age) + return 1; + return -1; +} +#endif diff --git a/contrib/ipfilter/ip_auth.c b/contrib/ipfilter/ip_auth.c index f4fcf1e..78aff43 100644 --- a/contrib/ipfilter/ip_auth.c +++ b/contrib/ipfilter/ip_auth.c @@ -1,12 +1,12 @@ /* - * Copyright (C) 1998 by Darren Reed & Guido van Rooij. + * Copyright (C) 1998-2000 by Darren Reed & Guido van Rooij. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.1.2.2 2000/01/16 10:12:14 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.2 2000/05/22 10:26:11 darrenr Exp $"; #endif #include <sys/errno.h> @@ -19,7 +19,7 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.1.2.2 2000/01/16 10:12:14 da # include <stdlib.h> # include <string.h> #endif -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> #else @@ -30,7 +30,7 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.1.2.2 2000/01/16 10:12:14 da # include <sys/protosw.h> #endif #include <sys/socket.h> -#if defined(_KERNEL) && !defined(linux) +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) # include <sys/systm.h> #endif #if !defined(__SVR4) && !defined(__svr4__) @@ -123,11 +123,12 @@ static struct wait_queue *ipfauthwait = NULL; int fr_authsize = FR_NUMAUTH; int fr_authused = 0; int fr_defaultauthage = 600; +int fr_auth_lock = 0; fr_authstat_t fr_authstats; -frauth_t fr_auth[FR_NUMAUTH]; +static frauth_t fr_auth[FR_NUMAUTH]; mb_t *fr_authpkts[FR_NUMAUTH]; -int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; -frauthent_t *fae_list = NULL; +static int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; +static frauthent_t *fae_list = NULL; frentry_t *ipauth = NULL; @@ -144,6 +145,9 @@ fr_info_t *fin; u_32_t pass; int i; + if (fr_auth_lock) + return 0; + READ_ENTER(&ipf_auth); for (i = fr_authstart; i != fr_authend; ) { /* @@ -196,19 +200,19 @@ fr_info_t *fin; * If we do, store it and wake up any user programs which are waiting to * hear about these events. */ -int fr_newauth(m, fin, ip -#if defined(_KERNEL) && SOLARIS -, qif) -qif_t *qif; -#else -) -#endif +int fr_newauth(m, fin, ip) mb_t *m; fr_info_t *fin; ip_t *ip; { +#if defined(_KERNEL) && SOLARIS + qif_t *qif = fin->fin_qif; +#endif int i; + if (fr_auth_lock) + return 0; + WRITE_ENTER(&ipf_auth); if (fr_authstart > fr_authend) { fr_authstats.fas_nospace++; @@ -238,14 +242,15 @@ ip_t *ip; * them. */ # if SOLARIS && defined(_KERNEL) - if (ip == (ip_t *)m->b_rptr) + if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4)) # endif { register u_short bo; bo = ip->ip_len; ip->ip_len = htons(bo); -# if !SOLARIS /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ +# if !SOLARIS && !defined(__NetBSD__) + /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ bo = ip->ip_id; ip->ip_id = htons(bo); # endif @@ -272,7 +277,7 @@ ip_t *ip; int fr_auth_ioctl(data, cmd, fr, frptr) caddr_t data; -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (FreeBSD_version >= 300003) u_long cmd; #else int cmd; @@ -280,11 +285,8 @@ int cmd; frentry_t *fr, **frptr; { mb_t *m; -#if defined(_KERNEL) -# if !SOLARIS +#if defined(_KERNEL) && !SOLARIS struct ifqueue *ifq; - int s; -# endif #endif frauth_t auth, *au = &auth; frauthent_t *fae, **faep; @@ -292,12 +294,17 @@ frentry_t *fr, **frptr; switch (cmd) { + case SIOCSTLCK : + error = fr_lock(data, &fr_auth_lock); + break; case SIOCINIFR : case SIOCRMIFR : case SIOCADIFR : error = EINVAL; break; case SIOCINAFR : + error = EINVAL; + break; case SIOCRMAFR : case SIOCADAFR : for (faep = &fae_list; (fae = *faep); ) @@ -318,8 +325,8 @@ frentry_t *fr, **frptr; } else { KMALLOC(fae, frauthent_t *); if (fae != NULL) { - IRCOPY((char *)data, (char *)&fae->fae_fr, - sizeof(fae->fae_fr)); + bcopy((char *)fr, (char *)&fae->fae_fr, + sizeof(*fr)); WRITE_ENTER(&ipf_auth); fae->fae_age = fr_defaultauthage; fae->fae_fr.fr_hits = 0; @@ -337,15 +344,18 @@ frentry_t *fr, **frptr; READ_ENTER(&ipf_auth); fr_authstats.fas_faelist = fae_list; RWLOCK_EXIT(&ipf_auth); - IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats)); + error = IWCOPYPTR((char *)&fr_authstats, data, + sizeof(fr_authstats)); break; case SIOCAUTHW: fr_authioctlloop: READ_ENTER(&ipf_auth); if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { - IWCOPY((char *)&fr_auth[fr_authnext], data, - sizeof(fr_info_t)); + error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data, + sizeof(fr_info_t)); RWLOCK_EXIT(&ipf_auth); + if (error) + break; WRITE_ENTER(&ipf_auth); fr_authnext++; if (fr_authnext == FR_NUMAUTH) @@ -376,7 +386,9 @@ fr_authioctlloop: goto fr_authioctlloop; break; case SIOCAUTHR: - IRCOPY(data, (caddr_t)&auth, sizeof(auth)); + error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth)); + if (error) + return error; WRITE_ENTER(&ipf_auth); i = au->fra_index; if ((i < 0) || (i > FR_NUMAUTH) || @@ -390,7 +402,6 @@ fr_authioctlloop: fr_authpkts[i] = NULL; #ifdef _KERNEL RWLOCK_EXIT(&ipf_auth); - SPL_NET(s); # ifndef linux if (m && au->fra_info.fin_out) { # if SOLARIS @@ -456,7 +467,6 @@ fr_authioctlloop: } } # endif - SPL_X(s); #endif /* _KERNEL */ break; default : @@ -510,6 +520,9 @@ void fr_authexpire() int s; #endif + if (fr_auth_lock) + return; + SPL_NET(s); WRITE_ENTER(&ipf_auth); for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { diff --git a/contrib/ipfilter/ip_auth.h b/contrib/ipfilter/ip_auth.h index 46b8d92..b543318 100644 --- a/contrib/ipfilter/ip_auth.h +++ b/contrib/ipfilter/ip_auth.h @@ -1,11 +1,11 @@ /* - * Copyright (C) 1997-1998 by Darren Reed & Guido Van Rooij. + * Copyright (C) 1997-2000 by Darren Reed & Guido Van Rooij. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_auth.h,v 2.1 1999/08/04 17:29:54 darrenr Exp $ + * $Id: ip_auth.h,v 2.3.2.1 2000/05/22 10:26:11 darrenr Exp $ * */ #ifndef __IP_AUTH_H__ @@ -50,15 +50,12 @@ extern int fr_authstart; extern int fr_authend; extern int fr_authsize; extern int fr_authused; +extern int fr_auth_lock; extern u_32_t fr_checkauth __P((ip_t *, fr_info_t *)); extern void fr_authexpire __P((void)); extern void fr_authunload __P((void)); extern mb_t *fr_authpkts[]; -#if defined(_KERNEL) && SOLARIS -extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *, qif_t *)); -#else extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); -#endif #if defined(__NetBSD__) || defined(__OpenBSD__) extern int fr_auth_ioctl __P((caddr_t, u_long, frentry_t *, frentry_t **)); #else diff --git a/contrib/ipfilter/ip_compat.h b/contrib/ipfilter/ip_compat.h index 318ef2f..9b7cddf 100644 --- a/contrib/ipfilter/ip_compat.h +++ b/contrib/ipfilter/ip_compat.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.1.2.3 1999/11/18 13:55:26 darrenr Exp $ + * $Id: ip_compat.h,v 2.26.2.3 2000/04/28 14:56:49 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -27,6 +27,11 @@ #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif +#if SOLARIS2 >= 8 +# ifndef USE_INET6 +# define USE_INET6 +# endif +#endif #if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL__) # undef KERNEL @@ -90,19 +95,29 @@ struct ether_addr { # ifndef KERNEL # define _KERNEL # undef RES_INIT +# if SOLARIS2 >= 8 +# include <netinet/ip6.h> +# endif # include <inet/common.h> # include <inet/ip.h> # include <inet/ip_ire.h> # undef _KERNEL # else /* _KERNEL */ +# if SOLARIS2 >= 8 +# include <netinet/ip6.h> +# endif # include <inet/common.h> # include <inet/ip.h> # include <inet/ip_ire.h> # endif /* _KERNEL */ # if SOLARIS2 >= 8 +# include <inet/ip_if.h> # include <netinet/ip6.h> -# include <inet/ip6.h> # define ipif_local_addr ipif_lcl_addr +/* Only defined in private include file */ +# ifndef V4_PART_OF_V6 +# define V4_PART_OF_V6(v6) v6.s6_addr32[3] +# endif # endif #else # if !defined(__sgi) @@ -124,12 +139,25 @@ typedef int minor_t; # define QUAD_T long #endif /* BSD > 199306 */ + /* * These operating systems already take care of the problem for us. */ #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ defined(__sgi) typedef u_int32_t u_32_t; +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000) +# include "opt_inet.h" +# endif +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ + !defined(KLD_MODULE) +# include "opt_inet6.h" +# endif +# ifdef INET6 +# define USE_INET6 +# endif +# endif #else /* * Really, any arch where sizeof(long) != sizeof(int). @@ -137,10 +165,38 @@ typedef u_int32_t u_32_t; # if defined(__alpha__) || defined(__alpha) || defined(_LP64) typedef unsigned int u_32_t; # else -typedef unsigned long u_32_t; +# if SOLARIS2 >= 6 +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; +# endif # endif #endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */ +#ifdef USE_INET6 +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +# include <netinet/ip6.h> +# ifdef _KERNEL +# include <netinet6/ip6_var.h> +# endif +typedef struct ip6_hdr ip6_t; +# endif +union i6addr { + u_32_t i6[4]; + struct in_addr in4; + struct in6_addr in6; +}; +#else +union i6addr { + u_32_t i6[4]; + struct in_addr in4; +}; +#endif + +#define IP6CMP(a,b) bcmp((char *)&(a), (char *)&(b), sizeof(a)) +#define IP6EQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) == 0) +#define IP6NEQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) != 0) + #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif @@ -202,12 +258,15 @@ typedef unsigned long u_32_t; #define IPOPT_FINN 205 /* FINN */ -#if defined(__FreeBSD__) && defined(KERNEL) +#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) # if __FreeBSD__ < 3 # include <machine/spl.h> -# endif -# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) -# define ACTUALLY_LKM_NOT_KERNEL +# else +# if __FreeBSD__ == 3 +# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) +# define ACTUALLY_LKM_NOT_KERNEL +# endif +# endif # endif #endif /* __FreeBSD__ && KERNEL */ @@ -215,12 +274,39 @@ typedef unsigned long u_32_t; * Build some macros and #defines to enable the same code to compile anywhere * Well, that's the idea, anyway :-) */ +#if !SOLARIS || (SOLARIS2 < 6) || !defined(KERNEL) +# define ATOMIC_INCL ATOMIC_INC +# define ATOMIC_INC64 ATOMIC_INC +# define ATOMIC_INC32 ATOMIC_INC +# define ATOMIC_INC16 ATOMIC_INC +# define ATOMIC_DECL ATOMIC_DEC +# define ATOMIC_DEC64 ATOMIC_DEC +# define ATOMIC_DEC32 ATOMIC_DEC +# define ATOMIC_DEC16 ATOMIC_DEC +#endif #ifdef KERNEL # if SOLARIS -# define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ +# if SOLARIS2 >= 6 +# include <sys/atomic.h> +# if SOLARIS2 == 6 +# define ATOMIC_INCL(x) atomic_add_long((uint32_t*)&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long((uint32_t*)&(x), -1) +# else +# define ATOMIC_INCL(x) atomic_add_long(&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long(&(x), -1) +# endif +# define ATOMIC_INC64(x) atomic_add_64((uint64_t*)&(x), 1) +# define ATOMIC_INC32(x) atomic_add_32((uint32_t*)&(x), 1) +# define ATOMIC_INC16(x) atomic_add_16((uint16_t*)&(x), 1) +# define ATOMIC_DEC64(x) atomic_add_64((uint64_t*)&(x), -1) +# define ATOMIC_DEC32(x) atomic_add_32((uint32_t*)&(x), -1) +# define ATOMIC_DEC16(x) atomic_add_16((uint16_t*)&(x), -1) +# else +# define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ mutex_exit(&ipf_rw); } -# define ATOMIC_DEC(x) { mutex_enter(&ipf_rw); (x)--; \ +# define ATOMIC_DEC(x) { mutex_enter(&ipf_rw); (x)--; \ mutex_exit(&ipf_rw); } +# endif # define MUTEX_ENTER(x) mutex_enter(x) # if 1 # define KRWLOCK_T krwlock_t @@ -243,10 +329,14 @@ typedef unsigned long u_32_t; # define RWLOCK_EXIT(x) mutex_exit(x) # define RW_DESTROY(x) mutex_destroy(x) # endif +# define MUTEX_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) +# 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 IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr # define FREE_MB_T(m) freemsg(m) # define SPL_NET(x) ; # define SPL_IMP(x) ; @@ -282,9 +372,11 @@ typedef struct qif { * in case the ILL has disappeared... */ size_t qf_hl; /* header length */ + int qf_sap; } qif_t; -extern ill_t *get_unit __P((char *)); -# define GETUNIT(n) get_unit((n)) +extern ill_t *get_unit __P((char *, int)); +# define GETUNIT(n, v) get_unit(n, v) +# define IFNAME(x) ((ill_t *)x)->ill_name # else /* SOLARIS */ # if defined(__sgi) # define hz HZ @@ -306,35 +398,48 @@ typedef struct { # define WRITE_ENTER(x) MUTEX_ENTER(x) # define RW_UPGRADE(x) ; # define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_EXIT(x) MUTEX_EXIT(x) -# define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); +# 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) # else /* __sgi */ # define ATOMIC_INC(x) (x)++ # define ATOMIC_DEC(x) (x)-- # define MUTEX_ENTER(x) ; -# define READ_ENTER(x) ; -# define WRITE_ENTER(x) ; -# define RW_UPGRADE(x) ; +# define READ_ENTER(x) ; +# define WRITE_ENTER(x) ; +# define RW_UPGRADE(x) ; # define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_EXIT(x) ; -# define MUTEX_EXIT(x) ; +# define RWLOCK_EXIT(x) ; +# define MUTEX_EXIT(x) ; +# define MUTEX_INIT(x,y,z) ; +# define MUTEX_DESTROY(x) ; # endif /* __sgi */ # ifndef linux # define FREE_MB_T(m) m_freem(m) # define MTOD(m,t) mtod(m,t) -# define IRCOPY(a,b,c) bcopy((a), (b), (c)) -# define IWCOPY(a,b,c) bcopy((a), (b), (c)) +# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr # endif /* !linux */ # endif /* SOLARIS */ # ifdef sun # if !SOLARIS # include <sys/kmem_alloc.h> -# define GETUNIT(n) ifunit((n), IFNAMSIZ) +# define GETUNIT(n, v) ifunit(n, IFNAMSIZ) +# define IFNAME(x) ((struct ifnet *)x)->if_name # endif # else # ifndef linux -# define GETUNIT(n) ifunit((n)) +# define GETUNIT(n, v) ifunit(n) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) +# define IFNAME(x) ((struct ifnet *)x)->if_xname +# else +# define IFNAME(x) ((struct ifnet *)x)->if_name +# endif # endif # endif /* sun */ @@ -408,6 +513,8 @@ extern vm_map_t kmem_map; # define ATOMIC_DEC(x) (x)-- # define MUTEX_ENTER(x) ; # define READ_ENTER(x) ; +# define MUTEX_INIT(x,y,z) ; +# define MUTEX_DESTROY(x) ; # define WRITE_ENTER(x) ; # define RW_UPGRADE(x) ; # define MUTEX_DOWNGRADE(x) ; @@ -421,9 +528,11 @@ extern vm_map_t kmem_map; # define KMALLOCS(a,b,c) (a) = (b)malloc(c) # define KFREE(x) free(x) # define KFREES(x,s) free(x) -# define GETUNIT(x) get_unit(x) -# define IRCOPY(a,b,c) bcopy((a), (b), (c)) -# define IWCOPY(a,b,c) bcopy((a), (b), (c)) +# define GETUNIT(x, v) get_unit(x,v) +# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr #endif /* KERNEL */ #if SOLARIS @@ -745,7 +854,7 @@ typedef struct uio { # define if_name name # ifdef KERNEL -# define GETUNIT(x) dev_get(x) +# define GETUNIT(x, v) dev_get(x) # define FREE_MB_T(m) kfree_skb(m, FREE_WRITE) # define uniqtime do_gettimeofday # undef INT_MAX @@ -767,16 +876,50 @@ typedef struct uio { # define KMALLOCS(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC) # define KFREE(x) kfree_s((x), sizeof(*(x))) # define KFREES(x,s) kfree_s((x), (s)) -# define IRCOPY(a,b,c) { \ - error = verify_area(VERIFY_READ, (a) ,(c)); \ - if (!error) \ - memcpy_fromfs((b), (a), (c)); \ - } -# define IWCOPY(a,b,c) { \ - error = verify_area(VERIFY_WRITE, (b), (c)); \ - if (!error) \ - memcpy_tofs((b), (a), (c)); \ - } +#define IRCOPY(const void *a, void *b, size_t c) { \ + int error; \ + + error = verify_area(VERIFY_READ, a ,c); \ + if (!error) \ + memcpy_fromfs(b, a, c); \ + return error; \ +} +static inline int IWCOPY(const void *a, void *b, size_t c) +{ + int error; + + error = verify_area(VERIFY_WRITE, b, c); + if (!error) + memcpy_tofs(b, a, c); + return error; +} +static inline int IRCOPYPTR(const void *a, void *b, size_t c) { + caddr_t ca; + int error; + + error = verify_area(VERIFY_READ, a ,sizeof(ca)); + if (!error) { + memcpy_fromfs(ca, a, sizeof(ca)); + error = verify_area(VERIFY_READ, ca , c); + if (!error) + memcpy_fromfs(b, ca, c); + } + return error; +} +static inline int IWCOPYPTR(const void *a, void *b, size_t c) { + caddr_t ca; + int error; + + + error = verify_area(VERIFY_READ, b ,sizeof(ca)); + if (!error) { + memcpy_fromfs(ca, b, sizeof(ca)); + error = verify_area(VERIFY_WRITE, ca, c); + if (!error) + memcpy_tofs(ca, a, c); + } + return error; +} # else # define __KERNEL__ # undef INT_MAX @@ -817,12 +960,18 @@ struct ether_addr { #define A_A & #endif +#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + #ifndef ICMP_ROUTERADVERT # define ICMP_ROUTERADVERT 9 #endif #ifndef ICMP_ROUTERSOLICIT # define ICMP_ROUTERSOLICIT 10 #endif +#undef ICMP_MAX_UNREACH +#define ICMP_MAX_UNREACH 14 +#undef ICMP_MAXTYPE +#define ICMP_MAXTYPE 18 /* * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data, * another IP header and then 64 bits of data, totalling 56. Of course, @@ -832,5 +981,6 @@ struct ether_addr { #define ICMPERR_IPICMPHLEN (20 + 8) #define ICMPERR_MINPKTLEN (20 + 8 + 20) #define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) +#define ICMP6ERR_MINPKTLEN (20 + 8) #endif /* __IP_COMPAT_H__ */ diff --git a/contrib/ipfilter/ip_fil.c b/contrib/ipfilter/ip_fil.c index 7943cdc..9216b3c 100644 --- a/contrib/ipfilter/ip_fil.c +++ b/contrib/ipfilter/ip_fil.c @@ -1,13 +1,13 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.4.2.16 2000/01/16 10:12:42 darrenr Exp $"; +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.9 2000/05/22 12:48:28 darrenr Exp $"; #endif #ifndef SOLARIS @@ -17,15 +17,17 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.4.2.16 2000/01/16 10:12:42 da #if defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif #include <sys/param.h> #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ defined(_KERNEL) # include "opt_ipfilter_log.h" #endif -#ifdef __FreeBSD__ -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include <sys/osreldate.h> -# else +#if defined(__FreeBSD__) && !defined(__FreeBSD_version) +# if !defined(_KERNEL) || defined(IPFILTER_LKM) # include <osreldate.h> # endif #endif @@ -96,6 +98,9 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.4.2.16 2000/01/16 10:12:42 da # include <syslog.h> #endif #include "netinet/ip_compat.h" +#ifdef USE_INET6 +# include <netinet/icmp6.h> +#endif #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" @@ -129,15 +134,15 @@ extern int tcp_ttl; int ipl_unreach = ICMP_UNREACH_FILTER; u_long ipl_frouteok[2] = {0, 0}; -static void frzerostats __P((caddr_t)); -#if defined(__NetBSD__) || defined(__OpenBSD__) +static int frzerostats __P((caddr_t)); +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) static int frrequest __P((int, u_long, caddr_t, int)); #else static int frrequest __P((int, int, caddr_t, int)); #endif #ifdef _KERNEL static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); -static int send_ip __P((struct mbuf *, ip_t *)); +static int send_ip __P((ip_t *, fr_info_t *, struct mbuf *)); # ifdef __sgi extern kmutex_t ipf_rw; extern KRWLOCK_T ipf_mutex; @@ -157,15 +162,15 @@ static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); # endif #endif -#if defined(IPFILTER_LKM) -int fr_running = 1; -#else int fr_running = 0; -#endif #if (__FreeBSD_version >= 300000) && defined(_KERNEL) struct callout_handle ipfr_slowtimer_ch; #endif +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) +# include <sys/callout.h> +struct callout ipfr_slowtimer_ch; +#endif #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include <sys/device.h> @@ -224,8 +229,8 @@ int iplattach() { char *defpass; int s; -# ifdef __sgi - int error; +# if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)) + int error = 0; # endif SPL_NET(s); @@ -246,13 +251,44 @@ int iplattach() return -1; # ifdef NETBSD_PF +# if __NetBSD_Version__ >= 104200000 + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + if (error) { +# ifdef USE_INET6 + goto pfil_error; +# else + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; +# endif + } +# else pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + if (error) { + pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +pfil_error: + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; + } +# endif # endif # ifdef __sgi error = ipfilter_sgi_attach(); if (error) { SPL_X(s); + appr_unload(); + ip_natunload(); + fr_stateunload(); return error; } # endif @@ -260,6 +296,7 @@ int iplattach() bzero((char *)frcache, sizeof(frcache)); fr_savep = fr_checkp; fr_checkp = fr_check; + fr_running = 1; SPL_X(s); if (fr_pass & FR_PASS) @@ -269,22 +306,25 @@ int iplattach() else defpass = "no-match -> block"; - printf("IP Filter: initialized. Default = %s all, Logging = %s\n", - defpass, + printf("%s initialized. Default = %s all, Logging = %s\n", + ipfilter_version, defpass, # ifdef IPFILTER_LOG "enabled"); # else "disabled"); # endif - printf("%s\n", ipfilter_version); -#ifdef _KERNEL -# if (__FreeBSD_version >= 300000) && defined(_KERNEL) - ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +#ifdef _KERNEL +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) + callout_init(&ipfr_slowtimer_ch); + callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); # else +# if (__FreeBSD_version >= 300000) && defined(_KERNEL) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else timeout(ipfr_slowtimer, NULL, hz/2); +# endif # endif #endif - fr_running = 1; return 0; } @@ -296,17 +336,24 @@ int iplattach() int ipldetach() { int s, i = FR_INQUE|FR_OUTQUE; +#if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000) + int error = 0; +#endif -#ifdef _KERNEL -# if (__FreeBSD_version >= 300000) - untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); +#ifdef _KERNEL +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) + callout_stop(&ipfr_slowtimer_ch); # else +# if (__FreeBSD_version >= 300000) + untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); +# else # ifdef __sgi untimeout(ipfr_slowtimer); -# else +# else untimeout(ipfr_slowtimer, NULL); -# endif -# endif +# endif +# endif /* FreeBSD */ +# endif /* NetBSD */ #endif SPL_NET(s); if (!fr_running) @@ -316,18 +363,34 @@ int ipldetach() return 0; } + printf("%s unloaded\n", ipfilter_version); + fr_checkp = fr_savep; i = frflush(IPL_LOGIPF, i); fr_running = 0; # ifdef NETBSD_PF +# if __NetBSD_Version__ >= 104200000 + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + if (error) + return error; +# else pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + if (error) + return error; +# endif # endif # ifdef __sgi ipfilter_sgi_detach(); # endif + appr_unload(); ipfr_unload(); ip_natunload(); fr_stateunload(); @@ -339,26 +402,20 @@ int ipldetach() #endif /* _KERNEL */ -static void frzerostats(data) +static int frzerostats(data) caddr_t data; { friostat_t fio; + int error; + + fr_getstat(&fio); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (error) + return EFAULT; - bcopy((char *)frstats, (char *)fio.f_st, - sizeof(struct filterstats) * 2); - fio.f_fin[0] = ipfilter[0][0]; - fio.f_fin[1] = ipfilter[0][1]; - fio.f_fout[0] = ipfilter[1][0]; - fio.f_fout[1] = ipfilter[1][1]; - fio.f_acctin[0] = ipacct[0][0]; - fio.f_acctin[1] = ipacct[0][1]; - fio.f_acctout[0] = ipacct[1][0]; - fio.f_acctout[1] = ipacct[1][1]; - fio.f_active = fr_active; - fio.f_froute[0] = ipl_frouteok[0]; - fio.f_froute[1] = ipl_frouteok[1]; - IWCOPY((caddr_t)&fio, data, sizeof(fio)); bzero((char *)frstats, sizeof(*frstats) * 2); + + return 0; } @@ -373,20 +430,21 @@ int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode ) #else int IPL_EXTERN(ioctl)(dev, cmd, data, mode -#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) +# if (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \ + (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \ + defined(__OpenBSD__))) , p) struct proc *p; -#else +# else ) -#endif +# endif dev_t dev; -#if defined(__NetBSD__) || defined(__OpenBSD__) || \ - (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) +# if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) u_long cmd; -#else +# else int cmd; -#endif +# endif caddr_t data; int mode; #endif /* __sgi */ @@ -411,24 +469,34 @@ int mode; SPL_NET(s); if (unit == IPL_LOGNAT) { - if (!fr_running) - return EIO; - error = nat_ioctl(data, cmd, mode); + if (fr_running) + error = nat_ioctl(data, cmd, mode); + else + error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSTATE) { + if (fr_running) + error = fr_state_ioctl(data, cmd, mode); + else + error = EIO; + SPL_X(s); + return error; + } + if (unit == IPL_LOGAUTH) { if (!fr_running) return EIO; - error = fr_state_ioctl(data, cmd, mode); + error = fr_auth_ioctl(data, cmd, NULL, NULL); SPL_X(s); return error; } + switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG - IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, - sizeof(iplused[IPL_LOGIPF])); + error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, + sizeof(iplused[IPL_LOGIPF])); #endif break; #if !defined(IPFILTER_LKM) && defined(_KERNEL) @@ -439,7 +507,9 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else { - IRCOPY(data, (caddr_t)&enable, sizeof(enable)); + error = IRCOPY(data, (caddr_t)&enable, sizeof(enable)); + if (error) + break; if (enable) error = iplattach(); else @@ -452,10 +522,11 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else - IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags)); + error = IRCOPY(data, (caddr_t)&fr_flags, + sizeof(fr_flags)); break; case SIOCGETFF : - IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); + error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); break; case SIOCINAFR : case SIOCRMAFR : @@ -485,55 +556,42 @@ int mode; break; case SIOCGETFS : { - struct friostat fio; - - bcopy((char *)frstats, (char *)fio.f_st, - sizeof(struct filterstats) * 2); - fio.f_fin[0] = ipfilter[0][0]; - fio.f_fin[1] = ipfilter[0][1]; - fio.f_fout[0] = ipfilter[1][0]; - fio.f_fout[1] = ipfilter[1][1]; - fio.f_acctin[0] = ipacct[0][0]; - fio.f_acctin[1] = ipacct[0][1]; - fio.f_acctout[0] = ipacct[1][0]; - fio.f_acctout[1] = ipacct[1][1]; - fio.f_auth = ipauth; - fio.f_active = fr_active; - fio.f_froute[0] = ipl_frouteok[0]; - fio.f_froute[1] = ipl_frouteok[1]; - fio.f_running = fr_running; - fio.f_groups[0][0] = ipfgroups[0][0]; - fio.f_groups[0][1] = ipfgroups[0][1]; - fio.f_groups[1][0] = ipfgroups[1][0]; - fio.f_groups[1][1] = ipfgroups[1][1]; - fio.f_groups[2][0] = ipfgroups[2][0]; - fio.f_groups[2][1] = ipfgroups[2][1]; -#ifdef IPFILTER_LOG - fio.f_logging = 1; -#else - fio.f_logging = 0; -#endif - fio.f_defpass = fr_pass; - strncpy(fio.f_version, ipfilter_version, - sizeof(fio.f_version)); - IWCOPY((caddr_t)&fio, data, sizeof(fio)); + friostat_t fio; + + fr_getstat(&fio); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (error) + return EFAULT; break; } case SIOCFRZST : if (!(mode & FWRITE)) error = EPERM; else - frzerostats(data); + error = frzerostats(data); break; case SIOCIPFFL : if (!(mode & FWRITE)) error = EPERM; else { - IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - tmp = frflush(unit, tmp); - IWCOPY((caddr_t)&tmp, data, sizeof(tmp)); + error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + tmp = frflush(unit, tmp); + error = IWCOPY((caddr_t)&tmp, data, + sizeof(tmp)); + } } break; + case SIOCSTLCK : + error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + fr_state_lock = tmp; + fr_nat_lock = tmp; + fr_frag_lock = tmp; + fr_auth_lock = tmp; + } else + error = EFAULT; + break; #ifdef IPFILTER_LOG case SIOCIPFFB : if (!(mode & FWRITE)) @@ -543,7 +601,10 @@ int mode; break; #endif /* IPFILTER_LOG */ case SIOCGFRST : - IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t)); + error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, + sizeof(ipfrstat_t)); + if (error) + return EFAULT; break; case SIOCAUTHW : case SIOCAUTHR : @@ -551,9 +612,6 @@ int mode; error = EPERM; break; } - case SIOCATHST : - error = fr_auth_ioctl(data, cmd, NULL, NULL); - break; case SIOCFRSYN : if (!(mode & FWRITE)) error = EPERM; @@ -591,6 +649,20 @@ void *ifp; for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; +#ifdef USE_INET6 + for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; +#endif RWLOCK_EXIT(&ipf_mutex); ip_natsync(ifp); } @@ -598,7 +670,7 @@ void *ifp; static int frrequest(unit, req, data, set) int unit; -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) u_long req; #else int req; @@ -611,11 +683,14 @@ caddr_t data; frentry_t frd; frdest_t *fdp; frgroup_t *fg = NULL; + u_int *p, *pp; int error = 0, in; u_int group; fp = &frd; - IRCOPY(data, (caddr_t)fp, sizeof(*fp)); + error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); + if (error) + return EFAULT; fp->fr_ref = 0; /* @@ -633,10 +708,16 @@ caddr_t data; if (unit == IPL_LOGAUTH) ftail = fprev = &ipauth; - else if (fp->fr_flags & FR_ACCOUNT) + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4)) ftail = fprev = &ipacct[in][set]; - else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE)) + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4)) ftail = fprev = &ipfilter[in][set]; +#ifdef USE_INET6 + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6)) + ftail = fprev = &ipacct6[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6)) + ftail = fprev = &ipfilter6[in][set]; +#endif else return ESRCH; @@ -649,13 +730,13 @@ caddr_t data; bzero((char *)frcache, sizeof(frcache[0]) * 2); if (*fp->fr_ifname) { - fp->fr_ifa = GETUNIT(fp->fr_ifname); + fp->fr_ifa = GETUNIT(fp->fr_ifname, fp->fr_v); if (!fp->fr_ifa) fp->fr_ifa = (void *)-1; } #if BSD >= 199306 if (*fp->fr_oifname) { - fp->fr_oifa = GETUNIT(fp->fr_oifname); + fp->fr_oifa = GETUNIT(fp->fr_oifname, fp->fr_v); if (!fp->fr_oifa) fp->fr_oifa = (void *)-1; } @@ -664,7 +745,7 @@ caddr_t data; fdp = &fp->fr_dif; fp->fr_flags &= ~FR_DUP; if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname); + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; else @@ -673,7 +754,7 @@ caddr_t data; fdp = &fp->fr_tif; if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname); + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; } @@ -682,9 +763,13 @@ caddr_t data; * Look for a matching filter rule, but don't include the next or * interface pointer in the comparison (fr_next, fr_ifa). */ + for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum; + p != pp; p++) + fp->fr_cksum += *p; + for (; (f = *ftail); ftail = &f->fr_next) - if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, - FR_CMPSIZ) == 0) + if ((fp->fr_cksum == f->fr_cksum) && + !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ)) break; /* @@ -693,7 +778,9 @@ caddr_t data; if (req == SIOCZRLST) { if (!f) return ESRCH; - IWCOPY((caddr_t)f, data, sizeof(*f)); + error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); + if (error) + return EFAULT; f->fr_hits = 0; f->fr_bytes = 0; return 0; @@ -713,11 +800,16 @@ caddr_t data; } } - if (req == SIOCDELFR || req == SIOCRMIFR) { + if (req == SIOCRMAFR || req == SIOCRMIFR) { if (!f) error = ESRCH; else { - if (f->fr_ref > 1) + /* + * Only return EBUSY if there is a group list, else + * it's probably just state information referencing + * the rule. + */ + if ((f->fr_ref > 1) && f->fr_grp) return EBUSY; if (fg && fg->fg_head) fg->fg_head->fr_ref--; @@ -728,7 +820,9 @@ caddr_t data; unit, set); fixskip(fprev, f, -1); *ftail = f->fr_next; - KFREE(f); + f->fr_next = NULL; + if (f->fr_ref == 0) + KFREE(f); } } else { if (f) @@ -852,14 +946,16 @@ register struct uio *uio; * send_reset - this could conceivably be a call to tcp_respond(), but that * requires a large amount of setting up and isn't any more efficient. */ -int send_reset(fin, oip) -fr_info_t *fin; +int send_reset(oip, fin) struct ip *oip; +fr_info_t *fin; { struct tcphdr *tcp, *tcp2; - struct tcpiphdr *tp; + int tlen = 0, hlen; struct mbuf *m; - int tlen = 0; +#ifdef USE_INET6 + ip6_t *ip6, *oip6 = (ip6_t *)oip; +#endif ip_t *ip; tcp = (struct tcphdr *)fin->fin_dp; @@ -877,145 +973,228 @@ struct ip *oip; if (tcp->th_flags & TH_SYN) tlen = 1; - m->m_len = sizeof(*tcp2) + sizeof(*ip); +#ifdef USE_INET6 + hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); +#else + hlen = sizeof(ip_t); +#endif + m->m_len = sizeof(*tcp2) + hlen; # if BSD >= 199306 m->m_data += max_linkhdr; m->m_pkthdr.len = m->m_len; m->m_pkthdr.rcvif = (struct ifnet *)0; # endif - bzero(mtod(m, char *), sizeof(struct tcpiphdr)); ip = mtod(m, struct ip *); - tp = mtod(m, struct tcpiphdr *); - tcp2 = (struct tcphdr *)((char *)ip + sizeof(*ip)); +# ifdef USE_INET6 + ip6 = (ip6_t *)ip; +# endif + bzero((char *)ip, sizeof(*tcp2) + hlen); + tcp2 = (struct tcphdr *)((char *)ip + hlen); - ip->ip_src.s_addr = oip->ip_dst.s_addr; - ip->ip_dst.s_addr = oip->ip_src.s_addr; - tcp2->th_dport = tcp->th_sport; 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); tcp2->th_off = sizeof(*tcp2) >> 2; tcp2->th_flags = TH_RST|TH_ACK; - tp->ti_pr = oip->ip_p; - tp->ti_len = htons(sizeof(struct tcphdr)); - tcp2->th_sum = in_cksum(m, sizeof(*ip) + sizeof(*tcp2)); - - ip->ip_tos = oip->ip_tos; - ip->ip_p = oip->ip_p; - ip->ip_len = sizeof(*ip) + sizeof(*tcp2); - - return send_ip(m, ip); +# ifdef USE_INET6 + if (fin->fin_v == 6) { + ip6->ip6_plen = htons(sizeof(struct tcphdr)); + ip6->ip6_nxt = IPPROTO_TCP; + ip6->ip6_src = oip6->ip6_dst; + ip6->ip6_dst = oip6->ip6_src; + tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, + sizeof(*ip6), sizeof(*tcp2)); + return send_ip(oip, fin, m); + } +# endif + ip->ip_p = IPPROTO_TCP; + ip->ip_len = htons(sizeof(struct tcphdr)); + ip->ip_src.s_addr = oip->ip_dst.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); + ip->ip_len = hlen + sizeof(*tcp2); + return send_ip(oip, fin, m); } -static int send_ip(m, ip) +static int send_ip(oip, fin, m) +ip_t *oip; +fr_info_t *fin; struct mbuf *m; -ip_t *ip; { -# if (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) || \ - (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) - struct route ro; -# endif + ip_t *ip; + + ip = mtod(m, ip_t *); + ip->ip_v = fin->fin_v; + if (ip->ip_v == 4) { + ip->ip_hl = (sizeof(*oip) >> 2); + ip->ip_v = IPVERSION; + ip->ip_tos = oip->ip_tos; + ip->ip_id = oip->ip_id; + ip->ip_off = 0; # if (BSD < 199306) || defined(__sgi) - ip->ip_ttl = tcp_ttl; + ip->ip_ttl = tcp_ttl; # else - ip->ip_ttl = ip_defttl; + ip->ip_ttl = ip_defttl; # endif + ip->ip_sum = 0; + } +# ifdef USE_INET6 + else if (ip->ip_v == 6) { + ip6_t *ip6 = (ip6_t *)ip; -# ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -# endif -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) - { - int err; + ip6->ip6_hlim = 127; - bzero((char *)&ro, sizeof(ro)); - err = ip_output(m, (struct mbuf *)0, &ro, 0, 0); - if (ro.ro_rt) - RTFREE(ro.ro_rt); - return err; + return ip6_output(m, NULL, NULL, 0, NULL, NULL); } -# else - /* - * extra 0 in case of multicast - */ -# if _BSDI_VERSION >= 199802 - return ip_output(m, (struct mbuf *)0, &ro, 0, 0, NULL); -# else -# if defined(__OpenBSD__) - return ip_output(m, (struct mbuf *)0, 0, 0, 0, NULL); -# else - return ip_output(m, (struct mbuf *)0, 0, 0, 0); -# endif -# endif # endif +# ifdef IPSEC + m->m_pkthdr.rcvif = NULL; +# endif + return ipfr_fastroute(m, fin, NULL); } -int send_icmp_err(oip, type, code, ifp, dst) +int send_icmp_err(oip, type, fin, dst) ip_t *oip; -int type, code; -void *ifp; -struct in_addr dst; +int type; +fr_info_t *fin; +int dst; { + int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code; + struct in_addr dst4; struct icmp *icmp; struct mbuf *m; - ip_t *nip; + void *ifp; +#ifdef USE_INET6 + ip6_t *ip6, *oip6 = (ip6_t *)oip; + struct in6_addr dst6; +#endif + ip_t *ip; + if ((type < 0) || (type > ICMP_MAXTYPE)) + return -1; + + code = fin->fin_icode; +#ifdef USE_INET6 + if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) + return -1; +#endif + + avail = 0; + m = NULL; + ifp = fin->fin_ifp; + if (fin->fin_v == 4) { # if (BSD < 199306) || defined(__sgi) - m = m_get(M_DONTWAIT, MT_HEADER); + avail = MLEN; + m = m_get(M_DONTWAIT, MT_HEADER); # else - m = m_gethdr(M_DONTWAIT, MT_HEADER); + avail = MHLEN; + m = m_gethdr(M_DONTWAIT, MT_HEADER); # endif - if (m == NULL) - return ENOBUFS; - m->m_len = sizeof(*nip) + sizeof(*icmp) + 8; + if (m == NULL) + return ENOBUFS; + + if (dst == 0) { + if (fr_ifpaddr(4, ifp, &dst4) == -1) + return -1; + } else + dst4.s_addr = oip->ip_dst.s_addr; + + hlen = sizeof(ip_t); + ohlen = oip->ip_hl << 2; + xtra = 8; + } + +#ifdef USE_INET6 + else if (fin->fin_v == 6) { + hlen = sizeof(ip6_t); + ohlen = sizeof(ip6_t); + type = icmptoicmp6types[type]; + if (type == ICMP6_DST_UNREACH) + code = icmptoicmp6unreach[code]; + + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (!m) + return ENOBUFS; + + MCLGET(m, M_DONTWAIT); + if (!m) + return ENOBUFS; + avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; + xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), + avail - hlen - sizeof(*icmp) - max_linkhdr); + if (dst == 0) { + if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1) + return -1; + } else + dst6 = oip6->ip6_dst; + } +#endif + + iclen = hlen + sizeof(*icmp); # if BSD >= 199306 + avail -= (max_linkhdr + iclen); m->m_data += max_linkhdr; - m->m_pkthdr.len = sizeof(*nip) + sizeof(*icmp) + 8; m->m_pkthdr.rcvif = (struct ifnet *)0; -# endif - - bzero(mtod(m, char *), (size_t)sizeof(*nip) + sizeof(*icmp) + 8); - nip = mtod(m, ip_t *); - icmp = (struct icmp *)(nip + 1); - - nip->ip_v = IPVERSION; - nip->ip_hl = (sizeof(*nip) >> 2); - nip->ip_p = IPPROTO_ICMP; - nip->ip_id = oip->ip_id; - nip->ip_sum = 0; - nip->ip_ttl = 60; - nip->ip_tos = oip->ip_tos; - nip->ip_len = sizeof(*nip) + sizeof(*icmp) + 8; - if (dst.s_addr == 0) { - if (fr_ifpaddr(ifp, &dst) == -1) - return -1; - } - nip->ip_src = dst; - nip->ip_dst = oip->ip_src; + if (xtra > avail) + xtra = avail; + iclen += xtra; + m->m_pkthdr.len = iclen; +#else + avail -= (m->m_off + iclen); + if (xtra > avail) + xtra = avail; + iclen += xtra; +#endif + m->m_len = iclen; + ip = mtod(m, ip_t *); + icmp = (struct icmp *)((char *)ip + hlen); + bzero((char *)ip, iclen); icmp->icmp_type = type; - icmp->icmp_code = code; + icmp->icmp_code = fin->fin_icode; icmp->icmp_cksum = 0; - bcopy((char *)oip, (char *)&icmp->icmp_ip, sizeof(*oip)); - bcopy((char *)oip + (oip->ip_hl << 2), - (char *)&icmp->icmp_ip + sizeof(*oip), 8); /* 64 bits */ -# ifndef sparc - { - register u_short __iplen, __ipoff; - ip_t *ip = &icmp->icmp_ip; + if (avail) { + bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); + avail -= MIN(ohlen, avail); + } - __iplen = ip->ip_len; - __ipoff = ip->ip_off; - ip->ip_len = htons(__iplen); - ip->ip_off = htons(__ipoff); +#ifdef USE_INET6 + ip6 = (ip6_t *)ip; + if (fin->fin_v == 6) { + ip6->ip6_flow = 0; + ip6->ip6_plen = htons(iclen - hlen); + ip6->ip6_nxt = IPPROTO_ICMPV6; + ip6->ip6_hlim = 0; + ip6->ip6_src = dst6; + ip6->ip6_dst = oip6->ip6_src; + if (avail) + bcopy((char *)oip + ohlen, + (char *)&icmp->icmp_ip + ohlen, avail); + icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, + sizeof(*ip6), iclen - hlen); + } else +#endif + { + ip->ip_src.s_addr = dst4.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + + if (avail > 8) + avail = 8; + if (avail) + bcopy((char *)oip + ohlen, + (char *)&icmp->icmp_ip + ohlen, avail); + icmp->icmp_cksum = ipf_cksum((u_short *)icmp, + sizeof(*icmp) + 8); + ip->ip_len = iclen; + ip->ip_p = IPPROTO_ICMP; } -# endif - icmp->icmp_cksum = ipf_cksum((u_short *)icmp, sizeof(*icmp) + 8); - return send_ip(m, nip); + err = send_ip(oip, fin, m); + return err; } @@ -1057,14 +1236,24 @@ frdest_t *fdp; register struct ip *ip, *mhip; register struct mbuf *m = m0; register struct route *ro; - int len, off, error = 0, hlen; + int len, off, error = 0, hlen, code; + struct ifnet *ifp, *sifp; struct sockaddr_in *dst; struct route iproute; - struct ifnet *ifp; frentry_t *fr; hlen = fin->fin_hlen; ip = mtod(m0, struct ip *); + +#ifdef USE_INET6 + if (ip->ip_v == 6) { + /* + * currently "to <if>" and "to <if>:ip#" are not supported + * for IPv6 + */ + return ip6_output(m0, NULL, NULL, 0, NULL, NULL); + } +#endif /* * Route packet. */ @@ -1074,7 +1263,13 @@ frdest_t *fdp; dst->sin_family = AF_INET; fr = fin->fin_fr; - ifp = fdp->fd_ifp; + if (fdp) + ifp = fdp->fd_ifp; + else { + ifp = fin->fin_ifp; + dst->sin_addr = ip->ip_dst; + } + /* * In case we're here due to "to <if>" being used with "keep state", * check that we're going in the correct direction. @@ -1083,9 +1278,10 @@ frdest_t *fdp; if ((ifp != NULL) && (fdp == &fr->fr_tif)) return -1; dst->sin_addr = ip->ip_dst; - } else + } else if (fdp) dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst; -# ifdef __bsdi__ + +# if BSD >= 199306 dst->sin_len = sizeof(*dst); # endif # if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ @@ -1099,7 +1295,7 @@ frdest_t *fdp; rtalloc(ro); # endif if (!ifp) { - if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) { + if (!fr || !(fr->fr_flags & FR_FASTROUTE)) { error = -2; goto bad; } @@ -1126,17 +1322,29 @@ frdest_t *fdp; fin->fin_out = 1; if ((fin->fin_fr = ipacct[1][fr_active]) && (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INC(frstats[1].fr_acct); + ATOMIC_INCL(frstats[1].fr_acct); } fin->fin_fr = NULL; - (void) fr_checkstate(ip, fin); - (void) ip_natout(ip, fin); + if (!fr || !(fr->fr_flags & FR_RETMASK)) { + (void) fr_checkstate(ip, fin); + (void) ip_natout(ip, fin); + } } else ip->ip_sum = 0; /* * If small enough for interface, can just send directly. */ if (ip->ip_len <= ifp->if_mtu) { +# if BSD >= 199306 + int i = 0; + +# ifdef MCLISREFERENCED + if ((m->m_flags & M_EXT) && MCLISREFERENCED(m)) +# else + if (m->m_flags & M_EXT) +# endif + i = 1; +# endif # ifndef sparc ip->ip_id = htons(ip->ip_id); ip->ip_len = htons(ip->ip_len); @@ -1147,6 +1355,11 @@ frdest_t *fdp; # if BSD >= 199306 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); + if (i) { + ip->ip_id = ntohs(ip->ip_id); + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + } # else error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); # endif @@ -1258,12 +1471,46 @@ done: RTFREE(ro->ro_rt); return 0; bad: - if (error == EMSGSIZE) - (void) send_icmp_err(ip, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, - ifp, ip->ip_dst); + if (error == EMSGSIZE) { + sifp = fin->fin_ifp; + code = fin->fin_icode; + fin->fin_icode = ICMP_UNREACH_NEEDFRAG; + fin->fin_ifp = ifp; + (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1); + fin->fin_ifp = sifp; + fin->fin_icode = code; + } m_freem(m); goto done; } + + +int fr_verifysrc(ipa, ifp) +struct in_addr ipa; +void *ifp; +{ + struct sockaddr_in *dst; + struct route iproute; + + bzero((char *)&iproute, sizeof(iproute)); + dst = (struct sockaddr_in *)&iproute.ro_dst; + dst->sin_family = AF_INET; + dst->sin_addr = ipa; +# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ + !defined(__OpenBSD__) +# ifdef RTF_CLONING + rtalloc_ign(&iproute, RTF_CLONING); +# else + rtalloc_ign(&iproute, RTF_PRCLONING); +# endif +# else + rtalloc(&iproute); +# endif + if (iproute.ro_rt == NULL) + return 0; + return (ifp == iproute.ro_rt->rt_ifp); +} + #else /* #ifdef _KERNEL */ @@ -1315,8 +1562,9 @@ ip_t *ip; } -struct ifnet *get_unit(name) +struct ifnet *get_unit(name, v) char *name; +int v; { struct ifnet *ifp, **ifa; # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ diff --git a/contrib/ipfilter/ip_fil.h b/contrib/ipfilter/ip_fil.h index aa42f2f..14f4861 100644 --- a/contrib/ipfilter/ip_fil.h +++ b/contrib/ipfilter/ip_fil.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.3.2.7 2000/01/27 08:49:41 darrenr Exp $ + * $Id: ip_fil.h,v 2.29.2.2 2000/05/22 10:26:13 darrenr Exp $ */ #ifndef __IP_FIL_H__ @@ -37,58 +37,69 @@ #endif #if defined(__STDC__) || defined(__GNUC__) -# define SIOCADAFR _IOW('r', 60, struct frentry) -# define SIOCRMAFR _IOW('r', 61, struct frentry) +# define SIOCADAFR _IOW('r', 60, struct frentry *) +# define SIOCRMAFR _IOW('r', 61, struct frentry *) # define SIOCSETFF _IOW('r', 62, u_int) # define SIOCGETFF _IOR('r', 63, u_int) -# define SIOCGETFS _IOR('r', 64, struct friostat) +# define SIOCGETFS _IOWR('r', 64, struct friostat *) # define SIOCIPFFL _IOWR('r', 65, int) # define SIOCIPFFB _IOR('r', 66, int) -# define SIOCADIFR _IOW('r', 67, struct frentry) -# define SIOCRMIFR _IOW('r', 68, struct frentry) +# define SIOCADIFR _IOW('r', 67, struct frentry *) +# define SIOCRMIFR _IOW('r', 68, struct frentry *) # define SIOCSWAPA _IOR('r', 69, u_int) -# define SIOCINAFR _IOW('r', 70, struct frentry) -# define SIOCINIFR _IOW('r', 71, struct frentry) +# define SIOCINAFR _IOW('r', 70, struct frentry *) +# define SIOCINIFR _IOW('r', 71, struct frentry *) # define SIOCFRENB _IOW('r', 72, u_int) # define SIOCFRSYN _IOW('r', 73, u_int) -# define SIOCFRZST _IOWR('r', 74, struct friostat) -# define SIOCZRLST _IOWR('r', 75, struct frentry) -# define SIOCAUTHW _IOWR('r', 76, struct fr_info) -# define SIOCAUTHR _IOWR('r', 77, struct fr_info) -# define SIOCATHST _IOWR('r', 78, struct fr_authstat) +# define SIOCFRZST _IOWR('r', 74, struct friostat *) +# define SIOCZRLST _IOWR('r', 75, struct frentry *) +# define SIOCAUTHW _IOWR('r', 76, struct fr_info *) +# define SIOCAUTHR _IOWR('r', 77, struct fr_info *) +# define SIOCATHST _IOWR('r', 78, struct fr_authstat *) +# define SIOCSTLCK _IOWR('r', 79, u_int) +# define SIOCSTPUT _IOWR('r', 80, struct ipstate_save *) +# define SIOCSTGET _IOWR('r', 81, struct ipstate_save *) +# define SIOCSTGSZ _IOWR('r', 82, struct natget *) +# define SIOCGFRST _IOWR('r', 83, struct ipfrstat *) #else -# define SIOCADAFR _IOW(r, 60, struct frentry) -# define SIOCRMAFR _IOW(r, 61, struct frentry) +# define SIOCADAFR _IOW(r, 60, struct frentry *) +# define SIOCRMAFR _IOW(r, 61, struct frentry *) # define SIOCSETFF _IOW(r, 62, u_int) # define SIOCGETFF _IOR(r, 63, u_int) -# define SIOCGETFS _IOR(r, 64, struct friostat) +# define SIOCGETFS _IOWR(r, 64, struct friostat *) # define SIOCIPFFL _IOWR(r, 65, int) # define SIOCIPFFB _IOR(r, 66, int) -# define SIOCADIFR _IOW(r, 67, struct frentry) -# define SIOCRMIFR _IOW(r, 68, struct frentry) +# define SIOCADIFR _IOW(r, 67, struct frentry *) +# define SIOCRMIFR _IOW(r, 68, struct frentry *) # define SIOCSWAPA _IOR(r, 69, u_int) -# define SIOCINAFR _IOW(r, 70, struct frentry) -# define SIOCINIFR _IOW(r, 71, struct frentry) +# define SIOCINAFR _IOW(r, 70, struct frentry *) +# define SIOCINIFR _IOW(r, 71, struct frentry *) # define SIOCFRENB _IOW(r, 72, u_int) # define SIOCFRSYN _IOW(r, 73, u_int) -# define SIOCFRZST _IOWR(r, 74, struct friostat) -# define SIOCZRLST _IOWR(r, 75, struct frentry) -# define SIOCAUTHW _IOWR(r, 76, struct fr_info) -# define SIOCAUTHR _IOWR(r, 77, struct fr_info) -# define SIOCATHST _IOWR(r, 78, struct fr_authstat) +# define SIOCFRZST _IOWR(r, 74, struct friostat *) +# define SIOCZRLST _IOWR(r, 75, struct frentry *) +# define SIOCAUTHW _IOWR(r, 76, struct fr_info *) +# define SIOCAUTHR _IOWR(r, 77, struct fr_info *) +# define SIOCATHST _IOWR(r, 78, struct fr_authstat *) +# define SIOCSTLCK _IOWR(r, 79, u_int) +# define SIOCSTPUT _IOWR(r, 80, struct ipstate_save *) +# define SIOCSTGET _IOWR(r, 81, struct ipstate_save *) +# define SIOCSTGSZ _IOWR(r, 82, struct natget *) +# define SIOCGFRST _IOWR(r, 83, struct ipfrstat *) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR #define SIOCINSFR SIOCINAFR + typedef struct fr_ip { - u_char fi_v:4; /* IP version */ - u_char fi_fl:4; /* packet flags */ - u_char fi_tos; /* IP packet TOS */ - u_char fi_ttl; /* IP packet TTL */ - u_char fi_p; /* IP packet protocol */ - struct in_addr fi_src; /* source address from packet */ - struct in_addr fi_dst; /* destination address from packet */ + u_32_t fi_v:4; /* IP version */ + u_32_t fi_fl:4; /* packet flags */ + u_32_t fi_tos:8; /* IP packet TOS */ + u_32_t fi_ttl:8; /* IP packet TTL */ + u_32_t fi_p:8; /* IP packet protocol */ + union i6addr fi_src; /* source address from packet */ + union i6addr fi_dst; /* destination address from packet */ u_32_t fi_optmsk; /* bitmask composed from IP options */ u_short fi_secmsk; /* bitmask composed from IP security options */ u_short fi_auth; /* authentication code from IP sec. options */ @@ -100,13 +111,21 @@ typedef struct fr_ip { #define FI_SHORT (FF_SHORT >> 24) #define FI_CMP (FI_OPTIONS|FI_TCPUDP|FI_SHORT) +#define fi_saddr fi_src.in4.s_addr +#define fi_daddr fi_dst.in4.s_addr + + /* * These are both used by the state and NAT code to indicate that one port or * the other should be treated as a wildcard. */ #define FI_W_SPORT 0x00000100 #define FI_W_DPORT 0x00000200 -#define FI_WILD (FI_W_SPORT|FI_W_DPORT) +#define FI_WILDP (FI_W_SPORT|FI_W_DPORT) +#define FI_W_SADDR 0x00000400 +#define FI_W_DADDR 0x00000800 +#define FI_WILDA (FI_W_SADDR|FI_W_DADDR) +#define FI_NEWFR 0x00001000 typedef struct fr_info { void *fin_ifp; /* interface packet is `on' */ @@ -119,18 +138,22 @@ typedef struct fr_info { /* From here on is packet specific */ u_char fin_icode; /* ICMP error to return */ u_short fin_rule; /* rule # last matched */ - u_short fin_group; /* group number, -1 for none */ + u_32_t fin_group; /* group number, -1 for none */ struct frentry *fin_fr; /* last matching rule */ char *fin_dp; /* start of data past IP header */ u_short fin_dlen; /* length of data portion of packet */ u_short fin_id; /* IP packet id field */ void *fin_mp; /* pointer to pointer to mbuf */ -#if SOLARIS && defined(_KERNEL) +#if SOLARIS void *fin_qfm; /* pointer to mblk where pkt starts */ void *fin_qif; #endif + u_short fin_plen; + u_short fin_off; } fr_info_t; +#define fin_v fin_fi.fi_v + /* * Size for compares on fr_info structures */ @@ -147,10 +170,30 @@ typedef struct frdest { char fd_ifname[IFNAMSIZ]; } frdest_t; +typedef struct frpcmp { + int frp_cmp; /* data for port comparisons */ + u_short frp_port; /* top port for <> and >< */ + u_short frp_top; /* top port for <> and >< */ +} frpcmp_t; + +typedef struct frtuc { + u_char ftu_tcpfm; /* tcp flags mask */ + u_char ftu_tcpf; /* tcp flags */ + frpcmp_t ftu_src; + frpcmp_t ftu_dst; +} frtuc_t; + +#define ftu_scmp ftu_src.frp_cmp +#define ftu_dcmp ftu_dst.frp_cmp +#define ftu_sport ftu_src.frp_port +#define ftu_dport ftu_dst.frp_port +#define ftu_stop ftu_src.frp_top +#define ftu_dtop ftu_dst.frp_top + typedef struct frentry { struct frentry *fr_next; - u_short fr_group; /* group to which this rule belongs */ - u_short fr_grhead; /* group # which this rule starts */ + u_32_t fr_group; /* group to which this rule belongs */ + u_32_t fr_grhead; /* group # which this rule starts */ struct frentry *fr_grp; int fr_ref; /* reference count - for grouping */ void *fr_ifa; @@ -169,38 +212,42 @@ typedef struct frentry { struct fr_ip fr_ip; struct fr_ip fr_mip; /* mask structure */ - u_char fr_tcpfm; /* tcp flags mask */ - u_char fr_tcpf; /* tcp flags */ u_short fr_icmpm; /* data for ICMP packets (mask) */ u_short fr_icmp; - u_char fr_scmp; /* data for port comparisons */ - u_char fr_dcmp; - u_short fr_dport; - u_short fr_sport; - u_short fr_stop; /* top port for <> and >< */ - u_short fr_dtop; /* top port for <> and >< */ + frtuc_t fr_tuc; u_32_t fr_flags; /* per-rule flags && options (see below) */ - u_short fr_skip; /* # of rules to skip */ - u_short fr_loglevel; /* syslog log facility + priority */ + u_int fr_skip; /* # of rules to skip */ + u_int fr_loglevel; /* syslog log facility + priority */ int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ - char fr_icode; /* return ICMP code */ + int fr_sap; /* For solaris only */ + u_char fr_icode; /* return ICMP code */ char fr_ifname[IFNAMSIZ]; #if BSD >= 199306 char fr_oifname[IFNAMSIZ]; #endif struct frdest fr_tif; /* "to" interface */ struct frdest fr_dif; /* duplicate packet interfaces */ + u_int fr_cksum; /* checksum on filter rules for performance */ } frentry_t; +#define fr_v fr_ip.fi_v #define fr_proto fr_ip.fi_p #define fr_ttl fr_ip.fi_ttl #define fr_tos fr_ip.fi_tos -#define fr_dst fr_ip.fi_dst -#define fr_src fr_ip.fi_src -#define fr_dmsk fr_mip.fi_dst -#define fr_smsk fr_mip.fi_src +#define fr_tcpfm fr_tuc.ftu_tcpfm +#define fr_tcpf fr_tuc.ftu_tcpf +#define fr_scmp fr_tuc.ftu_scmp +#define fr_dcmp fr_tuc.ftu_dcmp +#define fr_dport fr_tuc.ftu_dport +#define fr_sport fr_tuc.ftu_sport +#define fr_stop fr_tuc.ftu_stop +#define fr_dtop fr_tuc.ftu_dtop +#define fr_dst fr_ip.fi_dst.in4 +#define fr_src fr_ip.fi_src.in4 +#define fr_dmsk fr_mip.fi_dst.in4 +#define fr_smsk fr_mip.fi_src.in4 #ifndef offsetof #define offsetof(t,m) (int)((&((t *)0L)->m)) @@ -287,13 +334,16 @@ typedef struct filterstats { u_long fr_chit; /* cached hit */ u_long fr_tcpbad; /* TCP checksum check failures */ u_long fr_pull[2]; /* good and bad pullup attempts */ + u_long fr_badsrc; /* source received doesn't match route */ #if SOLARIS u_long fr_notdata; /* PROTO/PCPROTO that have no data */ u_long fr_nodata; /* mblks that have no data */ u_long fr_bad; /* bad IP packets to the filter */ u_long fr_notip; /* packets passed through no on ip queue */ u_long fr_drop; /* packets dropped - no info for them! */ + u_long fr_copy; /* messages copied due to db_ref > 1 */ #endif + u_long fr_ipv6[2]; /* IPv6 packets in/out */ } filterstats_t; /* @@ -305,6 +355,10 @@ typedef struct friostat { struct frentry *f_fout[2]; struct frentry *f_acctin[2]; struct frentry *f_acctout[2]; + struct frentry *f_fin6[2]; + struct frentry *f_fout6[2]; + struct frentry *f_acctin6[2]; + struct frentry *f_acctout6[2]; struct frentry *f_auth; struct frgroup *f_groups[3][2]; u_long f_froute[2]; @@ -312,11 +366,8 @@ typedef struct friostat { char f_active; /* 1 or 0 - active rule set */ char f_running; /* 1 if running, else 0 */ char f_logging; /* 1 if enabled, else 0 */ -#if !SOLARIS && defined(sun) - char f_version[25]; /* version string */ -#else char f_version[32]; /* version string */ -#endif + int f_locks[4]; } friostat_t; typedef struct optlist { @@ -329,7 +380,7 @@ typedef struct optlist { * Group list structure. */ typedef struct frgroup { - u_short fg_num; + u_32_t fg_num; struct frgroup *fg_next; struct frentry *fg_head; struct frentry **fg_start; @@ -362,9 +413,9 @@ typedef struct ipflog { #endif u_char fl_plen; /* extra data after hlen */ u_char fl_hlen; /* length of IP headers saved */ - u_short fl_rule; /* assume never more than 64k rules, total */ - u_short fl_group; u_short fl_loglevel; /* syslog log level */ + u_32_t fl_rule; + u_32_t fl_group; u_32_t fl_flags; u_32_t fl_lflags; } ipflog_t; @@ -433,7 +484,7 @@ extern int send_reset __P((ip_t *, struct ifnet *)); extern int icmp_error __P((ip_t *, struct ifnet *)); extern int ipf_log __P((void)); extern int ipfr_fastroute __P((ip_t *, fr_info_t *, frdest_t *)); -extern struct ifnet *get_unit __P((char *)); +extern struct ifnet *get_unit __P((char *, int)); # if defined(__NetBSD__) || defined(__OpenBSD__) || \ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) extern int iplioctl __P((dev_t, u_long, caddr_t, int)); @@ -454,11 +505,12 @@ extern int ipflog_clear __P((minor_t)); extern int ipflog_read __P((minor_t, struct uio *)); extern int ipflog __P((u_int, ip_t *, fr_info_t *, mb_t *)); extern int ipllog __P((int, fr_info_t *, void **, size_t *, int *, int)); +extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); +extern int send_reset __P((ip_t *, fr_info_t *)); # if SOLARIS extern int fr_check __P((ip_t *, int, void *, int, qif_t *, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, qif_t *, mb_t **)); -extern int icmp_error __P((ip_t *, int, int, qif_t *, struct in_addr)); # if SOLARIS2 >= 7 extern int iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *)); # else @@ -467,25 +519,18 @@ extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *)); extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); extern int ipfsync __P((void)); -extern int send_reset __P((fr_info_t *, ip_t *, qif_t *)); extern int ipfr_fastroute __P((qif_t *, ip_t *, mblk_t *, mblk_t **, fr_info_t *, frdest_t *)); extern void copyin_mblk __P((mblk_t *, size_t, size_t, char *)); extern void copyout_mblk __P((mblk_t *, size_t, size_t, char *)); extern int fr_qin __P((queue_t *, mblk_t *)); extern int fr_qout __P((queue_t *, mblk_t *)); -# ifdef IPFILTER_LOG extern int iplread __P((dev_t, struct uio *, cred_t *)); -# endif # else /* SOLARIS */ extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); -# ifdef linux -extern int send_reset __P((tcpiphdr_t *, struct ifnet *)); -# else -extern int send_reset __P((fr_info_t *, struct ip *)); -extern int send_icmp_err __P((ip_t *, int, int, void *, struct in_addr)); -# endif +extern int send_reset __P((struct ip *, fr_info_t *)); +extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); extern int ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi @@ -536,35 +581,49 @@ extern int iplread(struct inode *, struct file *, char *, int); # endif /* SOLARIS */ #endif /* #ifndef _KERNEL */ +extern char *memstr __P((char *, char *, int, int)); extern void fixskip __P((frentry_t **, frentry_t *, int)); extern int countbits __P((u_32_t)); extern int ipldetach __P((void)); -extern u_short fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *)); -extern int fr_scanlist __P((u_32_t, ip_t *, fr_info_t *, void *)); extern u_short ipf_cksum __P((u_short *, int)); -extern int fr_copytolog __P((int, char *, int)); -extern void fr_forgetifp __P((void *)); +extern int ircopyptr __P((void *, void *, size_t)); +extern int iwcopyptr __P((void *, void *, size_t)); + extern int frflush __P((minor_t, int)); extern void frsync __P((void)); -extern frgroup_t *fr_addgroup __P((u_int, frentry_t *, minor_t, int)); -extern frgroup_t *fr_findgroup __P((u_int, u_32_t, minor_t, int, frgroup_t ***)); -extern void fr_delgroup __P((u_int, u_32_t, minor_t, int)); +extern frgroup_t *fr_addgroup __P((u_32_t, frentry_t *, minor_t, int)); +extern void fr_delgroup __P((u_32_t, u_32_t, minor_t, int)); +extern frgroup_t *fr_findgroup __P((u_32_t, u_32_t, minor_t, int, + frgroup_t ***)); + +extern int fr_copytolog __P((int, char *, int)); +extern void fr_forgetifp __P((void *)); +extern void fr_getstat __P((struct friostat *)); +extern int fr_ifpaddr __P((int, void *, struct in_addr *)); +extern int fr_lock __P((caddr_t, int *)); extern void fr_makefrip __P((int, ip_t *, fr_info_t *)); -extern int fr_ifpaddr __P((void *, struct in_addr *)); -extern char *memstr __P((char *, char *, int, int)); +extern u_short fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *)); +extern int fr_scanlist __P((u_32_t, ip_t *, fr_info_t *, void *)); +extern int fr_tcpudpchk __P((frtuc_t *, fr_info_t *)); +extern int fr_verifysrc __P((struct in_addr, void *)); + extern int ipl_unreach; extern int fr_running; extern u_long ipl_frouteok[2]; extern int fr_pass; extern int fr_flags; extern int fr_active; +extern int fr_chksrc; extern fr_info_t frcache[2]; extern char ipfilter_version[]; -#ifdef IPFILTER_LOG extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; extern size_t iplused[IPL_LOGMAX + 1]; -#endif extern struct frentry *ipfilter[2][2], *ipacct[2][2]; +#ifdef USE_INET6 +extern struct frentry *ipfilter6[2][2], *ipacct6[2][2]; +extern int icmptoicmp6types[ICMP_MAXTYPE+1]; +extern int icmptoicmp6unreach[ICMP_MAX_UNREACH]; +#endif extern struct frgroup *ipfgroups[3][2]; extern struct filterstats frstats[]; diff --git a/contrib/ipfilter/ip_frag.c b/contrib/ipfilter/ip_frag.c index 9de8a6d..3e0a7f3 100644 --- a/contrib/ipfilter/ip_frag.c +++ b/contrib/ipfilter/ip_frag.c @@ -1,13 +1,13 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.4.2.4 1999/11/28 04:52:10 darrenr Exp $"; +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.3 2000/05/05 15:10:23 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) @@ -24,7 +24,7 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.4.2.4 1999/11/28 04:52:10 da # include <string.h> # include <stdlib.h> #endif -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> #else @@ -85,13 +85,20 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.4.2.4 1999/11/28 04:52:10 da extern struct callout_handle ipfr_slowtimer_ch; # endif #endif +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) +# include <sys/callout.h> +extern struct callout ipfr_slowtimer_ch; +#endif + + +static ipfr_t *ipfr_heads[IPFT_SIZE]; +static ipfr_t *ipfr_nattab[IPFT_SIZE]; +static ipfrstat_t ipfr_stats; +static int ipfr_inuse = 0; +int fr_ipfrttl = 120; /* 60 seconds */ +int fr_frag_lock = 0; -ipfr_t *ipfr_heads[IPFT_SIZE]; -ipfr_t *ipfr_nattab[IPFT_SIZE]; -ipfrstat_t ipfr_stats; -int ipfr_inuse = 0, - fr_ipfrttl = 120; /* 60 seconds */ #ifdef _KERNEL # if SOLARIS2 >= 7 extern timeout_id_t ipfr_timer_id; @@ -155,7 +162,7 @@ ipfr_t *table[]; for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next) if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ)) { - ATOMIC_INC(ipfr_stats.ifs_exists); + ATOMIC_INCL(ipfr_stats.ifs_exists); return NULL; } @@ -165,12 +172,12 @@ ipfr_t *table[]; */ KMALLOC(fra, ipfr_t *); if (fra == NULL) { - ATOMIC_INC(ipfr_stats.ifs_nomem); + ATOMIC_INCL(ipfr_stats.ifs_nomem); return NULL; } if ((fra->ipfr_rule = fin->fin_fr) != NULL) { - ATOMIC_INC(fin->fin_fr->fr_ref); + ATOMIC_INC32(fin->fin_fr->fr_ref); } @@ -190,8 +197,8 @@ ipfr_t *table[]; * Compute the offset of the expected start of the next packet. */ fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); - ATOMIC_INC(ipfr_stats.ifs_new); - ATOMIC_INC(ipfr_inuse); + ATOMIC_INCL(ipfr_stats.ifs_new); + ATOMIC_INC32(ipfr_inuse); return fra; } @@ -203,6 +210,8 @@ u_int pass; { ipfr_t *ipf; + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); RWLOCK_EXIT(&ipf_frag); @@ -218,6 +227,8 @@ nat_t *nat; { ipfr_t *ipf; + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; WRITE_ENTER(&ipf_natfrag); ipf = ipfr_new(ip, fin, pass, ipfr_nattab); if (ipf != NULL) { @@ -291,7 +302,7 @@ ipfr_t *table[]; else f->ipfr_off = atoff; } - ATOMIC_INC(ipfr_stats.ifs_hits); + ATOMIC_INCL(ipfr_stats.ifs_hits); return f; } return NULL; @@ -308,6 +319,8 @@ fr_info_t *fin; nat_t *nat; ipfr_t *ipf; + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; READ_ENTER(&ipf_natfrag); ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { @@ -336,6 +349,8 @@ fr_info_t *fin; frentry_t *fr = NULL; ipfr_t *fra; + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; READ_ENTER(&ipf_frag); fra = ipfr_lookup(ip, fin, ipfr_heads); if (fra != NULL) @@ -371,7 +386,7 @@ ipfr_t *fra; fr = fra->ipfr_rule; if (fr != NULL) { - ATOMIC_DEC(fr->fr_ref); + ATOMIC_DEC32(fr->fr_ref); if (fr->fr_ref == 0) KFREE(fr); } @@ -418,19 +433,7 @@ void ipfr_unload() #ifdef _KERNEL -/* - * Slowly expire held state for fragments. Timeouts are set * in expectation - * of this being called twice per second. - */ -# if (BSD >= 199306) || SOLARIS || defined(__sgi) -# if defined(SOLARIS2) && (SOLARIS2 < 7) -void ipfr_slowtimer() -# else -void ipfr_slowtimer __P((void *ptr)) -# endif -# else -int ipfr_slowtimer() -# endif +void ipfr_fragexpire() { ipfr_t **fp, *fra; nat_t *nat; @@ -438,18 +441,11 @@ int ipfr_slowtimer() #if defined(_KERNEL) # if !SOLARIS int s; -# else - extern int fr_running; - - if (fr_running <= 0) - return; # endif #endif - READ_ENTER(&ipf_solaris); -#ifdef __sgi - ipfilter_sgi_intfsync(); -#endif + if (fr_frag_lock) + return; SPL_NET(s); WRITE_ENTER(&ipf_frag); @@ -465,8 +461,8 @@ int ipfr_slowtimer() if (fra->ipfr_ttl == 0) { *fp = fra->ipfr_next; ipfr_delete(fra); - ATOMIC_INC(ipfr_stats.ifs_expire); - ATOMIC_DEC(ipfr_inuse); + ATOMIC_INCL(ipfr_stats.ifs_expire); + ATOMIC_DEC32(ipfr_inuse); } else fp = &fra->ipfr_next; } @@ -485,8 +481,8 @@ int ipfr_slowtimer() for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { --fra->ipfr_ttl; if (fra->ipfr_ttl == 0) { - ATOMIC_INC(ipfr_stats.ifs_expire); - ATOMIC_DEC(ipfr_inuse); + ATOMIC_INCL(ipfr_stats.ifs_expire); + ATOMIC_DEC32(ipfr_inuse); nat = fra->ipfr_data; if (nat != NULL) { if (nat->nat_data == fra) @@ -500,23 +496,55 @@ int ipfr_slowtimer() RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); SPL_X(s); +} + + +/* + * Slowly expire held state for fragments. Timeouts are set * in expectation + * of this being called twice per second. + */ +# if (BSD >= 199306) || SOLARIS || defined(__sgi) +# if defined(SOLARIS2) && (SOLARIS2 < 7) +void ipfr_slowtimer() +# else +void ipfr_slowtimer __P((void *ptr)) +# endif +# else +int ipfr_slowtimer() +# endif +{ +#if defined(_KERNEL) && SOLARIS + extern int fr_running; + + if (fr_running <= 0) + return; +#endif + + READ_ENTER(&ipf_solaris); +#ifdef __sgi + ipfilter_sgi_intfsync(); +#endif + + ipfr_fragexpire(); fr_timeoutstate(); ip_natexpire(); fr_authexpire(); -# if SOLARIS +# if SOLARIS ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); + RWLOCK_EXIT(&ipf_solaris); # else -# ifndef linux +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) + callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); +# else # if (__FreeBSD_version >= 300000) ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); # else timeout(ipfr_slowtimer, NULL, hz/2); # endif -# endif -# if (BSD < 199306) && !defined(__sgi) +# if (BSD < 199306) && !defined(__sgi) return 0; -# endif -# endif - RWLOCK_EXIT(&ipf_solaris); +# endif /* FreeBSD */ +# endif /* NetBSD */ +# endif /* SOLARIS */ } #endif /* defined(_KERNEL) */ diff --git a/contrib/ipfilter/ip_frag.h b/contrib/ipfilter/ip_frag.h index 1097dec..6a3bd2c 100644 --- a/contrib/ipfilter/ip_frag.h +++ b/contrib/ipfilter/ip_frag.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.2 1999/08/06 06:26:38 darrenr Exp $ + * $Id: ip_frag.h,v 2.4 2000/03/13 22:10:21 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -42,6 +42,7 @@ typedef struct ipfrstat { #define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1) extern int fr_ipfrttl; +extern int fr_frag_lock; extern ipfrstat_t *ipfr_fragstats __P((void)); extern int ipfr_newfrag __P((ip_t *, fr_info_t *, u_int)); extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, u_int, struct nat *)); @@ -49,6 +50,7 @@ extern nat_t *ipfr_nat_knownfrag __P((ip_t *, fr_info_t *)); extern frentry_t *ipfr_knownfrag __P((ip_t *, fr_info_t *)); extern void ipfr_forget __P((void *)); extern void ipfr_unload __P((void)); +extern void ipfr_fragexpire __P((void)); #if (BSD >= 199306) || SOLARIS || defined(__sgi) # if defined(SOLARIS2) && (SOLARIS2 < 7) diff --git a/contrib/ipfilter/ip_ftp_pxy.c b/contrib/ipfilter/ip_ftp_pxy.c index 73c27ce..691e0ad 100644 --- a/contrib/ipfilter/ip_ftp_pxy.c +++ b/contrib/ipfilter/ip_ftp_pxy.c @@ -1,12 +1,15 @@ /* * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. + * + * $Id: ip_ftp_pxy.c,v 2.7.2.7 2000/05/13 14:28:14 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; #endif #define isdigit(x) ((x) >= '0' && (x) <= '9') +#define isupper(x) ((unsigned)((x) - 'A') <= 'Z' - 'A') #define IPF_FTP_PROXY @@ -14,17 +17,24 @@ extern kmutex_t ipf_rw; #define IPF_MAXPORTLEN 30 #define IPF_MIN227LEN 39 #define IPF_MAX227LEN 51 +#define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ +int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_complete __P((char *, size_t)); +int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); int ippr_ftp_init __P((void)); +int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_ftp_portmsg __P((fr_info_t *, ip_t *, nat_t *)); -int ippr_ftp_pasvmsg __P((fr_info_t *, ip_t *, nat_t *)); - -u_short ipf_ftp_atoi __P((char **)); +int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); +int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); +int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_valid __P((char *, size_t)); +u_short ippr_ftp_atoi __P((char **)); static frentry_t natfr; +int ippr_ftp_pasvonly = 0; /* @@ -39,48 +49,47 @@ int ippr_ftp_init() } -/* - * ipf_ftp_atoi - implement a version of atoi which processes numbers in - * pairs separated by commas (which are expected to be in the range 0 - 255), - * returning a 16 bit number combining either side of the , as the MSB and - * LSB. - */ -u_short ipf_ftp_atoi(ptr) -char **ptr; +int ippr_ftp_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; { - register char *s = *ptr, c; - register u_char i = 0, j = 0; - - while ((c = *s++) && isdigit(c)) { - i *= 10; - i += c - '0'; - } - if (c != ',') { - *ptr = NULL; - return 0; - } - while ((c = *s++) && isdigit(c)) { - j *= 10; - j += c - '0'; - } - *ptr = s; - return (i << 8) | j; + ftpinfo_t *ftp; + ftpside_t *f; + + KMALLOC(ftp, ftpinfo_t *); + if (ftp == NULL) + return -1; + aps->aps_data = ftp; + aps->aps_psiz = sizeof(ftpinfo_t); + + bzero((char *)ftp, sizeof(*ftp)); + f = &ftp->ftp_side[0]; + f->ftps_rptr = f->ftps_buf; + f->ftps_wptr = f->ftps_buf; + f = &ftp->ftp_side[1]; + f->ftps_rptr = f->ftps_buf; + f->ftps_wptr = f->ftps_buf; + return 0; } -int ippr_ftp_portmsg(fin, ip, nat) +int ippr_ftp_port(fin, ip, nat, f, dlen) fr_info_t *fin; ip_t *ip; nat_t *nat; +ftpside_t *f; +int dlen; { - char portbuf[IPF_MAXPORTLEN + 1], newbuf[IPF_MAXPORTLEN + 1], *s; tcphdr_t *tcp, tcph, *tcp2 = &tcph; - size_t nlen = 0, dlen, olen; + char newbuf[IPF_FTPBUFSZ], *s; u_short a5, a6, sp, dp; u_int a1, a2, a3, a4; struct in_addr swip; - int off, inc = 0; + size_t nlen, olen; fr_info_t fi; + int inc, off; nat_t *ipn; mb_t *m; #if SOLARIS @@ -88,46 +97,34 @@ nat_t *nat; #endif tcp = (tcphdr_t *)fin->fin_dp; - bzero(portbuf, sizeof(portbuf)); - off = (ip->ip_hl << 2) + (tcp->th_off << 2); - -#if SOLARIS - m = fin->fin_qfm; - - dlen = msgdsize(m) - off; - if (dlen > 0) - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#else - m = *(mb_t **)fin->fin_mp; - - dlen = mbufchainlen(m) - off; - if (dlen > 0) - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#endif - if (dlen == 0) + off = f->ftps_seq - ntohl(tcp->th_seq); + if (off < 0) return 0; - portbuf[sizeof(portbuf) - 1] = '\0'; - *newbuf = '\0'; - if (!strncmp(portbuf, "PORT ", 5)) { - if (dlen < IPF_MINPORTLEN) - return 0; - } else + /* + * Check for client sending out PORT message. + */ + if (dlen < IPF_MINPORTLEN) + return 0; + /* + * Count the number of bytes in the PORT message is. + */ + if (off < 0) return 0; + off += fin->fin_hlen + (tcp->th_off << 2); /* * Skip the PORT command + space */ - s = portbuf + 5; + s = f->ftps_rptr + 5; /* * Pick out the address components, two at a time. */ - a1 = ipf_ftp_atoi(&s); + a1 = ippr_ftp_atoi(&s); if (!s) return 0; - a2 = ipf_ftp_atoi(&s); + a2 = ippr_ftp_atoi(&s); if (!s) return 0; - /* * check that IP address in the PORT/PASV reply is the same as the * sender of the command - prevents using PORT for port scanning. @@ -137,7 +134,7 @@ nat_t *nat; if (a1 != ntohl(nat->nat_inip.s_addr)) return 0; - a5 = ipf_ftp_atoi(&s); + a5 = ippr_ftp_atoi(&s); if (!s) return 0; if (*s == ')') @@ -162,13 +159,18 @@ nat_t *nat; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; - olen = s - portbuf; + olen = s - f->ftps_rptr; + /* DO NOT change this to sprintf! */ (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "PORT", a1, a2, a3, a4, a5, a6); nlen = strlen(newbuf); inc = nlen - olen; + if ((inc + ip->ip_len) > 65535) + return 0; + #if SOLARIS + m = fin->fin_qfm; for (m1 = m; m1->b_cont; m1 = m1->b_cont) ; if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { @@ -194,6 +196,7 @@ nat_t *nat; } copyin_mblk(m, off, nlen, newbuf); #else + m = *((mb_t **)fin->fin_mp); if (inc < 0) m_adj(m, inc); /* the mbuf chain will be extended if necessary by m_copyback() */ @@ -223,6 +226,12 @@ nat_t *nat; */ sp = htons(a5 << 8 | a6); /* + * Don't allow the PORT command to specify a port < 1024 due to + * security crap. + */ + if (ntohs(sp) < 1024) + return 0; + /* * The server may not make the connection back from port 20, but * it is the most likely so use it here to check for a conflicting * mapping. @@ -231,10 +240,15 @@ nat_t *nat; ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, ip->ip_dst, (dp << 16) | sp); if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp2); bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = sp; + tcp2->th_off = 5; tcp2->th_dport = 0; /* XXX - don't specify remote port */ fi.fin_data[0] = ntohs(sp); fi.fin_data[1] = 0; @@ -247,82 +261,92 @@ nat_t *nat; ipn->nat_age = fr_defnatage; (void) fr_addstate(ip, &fi, FI_W_DPORT); } + ip->ip_len = slen; ip->ip_src = swip; } return inc; } -int ippr_ftp_out(fin, ip, aps, nat) +int ippr_ftp_client(fin, ip, nat, ftp, dlen) fr_info_t *fin; -ip_t *ip; -ap_session_t *aps; nat_t *nat; +ftpinfo_t *ftp; +ip_t *ip; +int dlen; { - return ippr_ftp_portmsg(fin, ip, nat); + char *rptr, *wptr; + ftpside_t *f; + int inc; + + inc = 0; + f = &ftp->ftp_side[0]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + + if ((ftp->ftp_passok == 0) && !strncmp(rptr, "USER ", 5)) + ftp->ftp_passok = 1; + else if ((ftp->ftp_passok == 2) && !strncmp(rptr, "PASS ", 5)) + ftp->ftp_passok = 3; + else if ((ftp->ftp_passok == 4) && !ippr_ftp_pasvonly && + !strncmp(rptr, "PORT ", 5)) { + inc = ippr_ftp_port(fin, ip, nat, f, dlen); + } + + while ((*rptr++ != '\n') && (rptr < wptr)) + ; + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + return inc; } -int ippr_ftp_pasvmsg(fin, ip, nat) +int ippr_ftp_pasv(fin, ip, nat, f, dlen) fr_info_t *fin; ip_t *ip; nat_t *nat; +ftpside_t *f; +int dlen; { - char portbuf[IPF_MAX227LEN + 1], newbuf[IPF_MAX227LEN + 1], *s; - int off, olen, dlen, nlen = 0, inc = 0; - tcphdr_t tcph, *tcp2 = &tcph; + tcphdr_t *tcp, tcph, *tcp2 = &tcph; struct in_addr swip, swip2; - u_short a5, a6, dp, sp; + u_short a5, a6, sp, dp; u_int a1, a2, a3, a4; - tcphdr_t *tcp; fr_info_t fi; + int inc, off; nat_t *ipn; - mb_t *m; -#if SOLARIS - mb_t *m1; -#endif - - tcp = (tcphdr_t *)fin->fin_dp; - off = (ip->ip_hl << 2) + (tcp->th_off << 2); - m = *(mb_t **)fin->fin_mp; - bzero(portbuf, sizeof(portbuf)); + char *s; -#if SOLARIS - m = fin->fin_qfm; - - dlen = msgdsize(m) - off; - if (dlen > 0) - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#else - dlen = mbufchainlen(m) - off; - if (dlen > 0) - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#endif - if (dlen == 0) + /* + * Check for PASV reply message. + */ + if (dlen < IPF_MIN227LEN) + return 0; + else if (strncmp(f->ftps_rptr, "227 Entering Passive Mode", 25)) return 0; - portbuf[sizeof(portbuf) - 1] = '\0'; - *newbuf = '\0'; - if (!strncmp(portbuf, "227 ", 4)) { - if (dlen < IPF_MIN227LEN) - return 0; - else if (strncmp(portbuf, "227 Entering Passive Mode", 25)) - return 0; - } else + /* + * Count the number of bytes in the 227 reply is. + */ + tcp = (tcphdr_t *)fin->fin_dp; + off = f->ftps_seq - ntohl(tcp->th_seq); + if (off < 0) return 0; + + off += fin->fin_hlen + (tcp->th_off << 2); /* * Skip the PORT command + space */ - s = portbuf + 25; + s = f->ftps_rptr + 25; while (*s && !isdigit(*s)) s++; /* * Pick out the address components, two at a time. */ - a1 = ipf_ftp_atoi(&s); + a1 = ippr_ftp_atoi(&s); if (!s) return 0; - a2 = ipf_ftp_atoi(&s); + a2 = ippr_ftp_atoi(&s); if (!s) return 0; @@ -335,7 +359,7 @@ nat_t *nat; if (a1 != ntohl(nat->nat_oip.s_addr)) return 0; - a5 = ipf_ftp_atoi(&s); + a5 = ippr_ftp_atoi(&s); if (!s) return 0; @@ -360,13 +384,18 @@ nat_t *nat; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; - olen = s - portbuf; + inc = 0; +#if 0 + olen = s - f->ftps_rptr; (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); - nlen = strlen(newbuf); inc = nlen - olen; + if ((inc + ip->ip_len) > 65535) + return 0; + #if SOLARIS + m = fin->fin_qfm; for (m1 = m; m1->b_cont; m1 = m1->b_cont) ; if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { @@ -387,12 +416,13 @@ nat_t *nat; } else { m1->b_wptr += inc; } - copyin_mblk(m, off, nlen, newbuf); + /*copyin_mblk(m, off, nlen, newbuf);*/ #else + m = *((mb_t **)fin->fin_mp); if (inc < 0) m_adj(m, inc); /* the mbuf chain will be extended if necessary by m_copyback() */ - m_copyback(m, off, nlen, newbuf); + /*m_copyback(m, off, nlen, newbuf);*/ #endif if (inc != 0) { #if SOLARIS || defined(__sgi) @@ -411,6 +441,7 @@ nat_t *nat; #endif ip->ip_len += inc; } +#endif /* * Add skeleton NAT entry for connection which will come back the @@ -421,10 +452,15 @@ nat_t *nat; ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, ip->ip_dst, (dp << 16) | sp); if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp2); bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = 0; /* XXX - fake it for nat_new */ + tcp2->th_off = 5; fi.fin_data[0] = a5 << 8 | a6; tcp2->th_dport = htons(fi.fin_data[0]); fi.fin_data[1] = 0; @@ -439,6 +475,7 @@ nat_t *nat; ipn->nat_age = fr_defnatage; (void) fr_addstate(ip, &fi, FI_W_SPORT); } + ip->ip_len = slen; ip->ip_src = swip; ip->ip_dst = swip2; } @@ -446,12 +483,274 @@ nat_t *nat; } +int ippr_ftp_server(fin, ip, nat, ftp, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpinfo_t *ftp; +int dlen; +{ + char *rptr, *wptr; + ftpside_t *f; + int inc; + + inc = 0; + f = &ftp->ftp_side[1]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + + if ((ftp->ftp_passok == 1) && !strncmp(rptr, "331", 3)) + ftp->ftp_passok = 2; + else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "230", 3)) + ftp->ftp_passok = 4; + else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "530", 3)) + ftp->ftp_passok = 0; + else if ((ftp->ftp_passok == 4) && !strncmp(rptr, "227 ", 4)) { + inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + } + while ((*rptr++ != '\n') && (rptr < wptr)) + ; + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + return inc; +} + + +/* + * Look to see if the buffer starts with something which we recognise as + * being the correct syntax for the FTP protocol. + */ +int ippr_ftp_valid(buf, len) +char *buf; +size_t len; +{ + register char *s, c; + register size_t i = len; + + if (i < 5) + return 2; + s = buf; + c = *s++; + i--; + + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if ((c != '-') && (c != ' ')) + return 1; + } else + return 1; + } else + return 1; + } else if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if ((c != ' ') && (c != '\r')) + return 1; + } else if ((c != ' ') && (c != '\r')) + return 1; + } else + return 1; + } else + return 1; + } else + return 1; + for (; i; i--) { + c = *s++; + if (c == '\n') + return 0; + } + return 2; +} + + +int ippr_ftp_process(fin, ip, nat, ftp, rv) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpinfo_t *ftp; +int rv; +{ + int mlen, len, off, inc, i; + char *rptr, *wptr; + tcphdr_t *tcp; + ftpside_t *f; + mb_t *m; + + tcp = (tcphdr_t *)fin->fin_dp; + off = fin->fin_hlen + (tcp->th_off << 2); + +#if SOLARIS + m = fin->fin_qfm; +#else + m = *((mb_t **)fin->fin_mp); +#endif + +#if SOLARIS + mlen = msgdsize(m) - off; +#else + mlen = mbufchainlen(m) - off; +#endif + if (!mlen) + return 0; + + inc = 0; + f = &ftp->ftp_side[rv]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + if ((wptr == f->ftps_buf) && (f->ftps_seq <= ntohl(tcp->th_seq))) + f->ftps_seq = ntohl(tcp->th_seq); + + /* + * XXX - Ideally, this packet should get dropped because we now know + * that it is out of order (and there is no real danger in doing so + * apart from causing packets to go through here ordered). + */ + if (ntohl(tcp->th_seq) != f->ftps_seq + (wptr - rptr)) { + return APR_ERR(0); + } + + while (mlen > 0) { + len = MIN(mlen, FTP_BUFSZ / 2); + +#if SOLARIS + copyout_mblk(m, off, len, wptr); +#else + m_copydata(m, off, len, wptr); +#endif + mlen -= len; + off += len; + wptr += len; + f->ftps_wptr = wptr; + if (f->ftps_junk == 2) + f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + + while ((f->ftps_junk == 0) && (wptr > rptr)) { + f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + if (f->ftps_junk == 0) { + len = wptr - rptr; + f->ftps_rptr = rptr; + if (rv) + inc += ippr_ftp_server(fin, ip, nat, + ftp, len); + else + inc += ippr_ftp_client(fin, ip, nat, + ftp, len); + rptr = f->ftps_rptr; + } + } + + while ((f->ftps_junk == 1) && (rptr < wptr)) { + while ((rptr < wptr) && (*rptr != '\r')) + rptr++; + + if ((*rptr == '\r') && (rptr + 1 < wptr)) { + if (*(rptr + 1) == '\n') { + rptr += 2; + f->ftps_junk = 0; + } else + rptr++; + } + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + } + + if (rptr == wptr) { + rptr = wptr = f->ftps_buf; + } else { + if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) { + i = wptr - rptr; + if ((rptr == f->ftps_buf) || + (wptr - rptr > FTP_BUFSZ / 2)) { + f->ftps_seq += i; + f->ftps_junk = 1; + rptr = wptr = f->ftps_buf; + } else { + bcopy(rptr, f->ftps_buf, i); + wptr = f->ftps_buf + i; + rptr = f->ftps_buf; + } + } + f->ftps_rptr = rptr; + f->ftps_wptr = wptr; + } + } + + f->ftps_rptr = rptr; + f->ftps_wptr = wptr; + return inc; +} + + +int ippr_ftp_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ftpinfo_t *ftp; + + ftp = aps->aps_data; + if (ftp == NULL) + return 0; + return ippr_ftp_process(fin, ip, nat, ftp, 0); +} + + int ippr_ftp_in(fin, ip, aps, nat) fr_info_t *fin; ip_t *ip; ap_session_t *aps; nat_t *nat; { + ftpinfo_t *ftp; + + ftp = aps->aps_data; + if (ftp == NULL) + return 0; + return ippr_ftp_process(fin, ip, nat, ftp, 1); +} + - return ippr_ftp_pasvmsg(fin, ip, nat); +/* + * ippr_ftp_atoi - implement a version of atoi which processes numbers in + * pairs separated by commas (which are expected to be in the range 0 - 255), + * returning a 16 bit number combining either side of the , as the MSB and + * LSB. + */ +u_short ippr_ftp_atoi(ptr) +char **ptr; +{ + register char *s = *ptr, c; + register u_char i = 0, j = 0; + + while ((c = *s++) && isdigit(c)) { + i *= 10; + i += c - '0'; + } + if (c != ',') { + *ptr = NULL; + return 0; + } + while ((c = *s++) && isdigit(c)) { + j *= 10; + j += c - '0'; + } + *ptr = s; + return (i << 8) | j; } diff --git a/contrib/ipfilter/ip_lfil.c b/contrib/ipfilter/ip_lfil.c index 8e7ea33..4763ad7 100644 --- a/contrib/ipfilter/ip_lfil.c +++ b/contrib/ipfilter/ip_lfil.c @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_lfil.c,v 2.1.2.1 2000/01/16 10:13:02 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_lfil.c,v 2.6 2000/03/13 22:10:21 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) @@ -179,8 +179,9 @@ caddr_t data; fio.f_active = fr_active; fio.f_froute[0] = ipl_frouteok[0]; fio.f_froute[1] = ipl_frouteok[1]; - IWCOPY((caddr_t)&fio, data, sizeof(fio)); - bzero((char *)frstats, sizeof(*frstats) * 2); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (!error) + bzero((char *)frstats, sizeof(*frstats) * 2); return error; } @@ -219,8 +220,8 @@ int iplioctl(dev_t dev, int cmd, caddr_t data, int mode) switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG - IWCOPY((caddr_t)&iplused[IPL_LOGIPF], data, - sizeof(iplused[IPL_LOGIPF])); + error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], data, + sizeof(iplused[IPL_LOGIPF])); #endif break; #if !defined(IPFILTER_LKM) && defined(_KERNEL) @@ -231,7 +232,7 @@ int iplioctl(dev_t dev, int cmd, caddr_t data, int mode) if (!(mode & FWRITE)) error = EPERM; else { - IRCOPY(data, (caddr_t)&enable, sizeof(enable)); + error = IRCOPY(data, (caddr_t)&enable, sizeof(enable)); if (error) break; if (enable) @@ -246,10 +247,11 @@ int iplioctl(dev_t dev, int cmd, caddr_t data, int mode) if (!(mode & FWRITE)) error = EPERM; else - IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags)); + error = IRCOPY(data, (caddr_t)&fr_flags, + sizeof(fr_flags)); break; case SIOCGETFF : - IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); + error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); break; case SIOCINAFR : case SIOCRMAFR : @@ -295,22 +297,25 @@ int iplioctl(dev_t dev, int cmd, caddr_t data, int mode) fio.f_active = fr_active; fio.f_froute[0] = ipl_frouteok[0]; fio.f_froute[1] = ipl_frouteok[1]; - IWCOPY((caddr_t)&fio, data, sizeof(fio)); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); break; } case SIOCFRZST : if (!(mode & FWRITE)) error = EPERM; else - frzerostats(data); + error = frzerostats(data); break; case SIOCIPFFL : if (!(mode & FWRITE)) error = EPERM; else { - IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - tmp = frflush(unit, tmp); - IWCOPY((caddr_t)&tmp, data, sizeof(tmp)); + error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + tmp = frflush(unit, tmp); + error = IWCOPY((caddr_t)&tmp, data, + sizeof(tmp)); + } } break; #ifdef IPFILTER_LOG @@ -322,7 +327,8 @@ int iplioctl(dev_t dev, int cmd, caddr_t data, int mode) break; #endif /* IPFILTER_LOG */ case SIOCGFRST : - IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t)); + error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, + sizeof(ipfrstat_t)); break; case SIOCAUTHW : case SIOCAUTHR : @@ -377,7 +383,7 @@ caddr_t data; u_int group; fp = &frd; - IRCOPY(data, (caddr_t)fp, sizeof(*fp)); + error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); if (error) return error; @@ -412,7 +418,7 @@ caddr_t data; bzero((char *)frcache, sizeof(frcache[0]) * 2); if (*fp->fr_ifname) { - fp->fr_ifa = GETUNIT(fp->fr_ifname); + fp->fr_ifa = GETUNIT(fp->fr_ifname, fp->fr_ip.fi_v); if (!fp->fr_ifa) fp->fr_ifa = (void *)-1; } @@ -420,7 +426,7 @@ caddr_t data; fdp = &fp->fr_dif; fp->fr_flags &= ~FR_DUP; if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname); + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_ip.fi_v); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; else @@ -429,7 +435,7 @@ caddr_t data; fdp = &fp->fr_tif; if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname); + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_ip.fi_v); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; } @@ -449,7 +455,7 @@ caddr_t data; if (req == SIOCZRLST) { if (!f) return ESRCH; - IWCOPY((caddr_t)f, data, sizeof(*f)); + error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); if (error) return error; f->fr_hits = 0; @@ -458,17 +464,18 @@ caddr_t data; } if (!f) { - ftail = fprev; - if (req != SIOCINAFR && req != SIOCINIFR) - while ((f = *ftail)) - ftail = &f->fr_next; - else if (fp->fr_hits) - while (--fp->fr_hits && (f = *ftail)) - ftail = &f->fr_next; + if (req == SIOCINAFR || req == SIOCINIFR) { + ftail = fprev; + if (fp->fr_hits) { + while (--fp->fr_hits && (f = *ftail)) { + ftail = &f->fr_next; + } + } + } f = NULL; } - if (req == SIOCDELFR || req == SIOCRMIFR) { + if (req == SIOCRMAFR || req == SIOCRMIFR) { if (!f) error = ESRCH; else { @@ -796,9 +803,9 @@ int uiomove(caddr_t src, size_t ssize, int rw, struct uio *uio) size_t mv = MIN(ssize, uio->uio_resid); if (rw == UIO_READ) { - IWCOPY(src, (caddr_t)uio->uio_buf, mv); + error = IWCOPY(src, (caddr_t)uio->uio_buf, mv); } else if (rw == UIO_WRITE) { - IRCOPY((caddr_t)uio->uio_buf, src, mv); + error = IRCOPY((caddr_t)uio->uio_buf, src, mv); } else error = EINVAL; if (!error) { @@ -880,8 +887,9 @@ static int write_output __P((mb_t *m, struct ifnet *ifp)) } -struct ifnet *get_unit(name) +struct ifnet *get_unit(name, v) char *name; +int v; { struct ifnet *ifp, **ifa; char ifname[32], *s; diff --git a/contrib/ipfilter/ip_log.c b/contrib/ipfilter/ip_log.c index 1b92cfe..ef1af7f 100644 --- a/contrib/ipfilter/ip_log.c +++ b/contrib/ipfilter/ip_log.c @@ -1,11 +1,11 @@ /* - * Copyright (C) 1997-1998 by Darren Reed. + * Copyright (C) 1997-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_log.c,v 2.1.2.2 1999/09/21 11:55:44 darrenr Exp $ + * $Id: ip_log.c,v 2.5 2000/03/13 22:10:21 darrenr Exp $ */ #include <sys/param.h> #if defined(KERNEL) && !defined(_KERNEL) @@ -16,7 +16,6 @@ #endif #ifdef __FreeBSD__ # if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include <sys/osreldate.h> # if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) # include "opt_ipfilter.h" # endif @@ -128,7 +127,7 @@ extern kcondvar_t iplwait; iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; size_t iplused[IPL_LOGMAX+1]; -fr_info_t iplcrc[IPL_LOGMAX+1]; +static fr_info_t iplcrc[IPL_LOGMAX+1]; # ifdef linux static struct wait_queue *iplwait[IPL_LOGMAX+1]; # endif @@ -171,6 +170,7 @@ mb_t *m; size_t sizes[2]; void *ptrs[2]; int types[2]; + u_char p; # if SOLARIS ill_t *ifp = fin->fin_ifp; # else @@ -181,15 +181,16 @@ mb_t *m; * calculate header size. */ hlen = fin->fin_hlen; - if ((ip->ip_off & IP_OFFMASK) == 0) { - if (ip->ip_p == IPPROTO_TCP) + if (fin->fin_off == 0) { + p = fin->fin_fi.fi_p; + if (p == IPPROTO_TCP) hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); - else if (ip->ip_p == IPPROTO_UDP) + else if (p == IPPROTO_UDP) hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); - else if (ip->ip_p == IPPROTO_ICMP) { - struct icmp *icmp; + else if (p == IPPROTO_ICMP) { + struct icmp *icmp; - icmp = (struct icmp *)((char *)ip + hlen); + icmp = (struct icmp *)fin->fin_dp; /* * For ICMP, if the packet is an error packet, also @@ -234,7 +235,7 @@ mb_t *m; if ((ipfl.fl_ifname[2] = ifp->if_name[2])) ipfl.fl_ifname[3] = ifp->if_name[3]; # endif - mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0; + mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0; # endif ipfl.fl_plen = (u_char)mlen; ipfl.fl_hlen = (u_char)hlen; diff --git a/contrib/ipfilter/ip_nat.c b/contrib/ipfilter/ip_nat.c index bf11843..64f50b6 100644 --- a/contrib/ipfilter/ip_nat.c +++ b/contrib/ipfilter/ip_nat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-1998 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -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.2.2.12 2000/01/24 12:43:40 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.10 2000/05/19 15:54:44 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -30,7 +30,7 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.2.2.12 2000/01/24 12:43:40 da # include <string.h> # include <stdlib.h> #endif -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> #else @@ -117,24 +117,36 @@ ipnat_t *nat_list = NULL; 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; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; ipnat_t **nat_rules = NULL; ipnat_t **rdr_rules = NULL; +hostmap_t **maptable = NULL; u_long fr_defnatage = DEF_NAT_AGE, fr_defnaticmpage = 6; /* 3 seconds */ -natstat_t nat_stats; +static natstat_t nat_stats; +int fr_nat_lock = 0; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_t ipf_rw; +extern kmutex_t ipf_rw, ipf_hostmap; extern KRWLOCK_T ipf_nat; #endif static int nat_flushtable __P((void)); static int nat_clearlist __P((void)); +static void nat_addnat __P((struct ipnat *)); +static void nat_addrdr __P((struct ipnat *)); static void nat_delete __P((struct nat *)); static void nat_delrdr __P((struct ipnat *)); 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 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)); +static void nat_hostmapdel __P((struct hostmap *)); int nat_init() @@ -162,39 +174,129 @@ int nat_init() bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *)); else return -1; + + KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz); + if (maptable != NULL) + bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + else + return -1; return 0; } -void nat_delrdr(n) +static void nat_addrdr(n) ipnat_t *n; { - ipnat_t **n1; - u_32_t iph; + ipnat_t **np; + u_32_t j; u_int hv; + int k; + + k = countbits(n->in_outmsk); + if ((k >= 0) && (k != 32)) + rdr_masks |= 1 << k; + j = (n->in_outip & n->in_outmsk); + hv = NAT_HASH_FN(j, 0, ipf_rdrrules_sz); + np = rdr_rules + hv; + while (*np != NULL) + np = &(*np)->in_rnext; + n->in_rnext = NULL; + n->in_prnext = np; + *np = n; +} - iph = n->in_outip & n->in_outmsk; - hv = NAT_HASH_FN(iph, ipf_rdrrules_sz); - for (n1 = &rdr_rules[hv]; *n1 && (*n1 != n); n1 = &(*n1)->in_rnext) - ; - if (*n1) - *n1 = n->in_rnext; + +static void nat_addnat(n) +ipnat_t *n; +{ + ipnat_t **np; + u_32_t j; + u_int hv; + int k; + + k = countbits(n->in_inmsk); + if ((k >= 0) && (k != 32)) + nat_masks |= 1 << k; + j = (n->in_inip & n->in_inmsk); + hv = NAT_HASH_FN(j, 0, ipf_natrules_sz); + np = nat_rules + hv; + while (*np != NULL) + np = &(*np)->in_mnext; + n->in_mnext = NULL; + n->in_pmnext = np; + *np = n; +} + + +static void nat_delrdr(n) +ipnat_t *n; +{ + if (n->in_rnext) + n->in_rnext->in_prnext = n->in_prnext; + *n->in_prnext = n->in_rnext; } static void nat_delnat(n) ipnat_t *n; { - ipnat_t **n1; - u_32_t iph; + if (n->in_mnext) + n->in_mnext->in_pmnext = n->in_pmnext; + *n->in_pmnext = n->in_mnext; +} + + +/* + * check if an ip address has already been allocated for a given mapping that + * is not doing port based translation. + */ +static struct hostmap *nat_hostmap(np, real, map) +ipnat_t *np; +struct in_addr real; +struct in_addr map; +{ + hostmap_t *hm; u_int hv; - iph = n->in_inip & n->in_inmsk; - hv = NAT_HASH_FN(iph, ipf_natrules_sz); - for (n1 = &nat_rules[hv]; *n1 && (*n1 != n); n1 = &(*n1)->in_mnext) - ; - if (*n1) - *n1 = n->in_mnext; + MUTEX_ENTER(&ipf_hostmap); + hv = real.s_addr % HOSTMAP_SIZE; + for (hm = maptable[hv]; hm; hm = hm->hm_next) + if ((hm->hm_realip.s_addr == real.s_addr) && + (np == hm->hm_ipnat)) { + hm->hm_ref++; + MUTEX_EXIT(&ipf_hostmap); + return hm; + } + + KMALLOC(hm, hostmap_t *); + if (hm) { + hm->hm_next = maptable[hv]; + hm->hm_pnext = maptable + hv; + if (maptable[hv]) + maptable[hv]->hm_pnext = &hm->hm_next; + maptable[hv] = hm; + hm->hm_ipnat = np; + hm->hm_realip = real; + hm->hm_mapip = map; + hm->hm_ref = 1; + } + MUTEX_EXIT(&ipf_hostmap); + return hm; +} + + +static void nat_hostmapdel(hm) +struct hostmap *hm; +{ + MUTEX_ENTER(&ipf_hostmap); + ATOMIC_DEC32(hm->hm_ref); + if (hm->hm_ref == 0) { + if (hm->hm_next) + hm->hm_next->hm_pnext = hm->hm_pnext; + *hm->hm_pnext = hm->hm_next; + KFREE(hm); + } + MUTEX_EXIT(&ipf_hostmap); } @@ -279,7 +381,7 @@ int len; * Handle ioctls which manipulate the NAT. */ int nat_ioctl(data, cmd, mode) -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) u_long cmd; #else int cmd; @@ -288,12 +390,9 @@ caddr_t data; int mode; { register ipnat_t *nat, *nt, *n = NULL, **np = NULL; - int error = 0, ret, k; + int error = 0, ret, arg; ipnat_t natd; u_32_t i, j; -#if defined(_KERNEL) && !SOLARIS - int s; -#endif #if (BSD >= 199306) && defined(_KERNEL) if ((securelevel >= 2) && (mode & FWRITE)) @@ -303,19 +402,24 @@ int mode; nat = NULL; /* XXX gcc -Wuninitialized */ KMALLOC(nt, ipnat_t *); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) - IRCOPY(data, (char *)&natd, sizeof(natd)); + error = IRCOPYPTR(data, (char *)&natd, sizeof(natd)); + else if (cmd == SIOCIPFFL) /* SIOCFLNAT & SIOCCNATL */ + error = IRCOPY(data, (char *)&arg, sizeof(arg)); + + if (error) + goto done; /* * For add/delete, look to see if the NAT entry is already present */ - SPL_NET(s); WRITE_ENTER(&ipf_nat); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { nat = &natd; nat->in_flags &= IPN_USERFLAGS; if ((nat->in_redir & NAT_MAPBLK) == 0) { - nat->in_inip &= nat->in_inmsk; - if ((nat->in_flags & IPN_RANGE) == 0) + if ((nat->in_flags & IPN_SPLIT) == 0) + nat->in_inip &= nat->in_inmsk; + if ((nat->in_flags & IPN_IPRANGE) == 0) nat->in_outip &= nat->in_outmsk; } for (np = &nat_list; (n = *np); np = &n->in_next) @@ -328,11 +432,17 @@ int mode; { #ifdef IPFILTER_LOG case SIOCIPFFB : + { + int tmp; + if (!(mode & FWRITE)) error = EPERM; - else - *(int *)data = ipflog_clear(IPL_LOGNAT); + else { + tmp = ipflog_clear(IPL_LOGNAT); + IWCOPY((char *)&tmp, (char *)data, sizeof(tmp)); + } break; + } #endif case SIOCADNAT : if (!(mode & FWRITE)) { @@ -350,7 +460,7 @@ int mode; n = nt; nt = NULL; bcopy((char *)nat, (char *)n, sizeof(*n)); - n->in_ifp = (void *)GETUNIT(n->in_ifname); + n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); if (!n->in_ifp) n->in_ifp = (void *)-1; if (n->in_plabel[0] != '\0') { @@ -363,42 +473,20 @@ int mode; n->in_next = NULL; *np = n; - if (n->in_redir & NAT_REDIRECT) { - u_int hv; - - k = countbits(n->in_outmsk); - if ((k >= 0) && (k != 32)) - rdr_masks |= 1 << k; - j = (n->in_outip & n->in_outmsk); - hv = NAT_HASH_FN(j, ipf_rdrrules_sz); - np = rdr_rules + hv; - while (*np != NULL) - np = &(*np)->in_rnext; - n->in_rnext = NULL; - *np = n; - } - if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { - u_int hv; - - k = countbits(n->in_inmsk); - if ((k >= 0) && (k != 32)) - nat_masks |= 1 << k; - j = (n->in_inip & n->in_inmsk); - hv = NAT_HASH_FN(j, ipf_natrules_sz); - np = nat_rules + hv; - while (*np != NULL) - np = &(*np)->in_mnext; - n->in_mnext = NULL; - *np = n; - } + if (n->in_redir & NAT_REDIRECT) + nat_addrdr(n); + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) + nat_addnat(n); n->in_use = 0; if (n->in_redir & NAT_MAPBLK) n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); else if (n->in_flags & IPN_AUTOPORTMAP) n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); - else if (n->in_flags & IPN_RANGE) + else if (n->in_flags & IPN_IPRANGE) n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); + else if (n->in_flags & IPN_SPLIT) + n->in_space = 2; else n->in_space = ~ntohl(n->in_outmsk); /* @@ -411,15 +499,18 @@ int mode; * If to a single IP address, set to 1. */ if (n->in_space) { - if ((n->in_flags & IPN_RANGE) != 0) + if ((n->in_flags & IPN_IPRANGE) != 0) n->in_space += 1; else n->in_space -= 1; } else n->in_space = 1; if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && - ((n->in_flags & IPN_RANGE) == 0)) + ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) n->in_nip = ntohl(n->in_outip) + 1; + else if ((n->in_flags & IPN_SPLIT) && + (n->in_redir & NAT_REDIRECT)) + n->in_nip = ntohl(n->in_inip); else n->in_nip = ntohl(n->in_outip); if (n->in_redir & NAT_MAP) { @@ -501,44 +592,76 @@ int mode; nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; nat_stats.ns_instances = nat_instances; nat_stats.ns_apslist = ap_sess_list; - IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats)); + error = IWCOPYPTR((char *)&nat_stats, (char *)data, + sizeof(nat_stats)); break; case SIOCGNATL : { natlookup_t nl; MUTEX_DOWNGRADE(&ipf_nat); - IRCOPY((char *)data, (char *)&nl, sizeof(nl)); + error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl)); + if (error) + break; if (nat_lookupredir(&nl)) { - IWCOPY((char *)&nl, (char *)data, sizeof(nl)); + error = IWCOPYPTR((char *)&nl, (char *)data, + sizeof(nl)); } else error = ESRCH; break; } - case SIOCFLNAT : + case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ if (!(mode & FWRITE)) { error = EPERM; break; } - ret = nat_flushtable(); + error = 0; + if (arg == 0) + ret = nat_flushtable(); + else if (arg == 1) + ret = nat_clearlist(); + else + error = EINVAL; MUTEX_DOWNGRADE(&ipf_nat); - IWCOPY((caddr_t)&ret, data, sizeof(ret)); + if (!error) { + error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); + if (error) + error = EFAULT; + } break; - case SIOCCNATL : - if (!(mode & FWRITE)) { - error = EPERM; - break; + case SIOCSTLCK : + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (!error) { + error = IWCOPY((caddr_t)&fr_nat_lock, data, + sizeof(fr_nat_lock)); + if (!error) + fr_nat_lock = arg; } - ret = nat_clearlist(); - MUTEX_DOWNGRADE(&ipf_nat); - IWCOPY((caddr_t)&ret, data, sizeof(ret)); + break; + case SIOCSTPUT : + if (fr_nat_lock) + error = fr_natputent(data); + else + error = EACCES; + break; + case SIOCSTGSZ : + if (fr_nat_lock) + error = fr_natgetsz(data); + else + error = EACCES; + break; + case SIOCSTGET : + if (fr_nat_lock) + error = fr_natgetent(data); + else + error = EACCES; break; case FIONREAD : #ifdef IPFILTER_LOG MUTEX_DOWNGRADE(&ipf_nat); - IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, - sizeof(iplused[IPL_LOGNAT])); + error = IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, + sizeof(iplused[IPL_LOGNAT])); #endif break; default : @@ -546,13 +669,285 @@ int mode; break; } RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ - SPL_X(s); +done: if (nt) KFREE(nt); return error; } +static int fr_natgetsz(data) +caddr_t data; +{ + ap_session_t *aps; + nat_t *nat, *n; + int error = 0; + natget_t ng; + + error = IRCOPY(data, (caddr_t)&ng, sizeof(ng)); + if (error) + return EFAULT; + + nat = ng.ng_ptr; + if (!nat) { + nat = nat_instances; + ng.ng_sz = 0; + if (nat == NULL) { + error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); + if (error) + error = EFAULT; + return error; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (n = nat_instances; n; n = n->nat_next) + if (n == nat) + break; + if (!n) + return ESRCH; + } + + ng.ng_sz = sizeof(nat_save_t); + aps = nat->nat_aps; + if ((aps != NULL) && (aps->aps_data != 0)) { + ng.ng_sz += sizeof(ap_session_t); + ng.ng_sz += aps->aps_psiz; + } + + error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); + if (error) + error = EFAULT; + return error; +} + + +static int fr_natgetent(data) +caddr_t data; +{ + nat_save_t ipn, *ipnp, *ipnn; + register nat_t *n, *nat; + ap_session_t *aps; + int error; + + error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); + if (error) + return EFAULT; + + nat = ipn.ipn_next; + if (!nat) { + nat = nat_instances; + if (nat == NULL) { + if (nat_instances == NULL) + return ENOENT; + return 0; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (n = nat_instances; n; n = n->nat_next) + if (n == nat) + break; + if (!n) + return ESRCH; + } + + ipn.ipn_next = nat->nat_next; + ipn.ipn_dsize = 0; + bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat)); + ipn.ipn_nat.nat_data = NULL; + + if (nat->nat_ptr) { + bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat, + sizeof(ipn.ipn_ipnat)); + } + + if (nat->nat_fr) + bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule, + sizeof(ipn.ipn_rule)); + + if ((aps = nat->nat_aps)) { + ipn.ipn_dsize = sizeof(*aps); + if (aps->aps_data) + ipn.ipn_dsize += aps->aps_psiz; + KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); + if (ipnn == NULL) + return NULL; + bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + + bcopy((char *)aps, ipn.ipn_data, sizeof(*aps)); + if (aps->aps_data) { + bcopy(aps->aps_data, ipn.ipn_data + sizeof(*aps), + aps->aps_psiz); + ipn.ipn_dsize += aps->aps_psiz; + } + error = IWCOPY((caddr_t)ipnn, ipnp, + sizeof(ipn) + ipn.ipn_dsize); + if (error) + return EFAULT; + KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize); + } else { + error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); + if (error) + return EFAULT; + } + return 0; +} + + +static int fr_natputent(data) +caddr_t data; +{ + nat_save_t ipn, *ipnp, *ipnn; + register nat_t *n, *nat; + ap_session_t *aps; + frentry_t *fr; + ipnat_t *in; + + int error; + + error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); + if (error) + return EFAULT; + if (ipn.ipn_dsize) { + KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize); + if (ipnn == NULL) + return ENOMEM; + bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data, + ipn.ipn_dsize); + if (error) + return EFAULT; + } else + ipnn = NULL; + + KMALLOC(nat, nat_t *); + if (nat == NULL) + return ENOMEM; + + bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat)); + /* + * Initialize all these so that nat_delete() doesn't cause a crash. + */ + nat->nat_hstart[0] = NULL; + nat->nat_hstart[1] = NULL; + fr = nat->nat_fr; + nat->nat_fr = NULL; + aps = nat->nat_aps; + nat->nat_aps = NULL; + in = nat->nat_ptr; + nat->nat_ptr = NULL; + nat->nat_data = NULL; + + /* + * Restore the rule associated with this nat session + */ + if (in) { + KMALLOC(in, ipnat_t *); + if (in == NULL) { + error = ENOMEM; + goto junkput; + } + nat->nat_ptr = in; + bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in)); + in->in_use = 1; + in->in_flags |= IPN_DELETE; + in->in_next = NULL; + in->in_rnext = NULL; + in->in_prnext = NULL; + in->in_mnext = NULL; + in->in_pmnext = NULL; + in->in_ifp = GETUNIT(in->in_ifname, 4); + if (in->in_plabel[0] != '\0') { + in->in_apr = appr_match(in->in_p, in->in_plabel); + } + } + + /* + * Restore ap_session_t structure. Include the private data allocated + * if it was there. + */ + if (aps) { + KMALLOC(aps, ap_session_t *); + if (aps == NULL) { + error = ENOMEM; + goto junkput; + } + nat->nat_aps = aps; + aps->aps_next = ap_sess_list; + ap_sess_list = aps; + bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); + if (in) + aps->aps_apr = in->in_apr; + if (aps->aps_psiz) { + KMALLOCS(aps->aps_data, void *, aps->aps_psiz); + if (aps->aps_data == NULL) { + error = ENOMEM; + goto junkput; + } + bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, + aps->aps_psiz); + } else { + aps->aps_psiz = 0; + aps->aps_data = NULL; + } + } + + /* + * If there was a filtering rule associated with this entry then + * build up a new one. + */ + if (fr != NULL) { + if (nat->nat_flags & FI_NEWFR) { + KMALLOC(fr, frentry_t *); + nat->nat_fr = fr; + if (fr == NULL) { + error = ENOMEM; + goto junkput; + } + bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr)); + ipn.ipn_nat.nat_fr = fr; + error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); + if (error) { + error = EFAULT; + goto junkput; + } + } else { + for (n = nat_instances; n; n = n->nat_next) + if (n->nat_fr == fr) + break; + if (!n) { + error = ESRCH; + goto junkput; + } + } + } + + if (ipnn) + KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); + nat_insert(nat); + return 0; +junkput: + if (ipnn) + KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); + if (nat) + nat_delete(nat); + return error; +} + + /* * Delete a nat entry from the various lists and table. */ @@ -562,14 +957,14 @@ struct nat *natd; register struct nat **natp, *nat; struct ipnat *ipn; - for (natp = natd->nat_hstart[0]; (nat = *natp); + 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]; (nat = *natp); + for (natp = natd->nat_hstart[1]; natp && (nat = *natp); natp = &nat->nat_hnext[1]) if (nat == natd) { *natp = nat->nat_hnext[1]; @@ -577,8 +972,12 @@ struct nat *natd; } if (natd->nat_fr != NULL) { - ATOMIC_DEC(natd->nat_fr->fr_ref); + ATOMIC_DEC32(natd->nat_fr->fr_ref); } + + if (natd->nat_hm != NULL) + nat_hostmapdel(natd->nat_hm); + /* * If there is an active reference from the nat entry to its parent * rule, decrement the rule's reference count and free it too if no @@ -596,6 +995,7 @@ struct nat *natd; } } + MUTEX_DESTROY(&natd->nat_lock); /* * If there's a fragment table entry too for this nat entry, then * dereference that as well. @@ -681,11 +1081,11 @@ int direction; { register u_32_t sum1, sum2, sumd, l; u_short port = 0, sport = 0, dport = 0, nport = 0; - nat_t *nat, **natp, *natl = NULL; struct in_addr in, inb; tcphdr_t *tcp = NULL; + hostmap_t *hm = NULL; + nat_t *nat, *natl; u_short nflags; - u_int hv; #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) qif_t *qf = fin->fin_qif; #endif @@ -699,8 +1099,10 @@ int direction; /* Give me a new nat */ KMALLOC(nat, nat_t *); - if (nat == NULL) + if (nat == NULL) { + nat_stats.ns_memfail++; return NULL; + } bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; @@ -724,42 +1126,33 @@ int direction; do { port = 0; - in.s_addr = np->in_nip; + in.s_addr = htonl(np->in_nip); if (l == 0) { /* * Check to see if there is an existing NAT * setup for this IP address pair. */ - natl = nat_maplookup(fin->fin_ifp, flags, - ip->ip_src, ip->ip_dst); - if (natl != NULL) { - in = natl->nat_outip; - if ((in.s_addr & np->in_outmsk) != - np->in_outip) - in.s_addr = 0; - else -#ifndef sparc - in.s_addr = ntohl(in.s_addr); -#else - ; -#endif - } + hm = nat_hostmap(np, ip->ip_src, in); + if (hm != NULL) + in.s_addr = hm->hm_mapip.s_addr; + } else if ((l == 1) && (hm != NULL)) { + nat_hostmapdel(hm); + hm = NULL; } + in.s_addr = ntohl(in.s_addr); + + nat->nat_hm = hm; if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { - if (l > 0) { - KFREE(nat); - return NULL; - } + if (l > 0) + goto badnat; } if (np->in_redir & NAT_MAPBLK) { if ((l >= np->in_ppip) || ((l > 0) && - !(flags & IPN_TCPUDP))) { - KFREE(nat); - return NULL; - } + !(flags & IPN_TCPUDP))) + goto badnat; /* * map-block - Calculate destination address. */ @@ -781,29 +1174,25 @@ int direction; port += MAPBLK_MINPORT; port = htons(port); } - } else if (!in.s_addr && + } else if (!np->in_outip && (np->in_outmsk == 0xffffffff)) { /* * 0/32 - use the interface's IP address. */ if ((l > 0) || - fr_ifpaddr(fin->fin_ifp, &in) == -1) { - KFREE(nat); - return NULL; - } + fr_ifpaddr(4, fin->fin_ifp, &in) == -1) + goto badnat; in.s_addr = ntohl(in.s_addr); - } else if (!in.s_addr && !np->in_outmsk) { + } else if (!np->in_outip && !np->in_outmsk) { /* * 0/0 - use the original source address/port. */ - if (l > 0) { - KFREE(nat); - return NULL; - } + if (l > 0) + goto badnat; in.s_addr = ntohl(ip->ip_src.s_addr); } else if ((np->in_outmsk != 0xffffffff) && (np->in_pnext == 0) && - ((l > 0) || (natl == NULL))) + ((l > 0) || (hm == NULL))) np->in_nip++; natl = NULL; @@ -812,8 +1201,7 @@ int direction; (np->in_flags & IPN_AUTOPORTMAP)) { if ((l > 0) && (l % np->in_ppip == 0)) { if (l > np->in_space) { - KFREE(nat); - return NULL; + goto badnat; } else if ((l > np->in_ppip) && np->in_outmsk != 0xffffffff) np->in_nip++; @@ -839,8 +1227,8 @@ int direction; } } - if (np->in_flags & IPN_RANGE) { - if (np->in_nip >= ntohl(np->in_outmsk)) + if (np->in_flags & IPN_IPRANGE) { + if (np->in_nip > ntohl(np->in_outmsk)) np->in_nip = ntohl(np->in_outip); } else { if ((np->in_outmsk != 0xffffffff) && @@ -863,7 +1251,7 @@ int direction; * this is appropriate. */ inb.s_addr = htonl(in.s_addr); - natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILD, + natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP, (u_int)ip->ip_p, ip->ip_dst, inb, (port << 16) | dport); @@ -873,10 +1261,8 @@ int direction; */ if ((natl != NULL) && (np->in_pnext != 0) && (st_port == np->in_pnext) && - (np->in_nip != 0) && (st_ip == np->in_nip)) { - KFREE(nat); - return NULL; - } + (np->in_nip != 0) && (st_ip == np->in_nip)) + goto badnat; l++; } while (natl != NULL); @@ -887,6 +1273,9 @@ int direction; nat->nat_inip = ip->ip_src; nat->nat_outip.s_addr = htonl(in.s_addr); nat->nat_oip = ip->ip_dst; + if (nat->nat_hm == NULL) + nat->nat_hm = nat_hostmap(np, ip->ip_src, + nat->nat_outip); sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport); sum2 = LONG_SUM(in.s_addr) + ntohs(port); @@ -903,18 +1292,45 @@ int direction; * we want to rewrite to a fixed internal address and fixed * internal port. */ - in.s_addr = ntohl(np->in_inip); - if (!(nport = np->in_pnext)) + if (np->in_flags & IPN_SPLIT) { + in.s_addr = np->in_nip; + if (np->in_inip == htonl(in.s_addr)) + np->in_nip = ntohl(np->in_inmsk); + else { + np->in_nip = ntohl(np->in_inip); + if (np->in_flags & IPN_ROUNDR) { + nat_delrdr(np); + nat_addrdr(np); + } + } + } else { + in.s_addr = ntohl(np->in_inip); + if (np->in_flags & IPN_ROUNDR) { + nat_delrdr(np); + nat_addrdr(np); + } + } + if (!np->in_pnext) nport = dport; + else { + /* + * Whilst not optimized for the case where + * pmin == pmax, the gain is not significant. + */ + nport = ntohs(dport) - ntohs(np->in_pmin) + + ntohs(np->in_pnext); + nport = htons(nport); + } /* * When the redirect-to address is set to 0.0.0.0, just * assume a blank `forwarding' of the packet. We don't * setup any translation for this either. */ - if ((in.s_addr == 0) && (nport == dport)) { - KFREE(nat); - return NULL; + if (in.s_addr == 0) { + if (nport == dport) + goto badnat; + in.s_addr = ntohl(ip->ip_dst.s_addr); } nat->nat_inip.s_addr = htonl(in.s_addr); @@ -962,28 +1378,21 @@ int direction; nat->nat_ipsumd = nat->nat_sumd[0]; in.s_addr = htonl(in.s_addr); - nat->nat_next = nat_instances; - nat_instances = nat; - hv = NAT_HASH_FN(nat->nat_inip.s_addr, ipf_nattable_sz); - natp = &nat_table[0][hv]; - nat->nat_hstart[0] = natp; - nat->nat_hnext[0] = *natp; - *natp = nat; - hv = NAT_HASH_FN(nat->nat_outip.s_addr, ipf_nattable_sz); - natp = &nat_table[1][hv]; - nat->nat_hstart[1] = natp; - nat->nat_hnext[1] = *natp; - *natp = nat; + +#ifdef _KERNEL + strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ); +#endif + nat_insert(nat); + nat->nat_dir = direction; nat->nat_ifp = fin->fin_ifp; nat->nat_ptr = np; nat->nat_p = ip->ip_p; nat->nat_bytes = 0; nat->nat_pkts = 0; - nat->nat_age = fr_defnatage; nat->nat_fr = fin->fin_fr; if (nat->nat_fr != NULL) { - ATOMIC_INC(nat->nat_fr->fr_ref); + ATOMIC_INC32(nat->nat_fr->fr_ref); } if (direction == NAT_OUTBOUND) { if (flags & IPN_TCPUDP) @@ -992,16 +1401,55 @@ int direction; if (flags & IPN_TCPUDP) tcp->th_dport = nport; } - nat_stats.ns_added++; - nat_stats.ns_inuse++; np->in_use++; return nat; +badnat: + nat_stats.ns_badnat++; + if ((hm = nat->nat_hm) != NULL) + nat_hostmapdel(hm); + KFREE(nat); + return NULL; +} + + +void nat_insert(nat) +nat_t *nat; +{ + nat_t **natp; + u_int hv; + + MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL); + + nat->nat_age = fr_defnatage; + nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0'; + if (nat->nat_ifname[0] !='\0') { + nat->nat_ifp = GETUNIT(nat->nat_ifname, 4); + } + + 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; + 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; + nat->nat_hnext[1] = *natp; + *natp = nat; + + nat_stats.ns_added++; + nat_stats.ns_inuse++; } -nat_t *nat_icmpinlookup(ip, fin) +nat_t *nat_icmplookup(ip, fin, dir) ip_t *ip; fr_info_t *fin; +int dir; { icmphdr_t *icmp; tcphdr_t *tcp = NULL; @@ -1034,12 +1482,21 @@ fr_info_t *fin; flags = IPN_UDP; if (flags & IPN_TCPUDP) { tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); - return nat_inlookup(fin->fin_ifp, flags, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, - (tcp->th_sport << 16) | tcp->th_dport); + if (dir == NAT_INBOUND) + return nat_inlookup(fin->fin_ifp, flags, + (u_int)oip->ip_p, oip->ip_dst, oip->ip_src, + (tcp->th_sport << 16) | tcp->th_dport); + else + return nat_outlookup(fin->fin_ifp, flags, + (u_int)oip->ip_p, oip->ip_dst, oip->ip_src, + (tcp->th_sport << 16) | tcp->th_dport); } - return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, oip->ip_dst, - oip->ip_src, 0); + if (dir == NAT_INBOUND) + return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, + oip->ip_dst, oip->ip_src, 0); + else + return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, + oip->ip_dst, oip->ip_src, 0); } @@ -1047,10 +1504,11 @@ fr_info_t *fin; * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP * packet gets correctly recognised. */ -nat_t *nat_icmpin(ip, fin, nflags) +nat_t *nat_icmp(ip, fin, nflags, dir) ip_t *ip; fr_info_t *fin; u_int *nflags; +int dir; { u_32_t sum1, sum2, sumd; struct in_addr in; @@ -1059,7 +1517,7 @@ u_int *nflags; ip_t *oip; int flags = 0; - if (!(nat = nat_icmpinlookup(ip, fin))) + if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) return NULL; *nflags = IPN_ICMPERR; icmp = (icmphdr_t *)fin->fin_dp; @@ -1077,6 +1535,7 @@ u_int *nflags; * to only modify the checksum once for the port # and twice * for the IP#. */ + if (nat->nat_dir == NAT_OUTBOUND) { sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); in = nat->nat_inip; @@ -1104,7 +1563,7 @@ u_int *nflags; sumd += (sumd & 0xffff); while (sumd > 0xffff) sumd = (sumd & 0xffff) + (sumd >> 16); - fix_incksum(&icmp->icmp_cksum, sumd, 0); +/* fix_incksum(&icmp->icmp_cksum, sumd, 0); */ } @@ -1162,7 +1621,7 @@ u_32_t ports; sport = ports & 0xffff; flags &= IPN_TCPUDP; - hv = NAT_HASH_FN(mapdst.s_addr, ipf_nattable_sz); + hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz); nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; @@ -1201,7 +1660,7 @@ u_32_t ports; dport = ports >> 16; flags &= IPN_TCPUDP; - hv = NAT_HASH_FN(src.s_addr, ipf_nattable_sz); + hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz); nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; @@ -1220,35 +1679,6 @@ u_32_t ports; /* - * check if an ip address has already been allocated for a given mapping that - * is not doing port based translation. - */ -nat_t *nat_maplookup(ifp, flags, src, dst) -void *ifp; -register u_int flags; -struct in_addr src , dst; -{ - register nat_t *nat; - register int oflags; - u_int hv; - - hv = NAT_HASH_FN(src.s_addr, ipf_nattable_sz); - nat = nat_table[0][hv]; - for (; nat; nat = nat->nat_hnext[0]) { - oflags = (flags & IPN_TCPUDP) & nat->nat_ptr->in_flags; - if (oflags != 0) - continue; - - if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_inip.s_addr == src.s_addr && - nat->nat_oip.s_addr == dst.s_addr) - return nat; - } - return NULL; -} - - -/* * Lookup the NAT tables to search for a matching redirect */ nat_t *nat_lookupredir(np) @@ -1271,6 +1701,41 @@ register natlookup_t *np; } +static int nat_match(fin, np, ip) +fr_info_t *fin; +ipnat_t *np; +ip_t *ip; +{ + frtuc_t *ft; + + if (ip->ip_v != 4) + return 0; + + if (np->in_p && ip->ip_p != np->in_p) + return 0; + if (fin->fin_out) { + if (!(np->in_redir && (NAT_MAP|NAT_MAPBLK))) + return 0; + if ((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) + return 0; + if ((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) + return 0; + } else { + if (!(np->in_redir && NAT_REDIRECT)) + return 0; + } + + ft = &np->in_tuc; + if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) { + if (ft->ftu_scmp || ft->ftu_dcmp) + return 0; + return 1; + } + + return fr_tcpudpchk(ft, fin); +} + + /* * Packets going out on the external interface go through this. * Here, the source address requires alteration, if anything. @@ -1282,16 +1747,16 @@ fr_info_t *fin; register ipnat_t *np = NULL; register u_32_t ipa; tcphdr_t *tcp = NULL; - u_short nflags = 0, sport = 0, dport = 0, *csump = NULL; + u_short sport = 0, dport = 0, *csump = NULL; struct ifnet *ifp; int natadd = 1; frentry_t *fr; - u_int hv, msk; + u_int nflags = 0, hv, msk; u_32_t iph; nat_t *nat; int i; - if (nat_list == NULL) + if (nat_list == NULL || (fr_nat_lock)) return 0; if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && @@ -1315,8 +1780,12 @@ fr_info_t *fin; ipa = ip->ip_src.s_addr; READ_ENTER(&ipf_nat); - if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && - (nat = ipfr_nat_knownfrag(ip, fin))) + + if ((ip->ip_p == IPPROTO_ICMP) && + (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) + ; + else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && + (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p, ip->ip_src, ip->ip_dst, (dport << 16) | sport))) { @@ -1344,15 +1813,21 @@ fr_info_t *fin; i = 32; maskloop: iph = ipa & htonl(msk); - hv = NAT_HASH_FN(iph, ipf_natrules_sz); + hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); for (np = nat_rules[hv]; np; np = np->in_mnext) { - if ((np->in_ifp == ifp) && np->in_space && - (!(np->in_flags & IPN_RF) || - (np->in_flags & nflags)) && - ((ipa & np->in_inmsk) == np->in_inip) && - ((np->in_redir & (NAT_MAP|NAT_MAPBLK)) || - (np->in_pnext == sport))) { + if ((np->in_ifp && (np->in_ifp != ifp)) || + !np->in_space) + continue; + if ((np->in_flags & IPN_RF) && + !(np->in_flags & nflags)) + continue; + if (np->in_flags & IPN_FILTER) { + if (!nat_match(fin, np, ip)) + continue; + } else if ((ipa & np->in_inmsk) != np->in_inip) + continue; + if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) { if (*np->in_plabel && !appr_ok(ip, tcp, np)) continue; /* @@ -1389,11 +1864,11 @@ maskloop: if (natadd && fin->fin_fi.fi_fl & FI_FRAG) ipfr_nat_newfrag(ip, fin, 0, nat); ip->ip_src = nat->nat_outip; - MUTEX_ENTER(&ipf_rw); + MUTEX_ENTER(&nat->nat_lock); nat->nat_age = fr_defnatage; nat->nat_bytes += ip->ip_len; nat->nat_pkts++; - MUTEX_EXIT(&ipf_rw); + MUTEX_EXIT(&nat->nat_lock); /* * Fix up checksums, not by recalculating them, but @@ -1416,14 +1891,14 @@ maskloop: if (ip->ip_p == IPPROTO_TCP) { csump = &tcp->th_sum; - MUTEX_ENTER(&ipf_rw); + MUTEX_ENTER(&nat->nat_lock); fr_tcp_age(&nat->nat_age, - nat->nat_tcpstate, ip, fin, 1); + nat->nat_tcpstate, fin, 1); if (nat->nat_age < fr_defnaticmpage) nat->nat_age = fr_defnaticmpage; #ifdef LARGE_NAT - else if (nat->nat_age > DEF_NAT_AGE) - nat->nat_age = DEF_NAT_AGE; + else if (nat->nat_age > fr_defnatage) + nat->nat_age = fr_defnatage; #endif /* * Increase this because we may have @@ -1433,12 +1908,14 @@ maskloop: */ if (nat->nat_age == fr_tcpclosed) nat->nat_age = fr_tcplastack; - MUTEX_EXIT(&ipf_rw); + MUTEX_EXIT(&nat->nat_lock); } else if (ip->ip_p == IPPROTO_UDP) { udphdr_t *udp = (udphdr_t *)tcp; if (udp->uh_sum) csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; } if (csump) { if (nat->nat_dir == NAT_OUTBOUND) @@ -1449,12 +1926,17 @@ maskloop: ip->ip_len); } } + if ((np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && dport == np->in_dport))) - (void) appr_check(ip, fin, nat); - ATOMIC_INC(nat_stats.ns_mapped[1]); + (tcp != NULL && dport == np->in_dport))) { + i = appr_check(ip, fin, nat); + if (i == 0) + i = 1; + } else + i = 1; + ATOMIC_INCL(nat_stats.ns_mapped[1]); RWLOCK_EXIT(&ipf_nat); /* READ */ - return 1; + return i; } RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ return 0; @@ -1480,7 +1962,7 @@ fr_info_t *fin; u_32_t iph; int i; - if (nat_list == NULL) + if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock)) return 0; if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { @@ -1501,7 +1983,8 @@ fr_info_t *fin; READ_ENTER(&ipf_nat); - if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmpin(ip, fin, &nflags))) + if ((ip->ip_p == IPPROTO_ICMP) && + (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) ; else if ((ip->ip_off & IP_OFFMASK) && (nat = ipfr_nat_knownfrag(ip, fin))) @@ -1529,15 +2012,21 @@ fr_info_t *fin; i = 32; maskloop: iph = in.s_addr & htonl(msk); - hv = NAT_HASH_FN(iph, ipf_rdrrules_sz); - for (np = rdr_rules[hv]; np; np = np->in_rnext) - if ((np->in_ifp == ifp) && - (!np->in_flags || (nflags & np->in_flags)) && - ((in.s_addr & np->in_outmsk) == np->in_outip) && - ((src.s_addr & np->in_srcmsk) == np->in_srcip) && - (np->in_redir & NAT_REDIRECT) && - (!np->in_pmin || np->in_pmin == dport) && - (!np->in_p || np->in_p == ip->ip_p)) { + hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz); + for (np = rdr_rules[hv]; np; np = np->in_rnext) { + if ((np->in_ifp && (np->in_ifp != ifp)) || + (np->in_p && (np->in_p != ip->ip_p)) || + (np->in_flags && !(nflags & np->in_flags))) + continue; + if (np->in_flags & IPN_FILTER) { + if (!nat_match(fin, np, ip)) + continue; + } else if ((in.s_addr & np->in_outmsk) != np->in_outip) + continue; + if ((np->in_redir & NAT_REDIRECT) && + (!np->in_pmin || + ((ntohs(np->in_pmax) >= ntohs(dport)) && + (ntohs(dport) >= ntohs(np->in_pmin))))) if ((nat = nat_new(np, ip, fin, nflags, NAT_INBOUND))) { np->in_hits++; @@ -1546,7 +2035,8 @@ maskloop: #endif break; } - } + } + if ((np == NULL) && (i > 0)) { do { i--; @@ -1563,18 +2053,23 @@ maskloop: if (natadd && fin->fin_fi.fi_fl & FI_FRAG) ipfr_nat_newfrag(ip, fin, 0, nat); if ((np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && sport == np->in_dport))) - (void) appr_check(ip, fin, nat); + (tcp != NULL && sport == np->in_dport))) { + i = appr_check(ip, fin, nat); + if (i == -1) { + RWLOCK_EXIT(&ipf_nat); + return i; + } + } - MUTEX_ENTER(&ipf_rw); + MUTEX_ENTER(&nat->nat_lock); if (nflags != IPN_ICMPERR) nat->nat_age = fr_defnatage; nat->nat_bytes += ip->ip_len; nat->nat_pkts++; - MUTEX_EXIT(&ipf_rw); + MUTEX_EXIT(&nat->nat_lock); ip->ip_dst = nat->nat_inip; - fin->fin_fi.fi_dst = nat->nat_inip; + fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; /* * Fix up checksums, not by recalculating them, but @@ -1596,14 +2091,14 @@ maskloop: if (ip->ip_p == IPPROTO_TCP) { csump = &tcp->th_sum; - MUTEX_ENTER(&ipf_rw); + MUTEX_ENTER(&nat->nat_lock); fr_tcp_age(&nat->nat_age, - nat->nat_tcpstate, ip, fin, 0); + nat->nat_tcpstate, fin, 0); if (nat->nat_age < fr_defnaticmpage) nat->nat_age = fr_defnaticmpage; #ifdef LARGE_NAT - else if (nat->nat_age > DEF_NAT_AGE) - nat->nat_age = DEF_NAT_AGE; + else if (nat->nat_age > fr_defnatage) + nat->nat_age = fr_defnatage; #endif /* * Increase this because we may have @@ -1613,21 +2108,26 @@ maskloop: */ if (nat->nat_age == fr_tcpclosed) nat->nat_age = fr_tcplastack; - MUTEX_EXIT(&ipf_rw); + MUTEX_EXIT(&nat->nat_lock); } else if (ip->ip_p == IPPROTO_UDP) { udphdr_t *udp = (udphdr_t *)tcp; if (udp->uh_sum) csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; } + if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, nat->nat_sumd[0], 0); + fix_incksum(csump, nat->nat_sumd[0], + 0); else - fix_outcksum(csump, nat->nat_sumd[0], 0); + fix_outcksum(csump, nat->nat_sumd[0], + 0); } } - ATOMIC_INC(nat_stats.ns_mapped[0]); + ATOMIC_INCL(nat_stats.ns_mapped[0]); RWLOCK_EXIT(&ipf_nat); /* READ */ return 1; } @@ -1662,6 +2162,10 @@ void ip_natunload() KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz); rdr_rules = NULL; } + if (maptable != NULL) { + KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + maptable = NULL; + } } @@ -1727,7 +2231,7 @@ void *ifp; * new one. */ sum1 = nat->nat_outip.s_addr; - if (fr_ifpaddr(ifp2, &in) != -1) + if (fr_ifpaddr(4, ifp2, &in) != -1) nat->nat_outip = in; sum2 = nat->nat_outip.s_addr; @@ -1748,7 +2252,7 @@ void *ifp; for (n = nat_list; (n != NULL); n = n->in_next) if (n->in_ifp == ifp) { - n->in_ifp = (void *)GETUNIT(n->in_ifname); + n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); if (!n->in_ifp) n->in_ifp = (void *)-1; } diff --git a/contrib/ipfilter/ip_nat.h b/contrib/ipfilter/ip_nat.h index c57b4e7..f1a339f 100644 --- a/contrib/ipfilter/ip_nat.h +++ b/contrib/ipfilter/ip_nat.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1995-1998 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.1.2.3 2000/01/24 12:44:24 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.1 2000/05/15 06:50:14 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -17,23 +17,15 @@ #endif #if defined(__STDC__) || defined(__GNUC__) -#define SIOCADNAT _IOW('r', 80, struct ipnat) -#define SIOCRMNAT _IOW('r', 81, struct ipnat) -#define SIOCGNATS _IOR('r', 82, struct natstat) -#define SIOCGNATL _IOWR('r', 83, struct natlookup) -#define SIOCGFRST _IOR('r', 84, struct ipfrstat) -#define SIOCGIPST _IOR('r', 85, struct ips_stat) -#define SIOCFLNAT _IOWR('r', 86, int) -#define SIOCCNATL _IOWR('r', 87, int) +#define SIOCADNAT _IOW('r', 60, struct ipnat *) +#define SIOCRMNAT _IOW('r', 61, struct ipnat *) +#define SIOCGNATS _IOWR('r', 62, struct natstat *) +#define SIOCGNATL _IOWR('r', 63, struct natlookup *) #else -#define SIOCADNAT _IOW(r, 80, struct ipnat) -#define SIOCRMNAT _IOW(r, 81, struct ipnat) -#define SIOCGNATS _IOR(r, 82, struct natstat) -#define SIOCGNATL _IOWR(r, 83, struct natlookup) -#define SIOCGFRST _IOR(r, 84, struct ipfrstat) -#define SIOCGIPST _IOR(r, 85, struct ips_stat) -#define SIOCFLNAT _IOWR(r, 86, int) -#define SIOCCNATL _IOWR(r, 87, int) +#define SIOCADNAT _IOW(r, 60, struct ipnat *) +#define SIOCRMNAT _IOW(r, 61, struct ipnat *) +#define SIOCGNATS _IOWR(r, 62, struct natstat *) +#define SIOCGNATL _IOWR(r, 63, struct natlookup *) #endif #undef LARGE_NAT /* define this if you're setting up a system to NAT @@ -45,14 +37,17 @@ */ #define NAT_SIZE 127 #define RDR_SIZE 127 +#define HOSTMAP_SIZE 127 #define NAT_TABLE_SZ 127 #ifdef LARGE_NAT #undef NAT_SIZE #undef RDR_SIZE #undef NAT_TABLE_SZ +#undef HOSTMAP_SIZE 127 #define NAT_SIZE 2047 #define RDR_SIZE 2047 #define NAT_TABLE_SZ 16383 +#define HOSTMAP_SIZE 8191 #endif #ifndef APR_LABELLEN #define APR_LABELLEN 16 @@ -61,14 +56,16 @@ #define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ +struct ap_session; + typedef struct nat { u_long nat_age; int nat_flags; u_32_t nat_sumd[2]; u_32_t nat_ipsumd; void *nat_data; - void *nat_aps; /* proxy session */ - frentry_t *nat_fr; /* filter rule ptr if appropriate */ + struct ap_session *nat_aps; /* proxy session */ + struct frentry *nat_fr; /* filter rule ptr if appropriate */ struct in_addr nat_inip; struct in_addr nat_outip; struct in_addr nat_oip; /* other ip */ @@ -81,17 +78,24 @@ typedef struct nat { u_char nat_tcpstate[2]; u_char nat_p; /* protocol for NAT */ struct ipnat *nat_ptr; /* pointer back to the rule */ + struct hostmap *nat_hm; struct nat *nat_next; struct nat *nat_hnext[2]; struct nat **nat_hstart[2]; void *nat_ifp; int nat_dir; + char nat_ifname[IFNAMSIZ]; +#if SOLARIS || defined(_sgi) + kmutex_t nat_lock; +#endif } nat_t; typedef struct ipnat { struct ipnat *in_next; struct ipnat *in_rnext; + struct ipnat **in_prnext; struct ipnat *in_mnext; + struct ipnat **in_pmnext; void *in_ifp; void *in_apr; u_long in_space; @@ -106,11 +110,11 @@ typedef struct ipnat { struct in_addr in_in[2]; struct in_addr in_out[2]; struct in_addr in_src[2]; + struct frtuc in_tuc; int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */ char in_ifname[IFNAMSIZ]; char in_plabel[APR_LABELLEN]; /* proxy label */ char in_p; /* protocol */ - u_short in_dport; } ipnat_t; #define in_pmin in_port[0] /* Also holds static redir port */ @@ -122,6 +126,12 @@ typedef struct ipnat { #define in_outmsk in_out[1].s_addr #define in_srcip in_src[0].s_addr #define in_srcmsk in_src[1].s_addr +#define in_scmp in_tuc.ftu_scmp +#define in_dcmp in_tuc.ftu_dcmp +#define in_stop in_tuc.ftu_stop +#define in_dtop in_tuc.ftu_dtop +#define in_sport in_tuc.ftu_sport +#define in_dport in_tuc.ftu_dport #define NAT_OUTBOUND 0 #define NAT_INBOUND 1 @@ -146,6 +156,34 @@ typedef struct natlookup { u_short nl_realport; } natlookup_t; + +typedef struct nat_save { + void *ipn_next; + struct nat ipn_nat; + struct ipnat ipn_ipnat; + struct frentry ipn_fr; + int ipn_dsize; + char ipn_data[4]; +} nat_save_t; + +#define ipn_rule ipn_nat.nat_fr + +typedef struct natget { + void *ng_ptr; + int ng_sz; +} natget_t; + + +typedef struct hostmap { + struct hostmap *hm_next; + struct hostmap **hm_pnext; + struct ipnat *hm_ipnat; + struct in_addr hm_realip; + struct in_addr hm_mapip; + int hm_ref; +} hostmap_t; + + typedef struct natstat { u_long ns_mapped[2]; u_long ns_rules; @@ -154,6 +192,8 @@ typedef struct natstat { u_long ns_inuse; u_long ns_logged; u_long ns_logfail; + u_long ns_memfail; + u_long ns_badnat; nat_t **ns_table[2]; ipnat_t *ns_list; void *ns_apslist; @@ -163,16 +203,20 @@ typedef struct natstat { nat_t *ns_instances; } natstat_t; -#define IPN_ANY 0x00 -#define IPN_TCP 0x01 -#define IPN_UDP 0x02 +#define IPN_ANY 0x000 +#define IPN_TCP 0x001 +#define IPN_UDP 0x002 #define IPN_TCPUDP (IPN_TCP|IPN_UDP) -#define IPN_DELETE 0x04 -#define IPN_ICMPERR 0x08 +#define IPN_DELETE 0x004 +#define IPN_ICMPERR 0x008 #define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) -#define IPN_AUTOPORTMAP 0x10 -#define IPN_RANGE 0x20 -#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_RANGE) +#define IPN_AUTOPORTMAP 0x010 +#define IPN_IPRANGE 0x020 +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|\ + IPN_SPLIT|IPN_ROUNDR|IPN_FILTER) +#define IPN_FILTER 0x040 +#define IPN_SPLIT 0x080 +#define IPN_ROUNDR 0x100 typedef struct natlog { @@ -194,7 +238,7 @@ typedef struct natlog { #define NL_NEWRDR NAT_REDIRECT #define NL_EXPIRE 0xffff -#define NAT_HASH_FN(k,m) (((k) + ((k) >> 12)) % (m)) +#define NAT_HASH_FN(k,l,m) (((k) + ((k) >> 12) + l) % (m)) #define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) @@ -213,6 +257,7 @@ typedef struct natlog { extern u_int ipf_nattable_sz; extern u_int ipf_natrules_sz; extern u_int ipf_rdrrules_sz; +extern int fr_nat_lock; extern void ip_natsync __P((void *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; @@ -221,7 +266,7 @@ extern nat_t *nat_instances; extern ipnat_t **nat_rules; extern ipnat_t **rdr_rules; extern natstat_t nat_stats; -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) extern int nat_ioctl __P((caddr_t, u_long, int)); #else extern int nat_ioctl __P((caddr_t, int, int)); @@ -235,8 +280,9 @@ extern nat_t *nat_inlookup __P((void *, u_int, u_int, struct in_addr, extern nat_t *nat_maplookup __P((void *, u_int, struct in_addr, struct in_addr)); extern nat_t *nat_lookupredir __P((natlookup_t *)); -extern nat_t *nat_icmpinlookup __P((ip_t *, fr_info_t *)); -extern nat_t *nat_icmpin __P((ip_t *, fr_info_t *, u_int *)); +extern nat_t *nat_icmplookup __P((ip_t *, fr_info_t *, int)); +extern nat_t *nat_icmp __P((ip_t *, fr_info_t *, u_int *, int)); +extern void nat_insert __P((nat_t *)); extern int ip_natout __P((ip_t *, fr_info_t *)); extern int ip_natin __P((ip_t *, fr_info_t *)); diff --git a/contrib/ipfilter/ip_proxy.c b/contrib/ipfilter/ip_proxy.c index ccf9c12..e1e55f1 100644 --- a/contrib/ipfilter/ip_proxy.c +++ b/contrib/ipfilter/ip_proxy.c @@ -1,12 +1,12 @@ /* - * Copyright (C) 1997-1998 by Darren Reed. + * Copyright (C) 1997-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.2.2.1 1999/09/19 12:18:19 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.1 2000/05/06 12:30:50 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -98,23 +98,62 @@ static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); ap_session_t *ap_sess_tab[AP_SESS_SIZE]; ap_session_t *ap_sess_list = NULL; +aproxy_t *ap_proxylist = NULL; aproxy_t ap_proxies[] = { #ifdef IPF_FTP_PROXY - { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, - ippr_ftp_in, ippr_ftp_out }, + { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + ippr_ftp_new, ippr_ftp_in, ippr_ftp_out }, #endif #ifdef IPF_RCMD_PROXY - { "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_new, - NULL, ippr_rcmd_out }, + { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, + ippr_rcmd_new, NULL, ippr_rcmd_out }, #endif #ifdef IPF_RAUDIO_PROXY - { "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, + { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL, ippr_raudio_new, ippr_raudio_in, ippr_raudio_out }, #endif - { "", '\0', 0, 0, NULL, NULL } + { NULL, "", '\0', 0, 0, NULL, NULL } }; +int appr_add(ap) +aproxy_t *ap; +{ + aproxy_t *a; + + for (a = ap_proxies; a->apr_p; a++) + if ((a->apr_p == ap->apr_p) && + !strncmp(a->apr_label, ap->apr_label, + sizeof(ap->apr_label))) + return -1; + + for (a = ap_proxylist; a->apr_p; a = a->apr_next) + if ((a->apr_p == ap->apr_p) && + !strncmp(a->apr_label, ap->apr_label, + sizeof(ap->apr_label))) + return -1; + ap->apr_next = ap_proxylist; + ap_proxylist = ap; + return (*ap->apr_init)(); +} + + +int appr_del(ap) +aproxy_t *ap; +{ + aproxy_t *a, **app; + + for (app = &ap_proxylist; (a = *app); app = &a->apr_next) + if (a == ap) { + if (ap->apr_ref != 0) + return 1; + *app = a->apr_next; + return 0; + } + return -1; +} + + int appr_ok(ip, tcp, nat) ip_t *ip; tcphdr_t *tcp; @@ -152,16 +191,18 @@ nat_t *nat; if (!aps) return NULL; bzero((char *)aps, sizeof(*aps)); - aps->aps_next = ap_sess_list; aps->aps_p = ip->ip_p; aps->aps_data = NULL; aps->aps_apr = apr; aps->aps_psiz = 0; - ap_sess_list = aps; - aps->aps_nat = nat; - nat->nat_aps = aps; if (apr->apr_new != NULL) - (void) (*apr->apr_new)(fin, ip, aps, nat); + if ((*apr->apr_new)(fin, ip, aps, nat) == -1) { + KFREE(aps); + return NULL; + } + aps->aps_nat = nat; + aps->aps_next = ap_sess_list; + ap_sess_list = aps; return aps; } @@ -179,6 +220,7 @@ nat_t *nat; aproxy_t *apr; tcphdr_t *tcp = NULL; u_32_t sum; + short rv; int err; if (nat->nat_aps == NULL) @@ -213,8 +255,12 @@ nat_t *nat; err = (*apr->apr_inpkt)(fin, ip, aps, nat); } + rv = APR_EXIT(err); + if (rv == -1) + return rv; + if (tcp != NULL) { - err = appr_fixseqack(fin, ip, aps, err); + err = appr_fixseqack(fin, ip, aps, APR_INC(err)); #if SOLARIS && defined(_KERNEL) tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); #else @@ -223,9 +269,9 @@ nat_t *nat; } aps->aps_bytes += ip->ip_len; aps->aps_pkts++; - return 2; + return 1; } - return -1; + return 0; } @@ -241,6 +287,13 @@ char *name; ap->apr_ref++; return ap; } + + for (ap = ap_proxylist; ap; ap = ap->apr_next) + if ((ap->apr_p == pr) && + !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { + ap->apr_ref++; + return ap; + } return NULL; } @@ -266,11 +319,9 @@ ap_session_t *aps; break; } - if (a) { - if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) - KFREES(aps->aps_data, aps->aps_psiz); - KFREE(aps); - } + if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) + KFREES(aps->aps_data, aps->aps_psiz); + KFREE(aps); } @@ -385,3 +436,16 @@ int appr_init() } return err; } + + +void appr_unload() +{ + aproxy_t *ap; + + for (ap = ap_proxies; ap->apr_p; ap++) + if (ap->apr_fini) + (*ap->apr_fini)(); + for (ap = ap_proxylist; ap; ap = ap->apr_next) + if (ap->apr_fini) + (*ap->apr_fini)(); +} diff --git a/contrib/ipfilter/ip_proxy.h b/contrib/ipfilter/ip_proxy.h index 08409b0..933d79d 100644 --- a/contrib/ipfilter/ip_proxy.h +++ b/contrib/ipfilter/ip_proxy.h @@ -1,11 +1,11 @@ /* - * Copyright (C) 1997-1998 by Darren Reed. + * Copyright (C) 1997-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_proxy.h,v 2.1.2.1 1999/09/19 12:18:20 darrenr Exp $ + * $Id: ip_proxy.h,v 2.8.2.3 2000/05/06 12:32:43 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -54,7 +54,7 @@ typedef struct ap_session { int aps_psiz; /* size of private data */ struct ap_session *aps_hnext; struct ap_session *aps_next; -} ap_session_t ; +} ap_session_t; #define aps_sport aps_un.apu_tcp.apt_sport #define aps_dport aps_un.apu_tcp.apt_dport @@ -67,11 +67,13 @@ typedef struct ap_session { typedef struct aproxy { + struct aproxy *apr_next; char apr_label[APR_LABELLEN]; /* Proxy label # */ u_char apr_p; /* protocol */ int apr_ref; /* +1 per rule referencing it */ int apr_flags; int (* apr_init) __P((void)); + void (* apr_fini) __P((void)); int (* apr_new) __P((fr_info_t *, ip_t *, ap_session_t *, struct nat *)); int (* apr_inpkt) __P((fr_info_t *, ip_t *, @@ -82,6 +84,26 @@ typedef struct aproxy { #define APR_DELETE 1 +#define APR_ERR(x) (((x) & 0xffff) << 16) +#define APR_EXIT(x) (((x) >> 16) & 0xffff) +#define APR_INC(x) ((x) & 0xffff) + +#define FTP_BUFSZ 160 +/* + * For the ftp proxy. + */ +typedef struct ftpside { + char *ftps_rptr; + char *ftps_wptr; + u_32_t ftps_seq; + int ftps_junk; + char ftps_buf[FTP_BUFSZ]; +} ftpside_t; + +typedef struct ftpinfo { + u_int ftp_passok; + ftpside_t ftp_side[2]; +} ftpinfo_t; /* * Real audio proxy structure and #defines @@ -118,8 +140,12 @@ typedef struct { extern ap_session_t *ap_sess_tab[AP_SESS_SIZE]; extern ap_session_t *ap_sess_list; extern aproxy_t ap_proxies[]; +extern int ippr_ftp_pasvonly; +extern int appr_add __P((aproxy_t *)); +extern int appr_del __P((aproxy_t *)); extern int appr_init __P((void)); +extern void appr_unload __P((void)); extern int appr_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); extern void appr_free __P((aproxy_t *)); extern void aps_free __P((ap_session_t *)); diff --git a/contrib/ipfilter/ip_raudio_pxy.c b/contrib/ipfilter/ip_raudio_pxy.c index 6ccf4e4..18ca474 100644 --- a/contrib/ipfilter/ip_raudio_pxy.c +++ b/contrib/ipfilter/ip_raudio_pxy.c @@ -1,3 +1,6 @@ +/* + * $Id: ip_raudio_pxy.c,v 1.7.2.1 2000/05/06 11:19:33 darrenr Exp $ + */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; #endif @@ -38,12 +41,13 @@ nat_t *nat; KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); - if (aps->aps_data != NULL) { - bzero(aps->aps_data, sizeof(raudio_t)); - rap = aps->aps_data; - aps->aps_psiz = sizeof(raudio_t); - rap->rap_mode = RAP_M_TCP; /* default is for TCP */ - } + if (aps->aps_data == NULL) + return -1; + + bzero(aps->aps_data, sizeof(raudio_t)); + rap = aps->aps_data; + aps->aps_psiz = sizeof(raudio_t); + rap->rap_mode = RAP_M_TCP; /* default is for TCP */ return 0; } @@ -168,8 +172,8 @@ nat_t *nat; raudio_t *rap = aps->aps_data; struct in_addr swa, swb; u_int a1, a2, a3, a4; + int off, dlen, slen; u_short sp, dp; - int off, dlen; fr_info_t fi; tcp_seq seq; nat_t *ipn; @@ -258,9 +262,12 @@ nat_t *nat; bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_off = 5; fi.fin_dp = (char *)tcp2; fi.fin_fr = &raudiofr; tcp2->th_win = htons(8192); + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp); if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) && (rap->rap_srport != 0)) { @@ -271,8 +278,7 @@ nat_t *nat; fi.fin_data[0] = dp; fi.fin_data[1] = sp; ipn = nat_new(nat->nat_ptr, ip, &fi, - IPN_UDP | (sp ? 0 : FI_W_SPORT), - NAT_OUTBOUND); + IPN_UDP | (sp ? 0 : FI_W_SPORT), NAT_OUTBOUND); if (ipn != NULL) { ipn->nat_age = fr_defnatage; (void) fr_addstate(ip, &fi, sp ? 0 : FI_W_SPORT); @@ -292,8 +298,9 @@ nat_t *nat; (void) fr_addstate(ip, &fi, FI_W_DPORT); } } - + ip->ip_p = swp; + ip->ip_len = slen; ip->ip_src = swa; ip->ip_dst = swb; return 0; diff --git a/contrib/ipfilter/ip_rcmd_pxy.c b/contrib/ipfilter/ip_rcmd_pxy.c index 2b67ee5..daea94f 100644 --- a/contrib/ipfilter/ip_rcmd_pxy.c +++ b/contrib/ipfilter/ip_rcmd_pxy.c @@ -1,4 +1,7 @@ /* + * $Id: ip_rcmd_pxy.c,v 1.4.2.1 2000/05/06 11:19:34 darrenr Exp $ + */ +/* * Simple RCMD transparent proxy for in-kernel use. For use with the NAT * code. */ @@ -123,11 +126,16 @@ nat_t *nat; ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, ip->ip_dst, (dp << 16) | sp); if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp); bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = sp; tcp2->th_dport = 0; /* XXX - don't specify remote port */ + tcp2->th_off = 5; fi.fin_data[0] = ntohs(sp); fi.fin_data[1] = 0; fi.fin_dp = (char *)tcp2; @@ -140,6 +148,7 @@ nat_t *nat; fi.fin_fr = &rcmdfr; (void) fr_addstate(ip, &fi, FI_W_DPORT); } + ip->ip_len = slen; ip->ip_src = swip; } return 0; diff --git a/contrib/ipfilter/ip_sfil.c b/contrib/ipfilter/ip_sfil.c index b08525d5..40766e0 100644 --- a/contrib/ipfilter/ip_sfil.c +++ b/contrib/ipfilter/ip_sfil.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -8,8 +8,8 @@ * I hate legaleese, don't you ? */ #if !defined(lint) -static const char sccsid[] = "%W% %G% (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_sfil.c,v 2.1.2.6 2000/01/16 10:12:44 darrenr Exp $"; +static const char sccsid[] = "%W% %G% (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_sfil.c,v 2.23.2.2 2000/05/22 10:26:14 darrenr Exp $"; #endif #include <sys/types.h> @@ -42,6 +42,9 @@ static const char rcsid[] = "@(#)$Id: ip_sfil.c,v 2.1.2.6 2000/01/16 10:12:44 da #include <netinet/tcpip.h> #include <netinet/ip_icmp.h> #include "ip_compat.h" +#ifdef USE_INET6 +# include <netinet/icmp6.h> +#endif #include "ip_fil.h" #include "ip_state.h" #include "ip_nat.h" @@ -58,10 +61,10 @@ extern fr_flags, fr_active; int fr_running = 0; int ipl_unreach = ICMP_UNREACH_HOST; u_long ipl_frouteok[2] = {0, 0}; -static void frzerostats __P((caddr_t)); +static int frzerostats __P((caddr_t)); static int frrequest __P((minor_t, int, caddr_t, int)); -kmutex_t ipl_mutex, ipf_authmx, ipf_rw; +kmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_hostmap; KRWLOCK_T ipf_mutex, ipfs_mutex, ipf_solaris; KRWLOCK_T ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; kcondvar_t iplwait, ipfauthwait; @@ -85,6 +88,7 @@ int ipldetach() ip_natunload(); cv_destroy(&iplwait); cv_destroy(&ipfauthwait); + mutex_destroy(&ipf_hostmap); mutex_destroy(&ipf_authmx); mutex_destroy(&ipl_mutex); mutex_destroy(&ipf_rw); @@ -108,9 +112,10 @@ int iplattach __P((void)) cmn_err(CE_CONT, "iplattach()\n"); #endif bzero((char *)frcache, sizeof(frcache)); - mutex_init(&ipl_mutex, "ipf log mutex", MUTEX_DRIVER, NULL); mutex_init(&ipf_rw, "ipf rw mutex", MUTEX_DRIVER, NULL); + mutex_init(&ipl_mutex, "ipf log mutex", MUTEX_DRIVER, NULL); mutex_init(&ipf_authmx, "ipf auth log mutex", MUTEX_DRIVER, NULL); + mutex_init(&ipf_hostmap, "ipf hostmap mutex", MUTEX_DRIVER, NULL); RWLOCK_INIT(&ipf_solaris, "ipf filter load/unload mutex", NULL); RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock", NULL); RWLOCK_INIT(&ipfs_mutex, "ipf solaris mutex", NULL); @@ -134,26 +139,20 @@ int iplattach __P((void)) } -static void frzerostats(data) +static int frzerostats(data) caddr_t data; { friostat_t fio; + int error; + + fr_getstat(&fio); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (error) + return EFAULT; - bcopy((char *)frstats, (char *)fio.f_st, - sizeof(struct filterstats) * 2); - fio.f_fin[0] = ipfilter[0][0]; - fio.f_fin[1] = ipfilter[0][1]; - fio.f_fout[0] = ipfilter[1][0]; - fio.f_fout[1] = ipfilter[1][1]; - fio.f_acctin[0] = ipacct[0][0]; - fio.f_acctin[1] = ipacct[0][1]; - fio.f_acctout[0] = ipacct[1][0]; - fio.f_acctout[1] = ipacct[1][1]; - fio.f_active = fr_active; - fio.f_froute[0] = ipl_frouteok[0]; - fio.f_froute[1] = ipl_frouteok[1]; - IWCOPY((caddr_t)&fio, data, sizeof(fio)); bzero((char *)frstats, sizeof(*frstats) * 2); + + return 0; } @@ -197,6 +196,11 @@ int *rp; RWLOCK_EXIT(&ipf_solaris); return error; } + if (unit == IPL_LOGAUTH) { + error = fr_auth_ioctl((caddr_t)data, cmd, NULL, NULL); + RWLOCK_EXIT(&ipf_solaris); + return error; + } switch (cmd) { case SIOCFRENB : @@ -206,7 +210,8 @@ int *rp; if (!(mode & FWRITE)) error = EPERM; else - IRCOPY((caddr_t)data, (caddr_t)&enable, sizeof(enable)); + error = IRCOPY((caddr_t)data, (caddr_t)&enable, + sizeof(enable)); break; } case SIOCSETFF : @@ -214,13 +219,14 @@ int *rp; error = EPERM; else { WRITE_ENTER(&ipf_mutex); - IRCOPY((caddr_t)data, (caddr_t)&fr_flags, + error = IRCOPY((caddr_t)data, (caddr_t)&fr_flags, sizeof(fr_flags)); RWLOCK_EXIT(&ipf_mutex); } break; case SIOCGETFF : - IWCOPY((caddr_t)&fr_flags, (caddr_t)data, sizeof(fr_flags)); + error = IWCOPY((caddr_t)&fr_flags, (caddr_t)data, + sizeof(fr_flags)); break; case SIOCINAFR : case SIOCRMAFR : @@ -246,71 +252,61 @@ int *rp; else { WRITE_ENTER(&ipf_mutex); bzero((char *)frcache, sizeof(frcache[0]) * 2); - IWCOPY((caddr_t)&fr_active, (caddr_t)data, - sizeof(fr_active)); + error = IWCOPY((caddr_t)&fr_active, (caddr_t)data, + sizeof(fr_active)); fr_active = 1 - fr_active; RWLOCK_EXIT(&ipf_mutex); } break; case SIOCGETFS : { - struct friostat fio; + friostat_t fio; READ_ENTER(&ipf_mutex); - bcopy((char *)frstats, (char *)fio.f_st, - sizeof(struct filterstats) * 2); - fio.f_fin[0] = ipfilter[0][0]; - fio.f_fin[1] = ipfilter[0][1]; - fio.f_fout[0] = ipfilter[1][0]; - fio.f_fout[1] = ipfilter[1][1]; - fio.f_acctin[0] = ipacct[0][0]; - fio.f_acctin[1] = ipacct[0][1]; - fio.f_acctout[0] = ipacct[1][0]; - fio.f_acctout[1] = ipacct[1][1]; - fio.f_active = fr_active; - fio.f_froute[0] = ipl_frouteok[0]; - fio.f_froute[1] = ipl_frouteok[1]; - fio.f_running = fr_running; - fio.f_groups[0][0] = ipfgroups[0][0]; - fio.f_groups[0][1] = ipfgroups[0][1]; - fio.f_groups[1][0] = ipfgroups[1][0]; - fio.f_groups[1][1] = ipfgroups[1][1]; - fio.f_groups[2][0] = ipfgroups[2][0]; - fio.f_groups[2][1] = ipfgroups[2][1]; -#ifdef IPFILTER_LOG - fio.f_logging = 1; -#else - fio.f_logging = 0; -#endif - fio.f_defpass = fr_pass; - strncpy(fio.f_version, fio.f_version, - sizeof(fio.f_version)); + fr_getstat(&fio); RWLOCK_EXIT(&ipf_mutex); - IWCOPY((caddr_t)&fio, (caddr_t)data, sizeof(fio)); + error = IWCOPYPTR((caddr_t)&fio, (caddr_t)data, sizeof(fio)); + if (error) + error = EFAULT; break; } case SIOCFRZST : if (!(mode & FWRITE)) error = EPERM; else - frzerostats((caddr_t)data); + error = frzerostats((caddr_t)data); break; case SIOCIPFFL : if (!(mode & FWRITE)) error = EPERM; else { - IRCOPY((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); - tmp = frflush(unit, tmp); - IWCOPY((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); + error = IRCOPY((caddr_t)data, (caddr_t)&tmp, + sizeof(tmp)); + if (!error) { + tmp = frflush(unit, tmp); + error = IWCOPY((caddr_t)&tmp, (caddr_t)data, + sizeof(tmp)); + } } break; + case SIOCSTLCK : + error = IRCOPY((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + fr_state_lock = tmp; + fr_nat_lock = tmp; + fr_frag_lock = tmp; + fr_auth_lock = tmp; + } else + error = EFAULT; + break; #ifdef IPFILTER_LOG case SIOCIPFFB : if (!(mode & FWRITE)) error = EPERM; else { tmp = ipflog_clear(unit); - IWCOPY((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); + error = IWCOPY((caddr_t)&tmp, (caddr_t)data, + sizeof(tmp)); } break; #endif /* IPFILTER_LOG */ @@ -321,27 +317,20 @@ int *rp; error = ipfsync(); break; case SIOCGFRST : - IWCOPY((caddr_t)ipfr_fragstats(), (caddr_t)data, - sizeof(ipfrstat_t)); + error = IWCOPYPTR((caddr_t)ipfr_fragstats(), (caddr_t)data, + sizeof(ipfrstat_t)); + if (error) + error = EFAULT; break; case FIONREAD : { #ifdef IPFILTER_LOG int copy = (int)iplused[IPL_LOGIPF]; - IWCOPY((caddr_t)©, (caddr_t)data, sizeof(copy)); + error = IWCOPY((caddr_t)©, (caddr_t)data, sizeof(copy)); #endif break; } - case SIOCAUTHW : - case SIOCAUTHR : - if (!(mode & FWRITE)) { - error = EPERM; - break; - } - case SIOCATHST : - error = fr_auth_ioctl((caddr_t)data, cmd, NULL, NULL); - break; default : error = EINVAL; break; @@ -351,14 +340,22 @@ int *rp; } -ill_t *get_unit(name) +ill_t *get_unit(name, v) char *name; +int v; { - size_t len = strlen(name) + 1; /* includes \0 */ - ill_t *il; - + size_t len = strlen(name) + 1; /* includes \0 */ + ill_t *il; + int sap; + + if (v == 4) + sap = 0x0800; + else if (v == 6) + sap = 0x86dd; + else + return NULL; for (il = ill_g_head; il; il = il->ill_next) - if ((len == il->ill_name_length) && + if ((len == il->ill_name_length) && (il->ill_sap == sap) && !strncmp(il->ill_name, name, len)) return il; return NULL; @@ -375,15 +372,28 @@ caddr_t data; frentry_t fr; frdest_t *fdp; frgroup_t *fg = NULL; + u_int *p, *pp; int error = 0, in; - u_int group; + u_32_t group; ill_t *ill; ipif_t *ipif; ire_t *ire; fp = &fr; - IRCOPY(data, (caddr_t)fp, sizeof(*fp)); + error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); + if (error) + return EFAULT; fp->fr_ref = 0; +#if SOLARIS2 >= 8 + if (fp->fr_v == 4) + fp->fr_sap = IP_DL_SAP; + else if (fp->fr_v == 6) + fp->fr_sap = IP6_DL_SAP; + else + return EINVAL; +#else + fp->fr_sap = 0; +#endif WRITE_ENTER(&ipf_mutex); /* @@ -391,12 +401,12 @@ caddr_t data; * has been specified, doesn't exist. */ if ((req != SIOCZRLST) && fp->fr_grhead && - fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL)) { + fr_findgroup(fp->fr_grhead, fp->fr_flags, unit, set, NULL)) { error = EEXIST; goto out; } if ((req != SIOCZRLST) && fp->fr_group && - !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL)) { + !fr_findgroup(fp->fr_group, fp->fr_flags, unit, set, NULL)) { error = ESRCH; goto out; } @@ -405,10 +415,16 @@ caddr_t data; if (unit == IPL_LOGAUTH) ftail = fprev = &ipauth; - else if (fp->fr_flags & FR_ACCOUNT) + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4)) ftail = fprev = &ipacct[in][set]; - else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE)) + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4)) ftail = fprev = &ipfilter[in][set]; +#ifdef USE_INET6 + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6)) + ftail = fprev = &ipacct6[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6)) + ftail = fprev = &ipfilter6[in][set]; +#endif else { error = ESRCH; goto out; @@ -427,7 +443,8 @@ caddr_t data; bzero((char *)frcache, sizeof(frcache[0]) * 2); if (*fp->fr_ifname) { - fp->fr_ifa = (void *)get_unit((char *)fp->fr_ifname); + fp->fr_ifa = (void *)get_unit((char *)fp->fr_ifname, + (int)fp->fr_v); if (!fp->fr_ifa) fp->fr_ifa = (struct ifnet *)-1; } @@ -435,10 +452,10 @@ caddr_t data; fdp = &fp->fr_dif; fp->fr_flags &= ~FR_DUP; if (*fdp->fd_ifname) { - ill = get_unit(fdp->fd_ifname); + ill = get_unit(fdp->fd_ifname, (int)fp->fr_v); if (!ill) ire = (ire_t *)-1; - else if ((ipif = ill->ill_ipif)) { + else if ((ipif = ill->ill_ipif) && (fp->fr_v == 4)) { #if SOLARIS2 > 5 ire = ire_ctable_lookup(ipif->ipif_local_addr, 0, IRE_LOCAL, NULL, NULL, @@ -451,15 +468,26 @@ caddr_t data; else fp->fr_flags |= FR_DUP; } +#ifdef USE_INET6 + else if ((ipif = ill->ill_ipif) && (fp->fr_v == 6)) { + ire = ire_ctable_lookup_v6(&ipif->ipif_v6lcl_addr, 0, + IRE_LOCAL, NULL, NULL, + MATCH_IRE_TYPE); + if (!ire) + ire = (ire_t *)-1; + else + fp->fr_flags |= FR_DUP; + } +#endif fdp->fd_ifp = (struct ifnet *)ire; } fdp = &fp->fr_tif; if (*fdp->fd_ifname) { - ill = get_unit(fdp->fd_ifname); + ill = get_unit(fdp->fd_ifname, (int)fp->fr_v); if (!ill) ire = (ire_t *)-1; - else if ((ipif = ill->ill_ipif)) { + else if ((ipif = ill->ill_ipif) && (fp->fr_v == 4)) { #if SOLARIS2 > 5 ire = ire_ctable_lookup(ipif->ipif_local_addr, 0, IRE_LOCAL, NULL, NULL, @@ -470,6 +498,15 @@ caddr_t data; if (!ire) ire = (ire_t *)-1; } +#ifdef USE_INET6 + else if ((ipif = ill->ill_ipif) && (fp->fr_v == 6)) { + ire = ire_ctable_lookup_v6(&ipif->ipif_v6lcl_addr, 0, + IRE_LOCAL, NULL, NULL, + MATCH_IRE_TYPE); + if (!ire) + ire = (ire_t *)-1; + } +#endif fdp->fd_ifp = (struct ifnet *)ire; } @@ -477,9 +514,13 @@ caddr_t data; * Look for a matching filter rule, but don't include the next or * interface pointer in the comparison (fr_next, fr_ifa). */ + for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum; + p != pp; p++) + fp->fr_cksum += *p; + for (; (f = *ftail); ftail = &f->fr_next) - if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, - FR_CMPSIZ) == 0) + if ((fp->fr_cksum == f->fr_cksum) && + !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ)) break; /* @@ -491,7 +532,11 @@ caddr_t data; goto out; } MUTEX_DOWNGRADE(&ipf_mutex); - IWCOPY((caddr_t)f, data, sizeof(*f)); + error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); + if (error) { + error = EFAULT; + goto out; + } f->fr_hits = 0; f->fr_bytes = 0; goto out; @@ -511,26 +556,33 @@ caddr_t data; } } - if (req == SIOCDELFR || req == SIOCRMIFR) { + if (req == SIOCRMAFR || req == SIOCRMIFR) { if (!f) error = ESRCH; else { - if (f->fr_ref > 1) { + /* + * Only return EBUSY if there is a group list, else + * it's probably just state information referencing + * the rule. + */ + if ((f->fr_ref > 1) && f->fr_grp) { error = EBUSY; goto out; } if (fg && fg->fg_head) fg->fg_head->fr_ref--; if (unit == IPL_LOGAUTH) { - error = fr_auth_ioctl(data, req, f, ftail); + error = fr_auth_ioctl(data, req, fp, ftail); goto out; } if (f->fr_grhead) - fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, + fr_delgroup(f->fr_grhead, fp->fr_flags, unit, set); fixskip(fprev, f, -1); *ftail = f->fr_next; - KFREE(f); + f->fr_next = NULL; + if (f->fr_ref == 0) + KFREE(f); } } else { if (f) { @@ -623,14 +675,16 @@ cred_t *cp; * send_reset - this could conceivably be a call to tcp_respond(), but that * requires a large amount of setting up and isn't any more efficient. */ -int send_reset(fin, iphdr, qif) +int send_reset(oip, fin) +ip_t *oip; fr_info_t *fin; -ip_t *iphdr; -qif_t *qif; { tcphdr_t *tcp, *tcp2; - int tlen = 0; + int tlen = 0, hlen; mblk_t *m; +#ifdef USE_INET6 + ip6_t *ip6, *oip6 = (ip6_t *)oip; +#endif ip_t *ip; tcp = (struct tcphdr *)fin->fin_dp; @@ -638,105 +692,212 @@ qif_t *qif; return -1; if (tcp->th_flags & TH_SYN) tlen = 1; - if ((m = (mblk_t *)allocb(sizeof(*ip) + sizeof(*tcp),BPRI_HI)) == NULL) +#ifdef USE_INET6 + if (fin->fin_v == 6) + hlen = sizeof(ip6_t); + else +#endif + hlen = sizeof(ip_t); + hlen += sizeof(*tcp2); + if ((m = (mblk_t *)allocb(hlen + 16, BPRI_HI)) == NULL) return -1; + m->b_rptr += 16; MTYPE(m) = M_DATA; - m->b_wptr += sizeof(*ip) + sizeof(*tcp); - bzero((char *)m->b_rptr, sizeof(*ip) + sizeof(*tcp)); - ip = (ip_t *)m->b_rptr; - tcp2 = (struct tcphdr *)(m->b_rptr + sizeof(*ip)); - - ip->ip_src.s_addr = iphdr->ip_dst.s_addr; - ip->ip_dst.s_addr = iphdr->ip_src.s_addr; + m->b_wptr = m->b_rptr + hlen; + bzero((char *)m->b_rptr, hlen); + 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; tcp2->th_off = sizeof(struct tcphdr) >> 2; tcp2->th_flags = TH_RST|TH_ACK; + /* * This is to get around a bug in the Solaris 2.4/2.5 TCP checksum * computation that is done by their put routine. */ tcp2->th_sum = htons(0x14); - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; - ip->ip_p = IPPROTO_TCP; - ip->ip_len = htons(sizeof(*ip) + sizeof(*tcp)); - ip->ip_tos = iphdr->ip_tos; - ip->ip_off = 0; - ip->ip_ttl = 60; - ip->ip_sum = 0; +#ifdef USE_INET6 + if (fin->fin_v == 6) { + ip6 = (ip6_t *)m->b_rptr; + ip6->ip6_src = oip6->ip6_dst; + ip6->ip6_dst = oip6->ip6_src; + ip6->ip6_plen = htons(sizeof(*tcp)); + ip6->ip6_nxt = IPPROTO_TCP; + } else +#endif + { + ip = (ip_t *)m->b_rptr; + ip->ip_src.s_addr = oip->ip_dst.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + ip->ip_hl = sizeof(*ip) >> 2; + ip->ip_p = IPPROTO_TCP; + ip->ip_len = htons(sizeof(*ip) + sizeof(*tcp)); + ip->ip_tos = oip->ip_tos; + } + return send_ip(fin, m); +} + + +int send_ip(fin, m) +fr_info_t *fin; +mblk_t *m; +{ RWLOCK_EXIT(&ipfs_mutex); RWLOCK_EXIT(&ipf_solaris); - ip_wput(qif->qf_ill->ill_wq, m); +#ifdef USE_INET6 + if (fin->fin_v == 6) { + ip6_t *ip6; + + ip6 = (ip6_t *)m->b_rptr; + ip6->ip6_flow = 0; + ip6->ip6_vfc = 0x60; + ip6->ip6_hlim = 127; + ip_wput_v6(((qif_t *)fin->fin_qif)->qf_ill->ill_wq, m); + } else +#endif + { + ip_t *ip; + + ip = (ip_t *)m->b_rptr; + ip->ip_v = IPVERSION; + ip->ip_ttl = 60; + ip_wput(((qif_t *)fin->fin_qif)->qf_ill->ill_wq, m); + } READ_ENTER(&ipf_solaris); READ_ENTER(&ipfs_mutex); return 0; } -int icmp_error(ip, type, code, qif, dst) -ip_t *ip; -int type, code; -qif_t *qif; -struct in_addr dst; +int send_icmp_err(oip, type, fin, dst) +ip_t *oip; +int type; +fr_info_t *fin; +int dst; { - mblk_t *mb; + struct in_addr dst4; struct icmp *icmp; - ip_t *nip; - u_short sz = sizeof(*nip) + sizeof(*icmp) + 8; + mblk_t *m, *mb; + int hlen, code; + qif_t *qif; + u_short sz; +#ifdef USE_INET6 + ip6_t *ip6, *oip6; +#endif + ip_t *ip; - if ((mb = (mblk_t *)allocb((size_t)sz, BPRI_HI)) == NULL) + if ((type < 0) || (type > ICMP_MAXTYPE)) return -1; - MTYPE(mb) = M_DATA; - mb->b_wptr += sz; - bzero((char *)mb->b_rptr, (size_t)sz); - nip = (ip_t *)mb->b_rptr; - icmp = (struct icmp *)(nip + 1); - - nip->ip_v = IPVERSION; - nip->ip_hl = (sizeof(*nip) >> 2); - nip->ip_p = IPPROTO_ICMP; - nip->ip_id = ip->ip_id; - nip->ip_sum = 0; - nip->ip_ttl = 60; - nip->ip_tos = ip->ip_tos; - nip->ip_len = (u_short)htons(sz); - if (dst.s_addr == 0) { - if (fr_ifpaddr(qif->qf_ill, &dst) == -1) - return -1; + + code = fin->fin_icode; +#ifdef USE_INET6 + if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) + return -1; +#endif + + qif = fin->fin_qif; + m = fin->fin_qfm; + +#ifdef USE_INET6 + if (oip->ip_v == 6) { + oip6 = (ip6_t *)oip; + sz = sizeof(ip6_t); + sz += MIN(m->b_wptr - m->b_rptr, 512); + hlen = sizeof(ip6_t); + type = icmptoicmp6types[type]; + if (type == ICMP6_DST_UNREACH) + code = icmptoicmp6unreach[code]; + } else +#endif + { + if ((oip->ip_p == IPPROTO_ICMP) && + !(fin->fin_fi.fi_fl & FI_SHORT)) + switch (ntohs(fin->fin_data[0]) >> 8) + { + case ICMP_ECHO : + case ICMP_TSTAMP : + case ICMP_IREQ : + case ICMP_MASKREQ : + break; + default : + return 0; + } + + sz = sizeof(ip_t) * 2; + sz += 8; /* 64 bits of data */ + hlen = sz; } - nip->ip_src = dst; - nip->ip_dst = ip->ip_src; + sz += offsetof(struct icmp, icmp_ip); + if ((mb = (mblk_t *)allocb((size_t)sz + 16, BPRI_HI)) == NULL) + return -1; + MTYPE(mb) = M_DATA; + mb->b_rptr += 16; + mb->b_wptr = mb->b_rptr + sz; + bzero((char *)mb->b_rptr, (size_t)sz); + icmp = (struct icmp *)(mb->b_rptr + sizeof(*ip)); icmp->icmp_type = type; icmp->icmp_code = code; icmp->icmp_cksum = 0; - bcopy((char *)ip, (char *)&icmp->icmp_ip, sizeof(*ip)); - bcopy((char *)ip + (ip->ip_hl << 2), - (char *)&icmp->icmp_ip + sizeof(*ip), 8); /* 64 bits */ -#ifndef sparc - ip = &icmp->icmp_ip; - { - u_short __iplen, __ipoff; - __iplen = ip->ip_len; - __ipoff = ip->ip_len; - ip->ip_len = htons(__iplen); - ip->ip_off = htons(__ipoff); - } +#ifdef USE_INET6 + if (oip->ip_v == 6) { + struct in6_addr dst6; + int csz; + + if (dst == 0) { + if (fr_ifpaddr(6, ((qif_t *)fin->fin_qif)->qf_ill, + (struct in_addr *)&dst6) == -1) + return -1; + } else + dst6 = oip6->ip6_dst; + + csz = sz; + sz -= sizeof(ip6_t); + ip6 = (ip6_t *)mb->b_rptr; + ip6->ip6_flow = 0; + ip6->ip6_vfc = 0x60; + ip6->ip6_hlim = 127; + ip6->ip6_plen = htons(sz); + ip6->ip6_nxt = IPPROTO_ICMPV6; + ip6->ip6_src = dst6; + ip6->ip6_dst = oip6->ip6_src; + sz -= offsetof(struct icmp, icmp_ip); + bcopy((char *)m->b_rptr, (char *)&icmp->icmp_ip, sz); + icmp->icmp_cksum = csz - sizeof(ip6_t); + } else #endif - icmp->icmp_cksum = ipf_cksum((u_short *)icmp, sizeof(*icmp) + 8); + { + ip = (ip_t *)mb->b_rptr; + ip->ip_v = IPVERSION; + ip->ip_hl = (sizeof(*ip) >> 2); + ip->ip_p = IPPROTO_ICMP; + ip->ip_id = oip->ip_id; + ip->ip_sum = 0; + ip->ip_ttl = 60; + ip->ip_tos = oip->ip_tos; + ip->ip_len = (u_short)htons(sz); + if (dst == 0) { + if (fr_ifpaddr(4, ((qif_t *)fin->fin_qif)->qf_ill, + &dst4) == -1) + return -1; + } else + dst4 = oip->ip_dst; + ip->ip_src = dst4; + ip->ip_dst = oip->ip_src; + bcopy((char *)oip, (char *)&icmp->icmp_ip, sizeof(*oip)); + bcopy((char *)oip + (oip->ip_hl << 2), + (char *)&icmp->icmp_ip + sizeof(*oip), 8); + icmp->icmp_cksum = ipf_cksum((u_short *)icmp, + sizeof(*icmp) + 8); + } + /* * Need to exit out of these so we don't recursively call rw_enter * from fr_qout. */ - RWLOCK_EXIT(&ipfs_mutex); - RWLOCK_EXIT(&ipf_solaris); - ip_wput(qif->qf_ill->ill_wq, mb); - READ_ENTER(&ipf_solaris); - READ_ENTER(&ipfs_mutex); - return 0; + return send_ip(fin, mb); } diff --git a/contrib/ipfilter/ip_state.c b/contrib/ipfilter/ip_state.c index ad05e10..c9a28af 100644 --- a/contrib/ipfilter/ip_state.c +++ b/contrib/ipfilter/ip_state.c @@ -1,13 +1,13 @@ /* - * Copyright (C) 1995-1998 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.18 2000/01/27 08:51:30 darrenr Exp $"; +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.9 2000/05/22 10:26:15 darrenr Exp $"; #endif #include <sys/errno.h> @@ -18,6 +18,10 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.18 2000/01/27 08:51:30 defined(_KERNEL) # include "opt_ipfilter_log.h" #endif +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif #if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) # include <stdio.h> # include <stdlib.h> @@ -28,7 +32,7 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.18 2000/01/27 08:51:30 # include <linux/module.h> # endif #endif -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> # if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) @@ -43,7 +47,7 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.18 2000/01/27 08:51:30 # include <sys/protosw.h> #endif #include <sys/socket.h> -#if defined(_KERNEL) && !defined(linux) +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) # include <sys/systm.h> #endif #if !defined(__SVR4) && !defined(__svr4__) @@ -82,6 +86,9 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.18 2000/01/27 08:51:30 #include "netinet/ip_frag.h" #include "netinet/ip_proxy.h" #include "netinet/ip_state.h" +#ifdef USE_INET6 +#include <netinet/icmp6.h> +#endif #if (__FreeBSD_version >= 300000) # include <sys/malloc.h> # if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) @@ -96,20 +103,29 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.3.2.18 2000/01/27 08:51:30 #define TCP_CLOSE (TH_FIN|TH_RST) -ipstate_t **ips_table = NULL; -int ips_num = 0; -ips_stat_t ips_stats; +static ipstate_t **ips_table = NULL; +static ipstate_t *ips_list = NULL; +static int ips_num = 0; +static ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern KRWLOCK_T ipf_state, ipf_mutex; extern kmutex_t ipf_rw; #endif -static int fr_matchsrcdst __P((ipstate_t *, struct in_addr, struct in_addr, +#ifdef USE_INET6 +static frentry_t *fr_checkicmp6matchingstate __P((ip6_t *, fr_info_t *)); +#endif +static int fr_matchsrcdst __P((ipstate_t *, union i6addr, union i6addr, fr_info_t *, tcphdr_t *)); static frentry_t *fr_checkicmpmatchingstate __P((ip_t *, fr_info_t *)); +static int fr_matchicmpqueryreply __P((int, ipstate_t *, icmphdr_t *)); 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)); +int fr_stputent __P((caddr_t)); +int fr_stgetent __P((caddr_t)); +void fr_stinsert __P((ipstate_t *)); #define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */ @@ -124,16 +140,29 @@ u_long fr_tcpidletimeout = FIVE_DAYS, fr_icmptimeout = 120; int fr_statemax = IPSTATE_MAX, fr_statesize = IPSTATE_SIZE; -int fr_state_doflush = 0; +int fr_state_doflush = 0, + fr_state_lock = 0; +static int icmpreplytype4[ICMP_MAXTYPE + 1]; int fr_stateinit() { + int i; + KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *)); if (ips_table != NULL) bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *)); else return -1; + + /* fill icmp reply type table */ + for (i = 0; i <= ICMP_MAXTYPE; i++) + icmpreplytype4[i] = -1; + icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; + icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; + icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; + icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; + return 0; } @@ -142,6 +171,7 @@ static ips_stat_t *fr_statetstats() { ips_stats.iss_active = ips_num; ips_stats.iss_table = ips_table; + ips_stats.iss_list = ips_list; return &ips_stats; } @@ -155,7 +185,6 @@ static ips_stat_t *fr_statetstats() static int fr_state_flush(which) int which; { - register int i; register ipstate_t *is, **isp; #if defined(_KERNEL) && !SOLARIS int s; @@ -163,48 +192,69 @@ int which; int delete, removed = 0; SPL_NET(s); - WRITE_ENTER(&ipf_state); - for (i = fr_statesize - 1; i >= 0; i--) - for (isp = &ips_table[i]; (is = *isp); ) { - delete = 0; + for (isp = &ips_list; (is = *isp); ) { + delete = 0; - switch (which) - { - case 0 : - delete = 1; - break; - case 1 : - if (is->is_p != IPPROTO_TCP) - break; - if ((is->is_state[0] != TCPS_ESTABLISHED) || - (is->is_state[1] != TCPS_ESTABLISHED)) - delete = 1; + switch (which) + { + case 0 : + delete = 1; + break; + case 1 : + if (is->is_p != IPPROTO_TCP) break; - } + if ((is->is_state[0] != TCPS_ESTABLISHED) || + (is->is_state[1] != TCPS_ESTABLISHED)) + delete = 1; + break; + } - if (delete) { - *isp = is->is_next; - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; - if (ips_table[i] == NULL) - ips_stats.iss_inuse--; + if (delete) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; #ifdef IPFILTER_LOG - ipstate_log(is, ISL_FLUSH); + ipstate_log(is, ISL_FLUSH); #endif - fr_delstate(is); - ips_num--; - removed++; - } else - isp = &is->is_next; - } - RWLOCK_EXIT(&ipf_state); + fr_delstate(is); + removed++; + } else + isp = &is->is_next; + } SPL_X(s); return removed; } +static int fr_state_remove(data) +caddr_t data; +{ + ipstate_t *sp, st; + int error; + + sp = &st; + error = IRCOPYPTR(data, (caddr_t)&st, sizeof(st)); + if (error) + return EFAULT; + + 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))) { + WRITE_ENTER(&ipf_state); +#ifdef IPFILTER_LOG + ipstate_log(sp, ISL_REMOVE); +#endif + fr_delstate(sp); + RWLOCK_EXIT(&ipf_state); + return 0; + } + return ESRCH; +} + + int fr_state_ioctl(data, cmd, mode) caddr_t data; #if defined(__NetBSD__) || defined(__OpenBSD__) @@ -214,15 +264,22 @@ int cmd; #endif int mode; { - int arg, ret, error = 0; + int arg, ret, error = 0; switch (cmd) { + case SIOCDELST : + error = fr_state_remove(data); + break; case SIOCIPFFL : - IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (error) + break; if (arg == 0 || arg == 1) { + WRITE_ENTER(&ipf_state); ret = fr_state_flush(arg); - IWCOPY((caddr_t)&ret, data, sizeof(ret)); + RWLOCK_EXIT(&ipf_state); + error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); } else error = EINVAL; break; @@ -230,19 +287,41 @@ int mode; case SIOCIPFFB : if (!(mode & FWRITE)) error = EPERM; - else - *(int *)data = ipflog_clear(IPL_LOGSTATE); + else { + int tmp; + + tmp = ipflog_clear(IPL_LOGSTATE); + IWCOPY((char *)&tmp, data, sizeof(tmp)); + } break; #endif - case SIOCGIPST : - IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t)); + case SIOCGETFS : + error = IWCOPYPTR((caddr_t)fr_statetstats(), data, + sizeof(ips_stat_t)); break; case FIONREAD : #ifdef IPFILTER_LOG - IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, - sizeof(iplused[IPL_LOGSTATE])); + error = IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, + sizeof(iplused[IPL_LOGSTATE])); #endif break; + case SIOCSTLCK : + error = fr_lock(data, &fr_state_lock); + break; + case SIOCSTPUT : + if (!fr_state_lock) { + error = EACCES; + break; + } + error = fr_stputent(data); + break; + case SIOCSTGET : + if (!fr_state_lock) { + error = EACCES; + break; + } + error = fr_stgetent(data); + break; default : error = EINVAL; break; @@ -251,6 +330,138 @@ int mode; } +int fr_stgetent(data) +caddr_t data; +{ + register ipstate_t *is, *isn; + ipstate_save_t ips, *ipsp; + int error; + + error = IRCOPY(data, (caddr_t)&ipsp, sizeof(ipsp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipsp, (caddr_t)&ips, sizeof(ips)); + if (error) + return EFAULT; + + isn = ips.ips_next; + if (!isn) { + isn = ips_list; + if (isn == NULL) { + if (ips.ips_next == NULL) + return ENOENT; + return 0; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (is = ips_list; is; is = is->is_next) + if (is == isn) + break; + if (!is) + return ESRCH; + } + ips.ips_next = isn->is_next; + bcopy((char *)isn, (char *)&ips.ips_is, sizeof(ips.ips_is)); + if (isn->is_rule) + bcopy((char *)isn->is_rule, (char *)&ips.ips_fr, + sizeof(ips.ips_fr)); + error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); + if (error) + return EFAULT; + return 0; +} + + +int fr_stputent(data) +caddr_t data; +{ + register ipstate_t *is, *isn; + ipstate_save_t ips, *ipsp; + frentry_t *fr; + int error; + + error = IRCOPY(data, (caddr_t)&ipsp, sizeof(ipsp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipsp, (caddr_t)&ips, sizeof(ips)); + if (error) + return EFAULT; + + KMALLOC(isn, ipstate_t *); + if (isn == NULL) + return ENOMEM; + + bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn)); + fr = isn->is_rule; + if (fr != NULL) { + if (isn->is_flags & FI_NEWFR) { + KMALLOC(fr, frentry_t *); + if (fr == NULL) { + KFREE(isn); + return ENOMEM; + } + bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); + isn->is_rule = fr; + ips.ips_is.is_rule = fr; + error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); + if (error) { + KFREE(isn); + KFREE(fr); + return EFAULT; + } + } else { + for (is = ips_list; is; is = is->is_next) + if (is->is_rule == fr) + break; + if (!is) { + KFREE(isn); + return ESRCH; + } + } + } + fr_stinsert(isn); + return 0; +} + + +void fr_stinsert(is) +register ipstate_t *is; +{ + register u_int hv = is->is_hv; + + MUTEX_INIT(&is->is_lock, "ipf state entry", NULL); + + is->is_ifname[0][sizeof(is->is_ifname[0]) - 1] = '\0'; + if (is->is_ifname[0][0] != '\0') { + is->is_ifp[0] = GETUNIT(is->is_ifname[0], is->is_v); + } + is->is_ifname[1][sizeof(is->is_ifname[0]) - 1] = '\0'; + if (is->is_ifname[1][0] != '\0') { + is->is_ifp[1] = GETUNIT(is->is_ifname[1], is->is_v); + } + + /* + * add into list table. + */ + if (ips_list) + ips_list->is_pnext = &is->is_next; + is->is_pnext = &ips_list; + is->is_next = ips_list; + ips_list = is; + if (ips_table[hv]) + ips_table[hv]->is_phnext = &is->is_hnext; + else + ips_stats.iss_inuse++; + is->is_phnext = ips_table + hv; + is->is_hnext = ips_table[hv]; + ips_table[hv] = is; +} + + /* * Create a new ipstate structure and hang it off the hash table. */ @@ -259,18 +470,22 @@ ip_t *ip; fr_info_t *fin; u_int flags; { + register tcphdr_t *tcp = NULL; register ipstate_t *is; register u_int hv; ipstate_t ips; u_int pass; + int out; - if ((ip->ip_off & IP_OFFMASK) || (fin->fin_fi.fi_fl & FI_SHORT)) + if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || + (fin->fin_fi.fi_fl & FI_SHORT)) return NULL; if (ips_num == fr_statemax) { ips_stats.iss_max++; fr_state_doflush = 1; return NULL; } + out = fin->fin_out; is = &ips; bzero((char *)is, sizeof(*is)); ips.is_age = 1; @@ -279,39 +494,74 @@ u_int flags; /* * Copy and calculate... */ - hv = (is->is_p = ip->ip_p); - hv += (is->is_src.s_addr = ip->ip_src.s_addr); - hv += (is->is_dst.s_addr = ip->ip_dst.s_addr); + hv = (is->is_p = fin->fin_fi.fi_p); + is->is_src = fin->fin_fi.fi_src; + hv += is->is_saddr; + is->is_dst = fin->fin_fi.fi_dst; + hv += is->is_daddr; +#ifdef USE_INET6 + if (fin->fin_v == 6) { + if (is->is_p == IPPROTO_ICMPV6) { + if (IN6_IS_ADDR_MULTICAST(&is->is_dst.in6)) + flags |= FI_W_DADDR; + if (out) + hv -= is->is_daddr; + else + hv -= is->is_saddr; + } + } +#endif - switch (ip->ip_p) + switch (is->is_p) { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : +#endif case IPPROTO_ICMP : { struct icmp *ic = (struct icmp *)fin->fin_dp; +#ifdef USE_INET6 + if ((is->is_p == IPPROTO_ICMPV6) && + ((ic->icmp_type & ICMP6_INFOMSG_MASK) == 0)) + return NULL; +#endif switch (ic->icmp_type) { - case ICMP_ECHO : - is->is_icmp.ics_type = ICMP_ECHOREPLY; /* XXX */ +#ifdef USE_INET6 + case ICMP6_ECHO_REQUEST : + is->is_icmp.ics_type = ICMP6_ECHO_REPLY; hv += (is->is_icmp.ics_id = ic->icmp_id); hv += (is->is_icmp.ics_seq = ic->icmp_seq); break; + case ICMP6_MEMBERSHIP_QUERY : + case ND_ROUTER_SOLICIT : + case ND_NEIGHBOR_SOLICIT : + is->is_icmp.ics_type = ic->icmp_type + 1; + break; + break; +#endif + case ICMP_ECHO : case ICMP_TSTAMP : case ICMP_IREQ : case ICMP_MASKREQ : - is->is_icmp.ics_type = ic->icmp_type + 1; + is->is_icmp.ics_type = ic->icmp_type; + hv += (is->is_icmp.ics_id = ic->icmp_id); + hv += (is->is_icmp.ics_seq = ic->icmp_seq); break; default : return NULL; } - ATOMIC_INC(ips_stats.iss_icmp); + ATOMIC_INCL(ips_stats.iss_icmp); is->is_age = fr_icmptimeout; break; } case IPPROTO_TCP : { - register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + tcp = (tcphdr_t *)fin->fin_dp; + if (tcp->th_flags & TH_RST) + return NULL; /* * The endian of the ports doesn't matter, but the ack and * sequence numbers do as we do mathematics on them later. @@ -322,14 +572,13 @@ u_int flags; hv += tcp->th_dport; hv += tcp->th_sport; } - if (tcp->th_seq != 0) { - is->is_send = ntohl(tcp->th_seq) + ip->ip_len - - fin->fin_hlen - (tcp->th_off << 2) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - is->is_maxsend = is->is_send + 1; - } + is->is_send = ntohl(tcp->th_seq) + ip->ip_len - + fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + is->is_maxsend = is->is_send; is->is_dend = 0; + is->is_maxdwin = 1; is->is_maxswin = ntohs(tcp->th_win); if (is->is_maxswin == 0) is->is_maxswin = 1; @@ -338,16 +587,12 @@ u_int flags; * timer on it as we'll never see an error if it fails to * connect. */ - MUTEX_ENTER(&ipf_rw); - ips_stats.iss_tcp++; - fr_tcp_age(&is->is_age, is->is_state, ip, fin, - tcp->th_sport == is->is_sport); - MUTEX_EXIT(&ipf_rw); + ATOMIC_INCL(ips_stats.iss_tcp); break; } case IPPROTO_UDP : { - register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + tcp = (tcphdr_t *)fin->fin_dp; is->is_dport = tcp->th_dport; is->is_sport = tcp->th_sport; @@ -355,7 +600,7 @@ u_int flags; hv += tcp->th_dport; hv += tcp->th_sport; } - ATOMIC_INC(ips_stats.iss_udp); + ATOMIC_INCL(ips_stats.iss_udp); is->is_age = fr_udptimeout; break; } @@ -365,30 +610,29 @@ u_int flags; KMALLOC(is, ipstate_t *); if (is == NULL) { - ATOMIC_INC(ips_stats.iss_nomem); + ATOMIC_INCL(ips_stats.iss_nomem); return NULL; } bcopy((char *)&ips, (char *)is, sizeof(*is)); hv %= fr_statesize; - RW_UPGRADE(&ipf_mutex); + is->is_hv = hv; is->is_rule = fin->fin_fr; if (is->is_rule != NULL) { - is->is_rule->fr_ref++; + ATOMIC_INC32(is->is_rule->fr_ref); pass = is->is_rule->fr_flags; } else pass = fr_flags; - MUTEX_DOWNGRADE(&ipf_mutex); WRITE_ENTER(&ipf_state); - is->is_rout = pass & FR_OUTQUE ? 1 : 0; is->is_pass = pass; is->is_pkts = 1; - is->is_bytes = ip->ip_len; + is->is_bytes = fin->fin_dlen + fin->fin_hlen; /* * We want to check everything that is a property of this packet, * but we don't (automatically) care about it's fragment status as * this may change. */ + is->is_v = fin->fin_fi.fi_v; is->is_opt = fin->fin_fi.fi_optmsk; is->is_optmsk = 0xffffffff; is->is_sec = fin->fin_fi.fi_secmsk; @@ -397,29 +641,28 @@ u_int flags; is->is_authmsk = 0xffff; is->is_flags = fin->fin_fi.fi_fl & FI_CMP; is->is_flags |= FI_CMP << 4; - is->is_flags |= flags & (FI_W_DPORT|FI_W_SPORT); - /* - * add into table. - */ - is->is_next = ips_table[hv]; - ips_table[hv] = is; - if (is->is_next == NULL) - ips_stats.iss_inuse++; - if (fin->fin_out) { - is->is_ifpin = NULL; - is->is_ifpout = fin->fin_ifp; - } else { - is->is_ifpin = fin->fin_ifp; - is->is_ifpout = NULL; - } + is->is_flags |= flags & (FI_WILDP|FI_WILDA); + is->is_ifp[1 - out] = NULL; + is->is_ifp[out] = fin->fin_ifp; +#ifdef _KERNEL + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), IFNAMSIZ); +#endif + is->is_ifname[1 - out][0] = '\0'; if (pass & FR_LOGFIRST) is->is_pass &= ~(FR_LOGFIRST|FR_LOG); - ATOMIC_INC(ips_num); + fr_stinsert(is); + ips_num++; + if (is->is_p == IPPROTO_TCP) { + MUTEX_ENTER(&is->is_lock); + fr_tcp_age(&is->is_age, is->is_state, fin, + tcp->th_sport == is->is_sport); + MUTEX_EXIT(&is->is_lock); + } #ifdef IPFILTER_LOG ipstate_log(is, ISL_NEW); #endif RWLOCK_EXIT(&ipf_state); - fin->fin_rev = (is->is_dst.s_addr != ip->ip_dst.s_addr); + fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst); if (fin->fin_fi.fi_fl & FI_FRAG) ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); return is; @@ -448,13 +691,13 @@ tcphdr_t *tcp; /* * Find difference between last checked packet and this packet. */ - source = (ip->ip_src.s_addr == is->is_src.s_addr); + source = IP6EQ(fin->fin_fi.fi_src, is->is_src); fdata = &is->is_tcp.ts_data[!source]; tdata = &is->is_tcp.ts_data[source]; seq = ntohl(tcp->th_seq); ack = ntohl(tcp->th_ack); win = ntohs(tcp->th_win); - end = seq + ip->ip_len - fin->fin_hlen - (tcp->th_off << 2) + + end = seq + fin->fin_dlen - (tcp->th_off << 2) + ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); @@ -469,9 +712,6 @@ tcphdr_t *tcp; if (!(tcp->th_flags & TH_ACK)) { /* Pretend an ack was sent */ ack = tdata->td_end; - win = 1; - if ((tcp->th_flags == TH_SYN) && (tdata->td_maxwin == 0)) - tdata->td_maxwin = 1; } else if (((tcp->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && (ack == 0)) { /* gross hack to get around certain broken tcp stacks */ @@ -520,15 +760,15 @@ tcphdr_t *tcp; tdata->td_maxend++; } - ATOMIC_INC(ips_stats.iss_hits); + ATOMIC_INCL(ips_stats.iss_hits); is->is_pkts++; - is->is_bytes += ip->ip_len; + is->is_bytes += fin->fin_dlen + fin->fin_hlen; /* * Nearing end of connection, start timeout. */ - MUTEX_ENTER(&ipf_rw); - fr_tcp_age(&is->is_age, is->is_state, ip, fin, source); - MUTEX_EXIT(&ipf_rw); + MUTEX_ENTER(&is->is_lock); + fr_tcp_age(&is->is_age, is->is_state, fin, source); + MUTEX_EXIT(&is->is_lock); ret = 1; } return ret; @@ -537,7 +777,7 @@ tcphdr_t *tcp; static int fr_matchsrcdst(is, src, dst, fin, tcp) ipstate_t *is; -struct in_addr src, dst; +union i6addr src, dst; fr_info_t *fin; tcphdr_t *tcp; { @@ -545,7 +785,7 @@ tcphdr_t *tcp; u_short sp, dp; void *ifp; - rev = fin->fin_rev = (is->is_dst.s_addr != dst.s_addr); + rev = fin->fin_rev = IP6NEQ(is->is_dst, dst); ifp = fin->fin_ifp; out = fin->fin_out; @@ -554,14 +794,14 @@ tcphdr_t *tcp; sp = tcp->th_sport; dp = tcp->th_dport; } else { - flags = 0; + flags = is->is_flags & FI_WILDA; sp = 0; dp = 0; } if (rev == 0) { if (!out) { - if (is->is_ifpin == ifp) + if (is->is_ifpin == NULL || is->is_ifpin == ifp) ret = 1; } else { if (is->is_ifpout == NULL || is->is_ifpout == ifp) @@ -569,7 +809,7 @@ tcphdr_t *tcp; } } else { if (out) { - if (is->is_ifpin == ifp) + if (is->is_ifpin == NULL || is->is_ifpin == ifp) ret = 1; } else { if (is->is_ifpout == NULL || is->is_ifpout == ifp) @@ -581,15 +821,17 @@ tcphdr_t *tcp; ret = 0; if (rev == 0) { - if ((is->is_dst.s_addr == dst.s_addr) && - (is->is_src.s_addr == src.s_addr) && + if ( + (IP6EQ(is->is_dst, dst) || (flags & FI_W_DADDR)) && + (IP6EQ(is->is_src, src) || (flags & FI_W_SADDR)) && (!tcp || ((sp == is->is_sport || flags & FI_W_SPORT) && (dp == is->is_dport || flags & FI_W_DPORT)))) { ret = 1; } } else { - if ((is->is_dst.s_addr == src.s_addr) && - (is->is_src.s_addr == dst.s_addr) && + if ( + (IP6EQ(is->is_dst, src) || (flags & FI_W_DADDR)) && + (IP6EQ(is->is_src, dst) || (flags & FI_W_SADDR)) && (!tcp || ((sp == is->is_dport || flags & FI_W_DPORT) && (dp == is->is_sport || flags & FI_W_SPORT)))) { ret = 1; @@ -634,34 +876,80 @@ tcphdr_t *tcp; is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); } + ret = -1; + if (!rev) { - if (out && (out == is->is_rout)) { + if (out) { if (!is->is_ifpout) - is->is_ifpout = ifp; + ret = 1; } else { if (!is->is_ifpin) - is->is_ifpin = ifp; + ret = 0; } } else { - if (!out && (out != is->is_rout)) { + if (out) { if (!is->is_ifpin) - is->is_ifpin = ifp; + ret = 0; } else { if (!is->is_ifpout) - is->is_ifpout = ifp; + ret = 1; } } + + if (ret >= 0) { + is->is_ifp[ret] = ifp; +#ifdef _KERNEL + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[1])); +#endif + } +#ifdef _KERNEL + if (ret >= 0) { + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[1])); + } +#endif return 1; } -frentry_t *fr_checkicmpmatchingstate(ip, fin) +static int fr_matchicmpqueryreply(v, is, icmp) +int v; +ipstate_t *is; +icmphdr_t *icmp; +{ + if (v == 4) { + /* + * If we matched its type on the way in, then when going out + * it will still be the same type. + */ + if (((icmp->icmp_type == is->is_type) || + (icmpreplytype4[is->is_type] == icmp->icmp_type)) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq)) { + return 1; + }; + } +#ifdef USE_INET6 + else if (is->is_v == 6) { + if ((is->is_type == ICMP6_ECHO_REPLY) && + (icmp->icmp_type == ICMP6_ECHO_REQUEST) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq)) { + return 1; + }; + } +#endif + return 0; +} + +static frentry_t *fr_checkicmpmatchingstate(ip, fin) ip_t *ip; fr_info_t *fin; { - register struct in_addr dst, src; register ipstate_t *is, **isp; register u_short sport, dport; register u_char pr; + union i6addr dst, src; struct icmp *ic; u_short savelen; fr_info_t ofin; @@ -677,9 +965,10 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with * an ICMP error header. */ - if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN)) + if (((ip->ip_v != 4) && (ip->ip_hl != 5)) || + (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; - ic = (struct icmp *)((char *)ip + fin->fin_hlen); + ic = (struct icmp *)fin->fin_dp; type = ic->icmp_type; /* * If it's not an error type, then return @@ -689,12 +978,11 @@ fr_info_t *fin; (type != ICMP_PARAMPROB)) return NULL; - oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); - if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) + oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN); + if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) return NULL; if (oip->ip_p == IPPROTO_ICMP) { - icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); /* @@ -713,14 +1001,13 @@ fr_info_t *fin; /* * perform a lookup of the ICMP packet in the state table */ - hv = (pr = oip->ip_p); - hv += (src.s_addr = oip->ip_src.s_addr); - hv += (dst.s_addr = oip->ip_dst.s_addr); - if (icmp->icmp_type == ICMP_ECHO) { - hv += icmp->icmp_id; - hv += icmp->icmp_seq; - } + src.in4 = oip->ip_src; + hv += src.in4.s_addr; + dst.in4 = oip->ip_dst; + hv += dst.in4.s_addr; + hv += icmp->icmp_id; + hv += icmp->icmp_seq; hv %= fr_statesize; oip->ip_len = ntohs(oip->ip_len); @@ -731,26 +1018,16 @@ fr_info_t *fin; ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) - if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, &ofin, NULL)) { - /* - * in the state table ICMP query's are stored - * with the type of the corresponding ICMP - * response. Correct here - */ - if (((is->is_type == ICMP_ECHOREPLY) && - (icmp->icmp_id == is->is_icmp.ics_id) && - (icmp->icmp_seq == is->is_icmp.ics_seq) && - (icmp->icmp_type == ICMP_ECHO)) || - (is->is_type - 1 == ic->icmp_type)) { - ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += ip->ip_len; - fr = is->is_rule; - RWLOCK_EXIT(&ipf_state); - return fr; - } + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) + if ((is->is_p == pr) && (is->is_v == 4) && + fr_matchsrcdst(is, src, dst, &ofin, NULL) && + fr_matchicmpqueryreply(is->is_v, is, icmp)) { + ips_stats.iss_hits++; + is->is_pkts++; + is->is_bytes += ip->ip_len; + fr = is->is_rule; + RWLOCK_EXIT(&ipf_state); + return fr; } RWLOCK_EXIT(&ipf_state); return NULL; @@ -764,8 +1041,10 @@ fr_info_t *fin; sport = tcp->th_sport; hv = (pr = oip->ip_p); - hv += (src.s_addr = oip->ip_src.s_addr); - hv += (dst.s_addr = oip->ip_dst.s_addr); + src.in4 = oip->ip_src; + hv += src.in4.s_addr; + dst.in4 = oip->ip_dst; + hv += dst.in4.s_addr; hv += dport; hv += sport; hv %= fr_statesize; @@ -787,7 +1066,7 @@ fr_info_t *fin; ofin.fin_out = !fin->fin_out; ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) { + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { /* * Only allow this icmp though if the * encapsulated packet was allowed through the @@ -795,7 +1074,7 @@ fr_info_t *fin; * of info present does not allow for checking against * tcp internals such as seq and ack numbers. */ - if ((is->is_p == pr) && + if ((is->is_p == pr) && (is->is_v == 4) && fr_matchsrcdst(is, src, dst, &ofin, tcp)) { fr = is->is_rule; ips_stats.iss_hits++; @@ -804,7 +1083,7 @@ fr_info_t *fin; * comes the other way around */ is->is_pkts++; - is->is_bytes += ip->ip_len; + is->is_bytes += fin->fin_plen; /* * we deliberately do not touch the timeouts * for the accompanying state table entry. @@ -825,51 +1104,63 @@ frentry_t *fr_checkstate(ip, fin) ip_t *ip; fr_info_t *fin; { - register struct in_addr dst, src; + union i6addr dst, src; register ipstate_t *is, **isp; register u_char pr; - u_int hv, hvm, hlen, tryagain, pass; + u_int hv, hvm, hlen, tryagain, pass, v; struct icmp *ic; frentry_t *fr; tcphdr_t *tcp; - if ((ip->ip_off & IP_OFFMASK) || (fin->fin_fi.fi_fl & FI_SHORT)) + if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || + (fin->fin_fi.fi_fl & FI_SHORT)) return NULL; is = NULL; hlen = fin->fin_hlen; tcp = (tcphdr_t *)((char *)ip + hlen); ic = (struct icmp *)tcp; - hv = (pr = ip->ip_p); - hv += (src.s_addr = ip->ip_src.s_addr); - hv += (dst.s_addr = ip->ip_dst.s_addr); + hv = (pr = fin->fin_fi.fi_p); + src = fin->fin_fi.fi_src; + dst = fin->fin_fi.fi_dst; + hv += src.in4.s_addr; + hv += dst.in4.s_addr; /* * Search the hash table for matching packet header info. */ - switch (ip->ip_p) + v = fin->fin_fi.fi_v; + switch (fin->fin_fi.fi_p) { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + if (v == 6) { + if (fin->fin_out) + hv -= dst.in4.s_addr; + else + hv -= src.in4.s_addr; + if ((ic->icmp_type == ICMP6_ECHO_REQUEST) || + (ic->icmp_type == ICMP6_ECHO_REPLY)) { + hv += ic->icmp_id; + hv += ic->icmp_seq; + } + } +#endif case IPPROTO_ICMP : - if ((ic->icmp_type == ICMP_ECHO) || - (ic->icmp_type == ICMP_ECHOREPLY)) { + if (v == 4) { hv += ic->icmp_id; hv += ic->icmp_seq; } hv %= fr_statesize; READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) - if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, fin, NULL)) { - if ((is->is_type == ICMP_ECHOREPLY) && - (ic->icmp_type == ICMP_ECHO) && - (ic->icmp_id == is->is_icmp.ics_id) && - (ic->icmp_seq == is->is_icmp.ics_seq)) - ; - else if (is->is_type != ic->icmp_type) - continue; + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + if ((is->is_p == pr) && (is->is_v == v) && + fr_matchsrcdst(is, src, dst, fin, NULL) && + fr_matchicmpqueryreply(v, is, ic)) { is->is_age = fr_icmptimeout; break; } + } if (is != NULL) break; RWLOCK_EXIT(&ipf_state); @@ -877,7 +1168,12 @@ fr_info_t *fin; * No matching icmp state entry. Perhaps this is a * response to another state entry. */ - fr = fr_checkicmpmatchingstate(ip, fin); +#ifdef USE_INET6 + if (v == 6) + fr = fr_checkicmp6matchingstate((ip6_t *)ip, fin); + else +#endif + fr = fr_checkicmpmatchingstate(ip, fin); if (fr) return fr; break; @@ -890,22 +1186,13 @@ retry_tcp: hvm = hv % fr_statesize; WRITE_ENTER(&ipf_state); for (isp = &ips_table[hvm]; (is = *isp); - isp = &is->is_next) - if ((is->is_p == pr) && + 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)) { -#ifndef _KERNEL - if (tcp->th_flags & TCP_CLOSE) { - *isp = is->is_next; - isp = &ips_table[hvm]; - if (ips_table[hvm] == NULL) - ips_stats.iss_inuse--; - fr_delstate(is); - ips_num--; - } -#endif + if (fr_tcpstate(is, fin, ip, tcp)) break; - } is = NULL; break; } @@ -931,8 +1218,8 @@ retry_udp: * Nothing else to match on but ports. and IP#'s */ READ_ENTER(&ipf_state); - for (is = ips_table[hvm]; is; is = is->is_next) - if ((is->is_p == pr) && + for (is = ips_table[hvm]; is; is = is->is_hnext) + if ((is->is_p == pr) && (is->is_v == v) && fr_matchsrcdst(is, src, dst, fin, tcp)) { is->is_age = fr_udptimeout; break; @@ -952,17 +1239,21 @@ retry_udp: break; } if (is == NULL) { - ATOMIC_INC(ips_stats.iss_miss); + ATOMIC_INCL(ips_stats.iss_miss); return NULL; } - MUTEX_ENTER(&ipf_rw); - is->is_bytes += ip->ip_len; + MUTEX_ENTER(&is->is_lock); + is->is_bytes += fin->fin_plen; ips_stats.iss_hits++; is->is_pkts++; - MUTEX_EXIT(&ipf_rw); + MUTEX_EXIT(&is->is_lock); fr = is->is_rule; fin->fin_fr = fr; pass = is->is_pass; +#ifndef _KERNEL + if (tcp->th_flags & TCP_CLOSE) + fr_delstate(is); +#endif RWLOCK_EXIT(&ipf_state); if (fin->fin_fi.fi_fl & FI_FRAG) ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); @@ -970,18 +1261,53 @@ retry_udp: } +void ip_statesync(ifp) +void *ifp; +{ + register ipstate_t *is; + + WRITE_ENTER(&ipf_state); + for (is = ips_list; is; is = is->is_next) { + if (is->is_ifpin == ifp) { + is->is_ifpin = GETUNIT(is->is_ifname[0], is->is_v); + if (!is->is_ifpin) + is->is_ifpin = (void *)-1; + } + if (is->is_ifpout == ifp) { + is->is_ifpout = GETUNIT(is->is_ifname[1], is->is_v); + if (!is->is_ifpout) + is->is_ifpout = (void *)-1; + } + } + RWLOCK_EXIT(&ipf_state); +} + + static void fr_delstate(is) ipstate_t *is; { frentry_t *fr; + if (is->is_next) + is->is_next->is_pnext = is->is_pnext; + *is->is_pnext = is->is_next; + if (is->is_hnext) + is->is_hnext->is_phnext = is->is_phnext; + *is->is_phnext = is->is_hnext; + if (ips_table[is->is_hv] == NULL) + ips_stats.iss_inuse--; + fr = is->is_rule; if (fr != NULL) { - ATOMIC_DEC(fr->fr_ref); + ATOMIC_DEC32(fr->fr_ref); if (fr->fr_ref == 0) KFREE(fr); } +#ifdef _KERNEL + MUTEX_DESTROY(&is->is_lock); +#endif KFREE(is); + ips_num--; } @@ -990,16 +1316,11 @@ ipstate_t *is; */ void fr_stateunload() { - register int i; - register ipstate_t *is, **isp; + register ipstate_t *is; WRITE_ENTER(&ipf_state); - for (i = fr_statesize - 1; i >= 0; i--) - for (isp = &ips_table[i]; (is = *isp); ) { - *isp = is->is_next; - fr_delstate(is); - ips_num--; - } + while ((is = ips_list)) + fr_delstate(is); ips_stats.iss_inuse = 0; ips_num = 0; RWLOCK_EXIT(&ipf_state); @@ -1014,7 +1335,6 @@ void fr_stateunload() */ void fr_timeoutstate() { - register int i; register ipstate_t *is, **isp; #if defined(_KERNEL) && !SOLARIS int s; @@ -1022,23 +1342,18 @@ void fr_timeoutstate() SPL_NET(s); WRITE_ENTER(&ipf_state); - for (i = fr_statesize - 1; i >= 0; i--) - for (isp = &ips_table[i]; (is = *isp); ) - if (is->is_age && !--is->is_age) { - *isp = is->is_next; - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; - if (ips_table[i] == NULL) - ips_stats.iss_inuse--; + for (isp = &ips_list; (is = *isp); ) + if (is->is_age && !--is->is_age) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; #ifdef IPFILTER_LOG - ipstate_log(is, ISL_EXPIRE); + ipstate_log(is, ISL_EXPIRE); #endif - fr_delstate(is); - ips_num--; - } else - isp = &is->is_next; + fr_delstate(is); + } else + isp = &is->is_next; RWLOCK_EXIT(&ipf_state); SPL_X(s); if (fr_state_doflush) { @@ -1052,10 +1367,9 @@ void fr_timeoutstate() * Original idea freom Pradeep Krishnan for use primarily with NAT code. * (pkrishna@netcom.com) */ -void fr_tcp_age(age, state, ip, fin, dir) +void fr_tcp_age(age, state, fin, dir) u_long *age; u_char *state; -ip_t *ip; fr_info_t *fin; int dir; { @@ -1065,7 +1379,7 @@ int dir; ostate = state[1 - dir]; - dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2); + dlen = fin->fin_plen - fin->fin_hlen - (tcp->th_off << 2); if (flags & TH_RST) { if (!(tcp->th_flags & TH_PUSH) && !dlen) { @@ -1160,6 +1474,7 @@ u_int type; ipsl.isl_src = is->is_src; ipsl.isl_dst = is->is_dst; ipsl.isl_p = is->is_p; + ipsl.isl_v = is->is_v; ipsl.isl_flags = is->is_flags; if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) { ipsl.isl_sport = is->is_sport; @@ -1183,19 +1498,161 @@ u_int type; #endif -void ip_statesync(ifp) -void *ifp; +#ifdef USE_INET6 +frentry_t *fr_checkicmp6matchingstate(ip, fin) +ip6_t *ip; +fr_info_t *fin; { - register ipstate_t *is; - register int i; + register ipstate_t *is, **isp; + register u_short sport, dport; + register u_char pr; + struct icmp6_hdr *ic, *oic; + union i6addr dst, src; + u_short savelen; + fr_info_t ofin; + tcphdr_t *tcp; + frentry_t *fr; + ip6_t *oip; + int type; + u_int hv; - WRITE_ENTER(&ipf_state); - for (i = fr_statesize - 1; i >= 0; i--) - for (is = ips_table[i]; is != NULL; is = is->is_next) { - if (is->is_ifpin == ifp) - is->is_ifpin = NULL; - if (is->is_ifpout == ifp) - is->is_ifpout = NULL; + /* + * Does it at least have the return (basic) IP header ? + * Only a basic IP header (no options) should be with + * an ICMP error header. + */ + if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN)) + return NULL; + ic = (struct icmp6_hdr *)fin->fin_dp; + type = ic->icmp6_type; + /* + * If it's not an error type, then return + */ + if ((type != ICMP6_DST_UNREACH) && (type != ICMP6_PACKET_TOO_BIG) && + (type != ICMP6_TIME_EXCEEDED) && (type != ICMP6_PARAM_PROB)) + return NULL; + + oip = (ip6_t *)((char *)ic + ICMPERR_ICMPHLEN); + if (fin->fin_plen < sizeof(*oip)) + return NULL; + + if (oip->ip6_nxt == IPPROTO_ICMPV6) { + oic = (struct icmp6_hdr *)(oip + 1); + /* + * a ICMP error can only be generated as a result of an + * ICMP query, not as the response on an ICMP error + * + * XXX theoretically ICMP_ECHOREP and the other reply's are + * ICMP query's as well, but adding them here seems strange XXX + */ + if (!(oic->icmp6_type & ICMP6_INFOMSG_MASK)) + return NULL; + + /* + * perform a lookup of the ICMP packet in the state table + */ + hv = (pr = oip->ip6_nxt); + src.in6 = oip->ip6_src; + hv += src.in4.s_addr; + dst.in6 = oip->ip6_dst; + hv += dst.in4.s_addr; + hv += oic->icmp6_id; + hv += oic->icmp6_seq; + hv %= fr_statesize; + + oip->ip6_plen = ntohs(oip->ip6_plen); + fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); + oip->ip6_plen = htons(oip->ip6_plen); + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) + if ((is->is_p == pr) && + (oic->icmp6_id == is->is_icmp.ics_id) && + (oic->icmp6_seq == is->is_icmp.ics_seq) && + fr_matchsrcdst(is, src, dst, &ofin, NULL)) { + /* + * in the state table ICMP query's are stored + * with the type of the corresponding ICMP + * response. Correct here + */ + if (((is->is_type == ICMP6_ECHO_REPLY) && + (oic->icmp6_type == ICMP6_ECHO_REQUEST)) || + (is->is_type - 1 == oic->icmp6_type )) { + ips_stats.iss_hits++; + is->is_pkts++; + is->is_bytes += fin->fin_plen; + return is->is_rule; + } + } + RWLOCK_EXIT(&ipf_state); + + return NULL; + }; + + if ((oip->ip6_nxt != IPPROTO_TCP) && (oip->ip6_nxt != IPPROTO_UDP)) + return NULL; + tcp = (tcphdr_t *)(oip + 1); + dport = tcp->th_dport; + sport = tcp->th_sport; + + hv = (pr = oip->ip6_nxt); + src.in6 = oip->ip6_src; + hv += src.in4.s_addr; + dst.in6 = oip->ip6_dst; + hv += dst.in4.s_addr; + hv += dport; + hv += sport; + hv %= fr_statesize; + /* + * we make an fin entry to be able to feed it to + * matchsrcdst note that not all fields are encessary + * but this is the cleanest way. Note further we fill + * in fin_mp such that if someone uses it we'll get + * a kernel panic. fr_matchsrcdst does not use this. + * + * watch out here, as ip is in host order and oip in network + * order. Any change we make must be undone afterwards. + */ + savelen = oip->ip6_plen; + oip->ip6_plen = ip->ip6_plen - sizeof(*ip) - ICMPERR_ICMPHLEN; + ofin.fin_v = 6; + fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); + oip->ip6_plen = savelen; + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + /* + * Only allow this icmp though if the + * encapsulated packet was allowed through the + * other way around. Note that the minimal amount + * of info present does not allow for checking against + * tcp internals such as seq and ack numbers. + */ + if ((is->is_p == pr) && (is->is_v == 6) && + fr_matchsrcdst(is, src, dst, &ofin, tcp)) { + fr = is->is_rule; + ips_stats.iss_hits++; + /* + * we must swap src and dst here because the icmp + * comes the other way around + */ + is->is_pkts++; + is->is_bytes += fin->fin_plen; + /* + * we deliberately do not touch the timeouts + * for the accompanying state table entry. + * It remains to be seen if that is correct. XXX + */ + RWLOCK_EXIT(&ipf_state); + return fr; } + } RWLOCK_EXIT(&ipf_state); + return NULL; } +#endif diff --git a/contrib/ipfilter/ip_state.h b/contrib/ipfilter/ip_state.h index b20f286..01c26a0 100644 --- a/contrib/ipfilter/ip_state.h +++ b/contrib/ipfilter/ip_state.h @@ -1,16 +1,22 @@ /* - * Copyright (C) 1995-1998 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * 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.1.2.2 2000/01/24 13:13:52 darrenr Exp $ + * $Id: ip_state.h,v 2.13 2000/03/13 22:10:23 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ +#if defined(__STDC__) || defined(__GNUC__) +# define SIOCDELST _IOW('r', 61, struct ipstate *) +#else +# define SIOCDELST _IOW(r, 61, struct ipstate *) +#endif + #define IPSTATE_SIZE 257 #define IPSTATE_MAX 2048 /* Maximum number of states held */ @@ -46,17 +52,20 @@ typedef struct tcpstate { typedef struct ipstate { struct ipstate *is_next; + struct ipstate **is_pnext; + struct ipstate *is_hnext; + struct ipstate **is_phnext; u_long is_age; u_int is_pass; U_QUAD_T is_pkts; U_QUAD_T is_bytes; - void *is_ifpin; - void *is_ifpout; + void *is_ifp[2]; frentry_t *is_rule; - struct in_addr is_src; - struct in_addr is_dst; + union i6addr is_src; + union i6addr is_dst; u_char is_p; /* Protocol */ - u_char is_rout; /* Is rule in/out ? */ + u_char is_v; + u_int is_hv; u_32_t is_flags; u_32_t is_opt; /* packet options set */ u_32_t is_optmsk; /* " " mask */ @@ -69,15 +78,21 @@ typedef struct ipstate { tcpstate_t is_ts; udpstate_t is_us; } is_ps; + char is_ifname[2][IFNAMSIZ]; +#if SOLARIS || defined(__sgi) + kmutex_t is_lock; +#endif } ipstate_t; -#define is_icmp is_ps.is_ics -#define is_type is_icmp.ics_type -#define is_code is_icmp.ics_code -#define is_tcp is_ps.is_ts -#define is_udp is_ps.is_us -#define is_send is_tcp.ts_data[0].td_end -#define is_dend is_tcp.ts_data[1].td_end +#define is_saddr is_src.in4.s_addr +#define is_daddr is_dst.in4.s_addr +#define is_icmp is_ps.is_ics +#define is_type is_icmp.ics_type +#define is_code is_icmp.ics_code +#define is_tcp is_ps.is_ts +#define is_udp is_ps.is_us +#define is_send is_tcp.ts_data[0].td_end +#define is_dend is_tcp.ts_data[1].td_end #define is_maxswin is_tcp.ts_data[0].td_maxwin #define is_maxdwin is_tcp.ts_data[1].td_maxwin #define is_maxsend is_tcp.ts_data[0].td_maxend @@ -85,6 +100,8 @@ typedef struct ipstate { #define is_sport is_tcp.ts_sport #define is_dport is_tcp.ts_dport #define is_state is_tcp.ts_state +#define is_ifpin is_ifp[0] +#define is_ifpout is_ifp[1] #define TH_OPENING (TH_SYN|TH_ACK) /* @@ -96,21 +113,30 @@ typedef struct ipstate { * Bits 8,9 are used to indicate wildcard source/destination port matching. */ +typedef struct ipstate_save { + void *ips_next; + struct ipstate ips_is; + struct frentry ips_fr; +} ipstate_save_t; + +#define ips_rule ips_is.is_rule + typedef struct ipslog { U_QUAD_T isl_pkts; U_QUAD_T isl_bytes; - struct in_addr isl_src; - struct in_addr isl_dst; - u_char isl_p; - u_char isl_flags; - u_char isl_state[2]; + union i6addr isl_src; + union i6addr isl_dst; u_short isl_type; union { u_short isl_filler[2]; u_short isl_ports[2]; u_short isl_icmp; } isl_ps; + u_char isl_v; + u_char isl_p; + u_char isl_flags; + u_char isl_state[2]; } ipslog_t; #define isl_sport isl_ps.isl_ports[0] @@ -120,6 +146,7 @@ typedef struct ipslog { #define ISL_NEW 0 #define ISL_EXPIRE 0xffff #define ISL_FLUSH 0xfffe +#define ISL_REMOVE 0xfffd typedef struct ips_stat { @@ -137,6 +164,7 @@ typedef struct ips_stat { u_long iss_logfail; u_long iss_inuse; ipstate_t **iss_table; + ipstate_t *iss_list; } ips_stat_t; @@ -147,13 +175,14 @@ extern u_long fr_tcptimeout; extern u_long fr_tcpclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; +extern int fr_state_lock; extern int fr_stateinit __P((void)); extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *)); extern ipstate_t *fr_addstate __P((ip_t *, fr_info_t *, u_int)); extern frentry_t *fr_checkstate __P((ip_t *, fr_info_t *)); extern void ip_statesync __P((void *)); extern void fr_timeoutstate __P((void)); -extern void fr_tcp_age __P((u_long *, u_char *, ip_t *, fr_info_t *, int)); +extern void fr_tcp_age __P((u_long *, u_char *, fr_info_t *, int)); extern void fr_stateunload __P((void)); extern void ipstate_log __P((struct ipstate *, u_int)); #if defined(__NetBSD__) || defined(__OpenBSD__) diff --git a/contrib/ipfilter/ipf.c b/contrib/ipfilter/ipf.c index a20852d..ac975e5 100644 --- a/contrib/ipfilter/ipf.c +++ b/contrib/ipfilter/ipf.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -42,8 +42,8 @@ #include "ipl.h" #if !defined(lint) -static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipf.c,v 2.2 1999/08/06 15:26:08 darrenr Exp $"; +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 2000/03/13 22:10:23 darrenr Exp $"; #endif #if SOLARIS @@ -60,6 +60,9 @@ void zerostats __P((void)); int main __P((int, char *[])); int opts = 0; +#ifdef USE_INET6 +int use_inet6 = 0; +#endif static int fd = -1; @@ -77,7 +80,7 @@ static int get_flags __P((void)); static void usage() { - fprintf(stderr, "usage: ipf [-AdDEInoPrsUvVyzZ] %s %s %s\n", + fprintf(stderr, "usage: ipf [-6AdDEInoPrsUvVyzZ] %s %s %s\n", "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", "[-f filename]"); exit(1); } @@ -89,11 +92,16 @@ char *argv[]; { int c; - while ((c = getopt(argc, argv, "AdDEf:F:Il:noPrsUvVyzZ")) != -1) { + while ((c = getopt(argc, argv, "6AdDEf:F:Il:noPrsUvVyzZ")) != -1) { switch (c) { case '?' : usage(); +#ifdef USE_INET6 + case '6' : + use_inet6 = 1; + break; +#endif case 'A' : opts &= ~OPT_INACTIVE; break; @@ -122,7 +130,6 @@ char *argv[]; opts |= OPT_DONOTHING; break; case 'o' : - opts |= OPT_OUTQUE; break; case 'P' : ipfname = IPL_AUTH; @@ -175,7 +182,7 @@ char *ipfdev; if (!(opts & OPT_DONOTHING) && fd == -1) if ((fd = open(ipfdev, O_RDWR)) == -1) - if ((fd = open(ipfname, O_RDONLY)) == -1) + if ((fd = open(ipfdev, O_RDONLY)) == -1) perror("open device"); return fd; } @@ -193,7 +200,7 @@ static int get_flags() int i; if ((opendevice(ipfname) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) { - perror("SIOCFRENB"); + perror("SIOCGETFF"); return 0; } return i; @@ -204,8 +211,13 @@ static void set_state(enable) u_int enable; { if (opendevice(ipfname) != -2) - if (ioctl(fd, SIOCFRENB, &enable) == -1) - perror("SIOCFRENB"); + if (ioctl(fd, SIOCFRENB, &enable) == -1) { + if (errno == EBUSY) + fprintf(stderr, + "IP FIlter: already initialized\n"); + else + perror("SIOCFRENB"); + } return; } @@ -283,24 +295,26 @@ char *name, *file; if ((opts & OPT_ZERORULEST) && !(opts & OPT_DONOTHING)) { - if (ioctl(fd, add, fr) == -1) + if (ioctl(fd, add, &fr) == -1) perror("ioctl(SIOCZRLST)"); else { #ifdef USE_QUAD_T printf("hits %qd bytes %qd ", + (long long)fr->fr_hits, + (long long)fr->fr_bytes); #else printf("hits %ld bytes %ld ", -#endif fr->fr_hits, fr->fr_bytes); +#endif printfr(fr); } } else if ((opts & OPT_REMOVE) && !(opts & OPT_DONOTHING)) { - if (ioctl(fd, del, fr) == -1) - perror("ioctl(SIOCDELFR)"); + if (ioctl(fd, del, &fr) == -1) + perror("ioctl(delete rule)"); } else if (!(opts & OPT_DONOTHING)) { - if (ioctl(fd, add, fr) == -1) - perror("ioctl(SIOCADDFR)"); + if (ioctl(fd, add, &fr) == -1) + perror("ioctl(add/insert rule)"); } } } @@ -348,8 +362,8 @@ char *opt; { int flag, err; - err = get_flags(); - if (err != 0) { + flag = get_flags(); + if (flag != 0) { if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) printf("log flag is currently %#x\n", flag); } @@ -452,13 +466,14 @@ void frsync() void zerostats() { friostat_t fio; + friostat_t *fiop = &fio; if (opendevice(ipfname) != -2) { - if (ioctl(fd, SIOCFRZST, &fio) == -1) { + if (ioctl(fd, SIOCFRZST, &fiop) == -1) { perror("ioctl(SIOCFRZST)"); exit(-1); } - showstats(&fio); + showstats(fiop); } } @@ -526,12 +541,13 @@ static void blockunknown() static void showversion() { struct friostat fio; + struct friostat *fiop=&fio; u_32_t flags; char *s; - printf("ipf: %s (%d)\n", IPL_VERSION, sizeof(frentry_t)); + printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); - if (opendevice(ipfname) != -2 && ioctl(fd, SIOCGETFS, &fio)) { + if (opendevice(ipfname) != -2 && ioctl(fd, SIOCGETFS, &fiop)) { perror("ioctl(SIOCGETFS"); return; } diff --git a/contrib/ipfilter/ipf.h b/contrib/ipfilter/ipf.h index 2971bfe..ee6ae4d 100644 --- a/contrib/ipfilter/ipf.h +++ b/contrib/ipfilter/ipf.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ipf.h 1.12 6/5/96 - * $Id: ipf.h,v 2.1.2.1 1999/10/05 12:59:25 darrenr Exp $ + * $Id: ipf.h,v 2.9.2.2 2000/05/06 11:20:20 darrenr Exp $ */ #ifndef __IPF_H__ @@ -37,6 +37,14 @@ #define OPT_RAW 0x080000 #define OPT_NAT 0x100000 #define OPT_GROUPS 0x200000 +#define OPT_STATETOP 0x400000 +#define OPT_FLUSH 0x800000 +#define OPT_CLEAR 0x1000000 +#define OPT_NODO 0x80000000 + +#define OPT_STAT OPT_FRSTATES +#define OPT_LIST OPT_SHOWLIST + #ifndef __P # ifdef __STDC__ @@ -46,6 +54,8 @@ # endif #endif +struct frpcmp; + #ifdef ultrix extern char *strdup __P((char *)); #endif @@ -65,10 +75,26 @@ struct ipopt_names { }; +extern char *proto; +extern char flagset[]; +extern u_char flags[]; + +extern u_char tcp_flags __P((char *, u_char *, int)); +extern int countbits __P((u_32_t)); +extern int ratoi __P((char *, int *, int, int)); +extern int ratoui __P((char *, u_int *, u_int, u_int)); +extern int hostmask __P((char ***, u_32_t *, u_32_t *, u_short *, int *, + u_short *, int)); +extern int ports __P((char ***, u_short *, int *, u_short *, int)); +extern char *portname __P((int, int)); extern u_32_t buildopts __P((char *, char *, int)); -extern u_32_t hostnum __P((char *, int *, int)); +extern int genmask __P((char *, u_32_t *)); +extern int hostnum __P((u_32_t *, char *, int)); extern u_32_t optname __P((char ***, u_short *, int)); extern void printpacket __P((ip_t *)); +extern void printportcmp __P((int, struct frpcmp *)); +extern void printhostmask __P((int, u_32_t *, u_32_t *)); +extern void printbuf __P((char *, int, int)); #if SOLARIS extern int inet_aton __P((const char *, struct in_addr *)); extern int gethostname __P((char *, int )); diff --git a/contrib/ipfilter/ipfs.c b/contrib/ipfilter/ipfs.c new file mode 100644 index 0000000..6dc2f02 --- /dev/null +++ b/contrib/ipfilter/ipfs.c @@ -0,0 +1,763 @@ +/* + * Copyright (C) 1999 by Darren Reed. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and due credit is given + * to the original author and the contributors. + */ +#ifdef __FreeBSD__ +# include <osreldate.h> +#endif +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#if !defined(__SVR4) && !defined(__GNUC__) +#include <strings.h> +#endif +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#include <stdlib.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <sys/time.h> +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#include <netinet/ip.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_nat.h" +#include "ip_state.h" +#include "ipf.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ipfs.c,v 2.6.2.1 2000/05/06 00:11:18 darrenr Exp $"; +#endif + +#ifndef IPF_SAVEDIR +# define IPF_SAVEDIR "/var/db/ipf" +#endif +#if !defined(__SVR4) && defined(__GNUC__) +extern char *index __P((const char *, int)); +#endif + +extern char *optarg; + +int main __P((int, char *[])); +void usage __P((void)); +int changestateif __P((char *, char *)); +int changenatif __P((char *, char *)); +int readstate __P((int, char *)); +int readnat __P((int, char *)); +int writestate __P((int, char *)); +int opendevice __P((char *)); +void closedevice __P((int)); +int setlock __P((int, int)); +int writeall __P((char *)); +int readall __P((char *)); +int writenat __P((int, char *)); + +int opts = 0; + + +void usage() +{ + fprintf(stderr, "usage: ipfs [-nv] -l\n"); + fprintf(stderr, "usage: ipfs [-nv] -u\n"); + fprintf(stderr, "usage: ipfs [-nv] [-d <dir>] -R\n"); + fprintf(stderr, "usage: ipfs [-nv] [-d <dir>] -W\n"); + fprintf(stderr, "usage: ipfs [-nNSv] [-f <file>] -r\n"); + fprintf(stderr, "usage: ipfs [-nNSv] [-f <file>] -w\n"); + fprintf(stderr, "usage: ipfs [-nNSv] -f <filename> -i <if1>,<if2>\n"); + exit(1); +} + + +/* + * Change interface names in state information saved out to disk. + */ +int changestateif(ifs, fname) +char *ifs, *fname; +{ + int fd, olen, nlen, rw; + ipstate_save_t ips; + off_t pos; + char *s; + + s = strchr(ifs, ','); + if (!s) + usage(); + *s++ = '\0'; + nlen = strlen(s); + olen = strlen(ifs); + if (nlen >= sizeof(ips.ips_is.is_ifname) || + olen >= sizeof(ips.ips_is.is_ifname)) + usage(); + + fd = open(fname, O_RDWR); + if (fd == -1) { + perror("open"); + exit(1); + } + + for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { + rw = 0; + if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { + strcpy(ips.ips_is.is_ifname[0], s); + rw = 1; + } + if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { + strcpy(ips.ips_is.is_ifname[1], s); + rw = 1; + } + if (rw == 1) { + if (lseek(fd, pos, SEEK_SET) != pos) { + perror("lseek"); + exit(1); + } + if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { + perror("write"); + exit(1); + } + } + pos = lseek(fd, 0, SEEK_CUR); + } + close(fd); + + return 0; +} + + +/* + * Change interface names in NAT information saved out to disk. + */ +int changenatif(ifs, fname) +char *ifs, *fname; +{ + int fd, olen, nlen, rw; + nat_save_t ipn; + nat_t *nat; + off_t pos; + char *s; + + s = strchr(ifs, ','); + if (!s) + usage(); + *s++ = '\0'; + nlen = strlen(s); + olen = strlen(ifs); + nat = &ipn.ipn_nat; + if (nlen >= sizeof(nat->nat_ifname) || olen >= sizeof(nat->nat_ifname)) + usage(); + + fd = open(fname, O_RDWR); + if (fd == -1) { + perror("open"); + exit(1); + } + + for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { + rw = 0; + if (!strncmp(nat->nat_ifname, ifs, olen + 1)) { + strcpy(nat->nat_ifname, s); + rw = 1; + } + if (rw == 1) { + if (lseek(fd, pos, SEEK_SET) != pos) { + perror("lseek"); + exit(1); + } + if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { + perror("write"); + exit(1); + } + } + pos = lseek(fd, 0, SEEK_CUR); + } + close(fd); + + return 0; +} + + +int main(argc,argv) +int argc; +char *argv[]; +{ + int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; + char *dirname = NULL, *filename = NULL, *ifs = NULL; + + while ((c = getopt(argc, argv, "d:f:lNnSRruvWw")) != -1) + switch (c) + { + case 'd' : + if ((set == 0) && !dirname && !filename) + dirname = optarg; + else + usage(); + break; + case 'f' : + if ((set == 0) && !dirname && !filename) + filename = optarg; + else + usage(); + break; + case 'i' : + ifs = optarg; + set = 1; + break; + case 'l' : + if (filename || dirname || set) + usage(); + lock = 1; + set = 1; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'N' : + if ((ns > 0) || dirname || (rw != -1) || set) + usage(); + ns = 0; + set = 1; + break; + case 'r' : + if ((ns > 0) || dirname || (rw != -1)) + usage(); + rw = 0; + set = 1; + break; + case 'R' : + rw = 2; + set = 1; + break; + case 'S' : + if ((ns > 0) || dirname || (rw != -1) || set) + usage(); + ns = 1; + set = 1; + break; + case 'u' : + if (filename || dirname || set) + usage(); + lock = 0; + set = 1; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + case 'w' : + if ((ns > 0) || dirname || (rw != -1) || (ns == -1)) + usage(); + rw = 1; + set = 1; + break; + case 'W' : + rw = 3; + set = 1; + break; + case '?' : + default : + usage(); + } + + if (ifs) + return changestateif(ifs, filename); + + if ((ns >= 0) || (lock >= 0)) { + if (lock >= 0) + devfd = opendevice(NULL); + else if (ns >= 0) { + if (ns == 1) + devfd = opendevice(IPL_STATE); + else if (ns == 0) + devfd = opendevice(IPL_NAT); + } + if (devfd == -1) + exit(1); + } + + if (lock >= 0) + err = setlock(devfd, lock); + else if (rw >= 0) { + if (rw & 1) { /* WRITE */ + if (rw & 2) + err = writeall(dirname); + else { + if (ns == 0) + err = writenat(devfd, filename); + else if (ns == 1) + err = writestate(devfd, filename); + } + } else { + if (rw & 2) + err = readall(dirname); + else { + if (ns == 0) + err = readnat(devfd, filename); + else if (ns == 1) + err = readstate(devfd, filename); + } + } + } + return err; +} + + +int opendevice(ipfdev) +char *ipfdev; +{ + int fd = -1; + + if (opts & OPT_DONOTHING) + return -2; + + if (!ipfdev) + ipfdev = IPL_NAME; + + if ((fd = open(ipfdev, O_RDWR)) == -1) + if ((fd = open(ipfdev, O_RDONLY)) == -1) + perror("open device"); + return fd; +} + + +void closedevice(fd) +int fd; +{ + close(fd); +} + + +int setlock(fd, lock) +int fd, lock; +{ + if (opts & OPT_VERBOSE) + printf("Turn lock %s\n", lock ? "on" : "off"); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(fd, SIOCSTLCK, &lock) == -1) { + perror("SIOCSTLCK"); + return 1; + } + if (opts & OPT_VERBOSE) + printf("Lock now %s\n", lock ? "on" : "off"); + } + return 0; +} + + +int writestate(fd, file) +int fd; +char *file; +{ + ipstate_save_t ips, *ipsp; + int wfd = -1; + + wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); + if (wfd == -1) { + fprintf(stderr, "%s ", file); + perror("state:open"); + return 1; + } + + ipsp = &ips; + bzero((char *)ipsp, sizeof(ips)); + + do { + if (opts & OPT_VERBOSE) + printf("Getting state from addr %p\n", ips.ips_next); + if (ioctl(fd, SIOCSTGET, &ipsp)) { + if (errno == ENOENT) + break; + perror("state:SIOCSTGET"); + close(wfd); + return 1; + } + if (opts & OPT_VERBOSE) + printf("Got state next %p\n", ips.ips_next); + if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { + perror("state:write"); + close(wfd); + return 1; + } + } while (ips.ips_next != NULL); + close(wfd); + + return 0; +} + + +int readstate(fd, file) +int fd; +char *file; +{ + ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; + int sfd = -1, i; + + sfd = open(file, O_RDONLY, 0600); + if (sfd == -1) { + fprintf(stderr, "%s ", file); + perror("open"); + return 1; + } + + bzero((char *)&ips, sizeof(ips)); + + /* + * 1. Read all state information in. + */ + do { + i = read(sfd, &ips, sizeof(ips)); + if (i == -1) { + perror("read"); + close(sfd); + return 1; + } + if (i == 0) + break; + if (i != sizeof(ips)) { + fprintf(stderr, "incomplete read: %d != %d\n", i, + (int)sizeof(ips)); + close(sfd); + return 1; + } + is = (ipstate_save_t *)malloc(sizeof(*is)); + bcopy((char *)&ips, (char *)is, sizeof(ips)); + + /* + * Check to see if this is the first state entry that will + * reference a particular rule and if so, flag it as such + * else just adjust the rule pointer to become a pointer to + * the other. We do this so we have a means later for tracking + * who is referencing us when we get back the real pointer + * in is_rule after doing the ioctl. + */ + for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) + if (is1->ips_rule == is->ips_rule) + break; + if (is1 == NULL) + is->ips_is.is_flags |= FI_NEWFR; + else + is->ips_rule = (void *)&is1->ips_rule; + + /* + * Use a tail-queue type list (add things to the end).. + */ + is->ips_next = NULL; + if (!ipshead) + ipshead = is; + if (ipstail) + ipstail->ips_next = is; + ipstail = is; + } while (1); + + close(sfd); + + for (is = ipshead; is; is = is->ips_next) { + if (opts & OPT_VERBOSE) + printf("Loading new state table entry\n"); + if (is->ips_is.is_flags & FI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Loading new filter rule\n"); + } + if (!(opts & OPT_DONOTHING)) + if (ioctl(fd, SIOCSTPUT, &is)) { + perror("SIOCSTPUT"); + return 1; + } + + if (is->ips_is.is_flags & FI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Real rule addr %p\n", is->ips_rule); + for (is1 = is->ips_next; is1; is1 = is1->ips_next) + if (is1->ips_rule == (frentry_t *)&is->ips_rule) + is1->ips_rule = is->ips_rule; + } + } + + return 0; +} + + +int readnat(fd, file) +int fd; +char *file; +{ + nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL, *ipnp; + int nfd = -1, i; + nat_t *nat; + + nfd = open(file, O_RDONLY); + if (nfd == -1) { + fprintf(stderr, "%s ", file); + perror("nat:open"); + return 1; + } + + bzero((char *)&ipn, sizeof(ipn)); + + /* + * 1. Read all state information in. + */ + do { + i = read(nfd, &ipn, sizeof(ipn)); + if (i == -1) { + perror("read"); + close(nfd); + return 1; + } + if (i == 0) + break; + if (i != sizeof(ipn)) { + fprintf(stderr, "incomplete read: %d != %d\n", i, + (int)sizeof(ipn)); + close(nfd); + return 1; + } + + if (ipn.ipn_dsize > 0) { + char *s = ipnp->ipn_data; + int n = ipnp->ipn_dsize; + + n -= sizeof(ipnp->ipn_data); + in = malloc(sizeof(*in) + n); + if (!in) + break; + + s += sizeof(ipnp->ipn_data); + i = read(nfd, s, n); + if (i == 0) + break; + if (i != n) { + fprintf(stderr, "incomplete read: %d != %d\n", + i, n); + close(nfd); + return 1; + } + } else + in = (nat_save_t *)malloc(sizeof(*in)); + bcopy((char *)&ipnp, (char *)in, sizeof(ipn)); + + /* + * Check to see if this is the first state entry that will + * reference a particular rule and if so, flag it as such + * else just adjust the rule pointer to become a pointer to + * the other. We do this so we have a means later for tracking + * who is referencing us when we get back the real pointer + * in is_rule after doing the ioctl. + */ + nat = &in->ipn_nat; + if (nat->nat_fr != NULL) { + for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) + if (in1->ipn_rule == nat->nat_fr) + break; + if (in1 == NULL) + nat->nat_flags |= FI_NEWFR; + else + nat->nat_fr = &in1->ipn_fr; + } + + /* + * Use a tail-queue type list (add things to the end).. + */ + in->ipn_next = NULL; + if (!ipnhead) + ipnhead = in; + if (ipntail) + ipntail->ipn_next = in; + ipntail = in; + } while (1); + + close(nfd); + + for (in = ipnhead; in; in = in->ipn_next) { + if (opts & OPT_VERBOSE) + printf("Loading new NAT table entry\n"); + nat = &in->ipn_nat; + if (nat->nat_flags & FI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Loading new filter rule\n"); + } + if (!(opts & OPT_DONOTHING)) + if (ioctl(fd, SIOCSTPUT, &in)) { + perror("SIOCSTPUT"); + return 1; + } + + if (nat->nat_flags & FI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Real rule addr %p\n", nat->nat_fr); + for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) + if (in1->ipn_rule == &in->ipn_fr) + in1->ipn_rule = nat->nat_fr; + } + } + + return 0; +} + + +int writenat(fd, file) +int fd; +char *file; +{ + nat_save_t *ipnp = NULL, *next = NULL; + int nfd = -1; + natget_t ng; + + nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); + if (nfd == -1) { + fprintf(stderr, "%s ", file); + perror("nat:open"); + return 1; + } + + + do { + if (opts & OPT_VERBOSE) + printf("Getting nat from addr %p\n", ipnp); + ng.ng_ptr = next; + ng.ng_sz = 0; + if (ioctl(fd, SIOCSTGSZ, &ng)) { + perror("nat:SIOCSTGSZ"); + close(nfd); + return 1; + } + + if (opts & OPT_VERBOSE) + printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); + + if (ng.ng_sz == 0) + break; + + if (!ipnp) + ipnp = malloc(ng.ng_sz); + else + ipnp = realloc((char *)ipnp, ng.ng_sz); + if (!ipnp) { + fprintf(stderr, + "malloc for %d bytes failed\n", ng.ng_sz); + break; + } + + bzero((char *)ipnp, ng.ng_sz); + ipnp->ipn_next = next; + if (ioctl(fd, SIOCSTGET, &ipnp)) { + if (errno == ENOENT) + break; + perror("nat:SIOCSTGET"); + close(nfd); + return 1; + } + + if (opts & OPT_VERBOSE) + printf("Got nat next %p\n", ipnp->ipn_next); + if (write(nfd, ipnp, ng.ng_sz) != ng.ng_sz) { + perror("nat:write"); + close(nfd); + return 1; + } + next = ipnp->ipn_next; + } while (ipnp && next); + close(nfd); + + return 0; +} + + +int writeall(dirname) +char *dirname; +{ + int fd, devfd; + + if (!dirname) + dirname = IPF_SAVEDIR; + + if (chdir(dirname)) { + perror("chdir(IPF_SAVEDIR)"); + return 1; + } + + fd = opendevice(NULL); + if (fd == -1) + return 1; + if (setlock(fd, 1)) { + close(fd); + return 1; + } + + devfd = opendevice(IPL_STATE); + if (devfd == -1) + return 1; + if (writestate(devfd, "ipstate.ipf")) + return 1; + close(devfd); + + devfd = opendevice(IPL_NAT); + if (devfd == -1) + return 1; + if (writenat(devfd, "ipnat.ipf")) + return 1; + close(devfd); + + if (setlock(fd, 0)) { + close(fd); + return 1; + } + + return 0; +} + + +int readall(dirname) +char *dirname; +{ + int fd, devfd; + + if (!dirname) + dirname = IPF_SAVEDIR; + + if (chdir(dirname)) { + perror("chdir(IPF_SAVEDIR)"); + return 1; + } + + fd = opendevice(NULL); + if (fd == -1) + return 1; + if (setlock(fd, 1)) { + close(fd); + return 1; + } + + devfd = opendevice(IPL_STATE); + if (devfd == -1) + return 1; + if (readstate(devfd, "ipstate.ipf")) + return 1; + close(devfd); + + devfd = opendevice(IPL_NAT); + if (devfd == -1) + return 1; + if (readnat(devfd, "ipnat.ipf")) + return 1; + close(devfd); + + if (setlock(fd, 0)) { + close(fd); + return 1; + } + + return 0; +} diff --git a/contrib/ipfilter/ipft_ef.c b/contrib/ipfilter/ipft_ef.c index 1029ae8..cbdc599 100644 --- a/contrib/ipfilter/ipft_ef.c +++ b/contrib/ipfilter/ipft_ef.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -51,7 +51,7 @@ etherfind -n -t #if !defined(lint) static const char sccsid[] = "@(#)ipft_ef.c 1.6 2/4/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_ef.c,v 2.1 1999/08/04 17:30:02 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipft_ef.c,v 2.2 2000/03/13 22:10:24 darrenr Exp $"; #endif static int etherf_open __P((char *)); diff --git a/contrib/ipfilter/ipft_hx.c b/contrib/ipfilter/ipft_hx.c index 9f25fb0..ccbc3ee 100644 --- a/contrib/ipfilter/ipft_hx.c +++ b/contrib/ipfilter/ipft_hx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-1998 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -42,7 +42,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_hx.c,v 2.1 1999/08/04 17:30:03 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipft_hx.c,v 2.2 2000/03/13 22:10:24 darrenr Exp $"; #endif extern int opts; diff --git a/contrib/ipfilter/ipft_pc.c b/contrib/ipfilter/ipft_pc.c index e924341..061b7e4 100644 --- a/contrib/ipfilter/ipft_pc.c +++ b/contrib/ipfilter/ipft_pc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -33,7 +33,7 @@ #include "ipt.h" #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ipft_pc.c,v 2.1 1999/08/04 17:30:03 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipft_pc.c,v 2.2 2000/03/13 22:10:24 darrenr Exp $"; #endif struct llc { diff --git a/contrib/ipfilter/ipft_sn.c b/contrib/ipfilter/ipft_sn.c index 8dc0fa1..573c007 100644 --- a/contrib/ipfilter/ipft_sn.c +++ b/contrib/ipfilter/ipft_sn.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -37,7 +37,7 @@ #include "ipt.h" #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ipft_sn.c,v 2.1 1999/08/04 17:30:04 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipft_sn.c,v 2.2 2000/03/13 22:10:24 darrenr Exp $"; #endif struct llc { diff --git a/contrib/ipfilter/ipft_td.c b/contrib/ipfilter/ipft_td.c index 7ea43ea..457591c 100644 --- a/contrib/ipfilter/ipft_td.c +++ b/contrib/ipfilter/ipft_td.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -60,7 +60,7 @@ tcpdump -nqte #if !defined(lint) static const char sccsid[] = "@(#)ipft_td.c 1.8 2/4/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_td.c,v 2.1 1999/08/04 17:30:04 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipft_td.c,v 2.2 2000/03/13 22:10:24 darrenr Exp $"; #endif static int tcpd_open __P((char *)); diff --git a/contrib/ipfilter/ipft_tx.c b/contrib/ipfilter/ipft_tx.c index 9a5f139..9eeb055 100644 --- a/contrib/ipfilter/ipft_tx.c +++ b/contrib/ipfilter/ipft_tx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-1998 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -43,7 +43,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipft_tx.c,v 2.1 1999/08/04 17:30:05 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipft_tx.c,v 2.3 2000/03/13 22:10:24 darrenr Exp $"; #endif extern int opts; @@ -54,8 +54,8 @@ static int text_open __P((char *)), text_close __P((void)); static int text_readip __P((char *, int, char **, int *)); static int parseline __P((char *, ip_t *, char **, int *)); -static char tcp_flagset[] = "FSRPAU"; -static u_char tcp_flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, +static char _tcp_flagset[] = "FSRPAU"; +static u_char _tcp_flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG }; struct ipread iptext = { text_open, text_close, text_readip }; @@ -301,13 +301,13 @@ int *out; ip->ip_dst.s_addr = tx_hostnum(*cpp, &r); cpp++; if (*cpp && ip->ip_p == IPPROTO_TCP) { - extern char tcp_flagset[]; - extern u_char tcp_flags[]; + extern char _tcp_flagset[]; + extern u_char _tcp_flags[]; char *s, *t; for (s = *cpp; *s; s++) - if ((t = index(tcp_flagset, *s))) - tcp->th_flags |= tcp_flags[t - tcp_flagset]; + if ((t = index(_tcp_flagset, *s))) + tcp->th_flags |= _tcp_flags[t - _tcp_flagset]; if (tcp->th_flags) cpp++; assert(tcp->th_flags != 0); diff --git a/contrib/ipfilter/ipl.h b/contrib/ipfilter/ipl.h index 6eb9b1a..12d866c 100644 --- a/contrib/ipfilter/ipl.h +++ b/contrib/ipfilter/ipl.h @@ -1,16 +1,17 @@ /* - * Copyright (C) 1993-1999 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 + * $Id: ipl.h,v 2.15.2.5 2000/05/22 10:26:16 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.3.8" +#define IPL_VERSION "IP Filter: v3.4.4" #endif diff --git a/contrib/ipfilter/iplang/Makefile b/contrib/ipfilter/iplang/Makefile index 4537e8d..32ae8e3 100644 --- a/contrib/ipfilter/iplang/Makefile +++ b/contrib/ipfilter/iplang/Makefile @@ -6,13 +6,13 @@ #CC=gcc -Wuninitialized -Wstrict-prototypes -Werror -O CFLAGS=-I.. -all: $(DESTDIR)/y.tab.o $(DESTDIR)/lex.yy.o y.tab.o lex.yy.o +all: $(DESTDIR)/y.tab.o $(DESTDIR)/lex.yy.o -$(DESTDIR)/y.tab.o: y.tab.c - $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c y.tab.c -o $@ +$(DESTDIR)/y.tab.o: $(DESTDIR)/y.tab.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/y.tab.c -o $@ -$(DESTDIR)/lex.yy.o: lex.yy.c - $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c lex.yy.c -o $@ +$(DESTDIR)/lex.yy.o: $(DESTDIR)/lex.yy.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/lex.yy.c -o $@ y.tab.o: y.tab.c $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c y.tab.c -o $@ @@ -20,11 +20,14 @@ y.tab.o: y.tab.c lex.yy.o: lex.yy.c $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c lex.yy.c -o $@ -lex.yy.c: iplang_l.l y.tab.h +$(DESTDIR)/lex.yy.c: iplang_l.l $(DESTDIR)/y.tab.h lex iplang_l.l + mv lex.yy.c $(DESTDIR) -y.tab.c y.tab.h: iplang_y.y +$(DESTDIR)/y.tab.c $(DESTDIR)/y.tab.h: iplang_y.y yacc -d iplang_y.y + mv y.tab.c $(DESTDIR) + mv y.tab.h $(DESTDIR) clean: /bin/rm -f *.o lex.yy.c y.tab.c y.tab.h diff --git a/contrib/ipfilter/iplang/iplang_l.l b/contrib/ipfilter/iplang/iplang_l.l index 36a4ec8..4139792 100644 --- a/contrib/ipfilter/iplang/iplang_l.l +++ b/contrib/ipfilter/iplang/iplang_l.l @@ -6,7 +6,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: iplang_l.l,v 2.1 1999/08/04 17:30:53 darrenr Exp $ + * $Id: iplang_l.l,v 2.2 2000/02/18 00:18:05 darrenr Exp $ */ #include <stdio.h> #include <string.h> @@ -31,7 +31,7 @@ extern int opts; -int lineNum = 0, proto = 0, oldproto = 0, next = -1, laststate = 0; +int lineNum = 0, ipproto = 0, oldipproto = 0, next = -1, laststate = 0; int *prstack = NULL, numpr = 0, state = 0, token = 0; void yyerror __P((char *)); @@ -197,14 +197,14 @@ void push_proto() prstack = (int *)malloc(sizeof(int)); else prstack = (int *)realloc((char *)prstack, numpr * sizeof(int)); - prstack[numpr - 1] = oldproto; + prstack[numpr - 1] = oldipproto; } void pop_proto() { numpr--; - proto = prstack[numpr]; + ipproto = prstack[numpr]; if (!numpr) { free(prstack); prstack = NULL; @@ -262,45 +262,45 @@ int nstate, fornext; case IL_DATA : case IL_INTERFACE : case IL_ARP : - oldproto = proto; - proto = nstate; + oldipproto = ipproto; + ipproto = nstate; break; case IL_SUM : - if (proto == IL_IPV4) + if (ipproto == IL_IPV4) nstate = IL_V4SUM; - else if (proto == IL_TCP) + else if (ipproto == IL_TCP) nstate = IL_TCPSUM; - else if (proto == IL_UDP) + else if (ipproto == IL_UDP) nstate = IL_UDPSUM; break; case IL_OPT : - if (proto == IL_IPV4) + if (ipproto == IL_IPV4) nstate = IL_V4OPT; - else if (proto == IL_TCP) + else if (ipproto == IL_TCP) nstate = IL_TCPOPT; break; case IL_IPO_NOP : - if (proto == IL_TCP) + if (ipproto == IL_TCP) nstate = IL_TCPO_NOP; break; case IL_IPO_EOL : - if (proto == IL_TCP) + if (ipproto == IL_TCP) nstate = IL_TCPO_EOL; break; case IL_IPO_TS : - if (proto == IL_TCP) + if (ipproto == IL_TCP) nstate = IL_TCPO_TS; break; case IL_OFF : - if (proto == IL_IPV4) + if (ipproto == IL_IPV4) nstate = IL_V4OFF; - else if (proto == IL_TCP) + else if (ipproto == IL_TCP) nstate = IL_TCPOFF; break; case IL_LEN : - if (proto == IL_IPV4) + if (ipproto == IL_IPV4) nstate = IL_V4LEN; - else if (proto == IL_UDP) + else if (ipproto == IL_UDP) nstate = IL_UDPLEN; break; } diff --git a/contrib/ipfilter/iplang/iplang_y.y b/contrib/ipfilter/iplang/iplang_y.y index 2c71b15..95f3419 100644 --- a/contrib/ipfilter/iplang/iplang_y.y +++ b/contrib/ipfilter/iplang/iplang_y.y @@ -6,7 +6,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: iplang_y.y,v 2.1.2.1 1999/11/21 11:05:09 darrenr Exp $ + * $Id: iplang_y.y,v 2.2 1999/12/04 03:37:04 darrenr Exp $ */ #include <stdio.h> diff --git a/contrib/ipfilter/ipmon.c b/contrib/ipfilter/ipmon.c index b90b093..593c665 100644 --- a/contrib/ipfilter/ipmon.c +++ b/contrib/ipfilter/ipmon.c @@ -1,13 +1,13 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-1998 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipmon.c,v 2.3.2.4 2000/01/24 12:45:25 darrenr Exp $"; +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 2000/03/13 22:10:24 darrenr Exp $"; #endif #ifndef SOLARIS @@ -120,7 +120,7 @@ static void dumphex __P((FILE *, u_char *, int)); static int read_log __P((int, int *, char *, int)); static void write_pid __P((char *)); -char *hostname __P((int, struct in_addr)); +char *hostname __P((int, int, u_32_t *)); char *portname __P((int, char *, u_int)); int main __P((int, char *[])); @@ -145,6 +145,8 @@ static char **tcp_ports = NULL; #define OPT_PORTNUM 0x400 #define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) +#define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) + #ifndef LOGFAC #define LOGFAC LOG_LOCAL0 #endif @@ -168,7 +170,7 @@ static void init_tabs() struct protoent *p; struct servent *s; char *name, **tab; - u_int port; + int port; if (protocols != NULL) { free(protocols); @@ -207,11 +209,11 @@ static void init_tabs() if (s->s_proto == NULL) continue; else if (!strcmp(s->s_proto, "tcp")) { - port = (u_int)s->s_port; + port = s->s_port; name = s->s_name; tab = tcp_ports; } else if (!strcmp(s->s_proto, "udp")) { - port = (u_int)s->s_port; + port = s->s_port; name = s->s_name; tab = udp_ports; } else @@ -256,18 +258,33 @@ char *buf; } -char *hostname(res, ip) -int res; -struct in_addr ip; +char *hostname(res, v, ip) +int res, v; +u_32_t *ip; { +#ifdef USE_INET6 + static char hostbuf[MAXHOSTNAMELEN+1]; +#endif struct hostent *hp; + struct in_addr ipa; - if (!res) - return inet_ntoa(ip); - hp = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET); - if (!hp) - return inet_ntoa(ip); - return hp->h_name; + if (v == 4) { + ipa.s_addr = *ip; + if (!res) + return inet_ntoa(ipa); + hp = gethostbyaddr((char *)ip, sizeof(ip), AF_INET); + if (!hp) + return inet_ntoa(ipa); + return hp->h_name; + + } +#ifdef USE_INET6 + (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); + hostbuf[MAXHOSTNAMELEN] = '\0'; + return hostbuf; +#else + return "IPv6"; +#endif } @@ -390,22 +407,24 @@ int blen; proto = getproto(nl->nl_p); - (void) sprintf(t, "%s,%s <- -> ", hostname(res, nl->nl_inip), + (void) sprintf(t, "%s,%s <- -> ", HOSTNAME_V4(res, nl->nl_inip), portname(res, proto, (u_int)nl->nl_inport)); t += strlen(t); - (void) sprintf(t, "%s,%s ", hostname(res, nl->nl_outip), + (void) sprintf(t, "%s,%s ", HOSTNAME_V4(res, nl->nl_outip), portname(res, proto, (u_int)nl->nl_outport)); t += strlen(t); - (void) sprintf(t, "[%s,%s]", hostname(res, nl->nl_origip), + (void) sprintf(t, "[%s,%s]", HOSTNAME_V4(res, nl->nl_origip), portname(res, proto, (u_int)nl->nl_origport)); t += strlen(t); if (nl->nl_type == NL_EXPIRE) { #ifdef USE_QUAD_T (void) sprintf(t, " Pkts %qd Bytes %qd", + (long long)nl->nl_pkts, + (long long)nl->nl_bytes); #else (void) sprintf(t, " Pkts %ld Bytes %ld", -#endif nl->nl_pkts, nl->nl_bytes); +#endif t += strlen(t); } @@ -455,6 +474,8 @@ int blen; strcpy(t, "STATE:EXPIRE "); } else if (sl->isl_type == ISL_FLUSH) strcpy(t, "STATE:FLUSH "); + else if (sl->isl_type == ISL_REMOVE) + strcpy(t, "STATE:REMOVE "); else sprintf(t, "Type: %d ", sl->isl_type); t += strlen(t); @@ -463,26 +484,30 @@ int blen; if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { (void) sprintf(t, "%s,%s -> ", - hostname(res, sl->isl_src), + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src), portname(res, proto, (u_int)sl->isl_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s", - hostname(res, sl->isl_dst), + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), portname(res, proto, (u_int)sl->isl_dport), proto); } else if (sl->isl_p == IPPROTO_ICMP) { - (void) sprintf(t, "%s -> ", hostname(res, sl->isl_src)); + (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, + (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR icmp %d", - hostname(res, sl->isl_dst), sl->isl_itype); + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), + sl->isl_itype); } t += strlen(t); if (sl->isl_type != ISL_NEW) { #ifdef USE_QUAD_T (void) sprintf(t, " Pkts %qd Bytes %qd", + (long long)sl->isl_pkts, + (long long)sl->isl_bytes); #else (void) sprintf(t, " Pkts %ld Bytes %ld", -#endif sl->isl_pkts, sl->isl_bytes); +#endif t += strlen(t); } @@ -554,23 +579,27 @@ int blen; struct icmp *ic; struct tm *tm; char *t, *proto; - u_short hl, p; - int i, lvl, res, len; + int i, v, lvl, res, len, off, plen, ipoff; ip_t *ipc, *ip; - iplog_t *ipl; + u_short hl, p; ipflog_t *ipf; + iplog_t *ipl; + u_32_t *s, *d; +#ifdef USE_INET6 + ip6_t *ip6; +#endif ipl = (iplog_t *)buf; ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); ip = (ip_t *)((char *)ipf + sizeof(*ipf)); + v = ip->ip_v; res = (opts & OPT_RESOLVE) ? 1 : 0; t = line; *t = '\0'; - hl = (ip->ip_hl << 2); - p = (u_short)ip->ip_p; tm = localtime((time_t *)&ipl->ipl_sec); #ifdef linux - ip->ip_len = ntohs(ip->ip_len); + if (v == 4) + ip->ip_len = ntohs(ip->ip_len); #endif len = sizeof(line); @@ -609,7 +638,6 @@ int blen; #endif (void) sprintf(t, " @%hu:%hu ", ipf->fl_group, ipf->fl_rule + 1); t += strlen(t); - proto = getproto(p); if (ipf->fl_flags & FF_SHORT) { *t++ = 'S'; @@ -638,18 +666,43 @@ int blen; *t++ = ' '; *t = '\0'; - if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && - !(ip->ip_off & IP_OFFMASK)) { + if (v == 6) { +#ifdef USE_INET6 + off = 0; + ipoff = 0; + hl = sizeof(ip6_t); + ip6 = (ip6_t *)ip; + p = (u_short)ip6->ip6_nxt; + s = (u_32_t *)&ip6->ip6_src; + d = (u_32_t *)&ip6->ip6_dst; + plen = ntohs(ip6->ip6_plen); +#else + sprintf(t, "ipv6"); + goto printipflog; +#endif + } else if (v == 4) { + hl = (ip->ip_hl << 2); + ipoff = ip->ip_off; + off = ipoff & IP_OFFMASK; + 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); + } else { + goto printipflog; + } + proto = getproto(p); + + if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { tp = (tcphdr_t *)((char *)ip + hl); if (!(ipf->fl_flags & (FI_SHORT << 16))) { - (void) sprintf(t, "%s,%s -> ", - hostname(res, ip->ip_src), + (void) sprintf(t, "%s,%s -> ", hostname(res, v, s), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s len %hu %hu ", - hostname(res, ip->ip_dst), + hostname(res, v, d), portname(res, proto, (u_int)tp->th_dport), - proto, hl, ip->ip_len); + proto, hl, plen); t += strlen(t); if (p == IPPROTO_TCP) { @@ -667,18 +720,17 @@ int blen; } *t = '\0'; } else { - (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src)); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu %hu", - hostname(res, ip->ip_dst), proto, - hl, ip->ip_len); + hostname(res, v, d), proto, hl, plen); } - } else if ((p == IPPROTO_ICMP) && !(ip->ip_off & IP_OFFMASK)) { + } else if ((p == IPPROTO_ICMP) && !off && (v == 4)) { ic = (struct icmp *)((char *)ip + hl); - (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src)); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR icmp len %hu %hu icmp %d/%d", - hostname(res, ip->ip_dst), hl, ip->ip_len, + hostname(res, v, d), hl, plen, ic->icmp_type, ic->icmp_code); if (ic->icmp_type == ICMP_UNREACH || ic->icmp_type == ICMP_SOURCEQUENCH || @@ -692,26 +744,25 @@ int blen; t += strlen(t); (void) sprintf(t, " for %s,%s -", - hostname(res, ipc->ip_src), + HOSTNAME_V4(res, ipc->ip_src), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, " %s,%s PR %s len %hu %hu", - hostname(res, ipc->ip_dst), + HOSTNAME_V4(res, ipc->ip_dst), portname(res, proto, (u_int)tp->th_dport), proto, ipc->ip_hl << 2, ipc->ip_len); } } else { - (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src)); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu (%hu)", - hostname(res, ip->ip_dst), proto, hl, ip->ip_len); + hostname(res, v, d), proto, hl, plen); t += strlen(t); - if (ip->ip_off & IP_OFFMASK) + if (off & IP_OFFMASK) (void) sprintf(t, " frag %s%s%hu@%hu", - ip->ip_off & IP_MF ? "+" : "", - ip->ip_off & IP_DF ? "-" : "", - ip->ip_len - hl, - (ip->ip_off & IP_OFFMASK) << 3); + ipoff & IP_MF ? "+" : "", + ipoff & IP_DF ? "-" : "", + plen - hl, (off & IP_OFFMASK) << 3); } t += strlen(t); @@ -730,6 +781,7 @@ int blen; else if (ipf->fl_flags & FR_OUTQUE) strcpy(t, " OUT"); t += strlen(t); +printipflog: *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) diff --git a/contrib/ipfilter/ipnat.c b/contrib/ipfilter/ipnat.c index b088a7f..9e1ef34 100644 --- a/contrib/ipfilter/ipnat.c +++ b/contrib/ipfilter/ipnat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -45,6 +45,7 @@ #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" +#include "ipf.h" #include "kmem.h" #if defined(sun) && !SOLARIS2 @@ -56,21 +57,25 @@ extern char *sys_errlist[]; #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipnat.c,v 2.1.2.2 1999/12/04 02:09:30 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipnat.c,v 2.16.2.2 2000/05/15 06:54:18 darrenr Exp $"; #endif #if SOLARIS #define bzero(a,b) memset(a,0,b) #endif +#ifdef USE_INET6 +int use_inet6 = 0; +#endif + +static char thishost[MAXHOSTNAMELEN]; + extern char *optarg; extern ipnat_t *natparse __P((char *, int)); extern void natparsefile __P((int, char *, int)); extern void printnat __P((ipnat_t *, int, void *)); -u_32_t hostnum __P((char *, int *, int)); -u_32_t hostmask __P((char *)); void dostats __P((int, int)), flushtable __P((int, int)); void usage __P((char *)); int countbits __P((u_32_t)); @@ -79,15 +84,6 @@ int main __P((int, char*[])); void printaps __P((ap_session_t *, int)); char *getsumd __P((u_32_t)); -#define OPT_REM 1 -#define OPT_NODO 2 -#define OPT_STAT 4 -#define OPT_LIST 8 -#define OPT_VERBOSE 16 -#define OPT_FLUSH 32 -#define OPT_CLEAR 64 -#define OPT_HITS 128 - void usage(name) char *name; @@ -117,12 +113,15 @@ char *argv[]; char *file = NULL; int fd = -1, opts = 0, c; - while ((c = getopt(argc, argv, "CFf:hlnrsv")) != -1) + while ((c = getopt(argc, argv, "CdFf:hlnrsv")) != -1) switch (c) { case 'C' : opts |= OPT_CLEAR; break; + case 'd' : + opts |= OPT_DEBUG; + break; case 'f' : file = optarg; break; @@ -139,7 +138,7 @@ char *argv[]; opts |= OPT_NODO; break; case 'r' : - opts |= OPT_REM; + opts |= OPT_REMOVE; break; case 's' : opts |= OPT_STAT; @@ -151,6 +150,9 @@ char *argv[]; usage(argv[0]); } + gethostname(thishost, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; + if (!(opts & OPT_NODO) && ((fd = open(IPL_NAT, O_RDWR)) == -1) && ((fd = open(IPL_NAT, O_RDONLY)) == -1)) { (void) fprintf(stderr, "%s: open: %s\n", IPL_NAT, @@ -168,40 +170,12 @@ char *argv[]; } -/* - * count consecutive 1's in bit mask. If the mask generated by counting - * consecutive 1's is different to that passed, return -1, else return # - * of bits. - */ -int countbits(ip) -u_32_t ip; -{ - u_32_t ipn; - int cnt = 0, i, j; - - ip = ipn = ntohl(ip); - for (i = 32; i; i--, ipn *= 2) - if (ipn & 0x80000000) - cnt++; - else - break; - ipn = 0; - for (i = 32, j = cnt; i; i--, j--) { - ipn *= 2; - if (j > 0) - ipn++; - } - if (ipn == ip) - return cnt; - return -1; -} - - void printaps(aps, opts) ap_session_t *aps; int opts; { ap_session_t ap; + ftpinfo_t ftp; aproxy_t apr; raudio_t ra; @@ -213,7 +187,8 @@ int opts; apr.apr_p, apr.apr_ref, apr.apr_flags); printf("\t\tproto %d flags %#x bytes ", ap.aps_p, ap.aps_flags); #ifdef USE_QUAD_T - printf("%qu pkts %qu", ap.aps_bytes, ap.aps_pkts); + printf("%qu pkts %qu", (unsigned long long)ap.aps_bytes, + (unsigned long long)ap.aps_pkts); #else printf("%lu pkts %lu", ap.aps_bytes, ap.aps_pkts); #endif @@ -249,6 +224,27 @@ int opts; printf("\t\tMode: %#x\tSBF: %#x\n", ra.rap_mode, ra.rap_sbf); printf("\t\tPorts:pl %hu, pr %hu, sr %hu\n", ra.rap_plport, ra.rap_prport, ra.rap_srport); + } else if (!strcmp(apr.apr_label, "ftp") && + (ap.aps_psiz == sizeof(ftp))) { + if (kmemcpy((char *)&ftp, (long)ap.aps_data, sizeof(ftp))) + return; + printf("\tFTP Proxy:\n"); + printf("\t\tpassok: %d\n", ftp.ftp_passok); + ftp.ftp_side[0].ftps_buf[FTP_BUFSZ - 1] = '\0'; + ftp.ftp_side[1].ftps_buf[FTP_BUFSZ - 1] = '\0'; + printf("\tClient:\n"); + printf("\t\trptr %p wptr %p seq %x junk %d\n", + ftp.ftp_side[0].ftps_rptr, ftp.ftp_side[0].ftps_wptr, + ftp.ftp_side[0].ftps_seq, ftp.ftp_side[0].ftps_junk); + printf("\t\tbuf ["); + printbuf(ftp.ftp_side[0].ftps_buf, FTP_BUFSZ, 1); + printf("]\n\tServer:\n"); + printf("\t\trptr %p wptr %p seq %x junk %d\n", + ftp.ftp_side[1].ftps_rptr, ftp.ftp_side[1].ftps_wptr, + ftp.ftp_side[1].ftps_seq, ftp.ftp_side[1].ftps_junk); + printf("\t\tbuf ["); + printbuf(ftp.ftp_side[1].ftps_buf, FTP_BUFSZ, 1); + printf("]\n"); } } @@ -291,14 +287,13 @@ ipnat_t *ipnat; void dostats(fd, opts) int fd, opts; { - natstat_t ns; + natstat_t ns, *nsp = &ns; + nat_t **nt[2], *np, nat; ipnat_t ipn; - nat_t **nt[2], *np, nat; - int i = 0; bzero((char *)&ns, sizeof(ns)); - if (!(opts & OPT_NODO) && ioctl(fd, SIOCGNATS, &ns) == -1) { + if (!(opts & OPT_NODO) && ioctl(fd, SIOCGNATS, &nsp) == -1) { perror("ioctl(SIOCGNATS)"); return; } @@ -308,6 +303,8 @@ int fd, opts; ns.ns_mapped[0], ns.ns_mapped[1]); printf("added\t%lu\texpired\t%lu\n", ns.ns_added, ns.ns_expire); + printf("no memory\t%lu\tbad nat\t%lu\n", + ns.ns_memfail, ns.ns_badnat); printf("inuse\t%lu\nrules\t%lu\n", ns.ns_inuse, ns.ns_rules); if (opts & OPT_VERBOSE) printf("table %p list %p\n", ns.ns_table, ns.ns_list); @@ -322,7 +319,8 @@ int fd, opts; } if (opts & OPT_HITS) printf("%d ", ipn.in_hits); - printnat(&ipn, opts & OPT_VERBOSE, (void *)ns.ns_list); + printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE), + (void *)ns.ns_list); ns.ns_list = ipn.in_next; } @@ -349,12 +347,19 @@ int fd, opts; printf("\n\tage %lu use %hu sumd %s/", nat.nat_age, nat.nat_use, getsumd(nat.nat_sumd[0])); - printf("%s pr %u bkt %d flags %x ", + printf("%s pr %u bkt %d/%d flags %x ", getsumd(nat.nat_sumd[1]), nat.nat_p, - i, nat.nat_flags); + (int)NAT_HASH_FN(nat.nat_inip.s_addr, + nat.nat_inport, + NAT_TABLE_SZ), + (int)NAT_HASH_FN(nat.nat_outip.s_addr, + nat.nat_outport, + NAT_TABLE_SZ), + nat.nat_flags); #ifdef USE_QUAD_T printf("bytes %qu pkts %qu", - nat.nat_bytes, nat.nat_pkts); + (unsigned long long)nat.nat_bytes, + (unsigned long long)nat.nat_pkts); #else printf("bytes %lu pkts %lu", nat.nat_bytes, nat.nat_pkts); @@ -373,60 +378,6 @@ int fd, opts; } -u_32_t hostmask(msk) -char *msk; -{ - int bits = -1; - u_32_t mask; - - if (!isdigit(*msk)) - return (u_32_t)-1; - if (strchr(msk, '.')) - return inet_addr(msk); - if (strchr(msk, 'x')) - return (u_32_t)strtol(msk, NULL, 0); - /* - * set x most significant bits - */ - for (mask = 0, bits = atoi(msk); bits; bits--) { - mask /= 2; - mask |= ntohl(inet_addr("128.0.0.0")); - } - mask = htonl(mask); - return mask; -} - - -/* - * returns an ip address as a long var as a result of either a DNS lookup or - * straight inet_addr() call - */ -u_32_t hostnum(host, resolved, linenum) -char *host; -int *resolved; -int linenum; -{ - struct hostent *hp; - struct netent *np; - - *resolved = 0; - if (!strcasecmp("any", host)) - return 0L; - if (isdigit(*host)) - return inet_addr(host); - - if (!(hp = gethostbyname(host))) { - if (!(np = getnetbyname(host))) { - *resolved = -1; - fprintf(stderr, "Line %d: can't resolve hostname: %s\n", linenum, host); - return 0; - } - return htonl(np->n_net); - } - return *(u_32_t *)hp->h_addr; -} - - void flushtable(fd, opts) int fd, opts; { @@ -434,15 +385,15 @@ int fd, opts; if (opts & OPT_FLUSH) { n = 0; - if (!(opts & OPT_NODO) && ioctl(fd, SIOCFLNAT, &n) == -1) + if (!(opts & OPT_NODO) && ioctl(fd, SIOCIPFFL, &n) == -1) perror("ioctl(SIOCFLNAT)"); else printf("%d entries flushed from NAT table\n", n); } if (opts & OPT_CLEAR) { - n = 0; - if (!(opts & OPT_NODO) && ioctl(fd, SIOCCNATL, &n) == -1) + n = 1; + if (!(opts & OPT_NODO) && ioctl(fd, SIOCIPFFL, &n) == -1) perror("ioctl(SIOCCNATL)"); else printf("%d entries flushed from NAT list\n", n); diff --git a/contrib/ipfilter/ipsend/ipsend.c b/contrib/ipfilter/ipsend/ipsend.c index 41d05ee..748abfb 100644 --- a/contrib/ipfilter/ipsend/ipsend.c +++ b/contrib/ipfilter/ipsend/ipsend.c @@ -12,7 +12,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipsend.c,v 2.1.2.2 1999/11/28 03:43:44 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ipsend.c,v 2.2 1999/12/04 03:37:05 darrenr Exp $"; #endif #include <stdio.h> #include <stdlib.h> diff --git a/contrib/ipfilter/ipsend/iptest.c b/contrib/ipfilter/ipsend/iptest.c index 3a0e39a..dffee98 100644 --- a/contrib/ipfilter/ipsend/iptest.c +++ b/contrib/ipfilter/ipsend/iptest.c @@ -12,7 +12,7 @@ */ #if !defined(lint) static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: iptest.c,v 2.1.2.2 1999/11/28 03:43:45 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: iptest.c,v 2.2 1999/12/04 03:37:05 darrenr Exp $"; #endif #include <stdio.h> #include <netdb.h> diff --git a/contrib/ipfilter/ipt.c b/contrib/ipfilter/ipt.c index ff251f1..34a35e9 100644 --- a/contrib/ipfilter/ipt.c +++ b/contrib/ipfilter/ipt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -54,19 +54,22 @@ #include "ipt.h" #if !defined(lint) -static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipt.c,v 2.1.2.1 2000/01/24 14:49:11 darrenr Exp $"; +static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ipt.c,v 2.6 2000/03/13 22:10:25 darrenr Exp $"; #endif extern char *optarg; extern struct frentry *ipfilter[2][2]; extern struct ipread snoop, etherf, tcpd, pcap, iptext, iphex; -extern struct ifnet *get_unit __P((char *)); +extern struct ifnet *get_unit __P((char *, int)); extern void init_ifp __P((void)); extern ipnat_t *natparse __P((char *, int)); extern int fr_running; int opts = 0; +#ifdef USE_INET6 +int use_inet6 = 0; +#endif int main __P((int, char *[])); int main(argc,argv) @@ -80,9 +83,14 @@ char *argv[]; ip_t *ip; int fd, i, dir = 0, c; - while ((c = getopt(argc, argv, "bdEHi:I:NoPr:STvX")) != -1) + while ((c = getopt(argc, argv, "6bdEHi:I:NoPr:STvX")) != -1) switch (c) { +#ifdef USE_INET6 + case '6' : + use_inet6 = 1; + break; +#endif case 'b' : opts |= OPT_BRIEF; break; @@ -175,7 +183,8 @@ char *argv[]; if (!(fr = natparse(line, linenum))) continue; i = IPL_EXTERN(ioctl)(IPL_LOGNAT, SIOCADNAT, - fr, FWRITE|FREAD); + (caddr_t)&fr, + FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, "iplioctl(ADNAT,%p,1) = %d\n", @@ -183,11 +192,12 @@ char *argv[]; } else { if (!(fr = parse(line, linenum))) continue; - i = IPL_EXTERN(ioctl)(0, SIOCADDFR, fr, + i = IPL_EXTERN(ioctl)(0, SIOCADAFR, + (caddr_t)&fr, FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, - "iplioctl(ADDFR,%p,1) = %d\n", + "iplioctl(ADAFR,%p,1) = %d\n", fr, i); } } @@ -208,7 +218,7 @@ char *argv[]; ip = (ip_t *)buf; while ((i = (*r->r_readip)((char *)buf, sizeof(buf), &iface, &dir)) > 0) { - ifp = iface ? get_unit(iface) : NULL; + ifp = iface ? get_unit(iface, ip->ip_v) : NULL; ip->ip_off = ntohs(ip->ip_off); ip->ip_len = ntohs(ip->ip_len); i = fr_check(ip, ip->ip_hl << 2, ifp, dir, (mb_t **)&buf); diff --git a/contrib/ipfilter/ipt.h b/contrib/ipfilter/ipt.h index 9184090..bdc6a29 100644 --- a/contrib/ipfilter/ipt.h +++ b/contrib/ipfilter/ipt.h @@ -1,10 +1,10 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. - * $Id: ipt.h,v 2.1 1999/08/04 17:30:08 darrenr Exp $ + * $Id: ipt.h,v 2.2 2000/03/13 22:10:25 darrenr Exp $ */ #ifndef __IPT_H__ diff --git a/contrib/ipfilter/kmem.c b/contrib/ipfilter/kmem.c index 1dd6890..ab90bba 100644 --- a/contrib/ipfilter/kmem.c +++ b/contrib/ipfilter/kmem.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -20,7 +20,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed"; -static const char rcsid[] = "@(#)$Id: kmem.c,v 2.1 1999/08/04 17:30:09 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: kmem.c,v 2.2 2000/03/13 22:10:25 darrenr Exp $"; #endif static int kmemfd = -1; diff --git a/contrib/ipfilter/kmem.h b/contrib/ipfilter/kmem.h index 33ba8da..d6ed3c4 100644 --- a/contrib/ipfilter/kmem.h +++ b/contrib/ipfilter/kmem.h @@ -1,10 +1,10 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. - * $Id: kmem.h,v 2.1 1999/08/04 17:30:10 darrenr Exp $ + * $Id: kmem.h,v 2.2 2000/03/13 22:10:25 darrenr Exp $ */ #ifndef __KMEM_H__ diff --git a/contrib/ipfilter/l4check/Makefile b/contrib/ipfilter/l4check/Makefile new file mode 100644 index 0000000..e7366b6 --- /dev/null +++ b/contrib/ipfilter/l4check/Makefile @@ -0,0 +1,10 @@ +# For Solaris +#LIBS=-lsocket -lnsl + +all: l4check + +l4check: l4check.c + $(CC) -g -I.. $(CFLAGS) $(LIBS) l4check.c -o $@ + +clean: + /bin/rm -f l4check diff --git a/contrib/ipfilter/l4check/http.check b/contrib/ipfilter/l4check/http.check new file mode 100644 index 0000000..56d93d9 --- /dev/null +++ b/contrib/ipfilter/l4check/http.check @@ -0,0 +1,2 @@ +GET / + diff --git a/contrib/ipfilter/l4check/http.ok b/contrib/ipfilter/l4check/http.ok new file mode 100644 index 0000000..2b5d2c1 --- /dev/null +++ b/contrib/ipfilter/l4check/http.ok @@ -0,0 +1 @@ +<HTML>
\ No newline at end of file diff --git a/contrib/ipfilter/l4check/l4check.c b/contrib/ipfilter/l4check/l4check.c new file mode 100644 index 0000000..6945b1c --- /dev/null +++ b/contrib/ipfilter/l4check/l4check.c @@ -0,0 +1,805 @@ +/* + * (C)Copyright March, 2000 - Darren Reed. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include <net/if.h> + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> + +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_nat.h" + +#include "ipf.h" + +extern char *optarg; + + +typedef struct l4cfg { + struct l4cfg *l4_next; + struct ipnat l4_nat; /* NAT rule */ + struct sockaddr_in l4_sin; /* remote socket to connect */ + time_t l4_last; /* when we last connected */ + int l4_alive; /* 1 = remote alive */ + int l4_fd; + int l4_rw; /* 0 = reading, 1 = writing */ + char *l4_rbuf; /* read buffer */ + int l4_rsize; /* size of buffer */ + int l4_rlen; /* how much used */ + char *l4_wptr; /* next byte to write */ + int l4_wlen; /* length yet to be written */ +} l4cfg_t; + + +l4cfg_t *l4list = NULL; +char *response = NULL; +char *probe = NULL; +l4cfg_t template; +int frequency = 20; +int ctimeout = 1; +int rtimeout = 1; +size_t plen = 0; +size_t rlen = 0; +int natfd = -1; +int opts = 0; + +#if defined(sun) && !defined(__svr4__) && !defined(__SVR4) +# define strerror(x) sys_errlist[x] +#endif + + +char *copystr(dst, src) +char *dst, *src; +{ + register char *s, *t, c; + register int esc = 0; + + for (s = src, t = dst; s && t && (c = *s++); ) + if (esc) { + esc = 0; + switch (c) + { + case 'n' : + *t++ = '\n'; + break; + case 'r' : + *t++ = '\r'; + break; + case 't' : + *t++ = '\t'; + break; + } + } else if (c != '\\') + *t++ = c; + else + esc = 1; + *t = '\0'; + return dst; +} + +void addnat(l4) +l4cfg_t *l4; +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ntohs(ipn->in_pmin)); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext)); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCADNAT, &ipn) == -1) + perror("ioctl(SIOCADNAT)"); + } +} + + +void delnat(l4) +l4cfg_t *l4; +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Remove NAT rule for %s/%#x,%u -> ", + inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) + perror("ioctl(SIOCRMNAT)"); + } +} + + +void connectl4(l4) +l4cfg_t *l4; +{ + l4->l4_rw = 1; + l4->l4_rlen = 0; + l4->l4_wlen = plen; + if (!l4->l4_wlen) { + l4->l4_alive = 1; + addnat(l4); + } else + l4->l4_wptr = probe; +} + + +void closel4(l4, dead) +l4cfg_t *l4; +int dead; +{ + close(l4->l4_fd); + l4->l4_fd = -1; + l4->l4_rw = -1; + if (dead && l4->l4_alive) { + l4->l4_alive = 0; + delnat(l4); + } +} + + +void connectfd(l4) +l4cfg_t *l4; +{ + if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno == EISCONN) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connected fd %d\n", + l4->l4_fd); + connectl4(l4); + return; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connect failed fd %d: %s\n", + l4->l4_fd, strerror(errno)); + closel4(l4, 1); + return; + } + l4->l4_rw = 1; +} + + +void writefd(l4) +l4cfg_t *l4; +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + n = l4->l4_wlen; + + i = send(fd, l4->l4_wptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Send on fd %d failed: %s\n", + fd, strerror(errno)); + closel4(l4, 1); + } else { + l4->l4_wptr += i; + l4->l4_wlen -= i; + if (l4->l4_wlen == 0) + l4->l4_rw = 0; + if (opts & OPT_VERBOSE) + fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); + } +} + + +void readfd(l4) +l4cfg_t *l4; +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + if (l4->l4_rsize) { + n = l4->l4_rsize - l4->l4_rlen; + ptr = l4->l4_rbuf + l4->l4_rlen; + } else { + n = sizeof(buf) - 1; + ptr = buf; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read %d bytes on fd %d to %p\n", + n, fd, ptr); + i = recv(fd, ptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read error on fd %d: %s\n", + fd, (i == 0) ? "EOF" : strerror(errno)); + closel4(l4, 1); + } else { + if (ptr == buf) + ptr[i] = '\0'; + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", + fd, i, i, i, ptr); + if (ptr != buf) { + l4->l4_rlen += i; + if (l4->l4_rlen >= l4->l4_rsize) { + if (!strncmp(response, l4->l4_rbuf, + l4->l4_rsize)) { + printf("%d: Good response\n", + fd); + if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + } + closel4(l4, 0); + } else { + if (opts & OPT_VERBOSE) + printf("%d: Bad response\n", + fd); + closel4(l4, 1); + } + } + } else if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + closel4(l4, 0); + } + } +} + + +int runconfig() +{ + int fd, opt, res, mfd, i; + struct timeval tv; + time_t now, now1; + fd_set rfd, wfd; + l4cfg_t *l4; + + mfd = 0; + opt = 1; + now = time(NULL); + + /* + * First, initiate connections that are closed, as required. + */ + for (l4 = l4list; l4; l4 = l4->l4_next) { + if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { + l4->l4_last = now; + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + continue; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, + sizeof(opt)); +#ifdef O_NONBLOCK + if ((res = fcntl(fd, F_GETFL, 0)) != -1) + fcntl(fd, F_SETFL, res | O_NONBLOCK); +#endif + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Connecting to %s,%d (fd %d)...", + inet_ntoa(l4->l4_sin.sin_addr), + ntohs(l4->l4_sin.sin_port), fd); + if (connect(fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno != EINPROGRESS) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "failed\n"); + perror("connect"); + close(fd); + fd = -1; + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "waiting\n"); + l4->l4_rw = -2; + } + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "connected\n"); + connectl4(l4); + } + l4->l4_fd = fd; + } + } + + /* + * Now look for fd's which we're expecting to read/write from. + */ + FD_ZERO(&rfd); + FD_ZERO(&wfd); + tv.tv_sec = MIN(rtimeout, ctimeout); + tv.tv_usec = 0; + + for (l4 = l4list; l4; l4 = l4->l4_next) + if (l4->l4_rw == 0) { + if (now - l4->l4_last > rtimeout) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read timeout\n", + l4->l4_fd); + closel4(l4, 1); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for read on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &rfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } else if ((l4->l4_rw == 1 && l4->l4_wlen) || + l4->l4_rw == -2) { + if ((l4->l4_rw == -2) && + (now - l4->l4_last > ctimeout)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, + "%d: connect timeout\n", + l4->l4_fd); + closel4(l4); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for write on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &wfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, + tv.tv_sec); + i = select(mfd + 1, &rfd, &wfd, NULL, &tv); + if (i == -1) { + perror("select"); + return -1; + } + + now1 = time(NULL); + + for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { + if (l4->l4_fd < 0) + continue; + if (FD_ISSET(l4->l4_fd, &rfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to read on fd %d\n", + l4->l4_fd); + readfd(l4); + i--; + } + + if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to write on fd %d\n", + l4->l4_fd); + writefd(l4); + i--; + } + } + return 0; +} + + +int gethostport(str, lnum, ipp, portp) +char *str; +int lnum; +u_32_t *ipp; +u_short *portp; +{ + struct servent *sp; + struct hostent *hp; + char *host, *port; + struct in_addr ip; + + host = str; + port = strchr(host, ','); + if (port) + *port++ = '\0'; + +#ifdef HAVE_INET_ATON + if (isdigit(*host) && inet_aton(host, &ip)) + *ipp = ip.s_addr; +#else + if (isdigit(*host)) + *ipp = inet_addr(host); +#endif + else { + if (!(hp = gethostbyname(host))) { + fprintf(stderr, "%d: can't resolve hostname: %s\n", + lnum, host); + return 0; + } + *ipp = *(u_32_t *)hp->h_addr; + } + + if (port) { + if (isdigit(*port)) + *portp = htons(atoi(port)); + else { + sp = getservbyname(port, "tcp"); + if (sp) + *portp = sp->s_port; + else { + fprintf(stderr, "%d: unknown service %s\n", + lnum, port); + return 0; + } + } + } else + *portp = 0; + return 1; +} + + +char *mapfile(file, sizep) +char *file; +size_t *sizep; +{ + struct stat sb; + caddr_t addr; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) { + perror("open(mapfile)"); + return NULL; + } + + if (fstat(fd, &sb) == -1) { + perror("fstat(mapfile)"); + close(fd); + return NULL; + } + + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (addr == (caddr_t)-1) { + perror("mmap(mapfile)"); + close(fd); + return NULL; + } + close(fd); + *sizep = sb.st_size; + return (char *)addr; +} + + +int readconfig(filename) +char *filename; +{ + char c, buf[512], *s, *t, *errtxt = NULL, *line; + int num, err = 0; + ipnat_t *ipn; + l4cfg_t *l4; + FILE *fp; + + fp = fopen(filename, "r"); + if (!fp) { + perror("open(configfile)"); + return -1; + } + + bzero((char *)&template, sizeof(template)); + template.l4_fd = -1; + template.l4_rw = -1; + template.l4_sin.sin_family = AF_INET; + ipn = &template.l4_nat; + ipn->in_flags = IPN_TCP|IPN_ROUNDR; + ipn->in_redir = NAT_REDIRECT; + + for (num = 1; fgets(buf, sizeof(buf), fp); num++) { + s = strchr(buf, '\n'); + if (!s) { + fprintf(stderr, "%d: line too long\n", num); + fclose(fp); + return -1; + } + + *s = '\0'; + + /* + * lines which are comments + */ + s = strchr(buf, '#'); + if (s) + *s = '\0'; + + /* + * Skip leading whitespace + */ + for (line = buf; (c = *line) && isspace(c); line++) + ; + if (!*line) + continue; + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Parsing: [%s]\n", line); + t = strtok(line, " \t"); + if (!t) + continue; + if (!strcasecmp(t, "interface")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } + + if (!strchr(t, ',')) { + fprintf(stderr, + "%d: local address,port missing\n", + num); + err = -1; + break; + } + + strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname)); + if (!gethostport(t, num, &ipn->in_outip, + &ipn->in_pmin)) { + errtxt = line; + err = -1; + break; + } + ipn->in_outmsk = 0xffffffff; + ipn->in_pmax = ipn->in_pmin; + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Interface %s %s/%#x port %u\n", + ipn->in_ifname, + inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ipn->in_pmin); + } else if (!strcasecmp(t, "remote")) { + if (!*ipn->in_ifname) { + fprintf(stderr, + "%d: ifname not set prior to remote\n", + num); + err = -1; + break; + } + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, ""); + if (!s || !t || strcasecmp(s, "server")) { + errtxt = line; + err = -1; + break; + } + + ipn->in_pnext = 0; + if (!gethostport(t, num, &ipn->in_inip, + &ipn->in_pnext)) { + errtxt = line; + err = -1; + break; + } + ipn->in_inmsk = 0xffffffff; + if (ipn->in_pnext == 0) + ipn->in_pnext = ipn->in_pmin; + + l4 = (l4cfg_t *)malloc(sizeof(*l4)); + if (!l4) { + fprintf(stderr, "%d: out of memory (%d)\n", + num, sizeof(*l4)); + err = -1; + break; + } + bcopy((char *)&template, (char *)l4, sizeof(*l4)); + l4->l4_sin.sin_addr = ipn->in_in[0]; + l4->l4_sin.sin_port = ipn->in_pnext; + l4->l4_next = l4list; + l4list = l4; + } else if (!strcasecmp(t, "connect")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + ctimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, "connect timeout %d\n", + ctimeout); + } else if (!strcasecmp(s, "frequency")) { + frequency = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "connect frequency %d\n", + frequency); + } else { + errtxt = line; + err = -1; + break; + } + } else if (!strcasecmp(t, "probe")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "string")) { + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + t = strtok(NULL, ""); + if (!t) { + fprintf(stderr, + "%d: No probe string\n", num); + err = -1; + break; + } + + probe = malloc(strlen(t)); + copystr(probe, t); + plen = strlen(probe); + if (opts & OPT_VERBOSE) + fprintf(stderr, "Probe string [%s]\n", + probe); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + probe = mapfile(t, &plen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Probe file %s len %u@%p\n", + t, plen, probe); + } + } else if (!strcasecmp(t, "response")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + rtimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "response timeout %d\n", + rtimeout); + } else if (!strcasecmp(s, "string")) { + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = strdup(strtok(NULL, "")); + rlen = strlen(response); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response string [%s]\n", + response); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = mapfile(t, &rlen); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response file %s len %u@%p\n", + t, rlen, response); + } + } else { + errtxt = line; + err = -1; + break; + } + } + + if (errtxt) + fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); + fclose(fp); + return err; +} + + +void usage(prog) +char *prog; +{ + fprintf(stderr, "Usage: %s -f <configfile>\n", prog); + exit(1); +} + + +int main(argc, argv) +int argc; +char *argv[]; +{ + char *config = NULL; + int c; + + while ((c = getopt(argc, argv, "f:nv")) != -1) + switch (c) + { + case 'f' : + config = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (config == NULL) + usage(argv[0]); + + if (readconfig(config)) + exit(1); + + if (!l4list) { + fprintf(stderr, "No remote servers, exiting."); + exit(1); + } + + if (!(opts & OPT_DONOTHING)) { + natfd = open(IPL_NAT, O_RDWR); + if (natfd == -1) { + perror("open(IPL_NAT)"); + exit(1); + } + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Starting...\n"); + while (runconfig() == 0) + ; +} diff --git a/contrib/ipfilter/l4check/l4check.conf b/contrib/ipfilter/l4check/l4check.conf new file mode 100644 index 0000000..d000e9f --- /dev/null +++ b/contrib/ipfilter/l4check/l4check.conf @@ -0,0 +1,31 @@ +# +# NOTE: ORDER IS IMPORTANT IN THIS FILE +# +# Interface to do the redirections on and the IP address which will be +# targeted. +# +interface nf0 192.168.1.1,2100 +# +connect timeout 1 +connect frequency 20 +# +# If no probe string is specified, a successful connection implies the +# server is still alive. +# +probe string GET /\n\n +#probe file http.check +# +response timeout 4 +response string <HTML> +#response file http.ok +# +# Here we have multiple servers, listed because that's what happens to be +# used for testing of connect timeoutes, read timeouts, success and things +# which don't connect. +# +remote server 192.168.1.2,23 +remote server 192.168.1.2,2101 +remote server 192.168.1.3,25 +remote server 192.168.1.254,8000 +remote server 192.168.1.1,9 +# diff --git a/contrib/ipfilter/man/Makefile b/contrib/ipfilter/man/Makefile index 5e029de..c83337a 100644 --- a/contrib/ipfilter/man/Makefile +++ b/contrib/ipfilter/man/Makefile @@ -17,6 +17,7 @@ install: $(INSTALL) -m 0644 -c -o root -g bin ipf.5 $(MANDIR)/man5 $(INSTALL) -m 0644 -c -o root -g bin ipnat.5 $(MANDIR)/man5 $(INSTALL) -m 0644 -c -o root -g bin ipf.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipfs.8 $(MANDIR)/man8 $(INSTALL) -m 0644 -c -o root -g bin ipmon.8 $(MANDIR)/man8 $(INSTALL) -m 0644 -c -o root -g bin ipfstat.8 $(MANDIR)/man8 @echo "Remember to rebuild the whatis database." diff --git a/contrib/ipfilter/man/ipf.8 b/contrib/ipfilter/man/ipf.8 index e573b86..ea92e80 100644 --- a/contrib/ipfilter/man/ipf.8 +++ b/contrib/ipfilter/man/ipf.8 @@ -4,7 +4,7 @@ ipf \- alters packet filtering lists for IP packet input and output .SH SYNOPSIS .B ipf [ -.B \-AdDEInoPrsUvVyzZ +.B \-6AdDEInoPrsUvVyzZ ] [ .B \-l <block|pass|nomatch> @@ -30,6 +30,9 @@ Rules are added to the end of the internal lists, matching the order in which they appear when given to \fBipf\fP. .SH OPTIONS .TP +.B \-6 +This option is required to parse IPv6 rules and to have them loaded. +.TP .B \-A Set the list to make changes to the active list (default). .TP diff --git a/contrib/ipfilter/man/ipfs.8 b/contrib/ipfilter/man/ipfs.8 new file mode 100644 index 0000000..a120744 --- /dev/null +++ b/contrib/ipfilter/man/ipfs.8 @@ -0,0 +1,119 @@ +.TH IPFS 8 +.SH NAME +ipfs \- saves and restores information for NAT and state tables. +.SH SYNOPSIS +.B ipfs +[-nv] -l +.PP +.B ipfs +[-nv] -u +.PP +.B ipfs +[-nv] [ +.B \-d +<\fIdirname\fP> +] -R +.PP +.B ipfs +[-nv] [ +.B \-d +<\fIdirname\fP> +] -W +.PP +.B ipfs +[-nNSv] [ +.B \-f +<\fIfilename\fP> +] -r +.PP +.B ipfs +[-nNSv] [ +.B \-f +<\fIfilename\fP> +] -w +.PP +.B ipfs +[-nNSv] +.B \-f +<\fIfilename\fP> +.B \-i +<if1>,<if2> +.SH DESCRIPTION +.PP +\fBipfs\fP allows state information created for NAT entries and rules using +\fIkeep state\fP to be locked (modification prevented) and then saved to disk, +allowing for the system to experience a reboot, followed by the restoration +of that information, resulting in connections not being interrupted. +.SH OPTIONS +.TP +.B \-d +Change the default directory used with +.B \-R +and +.B \-W +options for saving state information. +.B \-n +Don't actually take any action that would effect information stored in +the kernel or on disk. +.TP +.B \-v +Provides a verbose description of what's being done. +.TP +.B \-N +Operate on NAT information. +.TP +.B \-S +Operate on filtering state information. +.TP +.B \-u +Unlock state tables in the kernel. +.TP +.B \-l +Unlock state tables in the kernel. +.TP +.B \-r +Read information in from the specified file and load it into the +kernel. This requires the state tables to have already been locked +and does not change the lock once comlete. +.TP +.B \-w +Write information out to the specified file and from the kernel. +This requires the state tables to have already been locked +and does not change the lock once comlete. +.TP +.B \-R +Restores all saved state information, if any, from two files, +\fIipstate.ipf\fP and \fIipnat.ipf\fP, stored in the \fI/var/db/ipf\fP +directory unless otherwise specified the +.B \-d +option is used. The state tables are locked at the beginning of this +operation and unlocked once complete. +.TP +.B \-W +Saves in-kernel state information, if any, out to two files, +\fIipstate.ipf\fP and \fIipnat.ipf\fP, stored in the \fI/var/db/ipf\fP +directory unless otherwise specified the +.B \-d +option is used. The state tables are locked at the beginning of this +operation and unlocked once complete. +.DT +.SH FILES +/var/db/ipf/ipstate.ipf +.br +/var/db/ipf/ipnat.ipf +.br +/dev/ipl +.br +/dev/ipstate +.br +/dev/ipnat +.SH SEE ALSO +ipf(8), ipl(4), ipmon(8), ipnat(8) +.SH DIAGNOSTICS +.PP +Perhaps the -W and -R operations should set the locking but rather than +undo it, restore it to what it was previously. Fragment table information +is currently not saved. +.SH BUGS +.PP +If you find any, please send email to me at darrenr@pobox.com diff --git a/contrib/ipfilter/man/ipfstat.8 b/contrib/ipfilter/man/ipfstat.8 index e39ed94..d1f2c3c 100644 --- a/contrib/ipfilter/man/ipfstat.8 +++ b/contrib/ipfilter/man/ipfstat.8 @@ -4,7 +4,27 @@ ipfstat \- reports on packet filter statistics and filter list .SH SYNOPSIS .B ipfstat [ -.B \-aAfghIinosv +.B \-6aAfghIinosv +] [ +.B \-d +<device> +] + +.B ipfstat -t +[ +.B \-C +] [ +.B \-D +<addrport> +] [ +.B \-P +<protocol> +] [ +.B \-S +<addrport> +] [ +.B \-T +<refresh time> ] [ .B \-d <device> @@ -21,15 +41,32 @@ is to retrieve and display the accumulated statistics which have been accumulated over time as the kernel has put packets through the filter. .SH OPTIONS .TP +.B \-6 +Display filter lists for IPv6, if available. +.TP .B \-a Display the accounting filter list and show bytes counted against each rule. .TP .B \-A Display packet authentication statistics. +.TP +.B \-C +This option is only valid in combination with \fB\-t\fP. +Display "closed" states as well in the top. Normally, a TCP connection is +not displayed when it reaches the CLOSE_WAIT protocol state. With this +option enabled, all state entries are displayed. .TP .BR \-d \0<device> Use a device other than \fB/dev/ipl\fP for interfacing with the kernel. .TP +.BR \-D \0<addrport> +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries whose destination IP address and port +match the addport argument. The addrport specification is of the form +ipaddress[,port]. The ipaddress and port should be either numerical or the +string "any" (specifying any ip address resp. any port). If the \fB\-D\fP +option is not specified, it defaults to "\fB\-D\fP any,any". +.TP .B \-f Show fragment state information (statistics) and held state information (in the kernel) if any is present. @@ -54,10 +91,38 @@ Show the "rule number" for each rule as it is printed. .B \-o Display the filter list used for the output side of the kernel IP processing. .TP +.BR \-P \0<protocol> +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries that match a specific protocol. The +argument can be a protocol name (as defined in \fB/etc/protocols\fP) or a +protocol number. If this option is not specified, state entries for any +protocol are specified. +.TP .B \-s Show packet/flow state information (statistics) and held state information (in the kernel) if any is present. .TP +.BR \-S \0<addrport> +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries whose source IP address and port match +the addport argument. The addrport specification is of the form +ipaddress[,port]. The ipaddress and port should be either numerical or the +string "any" (specifying any ip address resp. any port). If the \fB\-S\fP +option is not specified, it defaults to "\fB\-S\fP any,any". +.TP +.B \-t +Show the state table in a way similar to they way \fBtop(1)\fP shows the process +table. States can be sorted using a number of different ways. This options +requires \fBncurses(3)\fP and needs to be compiled in. It may not be available on +all operating systems. See below, for more information on the keys that can +be used while ipfstat is in top mode. +.TP +.BR \-T \0<refreshtime> +This option is only valid in combination with \fB\-t\fP. Specifies how often +the state top display should be updated. The refresh time is the number of +seconds between an update. Any postive integer can be used. The default (and +minimal update time) is 1. +.TP .B \-v Turn verbose mode on. Displays more debugging information. .SH SYNOPSIS @@ -69,6 +134,35 @@ parameters are present. When supplied with either \fB\-i\fP or \fB\-o\fP, it will retrieve and display the appropriate list of filter rules currently installed and in use by the kernel. +.SH STATE TOP +Using the \fB\-t\fP option \fBipfstat\fP will enter the state top mode. In +this mode the state table is displayed similar to the way \fBtop\fP displays +the process table. The \fB\-C\fP, \fB\-D\fP, \fB\-P\fP, \fB\-S\fP and\fB\-T\fP +commandline options can be used to restrict the state entries that will be +shown and to specify the frequency of display updates. +.PP +In state top mode, the following keys can be used to influence the displayed +information. \fBl\fP can be used to redraw the screen. \fBq\fP is used to +quit the program. \fBs\fP can be used to change the sorting criterion and +\fBr\fP can be used to reverse the sorting criterion. +.PP +States can be sorted by protocol number, by number of IP packets, by number +of bytes and by time-to-live of the state entry. The default is to sort by +the number of bytes. States are sorted in descending order, but you can use +the \fBr\fP key to sort them in ascending order. +.SH STATE TOP LIMITATIONS +It is currently not possible to interactively change the source, destination +and protocol filters or the refreh frequency. This must be done from the +command line. +.PP +The screen must have at least 80 columns. This is however not checked. +.PP +Only the first X-5 entries that match the sort and filter criteria are +displayed (where X is the number of rows on the display. There is no way to +see more entries. +.PP +No support for IPv6 +.PP .SH FILES /dev/kmem .br diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8 index 5e3bff1..61d6575 100644 --- a/contrib/ipfilter/man/ipmon.8 +++ b/contrib/ipfilter/man/ipmon.8 @@ -4,13 +4,15 @@ ipmon \- monitors /dev/ipl for logged packets .SH SYNOPSIS .B ipmon [ -.B \-aFhnstvxX +.B \-aDFhnpstvxX +] [ +.B "\-N <device>" ] [ .B "\-o [NSI]" ] [ .B "\-O [NSI]" ] [ -.B "\-N <device>" +.B "\-P <pidfile>" ] [ .B "\-S <device>" ] [ @@ -74,6 +76,10 @@ In order for \fBipmon\fP to properly work, the kernel option Open all of the device logfiles for reading log entries from. All entries are displayed to the same output 'device' (stderr or syslog). .TP +.B \-D +Cause ipmon to turn itself into a daemon. Using subshells or backgrounding +of ipmon is not required to turn it into an orphan so it can run indefinately. +.TP .B "\-f <device>" specify an alternative device/file from which to read the log information for normal IP Filter log records. @@ -99,14 +105,19 @@ Specify which log files you do not wish to read from. This is most sensibly used with the \fB-a\fP. Letters available as paramters to this are the same as for \fB-o\fP. .TP +.B \-p +Cause the port number in log messages to always be printed as a number and +never attempt to look it up as from \fI/etc/services\fP, etc. +.TP +.B \-P <pidfile> +Write the pid of the ipmon process to a file. By default this is +\fI//etc/opt/ipf/ipmon.pid\fP (Solaris), \fI/var/run/ipmon.pid\fP (44BSD +or later) or \fI/etc/ipmon.pid\fP for all others. +.TP .B \-s Packet information read in will be sent through syslogd rather than saved to a file. The default facility when compiled and installed is \fBlocal0\fP. The following levels are used: -.TP -.B "\-S <device>" -Set the logfile to be opened for reading state log records from to <device>. -.TP .IP .B LOG_INFO \- packets logged using the "log" keyword as the action rather @@ -122,6 +133,9 @@ than pass or block. \- packets which have been logged and which can be considered "short". .TP +.B "\-S <device>" +Set the logfile to be opened for reading state log records from to <device>. +.TP .B \-t read the input file/device in a manner akin to tail(1). .TP @@ -143,6 +157,8 @@ recorded data. /dev/ipnat .br /dev/ipstate +.br +/etc/services .SH SEE ALSO ipl(4), ipf(8), ipfstat(8), ipnat(8) .SH BUGS diff --git a/contrib/ipfilter/man/ipnat.5 b/contrib/ipfilter/man/ipnat.5 index e15fa0d..ec53059 100644 --- a/contrib/ipfilter/man/ipnat.5 +++ b/contrib/ipfilter/man/ipnat.5 @@ -8,14 +8,24 @@ The format for files accepted by ipnat is described by the following grammar: ipmap :: = mapblock | redir | map . map ::= mapit ifname ipmask "->" ipmask [ mapport ] . +map ::= mapit ifname fromto "->" ipmask [ mapport ] . mapblock ::= "map-block" ifname ipmask "->" ipmask [ ports ] . -redir ::= "rdr" ifname [ fromspec ] ipmask "->" ip [ ports ] [ tcpudp ] . +redir ::= "rdr" ifname ipmask dport "->" ip [ "," ip ] [ ports ] options . + +dport ::= "port" portnum [ "-" portnum ] . ports ::= "ports" numports | "auto" . mapit ::= "map" | "bimap" . +fromto ::= "from" object "to" object . ipmask ::= ip "/" bits | ip "/" mask | ip "netmask" mask . mapport ::= "portmap" tcpudp portnumber ":" portnumber . +options ::= [ tcpudp ] [ rr ] . + +object = addr [ port-comp | port-range ] . +addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +port-comp = "port" compare port-num . +port-range = "port" port-num range port-num . -fromspec ::= "from" ip "/" ipmask . +rr ::= "round-robin" . tcpudp ::= "tcp" | "udp" | "tcp/udp" . portnumber ::= number { numbers } | "auto" . ifname ::= 'A' - 'Z' { 'A' - 'Z' } numbers . @@ -40,7 +50,7 @@ When remapping TCP and UDP packets, it is also possible to change the source port number. Either TCP or UDP or both can be selected by each rule, with a range of port numbers to remap into given as \fBport-number:port-number\fP. .SH COMMANDS -There are found commands recognised by IP Filter's NAT code: +There are four commands recognised by IP Filter's NAT code: .TP .B map that is used for mapping one address or network to another in an unregulated @@ -60,10 +70,26 @@ squeeze the addresses to be translated into the destination range. .SH MATCHING .PP For basic NAT and redirection of packets, the address subject to change is used -along with its protocol to check if a packet should be altered. In the case -of redirects, it is also possible to select packets on a source address basis -using the \fBfrom\fP keyword, as well as the manditory destination port. The -packet \fImatching\fP part of the rule is to the left of the "->" in each rule. +along with its protocol to check if a packet should be altered. The packet +\fImatching\fP part of the rule is to the left of the "->" in each rule. +.PP +Matching of packets has now been extended to allow more complex compares. +In place of the address which is to be translated, an IP address and port +number comparison can be made using the same expressions available with +\fBipf\fP. A simple NAT rule could be written as: +.LP +.nf +map de0 10.1.0.0/16 -> 201.2.3.4/32 +.fi +.LP +or as +.LP +.nf +map de0 from 10.1.0.0/16 to any -> 201.2.3.4/32 +.fi +.LP +Only IP address and port numbers can be compared against. This is available +with all NAT rules. .SH TRANSLATION .PP To the right of the "->" is the address and port specificaton which will be @@ -93,6 +119,30 @@ True transparent proxying should be performed using the redirect (\fBrdr\fP) rules directing ports to localhost (127.0.0.1) with the proxy program doing a lookup through \fB/dev/ipnat\fP to determine the real source and address of the connection. +.SH LOAD-BALANCING +.PP +Two options for use with \fBrdr\fP are available to support primitive, +\fIround-robin\fP based load balancing. The first option allows for a +\fBrdr\fP to specify a second destination, as follows: +.LP +.nf +rdr le0 203.1.2.3/32 port 80 -> 203.1.2.3,203.1.2.4 port 80 tcp +.fi +.LP +This would send alternate connections to either 203.1.2.3 or 203.1.2.4. +In scenarios where the load is being spread amongst a larger set of +servers, you can use: +.LP +.nf +rdr le0 203.1.2.3/32 port 80 -> 203.1.2.3,203.1.2.4 port 80 tcp round-robin +rdr le0 203.1.2.3/32 port 80 -> 203.1.2.5 port 80 tcp round-robin +.fi +.LP +In this case, a connection will be redirected to 203.1.2.3, then 203.1.2.4 +and then 203.1.2.5 before going back to 203.1.2.3. In accomplishing this, +the rule is removed from the top of the list and added to the end, +automatically, as required. This will not effect the display of rules +using "ipnat -l", only the internal application order. .SH EXAMPLES .PP This section deals with the \fBmap\fP command and it's variations. diff --git a/contrib/ipfilter/man/mkfilters.1 b/contrib/ipfilter/man/mkfilters.1 index 52c7a8f..b5fd9dc 100644 --- a/contrib/ipfilter/man/mkfilters.1 +++ b/contrib/ipfilter/man/mkfilters.1 @@ -1,4 +1,4 @@ -.TH IPF 1 +.TH MKFILTERS 1 .SH NAME mkfilters \- generate a minimal firewall ruleset for ipfilter .SH SYNOPSIS diff --git a/contrib/ipfilter/misc.c b/contrib/ipfilter/misc.c index bd89be0..38b385d 100644 --- a/contrib/ipfilter/misc.c +++ b/contrib/ipfilter/misc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -52,7 +52,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)misc.c 1.3 2/4/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: misc.c,v 2.1 1999/08/04 17:30:11 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: misc.c,v 2.2 2000/03/13 22:10:25 darrenr Exp $"; #endif extern int opts; diff --git a/contrib/ipfilter/ml_ipl.c b/contrib/ipfilter/ml_ipl.c index 4408a75..0ee29cb 100644 --- a/contrib/ipfilter/ml_ipl.c +++ b/contrib/ipfilter/ml_ipl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given diff --git a/contrib/ipfilter/mlf_ipl.c b/contrib/ipfilter/mlf_ipl.c index 3ae9a78..f12e989 100644 --- a/contrib/ipfilter/mlf_ipl.c +++ b/contrib/ipfilter/mlf_ipl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -74,6 +74,7 @@ #include "netinet/ip_nat.h" #include "netinet/ip_auth.h" #include "netinet/ip_frag.h" +#include "netinet/ip_proxy.h" #if !defined(VOP_LEASE) && defined(LEASE_CHECK) @@ -91,6 +92,7 @@ SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); 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_tcpclosewait, CTLFLAG_RW, @@ -119,6 +121,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, &fr_authused, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, &fr_defaultauthage, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, + &ippr_ftp_pasvonly, 0, ""); #endif #ifdef DEVFS diff --git a/contrib/ipfilter/mlfk_ipl.c b/contrib/ipfilter/mlfk_ipl.c new file mode 100644 index 0000000..4412960 --- /dev/null +++ b/contrib/ipfilter/mlfk_ipl.c @@ -0,0 +1,181 @@ +/* + * Copyright 1999 Guido van Rooij. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: mlfk_ipl.c,v 2.1.2.1 2000/04/26 12:17:24 darrenr Exp $ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> + + +#include <netinet/ipl.h> +#include <netinet/ip_compat.h> +#include <netinet/ip_fil.h> +#include <netinet/ip_state.h> +#include <netinet/ip_nat.h> +#include <netinet/ip_auth.h> +#include <netinet/ip_frag.h> + +static dev_t ipf_devs[IPL_LOGMAX + 1]; + +SYSCTL_DECL(_net_inet); +SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW, + &fr_tcpidletimeout, 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, + &fr_tcplastack, 0, ""); +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_udptimeout, CTLFLAG_RW, + &fr_udptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, + &fr_icmptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, + &fr_defnatage, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, + &fr_ipfrttl, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW, + &ipl_unreach, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, + &fr_running, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, + &fr_authsize, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, + &fr_authused, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, + &fr_defaultauthage, 0, ""); + +#define CDEV_MAJOR 79 +static struct cdevsw ipl_cdevsw = { + /* open */ iplopen, + /* close */ iplclose, + /* read */ iplread, + /* write */ nowrite, + /* ioctl */ iplioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "ipl", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ 0, + /* bmaj */ -1 +}; + +static int +ipfilter_modevent(module_t mod, int type, void *unused) +{ + char *c; + int i, error = 0; + + switch (type) { + case MOD_LOAD : + + error = iplattach(); + if (error) + break; + + c = NULL; + for(i=strlen(IPL_NAME); i>0; i--) + if (IPL_NAME[i] == '/') { + c = &IPL_NAME[i+1]; + break; + } + if (!c) + c = IPL_NAME; + ipf_devs[IPL_LOGIPF] = + make_dev(&ipl_cdevsw, IPL_LOGIPF, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_NAT); i>0; i--) + if (IPL_NAT[i] == '/') { + c = &IPL_NAT[i+1]; + break; + } + if (!c) + c = IPL_NAT; + ipf_devs[IPL_LOGNAT] = + make_dev(&ipl_cdevsw, IPL_LOGNAT, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_STATE); i>0; i--) + if (IPL_STATE[i] == '/') { + c = &IPL_STATE[i+1]; + break; + } + if (!c) + c = IPL_STATE; + ipf_devs[IPL_LOGSTATE] = + make_dev(&ipl_cdevsw, IPL_LOGSTATE, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_AUTH); i>0; i--) + if (IPL_AUTH[i] == '/') { + c = &IPL_AUTH[i+1]; + break; + } + if (!c) + c = IPL_AUTH; + ipf_devs[IPL_LOGAUTH] = + make_dev(&ipl_cdevsw, IPL_LOGAUTH, 0, 0, 0600, c); + + break; + case MOD_UNLOAD : + destroy_dev(ipf_devs[IPL_LOGIPF]); + destroy_dev(ipf_devs[IPL_LOGNAT]); + destroy_dev(ipf_devs[IPL_LOGSTATE]); + destroy_dev(ipf_devs[IPL_LOGAUTH]); + error = ipldetach(); + break; + default: + error = EINVAL; + break; + } + return error; +} + +static moduledata_t ipfiltermod = { + IPL_VERSION, + ipfilter_modevent, + 0 +}; +DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); diff --git a/contrib/ipfilter/mli_ipl.c b/contrib/ipfilter/mli_ipl.c index dce52fc..0630bb4 100644 --- a/contrib/ipfilter/mli_ipl.c +++ b/contrib/ipfilter/mli_ipl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * (C)opyright 1997 by Marc Boucher. * * Redistribution and use in source and binary forms are permitted @@ -49,7 +49,7 @@ unsigned IPL_EXTERN(devflag) = D_MP; char *IPL_EXTERN(mversion) = M_VERSION; #endif -kmutex_t ipl_mutex, ipf_mutex, ipfi_mutex, ipf_rw; +kmutex_t ipl_mutex, ipf_mutex, ipfi_mutex, ipf_rw, ipf_hostmap; kmutex_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; int (*fr_checkp) __P((struct ip *, int, void *, int, mb_t **)); @@ -313,14 +313,14 @@ nifattach() for (f = ipfilter[0][0]; f; f = f->fr_next) { if ((f->fr_ifa == (struct ifnet *)-1)) { if (f->fr_ifname[0] && - (GETUNIT(f->fr_ifname) == ifp)) + (GETUNIT(f->fr_ifname, 4) == ifp)) f->fr_ifa = ifp; } } for (f = ipfilter[1][0]; f; f = f->fr_next) { if ((f->fr_ifa == (struct ifnet *)-1)) { if (f->fr_ifname[0] && - (GETUNIT(f->fr_ifname) == ifp)) + (GETUNIT(f->fr_ifname, 4) == ifp)) f->fr_ifa = ifp; } } @@ -329,7 +329,7 @@ nifattach() for (np = nat_list; np; np = np->in_next) { if ((np->in_ifp == (void *)-1)) { if (np->in_ifname[0] && - (GETUNIT(np->in_ifname) == ifp)) + (GETUNIT(np->in_ifname, 4) == ifp)) np->in_ifp = (void *)ifp; } } @@ -539,6 +539,7 @@ IPL_EXTERN(unload)(void) LOCK_DEALLOC(ipf_rw.l); LOCK_DEALLOC(ipf_auth.l); LOCK_DEALLOC(ipf_natfrag.l); + LOCK_DEALLOC(ipf_hostmap.l); LOCK_DEALLOC(ipf_nat.l); LOCK_DEALLOC(ipf_state.l); LOCK_DEALLOC(ipf_frag.l); @@ -561,6 +562,7 @@ IPL_EXTERN(init)(void) ipf_frag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); ipf_state.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); ipf_nat.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_hostmap.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); ipf_natfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); ipf_auth.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); ipf_rw.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); @@ -568,7 +570,7 @@ IPL_EXTERN(init)(void) if (!ipfi_mutex.l || !ipf_mutex.l || !ipf_frag.l || !ipf_state.l || !ipf_nat.l || !ipf_natfrag.l || !ipf_auth.l || !ipf_rw.l || - !ipl_mutex.l) + !ipl_mutex.l || !ipf_hostmap.l) panic("IP Filter: LOCK_ALLOC failed"); #ifdef IPFILTER_LKM diff --git a/contrib/ipfilter/mln_ipl.c b/contrib/ipfilter/mln_ipl.c index 47ed9e5..777ca9f 100644 --- a/contrib/ipfilter/mln_ipl.c +++ b/contrib/ipfilter/mln_ipl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given diff --git a/contrib/ipfilter/mls_ipl.c b/contrib/ipfilter/mls_ipl.c index 58f2ded..391b814 100644 --- a/contrib/ipfilter/mls_ipl.c +++ b/contrib/ipfilter/mls_ipl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -41,8 +41,8 @@ #if !defined(lint) -static const char sccsid[] = "@(#)mls_ipl.c 2.6 10/15/95 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: mls_ipl.c,v 2.1 1999/08/04 17:30:14 darrenr Exp $"; +static const char sccsid[] = "@(#)mls_ipl.c 2.6 10/15/95 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: mls_ipl.c,v 2.2 2000/03/13 22:10:26 darrenr Exp $"; #endif extern int ipldetach __P((void)); diff --git a/contrib/ipfilter/natparse.c b/contrib/ipfilter/natparse.c index 23f7f57..1069dbd 100644 --- a/contrib/ipfilter/natparse.c +++ b/contrib/ipfilter/natparse.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -43,6 +43,7 @@ #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" +#include "ipf.h" #if defined(sun) && !SOLARIS2 # define STRERROR(x) sys_errlist[x] @@ -53,7 +54,7 @@ extern char *sys_errlist[]; #if !defined(lint) static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] = "@(#)$Id: natparse.c,v 1.2.2.1 1999/11/20 22:50:30 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: natparse.c,v 1.17.2.1 2000/04/28 18:08:00 darrenr Exp $"; #endif @@ -62,27 +63,17 @@ static const char rcsid[] = "@(#)$Id: natparse.c,v 1.2.2.1 1999/11/20 22:50:30 d #endif extern int countbits __P((u_32_t)); -extern u_32_t hostnum __P((char *, int *, int)); +extern char *proto; ipnat_t *natparse __P((char *, int)); void printnat __P((ipnat_t *, int, void *)); void natparsefile __P((int, char *, int)); -u_32_t n_hostmask __P((char *)); -u_short n_portnum __P((char *, char *, int)); void nat_setgroupmap __P((struct ipnat *)); -#define OPT_REM 1 -#define OPT_NODO 2 -#define OPT_STAT 4 -#define OPT_LIST 8 -#define OPT_VERBOSE 16 -#define OPT_FLUSH 32 -#define OPT_CLEAR 64 - -void printnat(np, verbose, ptr) +void printnat(np, opts, ptr) ipnat_t *np; -int verbose; +int opts; void *ptr; { struct protoent *pr; @@ -92,16 +83,16 @@ void *ptr; switch (np->in_redir) { case NAT_REDIRECT : - printf("rdr "); + printf("rdr"); break; case NAT_MAP : - printf("map "); + printf("map"); break; case NAT_MAPBLK : - printf("map-block "); + printf("map-block"); break; case NAT_BIMAP : - printf("bimap "); + printf("bimap"); break; default : fprintf(stderr, "unknown value for in_redir: %#x\n", @@ -109,25 +100,46 @@ void *ptr; break; } + printf(" %s ", np->in_ifname); + + if (np->in_flags & IPN_FILTER) { + printf("from "); + if (np->in_redir == NAT_REDIRECT) + printhostmask(4, (u_32_t *)&np->in_srcip, + (u_32_t *)&np->in_srcmsk); + else + printhostmask(4, (u_32_t *)&np->in_inip, + (u_32_t *)&np->in_inmsk); + if (np->in_scmp) + printportcmp(np->in_p, &np->in_tuc.ftu_src); + + printf(" to "); + if (np->in_redir == NAT_REDIRECT) + printhostmask(4, (u_32_t *)&np->in_inip, + (u_32_t *)&np->in_inmsk); + else + printhostmask(4, (u_32_t *)&np->in_srcip, + (u_32_t *)&np->in_srcmsk); + if (np->in_dcmp) + printportcmp(np->in_p, &np->in_tuc.ftu_dst); + } + if (np->in_redir == NAT_REDIRECT) { - printf("%s ", np->in_ifname); - if (np->in_src[0].s_addr || np->in_src[1].s_addr) { - printf("from %s",inet_ntoa(np->in_src[0])); - bits = countbits(np->in_src[1].s_addr); + if (!(np->in_flags & IPN_FILTER)) { + printf("%s", inet_ntoa(np->in_out[0])); + bits = countbits(np->in_out[1].s_addr); if (bits != -1) printf("/%d ", bits); else - printf("/%s ", inet_ntoa(np->in_src[1])); + printf("/%s ", inet_ntoa(np->in_out[1])); } - printf("%s",inet_ntoa(np->in_out[0])); - bits = countbits(np->in_out[1].s_addr); - if (bits != -1) - printf("/%d ", bits); - else - printf("/%s ", inet_ntoa(np->in_out[1])); if (np->in_pmin) printf("port %d ", ntohs(np->in_pmin)); + if (np->in_pmax != np->in_pmin) + printf("- %d ", ntohs(np->in_pmax)); printf("-> %s", inet_ntoa(np->in_in[0])); + if (np->in_flags & IPN_SPLIT) + printf(",%s", inet_ntoa(np->in_in[1])); if (np->in_pnext) printf(" port %d", ntohs(np->in_pnext)); if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) @@ -136,21 +148,25 @@ void *ptr; printf(" tcp"); else if ((np->in_flags & IPN_UDP) == IPN_UDP) printf(" udp"); + if (np->in_flags & IPN_ROUNDR) + printf(" round-robin"); printf("\n"); - if (verbose) - printf("\t%p %lu %x %u %p %d\n", np->in_ifp, - np->in_space, np->in_flags, np->in_pnext, np, + if (opts & OPT_DEBUG) + printf("\t%p %lu %#x %u %p %d\n", np->in_ifp, + np->in_space, np->in_flags, np->in_pmax, np, np->in_use); } else { np->in_nextip.s_addr = htonl(np->in_nextip.s_addr); - printf("%s %s/", np->in_ifname, inet_ntoa(np->in_in[0])); - bits = countbits(np->in_in[1].s_addr); - if (bits != -1) - printf("%d ", bits); - else - printf("%s", inet_ntoa(np->in_in[1])); + if (!(np->in_flags & IPN_FILTER)) { + printf("%s/", inet_ntoa(np->in_in[0])); + bits = countbits(np->in_in[1].s_addr); + if (bits != -1) + printf("%d ", bits); + else + printf("%s", inet_ntoa(np->in_in[1])); + } printf(" -> "); - if (np->in_flags & IPN_RANGE) { + if (np->in_flags & IPN_IPRANGE) { printf("range %s-", inet_ntoa(np->in_out[0])); printf("%s", inet_ntoa(np->in_out[1])); } else { @@ -183,13 +199,13 @@ void *ptr; printf("%d", np->in_p); } else if (np->in_redir == NAT_MAPBLK) { printf(" ports %d", np->in_pmin); - if (verbose) + if (opts & OPT_VERBOSE) printf("\n\tip modulous %d", np->in_pmax); } else if (np->in_pmin || np->in_pmax) { printf(" portmap"); if (np->in_flags & IPN_AUTOPORTMAP) { printf(" auto"); - if (verbose) + if (opts & OPT_DEBUG) printf(" [%d:%d %d %d]", ntohs(np->in_pmin), ntohs(np->in_pmax), @@ -206,7 +222,7 @@ void *ptr; } } printf("\n"); - if (verbose) { + if (opts & OPT_DEBUG) { printf("\tifp %p space %lu nextip %s pnext %d", np->in_ifp, np->in_space, inet_ntoa(np->in_nextip), np->in_pnext); @@ -245,161 +261,187 @@ ipnat_t *natparse(line, linenum) char *line; int linenum; { - struct protoent *pr; static ipnat_t ipn; - char *s, *t; - char *shost, *snetm, *dhost, *proto, *srchost, *srcnetm; - char *dnetm = NULL, *dport = NULL, *tport = NULL; - int resolved; + struct protoent *pr; + char *dnetm = NULL, *dport = NULL; + char *s, *t, *cps[31], **cpp; + int i, cnt; - srchost = NULL; - srcnetm = NULL; - bzero((char *)&ipn, sizeof(ipn)); if ((s = strchr(line, '\n'))) *s = '\0'; if ((s = strchr(line, '#'))) *s = '\0'; + while (*line && isspace(*line)) + line++; if (!*line) return NULL; - if (!(s = strtok(line, " \t"))) + + bzero((char *)&ipn, sizeof(ipn)); + cnt = 0; + + for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++) + cps[++i] = strtok(NULL, " \b\t\r\n"); + + cps[i] = NULL; + + if (cnt < 3) { + fprintf(stderr, "%d: not enough segments in line\n", linenum); return NULL; - if (!strcasecmp(s, "map")) + } + + cpp = cps; + + if (!strcasecmp(*cpp, "map")) ipn.in_redir = NAT_MAP; - else if (!strcasecmp(s, "map-block")) + else if (!strcasecmp(*cpp, "map-block")) ipn.in_redir = NAT_MAPBLK; - else if (!strcasecmp(s, "rdr")) + else if (!strcasecmp(*cpp, "rdr")) ipn.in_redir = NAT_REDIRECT; - else if (!strcasecmp(s, "bimap")) + else if (!strcasecmp(*cpp, "bimap")) ipn.in_redir = NAT_BIMAP; else { fprintf(stderr, "%d: unknown mapping: \"%s\"\n", - linenum, s); + linenum, *cpp); return NULL; } - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "%d: missing fields (interface)\n", - linenum); - return NULL; - } + cpp++; - strncpy(ipn.in_ifname, s, sizeof(ipn.in_ifname) - 1); + strncpy(ipn.in_ifname, *cpp, sizeof(ipn.in_ifname) - 1); ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0'; - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, "%d: missing fields (%s)\n", linenum, - ipn.in_redir ? "from source | destination" : "source"); - return NULL; - } + cpp++; + + if (!strcasecmp(*cpp, "from")) { + ipn.in_flags |= IPN_FILTER; + cpp++; + if (ipn.in_redir == NAT_REDIRECT) { + if (hostmask(&cpp, (u_32_t *)&ipn.in_srcip, + (u_32_t *)&ipn.in_srcmsk, + &ipn.in_sport, &ipn.in_scmp, + &ipn.in_stop, linenum)) { + return NULL; + } + } else { + if (hostmask(&cpp, (u_32_t *)&ipn.in_inip, + (u_32_t *)&ipn.in_inmsk, + &ipn.in_dport, &ipn.in_dcmp, + &ipn.in_dtop, linenum)) { + return NULL; + } + } - if ((ipn.in_redir == NAT_REDIRECT) && !strcasecmp(s, "from")) { - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "%d: missing fields (source address)\n", - linenum); + if (strcasecmp(*cpp, "to")) { + fprintf(stderr, "%d: unexpected keyword (%s) - to\n", + linenum, *cpp); return NULL; } - srchost = s; - srcnetm = strrchr(srchost, '/'); - - if (srcnetm == NULL) { - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "%d: missing fields (source netmask)\n", - linenum); + if (!*++cpp) { + fprintf(stderr, "%d: missing host after to\n", linenum); + return NULL; + } + if (ipn.in_redir == NAT_REDIRECT) { + if (hostmask(&cpp, (u_32_t *)&ipn.in_inip, + (u_32_t *)&ipn.in_inmsk, + &ipn.in_dport, &ipn.in_dcmp, + &ipn.in_dtop, linenum)) { + return NULL; + } + } else { + if (hostmask(&cpp, (u_32_t *)&ipn.in_srcip, + (u_32_t *)&ipn.in_srcmsk, + &ipn.in_sport, &ipn.in_scmp, + &ipn.in_stop, linenum)) { + return NULL; + } + } + } else { + s = *cpp; + if (!s) + return NULL; + t = strchr(s, '/'); + if (!t) + return NULL; + *t++ = '\0'; + if (ipn.in_redir == NAT_REDIRECT) { + if (hostnum((u_32_t *)&ipn.in_outip, s, linenum) == -1) return NULL; - } - - if (strcasecmp(s, "netmask")) { - fprintf(stderr, - "%d: missing fields (netmask)\n", - linenum); + if (genmask(t, (u_32_t *)&ipn.in_outmsk) == -1) { return NULL; } - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "%d: missing fields (source netmask)\n", - linenum); + } else { + if (hostnum((u_32_t *)&ipn.in_inip, s, linenum) == -1) + return NULL; + if (genmask(t, (u_32_t *)&ipn.in_inmsk) == -1) { return NULL; } - srcnetm = s; } - if (*srcnetm == '/') - *srcnetm++ = '\0'; + cpp++; + if (!*cpp) + return NULL; + } - /* re read the next word -- destination */ - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "%d: missing fields (destination)\n", linenum); + if ((ipn.in_redir == NAT_REDIRECT) && !(ipn.in_flags & IPN_FILTER)) { + if (strcasecmp(*cpp, "port")) { + fprintf(stderr, "%d: missing fields - 1st port\n", + linenum); return NULL; } - } - - shost = s; + cpp++; - if (ipn.in_redir == NAT_REDIRECT) { - if (!(s = strtok(NULL, " \t"))) { + if (!*cpp) { fprintf(stderr, "%d: missing fields (destination port)\n", linenum); return NULL; } - if (strcasecmp(s, "port")) { - fprintf(stderr, "%d: missing fields (port)\n", linenum); - return NULL; - } + if (isdigit(**cpp) && (s = strchr(*cpp, '-'))) + *s++ = '\0'; + else + s = NULL; - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "%d: missing fields (destination port)\n", - linenum); + if (!portnum(*cpp, &ipn.in_pmin, linenum)) return NULL; + ipn.in_pmin = htons(ipn.in_pmin); + cpp++; + + if (!strcmp(*cpp, "-")) { + cpp++; + s = *cpp++; } - dport = s; + if (s) { + if (!portnum(s, &ipn.in_pmax, linenum)) + return NULL; + ipn.in_pmax = htons(ipn.in_pmax); + } else + ipn.in_pmax = ipn.in_pmin; } - - if (!(s = strtok(NULL, " \t"))) { + if (!*cpp) { fprintf(stderr, "%d: missing fields (->)\n", linenum); return NULL; } - if (!strcmp(s, "->")) { - snetm = strrchr(shost, '/'); - if (!snetm) { - fprintf(stderr, - "%d: missing fields (%s netmask)\n", linenum, - ipn.in_redir ? "destination" : "source"); - return NULL; - } - } else { - if (strcasecmp(s, "netmask")) { - fprintf(stderr, "%d: missing fields (netmask)\n", - linenum); - return NULL; - } - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "%d: missing fields (%s netmask)\n", linenum, - ipn.in_redir ? "destination" : "source"); - return NULL; - } - snetm = s; + if (strcmp(*cpp, "->")) { + fprintf(stderr, "%d: missing ->\n", linenum); + return NULL; } + cpp++; - if (!(s = strtok(NULL, " \t"))) { + if (!*cpp) { fprintf(stderr, "%d: missing fields (%s)\n", - linenum, ipn.in_redir ? "destination":"target"); + linenum, ipn.in_redir ? "destination" : "target"); return NULL; } if (ipn.in_redir == NAT_MAP) { - if (!strcasecmp(s, "range")) { - ipn.in_flags |= IPN_RANGE; - if (!(s = strtok(NULL, " \t"))) { + if (!strcasecmp(*cpp, "range")) { + cpp++; + ipn.in_flags |= IPN_IPRANGE; + if (!*cpp) { fprintf(stderr, "%d: missing fields (%s)\n", linenum, ipn.in_redir ? "destination":"target"); @@ -407,187 +449,167 @@ int linenum; } } } - dhost = s; - if (ipn.in_redir & (NAT_MAP|NAT_MAPBLK)) { - if (ipn.in_flags & IPN_RANGE) { - dnetm = strrchr(dhost, '-'); - if (dnetm == NULL) { - if (!(s = strtok(NULL, " \t"))) - dnetm = NULL; - else { - if (strcmp(s, "-")) - s = NULL; - else if ((s = strtok(NULL, " \t"))) { - dnetm = s; - } - } - } else - *dnetm++ = '\0'; - if (dnetm == NULL || *dnetm == '\0') { - fprintf(stderr, - "%d: desination range not specified\n", - linenum); - return NULL; - } - } else { - dnetm = strrchr(dhost, '/'); - if (dnetm == NULL) { - if (!(s = strtok(NULL, " \t"))) - dnetm = NULL; - else if (!strcasecmp(s, "netmask")) - if ((s = strtok(NULL, " \t")) != NULL) - dnetm = s; - } - if (dnetm == NULL) { - fprintf(stderr, - "%d: missing fields (dest netmask)\n", - linenum); - return NULL; - } - if (*dnetm == '/') - *dnetm++ = '\0'; + if (ipn.in_flags & IPN_IPRANGE) { + dnetm = strrchr(*cpp, '-'); + if (dnetm == NULL) { + cpp++; + if (*cpp && !strcmp(*cpp, "-") && *(cpp + 1)) + dnetm = *(cpp + 1); + } else + *dnetm++ = '\0'; + if (dnetm == NULL || *dnetm == '\0') { + fprintf(stderr, + "%d: desination range not specified\n", + linenum); + return NULL; + } + } else if (ipn.in_redir != NAT_REDIRECT) { + dnetm = strrchr(*cpp, '/'); + if (dnetm == NULL) { + cpp++; + if (*cpp && !strcasecmp(*cpp, "netmask")) + dnetm = *++cpp; + } + if (dnetm == NULL) { + fprintf(stderr, + "%d: missing fields (dest netmask)\n", + linenum); + return NULL; } - s = strtok(NULL, " \t"); + if (*dnetm == '/') + *dnetm++ = '\0'; } + if (ipn.in_redir == NAT_REDIRECT) { + dnetm = strchr(*cpp, ','); + if (dnetm != NULL) { + ipn.in_flags |= IPN_SPLIT; + *dnetm++ = '\0'; + } + if (hostnum((u_32_t *)&ipn.in_inip, *cpp, linenum) == -1) + return NULL; + } else { + if (hostnum((u_32_t *)&ipn.in_outip, *cpp, linenum) == -1) + return NULL; + } + cpp++; + if (ipn.in_redir & NAT_MAPBLK) { - if (s && strcasecmp(s, "ports")) { + if (*cpp && strcasecmp(*cpp, "ports")) { fprintf(stderr, "%d: expected \"ports\" - got \"%s\"\n", - linenum, s); + linenum, *cpp); return NULL; } - if (s != NULL) { - if ((s = strtok(NULL, " \t")) == NULL) - return NULL; - ipn.in_pmin = atoi(s); - s = strtok(NULL, " \t"); + cpp++; + if (*cpp) { + ipn.in_pmin = atoi(*cpp); + cpp++; } else ipn.in_pmin = 0; } else if ((ipn.in_redir & NAT_BIMAP) == NAT_REDIRECT) { - if (strrchr(dhost, '/') != NULL) { + if (strrchr(*cpp, '/') != NULL) { fprintf(stderr, "%d: No netmask supported in %s\n", linenum, "destination host for redirect"); return NULL; } /* If it's a in_redir, expect target port */ - if (!(s = strtok(NULL, " \t"))) { - fprintf(stderr, - "%d: missing fields (destination port)\n", - linenum); - return NULL; - } - if (strcasecmp(s, "port")) { - fprintf(stderr, "%d: missing fields (port)\n", - linenum); + if (strcasecmp(*cpp, "port")) { + fprintf(stderr, "%d: missing fields - 2nd port (%s)\n", + linenum, *cpp); return NULL; } - - if (!(s = strtok(NULL, " \t"))) { + cpp++; + if (!*cpp) { fprintf(stderr, "%d: missing fields (destination port)\n", linenum); return NULL; } - tport = s; + if (!portnum(*cpp, &ipn.in_pnext, linenum)) + return NULL; + ipn.in_pnext = htons(ipn.in_pnext); + cpp++; } if (dnetm && *dnetm == '/') *dnetm++ = '\0'; - if (snetm && *snetm == '/') - *snetm++ = '\0'; if (ipn.in_redir & (NAT_MAP|NAT_MAPBLK)) { - ipn.in_inip = hostnum(shost, &resolved, linenum); - if (resolved == -1) - return NULL; - ipn.in_inmsk = n_hostmask(snetm); - ipn.in_outip = hostnum(dhost, &resolved, linenum); - if (resolved == -1) - return NULL; - if (ipn.in_flags & IPN_RANGE) { - ipn.in_outmsk = hostnum(dnetm, &resolved, linenum); - if (resolved == -1) + if (ipn.in_flags & IPN_IPRANGE) { + if (hostnum((u_32_t *)&ipn.in_outmsk, dnetm, + linenum) == -1) return NULL; - } else - ipn.in_outmsk = n_hostmask(dnetm); - if (srchost) { - ipn.in_srcip = hostnum(srchost, &resolved, linenum); - if (resolved == -1) - return NULL; - } - if (srcnetm) - ipn.in_srcmsk = n_hostmask(srcnetm); + } else if (genmask(dnetm, (u_32_t *)&ipn.in_outmsk)) + return NULL; } else { - if (srchost) { - ipn.in_srcip = hostnum(srchost, &resolved, linenum); - if (resolved == -1) + if (ipn.in_flags & IPN_SPLIT) { + if (hostnum((u_32_t *)&ipn.in_inmsk, dnetm, + linenum) == -1) return NULL; - } - if (srcnetm) - ipn.in_srcmsk = n_hostmask(srcnetm); - ipn.in_inip = hostnum(dhost, &resolved, linenum); - if (resolved == -1) + } else if (genmask("255.255.255.255", (u_32_t *)&ipn.in_inmsk)) return NULL; - ipn.in_inmsk = n_hostmask("255.255.255.255"); - ipn.in_outip = hostnum(shost, &resolved, linenum); - if (resolved == -1) - return NULL; - ipn.in_outmsk = n_hostmask(snetm); - if (!(s = strtok(NULL, " \t"))) { - ipn.in_flags = IPN_TCP; /* XXX- TCP only by default */ + if (!*cpp) { + ipn.in_flags |= IPN_TCP; /* XXX- TCP only by default */ proto = "tcp"; } else { - if (!strcasecmp(s, "tcp")) - ipn.in_flags = IPN_TCP; - else if (!strcasecmp(s, "udp")) - ipn.in_flags = IPN_UDP; - else if (!strcasecmp(s, "tcp/udp")) - ipn.in_flags = IPN_TCPUDP; - else if (!strcasecmp(s, "tcpudp")) - ipn.in_flags = IPN_TCPUDP; - else if (!strcasecmp(s, "ip")) - ipn.in_flags = IPN_ANY; + if (!strcasecmp(*cpp, "tcp")) + ipn.in_flags |= IPN_TCP; + else if (!strcasecmp(*cpp, "udp")) + ipn.in_flags |= IPN_UDP; + else if (!strcasecmp(*cpp, "tcp/udp")) + ipn.in_flags |= IPN_TCPUDP; + else if (!strcasecmp(*cpp, "tcpudp")) + ipn.in_flags |= IPN_TCPUDP; + else if (!strcasecmp(*cpp, "ip")) + ipn.in_flags |= IPN_ANY; else { - ipn.in_flags = IPN_ANY; - if ((pr = getprotobyname(s))) + ipn.in_flags |= IPN_ANY; + if ((pr = getprotobyname(*cpp))) ipn.in_p = pr->p_proto; else - ipn.in_p = atoi(s); + ipn.in_p = atoi(*cpp); + } + proto = *cpp; + cpp++; + + if (*cpp && !strcasecmp(*cpp, "round-robin")) { + cpp++; + ipn.in_flags |= IPN_ROUNDR; } - proto = s; - if ((s = strtok(NULL, " \t"))) { + + if (*cpp) { fprintf(stderr, "%d: extra junk at the end of rdr: %s\n", - linenum, s); + linenum, *cpp); return NULL; } } - ipn.in_pmin = n_portnum(dport, proto, linenum); - ipn.in_pmax = ipn.in_pmin; - ipn.in_pnext = n_portnum(tport, proto, linenum); - s = NULL; } - ipn.in_inip &= ipn.in_inmsk; - if ((ipn.in_flags & IPN_RANGE) == 0) + + if (!(ipn.in_flags & IPN_SPLIT)) + ipn.in_inip &= ipn.in_inmsk; + if ((ipn.in_flags & IPN_IPRANGE) == 0) ipn.in_outip &= ipn.in_outmsk; ipn.in_srcip &= ipn.in_srcmsk; if ((ipn.in_redir & NAT_MAPBLK) != 0) nat_setgroupmap(&ipn); - if (!s) + if (!*cpp) return &ipn; if (ipn.in_redir == NAT_BIMAP) { fprintf(stderr, "%d: extra words at the end of bimap line: %s\n", - linenum, s); + linenum, *cpp); return NULL; } - if (!strcasecmp(s, "proxy")) { - if (!(s = strtok(NULL, " \t"))) { + + if (!strcasecmp(*cpp, "proxy")) { + cpp++; + if (!*cpp) { fprintf(stderr, "%d: missing parameter for \"proxy\"\n", linenum); @@ -595,17 +617,19 @@ int linenum; } dport = NULL; - if (!strcasecmp(s, "port")) { - if (!(s = strtok(NULL, " \t"))) { + if (!strcasecmp(*cpp, "port")) { + cpp++; + if (!*cpp) { fprintf(stderr, "%d: missing parameter for \"port\"\n", linenum); return NULL; } - dport = s; + dport = *cpp; + cpp++; - if (!(s = strtok(NULL, " \t"))) { + if (!*cpp) { fprintf(stderr, "%d: missing parameter for \"proxy\"\n", linenum); @@ -616,73 +640,83 @@ int linenum; "%d: missing keyword \"port\"\n", linenum); return NULL; } - if ((proto = index(s, '/'))) { + + if ((proto = index(*cpp, '/'))) { *proto++ = '\0'; if ((pr = getprotobyname(proto))) ipn.in_p = pr->p_proto; else ipn.in_p = atoi(proto); - if (dport) - ipn.in_dport = n_portnum(dport, proto, linenum); - } else { + } else ipn.in_p = 0; - if (dport) - ipn.in_dport = n_portnum(dport, NULL, linenum); - } - (void) strncpy(ipn.in_plabel, s, sizeof(ipn.in_plabel)); - if ((s = strtok(NULL, " \t"))) { + if (dport && !portnum(dport, &ipn.in_dport, linenum)) + return NULL; + ipn.in_dport = htons(ipn.in_dport); + + (void) strncpy(ipn.in_plabel, *cpp, sizeof(ipn.in_plabel)); + cpp++; + + if (*cpp) { fprintf(stderr, "%d: too many parameters for \"proxy\"\n", linenum); return NULL; } return &ipn; - } - if (strcasecmp(s, "portmap")) { + if (strcasecmp(*cpp, "portmap")) { fprintf(stderr, - "%d: expected \"portmap\" - got \"%s\"\n", linenum, s); + "%d: expected \"portmap\" - got \"%s\"\n", linenum, + *cpp); return NULL; } - if (!(s = strtok(NULL, " \t"))) + cpp++; + if (!*cpp) return NULL; - if (!strcasecmp(s, "tcp")) - ipn.in_flags = IPN_TCP; - else if (!strcasecmp(s, "udp")) - ipn.in_flags = IPN_UDP; - else if (!strcasecmp(s, "tcpudp")) - ipn.in_flags = IPN_TCPUDP; - else if (!strcasecmp(s, "tcp/udp")) - ipn.in_flags = IPN_TCPUDP; + + if (!strcasecmp(*cpp, "tcp")) + ipn.in_flags |= IPN_TCP; + else if (!strcasecmp(*cpp, "udp")) + ipn.in_flags |= IPN_UDP; + else if (!strcasecmp(*cpp, "tcpudp")) + ipn.in_flags |= IPN_TCPUDP; + else if (!strcasecmp(*cpp, "tcp/udp")) + ipn.in_flags |= IPN_TCPUDP; else { fprintf(stderr, "%d: expected protocol name - got \"%s\"\n", - linenum, s); + linenum, *cpp); return NULL; } + proto = *cpp; + cpp++; - if (!(s = strtok(NULL, " \t"))) { + if (!*cpp) { fprintf(stderr, "%d: no port range found\n", linenum); return NULL; } - if (!strcasecmp(s, "auto")) { + if (!strcasecmp(*cpp, "auto")) { ipn.in_flags |= IPN_AUTOPORTMAP; ipn.in_pmin = htons(1024); ipn.in_pmax = htons(65535); nat_setgroupmap(&ipn); return &ipn; } - proto = s; - if (!(t = strchr(s, ':'))) { - fprintf(stderr, "%d: no port range in \"%s\"\n", linenum, s); + + if (!(t = strchr(*cpp, ':'))) { + fprintf(stderr, "%d: no port range in \"%s\"\n", + linenum, *cpp); return NULL; } *t++ = '\0'; - ipn.in_pmin = n_portnum(s, proto, linenum); - ipn.in_pmax = n_portnum(t, proto, linenum); + if (!portnum(*cpp, &ipn.in_pmin, linenum) || + !portnum(t, &ipn.in_pmax, linenum)) + return NULL; + ipn.in_pmin = htons(ipn.in_pmin); + ipn.in_pmax = htons(ipn.in_pmax); return &ipn; } @@ -718,12 +752,12 @@ int opts; linenum, line); } else { if ((opts & OPT_VERBOSE) && np) - printnat(np, opts & OPT_VERBOSE, NULL); + printnat(np, opts, NULL); if (!(opts & OPT_NODO)) { - if (!(opts & OPT_REM)) { - if (ioctl(fd, SIOCADNAT, np) == -1) + if (!(opts & OPT_REMOVE)) { + if (ioctl(fd, SIOCADNAT, &np) == -1) perror("ioctl(SIOCADNAT)"); - } else if (ioctl(fd, SIOCRMNAT, np) == -1) + } else if (ioctl(fd, SIOCRMNAT, &np) == -1) perror("ioctl(SIOCRMNAT)"); } } @@ -731,64 +765,3 @@ int opts; if (fp != stdin) fclose(fp); } - - -u_32_t n_hostmask(msk) -char *msk; -{ - int bits = -1; - u_32_t mask; - - if (!isdigit(*msk)) - return (u_32_t)-1; - if (strchr(msk, '.')) - return inet_addr(msk); - if (strchr(msk, 'x')) - return (u_32_t)strtol(msk, NULL, 0); - /* - * set x most significant bits - */ - for (mask = 0, bits = atoi(msk); bits; bits--) { - mask /= 2; - mask |= ntohl(inet_addr("128.0.0.0")); - } - mask = htonl(mask); - return mask; -} - - -u_short n_portnum(name, proto, linenum) -char *name, *proto; -int linenum; -{ - struct servent *sp, *sp2; - u_short p1 = 0; - - if (isdigit(*name)) - return htons((u_short)atoi(name)); - if (!proto) - proto = "tcp/udp"; - if (strcasecmp(proto, "tcp/udp")) { - sp = getservbyname(name, proto); - if (sp) - return sp->s_port; - fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name); - return 0; - } - sp = getservbyname(name, "tcp"); - if (sp) - p1 = sp->s_port; - sp2 = getservbyname(name, "udp"); - if (!sp || !sp2) { - fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n", - linenum, name); - return 0; - } - if (p1 != sp2->s_port) { - fprintf(stderr, "%d: %s %d/tcp is a different port to ", - linenum, name, p1); - fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port); - return 0; - } - return p1; -} diff --git a/contrib/ipfilter/opt.c b/contrib/ipfilter/opt.c index 78e34a2..ae153a1 100644 --- a/contrib/ipfilter/opt.c +++ b/contrib/ipfilter/opt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -26,8 +26,8 @@ #include "ipf.h" #if !defined(lint) -static const char sccsid[] = "@(#)opt.c 1.8 4/10/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: opt.c,v 2.1 1999/08/04 17:30:15 darrenr Exp $"; +static const char sccsid[] = "@(#)opt.c 1.8 4/10/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: opt.c,v 2.2 2000/03/13 22:10:26 darrenr Exp $"; #endif extern int opts; diff --git a/contrib/ipfilter/parse.c b/contrib/ipfilter/parse.c index 3720561..0f05c15 100644 --- a/contrib/ipfilter/parse.c +++ b/contrib/ipfilter/parse.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -40,46 +40,29 @@ #include "facpri.h" #if !defined(lint) -static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: parse.c,v 2.1.2.8 2000/01/27 08:49:42 darrenr Exp $"; +static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 darrenr Exp $"; #endif extern struct ipopt_names ionames[], secclass[]; extern int opts; +#ifdef USE_INET6 +extern int use_inet6; +#endif -int portnum __P((char *, u_short *, int)); -u_char tcp_flags __P((char *, u_char *, int)); int addicmp __P((char ***, struct frentry *, int)); int extras __P((char ***, struct frentry *, int)); -char ***seg; -u_long *sa, *msk; -u_short *pp, *tp; -u_char *cp; - -int hostmask __P((char ***, u_32_t *, u_32_t *, u_short *, u_char *, - u_short *, int)); -int ports __P((char ***, u_short *, u_char *, u_short *, int)); + int icmpcode __P((char *)), addkeep __P((char ***, struct frentry *, int)); int to_interface __P((frdest_t *, char *, int)); void print_toif __P((char *, frdest_t *)); void optprint __P((u_short *, u_long, u_long)); -int countbits __P((u_32_t)); -char *portname __P((int, int)); -int ratoi __P((char *, int *, int, int)); - - -char *proto = NULL; -char flagset[] = "FSRPAU"; -u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG }; +int loglevel __P((char **, u_int *, int)); +void printlog __P((frentry_t *)); -static char thishost[MAXHOSTNAMELEN]; - - -void initparse() -{ - gethostname(thishost, sizeof(thishost)); - thishost[sizeof(thishost) - 1] = '\0'; -} +extern char *proto; +extern char flagset[]; +extern u_char flags[]; /* parse() @@ -93,8 +76,8 @@ int linenum; static struct frentry fil; struct protoent *p = NULL; char *cps[31], **cpp, *endptr; - u_char ch; - int i, cnt = 1, j; + int i, cnt = 1, j, ch; + u_int k; while (*line && isspace(*line)) line++; @@ -103,7 +86,11 @@ int linenum; bzero((char *)&fil, sizeof(fil)); fil.fr_mip.fi_v = 0xf; +#ifdef USE_INET6 + fil.fr_ip.fi_v = use_inet6 ? 6 : 4; +#else fil.fr_ip.fi_v = 4; +#endif fil.fr_loglevel = 0xffff; /* @@ -170,8 +157,8 @@ int linenum; fil.fr_flags |= FR_PREAUTH; } else if (!strcasecmp("skip", *cpp)) { cpp++; - if (ratoi(*cpp, &i, 0, USHRT_MAX)) - fil.fr_skip = i; + if (ratoui(*cpp, &k, 0, UINT_MAX)) + fil.fr_skip = k; else { fprintf(stderr, "%d: integer must follow skip\n", linenum); @@ -185,42 +172,16 @@ int linenum; } if (!strcasecmp(*(cpp+1), "first")) { fil.fr_flags |= FR_LOGFIRST; + cpp++; + } + if (*cpp && !strcasecmp(*(cpp+1), "or-block")) { + fil.fr_flags |= FR_LOGORBLOCK; + cpp++; } if (!strcasecmp(*(cpp+1), "level")) { - int fac, pri; - char *s; - - fac = 0; - pri = 0; - if (!*++cpp) { - fprintf(stderr, "%d: %s\n", linenum, - "missing identifier after level"); + cpp++; + if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) return NULL; - } - s = index(*cpp, '.'); - if (s) { - *s++ = '\0'; - fac = fac_findname(*cpp); - if (fac == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown facility", *cpp); - return NULL; - } - pri = pri_findname(s); - if (pri == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown priority", s); - return NULL; - } - } else { - pri = pri_findname(*cpp); - if (pri == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown priority", *cpp); - return NULL; - } - } - fil.fr_loglevel = fac|pri; cpp++; } } else { @@ -285,40 +246,9 @@ int linenum; cpp++; } if (*cpp && !strcasecmp(*cpp, "level")) { - int fac, pri; - char *s; - - fac = 0; - pri = 0; - if (!*++cpp) { - fprintf(stderr, "%d: %s\n", linenum, - "missing identifier after level"); + if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) return NULL; - } - s = index(*cpp, '.'); - if (s) { - *s++ = '\0'; - fac = fac_findname(*cpp); - if (fac == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown facility", *cpp); - return NULL; - } - pri = pri_findname(s); - if (pri == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown priority", s); - return NULL; - } - } else { - pri = pri_findname(*cpp); - if (pri == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown priority", *cpp); - return NULL; - } - } - fil.fr_loglevel = fac|pri; + cpp++; cpp++; } } @@ -464,16 +394,17 @@ int linenum; linenum); return NULL; } - ch = 0; if (**cpp == '!') { fil.fr_flags |= FR_NOTSRCIP; (*cpp)++; } + ch = 0; if (hostmask(&cpp, (u_32_t *)&fil.fr_src, (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch, &fil.fr_stop, linenum)) { return NULL; } + fil.fr_scmp = ch; if (!*cpp) { fprintf(stderr, "%d: missing to fields\n", linenum); @@ -535,7 +466,8 @@ int linenum; /* * extras... */ - if (*cpp && (!strcasecmp(*cpp, "with") || !strcasecmp(*cpp, "and"))) + if ((fil.fr_v == 4) && *cpp && (!strcasecmp(*cpp, "with") || + !strcasecmp(*cpp, "and"))) if (extras(&cpp, &fil, linenum)) return NULL; @@ -570,8 +502,8 @@ int linenum; fprintf(stderr, "%d: head without group #\n", linenum); return NULL; } - if (ratoi(*cpp, &i, 0, USHRT_MAX)) - fil.fr_grhead = i; + if (ratoui(*cpp, &k, 0, UINT_MAX)) + fil.fr_grhead = (u_32_t)k; else { fprintf(stderr, "%d: invalid group (%s)\n", linenum, *cpp); @@ -589,8 +521,8 @@ int linenum; linenum); return NULL; } - if (ratoi(*cpp, &i, 0, USHRT_MAX)) - fil.fr_group = i; + if (ratoui(*cpp, &k, 0, UINT_MAX)) + fil.fr_group = k; else { fprintf(stderr, "%d: invalid group (%s)\n", linenum, *cpp); @@ -642,20 +574,62 @@ int linenum; } +int loglevel(cpp, facpri, linenum) +char **cpp; +u_int *facpri; +int linenum; +{ + int fac, pri; + char *s; + + fac = 0; + pri = 0; + if (!*++cpp) { + fprintf(stderr, "%d: %s\n", linenum, + "missing identifier after level"); + return -1; + } + + s = index(*cpp, '.'); + if (s) { + *s++ = '\0'; + fac = fac_findname(*cpp); + if (fac == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown facility", *cpp); + return -1; + } + pri = pri_findname(s); + if (pri == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown priority", s); + return -1; + } + } else { + pri = pri_findname(*cpp); + if (pri == -1) { + fprintf(stderr, "%d: %s %s\n", linenum, + "Unknown priority", *cpp); + return -1; + } + } + *facpri = fac|pri; + return 0; +} + + int to_interface(fdp, to, linenum) frdest_t *fdp; char *to; int linenum; { - int r = 0; - char *s; + char *s; s = index(to, ':'); fdp->fd_ifp = NULL; if (s) { *s++ = '\0'; - fdp->fd_ip.s_addr = hostnum(s, &r, linenum); - if (r == -1) + if (hostnum((u_32_t *)&fdp->fd_ip, s, linenum) == -1) return -1; } (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1); @@ -677,270 +651,6 @@ frdest_t *fdp; /* - * returns -1 if neither "hostmask/num" or "hostmask mask addr" are - * found in the line segments, there is an error processing this information, - * or there is an error processing ports information. - */ -int hostmask(seg, sa, msk, pp, cp, tp, linenum) -char ***seg; -u_32_t *sa, *msk; -u_short *pp, *tp; -u_char *cp; -int linenum; -{ - char *s, *endptr; - int bits = -1, resolved; - struct in_addr maskaddr; - - /* - * is it possibly hostname/num ? - */ - if ((s = index(**seg, '/')) || (s = index(**seg, ':'))) { - *s++ = '\0'; - if (index(s, '.') || index(s, 'x')) { - /* possibly of the form xxx.xxx.xxx.xxx - * or 0xYYYYYYYY */ - if (inet_aton(s, &maskaddr) == 0) { - fprintf(stderr, "%d: bad mask (%s)\n", - linenum, s); - return -1; - } - *msk = maskaddr.s_addr; - } else { - /* - * set x most significant bits - */ - bits = (int)strtol(s, &endptr, 0); - if (*endptr != '\0' || bits > 32 || bits < 0) { - fprintf(stderr, "%d: bad mask (/%s)\n", - linenum, s); - return -1; - } - if (bits == 0) - *msk = 0; - else - *msk = htonl(0xffffffff << (32 - bits)); - } - *sa = hostnum(**seg, &resolved, linenum) & *msk; - if (resolved == -1) { - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; - } - (*seg)++; - return ports(seg, pp, cp, tp, linenum); - } - - /* - * look for extra segments if "mask" found in right spot - */ - if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) { - *sa = hostnum(**seg, &resolved, linenum); - if (resolved == -1) { - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; - } - (*seg)++; - (*seg)++; - if (inet_aton(**seg, &maskaddr) == 0) { - fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg); - return -1; - } - *msk = maskaddr.s_addr; - (*seg)++; - *sa &= *msk; - return ports(seg, pp, cp, tp, linenum); - } - - if (**seg) { - *sa = hostnum(**seg, &resolved, linenum); - if (resolved == -1) { - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; - } - (*seg)++; - *msk = (*sa ? inet_addr("255.255.255.255") : 0L); - *sa &= *msk; - return ports(seg, pp, cp, tp, linenum); - } - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; -} - -/* - * returns an ip address as a long var as a result of either a DNS lookup or - * straight inet_addr() call - */ -u_32_t hostnum(host, resolved, linenum) -char *host; -int *resolved; -int linenum; -{ - struct hostent *hp; - struct netent *np; - struct in_addr ip; - - *resolved = 0; - if (!strcasecmp("any", host)) - return 0; - if (isdigit(*host) && inet_aton(host, &ip)) - return ip.s_addr; - - if (!strcasecmp("<thishost>", host)) - host = thishost; - - if (!(hp = gethostbyname(host))) { - if (!(np = getnetbyname(host))) { - *resolved = -1; - fprintf(stderr, "%d: can't resolve hostname: %s\n", - linenum, host); - return 0; - } - return htonl(np->n_net); - } - return *(u_32_t *)hp->h_addr; -} - -/* - * check for possible presence of the port fields in the line - */ -int ports(seg, pp, cp, tp, linenum) -char ***seg; -u_short *pp, *tp; -u_char *cp; -int linenum; -{ - int comp = -1; - - if (!*seg || !**seg || !***seg) - return 0; - if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) { - (*seg)++; - if (isdigit(***seg) && *(*seg + 2)) { - if (portnum(**seg, pp, linenum) == 0) - return -1; - (*seg)++; - if (!strcmp(**seg, "<>")) - comp = FR_OUTRANGE; - else if (!strcmp(**seg, "><")) - comp = FR_INRANGE; - else { - fprintf(stderr, - "%d: unknown range operator (%s)\n", - linenum, **seg); - return -1; - } - (*seg)++; - if (**seg == NULL) { - fprintf(stderr, "%d: missing 2nd port value\n", - linenum); - return -1; - } - if (portnum(**seg, tp, linenum) == 0) - return -1; - } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq")) - comp = FR_EQUAL; - else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne")) - comp = FR_NEQUAL; - else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt")) - comp = FR_LESST; - else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt")) - comp = FR_GREATERT; - else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le")) - comp = FR_LESSTE; - else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge")) - comp = FR_GREATERTE; - else { - fprintf(stderr, "%d: unknown comparator (%s)\n", - linenum, **seg); - return -1; - } - if (comp != FR_OUTRANGE && comp != FR_INRANGE) { - (*seg)++; - if (portnum(**seg, pp, linenum) == 0) - return -1; - } - *cp = comp; - (*seg)++; - } - return 0; -} - -/* - * find the port number given by the name, either from getservbyname() or - * straight atoi(). Return 1 on success, 0 on failure - */ -int portnum(name, port, linenum) -char *name; -u_short *port; -int linenum; -{ - struct servent *sp, *sp2; - u_short p1 = 0; - int i; - if (isdigit(*name)) { - if (ratoi(name, &i, 0, USHRT_MAX)) { - *port = (u_short)i; - return 1; - } - fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name); - return 0; - } - if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) { - sp = getservbyname(name, proto); - if (sp) { - *port = ntohs(sp->s_port); - return 1; - } - fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name); - return 0; - } - sp = getservbyname(name, "tcp"); - if (sp) - p1 = sp->s_port; - sp2 = getservbyname(name, "udp"); - if (!sp || !sp2) { - fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n", - linenum, name); - return 0; - } - if (p1 != sp2->s_port) { - fprintf(stderr, "%d: %s %d/tcp is a different port to ", - linenum, name, p1); - fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port); - return 0; - } - *port = ntohs(p1); - return 1; -} - - -u_char tcp_flags(flgs, mask, linenum) -char *flgs; -u_char *mask; -int linenum; -{ - u_char tcpf = 0, tcpfm = 0, *fp = &tcpf; - char *s, *t; - - for (s = flgs; *s; s++) { - if (*s == '/' && fp == &tcpf) { - fp = &tcpfm; - continue; - } - if (!(t = index(flagset, *s))) { - fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s); - return 0; - } - *fp |= flags[t - flagset]; - } - if (!tcpfm) - tcpfm = 0xff; - *mask = tcpfm; - return tcpf; -} - - -/* * deal with extra bits on end of the line */ int extras(cp, fr, linenum) @@ -1283,6 +993,9 @@ struct frentry *fp; int linenum; { if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP && +#ifdef USE_INET6 + fp->fr_proto != IPPROTO_ICMPV6 && +#endif fp->fr_proto != IPPROTO_ICMP && !(fp->fr_ip.fi_fl & FI_TCPUDP)) { fprintf(stderr, "%d: Can only use keep with UDP/ICMP/TCP\n", linenum); @@ -1290,7 +1003,12 @@ int linenum; } (*cp)++; - if (**cp && strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) { + if (!**cp) { + fprintf(stderr, "%d: Missing state/frag after keep\n", + linenum); + return -1; + } + if (strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) { fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n", linenum, **cp); return -1; @@ -1306,77 +1024,16 @@ int linenum; /* - * count consecutive 1's in bit mask. If the mask generated by counting - * consecutive 1's is different to that passed, return -1, else return # - * of bits. - */ -int countbits(ip) -u_32_t ip; -{ - u_32_t ipn; - int cnt = 0, i, j; - - ip = ipn = ntohl(ip); - for (i = 32; i; i--, ipn *= 2) - if (ipn & 0x80000000) - cnt++; - else - break; - ipn = 0; - for (i = 32, j = cnt; i; i--, j--) { - ipn *= 2; - if (j > 0) - ipn++; - } - if (ipn == ip) - return cnt; - return -1; -} - - -char *portname(pr, port) -int pr, port; -{ - static char buf[32]; - struct protoent *p = NULL; - struct servent *sv = NULL, *sv1 = NULL; - - if (pr == -1) { - if ((sv = getservbyport(htons(port), "tcp"))) { - strncpy(buf, sv->s_name, sizeof(buf)-1); - buf[sizeof(buf)-1] = '\0'; - sv1 = getservbyport(htons(port), "udp"); - sv = strncasecmp(buf, sv->s_name, strlen(buf)) ? - NULL : sv1; - } - if (sv) - return buf; - } else if (pr && (p = getprotobynumber(pr))) { - if ((sv = getservbyport(htons(port), p->p_name))) { - strncpy(buf, sv->s_name, sizeof(buf)-1); - buf[sizeof(buf)-1] = '\0'; - return buf; - } - } - - (void) sprintf(buf, "%d", port); - return buf; -} - - -/* * print the filter structure in a useful way */ void printfr(fp) struct frentry *fp; { - static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=", - "<>", "><"}; - struct protoent *p; - int ones = 0, pr; - char *s, *u; - u_char *t; + struct protoent *p; u_short sec[2]; + char *s; + u_char *t; + int pr; if (fp->fr_flags & FR_PASS) printf("pass"); @@ -1397,11 +1054,7 @@ struct frentry *fp; } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST) printf(" return-rst"); } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) { - printf("log"); - if (fp->fr_flags & FR_LOGBODY) - printf(" body"); - if (fp->fr_flags & FR_LOGFIRST) - printf(" first"); + printlog(fp); } else if (fp->fr_flags & FR_ACCOUNT) printf("count"); else if (fp->fr_flags & FR_AUTH) @@ -1418,30 +1071,10 @@ struct frentry *fp; if (((fp->fr_flags & FR_LOGB) == FR_LOGB) || ((fp->fr_flags & FR_LOGP) == FR_LOGP)) { - printf("log "); - if (fp->fr_flags & FR_LOGBODY) - printf("body "); - if (fp->fr_flags & FR_LOGFIRST) - printf("first "); - if (fp->fr_flags & FR_LOGORBLOCK) - printf("or-block "); - if (fp->fr_loglevel != 0xffff) { - if (fp->fr_loglevel & LOG_FACMASK) { - s = fac_toname(fp->fr_loglevel); - if (s == NULL) - s = "!!!"; - } else - s = ""; - u = pri_toname(fp->fr_loglevel); - if (u == NULL) - u = "!!!"; - if (*s) - printf("level %s.%s ", s, u); - else - printf("level %s ", u); - } - + printlog(fp); + putchar(' '); } + if (fp->fr_flags & FR_QUICK) printf("quick "); @@ -1471,42 +1104,17 @@ struct frentry *fp; } printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : ""); - if (!fp->fr_src.s_addr && !fp->fr_smsk.s_addr) - printf("any "); - else { - printf("%s", inet_ntoa(fp->fr_src)); - if ((ones = countbits(fp->fr_smsk.s_addr)) == -1) - printf("/%s ", inet_ntoa(fp->fr_smsk)); - else - printf("/%d ", ones); - } - if (fp->fr_scmp) { - if (fp->fr_scmp == FR_INRANGE || fp->fr_scmp == FR_OUTRANGE) - printf("port %d %s %d ", fp->fr_sport, - pcmp1[fp->fr_scmp], fp->fr_stop); - else - printf("port %s %s ", pcmp1[fp->fr_scmp], - portname(pr, fp->fr_sport)); - } + printhostmask(fp->fr_v, (u_32_t *)&fp->fr_src.s_addr, + (u_32_t *)&fp->fr_smsk.s_addr); + if (fp->fr_scmp) + printportcmp(pr, &fp->fr_tuc.ftu_src); + + printf(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : ""); + printhostmask(fp->fr_v, (u_32_t *)&fp->fr_dst.s_addr, + (u_32_t *)&fp->fr_dmsk.s_addr); + if (fp->fr_dcmp) + printportcmp(pr, &fp->fr_tuc.ftu_dst); - printf("to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : ""); - if (!fp->fr_dst.s_addr && !fp->fr_dmsk.s_addr) - printf("any"); - else { - printf("%s", inet_ntoa(fp->fr_dst)); - if ((ones = countbits(fp->fr_dmsk.s_addr)) == -1) - printf("/%s", inet_ntoa(fp->fr_dmsk)); - else - printf("/%d", ones); - } - if (fp->fr_dcmp) { - if (fp->fr_dcmp == FR_INRANGE || fp->fr_dcmp == FR_OUTRANGE) - printf(" port %d %s %d", fp->fr_dport, - pcmp1[fp->fr_dcmp], fp->fr_dtop); - else - printf(" port %s %s", pcmp1[fp->fr_dcmp], - portname(pr, fp->fr_dport)); - } if ((fp->fr_ip.fi_fl & ~FI_TCPUDP) || (fp->fr_mip.fi_fl & ~FI_TCPUDP) || fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk || @@ -1540,7 +1148,7 @@ struct frentry *fp; type = ntohs(fp->fr_icmp); code = type & 0xff; type /= 256; - if (type < (sizeof(icmptypes) / sizeof(char *)) && + if (type < (sizeof(icmptypes) / sizeof(char *) - 1) && icmptypes[type]) printf(" icmp-type %s", icmptypes[type]); else @@ -1550,14 +1158,20 @@ struct frentry *fp; } if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) { printf(" flags "); - for (s = flagset, t = flags; *s; s++, t++) - if (fp->fr_tcpf & *t) - (void)putchar(*s); - if (fp->fr_tcpfm) { - (void)putchar('/'); + if (fp->fr_tcpf & ~TCPF_ALL) + printf("0x%x", fp->fr_tcpf); + else for (s = flagset, t = flags; *s; s++, t++) - if (fp->fr_tcpfm & *t) + if (fp->fr_tcpf & *t) (void)putchar(*s); + if (fp->fr_tcpfm) { + (void)putchar('/'); + if (fp->fr_tcpfm & ~TCPF_ALL) + printf("0x%x", fp->fr_tcpfm); + else + for (s = flagset, t = flags; *s; s++, t++) + if (fp->fr_tcpfm & *t) + (void)putchar(*s); } } @@ -1591,16 +1205,32 @@ struct frentry *fp; } -int ratoi(ps, pi, min, max) -char *ps; -int *pi, min, max; +void printlog(fp) +frentry_t *fp; { - int i; - char *pe; - - i = (int)strtol(ps, &pe, 0); - if (*pe != '\0' || i < min || i > max) - return 0; - *pi = i; - return 1; + char *s, *u; + + printf("log"); + if (fp->fr_flags & FR_LOGBODY) + printf(" body"); + if (fp->fr_flags & FR_LOGFIRST) + printf(" first"); + if (fp->fr_flags & FR_LOGORBLOCK) + printf(" or-block"); + if (fp->fr_loglevel != 0xffff) { + printf(" level "); + if (fp->fr_loglevel & LOG_FACMASK) { + s = fac_toname(fp->fr_loglevel); + if (s == NULL) + s = "!!!"; + } else + s = ""; + u = pri_toname(fp->fr_loglevel); + if (u == NULL) + u = "!!!"; + if (*s) + printf("%s.%s", s, u); + else + printf("%s", u); + } } diff --git a/contrib/ipfilter/pcap.h b/contrib/ipfilter/pcap.h index 8025bc6..1a53382 100644 --- a/contrib/ipfilter/pcap.h +++ b/contrib/ipfilter/pcap.h @@ -1,10 +1,10 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. - * $Id: pcap.h,v 2.1 1999/08/04 17:30:17 darrenr Exp $ + * $Id: pcap.h,v 2.2 2000/03/13 22:10:27 darrenr Exp $ */ /* * This header file is constructed to match the version described by diff --git a/contrib/ipfilter/perl/ipf-mrtg.pl b/contrib/ipfilter/perl/ipf-mrtg.pl new file mode 100644 index 0000000..cce30ab --- /dev/null +++ b/contrib/ipfilter/perl/ipf-mrtg.pl @@ -0,0 +1,22 @@ +#!/usr/local/bin/perl +# reads stats and uptime for ip-filter for mrtg +# ron@rosie.18james.com, 2 Jan 2000 + +my $firewall = "IP Filter v3.3.3"; +my($in_pkts,$out_pkts) = (0,0); + +open(FW, "/sbin/ipfstat -hi|") || die "cannot open ipfstat -hi\n"; +while (<FW>) { + $in_pkts += $1 if (/^(\d+)\s+pass\s+in\s+quick.*group\s+1\d0/); +} +close(FW); +open(FW, "/sbin/ipfstat -ho|") || die "cannot open ipfstat -ho\n"; +while (<FW>) { + $out_pkts += $1 if (/^(\d+)\s+pass\s+out\s+quick.*group\s+1\d0/); +} +print "$in_pkts\n", + "$out_pkts\n"; +my $uptime = `/usr/bin/uptime`; +$uptime =~ /^\s+(\d{1,2}:\d{2}..)\s+up\s+(\d+)\s+(......),/; +print "$2 $3\n", + "$firewall\n";
\ No newline at end of file diff --git a/contrib/ipfilter/perl/plog b/contrib/ipfilter/perl/plog index 8f3f73c..75c733b 100644 --- a/contrib/ipfilter/perl/plog +++ b/contrib/ipfilter/perl/plog @@ -1,8 +1,8 @@ #!/usr/bin/perl -wT # -# Author: Jefferson Ogata <jogata@nodc.noaa.gov> -# Date: 1998/11/01 -# Version: 0.4 +# Author: Jefferson Ogata (JO317) <jogata@pobox.com> +# Date: 2000/04/10 +# Version: 0.8 # # Please feel free to use or redistribute this program if you find it useful. # If you have suggestions, or even better, bits of new code, send them to me @@ -14,17 +14,79 @@ # Parse ipmon output into a coherent form. This program only handles the # lines regarding filter actions. It does not parse nat and state lines. # -# Present lines from ipmon to this program on standard input. One way I -# often use is: -# grep ' b ' logfile | plog -# since a ' b ' sequence indicates a blocked packet. +# Present lines from ipmon to this program on standard input. +# +# EXAMPLES +# +# plog -A block,log < /var/log/ipf +# +# Generate source and destination reports of all packets logged with +# block or log actions. +# +# plog -S -s ./services www.example.com < /var/log/ipf +# +# Generate a source report of traffic to or from www.example.com using +# the additional services defined in ./services. +# +# plog -nSA block < /var/log/ipf +# +# Generate a source report of all blocked packets with no hostname +# lookups. This is handy for an initial pass to identify portscans or +# other aggressive traffic. +# +# TODO # -# TODO: # - Handle output from ipmon -v. # - Handle timestamps from other locales. Anyone with a timestamp problem # please email me the format of your timestamps. +# - It looks as though short TCP or UDP packets will break things, but I +# haven't seen any yet. +# +# CHANGES +# +# 2000/04/12 (0.9): +# - Wasn't handling underscore in hostname,servicename fields; these may be +# logged using ipmon -n. Observation by <ark@eltex.ru>. +# - Hadn't properly attributed observation and fix for repetition counter in +# 0.8 change log. Added John Ladwig to attribution. Thanks, John. +# +# 2000/04/10 (0.8): +# - Service names can also have hyphens, dummy. I wasn't allowing these +# either. Observation and fix thanks to Taso N. Devetzis +# <devetzis@snet.net>. +# - IP Filter now logs a repetition counter. Observation and fixes (changed +# slightly) from Andy Kreiling <Andy@ntcs-inc.com> and John Ladwig +# <jladwig@nts.umn.edu>. +# - Added fix to handle new Solaris log format, e.g.: +# Nov 30 04:49:37 raoul ipmon[121]: [ID 702911 local0.warning] 04:49:36.420 +541 hme0 @0:34 b 205.152.16.6,58596 -> 204.60.220.24,113 PR tcp len 20 44 +# Fix thanks to Taso N. Devetzis <devetzis@SNET.Net>. +# - Added services map option. +# - Added options for generating only source/destination tables. +# - Added verbosity option. +# - Added option for reporting traffic for specific hosts. +# - Added some more ICMP unreachable codes, and made code and type names +# match the ones in IP Filter parse.c. +# - Condensed output format somewhat. +# - Various minor improvements, perhaps slight speed improvements. +# - Documented new options in usage() and tried to improve wording. +# +# 1999/08/02 (0.7): +# - Hostnames can have hyphens, dummy. I wasn't allowing them in the syslog +# line. Fix from Antoine Verheijen <antoine.verheijen@ualberta.ca>. +# +# 1999/05/05 (0.6): +# - IRIX syslog prefixes the hostname with a severity code. Handle it. Fix +# from John Ladwig <jladwig@nts.umn.edu>. +# +# 1999/05/05 (0.5): +# - Protocols other than TCP, UDP, or ICMP have packet lengths reported in +# parentheses for some reason. The script now handles this. Thanks to +# Dispatcher <dispatch@blackhelicopters.org>. +# - I had mixed up info-request and info-reply ICMP codes, and omitted the +# traceroute code. Sorted this out. I had also missed code 0 for type 6 +# (alternate address for host). Thanks to John Ladwig <jladwig@nts.umn.edu>. # -# CHANGES: # 1999/05/03: # - Now accepts hostnames in the source and destination address fields, as # well as port names in the port fields. This allows the people who are @@ -32,28 +94,33 @@ # hostnames, you are vulnerable to forgery of DNS information, modified # DNS information, and your log files will be larger also. If you are # using this program you can have it look up the names for you (still -# vulnerable to forgery) and keep your addresses all in numeric format, -# so that packets from the same source will always show the same source -# address regardless of what's up with DNS. Nevertheless, some people -# wanted this, so here it is. +# vulnerable to forgery) and keep your logged addresses all in numeric +# format, so that packets from the same source will always show the same +# source address regardless of what's up with DNS. Obviously, I don't +# favor using ipmon -n. Nevertheless, some people wanted this, so here it +# is. # - Added S and n flags to %acts hash. Thanks to Stephen J. Roznowski # <sjr@home.net>. # - Stopped reporting host IPs twice when numeric output was requested. # Thanks, yet again, to Stephen J. Roznowski <sjr@home.net>. # - Number of minor tweaks that might speed it up a bit, and some comments. -# - Put the script back up on the web site. I moved the site and forgot to -# move the tool. +# - Put the script back up on the web site. I had moved the site and +# forgotten to move the tool. +# # 1999/02/04: # - Changed log line parser to accept fully-qualified name in the logging # host field. Thanks to Stephen J. Roznowski <sjr@home.net>. +# # 1999/01/22: # - Changed high port strategy to use 65536 for unknown high ports so that # they are sorted last. +# # 1999/01/21: # - Moved icmp parsing to output loop. # - Added parsing of icmp codes, and more types. # - Changed packet sort routine to sort by port number rather than service # name. +# # 1999/01/20: # - Fixed problem matching ipmon log lines. Sometimes they have "/ipmon" in # them, sometimes just "ipmon". @@ -62,245 +129,540 @@ use strict; use Socket; +use IO::File; -select STDOUT ; $| = 1 ; +select STDOUT; $| = 1; my %hosts; my $me = $0; -$me =~ s/^([^\/]*\/)*//; - -my $numeric = 0; - -# Under IPv4 port numbers are unsigned shorts. The value below is higher -# than the maximum value of an unsigned port, and is used in place of -# high port numbers that don't correspond to known services. This makes -# high ports get sorted behind all others. -my $highPort = 0x10000; +$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}, + }, + 3 => +{ + name => 'unreach', + codes => +{ + 0 => 'net-unr', + 1 => 'host-unr', + 2 => 'proto-unr', + 3 => 'port-unr', + 4 => 'needfrag', + 5 => 'srcfail', + 6 => 'net-unk', + 7 => 'host-unk', + 8 => 'isolate', + 9 => 'net-prohib', + 10 => 'host-prohib', + 11 => 'net-tos', + 12 => 'host-tos', + 13 => 'filter-prohib', + 14 => 'host-preced', + 15 => 'preced-cutoff', + }, + }, + 4 => +{ + name => 'squench', + codes => +{0 => undef}, + }, + 5 => +{ + name => 'redir', + codes => +{ + 0 => 'net', + 1 => 'host', + 2 => 'tos', + 3 => 'tos-host', + }, + }, + 6 => +{ + name => 'alt-host-addr', + codes => +{ + 0 => 'alt-addr' + }, + }, + 8 => +{ + name => 'echo', + codes => +{0 => undef}, + }, + 9 => +{ + name => 'routerad', + codes => +{0 => undef}, + }, + 10 => +{ + name => 'routersol', + codes => +{0 => undef}, + }, + 11 => +{ + name => 'timex', + codes => +{ + 0 => 'in-transit', + 1 => 'frag-assy', + }, + }, + 12 => +{ + name => 'paramprob', + codes => +{ + 0 => 'ptr-err', + 1 => 'miss-opt', + 2 => 'bad-len', + }, + }, + 13 => +{ + name => 'timest', + codes => +{0 => undef}, + }, + 14 => +{ + name => 'timestrep', + codes => +{0 => undef}, + }, + 15 => +{ + name => 'inforeq', + codes => +{0 => undef}, + }, + 16 => +{ + name => 'inforep', + codes => +{0 => undef}, + }, + 17 => +{ + name => 'maskreq', + codes => +{0 => undef}, + }, + 18 => +{ + name => 'maskrep', + codes => +{0 => undef}, + }, + 30 => +{ + name => 'tracert', + codes => +{ }, + }, + 31 => +{ + name => 'dgram-conv-err', + codes => +{ }, + }, + 32 => +{ + name => 'mbl-host-redir', + codes => +{ }, + }, + 33 => +{ + name => 'ipv6-whereru?', + codes => +{ }, + }, + 34 => +{ + name => 'ipv6-iamhere', + codes => +{ }, + }, + 35 => +{ + name => 'mbl-reg-req', + codes => +{ }, + }, + 36 => +{ + name => 'mbl-reg-rep', + codes => +{ }, + }, +); + +# Arguments we will parse from argument list. +my $numeric = 0; # Don't lookup hostnames. +my $verbosity = 0; # Bla' bla' bla'. +my $sTable = 0; # Generate source table. +my $dTable = 0; # Generate destination table. +my $services = undef; # Preload services table. +my %selectHosts; # Limit report to these hosts. +my %selectActs; # Limit report to these actions. + +# Parse argument list. while (defined ($_ = shift)) { if (s/^-//) { - $numeric += s/n//g; - &usage (0) if (s/[h\?]//g); - &usage (1) if (length ($_)); - next; + 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; } - &usage (1); + + # Add host to hash of hosts we're interested in. + my $addr = &hostNumber ($_); + defined ($addr) || &usage (1, qq{cannot resolve hostname $_}); + $selectHosts{$addr} = undef; } +# Which tables will we generate? +$dTable = $sTable = 1 unless ($dTable || $sTable); +my @dirs; +push (@dirs, 'd') if ($dTable); +push (@dirs, 's') if ($sTable); + +# Are we interested in specific hosts? +my $selectHosts = scalar (keys (%selectHosts)); + +# Are we interested in specific actions? +if (scalar (keys (%selectActs)) == 0) +{ + %selectActs = %acts; +} + +# We use this hash to cache port name -> number and number -> name mappings. +# Isn't it cool that we can use the same hash for both? +my %pn; + +# Preload any services map. +if (defined ($services)) +{ + my $sf = new IO::File ($services, "r"); + defined ($sf) || &quit (1, qq{cannot open services file $services}); + + while (defined ($_ = $sf->getline ())) + { + my $text = $_; + chomp; + s/#.*$//; + s/\s+$//; + next unless (length); + my ($name, $spec, @aliases) = split (/\s+/); + ($spec =~ /^([\w\-]+)\/([\w\-]+)$/) + || &quit (1, qq{$services:$.: invalid definition: $text}); + my ($pnum, $proto) = ($1, $2); + + # Enter service definition in pn hash both forwards and backwards. + my $port; + my $pname; + foreach $port ($name, @aliases) + { + $pname = "$pnum/$proto"; + $pn{$pname} = $port; + } + $pname = "$name/$proto"; + $pn{$pname} = $pnum; + } + + $sf->close (); +} + +# Again, we can use the same hash for both host name -> IP mappings and +# IP -> name mappings. +my %ip; + +# Hash for protocol number <--> name mappings. +my %pr; + +# Under IPv4 port numbers are unsigned shorts. The value below is higher +# than the maximum value of an unsigned short, and is used in place of +# high port numbers that don't correspond to known services. This makes +# high ports get sorted behind all others. +my $highPort = 0x10000; + while (<STDIN>) { chomp; # For ipmon output that came through syslog, we'll have an asctime - # timestamp, hostname, "ipmon"[process id]: prefixed to the line. For - # output that was written directly to a file by ipmon, we'll have a date - # prefix as dd/mm/yyyy (no y2k problem here!). Both formats then have a - # packet timestamp and the log info. - my ($time, $log); - if (/^(\w+\s+\d+\s+\d+:\d+:\d+)\s+([\w\.]+)\s+\S*ipmon\[\d+\]:\s+(\d+:\d+:\d+\.\d+)\s+(.+)/) + # timestamp, an optional severity code (IRIX), the hostname, + # "ipmon"[process id]: prefixed to the line. For output that was + # written directly to a file by ipmon, we'll have a date prefix as + # dd/mm/yyyy (no y2k problem here!). Both formats then have a packet + # timestamp and the log info. + my ($log); + if (s/^\w+\s+\d+\s+\d+:\d+:\d+\s+(?:\d\w:)?[\w\.\-]+\s+\S*ipmon\[\d+\]:\s+( +?:\[ID\s+\d+\s+[\w\.]+\]\s+)?\d+:\d+:\d+\.\d+\s+//) { - my ($logtime, $loghost); - ($logtime, $loghost, $time, $log) = ($1, $2, $3, $4); + $log = $_; } - elsif (/^(\d+\/\d+\/\d+)\s+(\d+:\d+:\d+\.\d+)\s+(.+)$/) + elsif (s/^(?:\d+\/\d+\/\d+)\s+(?:\d+:\d+:\d+\.\d+)\s+//) { - my $logdate; - ($logdate, $time, $log) = ($1, $2, $3); + $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)); + print STDERR "$log\n" if ($verbosity); + # Parse the log line. We're expecting interface name, rule group and # number, an action code, a source host name or IP with possible port # name or number, a destination host name or IP with possible port # number, "PR", a protocol name or number, "len", a header length, a - # packet length, and maybe some additional info. - $log =~ /^(\w+)\s+@(\d+):(\d+)\s+(\w)\s+([a-zA-Z0-9\-\.,]+)\s+->\s+([a-zA-Z0-9\-\.,]+)\s+PR\s+(\w+)\s+len\s+(\d+)\s+(\d+)\s*(.*)$/; - my ($if, $group, $rule, $act, $src, $dest, $proto, $hlen, $len, $more) - = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10); - unless (defined ($len)) + # packet length (which will be in parentheses for protocols other than + # TCP, UDP, or ICMP), and maybe some additional info. + my @fields = ($log =~ /^(?:(\d+)x)?\s*(\w+)\s+@(\d+):(\d+)\s+(\w)\s+([\w\-\ +..,]+)\s+->\s+([\w\-\.,]+)\s+PR\s+(\w+)\s+len\s+(\d+)\s+\(?(\d+)\)?\s*(.*)$/ox); + unless (scalar (@fields)) { - warn ("Bad input line at $.: \"$_\""); - next; + print STDERR "$me:$.: cannot parse: $_\n"; + next; } + my ($count, $if, $group, $rule, $act, $src, $dest, $proto, $hlen, $len, $mo +re) = @fields; + + # Skip actions we're not interested in. + next unless (exists ($selectActs{$act})); + + # Packet count defaults to 1. + $count = 1 unless (defined ($count)); my ($sport, $dport); if ($proto eq 'icmp') { - if ($more =~ s/^icmp (\d+)\/(\d+)\s*//) - { - # We save icmp type and code in both sport and dport. - $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 { - $sport = (($src =~ s/,(\w+)$//) ? &portSimplify ($1, $proto) : ''); - $dport = (($dest =~ s/,(\w+)$//) ? &portSimplify ($1, $proto) : ''); + 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. - $src = &hostNumber ($src); - $dest = &hostNumber ($dest); + my $x; + $x = &hostNumber ($src); + unless (defined ($x)) + { + print STDERR "$me:$.: cannot resolve hostname $src\n"; + next; + } + $src = $x; + $x = &hostNumber ($dest); + unless (defined ($x)) + { + print STDERR "$me:$.: cannot resolve hostname $dest\n"; + next; + } + $dest = $x; + + # Skip hosts we're not interested in. + next if ($selectHosts && !(exists ($selectHosts{$src}) || exists ($selectHo +sts{$dest}))); # Convert proto to proto number. $proto = &protoNumber ($proto); sub countPacket { - my ($host, $dir, $peer, $proto, $packet) = @_; + my ($host, $dir, $peer, $proto, $count, $packet) = @_; - # Make sure host is in the hosts hash. - $hosts{$host} = - +{ - 'out' => +{ }, - 'in' => +{ }, - } unless (exists ($hosts{$host})); + # Make sure host is in the hosts hash. + $hosts{$host} = + +{ + 'd' => +{ }, + 's' => +{ }, + } unless (exists ($hosts{$host})); - # Get the incoming/outgoing 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}; + # Increment the counter. + $protoHash->{$packet} += $count; } # Count the packet as outgoing traffic from the source address. - &countPacket ($src, 'out', $dest, $proto, "$sport:$dport:$if:$act"); + &countPacket ($src, 's', $dest, $proto, $count, "$sport:$dport:$if:$act") i +f ($sTable); # Count the packet as incoming traffic to the destination address. - &countPacket ($dest, 'in', $src, $proto, "$dport:$sport:$if:$act"); + &countPacket ($dest, 'd', $src, $proto, $count, "$dport:$sport:$if:$act") i +f ($dTable); } my $dir; -foreach $dir (qw(out in)) +foreach $dir (@dirs) { - my $order = ($dir eq 'out' ? 'source' : 'destination'); - my $arrow = ($dir eq 'out' ? '->' : '<-'); + my $order = ($dir eq 's' ? 'source' : 'destination'); + my $arrow = ($dir eq 's' ? '->' : '<-'); + print "###\n"; print "### Traffic by $order address:\n"; + print "###\n"; sub ipSort { - my @a = split (/\./, $a); - my @b = split (/\./, $b); - $a[0] != $b[0] ? $a[0] <=> $b[0] - : $a[1] != $b[1] ? $a[1] <=> $b[1] - : $a[2] != $b[2] ? $a[2] <=> $b[2] - : $a[3] != $b[3] ? $a[3] <=> $b[3] - : 0; + my @a = split (/\./, $a); + my @b = split (/\./, $b); + $a[0] <=> $b[0] || $a[1] <=> $b[1] || $a[2] <=> $b[2] || $a[3] <=> $b[3 +]; + } + + sub packetSort + { + my ($asport, $adport, $aif, $aact) = split (/:/, $a); + my ($bsport, $bdport, $bif, $bact) = split (/:/, $b); + $bact cmp $aact || $aif cmp $bif || $asport <=> $bsport || $adport <=> +$bdport; } my $host; foreach $host (sort ipSort (keys %hosts)) { - my $traffic = $hosts{$host}->{$dir}; - - # Skip hosts with no traffic. - next unless (scalar (keys (%{$traffic}))); - - if ($numeric) - { - print " $host\n"; - } - else - { - print " ", &hostName ($host), " \[$host\]\n"; - } - - my $peer; - foreach $peer (sort ipSort (keys %{$traffic})) - { - my $peerHash = $traffic->{$peer}; - my $peerName = &hostName ($peer); - my $proto; - foreach $proto (sort (keys (%{$peerHash}))) - { - my $protoHash = $peerHash->{$proto}; - my $protoName = &protoName ($proto); - - sub packetSort - { - my ($asport, $adport, $aif, $aact) = split (/:/, $a); - my ($bsport, $bdport, $bif, $bact) = split (/:/, $b); - return $bact cmp $aact if ($aact ne $bact); - return $aif cmp $bif if ($aif ne $bif); - return $asport <=> $bsport if ($asport != $bsport); - return $adport <=> $bdport if ($adport != $bdport); - } - - my $packet; - foreach $packet (sort packetSort (keys %{$protoHash})) - { - my ($sport, $dport, $if, $act) = split (/:/, $packet); - my $count = $protoHash->{$packet}; - $act = '?' unless (defined ($act = $acts{$act})); - if (($protoName eq 'tcp') || ($protoName eq 'udp')) - { - printf (" %-6s %7s %5d %6s %14s %2s %s.%s\n", $if, $act, $count, $protoName, &portName ($sport, $protoName), $arrow, $peerName, &portName ($dport, $protoName)); - } - elsif ($protoName eq 'icmp') - { - printf (" %-6s %7s %5d %6s %14s %2s %s\n", $if, $act, $count, $protoName, &icmpType ($sport), $arrow, $peerName); - } - else - { - printf (" %-6s %7s %5d %6s %14s %2s %s\n", $if, $act, $count, $protoName, '', $arrow, $peerName); - } - } - } - } + my $traffic = $hosts{$host}->{$dir}; + + # Skip hosts with no traffic. + next unless (scalar (keys (%{$traffic}))); + + if ($numeric) + { + print "$host\n"; + } + else + { + print &hostName ($host), " \[$host\]\n"; + } + + my $peer; + foreach $peer (sort ipSort (keys %{$traffic})) + { + my $peerHash = $traffic->{$peer}; + my $peerName = &hostName ($peer); + my $proto; + foreach $proto (sort (keys (%{$peerHash}))) + { + my $protoHash = $peerHash->{$proto}; + my $protoName = &protoName ($proto); + + my $packet; + foreach $packet (sort packetSort (keys %{$protoHash})) + { + my ($sport, $dport, $if, $act) = split (/:/, $packet); + my $count = $protoHash->{$packet}; + $act = '?' unless (defined ($act = $acts{$act})); + if (($protoName eq 'tcp') || ($protoName eq 'udp')) + { + printf (" %-6s %7s %4d %4s %16s %2s %s.%s\n", $if, $ +act, $count, $protoName, &portName ($sport, $protoName), $arrow, $peerName, &po +rtName ($dport, $protoName)); + } + elsif ($protoName eq 'icmp') + { + printf (" %-6s %7s %4d %4s %16s %2s %s\n", $if, $act +, $count, $protoName, &icmpType ($sport), $arrow, $peerName); + } + else + { + printf (" %-6s %7s %4d %4s %16s %2s %s\n", $if, $act +, $count, $protoName, '', $arrow, $peerName); + } + } + } + } } - print "\n\n"; + print "\n"; } exit (0); -# We use this hash to cache port name -> number and number -> name mappings. -# Isn't is cool that we can use the same hash for both? -my %pn; - # Translates a numeric port/named protocol to a port name. Reserved ports -# that do # not have an entry in the services database are left numeric. -# High ports that do not have an entry in the services database are mapped +# that do not have an entry in the services database are left numeric. High +# ports that do not have an entry in the services database are mapped # to '<high>'. sub portName { @@ -309,8 +671,9 @@ sub portName my $pname = "$port/$proto"; unless (exists ($pn{$pname})) { - my $name = getservbyport ($port, $proto); - $pn{$pname} = (defined ($name) ? $name : ($port <= 1023 ? $port : '<high>')); + my $name = getservbyport ($port, $proto); + $pn{$pname} = (defined ($name) ? $name : ($port <= 1023 ? $port : '<hig +h>')); } return $pn{$pname}; } @@ -323,16 +686,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}; } @@ -346,7 +709,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); @@ -359,10 +722,6 @@ sub portSimplify return $port; } -# Again, we can use the same hash for both host name -> IP mappings and -# IP -> name mappings. -my %ip; - # Translates a dotted quad into a hostname. Don't pass names to this # function. sub hostName @@ -371,20 +730,20 @@ sub hostName 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; - } + my $addr = inet_aton ($ip); + my $name = gethostbyaddr ($addr, AF_INET); + if (defined ($name)) + { + $ip{$ip} = $name; + + # While we're at it, cache the forward lookup. + $ip{$name} = $ip; + } + else + { + # Just map the IP address to itself. There's no reverse. + $ip{$ip} = $ip; + } } return $ip{$ip}; } @@ -395,34 +754,31 @@ sub hostNumber 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)); + # Return original value for dotted quads. + my $or = int ($1) | int ($2) | int ($3) | int ($4); + return $name if ($or == ($or & 0xff)); } unless (exists ($ip{$name})) { - my $addr = inet_aton ($name); - unless (defined ($addr)) - { - # Again, I don't think we need to recover from this. If we can't - # resolve a hostname that ended up in the log file, punt. We - # want to be able to sort hosts by IP address later, and letting - # hostnames through will snarl up that code. Users of ipmon -n - # will have to grin and bear it for now. - die ("Unable to resolve host \"$name\" at $."); - } - my $ip = inet_ntoa ($addr); - $ip{$name} = $ip; - - # While we're at it, cache the reverse lookup. - $ip{$ip} = $name; + 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}; } -# Hash for protocol number <--> name mappings. -my %pr; - # Translates a protocol number into a protocol name, or a number if no name # is found in the protocol database. sub protoName @@ -431,15 +787,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}; } @@ -451,144 +807,27 @@ 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}; } sub icmpType { - my %icmp = ( - 0 => +{ - name => 'echo-reply', - codes => +{0 => undef}, - }, - 3 => +{ - name => 'dest-unr', - codes => +{ - 0 => 'net', - 1 => 'host', - 2 => 'proto', - 3 => 'port', - 4 => 'need-frag', - 5 => 'no-sroute', - 6 => 'net-unk', - 7 => 'host-unk', - 8 => 'shost-isol', - 9 => 'net-proh', - 10 => 'host-proh', - 11 => 'net-tos', - 12 => 'host-tos', - }, - }, - 4 => +{ - name => 'src-quench', - codes => +{0 => undef}, - }, - 5 => +{ - name => 'redirect', - codes => +{ - 0 => 'net', - 1 => 'host', - 2 => 'tos', - 3 => 'tos-host', - }, - }, - 6 => +{ - name => 'alt-host-addr', - codes => +{0 => undef}, - }, - 8 => +{ - name => 'echo', - codes => +{0 => undef}, - }, - 9 => +{ - name => 'rtr-advert', - codes => +{0 => undef}, - }, - 10 => +{ - name => 'rtr-select', - codes => +{0 => undef}, - }, - 11 => +{ - name => 'time-excd', - codes => +{ - 0 => 'in-transit', - 1 => 'frag-assy', - }, - }, - 12 => +{ - name => 'param-prob', - codes => +{ - 0 => 'ptr-err', - 1 => 'miss-opt', - 2 => 'bad-len', - }, - }, - 13 => +{ - name => 'time', - codes => +{0 => undef}, - }, - 14 => +{ - name => 'time-reply', - codes => +{0 => undef}, - }, - 15 => +{ - name => 'info', - codes => +{0 => undef}, - }, - 16 => +{ - name => 'info-req', - codes => +{0 => undef}, - }, - 17 => +{ - name => 'mask-req', - codes => +{0 => undef}, - }, - 18 => +{ - name => 'mask-reply', - codes => +{0 => undef}, - }, - 31 => +{ - name => 'dgram-conv-err', - codes => +{ }, - }, - 32 => +{ - name => 'mbl-host-redir', - codes => +{ }, - }, - 33 => +{ - name => 'ipv6-whereru?', - codes => +{ }, - }, - 34 => +{ - name => 'ipv6-iamhere', - codes => +{ }, - }, - 35 => +{ - name => 'mbl-reg-req', - codes => +{ }, - }, - 36 => +{ - name => 'mbl-reg-rep', - codes => +{ }, - }, - ); - my $typeCode = shift; my ($type, $code) = split ('\.', $typeCode); return "?" unless (defined ($code)); - my $info = $icmp{$type}; + my $info = $icmpTypeMap{$type}; return "\(type=$type/$code?\)" unless (defined ($info)); @@ -596,58 +835,83 @@ 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"; } -sub usage +sub quit { my $ec = shift; + my $msg = shift; - print STDERR <<EOT; -usage: $me [-n] - -Parses logging from ipmon and presents it in a comprehensible format. -This program generates two tables: one organized by source address and -another organized by destination address. For the first table, source -addresses are sorted by IP address. For each address, all packets -originating at the address are presented in a tabular form, where all -packets with the same source and destination address and port are counted -as a single entry. The packet count for each entry is shown as the third -field. In addition, any port number greater than 1024 that doesn't match -an entry in the services table is treated as a "high" port, and high ports -are coalesced into the same entry. The entry fields for the source address -table are: + print STDERR "$me: $msg\n"; + exit ($ec); +} - iface action packet-count proto src-port dest-ip dest-port +sub usage +{ + my $ec = shift; + my @msg = @_; -The entry fields for the destination table are: + if (scalar (@msg)) + { + print STDERR "$me: ", join ("\n", @msg), "\n\n"; + } + print STDERR <<EOT; +usage: $me [-n] [-S] [-D] [-s servicemap] [-A act1,...] host... + +Parses logging from ipmon and presents it in a comprehensible format. This +program generates two reports: one organized by source address and another +organized by destination address. For the first report, source addresses are +sorted by IP address. For each address, all packets originating at the address +are presented in a tabular form, where all packets with the same source and +destination address and port are counted as a single entry. Any port number +greater than 1023 that does not match an entry in the services table is treated +as a "high" port; all high ports are coalesced into the same entry. The fields +for the source address report are: + iface action packet-count proto src-port dest-ip dest-port +The fields for the destination address report are: iface action packet-count proto dest-port src-ip src-port -If the -n option is given, reverse hostname lookups are disabled and all -hosts are displayed as numeric addresses. - -Note: if you are logging traffic with ipmon -n, ipmon will already have -looked up and logged addresses as hostnames where possible. This has an -important side effect: this program will translate the hostnames back into -IP addresses which may not match the original addresses of the logged -packets because of numerous DNS issues. If you care about where packets -are really coming from, you simply cannot rely on ipmon -n. An attacker -with control of his reverse DNS can map the reverse lookup to anything he -likes. If you haven't logged the numeric IP address, there's no way to -discover the source of an attack reliably. For this reason, I strongly -recommend that you run ipmon without the -n option, and use this or a -similar script to do reverse lookups during analysis, rather than during -logging. +Options are: +-n Disable hostname lookups, and report only IP addresses. +-S Generate a source address report. +-D Generate a destination address report. +-s map Supply an alternate services map to be preloaded. The map should + be in the same format as /etc/services. Any service name not found + in the map will be looked for in the system services file. +-A act1,... Limit the report to the specified actions. The possible actions ar +e + pass, block, log, short, and nomatch. + +If any hostnames are supplied on the command line, the report is limited to +these hosts. If a host has multiple addresses, only the first address will be +considered. + +If neither -S nor -D is given, both reports are generated. + +Note: if you are logging traffic with ipmon -n, ipmon will already have looked +up and logged addresses as hostnames where possible. This has an important side +effect: this program will translate the hostnames back into IP addresses which +may not match the original addresses of the logged packets because of numerous +DNS issues. If you care about where packets are really coming from, you simply +cannot rely on ipmon -n. An attacker with control of his reverse DNS can map +the reverse lookup to anything he likes. If you haven't logged the numeric IP +address, there's no way to discover the source of an attack reliably. For this +reason, I strongly recommend that you run ipmon without the -n option, and use +this or a similar script to do reverse lookups during analysis, rather than +during logging. EOT exit ($ec); } + + diff --git a/contrib/ipfilter/relay.c b/contrib/ipfilter/relay.c index d6acd10..5919086 100644 --- a/contrib/ipfilter/relay.c +++ b/contrib/ipfilter/relay.c @@ -103,6 +103,7 @@ char *argv[]; { struct sockaddr_in sin; natlookup_t nl; + natlookup_t *nlp = &nl; int fd, sl = sizeof(sl), se; openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON); @@ -142,7 +143,7 @@ char *argv[]; nl.nl_outport = sin.sin_port; } - if (ioctl(fd, SIOCGNATL, &nl) == -1) { + if (ioctl(fd, SIOCGNATL, &nlp) == -1) { se = errno; perror("ioctl"); errno = se; diff --git a/contrib/ipfilter/samples/proxy.c b/contrib/ipfilter/samples/proxy.c index b72ccce..7ac6ec9 100644 --- a/contrib/ipfilter/samples/proxy.c +++ b/contrib/ipfilter/samples/proxy.c @@ -51,6 +51,7 @@ char *argv[]; { struct sockaddr_in sin, sloc, sout; natlookup_t natlook; + natlookup_t *natlookp = &natlook; char buffer[512]; int namelen, fd, n; @@ -88,7 +89,7 @@ char *argv[]; * Open the NAT device and lookup the mapping pair. */ fd = open(IPL_NAT, O_RDONLY); - if (ioctl(fd, SIOCGNATL, &natlook) == -1) { + if (ioctl(fd, SIOCGNATL, &natlookp) == -1) { perror("ioctl"); exit(-1); } diff --git a/contrib/ipfilter/samples/userauth.c b/contrib/ipfilter/samples/userauth.c index 9cecffd..65dcc74 100644 --- a/contrib/ipfilter/samples/userauth.c +++ b/contrib/ipfilter/samples/userauth.c @@ -15,13 +15,14 @@ extern int errno; main() { struct frauth fra; + struct frauth *frap = &fra; fr_info_t *fin = &fra.fra_info; fr_ip_t *fi = &fin->fin_fi; char yn[16]; int fd; fd = open(IPL_NAME, O_RDWR); - while (ioctl(fd, SIOCAUTHW, &fra) == 0) { + while (ioctl(fd, SIOCAUTHW, &frap) == 0) { if (fra.fra_info.fin_out) fra.fra_pass = FR_OUTQUE; else @@ -49,7 +50,7 @@ main() fra.fra_pass |= FR_NOMATCH; printf("answer = %c (%x), id %d idx %d\n", yn[0], fra.fra_pass, fra.fra_info.fin_id, fra.fra_index); - if (ioctl(fd, SIOCAUTHR, &fra) != 0) + if (ioctl(fd, SIOCAUTHR, &frap) != 0) perror("SIOCAUTHR"); } fprintf(stderr, "errno=%d \n", errno); diff --git a/contrib/ipfilter/snoop.h b/contrib/ipfilter/snoop.h index c5b2c88..df800ae 100644 --- a/contrib/ipfilter/snoop.h +++ b/contrib/ipfilter/snoop.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -11,7 +11,7 @@ /* * written to comply with the RFC (1761) from Sun. - * $Id: snoop.h,v 2.1 1999/08/04 17:30:19 darrenr Exp $ + * $Id: snoop.h,v 2.2 2000/03/13 22:10:27 darrenr Exp $ */ struct snoophdr { char s_id[8]; diff --git a/contrib/ipfilter/solaris.c b/contrib/ipfilter/solaris.c index 761ce55..5187bca 100644 --- a/contrib/ipfilter/solaris.c +++ b/contrib/ipfilter/solaris.c @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ /* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/ -#pragma ident "@(#)$Id: solaris.c,v 2.1.2.14 2000/01/25 15:32:03 darrenr Exp $" +#pragma ident "@(#)$Id: solaris.c,v 2.15.2.3 2000/05/22 10:26:17 darrenr Exp $" #include <sys/systm.h> #include <sys/types.h> @@ -213,7 +213,7 @@ int _init() return -1; ipfinst = mod_install(&modlink1); #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: _init() = %d\n", ipfinst); + cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst); #endif return ipfinst; } @@ -227,7 +227,7 @@ int _fini(void) return -1; ipfinst = mod_remove(&modlink1); #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: _fini() = %d\n", ipfinst); + cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst); #endif return ipfinst; } @@ -242,7 +242,7 @@ struct modinfo *modinfop; return -1; ipfinst = mod_info(&modlink1, modinfop); #ifdef IPFDEBUG - cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x\n", modinfop, ipfinst); + cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x", modinfop, ipfinst); #endif if (fr_running > 0) ipfsync(); @@ -399,7 +399,7 @@ ddi_detach_cmd_t cmd; return DDI_FAILURE; } if (!soldetach()) { - cmn_err(CE_CONT, "IP Filter: detached\n"); + cmn_err(CE_CONT, "%s detached\n", ipfilter_version); return (DDI_SUCCESS); } default: @@ -528,13 +528,18 @@ int out; { register mblk_t *m, *mt = *mp; register ip_t *ip; - size_t hlen, len, off, mlen, iphlen; - int err, synced = 0; + size_t hlen, len, off, mlen, iphlen, plen; + int err, synced = 0, sap, p; u_char *bp; +#if SOLARIS2 >= 8 + ip6_t *ip6; +#endif #ifndef sparc - u_short __iplen, __ipoff; + u_short __ipoff; #endif tryagain: + ip = NULL; + m = NULL; /* * If there is only M_DATA for a packet going out, then any header * information (which would otherwise appear in an M_PROTO mblk before @@ -552,8 +557,16 @@ tryagain: dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp; if (dl->dl_primitive != DL_UNITDATA_IND && dl->dl_primitive != DL_UNITDATA_REQ) { - frstats[out].fr_notdata++; - return 0; + ip = (ip_t *)dl; + if ((ip->ip_v == IPVERSION) && + (ip->ip_hl == (sizeof(*ip) >> 2)) && + (ntohs(ip->ip_len) == mt->b_wptr - mt->b_rptr)) { + off = 0; + m = mt; + } else { + frstats[out].fr_notdata++; + return 0; + } } } @@ -561,8 +574,9 @@ tryagain: * Find the first data block, count the data blocks in this chain and * the total amount of data. */ - for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont) - off = 0; /* Any non-M_DATA cancels the offset */ + if (ip == NULL) + for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont) + off = 0; /* Any non-M_DATA cancels the offset */ if (!m) { frstats[out].fr_nodata++; @@ -598,7 +612,6 @@ tryagain: off = (u_char *)ip - m->b_rptr; if (off != 0) m->b_rptr = (u_char *)ip; - mlen = msgdsize(m); len = m->b_wptr - m->b_rptr; if (m->b_wptr < m->b_rptr) { @@ -607,30 +620,72 @@ tryagain: frstats[out].fr_bad++; return -1; } + + mlen = msgdsize(m); + sap = qif->qf_ill->ill_sap; + + if (sap == 0x800) { + hlen = sizeof(*ip); + plen = ntohs(ip->ip_len); + sap = 0; + } +#if SOLARIS2 >= 8 + else if (sap == IP6_DL_SAP) { + hlen = sizeof(ip6_t); + ip6 = (ip6_t *)ip; + plen = ntohs(ip6->ip6_plen); + sap = IP6_DL_SAP; + } +#endif + else { + hlen = 0; + sap = -1; + } + /* * Ok, the IP header isn't on a 32bit aligned address so junk it. */ - if (((u_int)ip & 0x3) || (len < sizeof(*ip))) { + if (((u_int)ip & 0x3) || (len < hlen) || (sap == -1)) { + mblk_t *m2; + u_char *s; + /* - * We have link layer header and IP header in the same mbuf, - * problem being that a pullup without adjusting b_rptr will - * bring us back here again as it's likely that the start of - * the databuffer (b_datab->db_base) is already aligned. Hmm, - * should we pull it all up (length of -1 to pullupmsg) if we - * can, now ? + * Junk using pullupmsg - it's next to useless. */ fixalign: - if (!pullupmsg(m, sizeof(ip_t))) { + len = msgdsize(m); + m2 = allocb(len, BPRI_HI); + if (m2 == NULL) { frstats[out].fr_pull[1]++; return -1; } + + m2->b_wptr = m2->b_rptr + len; + s = (u_char *)ip; + for (bp = m2->b_rptr; m; bp += len) { + len = m->b_wptr - s; + bcopy(m->b_rptr, bp, len); + m = m->b_cont; + if (m) + s = m->b_rptr; + } + *mp = m2; + MTYPE(m2) = M_DATA; + freemsg(mt); + mt = m2; + frstats[out].fr_pull[0]++; synced = 1; off = 0; goto tryagain; } - if (ip->ip_v != IPVERSION) { + + if (((sap == 0) && (ip->ip_v != IP_VERSION)) +#if SOLARIS2 >= 8 + || ((sap == IP6_DL_SAP) && ((ip6->ip6_vfc >> 4) != 6)) +#endif + ) { m->b_rptr -= off; if (!synced) { synced = 1; @@ -644,26 +699,48 @@ fixalign: } #ifndef sparc - __iplen = (u_short)ip->ip_len, - __ipoff = (u_short)ip->ip_off; +# if SOLARIS2 >= 8 + if (sap == IP6_DL_SAP) { + ip6->ip6_plen = plen; + } else { +# endif + __ipoff = (u_short)ip->ip_off; - ip->ip_len = ntohs(__iplen); - ip->ip_off = ntohs(__ipoff); + ip->ip_len = plen; + ip->ip_off = ntohs(__ipoff); +# if SOLARIS2 >= 8 + } +# endif +#endif + if (sap == 0) + iphlen = ip->ip_hl << 2; +#if SOLARIS2 >= 8 + else if (sap == IP6_DL_SAP) + iphlen = sizeof(ip6_t); #endif - hlen = iphlen = ip->ip_hl << 2; - - if ((iphlen < sizeof(ip_t)) || (iphlen > (u_short)ip->ip_len) || - (mlen < (u_short)ip->ip_len)) { + if (( +#if SOLARIS2 >= 8 + (sap == IP6_DL_SAP) && (mlen < iphlen + plen)) || + ((sap == 0) && +#endif + ((iphlen < hlen) || (iphlen > plen) || (mlen < plen)))) { /* * Bad IP packet or not enough data/data length mismatches */ #ifndef sparc - __iplen = (u_short)ip->ip_len, - __ipoff = (u_short)ip->ip_off; +# if SOLARIS2 >= 8 + if (sap == IP6_DL_SAP) { + ip6->ip6_plen = htons(plen); + } else { +# endif + __ipoff = (u_short)ip->ip_off; - ip->ip_len = htons(__iplen); - ip->ip_off = htons(__ipoff); + ip->ip_len = htons(plen); + ip->ip_off = htons(__ipoff); +# if SOLARIS2 >= 8 + } +# endif #endif m->b_rptr -= off; frstats[out].fr_bad++; @@ -674,8 +751,17 @@ fixalign: * Make hlen the total size of the IP header plus TCP/UDP/ICMP header * (if it is one of these three). */ + if (sap == 0) + p = ip->ip_p; +#if SOLARIS2 >= 8 + else if (sap == IP6_DL_SAP) + p = ip6->ip6_nxt; + + if ((sap == IP6_DL_SAP) || ((ip->ip_off & IP_OFFMASK) == 0)) +#else if ((ip->ip_off & IP_OFFMASK) == 0) - switch (ip->ip_p) +#endif + switch (p) { case IPPROTO_TCP : hlen += sizeof(tcphdr_t); @@ -691,8 +777,15 @@ fixalign: break; } - if (hlen > mlen) + if (hlen > mlen) { hlen = mlen; +#if SOLARIS2 >= 8 + } else if (sap == IP6_DL_SAP) { + if (m->b_wptr - m->b_rptr > plen + hlen) + m->b_wptr = m->b_rptr + plen + hlen; +#endif + } else if (m->b_wptr - m->b_rptr > plen) + m->b_wptr = m->b_rptr + plen; /* * If we don't have enough data in the mblk or we haven't yet copied @@ -724,11 +817,20 @@ fixalign: if (*mp == mt) { m->b_rptr -= off; #ifndef sparc - __iplen = (u_short)ip->ip_len, - __ipoff = (u_short)ip->ip_off; - - ip->ip_len = htons(__iplen); - ip->ip_off = htons(__ipoff); +# if SOLARIS2 >= 8 + if (sap == IP6_DL_SAP) { + ip6->ip6_plen = htons(plen); + } else { +# endif + __ipoff = (u_short)ip->ip_off; + /* + * plen is useless because of NAT. + */ + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(__ipoff); +# if SOLARIS2 >= 8 + } +# endif #endif } else cmn_err(CE_NOTE, @@ -752,6 +854,15 @@ mblk_t *mb; return 0; } + if (mb->b_datap->db_ref > 1) { + mblk_t *m1; + + m1 = copymsg(mb); + freemsg(mb); + mb = m1; + frstats[0].fr_copy++; + } + READ_ENTER(&ipf_solaris); again: if (fr_running <= 0) { @@ -844,6 +955,15 @@ mblk_t *mb; return 0; } + if (mb->b_datap->db_ref > 1) { + mblk_t *m1; + + m1 = copymsg(mb); + freemsg(mb); + mb = m1; + frstats[1].fr_copy++; + } + READ_ENTER(&ipf_solaris); again: if (fr_running <= 0) { @@ -959,7 +1079,7 @@ mblk_t *mb; freemsg(mb); return 0; } - + if (MTYPE(mb) != M_IOCTL) return (*ipf_ip_inp)(q, mb); @@ -1056,10 +1176,6 @@ void solattach() if (!in || !il->ill_wq) continue; -#if SOLARIS2 >= 8 - if (il->ill_isv6) - continue; -#endif out = il->ill_wq->q_next; WRITE_ENTER(&ipfs_mutex); @@ -1142,6 +1258,7 @@ void solattach() mblk_t *m; qif->qf_hl = 0; + qif->qf_sap = il->ill_sap; # if 0 /* * Can't seem to lookup a route for the IP address on the @@ -1192,6 +1309,26 @@ void solattach() f->fr_ifa = il; } } +#if SOLARIS2 >= 8 + for (f = ipfilter6[0][fr_active]; f; f = f->fr_next) { + if ((f->fr_ifa == (struct ifnet *)-1)) { + len = strlen(f->fr_ifname) + 1; + if ((len != 0) && + (len == (size_t)il->ill_name_length) && + !strncmp(il->ill_name, f->fr_ifname, len)) + f->fr_ifa = il; + } + } + for (f = ipfilter6[1][fr_active]; f; f = f->fr_next) { + if ((f->fr_ifa == (struct ifnet *)-1)) { + len = strlen(f->fr_ifname) + 1; + if ((len != 0) && + (len == (size_t)il->ill_name_length) && + !strncmp(il->ill_name, f->fr_ifname, len)) + f->fr_ifa = il; + } + } +#endif RWLOCK_EXIT(&ipf_mutex); WRITE_ENTER(&ipf_nat); for (np = nat_list; np; np = np->in_next) { @@ -1228,8 +1365,14 @@ void solattach() out->q_qinfo = &qif->qf_wqinit; RWLOCK_EXIT(&ipfs_mutex); - cmn_err(CE_CONT, "IP Filter: attach to [%s,%d]\n", - qif->qf_name, il->ill_ppa); + cmn_err(CE_CONT, "IP Filter: attach to [%s,%d] - %s\n", + qif->qf_name, il->ill_ppa, +#if SOLARIS2 >= 8 + il->ill_isv6 ? "IPv6" : "IPv4" +#else + "IPv4" +#endif + ); } if (!qif_head) cmn_err(CE_CONT, "IP Filter: not attached to any interfaces\n"); @@ -1268,7 +1411,14 @@ int ipfsync() qp = &qif->qf_next; continue; } - cmn_err(CE_CONT, "IP Filter: detaching [%s]\n", qif->qf_name); + cmn_err(CE_CONT, "IP Filter: detaching [%s] - %s\n", + qif->qf_name, +#if SOLARIS2 >= 8 + (qif->qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4" +#else + "IPv4" +#endif + ); *qp = qif->qf_next; /* @@ -1286,6 +1436,14 @@ int ipfsync() for (f = ipfilter[1][fr_active]; f; f = f->fr_next) if (f->fr_ifa == (void *)qif->qf_ill) f->fr_ifa = (struct ifnet *)-1; +#if SOLARIS2 >= 8 + for (f = ipfilter6[0][fr_active]; f; f = f->fr_next) + if (f->fr_ifa == (void *)qif->qf_ill) + f->fr_ifa = (struct ifnet *)-1; + for (f = ipfilter6[1][fr_active]; f; f = f->fr_next) + if (f->fr_ifa == (void *)qif->qf_ill) + f->fr_ifa = (struct ifnet *)-1; +#endif #if 0 /* XXX */ /* @@ -1372,8 +1530,14 @@ int soldetach() if (il) { in = qif->qf_in; out = qif->qf_out; - cmn_err(CE_CONT, "IP Filter: detaching [%s,%d]\n", - qif->qf_name, il->ill_ppa); + cmn_err(CE_CONT, "IP Filter: detaching [%s,%d] - %s\n", + qif->qf_name, il->ill_ppa, +#if SOLARIS2 >= 8 + (qif->qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4" +#else + "IPv4" +#endif + ); #ifdef IPFDEBUG cmn_err(CE_NOTE, @@ -1404,13 +1568,24 @@ void printire(ire) ire_t *ire; { printf("ire: ll_hdr_mp %p rfq %p stq %p src_addr %x max_frag %d\n", - ire->ire_ll_hdr_mp, ire->ire_rfq, ire->ire_stq, +# if SOLARIS2 >= 8 + NULL, +# else + ire->ire_ll_hdr_mp, +# endif + ire->ire_rfq, ire->ire_stq, ire->ire_src_addr, ire->ire_max_frag); printf("ire: mask %x addr %x gateway_addr %x type %d\n", ire->ire_mask, ire->ire_addr, ire->ire_gateway_addr, ire->ire_type); printf("ire: ll_hdr_length %d ll_hdr_saved_mp %p\n", - ire->ire_ll_hdr_length, ire->ire_ll_hdr_saved_mp); + ire->ire_ll_hdr_length, +# if SOLARIS2 >= 8 + NULL +# else + ire->ire_ll_hdr_saved_mp +# endif + ); } #endif @@ -1422,14 +1597,20 @@ mblk_t *mb, **mpp; fr_info_t *fin; frdest_t *fdp; { +#ifdef USE_INET6 + ip6_t *ip6 = (ip6_t *)ip; +#endif ire_t *ir, *dir, *gw; struct in_addr dst; queue_t *q = NULL; mblk_t *mp = NULL; size_t hlen = 0; frentry_t *fr; + frdest_t fd; ill_t *ifp; + qif_t *qif; u_char *s; + int p; #ifndef sparc u_short __iplen, __ipoff; @@ -1455,18 +1636,50 @@ frdest_t *fdp; *mpp = mp; } + if (!fdp) { + ipif_t *ipif; + + ifp = fin->fin_ifp; + ipif = ifp->ill_ipif; + if (!ipif) + goto bad_fastroute; +#if SOLARIS2 > 5 + ir = ire_ctable_lookup(ipif->ipif_local_addr, 0, IRE_LOCAL, + NULL, NULL, MATCH_IRE_TYPE); +#else + ir = ire_lookup_myaddr(ipif->ipif_local_addr); +#endif + if (!ir) + ir = (ire_t *)-1; + + fd.fd_ifp = (struct ifnet *)ir; + fd.fd_ip = ip->ip_dst; + fdp = &fd; + } + ir = (ire_t *)fdp->fd_ifp; if (fdp->fd_ip.s_addr) dst = fdp->fd_ip; else - dst = fin->fin_fi.fi_dst; + dst.s_addr = fin->fin_fi.fi_daddr; #if SOLARIS2 >= 6 gw = NULL; - dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL, &gw, NULL, - MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT| - MATCH_IRE_RECURSIVE); + if (fin->fin_v == 4) { + p = ip->ip_p; + dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL, + &gw, NULL, MATCH_IRE_DSTONLY| + MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); + } +# ifdef USE_INET6 + else if (fin->fin_v == 6) { + p = ip6->ip6_nxt; + dir = ire_route_lookup_v6(&ip6->ip6_dst, 0xffffffff, 0, 0, + NULL, &gw, NULL, MATCH_IRE_DSTONLY| + MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); + } +# endif #else dir = ire_lookup(dst.s_addr); #endif @@ -1502,18 +1715,22 @@ frdest_t *fdp; fin->fin_fr = ipacct[1][fr_active]; if ((fin->fin_fr != NULL) && (fr_scanlist(FR_NOMATCH, ip, fin, mb)&FR_ACCOUNT)){ - ATOMIC_INC(frstats[1].fr_acct); + ATOMIC_INCL(frstats[1].fr_acct); } fin->fin_fr = NULL; - (void) fr_checkstate(ip, fin); - (void) ip_natout(ip, fin); - } + if (!fr || !(fr->fr_flags & FR_RETMASK)) { + (void) fr_checkstate(ip, fin); + (void) ip_natout(ip, fin); + } + } #ifndef sparc - __iplen = (u_short)ip->ip_len, - __ipoff = (u_short)ip->ip_off; + if (fin->fin_v == 4) { + __iplen = (u_short)ip->ip_len, + __ipoff = (u_short)ip->ip_off; - ip->ip_len = htons(__iplen); - ip->ip_off = htons(__ipoff); + ip->ip_len = htons(__iplen); + ip->ip_off = htons(__ipoff); + } #endif #if SOLARIS2 < 8 @@ -1541,7 +1758,7 @@ frdest_t *fdp; mp2 = copyb(mp); if (!mp2) goto bad_fastroute; - mp2->b_cont = mb; + linkb(mp2, mb); mb = mp2; } } @@ -1557,7 +1774,7 @@ frdest_t *fdp; RWLOCK_EXIT(&ipfs_mutex); RWLOCK_EXIT(&ipf_solaris); #if SOLARIS2 >= 6 - if ((ip->ip_p == IPPROTO_TCP) && dohwcksum && + if ((p == IPPROTO_TCP) && dohwcksum && (ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { tcphdr_t *tcp; u_32_t t; @@ -1643,3 +1860,23 @@ char *buf; bp += clen; } } + + +int fr_verifysrc(ipa, ifp) +struct in_addr ipa; +void *ifp; +{ + ire_t *ir, *dir, *gw; + +#if SOLARIS2 >= 6 + dir = ire_route_lookup(ipa.s_addr, 0xffffffff, 0, 0, NULL, &gw, NULL, + MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT| + MATCH_IRE_RECURSIVE); +#else + dir = ire_lookup(ipa.s_addr); +#endif + + if (!dir) + return 0; + return (ire_to_ill(dir) == ifp); +} diff --git a/contrib/ipfilter/test/expected/i3 b/contrib/ipfilter/test/expected/i3 index 4d70a94..18d9161 100644 --- a/contrib/ipfilter/test/expected/i3 +++ b/contrib/ipfilter/test/expected/i3 @@ -6,3 +6,5 @@ pass in from 128.0.0.0/24 to 128.0.0.0/16 pass in from 128.0.0.0/24 to 128.0.0.0/16 pass in from 127.0.0.1/32 to 127.0.0.1/32 block in log from any to any +block in log level auth.info on hme0(!) from any to any +log level local5.warn out from any to any diff --git a/contrib/ipfilter/test/expected/i7 b/contrib/ipfilter/test/expected/i7 index 2414f57..750cf26 100644 --- a/contrib/ipfilter/test/expected/i7 +++ b/contrib/ipfilter/test/expected/i7 @@ -1,3 +1,4 @@ pass in on ed0(!) proto tcp from 127.0.0.1/32 to 127.0.0.1/32 port = 23 flags S/SA -block in on lo0(!) proto tcp from any to any flags A/FSRPAU +block in on lo0(!) proto tcp from any to any flags A/0xff pass in on lo0(!) proto tcp from any to any flags /SPA +block in on lo0(!) proto tcp from any to any flags 0x80/A diff --git a/contrib/ipfilter/test/expected/n1 b/contrib/ipfilter/test/expected/n1 index 77365f8..c195f6f 100644 --- a/contrib/ipfilter/test/expected/n1 +++ b/contrib/ipfilter/test/expected/n1 @@ -81,16 +81,16 @@ ip 20(20) 255 10.1.1.0 > 10.3.4.5 ip 20(20) 255 10.1.1.1 > 10.3.4.5 ip 20(20) 255 10.1.1.2 > 10.3.4.5 ip 40(20) 6 10.1.1.1,1025 > 10.3.4.5,1025 -ip 48(20) 1 10.3.4.4 > 10.4.3.2 +ip 48(20) 1 10.3.4.2 > 10.4.3.2 ip 48(20) 1 10.4.3.2 > 10.2.2.2 ip 48(20) 1 10.4.3.2 > 10.3.4.3 ip 48(20) 1 10.4.3.2 > 10.3.4.5 -ip 20(20) 34 10.3.4.5 > 10.4.3.2 +ip 20(20) 34 10.3.4.3 > 10.4.3.2 ip 20(20) 34 10.4.3.2 > 10.3.4.4 -ip 20(20) 34 10.3.4.6 > 10.4.3.4 +ip 20(20) 34 10.3.4.3 > 10.4.3.4 ip 20(20) 34 10.4.3.4 > 10.3.4.5 -ip 20(20) 34 10.3.4.7 > 10.4.3.4 -ip 20(20) 34 10.4.3.4 > 10.1.1.2 -ip 20(20) 35 10.3.4.7 > 10.4.3.4 -ip 20(20) 35 10.4.3.4 > 10.1.1.3 +ip 20(20) 34 10.3.4.4 > 10.4.3.4 +ip 20(20) 34 10.4.3.4 > 10.3.4.6 +ip 20(20) 35 10.3.4.4 > 10.4.3.4 +ip 20(20) 35 10.4.3.4 > 10.3.4.7 ------------------------------- diff --git a/contrib/ipfilter/test/regress/i3 b/contrib/ipfilter/test/regress/i3 index e69663e..15e98bf 100644 --- a/contrib/ipfilter/test/regress/i3 +++ b/contrib/ipfilter/test/regress/i3 @@ -6,3 +6,5 @@ pass in from 128.0.0.1 mask 0xffffff00 to 128.0.0.1 mask 0xffff0000 pass in from 128.0.0.1 mask 255.255.255.0 to 128.0.0.1 mask 255.255.0.0 pass in from localhost to localhost block in log from 0/0 to 0/0 +block in log level auth.info on hme0 all +log level local5.warn out all diff --git a/contrib/ipfilter/test/regress/i7 b/contrib/ipfilter/test/regress/i7 index 9cb3572..4f3328d 100644 --- a/contrib/ipfilter/test/regress/i7 +++ b/contrib/ipfilter/test/regress/i7 @@ -1,3 +1,4 @@ pass in on ed0 proto tcp from localhost to localhost port = 23 flags S/SA block in on lo0 proto tcp from any to any flags A pass in on lo0 proto tcp from any to any flags /SAP +block in on lo0 proto tcp from any to any flags 0x80/A diff --git a/contrib/ipfilter/todo b/contrib/ipfilter/todo index 6b59675..1a7bdb5 100644 --- a/contrib/ipfilter/todo +++ b/contrib/ipfilter/todo @@ -17,20 +17,20 @@ time permitting: * record buffering for TCP/UDP * modular application proxying -on the way - -* keep fragment information for state entries automatically. -done for NAT +available * allow multiple ip addresses in a source route list for ipsend * complete Linux port to implement all the IP Filter features return-rst done, to/dup-to/fastroute remain - ip_forward() problems :-( +on hold until rewrite * add a flag to automate src spoofing +done * ipfsync() should change IP#'s in current mappings as well as what's in rules. +done * document bimap @@ -39,4 +39,59 @@ return-rst done, to/dup-to/fastroute remain - ip_forward() problems :-( * add more docs in progress +3.4: +XDDD. I agree. Bandwidth Shapping and QoS (Quality of Service, AKA +traffic priorization) should be *TOP* in the TO DO list. + +* irc proxy for dcc +* Bandwidth limiting!!! +* More examples +* More documentation +* And did I mention bandwidth limiting??? +* Load balancing features added to the NAT code, so that I can have +something coming in for 20.20.20.20:80 and it gets shuffled around between +internal addresses 10.10.10.1:8000 and 10.10.10.2:8000. or whatever. +- done, stage 1 (round robin/split) +The one thing that Cisco's PIX has on IPF that I can see is that +rewrites the sequence numbers with semi-random ones. + +I would also love to see a more extensive NAT. It can choose to do +rdr and map based on saddr, daddr, sport and dport. (Does the kernel +module already have functionality for that and it just needs support in +the userland ipnat?) + + * intrusion detection + detection of port scans + detection of multiple connection attempts + + * support for multiple log files + i.e. all connections to ftp and telnet logged to + a seperate log file + + * multiple levels of log severity with E-mail notification + of intrusion alerts or other high priority errors + + * poison pill facility + after detection of a port scan, start sending back + large packets of garbage or other packets to + otherwise confuse the intruder (ping of death?) + +* I ran into your solaris streams stuff and noticed you are +playing with mblk's in an unsafe way. You seem to be modifying the +underlying datab without checking db_ref. If db_ref is greater than one, +you'll need to copy the mblk, +- fixed + * fix up where manual pages go for Solaris2 + + +IPv6: +----- +* NAT is yet not available, either as a null proxy or address translation + +BSD: +* "to <if>" and "to <if>:<ip>" are not supported, but "fastroute" is. + +Solaris: +* "to <if>:<ip>" is not supported, but "fastroute" is and "to <if>" are. + |