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 | 9a5646e13d0f86d72d78eb42cb8c334aa2ecb185 (patch) | |
tree | 2f7dac018c2a19ebecc610cd1aa4a1e9a827744d /contrib | |
parent | defab84a4607e971ec302bbb732068539f59075c (diff) | |
parent | dda6755c7b3b3b5d3e9111b7d0c39a7d8b5f3e12 (diff) | |
download | FreeBSD-src-9a5646e13d0f86d72d78eb42cb8c334aa2ecb185.zip FreeBSD-src-9a5646e13d0f86d72d78eb42cb8c334aa2ecb185.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r60841,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib')
87 files changed, 9939 insertions, 3247 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/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/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/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/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. + |