diff options
Diffstat (limited to 'contrib/ipfilter')
458 files changed, 60111 insertions, 11191 deletions
diff --git a/contrib/ipfilter/.cvsignore b/contrib/ipfilter/.cvsignore new file mode 100644 index 0000000..616828f --- /dev/null +++ b/contrib/ipfilter/.cvsignore @@ -0,0 +1,28 @@ +ipf +sparcv7 +sparcv9 +h +ipf-darren +bugs +ipftest +patches +state +cbits +CVS +old +new +netinet +import +bak +streams +cvs.diff +threads +glibc +hp +windows +ipnat +opt_inet6.h +ippool +ipmon +ip_rules.c +ip_rules.h diff --git a/contrib/ipfilter/BNF b/contrib/ipfilter/BNF index cf30ab6..404cc28 100644 --- a/contrib/ipfilter/BNF +++ b/contrib/ipfilter/BNF @@ -1,25 +1,26 @@ filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] - [ proto ] [ ip ] [ group ]. + [ proto ] [ ip ] [ group ] [ tag ] [ pps ] . insert = "@" decnumber . -action = block | "no-match" | "pass" | log | "count" | skip | auth | call . +action = block | "pass" | log | "count" | auth | call . in-out = "in" | "out" . -options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] - [ via ] ] . +options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] . tos = "tos" decnumber | "tos" hexnumber . ttl = "ttl" decnumber . proto = "proto" protocol . ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . group = [ "head" decnumber ] [ "group" decnumber ] . +pps = "pps" decnumber . +onif = "on" interface-name [ "out-via" interface-name ] . block = "block" [ return-icmp[return-code] | "return-rst" ] . auth = "auth" | "preauth" . log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . -call = "call" [ "now" ] function-name . -skip = "skip" decnumber . +tag = "tag" tagid . +call = "call" [ "now" ] function-name "/" decnumber. dup = "dup-to" interface-name[":"ipaddr] . -via = "in-via" interface-name | "out-via" interface-name . -froute = "fastroute" | "to" interface-name [ ":" ipaddr ] . +froute = "fastroute" | "to" interface-name . +replyto = "reply-to" interface-name [ ":" ipaddr ] . protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . srcdst = "all" | fromto . fromto = "from" object "to" object . @@ -34,8 +35,7 @@ flags = "flags" flag { flag } [ "/" flag { flag } ] . with = "with" | "and" . icmp = "icmp-type" icmp-type [ "code" decnumber ] . return-code = "("icmp-code")" . -keep = "keep" "state" | "keep" "frags" | "keep" "state-age" state-age . -state-age = decnmber [ "/" decnumber ] . +keep = "keep" "state" [ "limit" number ] | "keep" "frags" . nummask = host-name [ "/" decnumber ] . host-name = ipaddr | hostname | "any" . @@ -43,8 +43,9 @@ ipaddr = host-num "." host-num "." host-num "." host-num . host-num = digit [ digit [ digit ] ] . port-num = service-name | decnumber . -withopt = [ "not" | "no" ] opttype [ withopt ] . -opttype = "ipopts" | "short" | "frag" | "opt" ipopts . +withopt = [ "not" | "no" ] opttype [ [ "," ] withopt ] . +opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" | + "mbcast" | "opt" ipopts . optname = ipopts [ "," optname ] . ipopts = optlist | "sec-class" [ secname ] . secname = seclvl [ "," secname ] . @@ -77,4 +78,4 @@ compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | range = "<>" | "><" . hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . -flag = "F" | "S" | "R" | "P" | "A" | "U" . +flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" . diff --git a/contrib/ipfilter/BSD/.cvsignore b/contrib/ipfilter/BSD/.cvsignore new file mode 100644 index 0000000..c149a00 --- /dev/null +++ b/contrib/ipfilter/BSD/.cvsignore @@ -0,0 +1,22 @@ +ipf +ipfs +ipfstat +ipftest +ipmon +ipnat +ipresend +ipsend +iptest +vnode_if.h +if_ipl +i386 +amiga +FreeBSD* +BSDOS* +NetBSD* +OpenBSD* +*_lex_var.h +*_y.c +*_l.c +*_y.h +ip_rules.* diff --git a/contrib/ipfilter/BSD/Makefile b/contrib/ipfilter/BSD/Makefile index 50a61e8..72086a0 100644 --- a/contrib/ipfilter/BSD/Makefile +++ b/contrib/ipfilter/BSD/Makefile @@ -1,16 +1,14 @@ # # Copyright (C) 1993-1998 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. +# See the IPFILTER.LICENCE file for details on licencing. # BINDEST=/usr/sbin SBINDEST=/sbin -SEARCHDIRS=$(BINDEST) $(SBINDEST) /bin /usr/bin /sbin /usr/sbin \ - /usr/local/bin /usr/local/sbin MANDIR=/usr/share/man -CC=cc -Wall -Wstrict-prototypes -Wuninitialized -O +SEARCHDIRS!=echo $(BINDEST) $(SBINDEST) /bin /usr/bin /sbin /usr/sbin /usr/local/bin /usr/local/sbin | awk '{for(i=1;i<NF;i++){print $$i;}}' - | sort -u + +CC=cc -Wall -Wuninitialized -Wstrict-prototypes -O CFLAGS=-g -I$(TOP) # # For NetBSD/FreeBSD @@ -21,16 +19,19 @@ INC=-I/usr/include -I/sys -I/sys/sys -I/sys/arch DEF=-D$(CPU) -D__$(CPU)__ -DINET -DKERNEL -D_KERNEL $(INC) $(DEVFS) IPDEF=$(DEF) -DGATEWAY -DDIRECTED_BROADCAST VNODESHDIR=/sys/kern -MLD=$(ML) vnode_if.h +MLD=$(ML) ML=mln_ipl.c -IPFILC=ip_fil.c LKM=if_ipl.o +LKMR=ipfrule.o DLKM= +OBJ=. +DEST=$(OBJ) MFLAGS="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" \ 'CFLAGS=$(CFLAGS) $(SOLARIS2)' "IPFLKM=$(IPFLKM)" \ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \ - "CPUDIR=$(CPUDIR)" + "CPUDIR=$(CPUDIR)" "LOOKUP=$(LOOKUP)" "SYNC=$(SYNC)" +LIBS=-L. -lipf $(LIBBPF) # ########## ########## ########## ########## ########## ########## ########## # @@ -39,205 +40,425 @@ RM=/bin/rm CHMOD=/bin/chmod 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) $(DEF) $(DLKM) -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 ip_log_u.o natparse.o facpri.o \ - printnat.o printstate.o -IPNAT=ipnat.o kmem.o natparse.o common.o printnat.o -FILS=fils.o parse.o kmem.o opt.o facpri.o common.o printstate.o - -build all: ipf ipfs ipfstat ipftest ipmon ipnat $(LKM) - /bin/rm -f $(TOP)/ipf - ln -s `pwd`/ipf $(TOP) - /bin/rm -f $(TOP)/ipftest - ln -s `pwd`/ipftest $(TOP) - /bin/rm -f $(TOP)/ipmon - ln -s `pwd`/ipmon $(TOP) - /bin/rm -f $(TOP)/ipnat - ln -s `pwd`/ipnat $(TOP) - -ipfstat: $(FILS) - $(CC) -static $(DEBUG) $(CFLAGS) $(STATETOP_CFLAGS) $(STATETOP_INC) \ - $(FILS) -o $@ $(LIBS) $(STATETOP_LIB) -lkvm - -ipf: $(IPF) - $(CC) -static $(DEBUG) $(CFLAGS) $(IPF) -o $@ $(LIBS) - -ipftest: $(IPT) - $(CC) $(DEBUG) $(CFLAGS) $(IPT) -o $@ $(LIBS) - -ipnat: $(IPNAT) - $(CC) -static $(DEBUG) $(CFLAGS) $(IPNAT) -o $@ $(LIBS) -lkvm +MODOBJS=ip_fil.o fil.o ml_ipl.o ip_nat.o ip_frag.o ip_state.o ip_proxy.o \ + ip_auth.o ip_log.o ip_pool.o ip_htable.o ip_lookup.o ip_rules.o \ + ip_scan.o ip_sync.o +# ip_trafcon.o +DFLAGS=$(IPFLKM) $(IPFLOG) $(LOOKUP) $(SYNC) $(DEF) $(DLKM) $(IPFBPF) +IPF=ipf.o ipfcomp.o ipf_y.o ipf_l.o +IPT=ipftest.o fil_u.o ip_frag_u.o ip_state_u.o ip_nat_u.o \ + ip_proxy_u.o ip_auth_u.o ip_htable_u.o ip_lookup_u.o ip_pool_u.o \ + ip_scan_u.o ip_sync_u.o ip_rules_u.o ip_fil_u.o ip_log_u.o \ + ippool_y.o ippool_l.o ipf_y.o ipf_l.o ipnat_y.o ipnat_l.o \ + md5_u.o radix_u.o bpf_filter_u.o +# ip_syn_u.o +#ip_trafcon_u.o +TOOL=$(TOP)/tools +IPNAT=ipnat.o ipnat_y.o ipnat_l.o +IPMON=ipmon.o ipmon_y.o ipmon_l.o +IPPOOL=ippool_y.o ippool_l.o kmem.o ippool.o +IPTRAFCON=iptrafcon.o +PROXYLIST=$(TOP)/ip_ftp_pxy.c $(TOP)/ip_ipsec_pxy.c $(TOP)/ip_irc_pxy.c \ + $(TOP)/ip_netbios_pxy.c $(TOP)/ip_raudio_pxy.c $(TOP)/ip_rcmd_pxy.c \ + $(TOP)/ip_rpcb_pxy.c $(TOP)/ip_pptp_pxy.c +FILS=ipfstat.o +LIBSRC=$(TOP)/lib +RANLIB=ranlib +AROPTS=cq +HERE!=pwd +CCARGS=-I. $(DEBUG) $(CFLAGS) +# +# Extra is option kernel things we always want in user space. +# +EXTRA=$(ALLOPTS) + +include $(TOP)/lib/Makefile + +build all: machine $(OBJ)/libipf.a ipf ipfs ipfstat ipftest ipmon ipnat \ + ippool ipscan ipsyncm ipsyncs $(LKM) $(LKMR) + -sh -c 'for i in ipf ipftest ipmon ippool ipnat ipscan ipsyncm ipsyncs; do /bin/rm -f $(TOP)/$$i; ln -s `pwd`/$$i $(TOP); done' + +machine: Makefile.kmod + if [ -f Makefile.kmod ] ; then \ + make -f Makefile.kmod depend MKUPDATE=no; \ + fi + +Makefile.kmod: + if [ -f /usr/share/mk/bsd.kmod.mk -a "`uname -s`" = "NetBSD" ] ; then \ + rm -f Makefile.kmod; \ + ln -s /usr/share/mk/bsd.kmod.mk Makefile.kmod; \ + fi + +ipfstat: $(FILS) $(OBJ)/libipf.a + $(CC) $(CCARGS) $(STATETOP_CFLAGS) $(STATETOP_INC) $(FILS) \ + -o $@ $(LIBS) $(STATETOP_LIB) -lkvm + +ipf: $(IPF) $(OBJ)/libipf.a + $(CC) $(CCARGS) $(IPF) -o $@ $(LIBS) -ll $(LIBBPF) + +ipftest: $(IPT) $(OBJ)/libipf.a + $(CC) $(CCARGS) $(IPT) -o $@ $(LIBS) -ll $(LIBBPF) + +ipnat: $(IPNAT) $(OBJ)/libipf.a + $(CC) $(CCARGS) $(IPNAT) -o $@ $(LIBS) -lkvm -ll ipfs: ipfs.o - $(CC) -static $(DEBUG) $(CFLAGS) ipfs.o -o $@ $(LIBS) + $(CC) $(CCARGS) ipfs.o -o $@ -tests: - (cd test; make ) +ipsyncm: ipsyncm.o $(OBJ)/libipf.a + $(CC) $(CCARGS) ipsyncm.o -o $@ $(LIBS) -fils.o: $(TOP)/fils.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_frag.h \ - $(TOP)/ip_compat.h $(TOP)/ip_state.h $(TOP)/ip_nat.h - $(CC) $(DEBUG) $(CFLAGS) $(STATETOP_CFLAGS) $(STATETOP_INC) \ - -c $(TOP)/fils.c -o $@ +ipsyncs: ipsyncs.o $(OBJ)/libipf.a + $(CC) $(CCARGS) ipsyncs.o -o $@ $(LIBS) -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 $@ +ipsyncm.o: $(TOOL)/ipsyncm.c $(TOP)/ip_sync.h + $(CC) $(CCARGS) -c $(TOOL)/ipsyncm.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 $@ +ipsyncs.o: $(TOOL)/ipsyncs.c $(TOP)/ip_sync.h + $(CC) $(CCARGS) -c $(TOOL)/ipsyncs.c -o $@ -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 $@ +tests: + (cd test; make ) -ipf.o: $(TOP)/ipf.c $(TOP)/ip_fil.h $(TOP)/ipf.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipf.c -o $@ +ipfstat.o: $(TOOL)/ipfstat.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_frag.h \ + $(TOP)/ip_compat.h $(TOP)/ip_state.h $(TOP)/ip_nat.h $(TOP)/opts.h + $(CC) $(CCARGS) $(STATETOP_CFLAGS) $(STATETOP_INC) \ + -c $(TOOL)/ipfstat.c -o $@ -ipt.o: $(TOP)/ipt.c $(TOP)/ip_fil.h $(TOP)/ipt.h $(TOP)/ipf.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipt.c -o $@ +ipfs.o: $(TOOL)/ipfs.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_state.h \ + $(TOP)/ip_nat.h $(TOP)/opts.h + $(CC) $(CCARGS) -c $(TOOL)/ipfs.c -o $@ -misc.o: $(TOP)/misc.c $(TOP)/ip_fil.h $(TOP)/ipt.h $(TOP)/ipf.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/misc.c -o $@ +fil_u.o: $(TOP)/fil.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_compat.h \ + $(TOP)/opts.h $(TOP)/ip_rules.h + $(CC) $(CCARGS) $(EXTRA) $(IPFBPF) -D_RADIX_H_ -c $(TOP)/fil.c -o $@ -opt.o: $(TOP)/opt.c $(TOP)/ip_fil.h $(TOP)/ipf.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/opt.c -o $@ +fil.o: $(TOP)/fil.c $(TOP)/ip_fil.h $(TOP)/ip_compat.h $(TOP)/ipl.h \ + $(TOP)/ip_rules.h + $(CC) $(CCARGS) $(POLICY) $(DFLAGS) $(IPFBPF) $(COMPIPF) \ + -c $(TOP)/fil.c -o $@ -ipnat.o: $(TOP)/ipnat.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_nat.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipnat.c -o $@ +ipf.o: $(TOOL)/ipf.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/opts.h + $(CC) $(CCARGS) -c $(TOOL)/ipf.c -o $@ -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 $@ +ipfcomp.o: $(TOOL)/ipfcomp.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/opts.h + $(CC) $(CCARGS) -c $(TOOL)/ipfcomp.c -o $@ -printnat.o: $(TOP)/printnat.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_nat.h \ - $(TOP)/ip_compat.h $(TOP)/ip_proxy.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/printnat.c -o $@ +ipftest.o: $(TOOL)/ipftest.c $(TOP)/ip_fil.h $(TOP)/ipt.h $(TOP)/ipf.h \ + $(TOP)/opts.h + $(CC) $(CCARGS) -c $(TOOL)/ipftest.c -o $@ -printstate.o: $(TOP)/printstate.c $(TOP)/ip_fil.h $(TOP)/ipf.h \ - $(TOP)/ip_state.h $(TOP)/ip_compat.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/printstate.c -o $@ +ipnat.o: $(TOOL)/ipnat.c $(TOP)/ip_fil.h $(TOP)/ipf.h $(TOP)/ip_nat.h \ + $(TOP)/opts.h + $(CC) $(CCARGS) -c $(TOOL)/ipnat.c -o $@ -ipft_sn.o: $(TOP)/ipft_sn.c $(TOP)/ipt.h $(TOP)/ipf.h $(TOP)/ip_fil.h \ - $(TOP)/snoop.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipft_sn.c -o $@ +ipnat_y.o: ipnat_y.c ipnat_y.h ipnat_l.h + $(CC) $(CCARGS) -c ipnat_y.c -o $@ -ipft_ef.o: $(TOP)/ipft_ef.c $(TOP)/ipf.h $(TOP)/ip_fil.h $(TOP)/ipt.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipft_ef.c -o $@ +ipnat_l.o: ipnat_l.c ipnat_y.h + $(CC) $(CCARGS) -I. -c ipnat_l.c -o $@ -ipft_td.o: $(TOP)/ipft_td.c $(TOP)/ipf.h $(TOP)/ip_fil.h $(TOP)/ipt.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipft_td.c -o $@ +ipnat_y.c: $(TOOL)/ipnat_y.y + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) -ipft_pc.o: $(TOP)/ipft_pc.c $(TOP)/ipf.h $(TOP)/ip_fil.h $(TOP)/ipt.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipft_pc.c -o $@ +ipnat_y.h: ipnat_y.c -ipft_tx.o: $(TOP)/ipft_tx.c $(TOP)/ipf.h $(TOP)/ip_fil.h $(TOP)/ipt.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipft_tx.c -o $@ +ipnat_l.c: $(TOOL)/lexer.c $(TOP)/ip_nat.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) -ipft_hx.o: $(TOP)/ipft_hx.c $(TOP)/ipf.h $(TOP)/ip_fil.h $(TOP)/ipt.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipft_hx.c -o $@ +ipnat_l.h: $(TOOL)/lexer.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) ip_nat_u.o: $(TOP)/ip_nat.c $(TOP)/ip_nat.h $(TOP)/ip_compat.h $(TOP)/ip_fil.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_nat.c -o $@ + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_nat.c -o $@ ip_proxy_u.o: $(TOP)/ip_proxy.c $(TOP)/ip_proxy.h $(TOP)/ip_compat.h \ - $(TOP)/ip_fil.h $(TOP)/ip_ftp_pxy.c $(TOP)/ip_rcmd_pxy.c \ - $(TOP)/ip_raudio_pxy.c $(TOP)/ip_ipsec_pxy.c $(TOP)/ip_nat.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_proxy.c -o $@ + $(TOP)/ip_fil.h $(PROXYLIST) $(TOP)/ip_nat.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_proxy.c -o $@ ip_frag_u.o: $(TOP)/ip_frag.c $(TOP)/ip_frag.h $(TOP)/ip_compat.h \ $(TOP)/ip_fil.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_frag.c -o $@ + $(CC) $(CCARGS) $(EXTRA) -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_nat.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_state.c -o $@ + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_state.c -o $@ ip_auth_u.o: $(TOP)/ip_auth.c $(TOP)/ip_auth.h $(TOP)/ip_compat.h \ $(TOP)/ip_fil.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_auth.c -o $@ + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_auth.c -o $@ + +ip_fil_u.o: $(TOP)/ip_fil.c $(TOP)/ip_fil.h $(TOP)/ip_compat.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_fil.c -o $@ + +ip_rules_u.o: ip_rules.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_rules.h + $(CC) $(CCARGS) $(EXTRA) -c ip_rules.c -o $@ + +ip_scan_u.o: $(TOP)/ip_scan.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_scan.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_scan.c -o $@ -ip_fil_u.o: $(TOP)/$(IPFILC) $(TOP)/ip_fil.h $(TOP)/ip_compat.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/$(IPFILC) -o $@ +ip_sync_u.o: $(TOP)/ip_sync.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_sync.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_sync.c -o $@ + +ip_pool_u.o: $(TOP)/ip_pool.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_pool.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_pool.c -o $@ + +ip_htable_u.o: $(TOP)/ip_htable.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_htable.c -o $@ + +ip_lookup_u.o: $(TOP)/ip_lookup.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_lookup.h $(TOP)/ip_pool.h $(TOP)/ip_htable.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_lookup.c -o $@ + +ip_trafcon_u.o: $(TOP)/ip_trafcon.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_trafcon.h + $(CC) $(CCARGS) -c $(TOP)/ip_trafcon.c -o $@ ip_log_u.o: $(TOP)/ip_log.c $(TOP)/ip_fil.h $(TOP)/ip_compat.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ip_log.c -o $@ + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/ip_log.c -o $@ + +md5_u.o: $(TOP)/md5.c $(TOP)/md5.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/md5.c -o $@ + +radix_u.o: $(TOP)/md5.c $(TOP)/radix_ipf.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/radix.c -o $@ + +bpf_filter_u.o: $(TOP)/bpf_filter.c $(TOP)/pcap-ipf.h + $(CC) $(CCARGS) $(EXTRA) -c $(TOP)/bpf_filter.c -o $@ if_ipl.o: $(MODOBJS) ld -r $(MODOBJS) -o $(LKM) ${RM} -f if_ipl +ipfrule.ko.5: ip_rulesx.o $(MLR) + ld -warn-common -r -d -o $(.TARGET:S/.ko/.kld/) ip_rulesx.o $(MLR) + ld -Bshareable -d -warn-common -o $(LKMR:S/.5$//) $(.TARGET:S/.ko/.kld/) +ipfrule.ko: ip_rulesx.o $(MLR) + gensetdefs ip_rulesx.o $(MLR) + $(CC) $(CCARGS) -c setdef0.c + $(CC) $(CCARGS) -c setdef1.c + ld -Bshareable -o $@ setdef0.o ip_rulesx.o $(MLR) setdef1.o + +ipf.ko.5 ipl.ko.5: $(MODOBJS) + ld -warn-common -r -d -o $(.TARGET:S/.ko/.kld/) $(MODOBJS) + ld -Bshareable -d -warn-common -o $(LKM:S/.5$//) $(.TARGET:S/.ko/.kld/) + 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 + $(CC) $(CCARGS) -c setdef0.c + $(CC) $(CCARGS) -c setdef1.c + ld -Bshareable -o $@ 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 $@ + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_nat.c -o $@ 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 $@ + $(CC) $(CCARGS) $(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_nat.h - $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/ip_state.c -o $@ + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_state.c -o $@ ip_proxy.o: $(TOP)/ip_proxy.c $(TOP)/ip_proxy.h $(TOP)/ip_compat.h \ - $(TOP)/ip_fil.h $(TOP)/ip_ftp_pxy.c $(TOP)/ip_raudio_pxy.c \ - $(TOP)/ip_rcmd_pxy.c $(TOP)/ip_ipsec_pxy.c $(TOP)/ip_nat.h - $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/ip_proxy.c -o $@ + $(TOP)/ip_fil.h $(PROXYLIST) $(TOP)/ip_nat.h + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_proxy.c -o $@ ip_auth.o: $(TOP)/ip_auth.c $(TOP)/ip_auth.h $(TOP)/ip_compat.h \ $(TOP)/ip_fil.h - $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/ip_auth.c -o $@ + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_auth.c -o $@ + +ip_fil.c: + /bin/rm -f ip_fil.c + ln -s $(TOP)/ip_fil_`uname -s|tr A-Z a-z`.c ip_fil.c -ip_fil.o: $(TOP)/$(IPFILC) $(TOP)/ip_fil.h $(TOP)/ip_compat.h $(TOP)/ip_nat.h - $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/$(IPFILC) -o $@ +ip_fil.o: ip_fil.c $(TOP)/ip_fil.h $(TOP)/ip_compat.h $(TOP)/ip_nat.h + $(CC) $(CCARGS) $(DFLAGS) $(COMPIPF) -c ip_fil.c -o $@ ip_log.o: $(TOP)/ip_log.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h - $(CC) $(DEBUG) $(CFLAGS) $(DFLAGS) -c $(TOP)/ip_log.c -o $@ + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_log.c -o $@ -vnode_if.h: $(VNODESHDIR)/vnode_if.sh $(VNODESHDIR)/vnode_if.src +ip_scan.o: $(TOP)/ip_scan.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h $(TOP)/ip_scan.h + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_scan.c -o $@ + +ip_sync.o: $(TOP)/ip_sync.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h $(TOP)/ip_sync.h + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_sync.c -o $@ + +ip_pool.o: $(TOP)/ip_pool.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_lookup.h $(TOP)/ip_pool.h + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_pool.c -o $@ + +ip_htable.o: $(TOP)/ip_htable.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_lookup.h $(TOP)/ip_htable.h + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_htable.c -o $@ + +ip_lookup.o: $(TOP)/ip_lookup.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_pool.h $(TOP)/ip_htable.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_lookup.c -o $@ + +ip_trafcon.o: $(TOP)/ip_trafcon.c $(TOP)/ip_compat.h $(TOP)/ip_fil.h \ + $(TOP)/ip_trafcon.h + $(CC) $(CCARGS) $(DFLAGS) -c $(TOP)/ip_trafcon.c -o $@ + +vnode_if.h: $(VNODESHDIR)/vnode_if.src mkdir -p ../sys - sh $(VNODESHDIR)/vnode_if.sh $(VNODESHDIR)/vnode_if.src + if [ -f $(VNODESHDIR)/vnode_if.sh ] ; then \ + sh $(VNODESHDIR)/vnode_if.sh $(VNODESHDIR)/vnode_if.src; \ + fi + if [ -f $(VNODESHDIR)/vnode_if.pl ] ; then \ + perl $(VNODESHDIR)/vnode_if.pl $(VNODESHDIR)/vnode_if.src; \ + fi if [ -f ../sys/vnode_if.h ] ; then mv ../sys/vnode_if.h .; fi rmdir ../sys -ml_ipl.o: $(TOP)/$(MLD) $(TOP)/ipl.h +ml_ipl.o: vnode_if.h $(TOP)/$(MLD) $(TOP)/ipl.h -/bin/rm -f vnode_if.c $(CC) -I. $(CFLAGS) $(DFLAGS) -c $(TOP)/$(ML) -o $@ -kmem.o: $(TOP)/kmem.c - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/kmem.c -o $@ +ip_rules.o: ip_rules.c $(TOP)/ip_rules.h + $(CC) -I. $(CFLAGS) $(DFLAGS) $(COMPIPF) -c ip_rules.c -o $@ + +ip_rules.c: $(TOP)/rules/ip_rules $(TOP)/tools/ipfcomp.c ipf + ./ipf -cc -nf $(TOP)/rules/ip_rules + +$(TOP)/ip_rules.h: ip_rules.c + if [ ! -f $(TOP)/ip_rules.h ] ; then \ + /bin/mv -f ip_rules.h $(TOP); \ + else \ + touch $(TOP)/ip_rules.h; \ + fi + +ip_rulesx.o: ip_rules.c $(TOP)/ip_rules.h + $(CC) -I. $(CFLAGS) $(DFLAGS) -DIPFILTER_COMPILED -c ip_rules.c -o $@ + +mlf_rule.o: $(TOP)/mlf_rule.c $(TOP)/ip_rules.h + $(CC) -I. $(CFLAGS) $(DFLAGS) -c $(TOP)/mlf_rule.c -o $@ + +mln_rule.o: $(TOP)/mln_rule.c $(TOP)/ip_rules.h + $(CC) -I. $(CFLAGS) $(DFLAGS) -c $(TOP)/mln_rule.c -o $@ + +mlo_rule.o: $(TOP)/mlo_rule.c $(TOP)/ip_rules.h + $(CC) -I. $(CFLAGS) $(DFLAGS) -c $(TOP)/mlo_rule.c -o $@ + +mlfk_rule.o: $(TOP)/mlfk_rule.c $(TOP)/ip_rules.h + $(CC) -I. $(CFLAGS) $(DFLAGS) -c $(TOP)/mlfk_rule.c -o $@ + +ipf_y.o: ipf_y.c ipf_y.h $(TOP)/ipf.h ipf_l.h $(TOP)/opts.h + $(CC) $(CCARGS) $(IPFBPF) -c ipf_y.c -o $@ + +ipf_l.o: ipf_l.c ipf_y.h $(TOP)/ipf.h ipf_l.h $(TOP)/opts.h + $(CC) $(CCARGS) -I. -c ipf_l.c -o $@ + +ipf_y.c: $(TOOL)/ipf_y.y $(TOP)/ipf.h $(TOP)/opts.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ipf_y.h: ipf_y.c + +ipf_l.c: $(TOOL)/lexer.c $(TOP)/ipf.h $(TOP)/opts.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ipf_l.h: $(TOOL)/lexer.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ipmon: $(IPMON) $(OBJ)/libipf.a + $(CC) $(CCARGS) $(IPMON) -o $@ $(LIBS) -ll + +ipmon.o: $(TOOL)/ipmon.c $(TOP)/ipmon.h + $(CC) $(CCARGS) $(LOGFAC) -c $(TOOL)/ipmon.c -o $@ + +ipmon_y.o: ipmon_y.c ipmon_y.h $(TOP)/ipmon.h ipmon_l.h + $(CC) $(CCARGS) -c ipmon_y.c -o $@ + +ipmon_l.o: ipmon_l.c ipmon_y.h $(TOP)/ipmon.h + $(CC) $(CCARGS) -I. -c ipmon_l.c -o $@ + +ipmon_y.c: $(TOOL)/ipmon_y.y $(TOP)/ipmon.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ipmon_y.h: ipmon_y.c + +ipmon_l.c: $(TOOL)/lexer.c $(TOP)/ipmon.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ipmon_l.h: $(TOOL)/lexer.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) -parse.o: $(TOP)/parse.c $(TOP)/ip_fil.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/parse.c -o $@ +ipscan: ipscan_y.o ipscan_l.o + $(CC) $(DEBUG) ipscan_y.o ipscan_l.o -o $@ -ll $(LIBS) -lkvm -common.o: $(TOP)/common.c $(TOP)/ip_fil.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/common.c -o $@ +ipscan_y.o: ipscan_y.c ipscan_y.h $(TOP)/ip_scan.h ipscan_l.h + $(CC) $(CCARGS) -c ipscan_y.c -o $@ -facpri.o: $(TOP)/facpri.c $(TOP)/facpri.h - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/facpri.c -o $@ +ipscan_l.o: ipscan_l.c ipscan_y.h $(TOP)/ip_scan.h + $(CC) $(CCARGS) -I. -c ipscan_l.c -o $@ -ipmon: $(TOP)/ipmon.c - $(CC) $(DEBUG) $(CFLAGS) $(LOGFAC) $(TOP)/ipmon.c -o $@ $(LIBS) +ipscan_y.c: $(TOOL)/ipscan_y.y $(TOP)/ip_scan.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ipscan_y.h: ipscan_y.c + +ipscan_l.c ipscan_l.h: $(TOOL)/lexer.c $(TOP)/ip_scan.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ippool: $(IPPOOL) $(OBJ)/libipf.a + $(CC) $(DEBUG) -I. $(CFLAGS) $(IPPOOL) -o $@ -ll -lkvm -L. -lipf + +ippool.o: $(TOOL)/ippool.c $(TOP)/ip_pool.h + $(CC) $(CCARGS) -c $(TOOL)/ippool.c -o $@ + +ippool_y.o: ippool_y.c ippool_y.h $(TOP)/ip_pool.h ippool_l.h + $(CC) $(CCARGS) -c ippool_y.c -o $@ + +ippool_l.o: ippool_l.c ippool_y.h $(TOP)/ip_pool.h + $(CC) $(CCARGS) -I. -c ippool_l.c -o $@ + +ippool_y.c: $(TOOL)/ippool_y.y $(TOP)/ip_pool.h ippool_l.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ippool_y.h: ippool_y.c + +ippool_l.c: $(TOOL)/lexer.c $(TOP)/ip_pool.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +ippool_l.h: $(TOOL)/lexer.h + (cd $(TOOL); make "DEST=$(HERE)" $(HERE)/$@) + +iptrafcon.o: $(TOP)/iptrafcon.c + $(CC) $(CCARGS) -c $< -o $@ + +iptrafcon: $(IPTRAFCON) $(OBJ)/libipf.a + $(CC) $(CCARGS) $(IPTRAFCON) -o $@ $(LIBS) + +.y.c: + +.l.c: clean: - ${RM} -f *.core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl ipnat \ - vnode_if.h $(LKM) ioconf.h *.ko setdef1.c setdef0.c setdefs.h \ - y.tab.? lex.yy.c ipfs - ${RM} -f ../opt_inet6.h ../ipftest ../ipmon ../ipf ../ipnat + ${RM} -f ../ipf ../ipnat ../ipmon ../ippool ../ipftest + ${RM} -f ../ipscan ../ipsyncm ../ipsyncs + ${RM} -f *.core *.o *.a ipt ipfstat ipf ipfstat ipftest ipmon + ${RM} -f if_ipl ipnat ipfrule.ko* ipf.kld* + ${RM} -f vnode_if.h $(LKM) ioconf.h *.ko setdef1.c setdef0.c setdefs.h + ${RM} -f ip_fil.c ipf_l.c ipf_y.c ipf_y.h ipf_l.h + ${RM} -f ipscan ipscan_y.c ipscan_y.h ipscan_l.c ipscan_l.h + ${RM} -f ippool ippool_y.c ippool_y.h ippool_l.c ippool_l.h + ${RM} -f ipnat_y.c ipnat_y.h ipnat_l.c ipnat_l.h + ${RM} -f ipmon_y.c ipmon_y.h ipmon_l.c ipmon_l.h + ${RM} -f ipsyncm ipsyncs ipfs ip_rules.c ip_rules.h ${MAKE} -f Makefile.ipsend ${MFLAGS} clean + if [ -f Makefile.kmod ] ; then \ + ${MAKE} -f Makefile.kmod ${MFLAGS} clean; \ + fi -(for i in *; do \ if [ -d $${i} -a -f $${i}/Makefile ] ; then \ - cd $${i}; (make clean); cd ..; \ - rm $${i}/Makefile $${i}/Makefile.ipsend; \ + cd $${i}; (make TOP=../.. clean); cd ..; \ + /bin/rm -f $${i}/Makefile $${i}/Makefile.ipsend; \ + /bin/rm -f $${i}/Makefile.kmod; \ rmdir $${i}; \ fi \ done) @@ -254,15 +475,31 @@ install: -if [ -d /modules -a -f ipf.ko ] ; then \ cp ipf.ko /modules; \ fi + -if [ -d /modules -a -f ipfrule.ko ] ; then \ + cp ipfrule.ko /modules; \ + fi + -if [ -d /boot/kernel -a -f ipf.ko ] ; then \ + cp ipf.ko /boot/kernel; \ + fi + -if [ -d /boot/kernel -a -f ipfrule.ko ] ; then \ + cp ipfrule.ko /boot/kernel; \ + fi + -if [ -d /usr/lkm -a -f if_ipl.o ] ; then \ + cp if_ipl.o /usr/lkm; \ + fi + -$(INSTALL) -cs -g wheel -m 755 -o root ipscan $(SBINDEST) + (cd $(TOP)/man; make INSTALL=$(INSTALL) MANDIR=$(MANDIR) install; cd $(TOP)) @for i in ipf:$(SBINDEST) ipfs:$(SBINDEST) ipnat:$(SBINDEST) \ + ippool:$(BINDEST) ipsyncm:$(BINDEST) ipsyncs:$(BINDEST) \ ipfstat:$(SBINDEST) ipftest:$(SBINDEST) ipmon:$(BINDEST); do \ def="`expr $$i : '[^:]*:\(.*\)'`"; \ p="`expr $$i : '\([^:]*\):.*'`"; \ + dd=; \ for d in $(SEARCHDIRS); do \ if [ -f $$d/$$p ] ; then \ echo "$(INSTALL) -cs -g wheel -m 755 -o root $$p $$d"; \ $(INSTALL) -cs -g wheel -m 755 -o root $$p $$d; \ - dd=$$d; \ + dd=XXX; \ fi; \ done; \ if [ -z "$$dd" ] ; then \ diff --git a/contrib/ipfilter/BSD/Makefile.ipsend b/contrib/ipfilter/BSD/Makefile.ipsend index 94a3c7a..410ea67 100644 --- a/contrib/ipfilter/BSD/Makefile.ipsend +++ b/contrib/ipfilter/BSD/Makefile.ipsend @@ -1,16 +1,18 @@ # -# $Id: Makefile.ipsend,v 2.2 2000/02/28 08:27:51 darrenr Exp $ +# Id: Makefile.ipsend,v 2.8 2002/05/22 16:15:36 darrenr Exp # BINDEST=/usr/sbin SBINDEST=/sbin MANDIR=/usr/share/man -OBJS=ipsend.o ip.o ipsopt.o y.tab.o lex.yy.o +OBJS=ipsend.o ip.o ipsopt.o iplang_y.o iplang_l.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 +ROBJS=ipresend.o ip.o resend.o TOBJS=iptest.o iptests.o ip.o UNIXOBJS=sbpf.o sock.o 44arp.o +OBJ=. +LIBS=-L$(OBJ) -lipf CC=gcc -Wuninitialized -Wstrict-prototypes -O CFLAGS=-g -I$(TOP) @@ -19,14 +21,14 @@ MFLAGS="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" \ 'CFLAGS=$(CFLAGS) $(SOLARIS2)' "IPFLKM=$(IPFLKM)" \ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \ - "CPUDIR=$(CPUDIR)" + "CPUDIR=$(CPUDIR)" "LOOKUP=$(LOOKUP)" # all build bsd-bpf : ipsend ipresend iptest -y.tab.o: $(TOP)/iplang/iplang_y.y +iplang_y.o: $(TOP)/iplang/iplang_y.y (cd $(TOP)/iplang; $(MAKE) ../BSD/$(CPUDIR)/$@ $(MFLAGS) 'DESTDIR=../BSD/$(CPUDIR)' ) -lex.yy.o: $(TOP)/iplang/iplang_l.l +iplang_l.o: $(TOP)/iplang/iplang_l.l (cd $(TOP)/iplang; $(MAKE) ../BSD/$(CPUDIR)/$@ $(MFLAGS) 'DESTDIR=../BSD/$(CPUDIR)' ) .c.o: @@ -42,7 +44,7 @@ iptest: $(TOBJS) $(UNIXOBJS) $(CC) $(DEBUG) $(TOBJS) $(UNIXOBJS) -o $@ $(LIBS) clean: - rm -rf *.o core a.out ipsend ipresend iptest + rm -rf *.o core a.out ipsend ipresend iptest iplang_y.* iplang_l.* ipsend.o: $(TOP)/ipsend/ipsend.c $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipsend/ipsend.c -o $@ @@ -101,9 +103,6 @@ dlcommon.o: $(TOP)/ipsend/dlcommon.c sdlpi.o: $(TOP)/ipsend/sdlpi.c $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipsend/sdlpi.c -o $@ -arp.o: $(TOP)/ipsend/arp.c - $(CC) $(DEBUG) $(CFLAGS) -c $(TOP)/ipsend/arp.c -o $@ - install: -$(INSTALL) -cs -g wheel -m 755 -o root ipsend ipresend iptest $(BINDEST) diff --git a/contrib/ipfilter/BSD/kupgrade b/contrib/ipfilter/BSD/kupgrade index ae0b71f..91f32da 100644 --- a/contrib/ipfilter/BSD/kupgrade +++ b/contrib/ipfilter/BSD/kupgrade @@ -1,41 +1,89 @@ #!/bin/sh # PATH=/sbin:/usr/sbin:/bin:/usr/bin; export PATH +argv0=`basename $0` +os=`uname -s` +rev=`uname -r` +maj=`expr $rev : '\([0-9]*\)\.'` +min=`expr $rev : '[0-9]*\.\([0-9]*\)'` +sub=`expr $rev : '[0-9]*\.[0-9]*\.\([0-9]*\)'` + # try to bomb out fast if anything fails.... set -e - -argv0=`basename $0` + +fullrev=`printf '%02d%02d%02d' $maj $min $sub` dir=`pwd` karch=`uname -m` -os=`uname -s` -if [ $os = FreeBSD ] ; then - rev=`uname -r` - rev=`expr $rev : '\([0-9]*\)\..*'` - if [ $rev = 2 ] ; then - echo "Copying /usr/include/osreldate.h to /sys/sys" - cp /usr/include/osreldate.h /sys/sys - fi - if [ -f /sys/contrib/ipfilter/netinet/mlfk_ipl.c ] ; then - /bin/cp mlfk_ipl.c /sys/contrib/ipfilter/netinet/ - fi -fi archdir="/sys/arch/$karch" ipfdir=/sys/netinet if [ -d /sys/contrib/ipfilter ] ; then ipfdir=/sys/contrib/ipfilter/netinet fi +if [ -d /sys/dist/ipf ] ; then + ipfdir=/sys/dist/ipf/netinet +fi confdir="$archdir/conf" +if [ -f /dev/ipnat ] ; then + major=`ls -l /dev/ipnat | sed -e 's/.* \([0-9]*\),.*/\1/'` + echo "Major number for IP Filter is $major" +else + major=x +fi echo -n "Installing " -for i in ip_fil.[ch] fil.c ip_nat.[ch] ip_frag.[ch] ip_state.[ch] ip_proxy.[ch] ip_auth.[ch] ip_log.c ip_compat.h ipl.h ip_*_pxy.c ; do - echo -n "$i " +for j in auth frag nat proxy scan state sync pool htable lookup rules; do + for i in ip_$j.[ch]; do + if [ -f "$i" ] ; then + echo -n " $i" + cp $i $ipfdir + chmod 644 $ipfdir/$i + fi + done +done + +case $os in +SunOS) + case `uname -r` in + 5.*) + filc=ip_fil_solaris.c + ;; + 4.*) + filc=ip_fil_sunos.c + ;; + esac + ;; +*BSD) + filc=ip_fil_`echo $os | tr A-Z a-z`.c + case $os in + FreeBSD) + cp mlfk_ipl.c $ipfdir/ + ;; + *) + ;; + esac + ;; +esac + +if [ -f $ipfdir/$filc ] ; then + echo -n "$filc -> $ipfdir/$filc " + cp $filc $ipfdir/$filc + chmod 644 $ipfdir/$filc +fi +if [ -f $ipfdir/ip_fil.c ] ; then + echo -n "$filc -> $ipfdir/ip_fil.c " + cp $filc $ipfdir/ip_fil.c + chmod 644 $ipfdir/ip_fil.c +fi + +for i in ip_fil.h fil.c ip_log.c ip_compat.h ipl.h ip_*_pxy.c; do + echo -n " $i" cp $i $ipfdir chmod 644 $ipfdir/$i done echo "" echo -n "Installing into /usr/include/netinet" -for j in auth compat fil frag nat proxy state ; do +for j in auth compat fil frag nat proxy scan state sync pool htable lookup; do i=ip_$j.h if [ -f "$i" ] ; then echo -n " $i" @@ -57,4 +105,148 @@ if [ -f /sys/netinet/ip_fil_compat.h ] ; then rm /sys/netinet/ip_fil_compat.h ln -s /sys/netinet/ip_compat.h /sys/netinet/ip_fil_compat.h fi + +if [ $major != x ] ; then + if [ ! -e /dev/ipsync ] ; then + echo "Creating /dev/ipsync" + mknod /dev/ipsync c $major 4 + fi + + if [ ! -e /dev/ipsync ] ; then + echo "Creating /dev/ipscan" + mknod /dev/ipsync c $major 5 + fi + + if [ ! -e /dev/iplookup ] ; then + echo "Creating /dev/iplookup" + mknod /dev/iplookup c $major 6 + fi +fi + +set +e +os=`uname -s` +if [ $os = FreeBSD -a -f /sys/conf/files ] ; then + cd /sys/conf + if [ -f options ] ; then + if [ ! -f options.preipf4 ] ; then + mv options options.preipf4 + cp -p options.preipf4 options + fi + for i in SCAN SYNC LOOKUP COMPILED; do + grep IPFILTER_$i options >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo >> options + echo "# extra option for IP Filter" >> options + echo "IPFILTER_$i opt_ipfilter.h" >> options + fi + done + fi + if [ ! -f files.preipf4 ] ; then + mv files files.preipf4 + cp -p files.preipf4 files + fi + for i in htable pool lookup; do + grep ip_$i.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo "contrib/ipfilter/netinet/ip_$i.c optional ipfilter inet ipfilter_lookup" >> files + fi + done + grep ip_sync.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'contrib/ipfilter/netinet/ip_sync.c optional ipfilter inet ipfilter_sync' >> files + fi + grep ip_scan.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'contrib/ipfilter/netinet/ip_scan.c optional ipfilter inet ipfilter_scan' >> files + fi + grep ip_rules.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'contrib/ipfilter/netinet/ip_rules.c optional ipfilter inet ipfilter_compiled' >> files + fi +fi +if [ $os = NetBSD -a -f /sys/conf/files ] ; then + cd /sys/conf + if [ ! -f files.preipf4 ] ; then + mv files files.preipf4 + cp -p files.preipf4 files + fi + if [ $fullrev -ge 010600 -a $fullrev -lt 020000 ] ; then + for i in htable pool lookup; do + grep ip_$i.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo "file netinet/ip_$i.c ipfilter & ipfilter_lookup" >> files + fi + done + grep ip_sync.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'file netinet/ip_sync.c ipfilter & ipfilter_sync' >> files + fi + grep ip_scan.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'file netinet/ip_scan.c ipfilter & ipfilter_scan' >> files + fi + grep ip_rules.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'file netinet/ip_rules.c ipfilter & ipfilter_compiled' >> files + fi + fi +fi +if [ $os = OpenBSD -a -f /sys/conf/files ] ; then + cd /sys/conf + if [ ! -f files.preipf4 ] ; then + mv files files.preipf4 + cp -p files.preipf4 files + fi + if [ $fullrev -ge 030400 ] ; then + for i in htable pool lookup; do + grep ip_$i.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo "file netinet/ip_$i.c ipfilter & ipfilter_lookup" >> files + fi + done + grep ip_sync.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'file netinet/ip_sync.c ipfilter & ipfilter_sync' >> files + fi + grep ip_scan.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'file netinet/ip_scan.c ipfilter & ipfilter_scan' >> files + fi + grep ip_rules.c files >/dev/null 2>&1 + if [ $? -ne 0 ] ; then + echo 'file netinet/ip_rules.c ipfilter & ipfilter_compiled' >> files + fi + fi +fi + +if [ -f /usr/src/sys/modules/ipfilter/Makefile -a \ + ! -f /usr/src/sys/modules/ipfilter/Makefile.orig ] ; then +cat | (cd /usr/src/sys/modules/ipfilter; patch) <<__EOF__ +*** Makefile.orig Mon Mar 28 09:10:11 2005 +--- Makefile Mon Mar 28 09:12:51 2005 +*************** +*** 5,13 **** + KMOD= ipl + SRCS= mlfk_ipl.c ip_nat.c ip_frag.c ip_state.c ip_proxy.c ip_auth.c \\ +! ip_log.c ip_fil.c fil.c + + .if !defined(NOINET6) + CFLAGS+= -DUSE_INET6 + .endif + CFLAGS+= -I$${.CURDIR}/../../contrib/ipfilter +! CFLAGS+= -DIPFILTER=1 -DIPFILTER_LKM -DIPFILTER_LOG -DPFIL_HOOKS +--- 5,15 ---- + KMOD= ipl + SRCS= mlfk_ipl.c ip_nat.c ip_frag.c ip_state.c ip_proxy.c ip_auth.c \\ +! ip_log.c ip_fil.c fil.c ip_lookup.c ip_pool.c ip_htable.c \\ +! ip_sync.c ip_scan.c ip_rules.c + + .if !defined(NOINET6) + CFLAGS+= -DUSE_INET6 + .endif + CFLAGS+= -I$${.CURDIR}/../../contrib/ipfilter +! CFLAGS+= -DIPFILTER=1 -DIPFILTER_LKM -DIPFILTER_LOG -DPFIL_HOOKS \\ +! -DIPFILTER_LOOKUP -DIPFILTER_COMPILED +__EOF__ +fi exit 0 diff --git a/contrib/ipfilter/BSD/make-devices b/contrib/ipfilter/BSD/make-devices index 320bd80..d512e1c 100755 --- a/contrib/ipfilter/BSD/make-devices +++ b/contrib/ipfilter/BSD/make-devices @@ -26,3 +26,5 @@ mknod /dev/ipl c $major 0 mknod /dev/ipnat c $major 1 mknod /dev/ipstate c $major 2 mknod /dev/ipauth c $major 3 +mknod /dev/ipsync c $major 4 +mknod /dev/ipscan c $major 5 diff --git a/contrib/ipfilter/FWTK/fwtk_transparent.diff b/contrib/ipfilter/FWTK/fwtk_transparent.diff index 69962b6..a6c21fa 100644 --- a/contrib/ipfilter/FWTK/fwtk_transparent.diff +++ b/contrib/ipfilter/FWTK/fwtk_transparent.diff @@ -124,7 +124,7 @@ diff -cr ../TIS.orig/fwtk/Makefile.config.solaris fwtk/Makefile.config.solaris *************** *** 11,30 **** # - # RcsId: "$Header: /devel/CVS/IP-Filter/FWTK/fwtk_transparent.diff,v 2.1 1999/08/04 17:40:48 darrenr Exp $" + # RcsId: "$Header: /devel/CVS/IP-Filter/FWTK/fwtk_transparent.diff,v 2.2 2001/02/28 09:36:06 darrenr Exp $" # Your C compiler (eg, "cc" or "gcc") @@ -145,7 +145,7 @@ diff -cr ../TIS.orig/fwtk/Makefile.config.solaris fwtk/Makefile.config.solaris -Dgethostbyaddr=res_gethostbyaddr -Dgetnetbyname=res_getnetbyname \ --- 11,34 ---- # - # RcsId: "$Header: /devel/CVS/IP-Filter/FWTK/fwtk_transparent.diff,v 2.1 1999/08/04 17:40:48 darrenr Exp $" + # RcsId: "$Header: /devel/CVS/IP-Filter/FWTK/fwtk_transparent.diff,v 2.2 2001/02/28 09:36:06 darrenr Exp $" + # + # Path to sources of ip_filter (ip_nat.h required in lib/hnam.c) @@ -649,15 +649,15 @@ diff -cr ../TIS.orig/fwtk/lib/hnam.c fwtk/lib/hnam.c + natlookup.nl_outport=rsin.sin_port; + natlookup.nl_inip=sin.sin_addr; + natlookup.nl_outip=rsin.sin_addr; -+ if((natfd=open("/dev/ipl",O_RDONLY))<0) { ++ if((natfd=open("/dev/ipnat",O_RDONLY))<0) { + return(NULL); + } + if(ioctl(natfd,SIOCGNATL,&natlookup)==(-1)) { + return(NULL); + } + close(natfd); -+ if(ptr) *ptr=ntohs(natlookup.nl_inport); -+ sprintf(buf,"%s",inet_ntoa(natlookup.nl_inip)); ++ if(ptr) *ptr=ntohs(natlookup.nl_realport); ++ sprintf(buf,"%s",inet_ntoa(natlookup.nl_realip)); + #endif + + #if defined(SOLARIS) /* for Solaris */ @@ -679,15 +679,15 @@ diff -cr ../TIS.orig/fwtk/lib/hnam.c fwtk/lib/hnam.c + natlookup.nl_outport=rsin.sin_port; + natlookup.nl_inip=sin.sin_addr; + natlookup.nl_outip=rsin.sin_addr; -+ if( (natfd=open("/dev/ipl",O_RDONLY)) < 0) { ++ if( (natfd=open(IPL_NAT,O_RDONLY)) < 0) { + return(NULL); + } + if(ioctl(natfd, SIOCGNATL, &natlookup) == -1) { + return(NULL); + } + close(natfd); -+ if(ptr) *ptr=ntohs(natlookup.nl_inport); -+ sprintf(buf,"%s",inet_ntoa(natlookup.nl_inip)); ++ if(ptr) *ptr=ntohs(natlookup.nl_realport); ++ sprintf(buf,"%s",inet_ntoa(natlookup.nl_realip)); + #endif + + /* No transparent proxy support */ diff --git a/contrib/ipfilter/FWTK/fwtkp b/contrib/ipfilter/FWTK/fwtkp index 8f4819a..aba869d 100644 --- a/contrib/ipfilter/FWTK/fwtkp +++ b/contrib/ipfilter/FWTK/fwtkp @@ -482,15 +482,15 @@ diff -c -r ./lib/hnam.c ../../NEW/fwtk/lib/hnam.c + natlookup.nl_outport=rsin.sin_port; + natlookup.nl_inip=sin.sin_addr; + natlookup.nl_outip=rsin.sin_addr; -+ if((natfd=open("/dev/ipl",O_RDONLY))<0) { ++ if((natfd=open(IPL_NAT,O_RDONLY))<0) { + return(NULL); + } + if(ioctl(natfd,SIOCGNATL,&natlookup)==(-1)) { + return(NULL); + } + close(natfd); -+ if(ptr) *ptr=ntohs(natlookup.nl_inport); -+ sprintf(buf,"%s",inet_ntoa(natlookup.nl_inip)); ++ if(ptr) *ptr=ntohs(natlookup.nl_realport); ++ sprintf(buf,"%s",inet_ntoa(natlookup.nl_realip)); + #endif + + /* No transparent proxy support */ diff --git a/contrib/ipfilter/FreeBSD-2.2/files.diffs b/contrib/ipfilter/FreeBSD-2.2/files.diffs index 10bce4b..2ada3fa 100644 --- a/contrib/ipfilter/FreeBSD-2.2/files.diffs +++ b/contrib/ipfilter/FreeBSD-2.2/files.diffs @@ -2,7 +2,7 @@ --- files Sat Apr 4 10:52:58 1998 *************** *** 222,227 **** ---- 222,236 ---- +--- 222,240 ---- netinet/tcp_timer.c optional inet netinet/tcp_usrreq.c optional inet netinet/udp_usrreq.c optional inet @@ -15,6 +15,10 @@ + netinet/mlf_ipl.c optional ipfilter inet + netinet/ip_auth.c optional ipfilter inet + netinet/ip_log.c optional ipfilter inet ++ netinet/ip_scan.c optional ipfilter inet ++ netinet/ip_sync.c optional ipfilter inet ++ netinet/ip_pool.c optional ipfilter_pool inet ++ netinet/ip_rules.c optional ipfilter_compiled ipfilter inet netipx/ipx.c optional ipx netipx/ipx_cksum.c optional ipx netipx/ipx_input.c optional ipx diff --git a/contrib/ipfilter/FreeBSD-2.2/files.newconf.diffs b/contrib/ipfilter/FreeBSD-2.2/files.newconf.diffs index 67894d0..82599f1 100644 --- a/contrib/ipfilter/FreeBSD-2.2/files.newconf.diffs +++ b/contrib/ipfilter/FreeBSD-2.2/files.newconf.diffs @@ -2,7 +2,7 @@ --- files.newconf Sun Jun 25 02:19:10 1995 *************** *** 161,166 **** ---- 161,175 ---- +--- 161,179 ---- file netinet/ip_input.c inet file netinet/ip_mroute.c inet file netinet/ip_output.c inet @@ -15,6 +15,10 @@ + file netinet/ip_auth.c ipfilter + file netinet/ip_log.c ipfilter + file netinet/mlf_ipl.c ipfilter ++ file netinet/ip_scan.c ipfilter ++ file netinet/ip_sync.c ipfilter ++ file netinet/ip_pool.c ipfilter_pool ++ file netinet/ip_rules.c ipfilter_compiled file netinet/raw_ip.c inet file netinet/tcp_debug.c inet file netinet/tcp_input.c inet diff --git a/contrib/ipfilter/FreeBSD-2.2/kinstall b/contrib/ipfilter/FreeBSD-2.2/kinstall index 9ecadc4..5a4368e 100755 --- a/contrib/ipfilter/FreeBSD-2.2/kinstall +++ b/contrib/ipfilter/FreeBSD-2.2/kinstall @@ -8,18 +8,17 @@ 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_*_pxy.c mlf_ipl.c ipl.h ip_compat.h \ - ip_auth.[ch] ip_log.c) +foreach i (ip_{auth,fil,frag,nat,pool,proxy,scan,state,sync}.[ch] fil.c \ + ip_*_pxy.c mlf_ipl.c ipl.h ip_compat.h ip_log.c) echo -n "$i "; cp $i /sys/netinet chmod 644 /sys/netinet/$i - switch ( $i ) + switch ($i) case *.h: /bin/cp $i /usr/include/netinet/$i chmod 644 /usr/include/netinet/$i - breaksw - endsw + breaksw + endsw end echo "" echo "Copying /usr/include/osreldate.h to /sys/sys" diff --git a/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 b/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 index 6c68dbb..5c30b57 100644 --- a/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 +++ b/contrib/ipfilter/FreeBSD-3/INST.FreeBSD-3 @@ -16,6 +16,8 @@ To build a kernel with the IP filter, follow these seven steps: mknod /dev/ipnat c 79 1 mknod /dev/ipstate c 79 2 mknod /dev/ipauth c 79 3 + mknod /dev/ipsync c 79 4 + mknod /dev/ipscan c 79 5 7. reboot diff --git a/contrib/ipfilter/FreeBSD-3/kinstall b/contrib/ipfilter/FreeBSD-3/kinstall index 8282de7..20f0369 100755 --- a/contrib/ipfilter/FreeBSD-3/kinstall +++ b/contrib/ipfilter/FreeBSD-3/kinstall @@ -9,17 +9,17 @@ 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_*_pxy.c mlf_ipl.c ipl.h \ + 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 - switch ( $i ) + switch ($i) case *.h: /bin/cp $i /usr/include/netinet/$i chmod 644 /usr/include/netinet/$i - breaksw - endsw + breaksw + endsw end echo "" echo "Linking /usr/include/osreldate.h to /sys/sys/osreldate.h" diff --git a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 index c232b2c..8a827cf 100755 --- a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 +++ b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.0 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" *** ip6_input.c.orig Sun Feb 13 14:32:01 2000 --- ip6_input.c Wed Apr 26 22:31:34 2000 *************** diff --git a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 index 90dac19..a6a4612 100644 --- a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 +++ b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.1 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" *** ip6_input.c.orig Sat Jul 15 07:14:34 2000 --- ip6_input.c Thu Oct 19 17:14:37 2000 *************** diff --git a/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.2 b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.2 new file mode 100644 index 0000000..a6a4612 --- /dev/null +++ b/contrib/ipfilter/FreeBSD-4.0/ipv6-patch-4.2 @@ -0,0 +1,65 @@ +.\" $NetBSD$ +.\" +*** ip6_input.c.orig Sat Jul 15 07:14:34 2000 +--- ip6_input.c Thu Oct 19 17:14:37 2000 +*************** +*** 120,125 **** +--- 120,127 ---- + + extern struct domain inet6domain; + extern struct ip6protosw inet6sw[]; ++ extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, ++ struct mbuf **)); + + u_char ip6_protox[IPPROTO_MAX]; + static int ip6qmaxlen = IFQ_MAXLEN; +*************** +*** 289,294 **** +--- 291,305 ---- + ip6stat.ip6s_badvers++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); + goto bad; ++ } ++ ++ if (fr_checkp) { ++ struct mbuf *m1 = m; ++ ++ if ((*fr_checkp)(ip6, sizeof(*ip6), m->m_pkthdr.rcvif, ++ 0, &m1) || !m1) ++ return; ++ ip6 = mtod(m = m1, struct ip6_hdr *); + } + + ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; + +*** ip6_output.c.orig Sat Jul 15 07:14:35 2000 +--- ip6_output.c Thu Oct 19 17:13:53 2000 +*************** +*** 106,111 **** +--- 106,113 ---- + #include <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 { +*************** +*** 787,792 **** +--- 789,803 ---- + ip6->ip6_src.s6_addr16[1] = 0; + if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) + ip6->ip6_dst.s6_addr16[1] = 0; ++ } ++ ++ if (fr_checkp) { ++ struct mbuf *m1 = m; ++ ++ if ((error = (*fr_checkp)(ip6, sizeof(*ip6), ifp, 1, &m1)) || ++ !m1) ++ goto done; ++ ip6 = mtod(m = m1, struct ip6_hdr *); + } + + #ifdef IPV6FIREWALL diff --git a/contrib/ipfilter/FreeBSD-4.0/kinstall b/contrib/ipfilter/FreeBSD-4.0/kinstall index 99ec679..ebd6e2e 100755 --- a/contrib/ipfilter/FreeBSD-4.0/kinstall +++ b/contrib/ipfilter/FreeBSD-4.0/kinstall @@ -11,31 +11,25 @@ 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_*_pxy.c mlf_ipl.c mlfk_ipl.c \ - ipl.h ip_compat.h ip_auth.[ch] ip_log.c) +foreach i (ip_{auth,fil,nat,pool,proxy,scan,state,sync}.[ch] fil.c \ + ip_*_pxy.c mlfk_ipl.c ipl.h ip_compat.h ip_log.c ) echo -n "$i "; - cp $i $ipfdir - chmod 644 $ipfdir/$i - switch ( $i ) + cp $i /sys/netinet + chmod 644 /sys/netinet/$i + switch ($i) case *.h: /bin/cp $i /usr/include/netinet/$i chmod 644 /usr/include/netinet/$i - breaksw - endsw + breaksw + endsw end echo "" echo "Linking /usr/include/osreldate.h to /sys/sys/osreldate.h" ln -s /usr/include/osreldate.h /sys/sys/osreldate.h -set patchfile=FreeBSD-4.0/ipv6-patch-$krev -if ( -f $patchfile ) then - echo "" - echo "Patching ip6_input.c and ip6_output.c" - cat $patchfile | (cd /sys/netinet6; patch) -else - echo "IPv6 patching not required for your OS version" -endif +echo "" +echo "Patching ip6_input.c and ip6_output.c" +cat FreeBSD-4.0/ipv6-patch-$krev | (cd /sys/netinet6; patch -N) set config=`(cd $confdir; /bin/ls -1t [0-9A-Z_]*) | head -1` echo -n "Kernel configuration to update [$config] " diff --git a/contrib/ipfilter/FreeBSD-4.0/unkinstall b/contrib/ipfilter/FreeBSD-4.0/unkinstall index b9c5f029..4e9caaa 100755 --- a/contrib/ipfilter/FreeBSD-4.0/unkinstall +++ b/contrib/ipfilter/FreeBSD-4.0/unkinstall @@ -12,7 +12,7 @@ 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 mlfk_ipl.c ipl.h) + ip_log.c mlf_ipl.c ipl.h) echo -n "$i "; /bin/rm -f /sys/netinet/$i end diff --git a/contrib/ipfilter/FreeBSD/files.diffs b/contrib/ipfilter/FreeBSD/files.diffs index 84893d4..2f028e3 100644 --- a/contrib/ipfilter/FreeBSD/files.diffs +++ b/contrib/ipfilter/FreeBSD/files.diffs @@ -2,7 +2,7 @@ --- files Sun Jan 14 14:32:25 1996 *************** *** 208,213 **** ---- 208,221 ---- +--- 208,225 ---- netinet/tcp_timer.c optional inet netinet/tcp_usrreq.c optional inet netinet/udp_usrreq.c optional inet @@ -14,6 +14,10 @@ + netinet/ip_auth.c optional ipfilter inet + netinet/ip_proxy.c optional ipfilter inet + netinet/ip_log.c optional ipfilter inet ++ netinet/ip_scan.c optional ipfilter inet ++ netinet/ip_sync.c optional ipfilter inet ++ netinet/ip_pool.c optional ipfilter_pool ipfilter inet ++ netinet/ip_rules.c optional ipfilter_compiled ipfilter inet netiso/clnp_debug.c optional iso netiso/clnp_er.c optional iso netiso/clnp_frag.c optional iso diff --git a/contrib/ipfilter/FreeBSD/files.newconf.diffs b/contrib/ipfilter/FreeBSD/files.newconf.diffs index cc7cf41..29aea54 100644 --- a/contrib/ipfilter/FreeBSD/files.newconf.diffs +++ b/contrib/ipfilter/FreeBSD/files.newconf.diffs @@ -2,7 +2,7 @@ --- files.newconf Sun Jun 25 02:19:10 1995 *************** *** 161,166 **** ---- 161,174 ---- +--- 161,178 ---- file netinet/ip_input.c inet file netinet/ip_mroute.c inet file netinet/ip_output.c inet @@ -14,6 +14,10 @@ + file netinet/ip_proxy.c ipfilter + file netinet/ip_auth.c ipfilter + file netinet/ip_log.c ipfilter ++ file netinet/ip_scan.c ipfilter ++ file netinet/ip_sync.c ipfilter ++ file netinet/ip_pool.c ipfilter_pool ++ file netinet/ip_rules.c ipfilter_compiled file netinet/raw_ip.c inet file netinet/tcp_debug.c inet file netinet/tcp_input.c inet diff --git a/contrib/ipfilter/FreeBSD/files.oldconf.diffs b/contrib/ipfilter/FreeBSD/files.oldconf.diffs index 55b526f..ed8aff9 100644 --- a/contrib/ipfilter/FreeBSD/files.oldconf.diffs +++ b/contrib/ipfilter/FreeBSD/files.oldconf.diffs @@ -2,7 +2,7 @@ --- files.oldconf Sun Apr 23 17:54:18 1995 *************** *** 180,185 **** ---- 180,193 ---- +--- 180,197 ---- netinet/tcp_timer.c optional inet netinet/tcp_usrreq.c optional inet netinet/udp_usrreq.c optional inet @@ -14,6 +14,10 @@ + netinet/ip_proxy.c optional ipfilter requires inet + netinet/ip_auth.c optional ipfilter requires inet + netinet/ip_log.c optional ipfilter requires inet ++ netinet/ip_scan.c optional ipfilter requires inet ++ netinet/ip_sync.c optional ipfilter requires inet ++ netinet/ip_pool.c optional ipfilter_pool requires ipfilter ++ netinet/ip_rules.c optional ipfilter_compiled requires ipfilter netiso/clnp_debug.c optional iso netiso/clnp_er.c optional iso netiso/clnp_frag.c optional iso diff --git a/contrib/ipfilter/FreeBSD/filez.diffs b/contrib/ipfilter/FreeBSD/filez.diffs index 52492e8..9656006 100644 --- a/contrib/ipfilter/FreeBSD/filez.diffs +++ b/contrib/ipfilter/FreeBSD/filez.diffs @@ -9,11 +9,15 @@ + file netinet/ip_fil.c ipfilter + file netinet/fil.c ipfilter + file netinet/ip_nat.c ipfilter -+ file netinet/ip_frag.c ipfilter -+ file netinet/ip_state.c ipfilter -+ file netinet/ip_proxy.c ipfilter -+ file netinet/ip_auth.c ipfilter ++ file netinet/ip_frag.c ipfilter ++ file netinet/ip_state.c ipfilter ++ file netinet/ip_proxy.c ipfilter ++ file netinet/ip_auth.c ipfilter + file netinet/ip_log.c ipfilter ++ file netinet/ip_scan.c ipfilter ++ file netinet/ip_sync.c ipfilter ++ file netinet/ip_pool.c ipfilter_pool ++ file netinet/ip_rules.c ipfilter_compiled file netiso/clnp_debug.c iso file netiso/clnp_er.c iso file netiso/clnp_frag.c iso diff --git a/contrib/ipfilter/FreeBSD/kinstall b/contrib/ipfilter/FreeBSD/kinstall index ef2db54..2b67b9a 100755 --- a/contrib/ipfilter/FreeBSD/kinstall +++ b/contrib/ipfilter/FreeBSD/kinstall @@ -8,17 +8,17 @@ 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_auth.[ch] ip_*_pxy.c ip_compat.h ip_log.c) +foreach i (ip_{auth,fil,frag,nat,pool,proxy,scan,state,sync}.[ch] fil.c \ + ip_*_pxy.c ip_compat.h ip_log.c ) echo -n "$i "; cp $i /sys/netinet chmod 644 /sys/netinet/$i - switch ( $i ) + switch ($i) case *.h: /bin/cp $i /usr/include/netinet/$i chmod 644 /usr/include/netinet/$i - breaksw - endsw + breaksw + endsw end echo "" grep iplopen $archdir/$karch/conf.c >& /dev/null diff --git a/contrib/ipfilter/HISTORY b/contrib/ipfilter/HISTORY index 85a8b5f..9b93e83 100644 --- a/contrib/ipfilter/HISTORY +++ b/contrib/ipfilter/HISTORY @@ -6,757 +6,394 @@ # in providing a very available location for the IP Filter home page and # distribution center. # -# Thanks to Hewlett Packard for making it possible to port IP Filter to -# HP-UX 11.00. -# -# Thanks to Tel.Net Media for supplying me with equipment to ensure that -# IP Filter continues to work on Solaris/sparc64. -# -# Thanks to BSDI for providing object files for BSD/OS 3.1 and the means -# to further support development of IP Filter under BSDI. -# -# Thanks to Craig Bishop of connect.com.au and Sun Microsystems for the -# loan of a machine to work on a Solaris 2.x port of this software. -# # Thanks also to all those who have contributed patches and other code, # and especially those who have found the time to port IP Filter to new # platforms. # -3.4.35 21/6/2004 - Released - -some cases of ICMP checksum alteration were wrong - -block packets that fail to create state table entries - -correctly handle all return values from ip_natout() when fastrouting - -ipmon was not correctly calculating the length of the IPv6 packet (excluded -ipv6 header length) - -3.4.34 20/4/2004 - Released - -correct the ICMP packet checksum fixing up when processing ICMP errors for NAT - -various changes to ipsend for sending packets with ipv4 options - -look for ipmon's pidfile in /var/run and /etc/opt/ipf in Solaris' init script - -only allow non-fragmented packets to influence whether or not a logged -packet is the same as the one logged before. - -make "ipfstat -f" output more informative - -compatibility for openbsd byte order changes to ip_off/ip_len - -disallow "freebsd" as a make target (encourages people to do the wrong thing) - -3.4.33 15/12/2003 - Released - -pass on messages moving through ipfilter when it is unloading itself on Solaris - -add disabling of auto-detach when the module attaches on Solaris - -compatibility patches for 'struct ifnet' changes on FreeBSD - -implement a maximum for the number of entries in the NAT table (NAT_TABLE_MAX -and ipf_nattable_max) - -fix ipfstat -A - -frsynclist() wasn't paying attention to all the places where interface -names are, like it should. - -fix where packet header pointers are pointing to after doing an ipf_pullup - -fix comparing ICMP packets with established TCP state where only 8 bytes -of header are returned in the ICMP error. - -3.4.32 18/6/2003 - Released - -fix up the behaviour of ipfs - -make parsing errors in ipf/ipnat return an error rather than return -indicating success. - -window scaling patch - -make ipfstat work as a set{g,u}id thing - gave up privs before opening -/dev/ipl - -checksum adjustment corrections for ICMP & NAT - -attempt to always get an mbuf full of data through pullup if possible - -Fix bug with NAT and fragments causing system to crash - -Add patches for OpenBSD 3.3 - -stop LKM locking up the machine on modern NetBSD(?) - -allow timeouts in NAT rules to over-ride fr_defnatage if LARGE_NAT is defined - -Locking patches for IRIX 6.5 from SGI. - -fix bug in synchronising state sessions where all interfaces were invalidated - -fix bug in openbsd 3.2 bridge diffs - -fix bug parsing port comparisons in proxy rules - -3.4.31 7/12/2002 - Released - -Solaris 10 compatibility - -fix linking into pfil in NetBSD - -fix IRIX 6.2 compatibility - -add code to check consistency of fr_checkp/fr_check on non-Solaris - -OpenBSD: missing patches for ip6_output.c on OpenBSD 3.2, - make LKM work for 3.2 (OpenBSD LKMs now match NetBSD) - -3.4.30 26/11/2002 - Released - -attempt to detect using GNU make and abort if so - -OpenBSD 3.2 patches from Stefan Hermes von GMX - -add MSS clamping code from NetBSD - -correctly display ipv6 output with ipfstat for (accounting) rules - -fix problems with ioctl handling for /dev/ipauth - -set SYN bit in rcmd fake packet to create back channel - -make libpcap reader capable of determining in/out (not in libpcap file) -and add more DLT types - -do not allow redirects to localhost for Solaris in NAT parser - -allow return-rst with auth rules - -man page corrections - -fix for handling ipv6 icmp errors - -fix up ipfs command line option processing - -only allow processing a ftp 227 response following a PASV command - -NetBSD: use poll() and adapt to new cdevsw mechanism - -make flushing for just ipv6 things work - -3.4.29 28/8/2002 - Released - -Make substantial changes to the FTP proxy to improve reliability, security -and functionality. - -don't send ICMP errors/TCP RST's in response to blocked proxy packets - -fix potential memory leaks when unloading ipfilter from kernel - -fix bug in SIOCGNATL handler that did not preserve the expected -byte order from earlier versions in the port number - -set do not fragment flag in generated packets according to system flags, -where available. - -preserve filter rule number and group number in state structure - -fix bug in ipmon printing of p/P/b/B - -make some changes to the kmem.c code for IRIX compatibility - -add code to specifically handle ip.tun* interfaces on Solaris - -3.4.28 6/6/2002 - Released - -Fix for H.323 proxy to work on little endian boxes - -IRIX: Update installation documentation - add route lock patch - -allow use of groups > 65535 - -create a new packet info summary for packets going through ipfr_fastroute() -so that where details are different (RST/ICMP errors), the packet now gets -correctly NAT'd, etc. - -fix the FTP proxy so that checks for TCP sequence numbers outside the -normal offset due to data changes use absolute numbers - -make it possible to remove rules in ipftest - -Update installing onto OpenBSD and split into two directories: -OpenBSD-2 and OpenBSD-3 - -fix error in printout out the protocol in NAT rules - -always unlock ipfilter if locking fails half way through in ipfs - -fix problems with TCP window scaling - -update of man pages for ipnat(4) and ipftest(1) - -3.4.27 28/04/2002 - Released - -fix calculation of 2's complmenent 16 bit checksum for user space - -add mbuflen() to usespace compiles. - -add more #ifdef complexity for platform portability - -add OpenBSD 3.1 diffs - -3.4.26 25/04/2002 - Released - -fix parsing and printing of NAT rules with regression tests. - -add code to adjust TCP checksums inside ICMP errors where present and as -required for NAT. - -fix documentation problems in instal documents - -fix locking problem with auth code on Solaris - -fix use of version macros for FreeBSD and make the use of __FreeBSD_version -override previous hacks except when not present - -fix the macros defined for SIOCAUTHR and SIOCAUTHW - -fix the H.323 proxy so it no longer panics (multiple issues: re-entry into -nat_ioctl with lock held on Solaris, trying to copy data from kernel space -with copyin, unaligned access to get 32bit & 16bit numbers) - -use the ip_ttl ndd parameter on Solaris to fill in ip_ttl for packets -generated by IPFilter - -fix comparing state information to delete state table entries - -flag packets as being "bad state" if they're outside the window and prevent -them from being able to cause new state to be created - except for SYN packets - -be stricter about what packets match a TCP state table entry if its creation -was triggered by a SYN packet. - -add patches to handle TCP window scaling - -don't update TCP state table entries if the packet is not considered to be -part of the connection - -ipfs wasn't allowing -i command line option in getopt - -IRIX: fix kvm interface, fix compile warnings, compile the kernel with -O2 - regardless of user compile, fix the getkflags script to prune down the - output more so it is acceptable - -change building in Makefiles to create links to the application in $(TOP) -at the end of "build" rather than when each is created. - -update BSD/kupgrade for FreeBSD - -l4check wasn't properly closing things when a connection fails - -man page updates for ipmon(8) and ipnat(5) - -more regression tests added. - -3.4.25 13/03/2002 - Released - -retain rule # in state information - -log the direction of a packet so ipmon gets it right rather than incorrectly -deriving it from the rule flags - -add #ifdef for IPFILTER_LOGSIZE (put options IPFILTER_LOGSIZE=16384 in BSD -kernel config files to increase that buffer size) - -recognise return-* rules differently to block in ipftest - -fix bug in ipmon output for solaris - -add regression testing for skip rules, logging and using head/group - -fix output of ipmon: was displaying large unsigned ints rather than -1 -when no rules matched. - -make logging code compile into ipftest and add -l command line option to -dump binary log file (read with ipmon -f) when it finishes. - -protect rule # and group # from interference when checking accounting rules - -add regression testing for log output (text) from ipmon. - -document -b command line option for ipmon - -fix double-quick in Solaris startup script - -3.4.24 01/03/2002 - Released - -fix how files are installed on SunOS5 - -fix some minor problems in SunOS5 ipfboot script - -by default, compile all OpenBSD tools in 3.0 for IPv6 - -fix NULL-pointer dereference in NAT code - -make a better attempt at replacing the appropriate binaries on BSD systems - -always print IPv6 icmp-types as a number - -impose some rules about what "skip" can be used with - -fix parsing problems with "keep state" and "keep state-age" - -Try to read as much data as is in the log device in ipmon - -remove some redundant checks when searching for rdr/nat rules - -fix bug in handling of ACCT with FTP proxy - -increase array size for interface names, using LIFNAMSIZ - -include H.323 proxy from QNX - -3.4.23 16/01/2002 - Released - -Include patches to install IPFilter into OpenBSD 3.0, both for just kernel -compiles and complete system builds. - -Fix bug in automatic flushing of state table which would cause it to hang -in an infinite loop bug introduced in 3.4.20. - -Modify the sample proxy (samples/proxy.c) so that it ads a NAT mapping for -the outgoing connection to make it look like it comes from the real source. - -Only support ICMPv6 with IPv6. - -Move ipnat.1 to ipnat.8 - -Enhance ipmon to print textual ICMP[v6] types and subtypes where possible. - -Make it possible to do IPv6 regression testing with ipftest. - -Use kvm library for kmem access, rather than trying to do it manually with -open/lseek/read. - -Fix diffs for ip_input.c on BSDOS so it doesn't crash with fastroute. - -Remove Berkeley advertising licence clause. Reference: -ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change - -Add more regression tests: ICMPv6 neighbour discovery, ICMP time exceeded -and fragmentation required. - -Fix ipfboot script on Solaris to deal with no nameservers or no route to -them in a clean manner. - -Support per-rule set timeouts for non-TCP NAT and state - -Add netbios proxy - -Add ICMPv6 stateful checking, including handling multicast destination -addresses for neighbour discovery. - -Fix problems with internals of ICMP messages for MTU discovery and -unreachables not being correctly adjust on little endian boxes. - -Add "in-via" and "out-via" to filtering rules grammar. It is now possible -to bind a rule to both incoming and outgoing interfaces, in both forward -and reverse directions (4 directions in total). allows for asymetric flows -through a firewall. - -Fix ipfstat and ipnat for working on crash dumps. - -Don't let USE_INET6 stay defined for SunOS4 - -Count things we see for each interface on solaris. - -Include <netinet/icmp6.h> when compiling with USE_INET6 defined and -also include a whole bunch of #define's to make sure the symbols expected -can be used. - -Fix up fastroute on BSD systems. - -Make fastrouting work for IPv6 just a bit better. doesn't split up big -packets into fragments like the IPv4 one does. You can now do a -"to <if>:<ipv6_addr>" - -Remove some of the differences between user-space and kernel-space code -that is internal to ipfilter. - -Call ipfr_slowtimer() after each packet is processed in ipftest to artificially -create the illusion of passing time and include the expire functions in the -code compiled for user-space. - -Fix issues with the IPSec proxy not working or leading to a system crash. - -Junk all processing of SPIs and special handling for ESP. - -Add "no-match" as a filter rule action (resets _LAST_ match) - -Add hack to workaround problems with Cassini interface cards on -Solaris and VLANs - -Add some protocols to etc/protocols - -3.4.22 03/12/2001 - Released - -various openbsd changes - -sorting based on IP numbers for ipfstat top output - -fix various IPv6 code & compile problems - -modify ip_fil.c to be more netbsd friendly - -fix fastroute bug where it modified a packet post-sending - -fix get_unit() - don't understand why it was broken. +4.1.8 - Released 29 March 2005 -add FI_IGNOREPKT and don't count so marked packets when doing stats or -state/nat. +include path from Phil Dibowitz for sorting ipfstat -t output by source or +destination port. -extend the interface name saved to log output +fix a bug in printing rules where interface names could not be printed, +even if they're in the rule structure. -make proxies capable of extending the matching done on a packet with a -particular nat session +fix BSD/kupgrade to correctly change ipfilter lkm Makefile for FreeBSD -change interfaces inside NAT & state code to accomodate redesign to allow -IPsec proxy to work. +add 2 new features to SIOCGNATL: +- if IPN_FINDFORWARD is set, check if the respective MAP is already + present in the outbound table +- if IPN_IN is set, search for a matching MAP entry instead of RDR + (Peter Potsma) -fix bug when free'ing loaded rules that results in a memory leak -(only an issue with "ipf -rf -", not flush) +turn off function inlining for freebsd 5.3+ -make ipftest capable of loading > 1 file or rules, making it now possible -to load both NAT & filter rules +UDP doesn't pullup enough data which can sometimes cause a panic. +Fix other protocols, as required, where a similar problem may exist. -fix hex input for ipftest to allow interface name & direction to work +overhaul the timeout queue management, especially that for user defined queues +which are now only freed in an orderly manner. -show ipsec proxy details in ipnat output +4.1.7 - Released 13 March 2005 -if OPT_HEX is set in opts, print a packet out as hex +Using the GRE call field is almost impossible because it is unbalanced and +both call fields are not present in each v1 header. -don't modify b_next or preseve it or preserve b_prev for solaris +Fix a problem where it was possible to load duplicate rules into ipf -fix up kinstall scripts to install all the files everywhere they need to +patch from John Wehle to address problems with fastroute on solaris -fix overflowing of bits in ip_off inside iptest +Copying data out for ipf -z failed because it tried to copy out to an address +that is a kernel pointer in user space. -make userauth and proxy in samples directory compile +add "ip" timeout for both NAT & state that's for non-TCP/UDP/ICMP -fix minimum size when doing a pullup for ESP & ICMPv6 +synch up with NetBSD's changes -3.4.21 24/10/2001 - Released +fix problems parsing long lines of text in the ftp proxy where they would not +be parsed properly and stop the session from working -include ipsec proxy +enhance the PPTP proxy so that it tries to decode messages in the TCP stream +so it knows when to create and destroy the state/nat sessions for GRE. There +are also 4 new regression tests for it, testing map/rdr rules. -make state work for non-tcp/udp/icmp in a very simple way +impose some limits on the size of data that can be moved with SIOCSTPUT in +the NAT code and also prevent a duplicate session entry from being created +using this method. -include diffs for ipv6 firewall on openbsd-2.9 +add a new flag (IPN_FINDFORWARD) to NAT code that can be used with SIOCGNATL +to check if it is possible to create an outgoing transparent NAT mapping to +compliment the redirect being investigated. -add compatibility filter wrapper for NetBSD-current +Linux requires that the checksums in the IP header get adjusted -fix command line option problems with ipfs +only resolve unknown interfaces in fr_stinsert, and nuke all interface pointers +in SIOCSTPUT to prevent bad data being loaded from userspace. -if we fill the state table and a automated flush doesn't purge any -expiring entries, remove all entries idle for more than half a day +make the byte counting for state correct (was counting data from ICMP packet +twice) -fix bug with sending resets/icmp errors where the pointer to the data -section of the packet was not being set (BSD only) +print out the keyword "frag-body" if the flag is set. -split out validating ftp commands and responses into different halves, -one for each of server & client. +fix ipfs loading/restoring NAT sessions -do not compile in STATETOP support for specific architectures +patch from Frank to correctly format IP addresses in ipfstat -t output -fix INSTALL.FreeBSD to no longer provide directions and properly direct -people to the right file for the right version of FreeBSD. +parsing port numbers in ipf/ipnat was confusing as the port number was returned +in an int that was also overloaded to be the suceess/failure. instead, change +the port using pass by reference and only use the return value for indicating +success or failure. -3.4.20 24/07/2001 - Released +4.1.6 - Released 19 February 2005 -adjust NAT hashing to give a better spread across the table +add a new timeout number to NAT (fr_defnatipage) that is used for all +non-TCP/UDP/ICMP protocols - default 60 seconds. -show icmp code/type names in output, where known +buffer leak with bad nat - David Gueluy -fix bug in altering cached interface names in state when resync'ing +fix memory leak with state entries created by proxies -fix bug in real audio proxy that caused crashs - -fix compiling using sunos4 cc +eliminate copying too much data into a scan buffer -patch from casper to address weird exit problem for ipstat in top mode +allow a trailing protocol name for map rules as well as rdr ones -patch from Greg Woods to produce names for icmp types/unreach codes, -where they are known +fix bug in parsing of <= and > for NAT rules (two were crossed over) -fix bug where ipfr_fastroute() would use a mblk and it would also get -freed later. +FreeBSD's iplwrite hasn't kept pace with iplread's prototype -don't match fragments which would cause 64k length to be exceeded +expand documention on the karma of using "auto" in ipnat map rules -ftp proxy fix for port numbers being setup for pasv ftp with state/nat +add matching on IP protocol to ipnat map rules -change hashing for NAT to include both IP#'s and ports. +allow ippool definitions to contain no addresses to start with -Solaris fixes for IPv6 +Linux NAT needs to modify the IP header checksum as it gets called after it +has been computed by IP. -fix compiling iplang bits, under Solaris, for ipsend +UDP was missing a pullup for packet header information before examining +the header -3.4.19 29/06/2001 - Released +4.1.5 - Released 9 January 2005 -fix to support suspend/resume on solaris8 as well as ipv6 +all rules were being converted into "dup-to" rules in the kernel -include group/group-head in match of filter rules +fix two ftp proxy problems: 1st, buffer needs to be bigger for fitting in +complete RETR/CWD commands, 2nd is () use in 227 messages isn't copied +over correctly. -fix endian problem reading snoop files +response to CWDs +revert ip_off back to network byte order in the ICMP error packet that +gets generated. -make all licence comments point to the one place +4.1.4 - Released 9 January 2005 -fix ftp proxy to only advance state if a reply is received in response to -a recognised command +force NAT rules to only match ipv4 NAT rules (which all are, currently, +by default) -3.4.18 05/06/2001 - Released +include state synchronisation fixes from Frank Volf -fix up parsing of "from ! host" where '!' is separate +make the maximum log size for internally buffered log entries accessible +via "ipf -T" -disable hardware checksums for NetBSD +redesign start of fr_check() to avoid putting duplicate information in +ipfilter about how much data needs to be pulled up for a protocol to be +properly filtered. -put ipftest temporary files in . rather than /tmp +tidy up sending ICMP error messages - some bad inputs could result in +data not being freed and/or no error returned. -modify ftp proxy to be more intelligent about moving between states -and recognise new authentication commands +make the maximum size of the log buffer run-time tunable -allow state/nat table sizes to be externally influenced +fix bug in parsing TCP header when looking for MSS option that could make +the system hang -print out host mapping table for NAT with ipnat -l +change pool lookups that fail to find a match to return "no match" +rather than fail. -fix handling of hardware checksum'ing on Solaris +add run-time tunable debugging for proxy support code and FTP proxy. -fixup makefiles for Solaris +fix state table updates for entries where the first packet as an ICMPv6 +multicast message -update regression tests +fix hang when flushing state for v4/v6 and other (v6/v4) entries are present +too -fix surrender of SPL's for failure cases +attaching filtering to ipv6 pfil hook wasn't present for solaris -include patches for OpenBSD's new timeout mechanism +don't allow rules with "keep state" and "with oow" -default ipl_unreach to ICMP_UNREACH_FILTER_PROHIB if defined, else make it -ICMP_UNREACH_FILTER +move a bunch of userland only code from fil.c to ip_fil.c -fix up handling of packets matching auth rules and interaction with state +make fr_coalesce() more resiliant to bad input, just returning an error +instead of crashing, making calling it easier in many places -add -q command line option to ipfstat on Solaris to list bound interfaces +When m_pulldown doesn't return NULL, it doesn't necessarily return a pointer +to the same mbuf passed in as the first arg. -add command line option to ipfstat/ipnat to select different core image +remove fr_unreach and use ENETUNREACH by default. -don't use ncurses on Solaris for STATETOP +printing out of tag data in ipf rules doesn't match input syntax -fix includes to get FreeBSD version +ipftest(1) man page update -do not byte swap ip_id +ipfs command line option parsing still rejects some valid syntaxes -fix handling success for packets matching the auth rule +SIGHUP handling by ipmon was not as safe as it could be -don't double-count short packets +fix various parsing regressions, including "<thishost>", "tcpudp", ordering +of "keep" options -add ICMP router discovery message size recognition +patches from Frank Volk: add udp_acktimeout to sysctl list for FreeBSD, +ICMP packet length not calculated correctly in send_icmp_err, reply-to +not printed by ipfstat, keep state with icmp passing (mtrr) -fix packet length calculation for IPv6 +patches for return-rst and return-icmp from Attila Fueloep +(lichtscheu@gesindel.org) -set CPUDIR when for install-sunos5 make target +4.1.3 - Released 18 July 2004 -SUNWspro -xF causes Solaris 2.5.1 kernel to crash +do some more fine tuning on NAT checksum adjustments -3.4.17 06/04/2001 - Released +correct IP address byte order in proxy setup for ipsec/pptp -fix fragment#0 handling bug where they could get in via cache information -created by state table entries +man page updates -use ire_walk to look for ire cache entries with link layer headers cached +fix numerous problems with ipfs operation -deal with bad SPL assumptions for log reading on BSD +complete new syntax for ipmon.conf in its parser and update the sample file -fix ftp proxy to allow logins with passwords +assign error value consistantly in fastroute code -some auth rule patches, fixing byte endian problems and returning as an error +rewrite allocation of mbufs in send_reset/send_icmp_err to better use +mbuf clusters and size calculations -support LOG_SECURITY, where available, in ipmon +resolve problem with linux panic'ing because the wrong flag was being +passed to skb_clone/skb_alloc -don't return an error for packets which match auth rules +enable use of shared/exclusive locks on freebsd5 and above -introduce fr_icmpacktimeout to timeout entries once an ICMP reply has -been seen separately to when created +do not rely on m_pkthdr.len to be valid all the time for mbufs on modern BSD +and so use mbufchainlen to get the mbuf length instead -3.4.16 15/01/2001 - Released +replace lots of COPYIN/COPYOUT with BCOPYIN/BCOPYOUT where the data is +going to be on the stack and not in userland -fix race condition in flushing of state entries that are timing out +packet buffer pointers were not refreshed & used properly in fr_check() -Add TCP ECN patches +include extra bits for OpenBSD 3.4 & 3.5. -log all NAT entries created, not just those via rules +fix ipf/ipnat parsing regression problems with v3.4 -3.4.15 17/12/2000 - Released +4.1.2 - RELEASED - 27 May 2004 -add minimum ttl filtering (to be replaced later by return-icmp-as-dest -for all ICMP packets matching state entries). +add state top for ipv6 -fix NAT'ing of fragments +fix numerous parsing regressions -fix sanity checks for ICMPV6 +change sample proxies to use SIOCGNATL with the new API -fix up compiling on IRIX 6.2 with IDF/IDL installed +allow macro names to contain underscores (_) -3.4.14 02/11/2000 - Released +split the parser into a collection of dictionaries so that keywords do +not interfere with resolving hostnames and portnames -cause flushing NAT table to generate log records the same as state flush -does. +fix ipfrule LKM loading on freebsd -fix ftp proxy port/pasv +support mapping a fixed range of ports to a single port -fix problem where nat_{in,out}lookup() would release a write lock when it -didn't need to. +fix timeout queue use by proxies with private queues -add check for ipf6.conf in Solaris ipfboot +handle space-led ftp server replies properly -3.4.13 28/10/2000 - Released +fix timeout queue management -fix introduced bug with ICMP packets being rejected when valid +fix fastroute, generation of RST & ICMP packets and operation with to/fastroute -fix bug with proxy's that don't set fin_dlen correctly when calling -fr_addstate() +resolve further linux compatibility problems -3.4.12 26/10/2000 - Released +replace the use of COPYIN with BCOPYIN for platforms that provide ioctl +args on the stack -fix installing into FreeBSD-4.1 +allow flushing of ipv6 rules independant of ipv4 rules -fix FTP proxy bug where it'd hang and make NAT slightly more efficient +correct internal ipv6 checksum calculations -fix general compiling errors/warnings on various platforms +if a 'keep state' rule fails to create state, block the packet rather +than let it through -don't access ICMP data fields that aren't there +correct all checksums in regression tests and correct NAT code to adjust +checksums correctly. -3.4.11 09/10/2000 - Released +fix ipfs -R/-W -return NULL for IPv6 access control lists if it is disabled rather than -random garbage. +4.1.1 - RELEASED - 24 March 2004 -fix for getting protocol & packet length for IPv6 packets for pullup. +allow new connections with the same port numbers as an existing one +in the state table if the creating packet is a SYN -update plog script from version 0.8 to version 0.10 +timeout values have drifted, incorrectly, from what they were in 3.4 -patch from Frank Volf adding fix_datacksum() to NAT code, enhancing the -capabilities for "fixing" checksums. +FreeBSD - compatibility changes for 5.2 -3.4.10 03/09/2000 - Released +don't match on sequence number (as well) for ICMO ECHO/REPLY, just the +ICMP Id. field as otherwise thre is a state/NAT entry per packet pair +rather than per "flow" -merge patch from Frank Volf for ICMP nat handling of TCP/UDP data `errors' +fr_cksum() returned the wrong answer for ICMP -getline() adjusts linenum now +Linux: +- get return-rst and return-icmp working +- treat the interface name the same as if_xname on BSD -add tcphalfclosed timeout +adjust expectations for TCP urgent bits based on observed traffic in the +wild -fill in icmp_nextmtu field if it is defined on the platform +openbsd3.4 has ip_len/ip_off in network byte order when ipfilter is called -RST generation fix from guido +fix flushing of hash pool gorups (ippool -F) as well as displaying them +(ippool -l) -force 32bit compile for gcc on solaris if it can't generate 64bit code +passing of pointers to interface structures wrong for HP-UX/Solaris with +return-* rules. -encase logging when fr_chksrc == 2 in #ifdef IPFILTER_LOG +Make the solaris boot script able to run on 2.5.1 -fix up line wrap problems in plog script +ippool related files missing from Solaris packages -fix ICMP packet handling to not drop valid ICMP errors +The name /dev/ippool should be /dev/iplookup -freebsd 5.0 compat changes +add regression testing for parsing long interface names in nat rules, +along with mssclamp and tags. Also add test for mssclamp operation. -3.4.9 08/08/2000 - Released +ttl displayed for "ipfstat -t" is wrong because ttl is not computed. -implement new aging mechanism in fr_tcp_age() +parse logical interface names (Sun) -fix icmp state checking bug +unloading LKMs was only working if they were enabled. -revamp buildsunos script and build both sparcv7/sparcv9 for Solaris -if on an Ultra with a 64bit system & compiler (Caseper Dik) +sync'ing up NAT sessions when NICs change should cause NAT rules to +re-lookup name->pointer mappings -open ipfilter device read only if we know we can +not all of the ippool ioctl's are IOWR and they should be because they +use the ipfobj_t for passing information in/out of the kernel. leave the +old values defined and handle them, for compatibility. -print out better information for ICMP packets in ipmon +pool stats wrong: ippoolstate used where ipoolstat should be, hash table + statistics not reported at all -move checking for source spoofed packets to a point where we can generate -logs of them +fr_running not set correctly for OpenBSD when compiled into the kernel -return EFAULT from ircopyptr/iwcopyptr +Allow SIOCGETFF while disabled -don't do ioctl(SIOCGETFS) for auth stats +Fix mssclamp with NAT (pasing and printing of the word, plus wrong bytes +altered. How do you say "untested" ?) -fix up freeing mbufs for post-4.3BSD +4.1 - RELEASED - 12 February 2004 -fix returning of inc from ftp proxy +4.0-BETA1 20 August 2003 -fix bugs with ipfs -R/-W (Caseper Dik) +support 0/32 and 0/0 on the RHS in redirect rules -3.4.8 19/07/2000 - Released +where LHS and RHS netmasks are the same size for redirect, do 1:1 mapping +for bimap rules. -create fake opt_inet6.h for FreeBSD-4 compile as LKM +allow NAT rule to match 'all' interfaces with * as interface name -add #ifdef's for KLD_MODULE sanity +do mapping of ICMP sequence id#'s in pings -NAT fastroute'd packets which come out of return-* +allow default age for NAT entries to be set per NAT rule -fix upper/lower case crap in ftp proxy and get seq# checking fixed up. +provide round robin selection of destination addresses for redirect -3.4.7 08/07/2000 - Released +ipmon can load a configuration file with instructions on actions +to take when a matching log entry is received -make "ipf -y" lookup NAT if's which are unknown +now requires pfil to work on Solaris & HP-UX -prepend line numbers to ioctl error messages in ipf/ipnat +supports mapping outbound connections to a specific address/port -don't apply patches to FreeBSD twice +support toggling of logging per ipfilter 'device' -allow for ip_len to be on an unaligned boundary early on in fr_precheck +use queues to expire data rather than lists -fix printing of icmp code when it is 0 +add MSN RPC proxy -correct printing of port numbers in map rules with from/to +add IRC proxy -don't allow fr_func to be called at securelevel > 0 or rules to be added -if securelevel > 0 if they have a non-zero fr_func. +support rules with dynamic ip addresses -3.4.6 11/06/2000 - Released +add ability to define a pool of addresses & networks which can then +be placed in a single rule -add extra regression tests for new nat functionality +support passing entire packet back to user program for authentication -place restrictions on using '!' in map/rdr rules +support master/slave for state information sharing -fix up solaris compile problems +reorganise generic code into a lib directory and make libipf.a -3.4.5 10/06/2000 - Released +user programs enforce version matching with the kernel -mention -sl in ipfstat.8 +supports window scaling if seen at TCP session setup -fix/support '!' in from/to rules (rdr) for NAT +generates C code from filter rules to compile in or load as native +machine code. -add from/to support to rdr NAT rules +supports loading rules comprised of BPF bytecode statements -don't send ICMP errors in response to ICMP errors +HP-UX 11 port completed -fix sunos5 compilation for "ipfstat-top" and cleanup ipfboot +and packets-per-second filtering -input accounting list used for both outbound and inbound packets +add numerical tags to rules for filtering and display in ipmon output -3.4.4 23/05/2000 - Released +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 +3.4.3 20/05/2000 - Released fix ipmon -F diff --git a/contrib/ipfilter/INST.FreeBSD-2.2 b/contrib/ipfilter/INST.FreeBSD-2.2 index 78f7295..0e0ea06 100644 --- a/contrib/ipfilter/INST.FreeBSD-2.2 +++ b/contrib/ipfilter/INST.FreeBSD-2.2 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" To build a kernel for use with the loadable kernel module, follow these steps: diff --git a/contrib/ipfilter/INSTALL.FreeBSD b/contrib/ipfilter/INSTALL.FreeBSD index c732bac..a4a787a 100644 --- a/contrib/ipfilter/INSTALL.FreeBSD +++ b/contrib/ipfilter/INSTALL.FreeBSD @@ -1,7 +1,56 @@ -*** IF you are using FreeBSD 2.2.x, see the file "INST.FreeBSD-2.2" *** -*** IF you are using FreeBSD 3.x, see the file "FreeBSD-3/INST.FreeBSD-3" *** -*** IF you are using FreeBSD 4.x, see the file "FreeBSD-4.0/INST.FreeBSD-4" *** +This file is for use with FreeBSD 4.x and 5.x only. + +To build a kernel for use with the loadable kernel module, follow these +steps: + 1. For FreeBSD version: + 4.* do make freebsd4 + 5.* do make freebsd5 + + 2. do "make install-bsd" + (probably has to be done as root) + + 3. Run "BSD/kupgrade" + + 4. build a new kernel + + 5. install and reboot with the new kernel + + 6. use modload(8) to load the packet filter with: + modload if_ipl.o + + 7. do "modstat" to confirm that it has been loaded successfully. + +There is no need to use mknod to create the device in /dev; +- upon loading the module, it will create itself with the correct values, + under the name (IPL_NAME) from the Makefile. It will also remove itself + from /dev when it is modunload'd. + +To build a kernel with the IP filter, follow these steps: + + 1. For FreeBSD version: + 4.* do make freebsd4 + 5.* do make freebsd5 + + 2. do "make install-bsd" + (probably has to be done as root) + + 3. run "FreeBSD/kinstall" as root + + 4. build a new kernel + + 5. + b) If you are using FreeBSD-3 or later: + create devices for IP Filter as follows (assuming it was + installed into the device table as char dev 20): + mknod /dev/ipl c 79 0 + mknod /dev/ipnat c 79 1 + mknod /dev/ipstate c 79 2 + mknod /dev/ipauth c 79 3 + mknod /dev/ipsync c 79 4 + mknod /dev/ipscan c 79 5 + + 6. install and reboot with the new kernel Darren Reed darrenr@pobox.com diff --git a/contrib/ipfilter/IPFILTER.LICENCE b/contrib/ipfilter/IPFILTER.LICENCE index 2b4b67e..41c151c 100644 --- a/contrib/ipfilter/IPFILTER.LICENCE +++ b/contrib/ipfilter/IPFILTER.LICENCE @@ -1,28 +1,29 @@ -Copyright (C) 1993-2002 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. - -Redistribution and use, with or without modification, in source and binary -forms, are permitted provided that this notice is preserved in its entirety -and due credit is given to the original author and the contributors. - -The licence and distribution terms for any publically available version or -derivative of this code cannot be changed. i.e. this code cannot simply be -copied, in part or in whole, and put under another distribution licence -[including the GNU Public Licence.] - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. - -I hate legalese, don't you ? - +/* + * Copyright (C) 1993-2001 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. + * + * Redistribution and use, with or without modification, in source and binary + * forms, are permitted provided that this notice is preserved in its entirety + * and due credit is given to the original author and the contributors. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied, in part or in whole, and put under another distribution licence + * [including the GNU Public Licence.] + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 AUTHOR 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. + * + * I hate legalese, don't you ? + */ diff --git a/contrib/ipfilter/Makefile b/contrib/ipfilter/Makefile index 44bd106..c54e1db 100644 --- a/contrib/ipfilter/Makefile +++ b/contrib/ipfilter/Makefile @@ -1,23 +1,27 @@ # # Copyright (C) 1993-2001 by Darren Reed. # -# See the IPFILTER.LICENCE file for details on licencing. +# 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.11.2.17 2004/04/16 23:26:09 darrenr Exp $ +# Id: Makefile,v 2.76.2.13 2004/11/08 18:42:40 darrenr Exp # +SHELL=/bin/sh BINDEST=/usr/local/bin SBINDEST=/sbin MANDIR=/usr/local/man #To test prototyping -CC=gcc -Wstrict-prototypes -Wmissing-prototypes +#CC=gcc -Wstrict-prototypes -Wmissing-prototypes +# -Wunused -Wuninitialized #CC=gcc #CC=cc -Dconst= DEBUG=-g -TOP=../.. -CFLAGS=-I$$(TOP) +# -O +CFLAGS=-I$$(TOP) -D_BSD_SOURCE CPU=`uname -m` CPUDIR=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m` -IPFILKERN=`/bin/ls -1tr /usr/src/sys/compile | grep -v .bak | tail -1` +OBJ=. # # To enable this to work as a Loadable Kernel Module... # @@ -27,14 +31,53 @@ IPFLKM=-DIPFILTER_LKM # IPFLOG=-DIPFILTER_LOG # +# To enable loading filter rules compiled to C code... +# +#COMPIPF=-DIPFILTER_COMPILED +# +# To enable synchronisation between IPFilter hosts +# +#SYNC=-DIPFILTER_SYNC +# +# To enable extended IPFilter functionality +# +LOOKUP=-DIPFILTER_LOOKUP -DIPFILTER_SCAN +# # The facility you wish to log messages from ipmon to syslogd with. # LOGFAC=-DLOGFAC=LOG_LOCAL0 +# +# To enable rules to be written with BPF syntax, uncomment these two lines. +# +# WARNING: If you're building a commercial product based on IPFilter, using +# this options *may* infringe at least one patent held by CheckPoint +# (5,606,668.) +# +#IPFBPF=-DIPFILTER_BPF -I/usr/local/include +#LIBBPF=-L/usr/local/lib -lpcap +# +# HP-UX and Solaris require this uncommented for BPF. +# +#BPFILTER=bpf_filter.o +# +# LINUXKERNEL is the path to the top of your Linux kernel source tree. +# By default IPFilter looks for /usr/src/linux, but you may have to change +# it to /usr/src/linux-2.4 or similar. +# +LINUXKERNEL=/usr/src/linux +LINUX=`uname -r | awk -F. ' { printf"%d",$$1;for(i=1;i<NF&&i<3;i++){printf("%02d",$$(i+1));}}'` + +# +# All of the compile-time options are here, used for compiling the userland +# tools for regression testing. Well, all except for IPFILTER_LKM, of course. +# +ALLOPTS=-DIPFILTER_LOG -DIPFILTER_LOOKUP \ + -DIPFILTER_SCAN -DIPFILTER_SYNC -DIPFILTER_CKSUM # # 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 +#STATETOP_CFLAGS=-DSTATETOP # # Where to find the ncurses include files (if not in default path), # @@ -43,7 +86,7 @@ STATETOP_CFLAGS=-DSTATETOP # # How to link the ncurses library # -STATETOP_LIB=-lcurses +#STATETOP_LIB=-lncurses #STATETOP_LIB=-L/usr/local/lib -lncurses # @@ -59,14 +102,16 @@ STATETOP_LIB=-lcurses # POLICY=-DIPF_DEFAULT_PASS=FR_PASS # -MFLAGS1='CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2) $(INET6) $(IPFLOG)' \ +MFLAGS1='CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2) $(SGIREV) $(INET6)' \ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \ - "CPUDIR=$(CPUDIR)" 'STATETOP_CFLAGS=$(STATETOP_CFLAGS)' \ + "LIBBPF=$(LIBBPF)" "CPUDIR=$(CPUDIR)" "IPFBPF=$(IPFBPF)" \ + 'STATETOP_CFLAGS=$(STATETOP_CFLAGS)' "BPFILTER=$(BPFILTER)" \ 'STATETOP_INC=$(STATETOP_INC)' 'STATETOP_LIB=$(STATETOP_LIB)' \ - "BITS=$(BITS)" "OBJ=$(OBJ)" -DEST="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" + "BITS=$(BITS)" "OBJ=$(OBJ)" "LOOKUP=$(LOOKUP)" "COMPIPF=$(COMPIPF)" \ + 'SYNC=$(SYNC)' 'ALLOPTS=$(ALLOPTS)' 'LIBBPF=$(LIBBPF)' MFLAGS=$(MFLAGS1) "IPFLKM=$(IPFLKM)" +MACHASSERT=`/bin/ls -1 /usr/sys/*/mach_assert.h | head -1` # SHELL=/bin/sh # @@ -88,227 +133,248 @@ all: @echo "freebsd22 - compile for FreeBSD-2.2 or greater" @echo "freebsd3 - compile for FreeBSD-3.x" @echo "freebsd4 - compile for FreeBSD-4.x" + @echo "freebsd5 - compile for FreeBSD-5.x" @echo "bsd - compile for generic 4.4BSD systems" @echo "bsdi - compile for BSD/OS" @echo "irix - compile for SGI IRIX" + @echo "hpux - compile for HP-UX 11.00" + @echo "osf - compile for OSF/Tru64 5.1" @echo "" tests: @if [ -d test ]; then (cd test; make) \ else echo test directory not present, sorry; fi +retest: + @if [ -d test ]; then (cd test; make clean && make) \ + else echo test directory not present, sorry; fi + include: if [ ! -f netinet/done ] ; then \ - (cd netinet; ln -s ../*.h .; ln -s ../ip_*_pxy.c .; ); \ + (cd netinet; ln -s ../*.h .; ln -s ../ip_*_pxy.c .;); \ (cd netinet; ln -s ../ipsend/tcpip.h tcpip.h); \ touch netinet/done; \ fi + -(cd netinet; ln -s ../ip_rules.h ip_rules.h) + if [ ! -f net/done ] ; then \ + (cd net; ln -s ../radix_ipf.h .; ); \ + touch net/done; \ + fi sunos solaris: include - CC="$(CC)" ./buildsunos + MAKE="$(MAKE)" MAKEFLAGS="$(MAKEFLAGS)" BPFILTER=$(BPFILTER) \ + CC="$(CC)" DEBUG="$(DEBUG)" ./buildsunos freebsd22: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" -rm -f BSD/$(CPUDIR)/ioconf.h - @if [ -n $(IPFILKERN) ] ; then \ + -if [ x$(IPFILKERN) != x ] ; then \ if [ -f /sys/compile/$(IPFILKERN)/ioconf.h ] ; then \ - ln -s /sys/compile/$(IPFILKERN)/ioconf.h BSD/$(CPUDIR); \ + ln -s /sys/compile/$(IPFILKERN)/ioconf.h BSD/$$y; \ else \ - ln -s /sys/$(IPFILKERN)/ioconf.h BSD/$(CPUDIR); \ + ln -s /sys/$(IPFILKERN)/ioconf.h BSD/$$y; \ fi \ - elif [ ! -f `uname -v|sed -e 's@^.*:\(/[^: ]*\).*@\1@'`/ioconf.h ] ; then \ - echo -n "Can't find ioconf.h in "; \ - echo `uname -v|sed -e 's@^.*:\(/[^: ]*\).*@\1@'`; \ - exit 1;\ else \ - ln -s `uname -v|sed -e 's@^.*:\(/[^: ]*\).*@\1@'`/ioconf.h BSD/$(CPU) ; \ + x=`uname -v|sed -e 's@^.*:\(/[^: ]*\).*$$@\1/ioconf.h@'`; \ + y=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m`; \ + if [ ! -f $$x ] ; then \ + echo -n "Can't find ioconf.h at $$x "; \ + exit 1;\ + else \ + ln -s $$x BSD/$$y ; \ + fi \ fi make freebsd20 -freebsd4: include - if [ x$INET6 = x ] ; then \ +freebsd5: include + if [ x$(INET6) = x ] ; then \ + echo "#undef INET6" > opt_inet6.h; \ + else \ + echo "#define INET6" > opt_inet6.h; \ + fi + if [ x$(ENABLE_PFIL) = x ] ; then \ + echo "#undef PFIL_HOOKS" > opt_pfil.h; \ + else \ + echo "#define PFIL_HOOKS" > opt_pfil.h; \ + fi + + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko.5" "LKMR=ipfrule.ko.5" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) + +freebsd4 : include + if [ x$(INET6) = x ] ; then \ echo "#undef INET6" > opt_inet6.h; \ else \ echo "#define INET6" > opt_inet6.h; \ fi 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 -I/sys"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS1); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko" "LKMR=ipfrule.ko" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build 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 ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS1); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS1) "ML=mlf_ipl.c" "MLR=mlf_rule.o" LKM= LKMR=; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) netbsd: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" LKMR= "MLR=mln_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) -openbsd openbsd21: include +openbsd: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mlo_ipl.c" LKMR= "MLR=mlo_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) freebsd20 freebsd21: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlf_ipl.c"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlf_ipl.c" "MLR=mlf_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) + +osf tru64: null include + make setup "TARGOS=OSF" "CPUDIR=`OSF/cpurev`" + (cd OSF/`OSF/cpurev`; make build TRU64=`uname -v` TOP=../.. "DEBUG=-g" $(MFLAGS) "MACHASSERT=$(MACHASSERT)" "OSREV=`../cpurev`"; cd ..) + (cd OSF/`OSF/cpurev`; make -f Makefile.ipsend build TRU64=`uname -v` TOP=../.. $(MFLAGS) "OSREV=`../cpurev`"; cd ..) bsd: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS); cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" "MLR=mln_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) bsdi bsdos: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build "CC=$(CC)" TOP=../.. $(MFLAGS) LKM= ; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend "CC=$(CC)" TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build "CC=$(CC)" TOP=../.. $(MFLAGS) LKM= LKMR= ; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build "CC=$(CC)" TOP=../.. $(MFLAGS); cd ..) irix IRIX: include - make setup "TARGOS=IRIX" "CPUDIR=$(CPUDIR)" - -(cd IRIX/$(CPUDIR); if [ $(MAKE) = make ] ; then make -f Makefile.std build TOP=../.. $(DEST) SGI=`../getrev` $(MFLAGS); else smake build SGI=`../getrev` TOP=../.. $(DEST) $(MFLAGS); fi;) - -(cd IRIX/$(CPUDIR); if [ $(MAKE) = make ] ; then make -f Makefile.ipsend.std SGI=`../getrev` TOP=../.. $(DEST) $(MFLAGS); else smake -f Makefile.ipsend SGI=`../getrev` TOP=../.. $(DEST) $(MFLAGS); fi) - -linux: include - make setup "TARGOS=Linux" "CPUDIR=$(CPUDIR)" - ./buildlinux - -linuxrev: - (cd Linux/$(CPUDIR); make build TOP=../.. $(DEST) $(MFLAGS) LKM= ; cd ..) - (cd Linux/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(DEST) $(MFLAGS); cd ..) + make setup TARGOS=IRIX CPUDIR=`IRIX/cpurev` + if [ "x${SGIREV}" = "x" ] ; then \ + make irix "SGIREV=-D_KMEMUSER -DIRIX=`IRIX/getrev`"; \ + else \ + (cd IRIX/`IRIX/cpurev`; smake -l -J 1 build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \ + (cd IRIX/`IRIX/cpurev`; make -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \ + fi setup: -if [ ! -d $(TARGOS)/$(CPUDIR) ] ; then mkdir $(TARGOS)/$(CPUDIR); fi -rm -f $(TARGOS)/$(CPUDIR)/Makefile $(TARGOS)/$(CPUDIR)/Makefile.ipsend -ln -s ../Makefile $(TARGOS)/$(CPUDIR)/Makefile - -if [ ! -f $(TARGOS)/$(CPUDIR)/Makefile.std -a \ - -f $(TARGOS)/Makefile.std ] ; then \ - ln -s ../Makefile.std $(TARGOS)/$(CPUDIR)/Makefile.std; \ - fi - -if [ ! -f $(TARGOS)/$(CPUDIR)/Makefile.ipsend.std -a \ - -f $(TARGOS)/Makefile.ipsend.std ] ; then \ - ln -s ../Makefile.ipsend.std $(TARGOS)/$(CPUDIR)/Makefile.ipsend.std; \ - fi -ln -s ../Makefile.ipsend $(TARGOS)/$(CPUDIR)/Makefile.ipsend + -if [ -f $(TARGOS)/Makefile.common ] ; then \ + rm -f $(TARGOS)/$(CPUDIR)/Makefile.common; \ + ln -s ../Makefile.common $(TARGOS)/$(CPUDIR)/Makefile.common;\ + fi clean: clean-include + /bin/rm -rf h y.output ${RM} -f core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl \ vnode_if.h $(LKM) *~ - ${RM} -rf sparcv7 sparcv9 - (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 - [ -d test ] && (cd test; make clean) - (cd ipsend; make clean) + /bin/rm -rf sparcv7 sparcv9 mdbgen_build + (cd SunOS4; $(MAKE) TOP=.. clean) + -(cd SunOS5; $(MAKE) TOP=.. clean) + (cd BSD; $(MAKE) TOP=.. clean) + (cd HPUX; $(MAKE) BITS=32 TOP=.. clean) + (cd Linux; $(MAKE) TOP=.. clean) + (cd OSF; $(MAKE) TOP=.. clean) + if [ "`uname -s`" = "IRIX" ]; then (cd IRIX; $(MAKE) clean); fi + [ -d test ] && (cd test; $(MAKE) clean) + (cd ipsend; $(MAKE) clean) clean-include: - sh -c 'cd netinet; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done' - ${RM} -f netinet/done + sh -c 'if [ -d netinet ] ; then cd netinet; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi' + sh -c 'if [ -d net ] ; then cd net; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi' + ${RM} -f netinet/done net/done clean-bsd: clean-include - (cd BSD; make clean) + (cd BSD; make TOP=.. clean) + +clean-hpux: clean-include + (cd HPUX; $(MAKE) BITS=32 clean) + +clean-osf: clean-include + (cd OSF; make clean) + +clean-linux: clean-include + (cd Linux; make clean) clean-sunos4: clean-include (cd SunOS4; make clean) clean-sunos5: clean-include - (cd SunOS5; make clean) + (cd SunOS5; $(MAKE) clean) + /bin/rm -rf sparcv? clean-irix: clean-include - (cd IRIX; make clean) + (cd IRIX; $(MAKE) clean) -clean-linux: clean-include - (cd Linux; make clean) +h/xti.h: + mkdir -p h + ln -s /usr/include/sys/xti.h h -get: - -@for i in ipf.c ipt.h solaris.c ipf.h kmem.c ipft_ef.c linux.h \ - ipft_pc.c fil.c ipft_sn.c mln_ipl.c fils.c ipft_td.c \ - mls_ipl.c ip_compat.h ipl.h opt.c ip_fil.c ipl_ldev.c \ - parse.c ip_fil.h ipmon.c pcap.h ip_sfil.c ipt.c snoop.h \ - ip_state.c ip_state.h ip_nat.c ip_nat.h ip_frag.c \ - ip_frag.h ip_sfil.c misc.c; do \ - if [ ! -f $$i ] ; then \ - echo "getting $$i"; \ - sccs get $$i; \ - fi \ - done +hpux: include h/xti.h + make setup CPUDIR=`HPUX/cpurev` TARGOS=HPUX + (cd HPUX/`HPUX/cpurev`; $(MAKE) build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..) + (cd HPUX/`HPUX/cpurev`; $(MAKE) -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..) -sunos4 solaris1: null +sunos4 solaris1: (cd SunOS4; make build TOP=.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) - (cd SunOS4; make -f Makefile.ipsend "CC=$(CC)" TOP=.. $(DEST) $(MFLAGS); cd ..) + (cd SunOS4; make -f Makefile.ipsend build "CC=$(CC)" TOP=.. $(DEST) $(MFLAGS); cd ..) sunos5 solaris2: null - (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 ..) + (cd SunOS5/$(CPUDIR); $(MAKE) build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Dsparc -D__sparc__"; cd ..) + (cd SunOS5/$(CPUDIR); $(MAKE) -f Makefile.ipsend build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) sunos5x86 solaris2x86: null (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 ..) + (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) + +linux: include + (cd Linux; make build LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) LINUXKERNEL=$(LINUXKERNEL); cd ..) + (cd Linux; make ipflkm LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) LINUXKERNEL=$(LINUXKERNEL) WORKDIR=`pwd`; cd ..) +# (cd Linux; make -f Makefile.ipsend build LINUX=$(LINUX) TOP=.. "CC=$(CC)" $(MFLAGS); cd ..) -install-linux: - (cd Linux/$(CPUDIR); make install "TOP=../.." $(DEST) $(MFLAGS); cd ..) - (cd Linux/$(CPUDIR); make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(DEST) $(MFLAGS); cd ..) +install-linux: linux + (cd Linux/; make LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) install ; cd ..) install-bsd: (cd BSD/$(CPUDIR); make install "TOP=../.." $(MFLAGS); cd ..) (cd BSD/$(CPUDIR); make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(MFLAGS); cd ..) install-sunos4: solaris - (cd SunOS4; $(MAKE) "CPU=$(CPU)" "TOP=.." install) + (cd SunOS4; $(MAKE) CPU=$(CPU) TOP=.. install) -install-sunos5: solaris - (cd SunOS5; $(MAKE) "CPUDIR=`uname -p`-`uname -r`" "CPU=$(CPU) TOP=.." install) +install-sunos5: solaris null + (cd SunOS5; $(MAKE) CPU=$(CPU) TOP=.. install) + +install-hpux: hpux + (cd HPUX/`HPUX/cpurev`; $(MAKE) CPU=$(CPU) TOP=../.. "BITS=`getconf KERNEL_BITS`" install) install-irix: irix - (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 \ - ipft_pc.c fil.c ipft_sn.c mln_ipl.c fils.c ipft_td.c \ - mls_ipl.c ip_compat.h ipl.h opt.c ip_fil.c ipl_ldev.c \ - parse.c ip_fil.h ipmon.c pcap.h ip_sfil.c ipt.c snoop.h \ - ip_state.c ip_state.h ip_nat.c ip_nat.h ip_frag.c \ - ip_frag.h ip_sfil.c misc.c; do \ - if [ ! -f $$i ] ; then \ - echo "getting $$i"; \ - co $$i; \ - fi \ - done + (cd IRIX; smake install CPU=$(CPU) TOP=.. $(DEST) $(MFLAGS) CPUDIR=`./cpurev`) + +install-osf install-tru64: + (cd OSF/`OSF/cpurev`; make install "TOP=../.." $(MFLAGS); cd ..) + (cd OSF/`OSF/cpurev`; make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(MFLAGS); cd ..) do-cvs: find . -type d -name CVS -print | xargs /bin/rm -rf find . -type f -name .cvsignore -print | xargs /bin/rm -f + /bin/rm -f ip_msnrpc_pxy.c ip_sunrpc_pxy.c + +ip_rules.c ip_rules.h: rules/ip_rules tools/ipfcomp.c + -./ipf -n -cc -f rules/ip_rules 2>/dev/null 1>&2 null: - -@if [ "`$(MAKE) -v 2>&1 | sed -ne 's/GNU.*/GNU/p'`" = "GNU" ] ; then \ + @if [ "`$(MAKE) -v 2>&1 | sed -ne 's/GNU.*/GNU/p'`" = "GNU" ] ; then \ echo 'Do not use GNU make (gmake) to compile IPFilter'; \ exit 1; \ fi -@echo make ok -test-solaris test-sunos4 test-sunos5: solaris - (cd test && make clean && make) - -test-freebsd: freebsd - (cd test && make clean && make) - -test-freebsd22: freebsd22 - (cd test && make clean && make) - -test-freebsd3: freebsd3 - (cd test && make clean && make) - -test-freebsd4: freebsd4 - (cd test && make clean && make) - -test-netbsd: netbsd - (cd test && make clean && make) - -test-openbsd: openbsd - (cd test && make clean && make) - -test-irix: irix - (cd test && make clean && make) +mdb: + /bin/rm -rf mdbgen_build + mdbgen -D_KERNEL -DIPFILTER_LOG -DIPFILTER_LOOKUP -DSUNDDI \ + -DIPFILTER_SCAN -DIPFILTER_LKM -DSOLARIS2=10 -n ipf_mdb -k \ + -I/home/dr146992/pfil -I/home/dr146992/ipf -f \ + /usr/include/netinet/in_systm.h,/usr/include/sys/ethernet.h,/usr/include/netinet/in.h,/usr/include/netinet/ip.h,/usr/include/netinet/ip_var.h,/usr/include/netinet/tcp.h,/usr/include/netinet/tcpip.h,/usr/include/netinet/ip_icmp.h,/usr/include/netinet/udp.h,ip_compat.h,ip_fil.h,ip_nat.h,ip_state.h,ip_proxy.h,ip_scan.h diff --git a/contrib/ipfilter/README b/contrib/ipfilter/README index 80ce748..8464af4 100644 --- a/contrib/ipfilter/README +++ b/contrib/ipfilter/README @@ -1,5 +1,7 @@ IP Filter - What's this about ? ============================ +Web site: http://coombs.anu.edu.au/~avalon/ip-filter.html +How-to: http://www.obfuscation.org/ipf/ipf-howto.txt The idea behind this package is allow those who use Unix workstations as routers (a common occurance in Universities it appears) to apply packet @@ -96,3 +98,4 @@ BNF Darren Reed darrenr@pobox.com +http://coombs.anu.edu.au/~avalon/ip-filter.html diff --git a/contrib/ipfilter/STYLE.TXT b/contrib/ipfilter/STYLE.TXT new file mode 100644 index 0000000..384bcec --- /dev/null +++ b/contrib/ipfilter/STYLE.TXT @@ -0,0 +1,57 @@ + +Over time, I am moving all of the IPFilter code to what I consider a better +coding style than it had before. If you submit patches, I expect them to +conform as appropriate. + +Function Comments +================= +Preceeding each and every function, a comment block like this should +be present: + +/* ------------------------------------------------------------------------ */ +/* Function: function-name */ +/* Returns: return-type */ +/* Parameters: param1(I) - param1 is an input parameter */ +/* p2(O) - p2 is an output parameter passed as an arg */ +/* par3(IO) - par3 is a parameter which is both input and */ +/* output. Pointers to things which are used and */ +/* then get a result stored in them qualify here. */ +/* */ +/* Description about what the function does. This comment should explain */ +/* any gotchas or algorithms that are used which aren't obvious to the */ +/* casual reader. It should not be an excuse to not use comments inside */ +/* the function. */ +/* ------------------------------------------------------------------------ */ + + +Tab spacing +=========== +Tabs are to be at 8 characters. + + +Conditions +========== +All expressions which evaluate to a boolean for a test condition, such as +in an if()/while() statement must involve a boolean operation. Since C +has no native boolean type, this means that one of <,>,<=,>=,==,!= must +be present. Implied boolean evaluations are out. + +In code, the following is banned: + +if (x) +if (!x) +while ((a = b)) + +and should be replaced by: + +if (x != 0) +if (x == 0) +while ((a = b) != 0) + +If pointers are involved, always compare with NULL, ie.: + +if (x != NULL) +if (x == NULL) +while ((a = b) != NULL) + + diff --git a/contrib/ipfilter/WhatsNew40.txt b/contrib/ipfilter/WhatsNew40.txt new file mode 100644 index 0000000..e5b8294 --- /dev/null +++ b/contrib/ipfilter/WhatsNew40.txt @@ -0,0 +1,90 @@ +What's new in IPFilter 4.1 +========================== +(Well, compared to 3.*, anyway) +In no particular order, except headline alphabetical: + +Administration: + - Run-time support for modifying ipf table size parameters. + - Run-time support for tuning other ipfilter parameters. + +Content Scanning: + - Simple matching of content for TCP session startup. + +Firewall Synchronising: + - Master/slave programs available. + +General: + - All input files allow simple 'marco' definitions and expansion, + including nesting. + - Code has been rototilled to make maintenance and enhancements + eaiser for me and you. + - More configuration files and binaries. + - Takes up more memory. + - Probably slower. + - Versioned API to support changes in the ABI without breaking + existing binaries (4.0 onward only.) + - IP-Filter framework in place for handling multiple different + types of packet matching for firewalling. + - IP Id number rewriting available. + - Verification of checksums for recognised packet types. + - Optionally enable/disable IP forwarding when enabled/disabled. + +IPF: + - BPF syntax available for matching packets in ipf rules (1). + - Can convert IPv4 ipf rules into C code and either: + * load them as an LKM o; + * compile them statically into the kernel (where possible.) + - Address pools allow for simpler rules covering large numbers of + addresses/networks (IPv4 only). + - Lookup functions available to map an IPv4 address to a group. + - Groups can be referenced by multiple heads for subroutine-like use. + - NAT/ipf rules can refer to each other via a tag, creating an implied + join that forms part of the packet matching. + - Extra packet attributes available for filter rules: + * source address/routing interface mismatch; + * multicast (3); + * broadcast (2,3); + * state lookup partially failed; + * out of the TCP window for a state connection; + * NAT lookup partially failed. + - PPS (packets per second) matching available for ipf rules. + - Rule collections (cf FreeBSD numbering) supported for ipf rules. + - Groups can now be names rather than just numbers + +IPV6: + - understands extension headers. + - can filter on extension headers. + +Logging: + - ipmon now comes with a configuration file for more advanced logging + behaviour. + - Can append arbitrary logging tags with ipf rules for easy matching. + +NAT: + - "sticky" mapping available to ensure an address translation on + a per-address basis is always the same (while known) for a set + IP address. + +Operating System Support: + - HP-UX 11 added. + - Tru64 5.1a added. + - Solaris/HP-UX now use pfil STREAMS module. + - Linux 2.4 on the way. + +Proxies: + - PPTP proxy added. + - IRC proxy added. + - RPCBIND proxy added. + - FTP proxy support for EPSV (IPv4 only.) + +Stateful Inspection: + - Can insist that all TCP data arrives in order. + - Can insist that all fragments pass through in order. + - The number of states created per-rule can be set where the total + across all rules may exceed the maximum allowed. + - Can elect not to automatically match ICMP error packets. + - TCP sequence number rewriting supported. + +(1) - Requires libpcap for rule parsing +(2) - On Solaris/HP-UX, broadcast packets are seen as multicast packets. +(3) - Not supported on SunOS4 diff --git a/contrib/ipfilter/bpf-ipf.h b/contrib/ipfilter/bpf-ipf.h new file mode 100644 index 0000000..c303152 --- /dev/null +++ b/contrib/ipfilter/bpf-ipf.h @@ -0,0 +1,452 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /devel/CVS/IP-Filter/bpf-ipf.h,v 2.1 2002/10/26 12:14:26 darrenr Exp $ (LBL) + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +typedef int bpf_int32; +typedef u_int bpf_u_int32; + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXINSNS 512 +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for BIOCSETF. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct returned by BIOCGSTATS. + */ +struct bpf_stat { + u_int bs_recv; /* number of packets received */ + u_int bs_drop; /* number of packets dropped */ +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * BPF ioctls + * + * The first set is for compatibility with Sun's pcc style + * header files. If your using gcc, we assume that you + * have run fixincludes so the latter set should work. + */ +#if (defined(sun) || defined(ibm032)) && !defined(__GNUC__) +#define BIOCGBLEN _IOR(B,102, u_int) +#define BIOCSBLEN _IOWR(B,102, u_int) +#define BIOCSETF _IOW(B,103, struct bpf_program) +#define BIOCFLUSH _IO(B,104) +#define BIOCPROMISC _IO(B,105) +#define BIOCGDLT _IOR(B,106, u_int) +#define BIOCGETIF _IOR(B,107, struct ifreq) +#define BIOCSETIF _IOW(B,108, struct ifreq) +#define BIOCSRTIMEOUT _IOW(B,109, struct timeval) +#define BIOCGRTIMEOUT _IOR(B,110, struct timeval) +#define BIOCGSTATS _IOR(B,111, struct bpf_stat) +#define BIOCIMMEDIATE _IOW(B,112, u_int) +#define BIOCVERSION _IOR(B,113, struct bpf_version) +#define BIOCSTCPF _IOW(B,114, struct bpf_program) +#define BIOCSUDPF _IOW(B,115, struct bpf_program) +#else +#define BIOCGBLEN _IOR('B',102, u_int) +#define BIOCSBLEN _IOWR('B',102, u_int) +#define BIOCSETF _IOW('B',103, struct bpf_program) +#define BIOCFLUSH _IO('B',104) +#define BIOCPROMISC _IO('B',105) +#define BIOCGDLT _IOR('B',106, u_int) +#define BIOCGETIF _IOR('B',107, struct ifreq) +#define BIOCSETIF _IOW('B',108, struct ifreq) +#define BIOCSRTIMEOUT _IOW('B',109, struct timeval) +#define BIOCGRTIMEOUT _IOR('B',110, struct timeval) +#define BIOCGSTATS _IOR('B',111, struct bpf_stat) +#define BIOCIMMEDIATE _IOW('B',112, u_int) +#define BIOCVERSION _IOR('B',113, struct bpf_version) +#define BIOCSTCPF _IOW('B',114, struct bpf_program) +#define BIOCSUDPF _IOW('B',115, struct bpf_program) +#endif + +/* + * Structure prepended to each packet. + */ +struct bpf_hdr { + struct timeval bh_tstamp; /* time stamp */ + bpf_u_int32 bh_caplen; /* length of captured portion */ + bpf_u_int32 bh_datalen; /* original length of packet */ + u_short bh_hdrlen; /* length of bpf header (this struct + plus alignment padding) */ +}; +/* + * Because the structure above is not a multiple of 4 bytes, some compilers + * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work. + * Only the kernel needs to know about it; applications use bh_hdrlen. + */ +#if defined(KERNEL) || defined(_KERNEL) +#define SIZEOF_BPF_HDR 18 +#endif + +/* + * Data-link level type codes. + */ + +/* + * These are the types that are the same on all platforms; on other + * platforms, a <net/bpf.h> should be supplied that defines the additional + * DLT_* codes appropriately for that platform (the BSDs, for example, + * should not just pick up this version of "bpf.h"; they should also define + * the additional DLT_* codes used by their kernels, as well as the values + * defined here - and, if the values they use for particular DLT_ types + * differ from those here, they should use their values, not the ones + * here). + */ +#define DLT_NULL 0 /* no link-layer encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* IEEE 802 Networks */ +#define DLT_ARCNET 7 /* ARCNET */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are values from the traditional libpcap "bpf.h". + * Ports of this to particular platforms should replace these definitions + * with the ones appropriate to that platform, if the values are + * different on that platform. + */ +#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ +#define DLT_RAW 12 /* raw IP */ + +/* + * These are values from BSD/OS's "bpf.h". + * These are not the same as the values from the traditional libpcap + * "bpf.h"; however, these values shouldn't be generated by any + * OS other than BSD/OS, so the correct values to use here are the + * BSD/OS values. + * + * Platforms that have already assigned these values to other + * DLT_ codes, however, should give these codes the values + * from that platform, so that programs that use these codes will + * continue to compile - even though they won't correctly read + * files of these types. + */ +#ifdef __NetBSD__ +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * Values between 106 and 107 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * OpenBSD defines it as 12, but that collides with DLT_RAW, so we + * define it as 108 here. If OpenBSD picks up this file, it should + * define DLT_LOOP as 12 in its version, as per the comment above - + * and should not use 108 as a DLT_ value. + */ +#define DLT_LOOP 108 + +/* + * Values between 109 and 112 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * Reserved for use in capture-file headers as a link-layer type + * corresponding to OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, + * but that's DLT_LANE8023 in SuSE 6.3, so we can't use 17 for it + * in capture-file headers. + */ +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * Reserved for 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * Reserved for RFC 2625 IP-over-Fibre Channel, as per a request from + * Don Lee <donlee@cray.com>. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if defined(BSD) && (defined(KERNEL) || defined(_KERNEL)) +/* + * Systems based on non-BSD kernels don't have ifnet's (or they don't mean + * anything if it is in <net/if.h>) and won't work like this. + */ +# if __STDC__ +extern void bpf_tap(struct ifnet *, u_char *, u_int); +extern void bpf_mtap(struct ifnet *, struct mbuf *); +extern void bpfattach(struct ifnet *, u_int, u_int); +extern void bpfilterattach(int); +# else +extern void bpf_tap(); +extern void bpf_mtap(); +extern void bpfattach(); +extern void bpfilterattach(); +# endif /* __STDC__ */ +#endif /* BSD && (_KERNEL || KERNEL) */ +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(struct bpf_insn *, int); +extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/ipfilter/bpf_filter.c b/contrib/ipfilter/bpf_filter.c new file mode 100644 index 0000000..9876ff3 --- /dev/null +++ b/contrib/ipfilter/bpf_filter.c @@ -0,0 +1,517 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)bpf.c 7.5 (Berkeley) 7/15/91 + */ + +#if !(defined(lint) || defined(KERNEL) || defined(_KERNEL)) +static const char rcsid[] = + "@(#) $Header: /devel/CVS/IP-Filter/bpf_filter.c,v 2.2 2003/08/19 16:49:58 darrenr Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include "ip_compat.h" +#include "bpf-ipf.h" + + +#if (defined(__hpux) || SOLARIS) && (defined(_KERNEL) || defined(KERNEL)) +# include <sys/sysmacros.h> +# include <sys/stream.h> +#endif + +#include "pcap-ipf.h" + +#if !defined(KERNEL) && !defined(_KERNEL) +#include <stdlib.h> +#endif + +#define int32 bpf_int32 +#define u_int32 bpf_u_int32 + +static int m_xword __P((mb_t *, int, int *)); +static int m_xhalf __P((mb_t *, int, int *)); + +#ifndef LBL_ALIGN +/* + * XXX - IA-64? If not, this probably won't work on Win64 IA-64 + * systems, unless LBL_ALIGN is defined elsewhere for them. + * XXX - SuperH? If not, this probably won't work on WinCE SuperH + * systems, unless LBL_ALIGN is defined elsewhere for them. + */ +#if defined(sparc) || defined(__sparc__) || defined(mips) || \ + defined(ibm032) || defined(__alpha) || defined(__hpux) || \ + defined(__arm__) +#define LBL_ALIGN +#endif +#endif + +#ifndef LBL_ALIGN + +#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) +#define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p)) +#else +#define EXTRACT_SHORT(p)\ + ((u_short)\ + ((u_short)*((u_char *)p+0)<<8|\ + (u_short)*((u_char *)p+1)<<0)) +#define EXTRACT_LONG(p)\ + ((u_int32)*((u_char *)p+0)<<24|\ + (u_int32)*((u_char *)p+1)<<16|\ + (u_int32)*((u_char *)p+2)<<8|\ + (u_int32)*((u_char *)p+3)<<0) +#endif + +#define MINDEX(len, _m, _k) \ +{ \ + len = M_LEN(m); \ + while ((_k) >= len) { \ + (_k) -= len; \ + (_m) = (_m)->m_next; \ + if ((_m) == 0) \ + return 0; \ + len = M_LEN(m); \ + } \ +} + +static int +m_xword(m, k, err) + register mb_t *m; + register int k, *err; +{ + register int len; + register u_char *cp, *np; + register mb_t *m0; + + MINDEX(len, m, k); + cp = MTOD(m, u_char *) + k; + if (len - k >= 4) { + *err = 0; + return EXTRACT_LONG(cp); + } + m0 = m->m_next; + if (m0 == 0 || M_LEN(m0) + len - k < 4) + goto bad; + *err = 0; + np = MTOD(m0, u_char *); + switch (len - k) { + + case 1: + return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2]; + + case 2: + return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1]; + + default: + return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0]; + } + bad: + *err = 1; + return 0; +} + +static int +m_xhalf(m, k, err) + register mb_t *m; + register int k, *err; +{ + register int len; + register u_char *cp; + register mb_t *m0; + + MINDEX(len, m, k); + cp = MTOD(m, u_char *) + k; + if (len - k >= 2) { + *err = 0; + return EXTRACT_SHORT(cp); + } + m0 = m->m_next; + if (m0 == 0) + goto bad; + *err = 0; + return (cp[0] << 8) | MTOD(m0, u_char *)[0]; + bad: + *err = 1; + return 0; +} + +/* + * Execute the filter program starting at pc on the packet p + * wirelen is the length of the original packet + * buflen is the amount of data present + * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0, + * in all other cases, p is a pointer to a buffer and buflen is its size. + */ +u_int +bpf_filter(pc, p, wirelen, buflen) + register struct bpf_insn *pc; + register u_char *p; + u_int wirelen; + register u_int buflen; +{ + register u_int32 A, X; + register int k; + int32 mem[BPF_MEMWORDS]; + mb_t *m, *n; + int merr, len; + + if (buflen == 0) { + m = (mb_t *)p; + p = MTOD(m, u_char *); + buflen = M_LEN(m); + } else + m = NULL; + + if (pc == 0) + /* + * No filter means accept all. + */ + return (u_int)-1; + A = 0; + X = 0; + --pc; + while (1) { + ++pc; + switch (pc->code) { + + default: + return 0; + case BPF_RET|BPF_K: + return (u_int)pc->k; + + case BPF_RET|BPF_A: + return (u_int)A; + + case BPF_LD|BPF_W|BPF_ABS: + k = pc->k; + if (k + sizeof(int32) > buflen) { + if (m == NULL) + return 0; + A = m_xword(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_ABS: + k = pc->k; + if (k + sizeof(short) > buflen) { + if (m == NULL) + return 0; + A = m_xhalf(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_ABS: + k = pc->k; + if (k >= buflen) { + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + A = MTOD(n, u_char *)[k]; + continue; + } + A = p[k]; + continue; + + case BPF_LD|BPF_W|BPF_LEN: + A = wirelen; + continue; + + case BPF_LDX|BPF_W|BPF_LEN: + X = wirelen; + continue; + + case BPF_LD|BPF_W|BPF_IND: + k = X + pc->k; + if (k + sizeof(int32) > buflen) { + if (m == NULL) + return 0; + A = m_xword(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_IND: + k = X + pc->k; + if (k + sizeof(short) > buflen) { + if (m == NULL) + return 0; + A = m_xhalf(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_IND: + k = X + pc->k; + if (k >= buflen) { + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + A = MTOD(n, u_char *)[k]; + continue; + } + A = p[k]; + continue; + + case BPF_LDX|BPF_MSH|BPF_B: + k = pc->k; + if (k >= buflen) { + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + X = (MTOD(n, char *)[k] & 0xf) << 2; + continue; + } + X = (p[pc->k] & 0xf) << 2; + continue; + + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + + case BPF_JMP|BPF_JA: + pc += pc->k; + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += (A > pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += (A >= pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += (A == pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; + + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + A = -A; + continue; + + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; + } + } +} + + +/* + * Return true if the 'fcode' is a valid filter program. + * The constraints are that each jump be forward and to a valid + * code. The code must terminate with either an accept or reject. + * 'valid' is an array for use by the routine (it must be at least + * 'len' bytes long). + * + * The kernel needs to be able to verify an application's filter code. + * Otherwise, a bogus program could easily crash the system. + */ +int +bpf_validate(f, len) + struct bpf_insn *f; + int len; +{ + register int i; + register struct bpf_insn *p; + + for (i = 0; i < len; ++i) { + /* + * Check that that jumps are forward, and within + * the code block. + */ + p = &f[i]; + if (BPF_CLASS(p->code) == BPF_JMP) { + register int from = i + 1; + + if (BPF_OP(p->code) == BPF_JA) { + if (from + p->k >= (unsigned)len) + return 0; + } + else if (from + p->jt >= len || from + p->jf >= len) + return 0; + } + /* + * Check that memory operations use valid addresses. + */ + if ((BPF_CLASS(p->code) == BPF_ST || + (BPF_CLASS(p->code) == BPF_LD && + (p->code & 0xe0) == BPF_MEM)) && + (p->k >= BPF_MEMWORDS || p->k < 0)) + return 0; + /* + * Check for constant division by 0. + */ + if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) + return 0; + } + return BPF_CLASS(f[len - 1].code) == BPF_RET; +} diff --git a/contrib/ipfilter/bsdinstall b/contrib/ipfilter/bsdinstall index ce921b6..7689a21 100755 --- a/contrib/ipfilter/bsdinstall +++ b/contrib/ipfilter/bsdinstall @@ -5,8 +5,13 @@ cmd=/bin/mv strip="" chmod="chmod 755" -chown="chown -f root" -chgrp="chgrp -f bin" +if [ "`uname -s`" = "HP-UX" ] ; then + chown="chown root" + chgrp="chgrp bin" +else + chown="chown -f root" + chgrp="chgrp -f bin" +fi while true ; do case $1 in -s ) strip="strip" diff --git a/contrib/ipfilter/buildsunos b/contrib/ipfilter/buildsunos index fa2474e..5e857e7 100755 --- a/contrib/ipfilter/buildsunos +++ b/contrib/ipfilter/buildsunos @@ -3,13 +3,30 @@ if [ ! -f netinet/done ] ; then echo "Do NOT run this script directly, do 'make solaris'!" exit 1 fi -# $Id: buildsunos,v 2.1.2.1 1999/08/08 13:55:20 darrenr Exp $ +# Id: buildsunos,v 2.20 2004/02/07 18:08:46 darrenr Exp : rev=`uname -r | sed -e 's/^\([^\.]*\)\..*/\1/'` if [ -d /usr/ccs/bin ] ; then PATH=/usr/ccs/bin:${PATH} + export PATH fi + if [ $rev = 5 ] ; then + if [ ! -d ../pfil ] ; then + cat << __EOF__ +pfil directory in .. missing, please download pfil package and extract that +into the parent directory. + +See INSTALL.Sol2 for more instructions. +__EOF__ + exit 1 + fi + # + # /usr/ucb/cc will not work + # + PATH=`echo $PATH | sed -e s:/usr/ucb::g -e s/::/:/g` + export PATH + cpu=`uname -p` cpudir=${cpu}-`uname -r` solrev=`uname -r | sh -c 'IFS=. read j n x; echo $n'` @@ -20,30 +37,132 @@ if [ $rev = 5 ] ; then /bin/rm -f SunOS5/${cpudir}/Makefile.ipsend ln -s `pwd`/SunOS5/Makefile SunOS5/${cpudir}/Makefile ln -s `pwd`/SunOS5/Makefile.ipsend SunOS5/${cpudir}/Makefile.ipsend - ARCHINC= - XARCH= - if [ -d /opt/SUNWspro/bin ] ; then - CC="/opt/SUNWspro/bin/cc ${CFL}" - export CC - /bin/optisa sparcv9 >/dev/null 2>&1 - if [ $? -eq 0 ] ; then - ARCHINC="-I/usr/include/v9" - XARCH="-xarch=v9 -xchip=ultra -dalign -xcode=abs32" + + # + # Default C compiler is "cc", override on make commandline + # + if [ "x$CC" = "x" ] ; then + if echo '' | cc -E - >/dev/null 2>&1 ; then + CC=cc + else + if echo '' | gcc -E - >/dev/null 2>&1 ; then + CC=gcc + else + echo "No working compiler found" + exit 1 + fi fi - else + fi + v=`echo '__GNUC__' | 2>&1 ${CC} -E - | 2>&1 sed -ne '/^[0-9]* *$/p'` + if [ x$v != x ] ; then CC=gcc fi + + case "$CC" in + *gcc*) # gcc + XARCH32="" + XARCH64="-m64 -mcmodel=medlow" + ;; + *) # Sun C + XARCH32="-Xa -xildoff" + XARCH64="$XARCH32 -xarch=v9 -xchip=ultra -dalign -xcode=abs32" + ;; + esac + + export CC + + ISABITS=32 + + OBJ32=sparcv7 + ARCHINC32= + OBJ64=sparcv9 + ARCHINC64="-I/usr/include/v9" + + if [ $solrev -ge 7 ] && /bin/optisa sparcv8plus > /dev/null + then + # We run Solaris 7+ on 64 bit capable hardware. + BUILDBOTH=true + else + BUILDBOTH=false + OBJ32=. + fi + + if $BUILDBOTH + then + echo Testing compiler $CC for 64 bit object file generation. + t=conftest$$.c + trap 'rm -f $t 32.out 64.out; exit 1' 0 1 2 3 15 + cat > $t <<-EOF + #include <stdio.h> + int main(void) + { + printf("%ld\n", (long) sizeof(long)); + exit(0); + } + EOF + + # Is it perhaps a 64 bit only compiler? + if $CC $XARCH32 $t -o 32.out >/dev/null 2>&1 && + [ "`./32.out`" = 4 ] + then :; else + echo $CC $XARCH32 cannot create 32 bit executables. 1>&2 + exit 1 + fi + if $CC $XARCH64 $t -o 64.out >/dev/null 2>&1 && + { out64=`./64.out 2>/dev/null` ; + [ "$out64" = 8 -o "`isainfo -b`" = 32 -a "$out64" = "" ] + } + then + echo "found 32/64 bit compiler" 1>&2 + CC64=true + else + CC64=false + fi + rm -f $t 32.out 64.out + trap 0 1 2 3 15 + fi + + # If we're running 64 bit, we *must* build 64 bit. + if ([ "`isainfo -b`" = 64 ]) 2>/dev/null ; then + if $CC64 ; then :; else + echo "No 64 bit capable compiler was found" 1>&2 + exit 1 + fi + ISABITS="32 64" + elif $BUILDBOTH && $CC64 + then + ISABITS="32 64" + else + OBJ32=. + fi else cpu=`uname -m` cpudir=${cpu}-`uname -r` fi + +# Default $MAKE to make +: ${MAKE:=make} + if [ $cpu = i386 ] ; then - make ${1+"$@"} sunos5x86 SOLARIS2="-DSOLARIS2=$solrev" CPU= CPUDIR=${cpudir} CC="$CC $XARCH" XARCH="$XARCH" ARCHINC="$ARCHINC" + if [ -n "$BPFILTER" ] ; then + BPF="BPFILTER=./$BPFILTER" + fi + $MAKE $MAKEFLAGS ${1+"$@"} sunos5x86 SOLARIS2="-DSOLARIS2=$solrev" CPU= CPUDIR=${cpudir} CC="$CC $XARCH32" XARCH="$XARCH32" ARCHINC="$ARCHINC32" BITS=32 OBJ=. $BPF exit $? fi if [ x$solrev = x ] ; then - make ${1+"$@"} sunos$rev "ARCH=`uname -m`" + make ${1+"$@"} sunos$rev "TOP=.." "ARCH=`uname -m`" exit $? fi -make ${1+"$@"} sunos$rev SOLARIS2="-DSOLARIS2=$solrev" CPU= CPUDIR=${cpudir} CC="$CC $XARCH" XARCH="$XARCH" ARCHINC="$ARCHINC" -exit $? +for b in $ISABITS +do + echo build $b bit binaries. + for v in OBJ ARCHINC XARCH + do + eval $v=\"\$$v$b\" + done + if [ -n "$BPFILTER" ] ; then + BPF="BPFILTER=$OBJ/$BPFILTER" + fi + $MAKE $MAKEFLAGS ${1+"$@"} sunos$rev SOLARIS2="-DSOLARIS2=$solrev" CPU= CPUDIR=${cpudir} CC="$CC $XARCH" XARCH="$XARCH" ARCHINC="$ARCHINC" BITS=$b OBJ=$OBJ $BPF || exit $? +done diff --git a/contrib/ipfilter/etc/protocols b/contrib/ipfilter/etc/protocols index fd7a1d2..30c5b76 100644 --- a/contrib/ipfilter/etc/protocols +++ b/contrib/ipfilter/etc/protocols @@ -38,9 +38,12 @@ ddp 37 DDP # Datagram Delivery Protocol idpr-cmtp 38 IDPR-CMTP # IDPR Control Message Transport Proto tp++ 39 TP++ # TP++ Transport Protocol il 40 IL # IL Transport Protocol +ipv6 41 IPv6 # Internet Protocol, version 6 sip 41 SIP # Simple Internet Protocol sdrp 42 SDRP # Source Demand Routing Protocol +ipv6-route 43 IPv6-Route # Routing Header for IPv6 sip-sr 43 SIP-SR # SIP Source Route +ipv6-frag 44 IPv6-Frag # Fragment Hedaer for IPv6 sip-frag 44 SIP-FRAG # SIP Fragment idrp 45 IDRP # Inter-Domain Routing Protocol rsvp 46 RSVP # Reservation Protocol diff --git a/contrib/ipfilter/etc/services b/contrib/ipfilter/etc/services index 01c4b782..d8aa0d5 100644 --- a/contrib/ipfilter/etc/services +++ b/contrib/ipfilter/etc/services @@ -2359,8 +2359,8 @@ dpserve 7020/tcp # DP Serve dpserve 7020/udp # DP Serve dpserveadmin 7021/tcp # DP Serve Admin dpserveadmin 7021/udp # DP Serve Admin +raudio 7070/tcp @ Real Audio arcp 7070/tcp # ARCP -raudio 7070/tcp # Real Audio arcp 7070/udp # ARCP clutild 7174/tcp # Clutild clutild 7174/udp # Clutild diff --git a/contrib/ipfilter/fil.c b/contrib/ipfilter/fil.c index 1a1da36..6f3a13d 100644 --- a/contrib/ipfilter/fil.c +++ b/contrib/ipfilter/fil.c @@ -1,24 +1,29 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include <sys/errno.h> #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> -#include <sys/file.h> -#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ - defined(_KERNEL) -# include "opt_ipfilter_log.h" +#if defined(__NetBSD__) +# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) +# include "opt_ipfilter_log.h" +# endif #endif -#if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \ +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ (__FreeBSD_version >= 220000) # if (__FreeBSD_version >= 400000) -# ifndef KLD_MODULE +# if !defined(IPFILTER_LKM) # include "opt_inet6.h" # endif # if (__FreeBSD_version == 400019) @@ -26,42 +31,56 @@ # endif # endif # include <sys/filio.h> -# include <sys/fcntl.h> #else # include <sys/ioctl.h> #endif -#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +#include <sys/fcntl.h> +#if defined(_KERNEL) # include <sys/systm.h> +# include <sys/file.h> #else # include <stdio.h> # include <string.h> # include <stdlib.h> -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux -# include <sys/mbuf.h> +# include <stddef.h> +# include <sys/file.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; # endif +# include <sys/uio.h> +# undef _KERNEL +#endif +#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ + !defined(linux) +# include <sys/mbuf.h> #else -# include <sys/cmn_err.h> -# include <sys/byteorder.h> -# if SOLARIS2 < 5 +# if !defined(linux) +# include <sys/byteorder.h> +# endif +# if (SOLARIS2 < 5) && defined(sun) # include <sys/dditypes.h> # endif -# include <sys/stream.h> #endif -#ifndef linux +#ifdef __hpux +# define _NET_ROUTE_INCLUDED +#endif +#if !defined(linux) # include <sys/protosw.h> -# include <sys/socket.h> #endif +#include <sys/socket.h> #include <net/if.h> #ifdef sun # include <net/af.h> #endif +#if !defined(_KERNEL) && defined(__FreeBSD__) +# include "radix_ipf.h" +#endif #include <net/route.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#ifndef linux +#if !defined(linux) # include <netinet/ip_var.h> #endif #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ @@ -69,12 +88,17 @@ # include <netinet/in_var.h> #endif #include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> +#if !defined(__sgi) || defined(_KERNEL) +# include <netinet/udp.h> +# include <netinet/ip_icmp.h> +#endif +#ifdef __hpux +# undef _NET_ROUTE_INCLUDED +#endif #include "netinet/ip_compat.h" #ifdef USE_INET6 # include <netinet/icmp6.h> -# if !SOLARIS && defined(_KERNEL) +# if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) # include <netinet6/in6_var.h> # endif #endif @@ -85,76 +109,142 @@ #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" #include "netinet/ip_auth.h" -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include "opt_ipfilter.h" -# endif +#ifdef IPFILTER_SCAN +# include "netinet/ip_scan.h" +#endif +#ifdef IPFILTER_SYNC +# include "netinet/ip_sync.h" +#endif +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#ifdef IPFILTER_COMPILED +# include "netinet/ip_rules.h" +#endif +#if defined(IPFILTER_BPF) && defined(_KERNEL) +# include <net/bpf.h> +#endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" # endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) #endif #include "netinet/ipl.h" +/* END OF INCLUDES */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.82 2004/06/20 10:27:47 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: fil.c,v 2.243.2.57 2005/03/28 10:47:50 darrenr Exp"; #endif #ifndef _KERNEL # include "ipf.h" # include "ipt.h" +# include "bpf-ipf.h" extern int opts; # define FR_VERBOSE(verb_pr) verbose verb_pr # define FR_DEBUG(verb_pr) debug verb_pr -# define IPLLOG(a, c, d, e) ipflog(a, c, d, e) #else /* #ifndef _KERNEL */ # define FR_VERBOSE(verb_pr) # define FR_DEBUG(verb_pr) -# define IPLLOG(a, c, d, e) ipflog(a, c, d, e) -# if SOLARIS || defined(__sgi) -extern KRWLOCK_T ipf_mutex, ipf_auth, ipf_nat; -extern kmutex_t ipf_rw; -# endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ -struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}}; +fr_info_t frcache[2][8]; +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]; + *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }, + *ipnatrules[2][2] = { { NULL, NULL }, { NULL, NULL } }; +struct frgroup *ipfgroups[IPL_LOGSIZE][2]; +char ipfilter_version[] = IPL_VERSION; +int fr_refcnt = 0; +/* + * For fr_running: + * 0 == loading, 1 = running, -1 = disabled, -2 = unloading + */ +int fr_running = 0; int fr_flags = IPF_LOGGING; int fr_active = 0; -int fr_chksrc = 0; -int fr_minttl = 3; -int fr_minttllog = 1; +int fr_control_forwarding = 0; +int fr_update_ipid = 0; +u_short fr_ip_id = 0; +int fr_chksrc = 0; /* causes a system crash if enabled */ +int fr_minttl = 4; +u_long fr_frouteok[2] = {0, 0}; +u_long fr_userifqs = 0; +u_long fr_badcoalesces[2] = {0, 0}; +u_char ipf_iss_secret[32]; #if defined(IPFILTER_DEFAULT_BLOCK) -int fr_pass = FR_NOMATCH|FR_BLOCK; +int fr_pass = FR_BLOCK|FR_NOMATCH; #else -int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH); +int fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; #endif -char ipfilter_version[] = IPL_VERSION; - -fr_info_t frcache[2]; +int fr_features = 0 +#ifdef IPFILTER_LKM + | IPF_FEAT_LKM +#endif +#ifdef IPFILTER_LOG + | IPF_FEAT_LOG +#endif +#ifdef IPFILTER_LOOKUP + | IPF_FEAT_LOOKUP +#endif +#ifdef IPFILTER_BPF + | IPF_FEAT_BPF +#endif +#ifdef IPFILTER_COMPILED + | IPF_FEAT_COMPILED +#endif +#ifdef IPFILTER_CKSUM + | IPF_FEAT_CKSUM +#endif +#ifdef IPFILTER_SYNC + | IPF_FEAT_SYNC +#endif +#ifdef IPFILTER_SCAN + | IPF_FEAT_SCAN +#endif +#ifdef USE_INET6 + | IPF_FEAT_IPV6 +#endif + ; -static int frflushlist __P((int, minor_t, int *, frentry_t **)); -#ifdef _KERNEL -static void frsynclist __P((frentry_t *)); -# ifndef __sgi -static void *ipf_pullup __P((mb_t *, fr_info_t *, int, void *)); -# endif +static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); +static int fr_portcheck __P((frpcmp_t *, u_short *)); +static int frflushlist __P((int, minor_t, int *, frentry_t **)); +static ipfunc_t fr_findfunc __P((ipfunc_t)); +static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *)); +static int fr_funcinit __P((frentry_t *fr)); +static INLINE void frpr_esp __P((fr_info_t *)); +static INLINE void frpr_gre __P((fr_info_t *)); +static INLINE void frpr_udp __P((fr_info_t *)); +static INLINE void frpr_tcp __P((fr_info_t *)); +static INLINE void frpr_icmp __P((fr_info_t *)); +static INLINE void frpr_ipv4hdr __P((fr_info_t *)); +static INLINE int frpr_pullup __P((fr_info_t *, int)); +static INLINE void frpr_short __P((fr_info_t *, int)); +static INLINE void frpr_tcpcommon __P((fr_info_t *)); +static INLINE void frpr_udpcommon __P((fr_info_t *)); +static INLINE int fr_updateipid __P((fr_info_t *)); +#ifdef IPFILTER_LOOKUP +static int fr_grpmapinit __P((frentry_t *fr)); +static INLINE void *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *)); #endif +static void frsynclist __P((frentry_t *, void *)); +static ipftuneable_t *fr_findtunebyname __P((char *)); +static ipftuneable_t *fr_findtunebycookie __P((void *, void **)); /* * bit values for identifying presence of individual IP options + * All of these tables should be ordered by increasing key value on the left + * hand side to allow for binary searching of the array and include a trailer + * with a 0 for the bitmask for linear searches to easily find the end with. */ -struct optlist ipopts[20] = { +const struct optlist ipopts[20] = { { IPOPT_NOP, 0x000001 }, { IPOPT_RR, 0x000002 }, { IPOPT_ZSU, 0x000004 }, @@ -177,10 +267,34 @@ struct optlist ipopts[20] = { { 0, 0x000000 } }; +#ifdef USE_INET6 +struct optlist ip6exthdr[] = { + { IPPROTO_HOPOPTS, 0x000001 }, + { IPPROTO_IPV6, 0x000002 }, + { IPPROTO_ROUTING, 0x000004 }, + { IPPROTO_FRAGMENT, 0x000008 }, + { IPPROTO_ESP, 0x000010 }, + { IPPROTO_AH, 0x000020 }, + { IPPROTO_NONE, 0x000040 }, + { IPPROTO_DSTOPTS, 0x000080 }, + { 0, 0 } +}; +#endif + +struct optlist tcpopts[] = { + { TCPOPT_NOP, 0x000001 }, + { TCPOPT_MAXSEG, 0x000002 }, + { TCPOPT_WINDOW, 0x000004 }, + { TCPOPT_SACK_PERMITTED, 0x000008 }, + { TCPOPT_SACK, 0x000010 }, + { TCPOPT_TIMESTAMP, 0x000020 }, + { 0, 0x000000 } +}; + /* * bit values for identifying presence of individual IP security options */ -struct optlist secopt[8] = { +const struct optlist secopt[8] = { { IPSO_CLASS_RES4, 0x01 }, { IPSO_CLASS_TOPS, 0x02 }, { IPSO_CLASS_SECR, 0x04 }, @@ -193,292 +307,1021 @@ struct optlist secopt[8] = { /* - * compact the IP header into a structure which contains just the info. - * which is useful for comparing IP headers with. + * Table of functions available for use with call rules. */ -int fr_makefrip(hlen, ip, fin) -int hlen; -ip_t *ip; +static ipfunc_resolve_t fr_availfuncs[] = { +#ifdef IPFILTER_LOOKUP + { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit }, + { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit }, +#endif + { "", NULL } +}; + + +/* + * The next section of code is a a collection of small routines that set + * fields in the fr_info_t structure passed based on properties of the + * current packet. There are different routines for the same protocol + * for each of IPv4 and IPv6. Adding a new protocol, for which there + * will "special" inspection for setup, is now more easily done by adding + * a new routine and expanding the frpr_ipinit*() function rather than by + * adding more code to a growing switch statement. + */ +#ifdef USE_INET6 +static INLINE void frpr_udp6 __P((fr_info_t *)); +static INLINE void frpr_tcp6 __P((fr_info_t *)); +static INLINE void frpr_icmp6 __P((fr_info_t *)); +static INLINE void frpr_ipv6hdr __P((fr_info_t *)); +static INLINE void frpr_short6 __P((fr_info_t *, int)); +static INLINE int frpr_hopopts6 __P((fr_info_t *)); +static INLINE int frpr_routing6 __P((fr_info_t *)); +static INLINE int frpr_dstopts6 __P((fr_info_t *)); +static INLINE int frpr_fragment6 __P((fr_info_t *)); + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_short6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function enforces the 'is a packet too short to be legit' rule */ +/* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ +/* for frpr_short() for more details. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_short6(fin, min) fr_info_t *fin; +int min; { - u_short optmsk = 0, secmsk = 0, auth = 0; - int i, mv, ol, off, p, plen, v; -#if defined(_KERNEL) -# if SOLARIS - mb_t *m = fin->fin_qfm; -# else - mb_t *m = fin->fin_mp ? *fin->fin_mp : NULL; -# endif -#endif fr_ip_t *fi = &fin->fin_fi; - struct optlist *op; - u_char *s, opt; - tcphdr_t *tcp; + int off; - fin->fin_rev = 0; - fin->fin_dp = NULL; - fin->fin_fr = NULL; - fin->fin_tcpf = 0; - fin->fin_data[0] = 0; - fin->fin_data[1] = 0; - fin->fin_rule = -1; - fin->fin_group = -1; - fin->fin_icode = ipl_unreach; - v = fin->fin_v; - fi->fi_v = v; - fin->fin_hlen = hlen; - if (v == 4) { - fin->fin_id = ip->ip_id; - fi->fi_tos = ip->ip_tos; -#if (OpenBSD >= 200311) && defined(_KERNEL) - ip->ip_off = ntohs(ip->ip_off); -#endif - off = (ip->ip_off & IP_OFFMASK); - (*(((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 & (IP_MF|IP_OFFMASK)) - fi->fi_fl |= FI_FRAG; -#if (OpenBSD >= 200311) && defined(_KERNEL) - ip->ip_len = ntohs(ip->ip_len); -#endif - plen = ip->ip_len; - fin->fin_dlen = plen - hlen; + off = fin->fin_off; + if (off == 0) { + if (fin->fin_plen < fin->fin_hlen + min) + fi->fi_flx |= FI_SHORT; + } else if (off < min) { + fi->fi_flx |= FI_SHORT; } -#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; - 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; - plen += sizeof(*ip6); + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_ipv6hdr */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Copy values from the IPv6 header into the fr_info_t struct and call the */ +/* per-protocol analyzer if it exists. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_ipv6hdr(fin) +fr_info_t *fin; +{ + int p, go = 1, i, hdrcount, coalesced; + ip6_t *ip6 = (ip6_t *)fin->fin_ip; + fr_ip_t *fi = &fin->fin_fi; + + fin->fin_off = 0; + + fi->fi_tos = 0; + fi->fi_optmsk = 0; + fi->fi_secmsk = 0; + fi->fi_auth = 0; + + coalesced = (fin->fin_flx & FI_COALESCE) ? 1 : 0; + p = ip6->ip6_nxt; + fi->fi_ttl = ip6->ip6_hlim; + fi->fi_src.in6 = ip6->ip6_src; + fi->fi_dst.in6 = ip6->ip6_dst; + fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff); + + hdrcount = 0; + while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) { + switch (p) + { + case IPPROTO_UDP : + frpr_udp6(fin); + go = 0; + break; + + case IPPROTO_TCP : + frpr_tcp6(fin); + go = 0; + break; + + case IPPROTO_ICMPV6 : + frpr_icmp6(fin); + go = 0; + break; + + case IPPROTO_GRE : + frpr_gre(fin); + go = 0; + break; + + case IPPROTO_HOPOPTS : + /* + * Actually, hop by hop header is only allowed right + * after IPv6 header! + */ + if (hdrcount != 0) + fin->fin_flx |= FI_BAD; + + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced != 1) + return; + } + p = frpr_hopopts6(fin); + break; + + case IPPROTO_DSTOPTS : + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced != 1) + return; + } + p = frpr_dstopts6(fin); + break; + + case IPPROTO_ROUTING : + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced != 1) + return; + } + p = frpr_routing6(fin); + break; + + case IPPROTO_ESP : + frpr_esp(fin); + /*FALLTHROUGH*/ + case IPPROTO_AH : + case IPPROTO_IPV6 : + for (i = 0; ip6exthdr[i].ol_bit != 0; i++) + if (ip6exthdr[i].ol_val == p) { + fin->fin_flx |= ip6exthdr[i].ol_bit; + break; + } + go = 0; + break; + + case IPPROTO_NONE : + go = 0; + break; + + case IPPROTO_FRAGMENT : + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced != 1) + return; + } + p = frpr_fragment6(fin); + break; + + default : + go = 0; + break; + } + hdrcount++; + + /* + * It is important to note that at this point, for the + * extension headers (go != 0), the entire header may not have + * been pulled up when the code gets to this point. This is + * only done for "go != 0" because the other header handlers + * will all pullup their complete header and the other + * indicator of an incomplete header is that this eas just an + * extension header. + */ + if ((go != 0) && (p != IPPROTO_NONE) && + (frpr_pullup(fin, 0) == -1)) { + p = IPPROTO_NONE; + go = 0; + } } -#endif - else - return -1; + fi->fi_p = p; +} - fin->fin_off = off; - fin->fin_plen = plen; - tcp = (tcphdr_t *)((char *)ip + hlen); - fin->fin_misc = 0; - off <<= 3; +/* ------------------------------------------------------------------------ */ +/* Function: frpr_hopopts6 */ +/* Returns: int - value of the next header or IPPROTO_NONE if error */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function checks pending hop by hop options extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_hopopts6(fin) +fr_info_t *fin; +{ + struct ip6_ext *hdr; + u_short shift; + int i; + + fin->fin_flx |= FI_V6EXTHDR; + + /* 8 is default length of extension hdr */ + if ((fin->fin_dlen - 8) < 0) { + fin->fin_flx |= FI_SHORT; + return IPPROTO_NONE; + } + + if (frpr_pullup(fin, 8) == -1) + return IPPROTO_NONE; + + hdr = fin->fin_dp; + shift = 8 + (hdr->ip6e_len << 3); + if (shift > fin->fin_dlen) { /* Nasty extension header length? */ + fin->fin_flx |= FI_BAD; + return IPPROTO_NONE; + } + + for (i = 0; ip6exthdr[i].ol_bit != 0; i++) + if (ip6exthdr[i].ol_val == IPPROTO_HOPOPTS) { + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + break; + } + + fin->fin_dp = (char *)fin->fin_dp + shift; + fin->fin_dlen -= shift; + + return hdr->ip6e_nxt; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_routing6 */ +/* Returns: int - value of the next header or IPPROTO_NONE if error */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function checks pending routing extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_routing6(fin) +fr_info_t *fin; +{ + struct ip6_ext *hdr; + u_short shift; + int i; + + fin->fin_flx |= FI_V6EXTHDR; + + /* 8 is default length of extension hdr */ + if ((fin->fin_dlen - 8) < 0) { + fin->fin_flx |= FI_SHORT; + return IPPROTO_NONE; + } + + if (frpr_pullup(fin, 8) == -1) + return IPPROTO_NONE; + hdr = fin->fin_dp; + + shift = 8 + (hdr->ip6e_len << 3); /* - * For both ICMPV6 & ICMP, we attempt to pullup the entire packet into - * a single buffer for recognised error return packets. Why? Because - * the entire data section of the ICMP payload is considered to be of - * significance and maybe required in NAT/state processing, so rather - * than be careful later, attempt to get it all in one buffeer first. - * For TCP we just make sure the _entire_ TCP header is in the first - * buffer for convienience. + * Nasty extension header length? */ - switch (p) - { -#ifdef USE_INET6 - case IPPROTO_ICMPV6 : - { - int minicmpsz = sizeof(struct icmp6_hdr); - struct icmp6_hdr *icmp6; + if ((shift > fin->fin_dlen) || (shift < sizeof(struct ip6_hdr)) || + ((shift - sizeof(struct ip6_hdr)) & 15)) { + fin->fin_flx |= FI_BAD; + return IPPROTO_NONE; + } - if (!(fin->fin_fl & FI_SHORT) && (fin->fin_dlen > 1)) { - fin->fin_data[0] = *(u_short *)tcp; + for (i = 0; ip6exthdr[i].ol_bit != 0; i++) + if (ip6exthdr[i].ol_val == IPPROTO_ROUTING) { + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + break; + } - icmp6 = (struct icmp6_hdr *)tcp; + fin->fin_dp = (char *)fin->fin_dp + shift; + fin->fin_dlen -= shift; - switch (icmp6->icmp6_type) - { - case ICMP6_ECHO_REPLY : - case ICMP6_ECHO_REQUEST : - minicmpsz = ICMP6_MINLEN; - break; - case ICMP6_DST_UNREACH : - case ICMP6_PACKET_TOO_BIG : - case ICMP6_TIME_EXCEEDED : - case ICMP6_PARAM_PROB : -# if defined(KERNEL) && !defined(__sgi) - if ((m != NULL) && (M_BLEN(m) < plen)) { - ip = ipf_pullup(m, fin, plen, ip); - if (ip == NULL) - return -1; - tcp = (tcphdr_t *)((char *)ip + hlen); - } -# endif /* KERNEL && !__sgi */ - minicmpsz = ICMP6ERR_IPICMPHLEN; - break; - default : - break; + return hdr->ip6e_nxt; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_fragment6 */ +/* Returns: int - value of the next header or IPPROTO_NONE if error */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Examine the IPv6 fragment header and extract fragment offset information.*/ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_fragment6(fin) +fr_info_t *fin; +{ + struct ip6_frag *frag; + struct ip6_ext *hdr; + int i; + + fin->fin_flx |= (FI_FRAG|FI_V6EXTHDR); + + /* 8 is default length of extension hdr */ + if ((fin->fin_dlen - 8) < 0) { + fin->fin_flx |= FI_SHORT; + return IPPROTO_NONE; + } + + /* + * Only one frgament header is allowed per IPv6 packet but it need + * not be the first nor last (not possible in some cases.) + */ + for (i = 0; ip6exthdr[i].ol_bit != 0; i++) + if (ip6exthdr[i].ol_val == IPPROTO_FRAGMENT) + break; + + if (fin->fin_optmsk & ip6exthdr[i].ol_bit) { + fin->fin_flx |= FI_BAD; + return IPPROTO_NONE; + } + + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + + if (frpr_pullup(fin, sizeof(*frag)) == -1) + return IPPROTO_NONE; + hdr = fin->fin_dp; + + /* + * Length must be zero, i.e. it has no length. + */ + if (hdr->ip6e_len != 0) { + fin->fin_flx |= FI_BAD; + return IPPROTO_NONE; + } + + if ((int)(fin->fin_dlen - sizeof(*frag)) < 0) { + fin->fin_flx |= FI_SHORT; + return IPPROTO_NONE; + } + + frag = fin->fin_dp; + fin->fin_off = frag->ip6f_offlg & IP6F_OFF_MASK; + fin->fin_off <<= 3; + if (fin->fin_off != 0) + fin->fin_flx |= FI_FRAGBODY; + + fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag); + fin->fin_dlen -= sizeof(*frag); + + return frag->ip6f_nxt; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_dstopts6 */ +/* Returns: int - value of the next header or IPPROTO_NONE if error */ +/* Parameters: fin(I) - pointer to packet information */ +/* nextheader(I) - stores next header value */ +/* */ +/* IPv6 Only */ +/* This is function checks pending destination options extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_dstopts6(fin) +fr_info_t *fin; +{ + struct ip6_ext *hdr; + u_short shift; + int i; + + /* 8 is default length of extension hdr */ + if ((fin->fin_dlen - 8) < 0) { + fin->fin_flx |= FI_SHORT; + return IPPROTO_NONE; + } + + if (frpr_pullup(fin, 8) == -1) + return IPPROTO_NONE; + hdr = fin->fin_dp; + + shift = 8 + (hdr->ip6e_len << 3); + if (shift > fin->fin_dlen) { /* Nasty extension header length? */ + fin->fin_flx |= FI_BAD; + return IPPROTO_NONE; + } + + for (i = 0; ip6exthdr[i].ol_bit != 0; i++) + if (ip6exthdr[i].ol_val == IPPROTO_DSTOPTS) + break; + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + fin->fin_dp = (char *)fin->fin_dp + shift; + fin->fin_dlen -= shift; + + return hdr->ip6e_nxt; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_icmp6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This routine is mainly concerned with determining the minimum valid size */ +/* for an ICMPv6 packet. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_icmp6(fin) +fr_info_t *fin; +{ + int minicmpsz = sizeof(struct icmp6_hdr); + struct icmp6_hdr *icmp6; + + if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t)) == -1) + return; + + if (fin->fin_dlen > 1) { + icmp6 = fin->fin_dp; + + fin->fin_data[0] = *(u_short *)icmp6; + + switch (icmp6->icmp6_type) + { + case ICMP6_ECHO_REPLY : + case ICMP6_ECHO_REQUEST : + minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); + break; + case ICMP6_DST_UNREACH : + case ICMP6_PACKET_TOO_BIG : + case ICMP6_TIME_EXCEEDED : + case ICMP6_PARAM_PROB : + if ((fin->fin_m != NULL) && + (M_LEN(fin->fin_m) < fin->fin_plen)) { + if (fr_coalesce(fin) != 1) + return; } + fin->fin_flx |= FI_ICMPERR; + minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); + break; + default : + break; } + } - if (!(fin->fin_dlen >= minicmpsz)) - fi->fi_fl |= FI_SHORT; + frpr_short(fin, minicmpsz); +} - break; + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_udp6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Analyse the packet for IPv6/UDP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_udp6(fin) +fr_info_t *fin; +{ + + fr_checkv6sum(fin); + + frpr_short(fin, sizeof(struct udphdr)); + + frpr_udpcommon(fin); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_tcp6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Analyse the packet for IPv6/TCP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_tcp6(fin) +fr_info_t *fin; +{ + + fr_checkv6sum(fin); + + frpr_short(fin, sizeof(struct tcphdr)); + + frpr_tcpcommon(fin); +} +#endif /* USE_INET6 */ + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_pullup */ +/* Returns: int - 0 == pullup succeeded, -1 == failure */ +/* Parameters: fin(I) - pointer to packet information */ +/* plen(I) - length (excluding L3 header) to pullup */ +/* */ +/* Short inline function to cut down on code duplication to perform a call */ +/* to fr_pullup to ensure there is the required amount of data, */ +/* consecutively in the packet buffer. */ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_pullup(fin, plen) +fr_info_t *fin; +int plen; +{ +#if defined(_KERNEL) + if (fin->fin_m != NULL) { + if (fin->fin_dp != NULL) + plen += (char *)fin->fin_dp - + ((char *)fin->fin_ip + fin->fin_hlen); + plen += fin->fin_hlen; + if (M_LEN(fin->fin_m) < plen) { + if (fr_pullup(fin->fin_m, fin, plen) == NULL) + return -1; + } } -#endif /* USE_INET6 */ +#endif + return 0; +} - case IPPROTO_ICMP : - { - int minicmpsz = sizeof(struct icmp); - icmphdr_t *icmp; - if (!off && (fin->fin_dlen > 1) && !(fin->fin_fl & FI_SHORT)) { - fin->fin_data[0] = *(u_short *)tcp; +/* ------------------------------------------------------------------------ */ +/* Function: frpr_short */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* min(I) - minimum header size */ +/* */ +/* Check if a packet is "short" as defined by min. The rule we are */ +/* applying here is that the packet must not be fragmented within the layer */ +/* 4 header. That is, it must not be a fragment that has its offset set to */ +/* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ +/* entire layer 4 header must be present (min). */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_short(fin, min) +fr_info_t *fin; +int min; +{ + fr_ip_t *fi = &fin->fin_fi; + int off; - icmp = (icmphdr_t *)tcp; + off = fin->fin_off; + if (off == 0) { + if (fin->fin_plen < fin->fin_hlen + min) + fi->fi_flx |= FI_SHORT; + } else if (off < min) { + fi->fi_flx |= FI_SHORT; + } +} + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_icmp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ +/* except extrememly bad packets, both type and code will be present. */ +/* The expected minimum size of an ICMP packet is very much dependant on */ +/* the type of it. */ +/* */ +/* XXX - other ICMP sanity checks? */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_icmp(fin) +fr_info_t *fin; +{ + int minicmpsz = sizeof(struct icmp); + icmphdr_t *icmp; + + if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1) + return; + + fr_checkv4sum(fin); + + if (!fin->fin_off && (fin->fin_dlen > 1)) { + icmp = fin->fin_dp; + + fin->fin_data[0] = *(u_short *)icmp; + + switch (icmp->icmp_type) + { + case ICMP_ECHOREPLY : + case ICMP_ECHO : + /* Router discovery messaes - RFC 1256 */ + case ICMP_ROUTERADVERT : + case ICMP_ROUTERSOLICIT : + minicmpsz = ICMP_MINLEN; + break; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + + * 3 * timestamp(3 * 4) + */ + case ICMP_TSTAMP : + case ICMP_TSTAMPREPLY : + minicmpsz = 20; + break; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + + * mask(4) + */ + case ICMP_MASKREQ : + case ICMP_MASKREPLY : + minicmpsz = 12; + break; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) + */ + case ICMP_UNREACH : + case ICMP_SOURCEQUENCH : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_PARAMPROB : + if (fr_coalesce(fin) != 1) + return; + fin->fin_flx |= FI_ICMPERR; + break; + default : + break; + } + + if (fin->fin_dlen >= 6) /* ID field */ + fin->fin_data[1] = icmp->icmp_id; + } + + frpr_short(fin, minicmpsz); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_tcpcommon */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* TCP header sanity checking. Look for bad combinations of TCP flags, */ +/* and make some checks with how they interact with other fields. */ +/* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ +/* valid and mark the packet as bad if not. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_tcpcommon(fin) +fr_info_t *fin; +{ + int flags, tlen; + tcphdr_t *tcp; + fr_ip_t *fi; + + fi = &fin->fin_fi; + fi->fi_flx |= FI_TCPUDP; + if (fin->fin_off != 0) + return; + + if (frpr_pullup(fin, sizeof(*tcp)) == -1) + return; + tcp = fin->fin_dp; + + if (fin->fin_dlen > 3) { + fin->fin_sport = ntohs(tcp->th_sport); + fin->fin_dport = ntohs(tcp->th_dport); + } + + if ((fi->fi_flx & FI_SHORT) != 0) + return; + + /* + * Use of the TCP data offset *must* result in a value that is at + * least the same size as the TCP header. + */ + tlen = TCP_OFF(tcp) << 2; + if (tlen < sizeof(tcphdr_t)) { + fin->fin_flx |= FI_BAD; + return; + } + + flags = tcp->th_flags; + fin->fin_tcpf = tcp->th_flags; + + /* + * If the urgent flag is set, then the urgent pointer must + * also be set and vice versa. Good TCP packets do not have + * just one of these set. + */ + if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { + fin->fin_flx |= FI_BAD; + } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { + /* Ignore this case, it shows up in "real" traffic with */ + /* bogus values in the urgent pointer field. */ + ; + } else if (((flags & (TH_SYN|TH_FIN)) != 0) && + ((flags & (TH_RST|TH_ACK)) == TH_RST)) { + /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ + fin->fin_flx |= FI_BAD; + } else if (!(flags & TH_ACK)) { + /* + * If the ack bit isn't set, then either the SYN or + * RST bit must be set. If the SYN bit is set, then + * we expect the ACK field to be 0. If the ACK is + * not set and if URG, PSH or FIN are set, consdier + * that to indicate a bad TCP packet. + */ + if ((flags == TH_SYN) && (tcp->th_ack != 0)) { /* - * Minimum ICMP packet is type(1) code(1) cksum(2) - * plus 4 bytes following, totalling 8 bytes. - */ - switch (icmp->icmp_type) - { - case ICMP_ECHOREPLY : - case ICMP_ECHO : - /* Router discovery messages - RFC 1256 */ - case ICMP_ROUTERADVERT : - case ICMP_ROUTERSOLICIT : - minicmpsz = ICMP_MINLEN; - break; - /* - * type(1) + code(1) + cksum(2) + id(2) seq(2) + - * 3*timestamp(3*4) - */ - case ICMP_TSTAMP : - case ICMP_TSTAMPREPLY : - minicmpsz = ICMP_MINLEN + 12; - break; - /* - * type(1) + code(1) + cksum(2) + id(2) seq(2) + - * mask(4) + * Cisco PIX sets the ACK field to a random value. + * In light of this, do not set FI_BAD until a patch + * is available from Cisco to ensure that + * interoperability between existing systems is + * achieved. */ - case ICMP_MASKREQ : - case ICMP_MASKREPLY : - minicmpsz = ICMP_MINLEN + 4; + /*fin->fin_flx |= FI_BAD*/; + } else if (!(flags & (TH_RST|TH_SYN))) { + fin->fin_flx |= FI_BAD; + } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { + fin->fin_flx |= FI_BAD; + } + } + + /* + * At this point, it's not exactly clear what is to be gained by + * marking up which TCP options are and are not present. The one we + * are most interested in is the TCP window scale. This is only in + * a SYN packet [RFC1323] so we don't need this here...? + * Now if we were to analyse the header for passive fingerprinting, + * then that might add some weight to adding this... + */ + if (tlen == sizeof(tcphdr_t)) + return; + + if (frpr_pullup(fin, tlen) == -1) + return; + +#if 0 + ip = fin->fin_ip; + s = (u_char *)(tcp + 1); + off = IP_HL(ip) << 2; +# ifdef _KERNEL + if (fin->fin_mp != NULL) { + mb_t *m = *fin->fin_mp; + + if (off + tlen > M_LEN(m)) + return; + } +# endif + for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { + opt = *s; + if (opt == '\0') + break; + else if (opt == TCPOPT_NOP) + ol = 1; + else { + if (tlen < 2) break; - /* - * type(1) + code(1) + cksum(2) + arg(4) ip(20+) - */ - case ICMP_UNREACH : - case ICMP_SOURCEQUENCH : - case ICMP_REDIRECT : - case ICMP_TIMXCEED : - case ICMP_PARAMPROB : -#if defined(KERNEL) && !defined(__sgi) - if ((m != NULL) && (M_BLEN(m) < plen)) { - ip = ipf_pullup(m, fin, plen, ip); - if (ip == NULL) - return -1; - tcp = (tcphdr_t *)((char *)ip + hlen); - } -#endif /* KERNEL && !__sgi */ - minicmpsz = ICMPERR_MINPKTLEN - sizeof(ip_t); + ol = (int)*(s + 1); + if (ol < 2 || ol > tlen) break; - default : - minicmpsz = ICMP_MINLEN; + } + + for (i = 9, mv = 4; mv >= 0; ) { + op = ipopts + i; + if (opt == (u_char)op->ol_val) { + optmsk |= op->ol_bit; break; } } + tlen -= ol; + s += ol; + } +#endif /* 0 */ +} - if ((!(plen >= hlen + minicmpsz) && !off) || - (off && off < sizeof(struct icmp))) - fi->fi_fl |= FI_SHORT; - break; + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_udpcommon */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Extract the UDP source and destination ports, if present. If compiled */ +/* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_udpcommon(fin) +fr_info_t *fin; +{ + udphdr_t *udp; + fr_ip_t *fi; + + fi = &fin->fin_fi; + fi->fi_flx |= FI_TCPUDP; + + if (!fin->fin_off && (fin->fin_dlen > 3)) { + if (frpr_pullup(fin, sizeof(*udp)) == -1) { + fi->fi_flx |= FI_SHORT; + return; + } + + udp = fin->fin_dp; + + fin->fin_sport = ntohs(udp->uh_sport); + fin->fin_dport = ntohs(udp->uh_dport); } +} - case IPPROTO_TCP : - fi->fi_fl |= FI_TCPUDP; -#ifdef USE_INET6 - if (v == 6) { - if (plen < sizeof(struct tcphdr)) - fi->fi_fl |= FI_SHORT; - } else + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_tcp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Analyse the packet for IPv4/TCP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_tcp(fin) +fr_info_t *fin; +{ + + fr_checkv4sum(fin); + + frpr_short(fin, sizeof(tcphdr_t)); + + frpr_tcpcommon(fin); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_udp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Analyse the packet for IPv4/UDP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_udp(fin) +fr_info_t *fin; +{ + + fr_checkv4sum(fin); + + frpr_short(fin, sizeof(udphdr_t)); + + frpr_udpcommon(fin); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_esp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Analyse the packet for ESP properties. */ +/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ +/* even though the newer ESP packets must also have a sequence number that */ +/* is 32bits as well, it is not possible(?) to determine the version from a */ +/* simple packet header. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_esp(fin) +fr_info_t *fin; +{ + if (frpr_pullup(fin, 8) == -1) + return; + + if (fin->fin_v == 4) + frpr_short(fin, 8); +#ifdef USE_INET6 + else if (fin->fin_v == 6) + frpr_short6(fin, sizeof(grehdr_t)); #endif - if (v == 4) { - if ((!IPMINLEN(ip, tcphdr) && !off) || - (off && off < sizeof(struct tcphdr))) - fi->fi_fl |= FI_SHORT; - } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_gre */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Analyse the packet for GRE properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_gre(fin) +fr_info_t *fin; +{ + grehdr_t *gre; + + if (frpr_pullup(fin, sizeof(grehdr_t)) == -1) + return; + + if (fin->fin_v == 4) + frpr_short(fin, sizeof(grehdr_t)); +#ifdef USE_INET6 + else if (fin->fin_v == 6) + frpr_short6(fin, sizeof(grehdr_t)); +#endif + gre = fin->fin_dp; + if (GRE_REV(gre->gr_flags) == 1) + fin->fin_data[0] = gre->gr_call; +} -#if defined(KERNEL) && !defined(__sgi) - if (!off && !(fi->fi_fl & FI_SHORT)) { - int tlen = hlen + (tcp->th_off << 2); - if ((m != NULL) && (M_BLEN(m) < tlen)) { - ip = ipf_pullup(m, fin, tlen, ip); - if (ip == NULL) - return -1; - tcp = (tcphdr_t *)((char *)ip + hlen); +/* ------------------------------------------------------------------------ */ +/* Function: frpr_ipv4hdr */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Analyze the IPv4 header and set fields in the fr_info_t structure. */ +/* Check all options present and flag their presence if any exist. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_ipv4hdr(fin) +fr_info_t *fin; +{ + u_short optmsk = 0, secmsk = 0, auth = 0; + int hlen, ol, mv, p, i; + const struct optlist *op; + u_char *s, opt; + u_short off; + fr_ip_t *fi; + ip_t *ip; + + fi = &fin->fin_fi; + hlen = fin->fin_hlen; + + ip = fin->fin_ip; + p = ip->ip_p; + fi->fi_p = p; + fi->fi_tos = ip->ip_tos; + fin->fin_id = ip->ip_id; + off = ip->ip_off; + + /* Get both TTL and protocol */ + fi->fi_p = ip->ip_p; + fi->fi_ttl = ip->ip_ttl; +#if 0 + (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); +#endif + + /* Zero out bits not used in IPv6 address */ + 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; + + /* + * set packet attribute flags based on the offset and + * calculate the byte offset that it represents. + */ + if ((off & IP_MF) != 0) { + fi->fi_flx |= FI_FRAG; + if (fin->fin_dlen == 0) + fi->fi_flx |= FI_BAD; + } + + off &= IP_MF|IP_OFFMASK; + if (off != 0) { + fi->fi_flx |= FI_FRAG; + off &= IP_OFFMASK; + if (off != 0) { + fin->fin_flx |= FI_FRAGBODY; + off <<= 3; + if (off + fin->fin_dlen > 0xffff) { + fi->fi_flx |= FI_BAD; } } -#endif /* _KERNEL && !_sgi */ + } + fin->fin_off = off; - if (!(fi->fi_fl & FI_SHORT) && !off) - fin->fin_tcpf = tcp->th_flags; - goto getports; + /* + * Call per-protocol setup and checking + */ + switch (p) + { case IPPROTO_UDP : - fi->fi_fl |= FI_TCPUDP; -#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); - fin->fin_data[1] = ntohs(tcp->th_dport); - } + frpr_udp(fin); + break; + case IPPROTO_TCP : + frpr_tcp(fin); + break; + case IPPROTO_ICMP : + frpr_icmp(fin); break; case IPPROTO_ESP : -#ifdef USE_INET6 - if (v == 6) { - if (plen < 8) - fi->fi_fl |= FI_SHORT; - } else -#endif - if (v == 4) { - if (((ip->ip_len < hlen + 8) && !off) || - (off && off < 8)) - fi->fi_fl |= FI_SHORT; - } + frpr_esp(fin); break; - default : + case IPPROTO_GRE : + frpr_gre(fin); break; } - fin->fin_dp = (char *)tcp; + ip = fin->fin_ip; + if (ip == NULL) + return; -#ifdef USE_INET6 - if (v == 6) { + /* + * If it is a standard IP header (no options), set the flag fields + * which relate to options to 0. + */ + if (hlen == sizeof(*ip)) { fi->fi_optmsk = 0; fi->fi_secmsk = 0; fi->fi_auth = 0; - return 0; + return; } -#endif + + /* + * So the IP header has some IP options attached. Walk the entire + * list of options present with this packet and set flags to indicate + * which ones are here and which ones are not. For the somewhat out + * of date and obscure security classification options, set a flag to + * represent which classification is present. + */ + fi->fi_flx |= FI_OPTIONS; for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { opt = *s; @@ -495,10 +1338,10 @@ getports: } for (i = 9, mv = 4; mv >= 0; ) { op = ipopts + i; - if (opt == (u_char)op->ol_val) { + if ((opt == (u_char)op->ol_val) && (ol > 4)) { optmsk |= op->ol_bit; if (opt == IPOPT_SECURITY) { - struct optlist *sp; + const struct optlist *sp; u_char sec; int j, m; @@ -513,98 +1356,174 @@ getports: break; } if (sec < sp->ol_val) - j -= m--; + j -= m; else - j += m--; + j += m; + m--; } } break; } if (opt < op->ol_val) - i -= mv--; + i -= mv; else - i += mv--; + i += mv; + mv--; } hlen -= ol; s += ol; } + + /* + * + */ if (auth && !(auth & 0x0100)) auth &= 0xff00; fi->fi_optmsk = optmsk; fi->fi_secmsk = secmsk; fi->fi_auth = auth; - return 0; } -/* - * check an IP packet for TCP/UDP characteristics such as ports and flags. - */ -int fr_tcpudpchk(ft, fin) -frtuc_t *ft; +/* ------------------------------------------------------------------------ */ +/* Function: fr_makefrip */ +/* Returns: void */ +/* Parameters: hlen(I) - length of IP packet header */ +/* ip(I) - pointer to the IP header */ +/* fin(IO) - pointer to packet information */ +/* */ +/* Compact the IP header into a structure which contains just the info. */ +/* which is useful for comparing IP headers with and store this information */ +/* in the fr_info_t structure pointer to by fin. At present, it is assumed */ +/* this function will be called with either an IPv4 or IPv6 packet. */ +/* ------------------------------------------------------------------------ */ +int fr_makefrip(hlen, ip, fin) +int hlen; +ip_t *ip; fr_info_t *fin; { - register u_short po, tup; - register char i; - register int err = 1; + int v; + + fin->fin_nat = NULL; + fin->fin_state = NULL; + fin->fin_depth = 0; + fin->fin_hlen = (u_short)hlen; + fin->fin_ip = ip; + fin->fin_rule = 0xffffffff; + fin->fin_group[0] = -1; + fin->fin_group[1] = '\0'; + fin->fin_dlen = fin->fin_plen - hlen; + fin->fin_dp = (char *)ip + hlen; + + v = fin->fin_v; + if (v == 4) + frpr_ipv4hdr(fin); +#ifdef USE_INET6 + else if (v == 6) + frpr_ipv6hdr(fin); +#endif + if (fin->fin_ip == NULL) + return -1; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_portcheck */ +/* Returns: int - 1 == port matched, 0 == port match failed */ +/* Parameters: frp(I) - pointer to port check `expression' */ +/* pop(I) - pointer to port number to evaluate */ +/* */ +/* Perform a comparison of a port number against some other(s), using a */ +/* structure with compare information stored in it. */ +/* ------------------------------------------------------------------------ */ +static INLINE int fr_portcheck(frp, pop) +frpcmp_t *frp; +u_short *pop; +{ + u_short tup, po; + int err = 1; + + tup = *pop; + po = frp->frp_port; /* - * Both ports should *always* be in the first fragment. - * So far, I cannot find any cases where they can not be. - * - * compare destination ports + * Do opposite test to that required and continue if that succeeds. */ - if ((i = (int)ft->ftu_dcmp)) { - po = ft->ftu_dport; - tup = fin->fin_data[1]; - /* - * Do opposite test to that required and - * continue if that succeeds. - */ - if (!--i && tup != po) /* EQUAL */ + switch (frp->frp_cmp) + { + case FR_EQUAL : + if (tup != po) /* EQUAL */ err = 0; - else if (!--i && tup == po) /* NOTEQUAL */ + break; + case FR_NEQUAL : + if (tup == po) /* NOTEQUAL */ err = 0; - else if (!--i && tup >= po) /* LESSTHAN */ + break; + case FR_LESST : + if (tup >= po) /* LESSTHAN */ + err = 0; + break; + case FR_GREATERT : + if (tup <= po) /* GREATERTHAN */ err = 0; - else if (!--i && tup <= po) /* GREATERTHAN */ + break; + case FR_LESSTE : + if (tup > po) /* LT or EQ */ err = 0; - else if (!--i && tup > po) /* LT or EQ */ + break; + case FR_GREATERTE : + if (tup < po) /* GT or EQ */ err = 0; - else if (!--i && tup < po) /* GT or EQ */ + break; + case FR_OUTRANGE : + if (tup >= po && tup <= frp->frp_top) /* Out of range */ err = 0; - else if (!--i && /* Out of range */ - (tup >= po && tup <= ft->ftu_dtop)) + break; + case FR_INRANGE : + if (tup <= po || tup >= frp->frp_top) /* In range */ err = 0; - else if (!--i && /* In range */ - (tup <= po || tup >= ft->ftu_dtop)) + break; + case FR_INCRANGE : + if (tup < po || tup > frp->frp_top) /* Inclusive range */ err = 0; + break; + default : + break; } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpudpchk */ +/* Returns: int - 1 == protocol matched, 0 == check failed */ +/* Parameters: fin(I) - pointer to packet information */ +/* ft(I) - pointer to structure with comparison data */ +/* */ +/* Compares the current pcket (assuming it is TCP/UDP) information with a */ +/* structure containing information that we want to match against. */ +/* ------------------------------------------------------------------------ */ +int fr_tcpudpchk(fin, ft) +fr_info_t *fin; +frtuc_t *ft; +{ + int err = 1; + + /* + * Both ports should *always* be in the first fragment. + * So far, I cannot find any cases where they can not be. + * + * compare destination ports + */ + if (ft->ftu_dcmp) + err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport); + /* * compare source ports */ - if (err && (i = (int)ft->ftu_scmp)) { - po = ft->ftu_sport; - tup = fin->fin_data[0]; - if (!--i && tup != po) - err = 0; - else if (!--i && tup == po) - err = 0; - else if (!--i && tup >= po) - err = 0; - else if (!--i && tup <= po) - err = 0; - else if (!--i && tup > po) - err = 0; - else if (!--i && tup < po) - err = 0; - else if (!--i && /* Out of range */ - (tup >= po && tup <= ft->ftu_stop)) - err = 0; - else if (!--i && /* In range */ - (tup <= po || tup >= ft->ftu_stop)) - err = 0; - } + if (err && ft->ftu_scmp) + err = fr_portcheck(&ft->ftu_src, &fin->fin_sport); /* * If we don't have all the TCP/UDP header, then how can we @@ -612,8 +1531,8 @@ fr_info_t *fin; * TCP flags, then NO match. If not, then match (which should * satisfy the "short" class too). */ - if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { - if (fin->fin_fl & FI_SHORT) + if (err && (fin->fin_p == IPPROTO_TCP)) { + if (fin->fin_flx & FI_SHORT) return !(ft->ftu_tcpf | ft->ftu_tcpfm); /* * Match the flags ? If not, abort this match. @@ -628,38 +1547,246 @@ fr_info_t *fin; return err; } -/* - * Check the input/output list of rules for a match and result. - * Could be per interface, but this gets real nasty when you don't have - * kernel sauce. - */ -int fr_scanlist(passin, ip, fin, m) -u_32_t passin; -ip_t *ip; -register fr_info_t *fin; -void *m; + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipfcheck */ +/* Returns: int - 0 == match, 1 == no match */ +/* Parameters: fin(I) - pointer to packet information */ +/* fr(I) - pointer to filter rule */ +/* portcmp(I) - flag indicating whether to attempt matching on */ +/* TCP/UDP port data. */ +/* */ +/* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ +/* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ +/* this function. */ +/* ------------------------------------------------------------------------ */ +static INLINE int fr_ipfcheck(fin, fr, portcmp) +fr_info_t *fin; +frentry_t *fr; +int portcmp; +{ + u_32_t *ld, *lm, *lip; + fripf_t *fri; + fr_ip_t *fi; + int i; + + fi = &fin->fin_fi; + fri = fr->fr_ipf; + lip = (u_32_t *)fi; + lm = (u_32_t *)&fri->fri_mip; + ld = (u_32_t *)&fri->fri_ip; + + /* + * first 32 bits to check coversion: + * IP version, TOS, TTL, protocol + */ + i = ((*lip & *lm) != *ld); + FR_DEBUG(("0. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + return 1; + + /* + * Next 32 bits is a constructed bitmask indicating which IP options + * are present (if any) in this packet. + */ + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("1. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + return 1; + + lip++, lm++, ld++; + /* + * Unrolled loops (4 each, for 32 bits) for address checks. + */ + /* + * Check the source address. + */ +#ifdef IPFILTER_LOOKUP + if (fr->fr_satype == FRI_LOOKUP) { + i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip); + if (i == -1) + return 1; + lip += 3; + lm += 3; + ld += 3; + } else { +#endif + i = ((*lip & *lm) != *ld); + FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } +#ifdef IPFILTER_LOOKUP + } +#endif + i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; + if (i) + return 1; + + /* + * Check the destination address. + */ + lip++, lm++, ld++; +#ifdef IPFILTER_LOOKUP + if (fr->fr_datype == FRI_LOOKUP) { + i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip); + if (i == -1) + return 1; + lip += 3; + lm += 3; + ld += 3; + } else { +#endif + i = ((*lip & *lm) != *ld); + FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } +#ifdef IPFILTER_LOOKUP + } +#endif + i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; + if (i) + return 1; + /* + * IP addresses matched. The next 32bits contains: + * mast of old IP header security & authentication bits. + */ + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("4. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + + /* + * Next we have 32 bits of packet flags. + */ + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("5. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + + if (i == 0) { + /* + * If a fragment, then only the first has what we're + * looking for here... + */ + if (portcmp) { + if (!fr_tcpudpchk(fin, &fr->fr_tuc)) + i = 1; + } else { + if (fr->fr_dcmp || fr->fr_scmp || + fr->fr_tcpf || fr->fr_tcpfm) + i = 1; + if (fr->fr_icmpm || fr->fr_icmp) { + if (((fi->fi_p != IPPROTO_ICMP) && + (fi->fi_p != IPPROTO_ICMPV6)) || + fin->fin_off || (fin->fin_dlen < 2)) + i = 1; + else if ((fin->fin_data[0] & fr->fr_icmpm) != + fr->fr_icmp) { + FR_DEBUG(("i. %#x & %#x != %#x\n", + fin->fin_data[0], + fr->fr_icmpm, fr->fr_icmp)); + i = 1; + } + } + } + } + return i; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_scanlist */ +/* Returns: int - result flags of scanning filter list */ +/* Parameters: fin(I) - pointer to packet information */ +/* pass(I) - default result to return for filtering */ +/* */ +/* Check the input/output list of rules for a match to the current packet. */ +/* If a match is found, the value of fr_flags from the rule becomes the */ +/* return value and fin->fin_fr points to the matched rule. */ +/* */ +/* This function may be called recusively upto 16 times (limit inbuilt.) */ +/* When unwinding, it should finish up with fin_depth as 0. */ +/* */ +/* Could be per interface, but this gets real nasty when you don't have, */ +/* or can't easily change, the kernel source code to . */ +/* ------------------------------------------------------------------------ */ +int fr_scanlist(fin, pass) +fr_info_t *fin; +u_32_t pass; { - register struct frentry *fr; - register fr_ip_t *fi = &fin->fin_fi; - int rulen, portcmp = 0, off, skip = 0, logged = 0; - u_32_t pass, passt, passl; - frentry_t *frl; + int rulen, portcmp, off, logged, skip; + struct frentry *fr, *fnext; + u_32_t passt; + + /* + * Do not allow nesting deeper than 16 levels. + */ + if (fin->fin_depth >= 16) + return pass; - frl = NULL; - pass = passin; fr = fin->fin_fr; + + /* + * If there are no rules in this list, return now. + */ + if (fr == NULL) + return pass; + + skip = 0; + logged = 0; + portcmp = 0; + fin->fin_depth++; fin->fin_fr = NULL; off = fin->fin_off; - if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) + if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) portcmp = 1; - for (rulen = 0; fr; fr = fr->fr_next, rulen++) { - if (skip) { + for (rulen = 0; fr; fr = fnext, rulen++) { + fnext = fr->fr_next; + if (skip != 0) { FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags)); skip--; continue; } + /* * In all checks below, a null (zero) value in the * filter struture is taken to mean a wildcard. @@ -667,198 +1794,376 @@ void *m; * check that we are working for the right interface */ #ifdef _KERNEL -# if (BSD >= 199306) - if (fin->fin_out != 0) { - if ((fr->fr_oifa && - (fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif))) - continue; - } -# endif + if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) + continue; #else if (opts & (OPT_VERBOSE|OPT_DEBUG)) printf("\n"); -#endif - - FR_VERBOSE(("%c", fr->fr_skip ? 's' : - (pass & FR_PASS) ? 'p' : - (pass & FR_AUTH) ? 'a' : - (pass & FR_ACCOUNT) ? 'A' : - (pass & FR_NOMATCH) ? 'n' : 'b')); - + FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : + FR_ISPASS(pass) ? 'p' : + FR_ISACCOUNT(pass) ? 'A' : + FR_ISAUTH(pass) ? 'a' : + (pass & FR_NOMATCH) ? 'n' :'b')); if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) continue; - FR_VERBOSE((":i")); +#endif + + switch (fr->fr_type) { - register u_32_t *ld, *lm, *lip; - register int i; - - lip = (u_32_t *)fi; - lm = (u_32_t *)&fr->fr_mip; - ld = (u_32_t *)&fr->fr_ip; - i = ((*lip & *lm) != *ld); - FR_DEBUG(("0. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - if (i) + case FR_T_IPF : + case FR_T_IPF|FR_T_BUILTIN : + if (fr_ipfcheck(fin, fr, portcmp)) 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). - */ - FR_DEBUG(("1a. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - if (fi->fi_v == 6) { - FR_DEBUG(("1b. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - FR_DEBUG(("1c. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - FR_DEBUG(("1d. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - } else { - lip += 3; - lm += 3; - ld += 3; - } - i ^= (fr->fr_flags & FR_NOTSRCIP); - if (i) + break; +#if defined(IPFILTER_BPF) + case FR_T_BPFOPC : + case FR_T_BPFOPC|FR_T_BUILTIN : + { + u_char *mc; + int wlen; + + if (*fin->fin_mp == NULL) continue; - FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - if (fi->fi_v == 6) { - FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - } else { - lip += 3; - lm += 3; - ld += 3; - } - i ^= (fr->fr_flags & FR_NOTDSTIP); - if (i) + if (fin->fin_v != fr->fr_v) continue; - FR_DEBUG(("3. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++); - FR_DEBUG(("4. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip & *lm) != *ld); - if (i) + mc = (u_char *)fin->fin_m; + wlen = fin->fin_dlen + fin->fin_hlen; + if (!bpf_filter(fr->fr_data, mc, wlen, 0)) continue; - } + break; + } +#endif + case FR_T_CALLFUNC|FR_T_BUILTIN : + { + frentry_t *f; - /* - * If a fragment, then only the first has what we're looking - * for here... - */ - if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf || - fr->fr_tcpfm)) - continue; - if (fi->fi_fl & FI_TCPUDP) { - if (!fr_tcpudpchk(&fr->fr_tuc, fin)) + f = (*fr->fr_func)(fin, &pass); + if (f != NULL) + fr = f; + else continue; - } else if (fr->fr_icmpm || fr->fr_icmp) { - if (((fi->fi_p != IPPROTO_ICMP) && - (fi->fi_p != IPPROTO_ICMPV6)) || off || - (fin->fin_dlen < 2)) + break; + } + default : + break; + } + + if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { + if (fin->fin_nattag == NULL) continue; - if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) { - FR_DEBUG(("i. %#x & %#x != %#x\n", - fin->fin_data[0], fr->fr_icmpm, - fr->fr_icmp)); + if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) continue; - } } - FR_VERBOSE(("*")); + FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen)); - if (fr->fr_flags & FR_NOMATCH) { - passt = passl; - passl = passin; - fin->fin_fr = frl; - frl = NULL; - if (fr->fr_flags & FR_QUICK) - break; + passt = fr->fr_flags; + + /* + * Allowing a rule with the "keep state" flag set to match + * packets that have been tagged "out of window" by the TCP + * state tracking is foolish as the attempt to add a new + * state entry to the table will fail. + */ + if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW)) continue; + + /* + * If the rule is a "call now" rule, then call the function + * in the rule, if it exists and use the results from that. + * If the function pointer is bad, just make like we ignore + * it, except for increasing the hit counter. + */ + if ((passt & FR_CALLNOW) != 0) { + ATOMIC_INC64(fr->fr_hits); + if ((fr->fr_func != NULL) && + (fr->fr_func != (ipfunc_t)-1)) { + frentry_t *frs; + + frs = fin->fin_fr; + fin->fin_fr = fr; + fr = (*fr->fr_func)(fin, &passt); + if (fr == NULL) { + fin->fin_fr = frs; + continue; + } + passt = fr->fr_flags; + fin->fin_fr = fr; + } + } else { + fin->fin_fr = fr; } - passl = passt; - passt = fr->fr_flags; - frl = fin->fin_fr; - fin->fin_fr = fr; -#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL)) - if (securelevel <= 0) -#endif - if ((passt & FR_CALLNOW) && fr->fr_func) - passt = (*fr->fr_func)(passt, ip, fin); #ifdef IPFILTER_LOG /* * Just log this packet... */ if ((passt & FR_LOGMASK) == FR_LOG) { - if (!IPLLOG(passt, ip, fin, m)) { - if (passt & FR_LOGORBLOCK) + if (ipflog(fin, passt) == -1) { + if (passt & FR_LOGORBLOCK) { + passt &= ~FR_CMDMASK; passt |= FR_BLOCK|FR_QUICK; + } ATOMIC_INCL(frstats[fin->fin_out].fr_skip); } ATOMIC_INCL(frstats[fin->fin_out].fr_pkl); logged = 1; } #endif /* IPFILTER_LOG */ - ATOMIC_INCL(fr->fr_hits); - if (passt & FR_ACCOUNT) - fr->fr_bytes += (U_QUAD_T)fin->fin_plen; - else + fr->fr_bytes += (U_QUAD_T)fin->fin_plen; + if (FR_ISSKIP(passt)) + skip = fr->fr_arg; + else if ((passt & FR_LOGMASK) != FR_LOG) + pass = passt; + if (passt & (FR_RETICMP|FR_FAKEICMP)) fin->fin_icode = fr->fr_icode; + FR_DEBUG(("pass %#x\n", pass)); + ATOMIC_INC64(fr->fr_hits); fin->fin_rule = rulen; - fin->fin_group = fr->fr_group; + (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN); if (fr->fr_grp != NULL) { - fin->fin_fr = fr->fr_grp; - passt = fr_scanlist(passt, ip, fin, m); + fin->fin_fr = *fr->fr_grp; + pass = fr_scanlist(fin, pass); if (fin->fin_fr == NULL) { fin->fin_rule = rulen; - fin->fin_group = fr->fr_group; + (void) strncpy(fin->fin_group, fr->fr_group, + FR_GROUPLEN); fin->fin_fr = fr; } - if (passt & FR_DONTCACHE) + if (fin->fin_flx & FI_DONTCACHE) logged = 1; } - if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG) - pass = passt; - FR_DEBUG(("pass %#x\n", pass)); - if (passt & FR_QUICK) + if (pass & FR_QUICK) break; } if (logged) - pass |= FR_DONTCACHE; - pass |= (fi->fi_fl << 24); + fin->fin_flx |= FI_DONTCACHE; + fin->fin_depth--; return pass; } -/* - * frcheck - filter check - * check using source and destination addresses/ports in a packet whether - * or not to pass it on or not. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_acctpkt */ +/* Returns: frentry_t* - always returns NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Checks a packet against accounting rules, if there are any for the given */ +/* IP protocol version. */ +/* */ +/* N.B.: this function returns NULL to match the prototype used by other */ +/* functions called from the IPFilter "mainline" in fr_check(). */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_acctpkt(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + char group[FR_GROUPLEN]; + frentry_t *fr, *frsave; + u_32_t pass, rulen; + + passp = passp; +#ifdef USE_INET6 + if (fin->fin_v == 6) + fr = ipacct6[fin->fin_out][fr_active]; + else +#endif + fr = ipacct[fin->fin_out][fr_active]; + + if (fr != NULL) { + frsave = fin->fin_fr; + bcopy(fin->fin_group, group, FR_GROUPLEN); + rulen = fin->fin_rule; + fin->fin_fr = fr; + pass = fr_scanlist(fin, FR_NOMATCH); + if (FR_ISACCOUNT(pass)) { + ATOMIC_INCL(frstats[0].fr_acct); + } + fin->fin_fr = frsave; + bcopy(group, fin->fin_group, FR_GROUPLEN); + fin->fin_rule = rulen; + } + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_firewall */ +/* Returns: frentry_t* - returns pointer to matched rule, if no matches */ +/* were found, returns NULL. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Applies an appropriate set of firewall rules to the packet, to see if */ +/* there are any matches. The first check is to see if a match can be seen */ +/* in the cache. If not, then search an appropriate list of rules. Once a */ +/* matching rule is found, take any appropriate actions as defined by the */ +/* rule - except logging. */ +/* ------------------------------------------------------------------------ */ +static frentry_t *fr_firewall(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + frentry_t *fr; + fr_info_t *fc; + u_32_t pass; + int out; + + out = fin->fin_out; + pass = *passp; + + /* + * If a packet is found in the auth table, then skip checking + * the access lists for permission but we do need to consider + * the result as if it were from the ACL's. + */ + fc = &frcache[out][CACHE_HASH(fin)]; + if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { + /* + * copy cached data so we can unlock the mutex + * earlier. + */ + bcopy((char *)fc, (char *)fin, FI_COPYSIZE); + ATOMIC_INCL(frstats[out].fr_chit); + if ((fr = fin->fin_fr) != NULL) { + ATOMIC_INC64(fr->fr_hits); + pass = fr->fr_flags; + } + } else { +#ifdef USE_INET6 + if (fin->fin_v == 6) + fin->fin_fr = ipfilter6[out][fr_active]; + else +#endif + fin->fin_fr = ipfilter[out][fr_active]; + if (fin->fin_fr != NULL) + pass = fr_scanlist(fin, fr_pass); + if (((pass & FR_KEEPSTATE) == 0) && + ((fin->fin_flx & FI_DONTCACHE) == 0)) + bcopy((char *)fin, (char *)fc, FI_COPYSIZE); + if ((pass & FR_NOMATCH)) { + ATOMIC_INCL(frstats[out].fr_nom); + } + fr = fin->fin_fr; + } + + /* + * Apply packets per second rate-limiting to a rule as required. + */ + if ((fr != NULL) && (fr->fr_pps != 0) && + !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { + pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST); + pass |= FR_BLOCK; + ATOMIC_INCL(frstats[out].fr_ppshit); + } + + /* + * If we fail to add a packet to the authorization queue, then we + * drop the packet later. However, if it was added then pretend + * we've dropped it already. + */ + if (FR_ISAUTH(pass)) { + if (fr_newauth(fin->fin_m, fin) != 0) { +#ifdef _KERNEL + fin->fin_m = *fin->fin_mp = NULL; +#else + ; +#endif + fin->fin_error = 0; + } else + fin->fin_error = ENOSPC; + } + + if ((fr != NULL) && (fr->fr_func != NULL) && + (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) + (void) (*fr->fr_func)(fin, &pass); + + /* + * If a rule is a pre-auth rule, check again in the list of rules + * loaded for authenticated use. It does not particulary matter + * if this search fails because a "preauth" result, from a rule, + * is treated as "not a pass", hence the packet is blocked. + */ + if (FR_ISPREAUTH(pass)) { + if ((fin->fin_fr = ipauth) != NULL) + pass = fr_scanlist(fin, fr_pass); + } + + /* + * If the rule has "keep frag" and the packet is actually a fragment, + * then create a fragment state entry. + */ + if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { + if (fin->fin_flx & FI_FRAG) { + if (fr_newfrag(fin, pass) == -1) { + ATOMIC_INCL(frstats[out].fr_bnfr); + } else { + ATOMIC_INCL(frstats[out].fr_nfr); + } + } else { + ATOMIC_INCL(frstats[out].fr_cfr); + } + } + + /* + * Finally, if we've asked to track state for this packet, set it up. + */ + if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) { + if (fr_addstate(fin, NULL, 0) != NULL) { + ATOMIC_INCL(frstats[out].fr_ads); + } else { + ATOMIC_INCL(frstats[out].fr_bads); + if (FR_ISPASS(pass)) { + pass &= ~FR_CMDMASK; + pass |= FR_BLOCK; + } + } + } + + fr = fin->fin_fr; + + if (passp != NULL) + *passp = pass; + + return fr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_check */ +/* Returns: int - 0 == packet allowed through, */ +/* User space: */ +/* -1 == packet blocked */ +/* 1 == packet not matched */ +/* -2 == requires authantication */ +/* Kernel: */ +/* > 0 == filter error # for packet */ +/* Parameters: ip(I) - pointer to start of IPv4/6 packet */ +/* hlen(I) - length of header */ +/* ifp(I) - pointer to interface this packet is on */ +/* out(I) - 0 == packet going in, 1 == packet going out */ +/* mp(IO) - pointer to caller's buffer pointer that holds this */ +/* IP packet. */ +/* Solaris & HP-UX ONLY : */ +/* qpi(I) - pointer to STREAMS queue information for this */ +/* interface & direction. */ +/* */ +/* fr_check() is the master function for all IPFilter packet processing. */ +/* It orchestrates: Network Address Translation (NAT), checking for packet */ +/* authorisation (or pre-authorisation), presence of related state info., */ +/* generating log entries, IP packet accounting, routing of packets as */ +/* directed by firewall rules and of course whether or not to allow the */ +/* packet to be further processed by the kernel. */ +/* */ +/* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ +/* freed. Packets passed may be returned with the pointer pointed to by */ +/* by "mp" changed to a new buffer. */ +/* ------------------------------------------------------------------------ */ int fr_check(ip, hlen, ifp, out -#if defined(_KERNEL) && SOLARIS +#if defined(_KERNEL) && defined(MENTAT) , qif, mp) -qif_t *qif; +void *qif; #else , mp) #endif @@ -871,49 +2176,59 @@ int out; /* * The above really sucks, but short of writing a diff */ - fr_info_t frinfo, *fc; - register fr_info_t *fin = &frinfo; - 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; + fr_info_t frinfo; + fr_info_t *fin = &frinfo; + u_32_t pass = fr_pass; + frentry_t *fr = NULL; + int v = IP_V(ip); + mb_t *mc = NULL; + mb_t *m; +#ifdef USE_INET6 + ip6_t *ip6; #endif -#ifdef _KERNEL - int p, len, drop = 0, logit = 0; - mb_t *mc = NULL; -# if !defined(__SVR4) && !defined(__svr4__) /* - * We don't do this section for Solaris because fr_precheck() does a - * pullupmsg() instead, effectively achieving the same result as here - * so no need to duplicate it. + * The first part of fr_check() deals with making sure that what goes + * into the filtering engine makes some sense. Information about the + * the packet is distilled, collected into a fr_info_t structure and + * the an attempt to ensure the buffer the packet is in is big enough + * to hold all the required packet headers. */ -# ifdef __sgi - char hbuf[128]; -# endif - int up; - -# if !defined(NETBSD_PF) && \ - ((defined(__FreeBSD__) && (__FreeBSD_version < 500011)) || \ - defined(__OpenBSD__) || defined(_BSDI_VERSION)) - if (fr_checkp != fr_check && fr_running > 0) { - static int counter = 0; - - if (counter == 0) { - printf("WARNING: fr_checkp corrupt: value %lx\n", - (u_long)fr_checkp); - printf("WARNING: fr_checkp should be %lx\n", - (u_long)fr_check); - printf("WARNING: fixing fr_checkp\n"); - } - fr_checkp = fr_check; - counter++; - if (counter == 10000) - counter = 0; +#ifdef _KERNEL +# ifdef MENTAT + qpktinfo_t *qpi = qif; + + if ((u_int)ip & 0x3) + return 2; +# endif + + READ_ENTER(&ipf_global); + + if (fr_running <= 0) { + RWLOCK_EXIT(&ipf_global); + return 0; } -# endif + bzero((char *)fin, sizeof(*fin)); + +# ifdef MENTAT + if (qpi->qpi_flags & QF_GROUP) + fin->fin_flx |= FI_MBCAST; + m = qpi->qpi_m; + fin->fin_qfm = m; + fin->fin_qpi = qpi; +# else /* MENTAT */ + + m = *mp; + +# if defined(M_MCAST) + if ((m->m_flags & M_MCAST) != 0) + fin->fin_flx |= FI_MBCAST|FI_MULTICAST; +# endif +# if defined(M_BCAST) + if ((m->m_flags & M_BCAST) != 0) + fin->fin_flx |= FI_MBCAST|FI_BROADCAST; +# endif # ifdef M_CANFASTFWD /* * XXX For now, IP Filter and fast-forwarding of cached flows @@ -926,179 +2241,91 @@ int out; /* * disable delayed checksums. */ - if ((out != 0) && (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)) { + 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 */ +# endif /* MENTAT */ +#else + READ_ENTER(&ipf_global); -# ifdef USE_INET6 - if (v == 6) { - len = ntohs(((ip6_t*)ip)->ip6_plen); - if (!len) - return -1; /* potential jumbo gram */ - len += sizeof(ip6_t); - p = ((ip6_t *)ip)->ip6_nxt; - } else -# endif - { - p = ip->ip_p; - len = ip->ip_len; - } + bzero((char *)fin, sizeof(*fin)); + m = *mp; +#endif /* _KERNEL */ + fin->fin_v = v; + fin->fin_m = m; + fin->fin_ip = ip; fin->fin_mp = mp; fin->fin_out = out; + fin->fin_ifp = ifp; + fin->fin_error = ENETUNREACH; + fin->fin_hlen = (u_short )hlen; + fin->fin_dp = (char *)ip + hlen; - if ((p == IPPROTO_TCP || p == IPPROTO_UDP || - (v == 4 && p == IPPROTO_ICMP) -# ifdef USE_INET6 - || (v == 6 && p == IPPROTO_ICMPV6) -# endif - )) { - int plen = 0; - - if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0) - switch(p) - { - case IPPROTO_TCP: - plen = sizeof(tcphdr_t); - break; - case IPPROTO_UDP: - plen = sizeof(udphdr_t); - break; - /* 96 - enough for complete ICMP error IP header */ - case IPPROTO_ICMP: - plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); - break; - case IPPROTO_ESP: - plen = 8; - break; -# ifdef USE_INET6 - case IPPROTO_ICMPV6 : - /* - * XXX does not take intermediate header - * into account - */ - plen = ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t); - break; -# endif - } - if ((plen > 0) && (len < hlen + plen)) - fin->fin_fl |= FI_SHORT; - up = MIN(hlen + plen, len); - - if (up > m->m_len) { -# ifdef __sgi - /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */ - if ((up > sizeof(hbuf)) || (m_length(m) < up)) { - ATOMIC_INCL(frstats[out].fr_pull[1]); - return -1; - } - m_copydata(m, 0, up, hbuf); - ATOMIC_INCL(frstats[out].fr_pull[0]); - ip = (ip_t *)hbuf; -# else /* __ sgi */ -# ifndef linux - /* - * Having determined that we need to pullup some data, - * try to bring as much of the packet up into a single - * buffer with the first pullup. This hopefully means - * less need for doing futher pullups. Not needed for - * Solaris because fr_precheck() does it anyway. - * - * The main potential for trouble here is if MLEN/MHLEN - * become quite small, lets say < 64 bytes...but if - * that did happen, BSD networking as a whole would be - * slow/inefficient. - */ -# ifdef MHLEN - /* - * Assume that M_PKTHDR is set and just work with what - * is left rather than check.. Should not make any - * real difference, anyway. - */ - if ((MHLEN > up) && (len > up)) - up = MIN(len, MHLEN); -# else - if ((MLEN > up) && (len > up)) - up = MIN(len, MLEN); -# endif - ip = ipf_pullup(m, fin, up, ip); - if (ip == NULL) - return -1; - m = *mp; -# endif /* !linux */ -# endif /* __sgi */ - } else - up = 0; + fin->fin_ipoff = (char *)ip - MTOD(m, char *); + +#ifdef USE_INET6 + if (v == 6) { + ATOMIC_INCL(frstats[out].fr_ipv6); + /* + * Jumbo grams are quite likely too big for internal buffer + * structures to handle comfortably, for now, so just drop + * them. + */ + ip6 = (ip6_t *)ip; + fin->fin_plen = ntohs(ip6->ip6_plen); + if (fin->fin_plen == 0) { + pass = FR_BLOCK|FR_NOMATCH; + goto filtered; + } + fin->fin_plen += sizeof(ip6_t); } else - up = 0; -# endif /* !defined(__SVR4) && !defined(__svr4__) */ -# if SOLARIS - mb_t *m = qif->qf_m; +#endif + { +#if (OpenBSD >= 200311) && defined(_KERNEL) + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); +#endif + fin->fin_plen = ip->ip_len; + } - if ((u_int)ip & 0x3) - return 2; - fin->fin_mp = mp; - fin->fin_out = out; - fin->fin_qfm = m; - fin->fin_qif = qif; -# endif -#else - fin->fin_mp = mp; - fin->fin_out = out; -#endif /* _KERNEL */ - - changed = 0; - fin->fin_v = v; - fin->fin_ifp = ifp; if (fr_makefrip(hlen, ip, fin) == -1) - return -1; + goto finished; + /* + * For at least IPv6 packets, if a m_pullup() fails then this pointer + * becomes NULL and so we have no packet to free. + */ + if (*fin->fin_mp == NULL) + goto finished; + + if (!out) { + if (v == 4) { #ifdef _KERNEL -# ifdef USE_INET6 - if (v == 6) { - ATOMIC_INCL(frstats[0].fr_ipv6[out]); - if (((ip6_t *)ip)->ip6_hlim < fr_minttl) { - ATOMIC_INCL(frstats[0].fr_badttl); - if (fr_minttllog & 1) - logit = -3; - if (fr_minttllog & 2) - drop = 1; + if (fr_chksrc && !fr_verifysrc(fin)) { + ATOMIC_INCL(frstats[0].fr_badsrc); + fin->fin_flx |= FI_BADSRC; + } +#endif + if (fin->fin_ip->ip_ttl < fr_minttl) { + ATOMIC_INCL(frstats[0].fr_badttl); + fin->fin_flx |= FI_LOWTTL; + } } - } else -# endif - if (!out) { - if (fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { - ATOMIC_INCL(frstats[0].fr_badsrc); - if (fr_chksrc & 1) - drop = 1; - if (fr_chksrc & 2) - logit = -2; - } else if (ip->ip_ttl < fr_minttl) { - ATOMIC_INCL(frstats[0].fr_badttl); - if (fr_minttllog & 1) - logit = -3; - if (fr_minttllog & 2) - drop = 1; - } - } - if (drop) { -# ifdef IPFILTER_LOG - if (logit) { - fin->fin_group = logit; - pass = FR_INQUE|FR_NOMATCH|FR_LOGB; - (void) IPLLOG(pass, ip, fin, m); +#ifdef USE_INET6 + else if (v == 6) { + ip6 = (ip6_t *)ip; + if (ip6->ip6_hlim < fr_minttl) { + ATOMIC_INCL(frstats[0].fr_badttl); + fin->fin_flx |= FI_LOWTTL; + } } -# endif -# if !SOLARIS - m_freem(m); -# endif - return error; - } #endif - pass = fr_pass; - if (fin->fin_fl & FI_SHORT) { + } + + if (fin->fin_flx & FI_SHORT) { ATOMIC_INCL(frstats[out].fr_short); } @@ -1111,210 +2338,71 @@ int out; * after it has no auth. table matchup. This also stops NAT from * occuring until after the packet has been auth'd. */ - apass = fr_checkauth(ip, fin); - + fr = fr_checkauth(fin, &pass); 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 = list) && - (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INCL(frstats[0].fr_acct); + if (fr_checknatin(fin, &pass) == -1) { + RWLOCK_EXIT(&ipf_mutex); + goto finished; } } + if (!out) + (void) fr_acctpkt(fin, NULL); - if (!apass) { - if ((fin->fin_fl & FI_FRAG) == FI_FRAG) - fr = ipfr_knownfrag(ip, fin); - if (!fr && !(fin->fin_fl & FI_SHORT)) - fr = fr_checkstate(ip, fin); - if (fr != NULL) - pass = fr->fr_flags; - if (fr && (pass & FR_LOGFIRST)) - pass &= ~(FR_LOGFIRST|FR_LOG); - } - - if (apass || !fr) { - /* - * If a packet is found in the auth table, then skip checking - * the access lists for permission but we do need to consider - * the result as if it were from the ACL's. - */ - if (!apass) { - fc = frcache + out; - if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { - /* - * copy cached data so we can unlock the mutex - * earlier. - */ - bcopy((char *)fc, (char *)fin, FI_COPYSIZE); - ATOMIC_INCL(frstats[out].fr_chit); - if ((fr = fin->fin_fr)) { - ATOMIC_INCL(fr->fr_hits); - pass = fr->fr_flags; - } - } else { -#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_INCL(frstats[out].fr_nom); - fin->fin_fr = NULL; - } - } - } else - pass = apass; - fr = fin->fin_fr; - - /* - * If we fail to add a packet to the authorization queue, - * then we drop the packet later. However, if it was added - * then pretend we've dropped it already. - */ - if ((pass & FR_AUTH)) { - if (fr_newauth((mb_t *)m, fin, ip) != 0) { - m = *mp = NULL; - error = 0; - } else - error = ENOSPC; - } - - if (pass & FR_PREAUTH) { - READ_ENTER(&ipf_auth); - if ((fin->fin_fr = ipauth) && - (pass = fr_scanlist(0, ip, fin, m))) { - ATOMIC_INCL(fr_authstats.fas_hits); - } else { - ATOMIC_INCL(fr_authstats.fas_miss); - } - RWLOCK_EXIT(&ipf_auth); - } + if (fr == NULL) + if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) + fr = fr_knownfrag(fin, &pass); + if (fr == NULL) + fr = fr_checkstate(fin, &pass); - fin->fin_fr = fr; - if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { - if (fin->fin_fl & FI_FRAG) { - if (ipfr_newfrag(ip, fin) == -1) { - ATOMIC_INCL(frstats[out].fr_bnfr); - } else { - ATOMIC_INCL(frstats[out].fr_nfr); - } - } else { - ATOMIC_INCL(frstats[out].fr_cfr); - } - } - if (pass & FR_KEEPSTATE) { - if (fr_addstate(ip, fin, NULL, 0) == NULL) { - ATOMIC_INCL(frstats[out].fr_bads); - if (pass & FR_PASS) { - pass &= ~FR_PASS; - pass |= FR_BLOCK; - } - } else { - ATOMIC_INCL(frstats[out].fr_ads); - } - } - } else if (fr != NULL) { - pass = fr->fr_flags; - if (pass & FR_LOGFIRST) - pass &= ~(FR_LOGFIRST|FR_LOG); - } + if ((pass & FR_NOMATCH) || (fr == NULL)) + fr = fr_firewall(fin, &pass); -#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL)) - if (securelevel <= 0) -#endif - if (fr && fr->fr_func && !(pass & FR_CALLNOW)) - pass = (*fr->fr_func)(pass, ip, fin); + fin->fin_fr = fr; /* * Only count/translate packets which will be passed on, out the * interface. */ - if (out && (pass & FR_PASS)) { -#ifdef USE_INET6 - if (v == 6) - list = ipacct6[1][fr_active]; - else -#endif - list = ipacct[1][fr_active]; - if (list != NULL) { - u_32_t sg, sr; - - fin->fin_fr = list; - sg = fin->fin_group; - sr = fin->fin_rule; - if (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT) { - ATOMIC_INCL(frstats[1].fr_acct); + if (out && FR_ISPASS(pass)) { + (void) fr_acctpkt(fin, NULL); + + if (fr_checknatout(fin, &pass) == -1) { + RWLOCK_EXIT(&ipf_mutex); + goto finished; + } else if ((fr_update_ipid != 0) && (v == 4)) { + if (fr_updateipid(fin) == -1) { + ATOMIC_INCL(frstats[1].fr_ipud); + pass &= ~FR_CMDMASK; + pass |= FR_BLOCK; + } else { + ATOMIC_INCL(frstats[0].fr_ipud); } - fin->fin_group = sg; - fin->fin_rule = sr; - fin->fin_fr = fr; } - changed = ip_natout(ip, fin); - } else - fin->fin_fr = fr; - RWLOCK_EXIT(&ipf_mutex); + } #ifdef IPFILTER_LOG if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { - if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { - pass |= FF_LOGNOMATCH; - 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_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_INCL(frstats[out].fr_bpkl); -logit: - if (!IPLLOG(pass, ip, fin, m)) { - ATOMIC_INCL(frstats[out].fr_skip); - if ((pass & (FR_PASS|FR_LOGORBLOCK)) == - (FR_PASS|FR_LOGORBLOCK)) - pass ^= FR_PASS|FR_BLOCK; - } - } + (void) fr_dolog(fin, &pass); } -#endif /* IPFILTER_LOG */ +#endif + + if (fin->fin_state != NULL) + fr_statederef(fin, (ipstate_t **)&fin->fin_state); + + if (fin->fin_nat != NULL) + fr_natderef((nat_t **)&fin->fin_nat); -#ifdef _KERNEL /* * Only allow FR_DUP to work if a rule matched - it makes no sense to * set FR_DUP as a "default" as there are no instructions about where - * to send the packet. + * to send the packet. Use fin_m here because it may have changed + * (without an update of 'm') in prior processing. */ - if (fr && (pass & FR_DUP)) -# if SOLARIS - mc = dupmsg(m); -# else -# if defined(__OpenBSD__) && (OpenBSD >= 199905) - mc = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); -# else - mc = m_copy(m, 0, M_COPYALL); -# endif -# endif -#endif - if (pass & FR_PASS) { - ATOMIC_INCL(frstats[out].fr_pass); - } else if (pass & FR_BLOCK) { - ATOMIC_INCL(frstats[out].fr_block); + if ((fr != NULL) && (pass & FR_DUP)) { + mc = M_DUPLICATE(fin->fin_m); + } + + if (pass & (FR_RETRST|FR_RETICMP)) { /* * Should we return an ICMP packet to indicate error * status passing through the packet filter ? @@ -1324,33 +2412,24 @@ logit: * some operating systems. */ if (!out) { - if (changed == -1) - /* - * If a packet results in a NAT error, do not - * send a reset or ICMP error as it may disrupt - * an existing flow. This is the proxy saying - * the content is bad so just drop the packet - * silently. - */ - ; - else if (pass & FR_RETICMP) { + if (pass & FR_RETICMP) { int dst; if ((pass & FR_RETMASK) == FR_FAKEICMP) dst = 1; else dst = 0; - send_icmp_err(ip, ICMP_UNREACH, fin, dst); + (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst); ATOMIC_INCL(frstats[0].fr_ret); } else if (((pass & FR_RETMASK) == FR_RETRST) && - !(fin->fin_fl & FI_SHORT)) { - if (send_reset(ip, fin) == 0) { + !(fin->fin_flx & FI_SHORT)) { + if (fr_send_reset(fin) == 0) { ATOMIC_INCL(frstats[1].fr_ret); } } } else { if (pass & FR_RETRST) - error = ECONNRESET; + fin->fin_error = ECONNRESET; } } @@ -1360,83 +2439,177 @@ logit: * instructions about what to do with a packet. * Once we're finished return to our caller, freeing the packet if * we are dropping it (* BSD ONLY *). + * Reassign m from fin_m as we may have a new buffer, now. */ - if ((changed == -1) && (pass & FR_PASS)) { - pass &= ~FR_PASS; - pass |= FR_BLOCK; - } -#if defined(_KERNEL) -# if !SOLARIS -# if !defined(linux) - if (fr) { - frdest_t *fdp = &fr->fr_tif; +#if defined(USE_INET6) || (defined(__sgi) && defined(_KERNEL)) +filtered: +#endif + m = fin->fin_m; + + if (fr != NULL) { + frdest_t *fdp; + + fdp = &fr->fr_tifs[fin->fin_rev]; - if (((pass & FR_FASTROUTE) && !out) || - (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - (void) ipfr_fastroute(m, mp, fin, fdp); - m = *mp; + if (!out && (pass & FR_FASTROUTE)) { + /* + * For fastroute rule, no destioation interface defined + * so pass NULL as the frdest_t parameter + */ + (void) fr_fastroute(m, mp, fin, NULL); + m = *mp = NULL; + } else if ((fdp->fd_ifp != NULL) && + (fdp->fd_ifp != (struct ifnet *)-1)) { + /* this is for to rules: */ + (void) fr_fastroute(m, mp, fin, fdp); + m = *mp = NULL; } + /* + * Generate a duplicated packet. + */ if (mc != NULL) - (void) ipfr_fastroute(mc, &mc, fin, &fr->fr_dif); - } - - if (!(pass & FR_PASS) && m) { - m_freem(m); - m = *mp = NULL; + (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif); } -# ifdef __sgi - else if (changed && up && m) - m_copyback(m, 0, up, hbuf); -# endif -# endif /* !linux */ -# else /* !SOLARIS */ - if (fr) { - frdest_t *fdp = &fr->fr_tif; - if (((pass & FR_FASTROUTE) && !out) || - (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) - (void) ipfr_fastroute(ip, m, mp, fin, fdp); + /* + * This late because the likes of fr_fastroute() use fin_fr. + */ + RWLOCK_EXIT(&ipf_mutex); - if (mc != NULL) - (void) ipfr_fastroute(ip, mc, &mc, fin, &fr->fr_dif); +finished: + if (!FR_ISPASS(pass)) { + ATOMIC_INCL(frstats[out].fr_block); + if (*mp != NULL) { + FREE_MB_T(*mp); + m = *mp = NULL; + } + } else { + ATOMIC_INCL(frstats[out].fr_pass); +#if defined(_KERNEL) && defined(__sgi) + if ((fin->fin_hbuf != NULL) && + (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { + COPYBACK(m, 0, fin->fin_plen, fin->fin_hbuf); + } +#endif } -# endif /* !SOLARIS */ -#if (OpenBSD >= 200311) && defined(_KERNEL) - if (pass & FR_PASS) { - ip->ip_len = htons(ip->ip_len); - ip->ip_off = htons(ip->ip_off); + + RWLOCK_EXIT(&ipf_global); +#ifdef _KERNEL +# if OpenBSD >= 200311 + if (FR_ISPASS(pass) && (v == 4)) { + ip = fin->fin_ip; + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); } -#endif - return (pass & FR_PASS) ? 0 : error; +# endif + return (FR_ISPASS(pass)) ? 0 : fin->fin_error; #else /* _KERNEL */ - if (pass & FR_NOMATCH) + FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); + if ((pass & FR_NOMATCH) != 0) return 1; - if (pass & FR_PASS) + + if ((pass & FR_RETMASK) != 0) + switch (pass & FR_RETMASK) + { + case FR_RETRST : + return 3; + case FR_RETICMP : + return 4; + case FR_FAKEICMP : + return 5; + } + + switch (pass & FR_CMDMASK) + { + case FR_PASS : return 0; - if (pass & FR_AUTH) + case FR_BLOCK : + return -1; + case FR_AUTH : return -2; - if ((pass & FR_RETMASK) == FR_RETRST) + case FR_ACCOUNT : return -3; - if ((pass & FR_RETMASK) == FR_RETICMP) + case FR_PREAUTH : return -4; - if ((pass & FR_RETMASK) == FR_FAKEICMP) - return -5; - return -1; + } + return 2; #endif /* _KERNEL */ } -/* - * ipf_cksum - * addr should be 16bit aligned and len is in bytes. - * length is in bytes - */ +#ifdef IPFILTER_LOG +/* ------------------------------------------------------------------------ */ +/* Function: fr_dolog */ +/* Returns: frentry_t* - returns contents of fin_fr (no change made) */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Checks flags set to see how a packet should be logged, if it is to be */ +/* logged. Adjust statistics based on its success or not. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_dolog(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + u_32_t pass; + int out; + + out = fin->fin_out; + pass = *passp; + + if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { + pass |= FF_LOGNOMATCH; + ATOMIC_INCL(frstats[out].fr_npkl); + goto logit; + } else if (((pass & FR_LOGMASK) == FR_LOGP) || + (FR_ISPASS(pass) && (fr_flags & FF_LOGPASS))) { + if ((pass & FR_LOGMASK) != FR_LOGP) + pass |= FF_LOGPASS; + ATOMIC_INCL(frstats[out].fr_ppkl); + goto logit; + } else if (((pass & FR_LOGMASK) == FR_LOGB) || + (FR_ISBLOCK(pass) && (fr_flags & FF_LOGBLOCK))) { + if ((pass & FR_LOGMASK) != FR_LOGB) + pass |= FF_LOGBLOCK; + ATOMIC_INCL(frstats[out].fr_bpkl); +logit: + if (ipflog(fin, pass) == -1) { + ATOMIC_INCL(frstats[out].fr_skip); + + /* + * If the "or-block" option has been used then + * block the packet if we failed to log it. + */ + if ((pass & FR_LOGORBLOCK) && + FR_ISPASS(pass)) { + pass &= ~FR_CMDMASK; + pass |= FR_BLOCK; + } + } + *passp = pass; + } + + return fin->fin_fr; +} +#endif /* IPFILTER_LOG */ + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_cksum */ +/* Returns: u_short - IP header checksum */ +/* Parameters: addr(I) - pointer to start of buffer to checksum */ +/* len(I) - length of buffer in bytes */ +/* */ +/* Calculate the two's complement 16 bit checksum of the buffer passed. */ +/* */ +/* N.B.: addr should be 16bit aligned. */ +/* ------------------------------------------------------------------------ */ u_short ipf_cksum(addr, len) -register u_short *addr; -register int len; +u_short *addr; +int len; { - register u_32_t sum = 0; + u_32_t sum = 0; for (sum = 0; len > 1; len -= 2) sum += *addr++; @@ -1454,42 +2627,127 @@ register int len; } -/* - * NB: This function assumes we've pullup'd enough for all of the IP header - * and the TCP header. We also assume that data blocks aren't allocated in - * odd sizes. - */ -u_short fr_tcpsum(m, ip, tcp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_cksum */ +/* Returns: u_short - layer 4 checksum */ +/* Parameters: m(I ) - pointer to buffer holding packet */ +/* ip(I) - pointer to IP header */ +/* l4proto(I) - protocol to caclulate checksum for */ +/* l4hdr(I) - pointer to layer 4 header */ +/* */ +/* Calculates the TCP checksum for the packet held in "m", using the data */ +/* in the IP header "ip" to seed it. */ +/* */ +/* NB: This function assumes we've pullup'd enough for all of the IP header */ +/* and the TCP header. We also assume that data blocks aren't allocated in */ +/* odd sizes. */ +/* */ +/* Expects ip_len to be in host byte order when called. */ +/* ------------------------------------------------------------------------ */ +u_short fr_cksum(m, ip, l4proto, l4hdr) mb_t *m; ip_t *ip; -tcphdr_t *tcp; +int l4proto; +void *l4hdr; { - u_short *sp, slen, ts; + u_short *sp, slen, sumsave, l4hlen, *csump; u_int sum, sum2; int hlen; +#ifdef USE_INET6 + ip6_t *ip6; +#endif + + csump = NULL; + sumsave = 0; + l4hlen = 0; + sp = NULL; + slen = 0; + hlen = 0; + sum = 0; /* * Add up IP Header portion */ - hlen = ip->ip_hl << 2; - slen = ip->ip_len - hlen; - sum = htons((u_short)ip->ip_p); - sum += htons(slen); - sp = (u_short *)&ip->ip_src; - sum += *sp++; /* ip_src */ - sum += *sp++; - sum += *sp++; /* ip_dst */ - sum += *sp++; - ts = tcp->th_sum; - tcp->th_sum = 0; -#ifdef KERNEL -# if SOLARIS +#ifdef USE_INET6 + if (IP_V(ip) == 4) { +#endif + hlen = IP_HL(ip) << 2; + slen = ip->ip_len - hlen; + sum = htons((u_short)l4proto); + sum += htons(slen); + sp = (u_short *)&ip->ip_src; + sum += *sp++; /* ip_src */ + sum += *sp++; + sum += *sp++; /* ip_dst */ + sum += *sp++; +#ifdef USE_INET6 + } else if (IP_V(ip) == 6) { + ip6 = (ip6_t *)ip; + hlen = sizeof(*ip6); + slen = ntohs(ip6->ip6_plen); + sum = htons((u_short)l4proto); + sum += htons(slen); + sp = (u_short *)&ip6->ip6_src; + sum += *sp++; /* ip6_src */ + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; /* ip6_dst */ + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + } +#endif + + switch (l4proto) + { + case IPPROTO_UDP : + csump = &((udphdr_t *)l4hdr)->uh_sum; + l4hlen = sizeof(udphdr_t); + break; + + case IPPROTO_TCP : + csump = &((tcphdr_t *)l4hdr)->th_sum; + l4hlen = sizeof(tcphdr_t); + break; + case IPPROTO_ICMP : + csump = &((icmphdr_t *)l4hdr)->icmp_cksum; + l4hlen = 4; + sum = 0; + break; + default : + break; + } + + if (csump != NULL) { + sumsave = *csump; + *csump = 0; + } + + l4hlen = l4hlen; /* LINT */ + +#ifdef _KERNEL +# ifdef MENTAT + { + void *rp = m->b_rptr; + + if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr) + m->b_rptr = (u_char *)ip; sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - sum2 = ~sum2 & 0xffff; -# else /* SOLARIS */ + m->b_rptr = rp; + sum2 = (u_short)(~sum2 & 0xffff); + } +# else /* MENTAT */ # if defined(BSD) || defined(sun) -# if BSD >= 199306 +# if BSD >= 199103 m->m_data += hlen; # else m->m_off += hlen; @@ -1497,7 +2755,7 @@ tcphdr_t *tcp; m->m_len -= hlen; sum2 = in_cksum(m, slen); m->m_len += hlen; -# if BSD >= 199306 +# if BSD >= 199103 m->m_data -= hlen; # else m->m_off -= hlen; @@ -1516,35 +2774,44 @@ tcphdr_t *tcp; u_short s; } bytes; u_short len = ip->ip_len; -# if defined(__sgi) +# if defined(__sgi) int add; -# endif +# endif /* * Add up IP Header portion */ - sp = (u_short *)&ip->ip_src; - len -= (ip->ip_hl << 2); - sum = ntohs(IPPROTO_TCP); - sum += htons(len); - sum += *sp++; /* ip_src */ - sum += *sp++; - sum += *sp++; /* ip_dst */ - sum += *sp++; - if (sp != (u_short *)tcp) - sp = (u_short *)tcp; - sum += *sp++; /* sport */ - sum += *sp++; /* dport */ - sum += *sp++; /* seq */ - sum += *sp++; - sum += *sp++; /* ack */ - sum += *sp++; - sum += *sp++; /* off */ - sum += *sp++; /* win */ - sum += *sp++; /* Skip over checksum */ - sum += *sp++; /* urp */ - -# ifdef __sgi + if (sp != (u_short *)l4hdr) + sp = (u_short *)l4hdr; + + switch (l4proto) + { + case IPPROTO_UDP : + sum += *sp++; /* sport */ + sum += *sp++; /* dport */ + sum += *sp++; /* udp length */ + sum += *sp++; /* checksum */ + break; + + case IPPROTO_TCP : + sum += *sp++; /* sport */ + sum += *sp++; /* dport */ + sum += *sp++; /* seq */ + sum += *sp++; + sum += *sp++; /* ack */ + sum += *sp++; + sum += *sp++; /* off */ + sum += *sp++; /* win */ + sum += *sp++; /* checksum */ + sum += *sp++; /* urp */ + break; + case IPPROTO_ICMP : + sum = *sp++; /* type/code */ + sum += *sp++; /* checksum */ + break; + } + +# ifdef __sgi /* * In case we had to copy the IP & TCP header out of mbufs, * skip over the mbuf bits which are the header @@ -1562,24 +2829,26 @@ tcphdr_t *tcp; break; sp = mtod(m, u_short *); } - PANIC((!m),("fr_tcpsum(1): not enough data")); + PANIC((!m),("fr_cksum(1): not enough data")); } } } -# endif +# endif - if (!(len -= sizeof(*tcp))) + len -= (l4hlen + hlen); + if (len <= 0) goto nodata; + while (len > 1) { if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { m = m->m_next; - PANIC((!m),("fr_tcpsum(2): not enough data")); + PANIC((!m),("fr_cksum(2): not enough data")); sp = mtod(m, u_short *); } if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { bytes.c[0] = *(u_char *)sp; m = m->m_next; - PANIC((!m),("fr_tcpsum(3): not enough data")); + PANIC((!m),("fr_cksum(3): not enough data")); sp = mtod(m, u_short *); bytes.c[1] = *(u_char *)sp; sum += bytes.s; @@ -1592,7 +2861,8 @@ tcphdr_t *tcp; sum += *sp++; len -= 2; } - if (len) + + if (len != 0) sum += ntohs(*(u_char *)sp << 8); nodata: while (sum > 0xffff) @@ -1600,22 +2870,24 @@ nodata: sum2 = (u_short)(~sum & 0xffff); } # endif /* defined(BSD) || defined(sun) */ -# endif /* SOLARIS */ -#else /* KERNEL */ +# endif /* MENTAT */ +#else /* _KERNEL */ for (; slen > 1; slen -= 2) - sum += *sp++; + sum += *sp++; if (slen) sum += ntohs(*(u_char *)sp << 8); while (sum > 0xffff) sum = (sum & 0xffff) + (sum >> 16); sum2 = (u_short)(~sum & 0xffff); -#endif /* KERNEL */ - tcp->th_sum = ts; +#endif /* _KERNEL */ + if (csump != NULL) + *csump = sumsave; return sum2; } -#if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) ) +#if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \ + defined(__sgi) ) && !defined(linux) /* * Copyright (c) 1982, 1986, 1988, 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -1628,11 +2900,7 @@ nodata: * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -1649,7 +2917,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.82 2004/06/20 10:27:47 darrenr Exp $ + * Id: fil.c,v 2.243.2.57 2005/03/28 10:47:50 darrenr Exp */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1657,12 +2925,12 @@ nodata: */ void m_copydata(m, off, len, cp) - register mb_t *m; - register int off; - register int len; + mb_t *m; + int off; + int len; caddr_t cp; { - register unsigned count; + unsigned count; if (off < 0 || len < 0) panic("m_copydata"); @@ -1687,7 +2955,6 @@ m_copydata(m, off, len, cp) } -# ifndef linux /* * Copy data from a buffer back into the indicated mbuf chain, * starting "off" bytes from the beginning, extending the mbuf @@ -1696,12 +2963,12 @@ m_copydata(m, off, len, cp) void m_copyback(m0, off, len, cp) struct mbuf *m0; - register int off; - register int len; + int off; + int len; caddr_t cp; { - register int mlen; - register struct mbuf *m = m0, *n; + int mlen; + struct mbuf *m = m0, *n; int totlen = 0; if (m0 == 0) @@ -1744,169 +3011,322 @@ out: #endif return; } -# endif /* linux */ -#endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */ - - -frgroup_t *fr_findgroup(num, flags, which, set, fgpp) -u_32_t num, flags; -minor_t which; +#endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */ + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_findgroup */ +/* Returns: frgroup_t * - NULL = group not found, else pointer to group */ +/* Parameters: group(I) - group name to search for */ +/* unit(I) - device to which this group belongs */ +/* set(I) - which set of rules (inactive/inactive) this is */ +/* fgpp(O) - pointer to place to store pointer to the pointer */ +/* to where to add the next (last) group or where */ +/* to delete group from. */ +/* */ +/* Search amongst the defined groups for a particular group number. */ +/* ------------------------------------------------------------------------ */ +frgroup_t *fr_findgroup(group, unit, set, fgpp) +char *group; +minor_t unit; int set; frgroup_t ***fgpp; { frgroup_t *fg, **fgp; - if (which == IPL_LOGAUTH) - fgp = &ipfgroups[2][set]; - else if (flags & FR_ACCOUNT) - fgp = &ipfgroups[1][set]; - else if (flags & (FR_OUTQUE|FR_INQUE)) - fgp = &ipfgroups[0][set]; - else - return NULL; + /* + * Which list of groups to search in is dependant on which list of + * rules are being operated on. + */ + fgp = &ipfgroups[unit][set]; - while ((fg = *fgp)) - if (fg->fg_num == num) + while ((fg = *fgp) != NULL) { + if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) break; else fgp = &fg->fg_next; - if (fgpp) + } + if (fgpp != NULL) *fgpp = fgp; return fg; } -frgroup_t *fr_addgroup(num, fp, which, set) -u_32_t num; -frentry_t *fp; -minor_t which; +/* ------------------------------------------------------------------------ */ +/* Function: fr_addgroup */ +/* Returns: frgroup_t * - NULL == did not create group, */ +/* != NULL == pointer to the group */ +/* Parameters: num(I) - group number to add */ +/* head(I) - rule pointer that is using this as the head */ +/* flags(I) - rule flags which describe the type of rule it is */ +/* unit(I) - device to which this group will belong to */ +/* set(I) - which set of rules (inactive/inactive) this is */ +/* Write Locks: ipf_mutex */ +/* */ +/* Add a new group head, or if it already exists, increase the reference */ +/* count to it. */ +/* ------------------------------------------------------------------------ */ +frgroup_t *fr_addgroup(group, head, flags, unit, set) +char *group; +void *head; +u_32_t flags; +minor_t unit; int set; { frgroup_t *fg, **fgp; + u_32_t gflags; - if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp))) - return fg; + if (group == NULL) + return NULL; + if (unit == IPL_LOGIPF && *group == '\0') + return NULL; + + fgp = NULL; + gflags = flags & FR_INOUT; + + fg = fr_findgroup(group, unit, set, &fgp); + if (fg != NULL) { + if (fg->fg_flags == 0) + fg->fg_flags = gflags; + else if (gflags != fg->fg_flags) + return NULL; + fg->fg_ref++; + return fg; + } KMALLOC(fg, frgroup_t *); - if (fg) { - fg->fg_num = num; + if (fg != NULL) { + fg->fg_head = head; + fg->fg_start = NULL; fg->fg_next = *fgp; - fg->fg_head = fp; - fg->fg_start = &fp->fr_grp; + bcopy(group, fg->fg_name, FR_GROUPLEN); + fg->fg_flags = gflags; + fg->fg_ref = 1; *fgp = fg; } return fg; } -void fr_delgroup(num, flags, which, set) -u_32_t num, flags; -minor_t which; +/* ------------------------------------------------------------------------ */ +/* Function: fr_delgroup */ +/* Returns: Nil */ +/* Parameters: group(I) - group name to delete */ +/* unit(I) - device to which this group belongs */ +/* set(I) - which set of rules (inactive/inactive) this is */ +/* Write Locks: ipf_mutex */ +/* */ +/* Attempt to delete a group head. */ +/* Only do this when its reference count reaches 0. */ +/* ------------------------------------------------------------------------ */ +void fr_delgroup(group, unit, set) +char *group; +minor_t unit; int set; { frgroup_t *fg, **fgp; - - if (!(fg = fr_findgroup(num, flags, which, set, &fgp))) + + fg = fr_findgroup(group, unit, set, &fgp); + if (fg == NULL) return; - - *fgp = fg->fg_next; - KFREE(fg); + + fg->fg_ref--; + if (fg->fg_ref == 0) { + *fgp = fg->fg_next; + KFREE(fg); + } } +/* ------------------------------------------------------------------------ */ +/* Function: fr_getrulen */ +/* Returns: frentry_t * - NULL == not found, else pointer to rule n */ +/* Parameters: unit(I) - device for which to count the rule's number */ +/* flags(I) - which set of rules to find the rule in */ +/* group(I) - group name */ +/* n(I) - rule number to find */ +/* */ +/* Find rule # n in group # g and return a pointer to it. Return NULl if */ +/* group # g doesn't exist or there are less than n rules in the group. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_getrulen(unit, group, n) +int unit; +char *group; +u_32_t n; +{ + frentry_t *fr; + frgroup_t *fg; -/* - * recursively flush rules from the list, descending groups as they are - * encountered. if a rule is the head of a group and it has lost all its - * group members, then also delete the group reference. - */ + fg = fr_findgroup(group, unit, fr_active, NULL); + if (fg == NULL) + return NULL; + for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--) + ; + if (n != 0) + return NULL; + return fr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_rulen */ +/* Returns: int - >= 0 - rule number, -1 == search failed */ +/* Parameters: unit(I) - device for which to count the rule's number */ +/* fr(I) - pointer to rule to match */ +/* */ +/* Return the number for a rule on a specific filtering device. */ +/* ------------------------------------------------------------------------ */ +int fr_rulen(unit, fr) +int unit; +frentry_t *fr; +{ + frentry_t *fh; + frgroup_t *fg; + u_32_t n = 0; + + if (fr == NULL) + return -1; + fg = fr_findgroup(fr->fr_group, unit, fr_active, NULL); + if (fg == NULL) + return -1; + for (fh = fg->fg_head; fh; n++, fh = fh->fr_next) + if (fh == fr) + break; + if (fh == NULL) + return -1; + return n; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frflushlist */ +/* Returns: int - >= 0 - number of flushed rules */ +/* Parameters: set(I) - which set of rules (inactive/inactive) this is */ +/* unit(I) - device for which to flush rules */ +/* flags(I) - which set of rules to flush */ +/* nfreedp(O) - pointer to int where flush count is stored */ +/* listp(I) - pointer to list to flush pointer */ +/* Write Locks: ipf_mutex */ +/* */ +/* Recursively flush rules from the list, descending groups as they are */ +/* encountered. if a rule is the head of a group and it has lost all its */ +/* group members, then also delete the group reference. nfreedp is needed */ +/* to store the accumulating count of rules removed, whereas the returned */ +/* value is just the number removed from the current list. The latter is */ +/* needed to correctly adjust reference counts on rules that define groups. */ +/* */ +/* NOTE: Rules not loaded from user space cannot be flushed. */ +/* ------------------------------------------------------------------------ */ static int frflushlist(set, unit, nfreedp, listp) int set; minor_t unit; int *nfreedp; frentry_t **listp; { - register int freed = 0, i; - register frentry_t *fp; + int freed = 0, i; + frentry_t *fp; - while ((fp = *listp)) { + while ((fp = *listp) != NULL) { + if ((fp->fr_type & FR_T_BUILTIN) || + !(fp->fr_flags & FR_COPIED)) { + listp = &fp->fr_next; + continue; + } *listp = fp->fr_next; - if (fp->fr_grp) { - i = frflushlist(set, unit, nfreedp, &fp->fr_grp); - MUTEX_ENTER(&ipf_rw); + if (fp->fr_grp != NULL) { + i = frflushlist(set, unit, nfreedp, fp->fr_grp); fp->fr_ref -= i; - MUTEX_EXIT(&ipf_rw); } - ATOMIC_DEC32(fp->fr_ref); - if (fp->fr_grhead) { - fr_delgroup(fp->fr_grhead, fp->fr_flags, - unit, set); - fp->fr_grhead = 0; + if (fp->fr_grhead != NULL) { + fr_delgroup(fp->fr_grhead, unit, set); + *fp->fr_grhead = '\0'; } - if (fp->fr_ref == 0) { - KFREE(fp); + + ASSERT(fp->fr_ref > 0); + fp->fr_next = NULL; + if (fr_derefrule(&fp) == 0) freed++; - } else - fp->fr_next = NULL; } *nfreedp += freed; return freed; } +/* ------------------------------------------------------------------------ */ +/* Function: frflush */ +/* Returns: int - >= 0 - number of flushed rules */ +/* Parameters: unit(I) - device for which to flush rules */ +/* flags(I) - which set of rules to flush */ +/* */ +/* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ +/* and IPv6) as defined by the value of flags. */ +/* ------------------------------------------------------------------------ */ int frflush(unit, proto, flags) minor_t unit; int proto, flags; { int flushed = 0, set; - if (unit != IPL_LOGIPF) - return 0; WRITE_ENTER(&ipf_mutex); - bzero((char *)frcache, sizeof(frcache[0]) * 2); + bzero((char *)frcache, sizeof(frcache)); set = fr_active; - if (flags & FR_INACTIVE) + if ((flags & FR_INACTIVE) == FR_INACTIVE) set = 1 - set; if (flags & FR_OUTQUE) { -#ifdef USE_INET6 if (proto == 0 || proto == 6) { (void) frflushlist(set, unit, - &flushed, &ipfilter6[1][set]); + &flushed, &ipfilter6[1][set]); (void) frflushlist(set, unit, - &flushed, &ipacct6[1][set]); + &flushed, &ipacct6[1][set]); } -#endif if (proto == 0 || proto == 4) { (void) frflushlist(set, unit, - &flushed, &ipfilter[1][set]); + &flushed, &ipfilter[1][set]); (void) frflushlist(set, unit, - &flushed, &ipacct[1][set]); + &flushed, &ipacct[1][set]); } } if (flags & FR_INQUE) { -#ifdef USE_INET6 if (proto == 0 || proto == 6) { (void) frflushlist(set, unit, - &flushed, &ipfilter6[0][set]); + &flushed, &ipfilter6[0][set]); (void) frflushlist(set, unit, - &flushed, &ipacct6[0][set]); + &flushed, &ipacct6[0][set]); } -#endif if (proto == 0 || proto == 4) { (void) frflushlist(set, unit, - &flushed, &ipfilter[0][set]); + &flushed, &ipfilter[0][set]); (void) frflushlist(set, unit, - &flushed, &ipacct[0][set]); + &flushed, &ipacct[0][set]); } } RWLOCK_EXIT(&ipf_mutex); + + if (unit == IPL_LOGIPF) { + int tmp; + + tmp = frflush(IPL_LOGCOUNT, proto, flags); + if (tmp >= 0) + flushed += tmp; + } return flushed; } +/* ------------------------------------------------------------------------ */ +/* Function: memstr */ +/* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ +/* Parameters: src(I) - pointer to byte sequence to match */ +/* dst(I) - pointer to byte sequence to search */ +/* slen(I) - match length */ +/* dlen(I) - length available to search in */ +/* */ +/* Search dst for a sequence of bytes matching those at src and extend for */ +/* slen bytes. */ +/* ------------------------------------------------------------------------ */ char *memstr(src, dst, slen, dlen) char *src, *dst; int slen, dlen; @@ -1923,34 +3343,50 @@ int slen, dlen; } return s; } - - -void fixskip(listp, rp, addremove) +/* ------------------------------------------------------------------------ */ +/* Function: fr_fixskip */ +/* Returns: Nil */ +/* Parameters: listp(IO) - pointer to start of list with skip rule */ +/* rp(I) - rule added/removed with skip in it. */ +/* addremove(I) - adjustment (-1/+1) to make to skip count, */ +/* depending on whether a rule was just added */ +/* or removed. */ +/* */ +/* Adjust all the rules in a list which would have skip'd past the position */ +/* where we are inserting to skip to the right place given the change. */ +/* ------------------------------------------------------------------------ */ +void fr_fixskip(listp, rp, addremove) frentry_t **listp, *rp; int addremove; { + int rules, rn; frentry_t *fp; - int rules = 0, rn = 0; - for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++) - ; + rules = 0; + for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) + rules++; if (!fp) return; - for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) - if (fp->fr_skip && (rn + fp->fr_skip >= rules)) - fp->fr_skip += addremove; + for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) + if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) + fp->fr_arg += addremove; } #ifdef _KERNEL -/* - * 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) +/* ------------------------------------------------------------------------ */ +/* Function: count4bits */ +/* Returns: int - >= 0 - number of consecutive bits in input */ +/* Parameters: ip(I) - 32bit IP address */ +/* */ +/* IPv4 ONLY */ +/* 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 count4bits(ip) u_32_t ip; { u_32_t ipn; @@ -1974,192 +3410,156 @@ u_32_t ip; } -/* - * return the first IP Address associated with an interface - */ -int fr_ifpaddr(v, ifptr, inp) -int v; -void *ifptr; -struct in_addr *inp; +# if 0 +/* ------------------------------------------------------------------------ */ +/* Function: count6bits */ +/* Returns: int - >= 0 - number of consecutive bits in input */ +/* Parameters: msk(I) - pointer to start of IPv6 bitmask */ +/* */ +/* IPv6 ONLY */ +/* count consecutive 1's in bit mask. */ +/* ------------------------------------------------------------------------ */ +int count6bits(msk) +u_32_t *msk; { -# ifdef USE_INET6 - struct in6_addr *inp6 = NULL; -# endif -# if SOLARIS - ill_t *ill = ifptr; -# else - struct ifnet *ifp = ifptr; -# endif - struct in_addr in; - -# if SOLARIS -# ifdef USE_INET6 - if (v == 6) { - struct in6_addr in6; + int i = 0, k; + u_32_t j; - /* - * 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 sockaddr_in *sin; - struct ifaddr *ifa; - -# if (__FreeBSD_version >= 300000) - ifa = TAILQ_FIRST(&ifp->if_addrhead); -# else -# if defined(__NetBSD__) || defined(__OpenBSD__) - ifa = ifp->if_addrlist.tqh_first; -# else -# if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ - ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa; -# else - ifa = ifp->if_addrlist; -# endif -# endif /* __NetBSD__ || __OpenBSD__ */ -# endif /* __FreeBSD_version >= 300000 */ -# if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK)) - sin = (struct sockaddr_in *)&ifa->ifa_addr; -# else - sin = (struct sockaddr_in *)ifa->ifa_addr; - 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; + for (k = 3; k >= 0; k--) + if (msk[k] == 0xffffffff) + i += 32; + else { + for (j = msk[k]; j; j <<= 1) + if (j & 0x80000000) + i++; } -# endif -# if (__FreeBSD_version >= 300000) - ifa = TAILQ_NEXT(ifa, ifa_link); -# else -# if defined(__NetBSD__) || defined(__OpenBSD__) - ifa = ifa->ifa_list.tqe_next; -# else - ifa = ifa->ifa_next; -# endif -# endif /* __FreeBSD_version >= 300000 */ - if (ifa) - sin = (struct sockaddr_in *)ifa->ifa_addr; - } - if (ifa == NULL) - sin = NULL; - if (sin == NULL) - return -1; -# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ -# 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 */ - return 0; + return i; } +# endif +#endif /* _KERNEL */ -static void frsynclist(fr) -register frentry_t *fr; +/* ------------------------------------------------------------------------ */ +/* Function: frsynclist */ +/* Returns: void */ +/* Parameters: fr(I) - start of filter list to sync interface names for */ +/* ifp(I) - interface pointer for limiting sync lookups */ +/* Write Locks: ipf_mutex */ +/* */ +/* Walk through a list of filter rules and resolve any interface names into */ +/* pointers. Where dynamic addresses are used, also update the IP address */ +/* used in the rule. The interface pointer is used to limit the lookups to */ +/* a specific set of matching names if it is non-NULL. */ +/* ------------------------------------------------------------------------ */ +static void frsynclist(fr, ifp) +frentry_t *fr; +void *ifp; { frdest_t *fdp; - int i; + int v, i; for (; fr; fr = fr->fr_next) { + v = fr->fr_v; + + /* + * Lookup all the interface names that are part of the rule. + */ for (i = 0; i < 4; i++) { - if ((fr->fr_ifnames[i][1] == '\0') && - ((fr->fr_ifnames[i][0] == '-') || - (fr->fr_ifnames[i][0] == '*'))) { - fr->fr_ifas[i] = NULL; - } else if (*fr->fr_ifnames[i]) { - fr->fr_ifas[i] = GETUNIT(fr->fr_ifnames[i], - fr->fr_v); - if (!fr->fr_ifas[i]) - fr->fr_ifas[i] = (void *)-1; + if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) + continue; + fr->fr_ifas[i] = fr_resolvenic(fr->fr_ifnames[i], v); + } + + if (fr->fr_type == FR_T_IPF) { + if (fr->fr_satype != FRI_NORMAL && + fr->fr_satype != FRI_LOOKUP) { + (void)fr_ifpaddr(v, fr->fr_satype, + fr->fr_ifas[fr->fr_sifpidx], + &fr->fr_src, &fr->fr_smsk); + } + if (fr->fr_datype != FRI_NORMAL && + fr->fr_datype != FRI_LOOKUP) { + (void)fr_ifpaddr(v, fr->fr_datype, + fr->fr_ifas[fr->fr_difpidx], + &fr->fr_dst, &fr->fr_dmsk); } } + fdp = &fr->fr_tifs[0]; + if ((ifp == NULL) || (fdp->fd_ifp == ifp)) + fr_resolvedest(fdp, v); + + fdp = &fr->fr_tifs[1]; + if ((ifp == NULL) || (fdp->fd_ifp == ifp)) + fr_resolvedest(fdp, v); + fdp = &fr->fr_dif; - fr->fr_flags &= ~FR_DUP; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fr->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; - else + if ((ifp == NULL) || (fdp->fd_ifp == ifp)) { + fr_resolvedest(fdp, v); + + fr->fr_flags &= ~FR_DUP; + if ((fdp->fd_ifp != (void *)-1) && + (fdp->fd_ifp != NULL)) fr->fr_flags |= FR_DUP; } - fdp = &fr->fr_tif; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fr->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; +#ifdef IPFILTER_LOOKUP + if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP && + fr->fr_srcptr == NULL) { + fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype, + fr->fr_srcnum, + &fr->fr_srcfunc); } - - if (fr->fr_grp) - frsynclist(fr->fr_grp); + if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP && + fr->fr_dstptr == NULL) { + fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype, + fr->fr_dstnum, + &fr->fr_dstfunc); + } +#endif } } -void frsync() +#ifdef _KERNEL +/* ------------------------------------------------------------------------ */ +/* Function: frsync */ +/* Returns: void */ +/* Parameters: Nil */ +/* */ +/* frsync() is called when we suspect that the interface list or */ +/* information about interfaces (like IP#) has changed. Go through all */ +/* filter rules, NAT entries and the state table and check if anything */ +/* needs to be changed/updated. */ +/* ------------------------------------------------------------------------ */ +void frsync(ifp) +void *ifp; { + int i; + # if !SOLARIS - register struct ifnet *ifp; - -# if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \ - (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) -# if (NetBSD >= 199905) || defined(__OpenBSD__) - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) -# elif defined(__FreeBSD_version) && (__FreeBSD_version >= 500043) - IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &ifnet, if_link); -# else - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) -# endif -# else - for (ifp = ifnet; ifp; ifp = ifp->if_next) -# endif - { - ip_natsync(ifp); - ip_statesync(ifp); - } - ip_natsync((struct ifnet *)-1); -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 500043) - IFNET_RUNLOCK(); -# endif -# endif /* !SOLARIS */ + fr_natsync(ifp); + fr_statesync(ifp); +# endif WRITE_ENTER(&ipf_mutex); - frsynclist(ipacct[0][fr_active]); - 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 + frsynclist(ipacct[0][fr_active], ifp); + frsynclist(ipacct[1][fr_active], ifp); + frsynclist(ipfilter[0][fr_active], ifp); + frsynclist(ipfilter[1][fr_active], ifp); + frsynclist(ipacct6[0][fr_active], ifp); + frsynclist(ipacct6[1][fr_active], ifp); + frsynclist(ipfilter6[0][fr_active], ifp); + frsynclist(ipfilter6[1][fr_active], ifp); + + for (i = 0; i < IPL_LOGSIZE; i++) { + frgroup_t *g; + + for (g = ipfgroups[i][0]; g != NULL; g = g->fg_next) + frsynclist(g->fg_start, ifp); + for (g = ipfgroups[i][1]; g != NULL; g = g->fg_next) + frsynclist(g->fg_start, ifp); + } RWLOCK_EXIT(&ipf_mutex); } @@ -2169,156 +3569,134 @@ void frsync() * 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; +/* ------------------------------------------------------------------------ */ +/* Function: copyinptr */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: src(I) - pointer to the source address */ +/* dst(I) - destination address */ +/* size(I) - number of bytes to copy */ +/* */ +/* Copy a block of data in from user space, given a pointer to the pointer */ +/* to start copying from (src) and a pointer to where to store it (dst). */ +/* NB: src - pointer to user space pointer, dst - kernel space pointer */ +/* ------------------------------------------------------------------------ */ +int copyinptr(src, dst, size) +void *src, *dst; +size_t size; { caddr_t ca; int err; -#if SOLARIS - if (copyin(a, (char *)&ca, sizeof(ca))) - return EFAULT; -#else - bcopy(a, &ca, sizeof(ca)); -#endif - err = copyin(ca, b, c); - if (err) - err = EFAULT; +# if SOLARIS + err = COPYIN(src, (caddr_t)&ca, sizeof(ca)); + if (err != 0) + return err; +# else + bcopy(src, (caddr_t)&ca, sizeof(ca)); +# endif + err = COPYIN(ca, dst, size); return err; } -int iwcopyptr(a, b, c) -void *a, *b; -size_t c; +/* ------------------------------------------------------------------------ */ +/* Function: copyoutptr */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: src(I) - pointer to the source address */ +/* dst(I) - destination address */ +/* size(I) - number of bytes to copy */ +/* */ +/* Copy a block of data out to user space, given a pointer to the pointer */ +/* to start copying from (src) and a pointer to where to store it (dst). */ +/* NB: src - kernel space pointer, dst - pointer to user space pointer. */ +/* ------------------------------------------------------------------------ */ +int copyoutptr(src, dst, size) +void *src, *dst; +size_t size; { caddr_t ca; int err; -#if SOLARIS - if (copyin(b, (char *)&ca, sizeof(ca))) - return EFAULT; -#else - bcopy(b, &ca, sizeof(ca)); -#endif - err = copyout(a, ca, c); - if (err) - err = EFAULT; +# if SOLARIS + err = COPYIN(dst, (caddr_t)&ca, sizeof(ca)); + if (err != 0) + return err; +# else + bcopy(dst, (caddr_t)&ca, sizeof(ca)); +# endif + err = COPYOUT(src, ca, size); return err; } - -#else /* _KERNEL */ - - -/* - * return the first IP Address associated with an interface - */ -int fr_ifpaddr(v, ifptr, inp) -int v; -void *ifptr; -struct in_addr *inp; -{ - return 0; -} - - -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) +/* ------------------------------------------------------------------------ */ +/* Function: fr_lock */ +/* Returns: (void) */ +/* Parameters: data(I) - pointer to lock value to set */ +/* lockp(O) - pointer to location to store old lock value */ +/* */ +/* Get the new value for the lock integer, set it and return the old value */ +/* in *lockp. */ +/* ------------------------------------------------------------------------ */ +void fr_lock(data, lockp) caddr_t data; int *lockp; { - int arg, error; + int arg; - error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); - if (!error) { - error = IWCOPY((caddr_t)lockp, data, sizeof(*lockp)); - if (!error) - *lockp = arg; - } - return error; + BCOPYIN(data, (caddr_t)&arg, sizeof(arg)); + BCOPYOUT((caddr_t)lockp, data, sizeof(*lockp)); + *lockp = arg; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_getstat */ +/* Returns: Nil */ +/* Parameters: fiop(I) - pointer to ipfilter stats structure */ +/* */ +/* Stores a copy of current pointers, counters, etc, in the friostat */ +/* structure. */ +/* ------------------------------------------------------------------------ */ void fr_getstat(fiop) friostat_t *fiop; { + int i, j; + 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]; -#else - fiop->f_fin6[0] = NULL; - fiop->f_fin6[1] = NULL; - fiop->f_fout6[0] = NULL; - fiop->f_fout6[1] = NULL; - fiop->f_acctin6[0] = NULL; - fiop->f_acctin6[1] = NULL; - fiop->f_acctout6[0] = NULL; - fiop->f_acctout6[1] = NULL; -#endif + fiop->f_locks[IPL_LOGSTATE] = fr_state_lock; + fiop->f_locks[IPL_LOGNAT] = fr_nat_lock; + fiop->f_locks[IPL_LOGIPF] = fr_frag_lock; + fiop->f_locks[IPL_LOGAUTH] = fr_auth_lock; + + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) { + fiop->f_ipf[i][j] = ipfilter[i][j]; + fiop->f_acct[i][j] = ipacct[i][j]; + fiop->f_ipf6[i][j] = ipfilter6[i][j]; + fiop->f_acct6[i][j] = ipacct6[i][j]; + } + + fiop->f_ticks = fr_ticks; fiop->f_active = fr_active; - fiop->f_froute[0] = ipl_frouteok[0]; - fiop->f_froute[1] = ipl_frouteok[1]; + fiop->f_froute[0] = fr_frouteok[0]; + fiop->f_froute[1] = fr_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]; + for (i = 0; i < IPL_LOGSIZE; i++) { + fiop->f_groups[i][0] = ipfgroups[i][0]; + fiop->f_groups[i][1] = ipfgroups[i][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)); + fiop->f_features = fr_features; + (void) strncpy(fiop->f_version, ipfilter_version, + sizeof(fiop->f_version)); } @@ -2362,77 +3740,2470 @@ int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { -1, /* 12: ICMP_UNREACH_TOSHOST */ ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ }; +int icmpreplytype6[ICMP6_MAXTYPE + 1]; #endif +int icmpreplytype4[ICMP_MAXTYPE + 1]; + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_matchicmpqueryreply */ +/* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ +/* Parameters: v(I) - IP protocol version (4 or 6) */ +/* ic(I) - ICMP information */ +/* icmp(I) - ICMP packet header */ +/* rev(I) - direction (0 = forward/1 = reverse) of packet */ +/* */ +/* Check if the ICMP packet defined by the header pointed to by icmp is a */ +/* reply to one as described by what's in ic. If it is a match, return 1, */ +/* else return 0 for no match. */ +/* ------------------------------------------------------------------------ */ +int fr_matchicmpqueryreply(v, ic, icmp, rev) +int v; +icmpinfo_t *ic; +icmphdr_t *icmp; +int rev; +{ + int ictype; -#ifndef _KERNEL -int mbuflen(buf) -mb_t *buf; + ictype = ic->ici_type; + + if (v == 4) { + /* + * If we matched its type on the way in, then when going out + * it will still be the same type. + */ + if ((!rev && (icmp->icmp_type == ictype)) || + (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { + if (icmp->icmp_type != ICMP_ECHOREPLY) + return 1; + if (icmp->icmp_id == ic->ici_id) + return 1; + } + } +#ifdef USE_INET6 + else if (v == 6) { + if ((!rev && (icmp->icmp_type == ictype)) || + (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { + if (icmp->icmp_type != ICMP6_ECHO_REPLY) + return 1; + if (icmp->icmp_id == ic->ici_id) + return 1; + } + } +#endif + return 0; +} + + +#ifdef IPFILTER_LOOKUP +/* ------------------------------------------------------------------------ */ +/* Function: fr_resolvelookup */ +/* Returns: void * - NULL = failure, else success. */ +/* Parameters: type(I) - type of lookup these parameters are for. */ +/* number(I) - table number to use when searching */ +/* funcptr(IO) - pointer to pointer for storing IP address */ +/* searching function. */ +/* */ +/* Search for the "table" number passed in amongst those configured for */ +/* that particular type. If the type is recognised then the function to */ +/* call to do the IP address search will be change, regardless of whether */ +/* or not the "table" number exists. */ +/* ------------------------------------------------------------------------ */ +static void *fr_resolvelookup(type, number, funcptr) +u_int type, number; +lookupfunc_t *funcptr; { - ip_t *ip; + char name[FR_GROUPLEN]; + iphtable_t *iph; + ip_pool_t *ipo; + void *ptr; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%u", number); +#else + (void) sprintf(name, "%u", number); +#endif + + READ_ENTER(&ip_poolrw); - ip = (ip_t *)buf; - return ip->ip_len; + switch (type) + { + case IPLT_POOL : +# if (defined(__osf__) && defined(_KERNEL)) + ptr = NULL; + *funcptr = NULL; +# else + ipo = ip_pool_find(IPL_LOGIPF, name); + ptr = ipo; + if (ipo != NULL) { + ATOMIC_INC32(ipo->ipo_ref); + } + *funcptr = ip_pool_search; +# endif + break; + case IPLT_HASH : + iph = fr_findhtable(IPL_LOGIPF, name); + ptr = iph; + if (iph != NULL) { + ATOMIC_INC32(iph->iph_ref); + } + *funcptr = fr_iphmfindip; + break; + default: + ptr = NULL; + *funcptr = NULL; + break; + } + RWLOCK_EXIT(&ip_poolrw); + + return ptr; } #endif -#if defined(_KERNEL) && !defined(__sgi) -void *ipf_pullup(m, fin, len, ipin) -mb_t *m; +/* ------------------------------------------------------------------------ */ +/* Function: frrequest */ +/* Returns: int - 0 == success, > 0 == errno value */ +/* Parameters: unit(I) - device for which this is for */ +/* req(I) - ioctl command (SIOC*) */ +/* data(I) - pointr to ioctl data */ +/* set(I) - 1 or 0 (filter set) */ +/* makecopy(I) - flag indicating whether data points to a rule */ +/* in kernel space & hence doesn't need copying. */ +/* */ +/* This function handles all the requests which operate on the list of */ +/* filter rules. This includes adding, deleting, insertion. It is also */ +/* responsible for creating groups when a "head" rule is loaded. Interface */ +/* names are resolved here and other sanity checks are made on the content */ +/* of the rule structure being loaded. If a rule has user defined timeouts */ +/* then make sure they are created and initialised before exiting. */ +/* ------------------------------------------------------------------------ */ +int frrequest(unit, req, data, set, makecopy) +int unit; +ioctlcmd_t req; +int set, makecopy; +caddr_t data; +{ + frentry_t frd, *fp, *f, **fprev, **ftail; + int error = 0, in, v; + void *ptr, *uptr; + u_int *p, *pp; + frgroup_t *fg; + char *group; + + fg = NULL; + fp = &frd; + if (makecopy != 0) { + error = fr_inobj(data, fp, IPFOBJ_FRENTRY); + if (error) + return EFAULT; + if ((fp->fr_flags & FR_T_BUILTIN) != 0) + return EINVAL; + fp->fr_ref = 0; + fp->fr_flags |= FR_COPIED; + } else { + fp = (frentry_t *)data; + if ((fp->fr_type & FR_T_BUILTIN) == 0) + return EINVAL; + fp->fr_flags &= ~FR_COPIED; + } + + if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || + ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) + return EINVAL; + + v = fp->fr_v; + uptr = fp->fr_data; + + /* + * Only filter rules for IPv4 or IPv6 are accepted. + */ + if (v == 4) + /*EMPTY*/; +#ifdef USE_INET6 + else if (v == 6) + /*EMPTY*/; +#endif + else { + return EINVAL; + } + + /* + * If the rule is being loaded from user space, i.e. we had to copy it + * into kernel space, then do not trust the function pointer in the + * rule. + */ + if ((makecopy == 1) && (fp->fr_func != NULL)) { + if (fr_findfunc(fp->fr_func) == NULL) + return ESRCH; + error = fr_funcinit(fp); + if (error != 0) + return error; + } + + ptr = NULL; + /* + * Check that the group number does exist and that its use (in/out) + * matches what the rule is. + */ + if (!strncmp(fp->fr_grhead, "0", FR_GROUPLEN)) + *fp->fr_grhead = '\0'; + group = fp->fr_group; + if (!strncmp(group, "0", FR_GROUPLEN)) + *group = '\0'; + + if (FR_ISACCOUNT(fp->fr_flags)) + unit = IPL_LOGCOUNT; + + if ((req != (int)SIOCZRLST) && (*group != '\0')) { + fg = fr_findgroup(group, unit, set, NULL); + if (fg == NULL) + return ESRCH; + if (fg->fg_flags == 0) + fg->fg_flags = fp->fr_flags & FR_INOUT; + else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) + return ESRCH; + } + + in = (fp->fr_flags & FR_INQUE) ? 0 : 1; + + /* + * Work out which rule list this change is being applied to. + */ + ftail = NULL; + fprev = NULL; + if (unit == IPL_LOGAUTH) + fprev = &ipauth; + else if (v == 4) { + if (FR_ISACCOUNT(fp->fr_flags)) + fprev = &ipacct[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) + fprev = &ipfilter[in][set]; + } else if (v == 6) { + if (FR_ISACCOUNT(fp->fr_flags)) + fprev = &ipacct6[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) + fprev = &ipfilter6[in][set]; + } + if (fprev == NULL) + return ESRCH; + + if (*group != '\0') { + if (!fg && !(fg = fr_findgroup(group, unit, set, NULL))) + return ESRCH; + fprev = &fg->fg_start; + } + + for (f = *fprev; (f = *fprev) != NULL; fprev = &f->fr_next) + if (fp->fr_collect <= f->fr_collect) + break; + ftail = fprev; + + /* + * Copy in extra data for the rule. + */ + if (fp->fr_dsize != 0) { + if (makecopy != 0) { + KMALLOCS(ptr, void *, fp->fr_dsize); + if (!ptr) + return ENOMEM; + error = COPYIN(uptr, ptr, fp->fr_dsize); + } else { + ptr = uptr; + error = 0; + } + if (error != 0) { + KFREES(ptr, fp->fr_dsize); + return ENOMEM; + } + fp->fr_data = ptr; + } else + fp->fr_data = NULL; + + /* + * Perform per-rule type sanity checks of their members. + */ + switch (fp->fr_type & ~FR_T_BUILTIN) + { +#if defined(IPFILTER_BPF) + case FR_T_BPFOPC : + if (fp->fr_dsize == 0) + return EINVAL; + if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + break; +#endif + case FR_T_IPF : + if (fp->fr_dsize != sizeof(fripf_t)) + return EINVAL; + + /* + * Allowing a rule with both "keep state" and "with oow" is + * pointless because adding a state entry to the table will + * fail with the out of window (oow) flag set. + */ + if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) + return EINVAL; + + switch (fp->fr_satype) + { + case FRI_BROADCAST : + case FRI_DYNAMIC : + case FRI_NETWORK : + case FRI_NETMASKED : + case FRI_PEERADDR : + if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) { + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + break; +#ifdef IPFILTER_LOOKUP + case FRI_LOOKUP : + fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype, + fp->fr_srcnum, + &fp->fr_srcfunc); + break; +#endif + default : + break; + } + + switch (fp->fr_datype) + { + case FRI_BROADCAST : + case FRI_DYNAMIC : + case FRI_NETWORK : + case FRI_NETMASKED : + case FRI_PEERADDR : + if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) { + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + break; +#ifdef IPFILTER_LOOKUP + case FRI_LOOKUP : + fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype, + fp->fr_dstnum, + &fp->fr_dstfunc); + break; +#endif + default : + + break; + } + break; + case FR_T_NONE : + break; + case FR_T_CALLFUNC : + break; + case FR_T_COMPIPF : + break; + default : + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + + /* + * Lookup all the interface names that are part of the rule. + */ + frsynclist(fp, NULL); + fp->fr_statecnt = 0; + + /* + * Look for an existing matching filter rule, but don't include the + * next or interface pointer in the comparison (fr_next, fr_ifa). + * This elminates rules which are indentical being loaded. Checksum + * the constant part of the filter rule to make comparisons quicker + * (this meaning no pointers are included). + */ + for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; + p < pp; p++) + fp->fr_cksum += *p; + pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); + for (p = (u_int *)fp->fr_data; p < pp; p++) + fp->fr_cksum += *p; + + WRITE_ENTER(&ipf_mutex); + bzero((char *)frcache, sizeof(frcache)); + + for (; (f = *ftail) != NULL; ftail = &f->fr_next) + if ((fp->fr_cksum == f->fr_cksum) && + (f->fr_dsize == fp->fr_dsize) && + !bcmp((char *)&f->fr_func, + (char *)&fp->fr_func, FR_CMPSIZ) && + (!ptr || !f->fr_data || + !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize))) + break; + + /* + * If zero'ing statistics, copy current to caller and zero. + */ + if (req == (ioctlcmd_t)SIOCZRLST) { + if (f == NULL) + error = ESRCH; + else { + /* + * Copy and reduce lock because of impending copyout. + * Well we should, but if we do then the atomicity of + * this call and the correctness of fr_hits and + * fr_bytes cannot be guaranteed. As it is, this code + * only resets them to 0 if they are successfully + * copied out into user space. + */ + bcopy((char *)f, (char *)fp, sizeof(*f)); + /* MUTEX_DOWNGRADE(&ipf_mutex); */ + + /* + * When we copy this rule back out, set the data + * pointer to be what it was in user space. + */ + fp->fr_data = uptr; + error = fr_outobj(data, fp, IPFOBJ_FRENTRY); + + if (error == 0) { + if ((f->fr_dsize != 0) && (uptr != NULL)) + error = COPYOUT(f->fr_data, uptr, + f->fr_dsize); + if (error == 0) { + f->fr_hits = 0; + f->fr_bytes = 0; + } + } + } + + if ((ptr != NULL) && (makecopy != 0)) { + KFREES(ptr, fp->fr_dsize); + } + RWLOCK_EXIT(&ipf_mutex); + return error; + } + + if (!f) { + if (req == (ioctlcmd_t)SIOCINAFR || + req == (ioctlcmd_t)SIOCINIFR) { + ftail = fprev; + if (fp->fr_hits != 0) { + while (--fp->fr_hits && (f = *ftail)) + ftail = &f->fr_next; + } + f = NULL; + ptr = NULL; + error = 0; + } + } + + /* + * Request to remove a rule. + */ + if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) { + if (!f) + error = ESRCH; + else { + /* + * Do not allow activity from user space to interfere + * with rules not loaded that way. + */ + if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { + error = EPERM; + goto done; + } + + /* + * Return EBUSY if the rule is being reference by + * something else (eg state information. + */ + if (f->fr_ref > 1) { + error = EBUSY; + goto done; + } +#ifdef IPFILTER_SCAN + if (f->fr_isctag[0] != '\0' && + (f->fr_isc != (struct ipscan *)-1)) + ipsc_detachfr(f); +#endif + if ((fg != NULL) && (fg->fg_head != NULL)) + fg->fg_head->fr_ref--; + if (unit == IPL_LOGAUTH) { + error = fr_preauthcmd(req, f, ftail); + goto done; + } + if (*f->fr_grhead != '\0') + fr_delgroup(f->fr_grhead, unit, set); + fr_fixskip(fprev, f, -1); + *ftail = f->fr_next; + f->fr_next = NULL; + (void)fr_derefrule(&f); + } + } else { + /* + * Not removing, so we must be adding/inserting a rule. + */ + if (f) + error = EEXIST; + else { + if (unit == IPL_LOGAUTH) { + error = fr_preauthcmd(req, fp, ftail); + goto done; + } + if (makecopy) { + KMALLOC(f, frentry_t *); + } else + f = fp; + if (f != NULL) { + if (fg != NULL && fg->fg_head!= NULL ) + fg->fg_head->fr_ref++; + if (fp != f) + bcopy((char *)fp, (char *)f, + sizeof(*f)); + MUTEX_NUKE(&f->fr_lock); + MUTEX_INIT(&f->fr_lock, "filter rule lock"); +#ifdef IPFILTER_SCAN + if (f->fr_isctag[0] != '\0' && + ipsc_attachfr(f)) + f->fr_isc = (struct ipscan *)-1; +#endif + f->fr_hits = 0; + if (makecopy != 0) + f->fr_ref = 1; + f->fr_next = *ftail; + *ftail = f; + if (req == (ioctlcmd_t)SIOCINIFR || + req == (ioctlcmd_t)SIOCINAFR) + fr_fixskip(fprev, f, 1); + f->fr_grp = NULL; + group = f->fr_grhead; + if (*group != '\0') { + fg = fr_addgroup(group, f, f->fr_flags, + unit, set); + if (fg != NULL) + f->fr_grp = &fg->fg_start; + } + } else + error = ENOMEM; + } + } +done: + RWLOCK_EXIT(&ipf_mutex); + if ((ptr != NULL) && (error != 0) && (makecopy != 0)) { + KFREES(ptr, fp->fr_dsize); + } + return (error); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_funcinit */ +/* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ +/* Parameters: fr(I) - pointer to filter rule */ +/* */ +/* If a rule is a call rule, then check if the function it points to needs */ +/* an init function to be called now the rule has been loaded. */ +/* ------------------------------------------------------------------------ */ +static int fr_funcinit(fr) +frentry_t *fr; +{ + ipfunc_resolve_t *ft; + int err; + + err = ESRCH; + + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (ft->ipfu_addr == fr->fr_func) { + err = 0; + if (ft->ipfu_init != NULL) + err = (*ft->ipfu_init)(fr); + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_findfunc */ +/* Returns: ipfunc_t - pointer to function if found, else NULL */ +/* Parameters: funcptr(I) - function pointer to lookup */ +/* */ +/* Look for a function in the table of known functions. */ +/* ------------------------------------------------------------------------ */ +static ipfunc_t fr_findfunc(funcptr) +ipfunc_t funcptr; +{ + ipfunc_resolve_t *ft; + + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (ft->ipfu_addr == funcptr) + return funcptr; + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_resolvefunc */ +/* Returns: int - 0 == success, else error */ +/* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ +/* */ +/* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ +/* This will either be the function name (if the pointer is set) or the */ +/* function pointer if the name is set. When found, fill in the other one */ +/* so that the entire, complete, structure can be copied back to user space.*/ +/* ------------------------------------------------------------------------ */ +int fr_resolvefunc(data) +void *data; +{ + ipfunc_resolve_t res, *ft; + + BCOPYIN(data, &res, sizeof(res)); + + if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (strncmp(res.ipfu_name, ft->ipfu_name, + sizeof(res.ipfu_name)) == 0) { + res.ipfu_addr = ft->ipfu_addr; + res.ipfu_init = ft->ipfu_init; + if (COPYOUT(&res, data, sizeof(res)) != 0) + return EFAULT; + return 0; + } + } + if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (ft->ipfu_addr == res.ipfu_addr) { + (void) strncpy(res.ipfu_name, ft->ipfu_name, + sizeof(res.ipfu_name)); + res.ipfu_init = ft->ipfu_init; + if (COPYOUT(&res, data, sizeof(res)) != 0) + return EFAULT; + return 0; + } + } + return ESRCH; +} + + +#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \ + (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \ + (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \ + (defined(__OpenBSD__) && (OpenBSD < 200006)) +/* + * From: NetBSD + * ppsratecheck(): packets (or events) per second limitation. + */ +int +ppsratecheck(lasttime, curpps, maxpps) + struct timeval *lasttime; + int *curpps; + int maxpps; /* maximum pps allowed */ +{ + struct timeval tv, delta; + int rv; + + GETKTIME(&tv); + + delta.tv_sec = tv.tv_sec - lasttime->tv_sec; + delta.tv_usec = tv.tv_usec - lasttime->tv_usec; + if (delta.tv_usec < 0) { + delta.tv_sec--; + delta.tv_usec += 1000000; + } + + /* + * check for 0,0 is so that the message will be seen at least once. + * if more than one second have passed since the last update of + * lasttime, reset the counter. + * + * we do increment *curpps even in *curpps < maxpps case, as some may + * try to use *curpps for stat purposes as well. + */ + if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || + delta.tv_sec >= 1) { + *lasttime = tv; + *curpps = 0; + rv = 1; + } else if (maxpps < 0) + rv = 1; + else if (*curpps < maxpps) + rv = 1; + else + rv = 0; + *curpps = *curpps + 1; + + return (rv); +} +#endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_derefrule */ +/* Returns: int - 0 == rule freed up, else rule not freed */ +/* Parameters: fr(I) - pointer to filter rule */ +/* */ +/* Decrement the reference counter to a rule by one. If it reaches zero, */ +/* free it and any associated storage space being used by it. */ +/* ------------------------------------------------------------------------ */ +int fr_derefrule(frp) +frentry_t **frp; +{ + frentry_t *fr; + + fr = *frp; + + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref--; + if (fr->fr_ref == 0) { + MUTEX_EXIT(&fr->fr_lock); + MUTEX_DESTROY(&fr->fr_lock); + +#ifdef IPFILTER_LOOKUP + if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP) + ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr); + if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP) + ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr); +#endif + + if (fr->fr_dsize) { + KFREES(fr->fr_data, fr->fr_dsize); + } + if ((fr->fr_flags & FR_COPIED) != 0) { + KFREE(fr); + return 0; + } + return 1; + } else { + MUTEX_EXIT(&fr->fr_lock); + } + *frp = NULL; + return -1; +} + + +#ifdef IPFILTER_LOOKUP +/* ------------------------------------------------------------------------ */ +/* Function: fr_grpmapinit */ +/* Returns: int - 0 == success, else ESRCH because table entry not found*/ +/* Parameters: fr(I) - pointer to rule to find hash table for */ +/* */ +/* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ +/* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */ +/* ------------------------------------------------------------------------ */ +static int fr_grpmapinit(fr) +frentry_t *fr; +{ + char name[FR_GROUPLEN]; + iphtable_t *iph; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%d", fr->fr_arg); +#else + (void) sprintf(name, "%d", fr->fr_arg); +#endif + iph = fr_findhtable(IPL_LOGIPF, name); + if (iph == NULL) + return ESRCH; + if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) + return ESRCH; + fr->fr_ptr = iph; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_srcgrpmap */ +/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Look for a rule group head in a hash table, using the source address as */ +/* the key, and descend into that group and continue matching rules against */ +/* the packet. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_srcgrpmap(fin, passp) fr_info_t *fin; -int len; -void *ipin; +u_32_t *passp; { -# if SOLARIS - qif_t *qf = fin->fin_qif; -# endif - int out = fin->fin_out, dpoff, ipoff; - char *ip; + frgroup_t *fg; + void *rval; - if (m == NULL) + rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_src); + if (rval == NULL) return NULL; - ipoff = (char *)ipin - MTOD(m, char *); - if (fin->fin_dp != NULL) - dpoff = (char *)fin->fin_dp - (char *)ipin; + fg = rval; + fin->fin_fr = fg->fg_start; + (void) fr_scanlist(fin, *passp); + return fin->fin_fr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_dstgrpmap */ +/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Look for a rule group head in a hash table, using the destination */ +/* address as the key, and descend into that group and continue matching */ +/* rules against the packet. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_dstgrpmap(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + frgroup_t *fg; + void *rval; + + rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_dst); + if (rval == NULL) + return NULL; + + fg = rval; + fin->fin_fr = fg->fg_start; + (void) fr_scanlist(fin, *passp); + return fin->fin_fr; +} +#endif /* IPFILTER_LOOKUP */ + +/* + * Queue functions + * =============== + * These functions manage objects on queues for efficient timeouts. There are + * a number of system defined queues as well as user defined timeouts. It is + * expected that a lock is held in the domain in which the queue belongs + * (i.e. either state or NAT) when calling any of these functions that prevents + * fr_freetimeoutqueue() from being called at the same time as any other. + */ + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_addtimeoutqueue */ +/* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ +/* timeout queue with given interval. */ +/* Parameters: parent(I) - pointer to pointer to parent node of this list */ +/* of interface queues. */ +/* seconds(I) - timeout value in seconds for this queue. */ +/* */ +/* This routine first looks for a timeout queue that matches the interval */ +/* being requested. If it finds one, increments the reference counter and */ +/* returns a pointer to it. If none are found, it allocates a new one and */ +/* inserts it at the top of the list. */ +/* */ +/* Locking. */ +/* It is assumed that the caller of this function has an appropriate lock */ +/* held (exclusively) in the domain that encompases 'parent'. */ +/* ------------------------------------------------------------------------ */ +ipftq_t *fr_addtimeoutqueue(parent, seconds) +ipftq_t **parent; +u_int seconds; +{ + ipftq_t *ifq; + u_int period; + + period = seconds * IPF_HZ_DIVIDE; + + MUTEX_ENTER(&ipf_timeoutlock); + for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { + if (ifq->ifq_ttl == period) { + /* + * Reset the delete flag, if set, so the structure + * gets reused rather than freed and reallocated. + */ + MUTEX_ENTER(&ifq->ifq_lock); + ifq->ifq_flags &= ~IFQF_DELETE; + ifq->ifq_ref++; + MUTEX_EXIT(&ifq->ifq_lock); + MUTEX_EXIT(&ipf_timeoutlock); + + return ifq; + } + } + + KMALLOC(ifq, ipftq_t *); + if (ifq != NULL) { + ifq->ifq_ttl = period; + ifq->ifq_head = NULL; + ifq->ifq_tail = &ifq->ifq_head; + ifq->ifq_next = *parent; + ifq->ifq_pnext = parent; + ifq->ifq_ref = 1; + ifq->ifq_flags = IFQF_USER; + *parent = ifq; + fr_userifqs++; + MUTEX_NUKE(&ifq->ifq_lock); + MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex"); + } + MUTEX_EXIT(&ipf_timeoutlock); + return ifq; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_deletetimeoutqueue */ +/* Returns: int - new reference count value of the timeout queue */ +/* Parameters: ifq(I) - timeout queue which is losing a reference. */ +/* Locks: ifq->ifq_lock */ +/* */ +/* This routine must be called when we're discarding a pointer to a timeout */ +/* queue object, taking care of the reference counter. */ +/* */ +/* Now that this just sets a DELETE flag, it requires the expire code to */ +/* check the list of user defined timeout queues and call the free function */ +/* below (currently commented out) to stop memory leaking. It is done this */ +/* way because the locking may not be sufficient to safely do a free when */ +/* this function is called. */ +/* ------------------------------------------------------------------------ */ +int fr_deletetimeoutqueue(ifq) +ipftq_t *ifq; +{ + + ifq->ifq_ref--; + if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { + ifq->ifq_flags |= IFQF_DELETE; + } + + return ifq->ifq_ref; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_freetimeoutqueue */ +/* Parameters: ifq(I) - timeout queue which is losing a reference. */ +/* Returns: Nil */ +/* */ +/* Locking: */ +/* It is assumed that the caller of this function has an appropriate lock */ +/* held (exclusively) in the domain that encompases the callers "domain". */ +/* The ifq_lock for this structure should not be held. */ +/* */ +/* Remove a user definde timeout queue from the list of queues it is in and */ +/* tidy up after this is done. */ +/* ------------------------------------------------------------------------ */ +void fr_freetimeoutqueue(ifq) +ipftq_t *ifq; +{ + + + if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || + ((ifq->ifq_flags & IFQF_USER) == 0)) { + printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", + (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, + ifq->ifq_ref); + return; + } + + /* + * Remove from its position in the list. + */ + *ifq->ifq_pnext = ifq->ifq_next; + if (ifq->ifq_next != NULL) + ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; + + MUTEX_DESTROY(&ifq->ifq_lock); + fr_userifqs--; + KFREE(ifq); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_deletequeueentry */ +/* Returns: Nil */ +/* Parameters: tqe(I) - timeout queue entry to delete */ +/* ifq(I) - timeout queue to remove entry from */ +/* */ +/* Remove a tail queue entry from its queue and make it an orphan. */ +/* fr_deletetimeoutqueue is called to make sure the reference count on the */ +/* queue is correct. We can't, however, call fr_freetimeoutqueue because */ +/* the correct lock(s) may not be held that would make it safe to do so. */ +/* ------------------------------------------------------------------------ */ +void fr_deletequeueentry(tqe) +ipftqent_t *tqe; +{ + ipftq_t *ifq; + + ifq = tqe->tqe_ifq; + if (ifq == NULL) + return; + + MUTEX_ENTER(&ifq->ifq_lock); + + if (tqe->tqe_pnext != NULL) { + *tqe->tqe_pnext = tqe->tqe_next; + if (tqe->tqe_next != NULL) + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + else /* we must be the tail anyway */ + ifq->ifq_tail = tqe->tqe_pnext; + + tqe->tqe_pnext = NULL; + tqe->tqe_ifq = NULL; + } + + (void) fr_deletetimeoutqueue(ifq); + + MUTEX_EXIT(&ifq->ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_queuefront */ +/* Returns: Nil */ +/* Parameters: tqe(I) - pointer to timeout queue entry */ +/* */ +/* Move a queue entry to the front of the queue, if it isn't already there. */ +/* ------------------------------------------------------------------------ */ +void fr_queuefront(tqe) +ipftqent_t *tqe; +{ + ipftq_t *ifq; + + ifq = tqe->tqe_ifq; + if (ifq == NULL) + return; + + MUTEX_ENTER(&ifq->ifq_lock); + if (ifq->ifq_head != tqe) { + *tqe->tqe_pnext = tqe->tqe_next; + if (tqe->tqe_next) + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + else + ifq->ifq_tail = tqe->tqe_pnext; + + tqe->tqe_next = ifq->ifq_head; + ifq->ifq_head->tqe_pnext = &tqe->tqe_next; + ifq->ifq_head = tqe; + tqe->tqe_pnext = &ifq->ifq_head; + } + MUTEX_EXIT(&ifq->ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_queueback */ +/* Returns: Nil */ +/* Parameters: tqe(I) - pointer to timeout queue entry */ +/* */ +/* Move a queue entry to the back of the queue, if it isn't already there. */ +/* ------------------------------------------------------------------------ */ +void fr_queueback(tqe) +ipftqent_t *tqe; +{ + ipftq_t *ifq; + + ifq = tqe->tqe_ifq; + if (ifq == NULL) + return; + tqe->tqe_die = fr_ticks + ifq->ifq_ttl; + + MUTEX_ENTER(&ifq->ifq_lock); + if (tqe->tqe_next == NULL) { /* at the end already ? */ + MUTEX_EXIT(&ifq->ifq_lock); + return; + } + + /* + * Remove from list + */ + *tqe->tqe_pnext = tqe->tqe_next; + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + + /* + * Make it the last entry. + */ + tqe->tqe_next = NULL; + tqe->tqe_pnext = ifq->ifq_tail; + *ifq->ifq_tail = tqe; + ifq->ifq_tail = &tqe->tqe_next; + MUTEX_EXIT(&ifq->ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_queueappend */ +/* Returns: Nil */ +/* Parameters: tqe(I) - pointer to timeout queue entry */ +/* ifq(I) - pointer to timeout queue */ +/* parent(I) - owing object pointer */ +/* */ +/* Add a new item to this queue and put it on the very end. */ +/* ------------------------------------------------------------------------ */ +void fr_queueappend(tqe, ifq, parent) +ipftqent_t *tqe; +ipftq_t *ifq; +void *parent; +{ + + MUTEX_ENTER(&ifq->ifq_lock); + tqe->tqe_parent = parent; + tqe->tqe_pnext = ifq->ifq_tail; + *ifq->ifq_tail = tqe; + ifq->ifq_tail = &tqe->tqe_next; + tqe->tqe_next = NULL; + tqe->tqe_ifq = ifq; + tqe->tqe_die = fr_ticks + ifq->ifq_ttl; + ifq->ifq_ref++; + MUTEX_EXIT(&ifq->ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_movequeue */ +/* Returns: Nil */ +/* Parameters: tq(I) - pointer to timeout queue information */ +/* oifp(I) - old timeout queue entry was on */ +/* nifp(I) - new timeout queue to put entry on */ +/* */ +/* Move a queue entry from one timeout queue to another timeout queue. */ +/* If it notices that the current entry is already last and does not need */ +/* to move queue, the return. */ +/* ------------------------------------------------------------------------ */ +void fr_movequeue(tqe, oifq, nifq) +ipftqent_t *tqe; +ipftq_t *oifq, *nifq; +{ + /* + * Is the operation here going to be a no-op ? + */ + MUTEX_ENTER(&oifq->ifq_lock); + if (oifq == nifq && *oifq->ifq_tail == tqe) { + MUTEX_EXIT(&oifq->ifq_lock); + return; + } + + /* + * Remove from the old queue + */ + *tqe->tqe_pnext = tqe->tqe_next; + if (tqe->tqe_next) + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; else - dpoff = 0; + oifq->ifq_tail = tqe->tqe_pnext; + tqe->tqe_next = NULL; - if (M_BLEN(m) < len) { -# if SOLARIS - qif_t *qf = fin->fin_qif; - int inc = 0; - - if (ipoff > 0) { - if ((ipoff & 3) != 0) { - inc = 4 - (ipoff & 3); - if (m->b_rptr - inc >= m->b_datap->db_base) - m->b_rptr -= inc; + /* + * If we're moving from one queue to another, release the lock on the + * old queue and get a lock on the new queue. For user defined queues, + * if we're moving off it, call delete in case it can now be freed. + */ + if (oifq != nifq) { + tqe->tqe_ifq = NULL; + + (void) fr_deletetimeoutqueue(oifq); + + MUTEX_EXIT(&oifq->ifq_lock); + + MUTEX_ENTER(&nifq->ifq_lock); + + tqe->tqe_ifq = nifq; + nifq->ifq_ref++; + } + + /* + * Add to the bottom of the new queue + */ + tqe->tqe_die = fr_ticks + nifq->ifq_ttl; + tqe->tqe_pnext = nifq->ifq_tail; + *nifq->ifq_tail = tqe; + nifq->ifq_tail = &tqe->tqe_next; + MUTEX_EXIT(&nifq->ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_updateipid */ +/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* When we are doing NAT, change the IP of every packet to represent a */ +/* single sequence of packets coming from the host, hiding any host */ +/* specific sequencing that might otherwise be revealed. If the packet is */ +/* a fragment, then store the 'new' IPid in the fragment cache and look up */ +/* the fragment cache for non-leading fragments. If a non-leading fragment */ +/* has no match in the cache, return an error. */ +/* ------------------------------------------------------------------------ */ +static INLINE int fr_updateipid(fin) +fr_info_t *fin; +{ + u_short id, ido, sums; + u_32_t sumd, sum; + ip_t *ip; + + if (fin->fin_off != 0) { + sum = fr_ipid_knownfrag(fin); + if (sum == 0xffffffff) + return -1; + sum &= 0xffff; + id = (u_short)sum; + } else { + id = fr_nextipid(fin); + if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) + (void) fr_ipid_newfrag(fin, (u_32_t)id); + } + + ip = fin->fin_ip; + ido = ntohs(ip->ip_id); + if (id == ido) + return 0; + ip->ip_id = htons(id); + CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ + sum = (~ntohs(ip->ip_sum)) & 0xffff; + sum += sumd; + sum = (sum >> 16) + (sum & 0xffff); + sum = (sum >> 16) + (sum & 0xffff); + sums = ~(u_short)sum; + ip->ip_sum = htons(sums); + return 0; +} + + +#ifdef NEED_FRGETIFNAME +/* ------------------------------------------------------------------------ */ +/* Function: fr_getifname */ +/* Returns: char * - pointer to interface name */ +/* Parameters: ifp(I) - pointer to network interface */ +/* buffer(O) - pointer to where to store interface name */ +/* */ +/* Constructs an interface name in the buffer passed. The buffer passed is */ +/* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ +/* as a NULL pointer then return a pointer to a static array. */ +/* ------------------------------------------------------------------------ */ +char *fr_getifname(ifp, buffer) +struct ifnet *ifp; +char *buffer; +{ + static char namebuf[LIFNAMSIZ]; +# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ + defined(__sgi) || defined(linux) || \ + (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) + int unit, space; + char temp[20]; + char *s; +# endif + + if (buffer == NULL) + buffer = namebuf; + (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); + buffer[LIFNAMSIZ - 1] = '\0'; +# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ + defined(__sgi) || \ + (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) + for (s = buffer; *s; s++) + ; + unit = ifp->if_unit; + space = LIFNAMSIZ - (s - buffer); + if (space > 0) { +# if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(temp, sizeof(temp), "%d", unit); +# else + (void) sprintf(temp, "%d", unit); +# endif + (void) strncpy(s, temp, space); + } +# endif + return buffer; +} +#endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ioctlswitch */ +/* Returns: int - -1 continue processing, else ioctl return value */ +/* Parameters: unit(I) - device unit opened */ +/* data(I) - pointer to ioctl data */ +/* cmd(I) - ioctl command */ +/* mode(I) - mode value */ +/* */ +/* Based on the value of unit, call the appropriate ioctl handler or return */ +/* EIO if ipfilter is not running. Also checks if write perms are req'd */ +/* for the device in order to execute the ioctl. */ +/* ------------------------------------------------------------------------ */ +int fr_ioctlswitch(unit, data, cmd, mode) +int unit, mode; +ioctlcmd_t cmd; +void *data; +{ + int error = 0; + + switch (unit) + { + case IPL_LOGIPF : + error = -1; + break; + case IPL_LOGNAT : + if (fr_running > 0) + error = fr_nat_ioctl(data, cmd, mode); + else + error = EIO; + break; + case IPL_LOGSTATE : + if (fr_running > 0) + error = fr_state_ioctl(data, cmd, mode); + else + error = EIO; + break; + case IPL_LOGAUTH : + if (fr_running > 0) { + if ((cmd == (ioctlcmd_t)SIOCADAFR) || + (cmd == (ioctlcmd_t)SIOCRMAFR)) { + if (!(mode & FWRITE)) { + error = EPERM; + } else { + error = frrequest(unit, cmd, data, + fr_active, 1); + } + } else { + error = fr_auth_ioctl(data, cmd, mode); + } + } else + error = EIO; + break; + case IPL_LOGSYNC : +#ifdef IPFILTER_SYNC + if (fr_running > 0) + error = fr_sync_ioctl(data, cmd, mode); + else +#endif + error = EIO; + break; + case IPL_LOGSCAN : +#ifdef IPFILTER_SCAN + if (fr_running > 0) + error = fr_scan_ioctl(data, cmd, mode); + else +#endif + error = EIO; + break; + case IPL_LOGLOOKUP : +#ifdef IPFILTER_LOOKUP + if (fr_running > 0) + error = ip_lookup_ioctl(data, cmd, mode); + else +#endif + error = EIO; + break; + default : + error = EIO; + break; + } + + return error; +} + + +/* + * This array defines the expected size of objects coming into the kernel + * for the various recognised object types. + */ +#define NUM_OBJ_TYPES 14 + +static int fr_objbytes[NUM_OBJ_TYPES][2] = { + { 1, sizeof(struct frentry) }, /* frentry */ + { 0, sizeof(struct friostat) }, + { 0, sizeof(struct fr_info) }, + { 0, sizeof(struct fr_authstat) }, + { 0, sizeof(struct ipfrstat) }, + { 0, sizeof(struct ipnat) }, + { 0, sizeof(struct natstat) }, + { 0, sizeof(struct ipstate_save) }, + { 1, sizeof(struct nat_save) }, /* nat_save */ + { 0, sizeof(struct natlookup) }, + { 1, sizeof(struct ipstate) }, /* ipstate */ + { 0, sizeof(struct ips_stat) }, + { 0, sizeof(struct frauth) }, + { 0, sizeof(struct ipftune) } +}; + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_inobj */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* ptr(I) - pointer to store real data in */ +/* type(I) - type of structure being moved */ +/* */ +/* Copy in the contents of what the ipfobj_t points to. In future, we */ +/* add things to check for version numbers, sizes, etc, to make it backward */ +/* compatible at the ABI for user land. */ +/* ------------------------------------------------------------------------ */ +int fr_inobj(data, ptr, type) +void *data; +void *ptr; +int type; +{ + ipfobj_t obj; + int error = 0; + + if ((type < 0) || (type > NUM_OBJ_TYPES-1)) + return EINVAL; + + BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); + + if (obj.ipfo_type != type) + return EINVAL; + +#ifndef IPFILTER_COMPAT + if ((fr_objbytes[type][0] & 1) != 0) { + if (obj.ipfo_size < fr_objbytes[type][1]) + return EINVAL; + } else if (obj.ipfo_size != fr_objbytes[type][1]) + return EINVAL; +#else + if (obj.ipfo_rev != IPFILTER_VERSION) + /* XXX compatibility hook here */ + ; + if ((fr_objbytes[type][0] & 1) != 0) { + if (obj.ipfo_size < fr_objbytes[type][1]) + /* XXX compatibility hook here */ + return EINVAL; + } else if (obj.ipfo_size != fr_objbytes[type][1]) + /* XXX compatibility hook here */ + return EINVAL; +#endif + + if ((fr_objbytes[type][0] & 1) != 0) { + error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, + fr_objbytes[type][1]); + } else { + error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, + obj.ipfo_size); + } + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_inobjsz */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* ptr(I) - pointer to store real data in */ +/* type(I) - type of structure being moved */ +/* sz(I) - size of data to copy */ +/* */ +/* As per fr_inobj, except the size of the object to copy in is passed in */ +/* but it must not be smaller than the size defined for the type and the */ +/* type must allow for varied sized objects. The extra requirement here is */ +/* that sz must match the size of the object being passed in - this is not */ +/* not possible nor required in fr_inobj(). */ +/* ------------------------------------------------------------------------ */ +int fr_inobjsz(data, ptr, type, sz) +void *data; +void *ptr; +int type, sz; +{ + ipfobj_t obj; + int error; + + if ((type < 0) || (type > NUM_OBJ_TYPES-1)) + return EINVAL; + if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1])) + return EINVAL; + + BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); + + if (obj.ipfo_type != type) + return EINVAL; + +#ifndef IPFILTER_COMPAT + if (obj.ipfo_size != sz) + return EINVAL; +#else + if (obj.ipfo_rev != IPFILTER_VERSION) + /* XXX compatibility hook here */ + ; + if (obj.ipfo_size != sz) + /* XXX compatibility hook here */ + return EINVAL; +#endif + + error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, sz); + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_outobjsz */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* ptr(I) - pointer to store real data in */ +/* type(I) - type of structure being moved */ +/* sz(I) - size of data to copy */ +/* */ +/* As per fr_outobj, except the size of the object to copy out is passed in */ +/* but it must not be smaller than the size defined for the type and the */ +/* type must allow for varied sized objects. The extra requirement here is */ +/* that sz must match the size of the object being passed in - this is not */ +/* not possible nor required in fr_outobj(). */ +/* ------------------------------------------------------------------------ */ +int fr_outobjsz(data, ptr, type, sz) +void *data; +void *ptr; +int type, sz; +{ + ipfobj_t obj; + int error; + + if ((type < 0) || (type > NUM_OBJ_TYPES-1) || + ((fr_objbytes[type][0] & 1) == 0) || + (sz < fr_objbytes[type][1])) + return EINVAL; + + BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); + + if (obj.ipfo_type != type) + return EINVAL; + +#ifndef IPFILTER_COMPAT + if (obj.ipfo_size != sz) + return EINVAL; +#else + if (obj.ipfo_rev != IPFILTER_VERSION) + /* XXX compatibility hook here */ + ; + if (obj.ipfo_size != sz) + /* XXX compatibility hook here */ + return EINVAL; +#endif + + error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, sz); + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_outobj */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* ptr(I) - pointer to store real data in */ +/* type(I) - type of structure being moved */ +/* */ +/* Copy out the contents of what ptr is to where ipfobj points to. In */ +/* future, we add things to check for version numbers, sizes, etc, to make */ +/* it backward compatible at the ABI for user land. */ +/* ------------------------------------------------------------------------ */ +int fr_outobj(data, ptr, type) +void *data; +void *ptr; +int type; +{ + ipfobj_t obj; + int error; + + if ((type < 0) || (type > NUM_OBJ_TYPES-1)) + return EINVAL; + + BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); + + if (obj.ipfo_type != type) + return EINVAL; + +#ifndef IPFILTER_COMPAT + if ((fr_objbytes[type][0] & 1) != 0) { + if (obj.ipfo_size < fr_objbytes[type][1]) + return EINVAL; + } else if (obj.ipfo_size != fr_objbytes[type][1]) + return EINVAL; +#else + if (obj.ipfo_rev != IPFILTER_VERSION) + /* XXX compatibility hook here */ + ; + if ((fr_objbytes[type][0] & 1) != 0) { + if (obj.ipfo_size < fr_objbytes[type][1]) + /* XXX compatibility hook here */ + return EINVAL; + } else if (obj.ipfo_size != fr_objbytes[type][1]) + /* XXX compatibility hook here */ + return EINVAL; +#endif + + error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size); + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkl4sum */ +/* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* If possible, calculate the layer 4 checksum for the packet. If this is */ +/* not possible, return without indicating a failure or success but in a */ +/* way that is ditinguishable. */ +/* ------------------------------------------------------------------------ */ +int fr_checkl4sum(fin) +fr_info_t *fin; +{ + u_short sum, hdrsum, *csump; + udphdr_t *udp; + int dosum; + + if ((fin->fin_flx & FI_NOCKSUM) != 0) + return 0; + + /* + * If the TCP packet isn't a fragment, isn't too short and otherwise + * isn't already considered "bad", then validate the checksum. If + * this check fails then considered the packet to be "bad". + */ + if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) + return 1; + + csump = NULL; + hdrsum = 0; + dosum = 0; + sum = 0; + +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) + if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) { + hdrsum = 0; + sum = 0; + } else { +#endif + switch (fin->fin_p) + { + case IPPROTO_TCP : + csump = &((tcphdr_t *)fin->fin_dp)->th_sum; + dosum = 1; + break; + + case IPPROTO_UDP : + udp = fin->fin_dp; + if (udp->uh_sum != 0) { + csump = &udp->uh_sum; + dosum = 1; + } + break; + + case IPPROTO_ICMP : + csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; + dosum = 1; + break; + + default : + return 1; + /*NOTREACHED*/ + } + + if (csump != NULL) + hdrsum = *csump; + + if (dosum) + sum = fr_cksum(fin->fin_m, fin->fin_ip, + fin->fin_p, fin->fin_dp); +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) + } +#endif +#if !defined(_KERNEL) + if (sum == hdrsum) { + FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); + } else { + FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); + } +#endif + if (hdrsum == sum) + return 0; + return -1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ifpfillv4addr */ +/* Returns: int - 0 = address update, -1 = address not updated */ +/* Parameters: atype(I) - type of network address update to perform */ +/* sin(I) - pointer to source of address information */ +/* mask(I) - pointer to source of netmask information */ +/* inp(I) - pointer to destination address store */ +/* inpmask(I) - pointer to destination netmask store */ +/* */ +/* Given a type of network address update (atype) to perform, copy */ +/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ +/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ +/* which case the operation fails. For all values of atype other than */ +/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ +/* value. */ +/* ------------------------------------------------------------------------ */ +int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask) +int atype; +struct sockaddr_in *sin, *mask; +struct in_addr *inp, *inpmask; +{ + if (inpmask != NULL && atype != FRI_NETMASKED) + inpmask->s_addr = 0xffffffff; + + if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { + if (atype == FRI_NETMASKED) { + if (inpmask == NULL) + return -1; + inpmask->s_addr = mask->sin_addr.s_addr; + } + inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; + } else { + inp->s_addr = sin->sin_addr.s_addr; + } + return 0; +} + + +#ifdef USE_INET6 +/* ------------------------------------------------------------------------ */ +/* Function: fr_ifpfillv6addr */ +/* Returns: int - 0 = address update, -1 = address not updated */ +/* Parameters: atype(I) - type of network address update to perform */ +/* sin(I) - pointer to source of address information */ +/* mask(I) - pointer to source of netmask information */ +/* inp(I) - pointer to destination address store */ +/* inpmask(I) - pointer to destination netmask store */ +/* */ +/* Given a type of network address update (atype) to perform, copy */ +/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ +/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ +/* which case the operation fails. For all values of atype other than */ +/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ +/* value. */ +/* ------------------------------------------------------------------------ */ +int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask) +int atype; +struct sockaddr_in6 *sin, *mask; +struct in_addr *inp, *inpmask; +{ + i6addr_t *src, *dst, *and, *dmask; + + src = (i6addr_t *)&sin->sin6_addr; + and = (i6addr_t *)&mask->sin6_addr; + dst = (i6addr_t *)inp; + dmask = (i6addr_t *)inpmask; + + if (inpmask != NULL && atype != FRI_NETMASKED) { + dmask->i6[0] = 0xffffffff; + dmask->i6[1] = 0xffffffff; + dmask->i6[2] = 0xffffffff; + dmask->i6[3] = 0xffffffff; + } + + if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { + if (atype == FRI_NETMASKED) { + if (inpmask == NULL) + return -1; + dmask->i6[0] = and->i6[0]; + dmask->i6[1] = and->i6[1]; + dmask->i6[2] = and->i6[2]; + dmask->i6[3] = and->i6[3]; + } + + dst->i6[0] = src->i6[0] & and->i6[0]; + dst->i6[1] = src->i6[1] & and->i6[1]; + dst->i6[2] = src->i6[2] & and->i6[2]; + dst->i6[3] = src->i6[3] & and->i6[3]; + } else { + dst->i6[0] = src->i6[0]; + dst->i6[1] = src->i6[1]; + dst->i6[2] = src->i6[2]; + dst->i6[3] = src->i6[3]; + } + return 0; +} +#endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_matchtag */ +/* Returns: 0 == mismatch, 1 == match. */ +/* Parameters: tag1(I) - pointer to first tag to compare */ +/* tag2(I) - pointer to second tag to compare */ +/* */ +/* Returns true (non-zero) or false(0) if the two tag structures can be */ +/* considered to be a match or not match, respectively. The tag is 16 */ +/* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ +/* compare the ints instead, for speed. tag1 is the master of the */ +/* comparison. This function should only be called with both tag1 and tag2 */ +/* as non-NULL pointers. */ +/* ------------------------------------------------------------------------ */ +int fr_matchtag(tag1, tag2) +ipftag_t *tag1, *tag2; +{ + if (tag1 == tag2) + return 1; + + if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) + return 1; + + if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && + (tag1->ipt_num[1] == tag2->ipt_num[1]) && + (tag1->ipt_num[2] == tag2->ipt_num[2]) && + (tag1->ipt_num[3] == tag2->ipt_num[3])) + return 1; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_coalesce */ +/* Returns: 1 == success, -1 == failure, 0 == no change */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Attempt to get all of the packet data into a single, contiguous buffer. */ +/* If this call returns a failure then the buffers have also been freed. */ +/* ------------------------------------------------------------------------ */ +int fr_coalesce(fin) +fr_info_t *fin; +{ + if ((fin->fin_flx & FI_COALESCE) != 0) + return 1; + + /* + * If the mbuf pointers indicate that there is no mbuf to work with, + * return but do not indicate success or failure. + */ + if (fin->fin_m == NULL || fin->fin_mp == NULL) + return 0; + +#if defined(_KERNEL) + if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { + ATOMIC_INCL(fr_badcoalesces[fin->fin_out]); +# ifdef MENTAT + FREE_MB_T(*fin->fin_mp); +# endif + *fin->fin_mp = NULL; + fin->fin_m = NULL; + return -1; + } +#else + fin = fin; /* LINT */ +#endif + return 1; +} + + +/* + * The following table lists all of the tunable variables that can be + * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row + * in the table below is as follows: + * + * pointer to value, name of value, minimum, maximum, size of the value's + * container, value attribute flags + * + * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED + * means the value can only be written to when IPFilter is loaded but disabled. + * The obvious implication is if neither of these are set then the value can be + * changed at any time without harm. + */ +ipftuneable_t ipf_tuneables[] = { + /* filtering */ + { { &fr_flags }, "fr_flags", 0, 0xffffffff, + sizeof(fr_flags), 0 }, + { { &fr_active }, "fr_active", 0, 0, + sizeof(fr_active), IPFT_RDONLY }, + { { &fr_control_forwarding }, "fr_control_forwarding", 0, 1, + sizeof(fr_control_forwarding), 0 }, + { { &fr_update_ipid }, "fr_update_ipid", 0, 1, + sizeof(fr_update_ipid), 0 }, + { { &fr_chksrc }, "fr_chksrc", 0, 1, + sizeof(fr_chksrc), 0 }, + { { &fr_pass }, "fr_pass", 0, 0xffffffff, + sizeof(fr_pass), 0 }, + /* state */ + { { &fr_tcpidletimeout }, "fr_tcpidletimeout", 1, 0x7fffffff, + sizeof(fr_tcpidletimeout), IPFT_WRDISABLED }, + { { &fr_tcpclosewait }, "fr_tcpclosewait", 1, 0x7fffffff, + sizeof(fr_tcpclosewait), IPFT_WRDISABLED }, + { { &fr_tcplastack }, "fr_tcplastack", 1, 0x7fffffff, + sizeof(fr_tcplastack), IPFT_WRDISABLED }, + { { &fr_tcptimeout }, "fr_tcptimeout", 1, 0x7fffffff, + sizeof(fr_tcptimeout), IPFT_WRDISABLED }, + { { &fr_tcpclosed }, "fr_tcpclosed", 1, 0x7fffffff, + sizeof(fr_tcpclosed), IPFT_WRDISABLED }, + { { &fr_tcphalfclosed }, "fr_tcphalfclosed", 1, 0x7fffffff, + sizeof(fr_tcphalfclosed), IPFT_WRDISABLED }, + { { &fr_udptimeout }, "fr_udptimeout", 1, 0x7fffffff, + sizeof(fr_udptimeout), IPFT_WRDISABLED }, + { { &fr_udpacktimeout }, "fr_udpacktimeout", 1, 0x7fffffff, + sizeof(fr_udpacktimeout), IPFT_WRDISABLED }, + { { &fr_icmptimeout }, "fr_icmptimeout", 1, 0x7fffffff, + sizeof(fr_icmptimeout), IPFT_WRDISABLED }, + { { &fr_icmpacktimeout }, "fr_icmpacktimeout", 1, 0x7fffffff, + sizeof(fr_icmpacktimeout), IPFT_WRDISABLED }, + { { &fr_iptimeout }, "fr_iptimeout", 1, 0x7fffffff, + sizeof(fr_iptimeout), IPFT_WRDISABLED }, + { { &fr_statemax }, "fr_statemax", 1, 0x7fffffff, + sizeof(fr_statemax), 0 }, + { { &fr_statesize }, "fr_statesize", 1, 0x7fffffff, + sizeof(fr_statesize), IPFT_WRDISABLED }, + { { &fr_state_lock }, "fr_state_lock", 0, 1, + sizeof(fr_state_lock), IPFT_RDONLY }, + { { &fr_state_maxbucket }, "fr_state_maxbucket", 1, 0x7fffffff, + sizeof(fr_state_maxbucket), IPFT_WRDISABLED }, + { { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset", 0, 1, + sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED }, + { { &ipstate_logging }, "ipstate_logging", 0, 1, + sizeof(ipstate_logging), 0 }, + /* nat */ + { { &fr_nat_lock }, "fr_nat_lock", 0, 1, + sizeof(fr_nat_lock), IPFT_RDONLY }, + { { &ipf_nattable_sz }, "ipf_nattable_sz", 1, 0x7fffffff, + sizeof(ipf_nattable_sz), IPFT_WRDISABLED }, + { { &ipf_nattable_max }, "ipf_nattable_max", 1, 0x7fffffff, + sizeof(ipf_nattable_max), 0 }, + { { &ipf_natrules_sz }, "ipf_natrules_sz", 1, 0x7fffffff, + sizeof(ipf_natrules_sz), IPFT_WRDISABLED }, + { { &ipf_rdrrules_sz }, "ipf_rdrrules_sz", 1, 0x7fffffff, + sizeof(ipf_rdrrules_sz), IPFT_WRDISABLED }, + { { &ipf_hostmap_sz }, "ipf_hostmap_sz", 1, 0x7fffffff, + sizeof(ipf_hostmap_sz), IPFT_WRDISABLED }, + { { &fr_nat_maxbucket }, "fr_nat_maxbucket", 1, 0x7fffffff, + sizeof(fr_nat_maxbucket), IPFT_WRDISABLED }, + { { &fr_nat_maxbucket_reset }, "fr_nat_maxbucket_reset", 0, 1, + sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED }, + { { &nat_logging }, "nat_logging", 0, 1, + sizeof(nat_logging), 0 }, + { { &fr_defnatage }, "fr_defnatage", 1, 0x7fffffff, + sizeof(fr_defnatage), IPFT_WRDISABLED }, + { { &fr_defnatipage }, "fr_defnatipage", 1, 0x7fffffff, + sizeof(fr_defnatipage), IPFT_WRDISABLED }, + { { &fr_defnaticmpage }, "fr_defnaticmpage", 1, 0x7fffffff, + sizeof(fr_defnaticmpage), IPFT_WRDISABLED }, + /* frag */ + { { &ipfr_size }, "ipfr_size", 1, 0x7fffffff, + sizeof(ipfr_size), IPFT_WRDISABLED }, + { { &fr_ipfrttl }, "fr_ipfrttl", 1, 0x7fffffff, + sizeof(fr_ipfrttl), IPFT_WRDISABLED }, +#ifdef IPFILTER_LOG + /* log */ + { { &ipl_suppress }, "ipl_suppress", 0, 1, + sizeof(ipl_suppress), 0 }, + { { &ipl_buffer_sz }, "ipl_buffer_sz", 0, 0, + sizeof(ipl_buffer_sz), IPFT_RDONLY }, + { { &ipl_logmax }, "ipl_logmax", 0, 0x7fffffff, + sizeof(ipl_logmax), IPFT_WRDISABLED }, + { { &ipl_logall }, "ipl_logall", 0, 1, + sizeof(ipl_logall), 0 }, + { { &ipl_logsize }, "ipl_logsize", 0, 0x80000, + sizeof(ipl_logsize), 0 }, +#endif + { { NULL }, NULL, 0, 0 } +}; + +static ipftuneable_t *ipf_tunelist = NULL; + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_findtunebycookie */ +/* Returns: NULL = search failed, else pointer to tune struct */ +/* Parameters: cookie(I) - cookie value to search for amongst tuneables */ +/* next(O) - pointer to place to store the cookie for the */ +/* "next" tuneable, if it is desired. */ +/* */ +/* This function is used to walk through all of the existing tunables with */ +/* successive calls. It searches the known tunables for the one which has */ +/* a matching value for "cookie" - ie its address. When returning a match, */ +/* the next one to be found may be returned inside next. */ +/* ------------------------------------------------------------------------ */ +static ipftuneable_t *fr_findtunebycookie(cookie, next) +void *cookie, **next; +{ + ipftuneable_t *ta, **tap; + + for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++) + if (ta == cookie) { + if (next != NULL) { + /* + * If the next entry in the array has a name + * present, then return a pointer to it for + * where to go next, else return a pointer to + * the dynaminc list as a key to search there + * next. This facilitates a weak linking of + * the two "lists" together. + */ + if ((ta + 1)->ipft_name != NULL) + *next = ta + 1; else - inc = 0; + *next = &ipf_tunelist; } + return ta; } - if (!pullupmsg(m, len + ipoff + inc)) { - ATOMIC_INCL(frstats[out].fr_pull[1]); - return NULL; + + for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) + if (tap == cookie) { + if (next != NULL) + *next = &ta->ipft_next; + return ta; } - m->b_rptr += inc; - ATOMIC_INCL(frstats[out].fr_pull[0]); - qf->qf_data = MTOD(m, char *) + ipoff; -# else - m = m_pullup(m, len); - *fin->fin_mp = m; - if (m == NULL) { - ATOMIC_INCL(frstats[out].fr_pull[1]); - return NULL; + + if (next != NULL) + *next = NULL; + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_findtunebyname */ +/* Returns: NULL = search failed, else pointer to tune struct */ +/* Parameters: name(I) - name of the tuneable entry to find. */ +/* */ +/* Search the static array of tuneables and the list of dynamic tuneables */ +/* for an entry with a matching name. If we can find one, return a pointer */ +/* to the matching structure. */ +/* ------------------------------------------------------------------------ */ +static ipftuneable_t *fr_findtunebyname(name) +char *name; +{ + ipftuneable_t *ta; + + for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++) + if (!strcmp(ta->ipft_name, name)) { + return ta; + } + + for (ta = ipf_tunelist; ta != NULL; ta = ta->ipft_next) + if (!strcmp(ta->ipft_name, name)) { + return ta; } - ATOMIC_INCL(frstats[out].fr_pull[0]); -# endif /* SOLARIS */ + + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_addipftune */ +/* Returns: int - 0 == success, else failure */ +/* Parameters: newtune - pointer to new tune struct to add to tuneables */ +/* */ +/* Appends the tune structure pointer to by "newtune" to the end of the */ +/* current list of "dynamic" tuneable parameters. Once added, the owner */ +/* of the object is not expected to ever change "ipft_next". */ +/* ------------------------------------------------------------------------ */ +int fr_addipftune(newtune) +ipftuneable_t *newtune; +{ + ipftuneable_t *ta, **tap; + + ta = fr_findtunebyname(newtune->ipft_name); + if (ta != NULL) + return EEXIST; + + for (tap = &ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next) + ; + + newtune->ipft_next = NULL; + *tap = newtune; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_delipftune */ +/* Returns: int - 0 == success, else failure */ +/* Parameters: oldtune - pointer to tune struct to remove from the list of */ +/* current dynamic tuneables */ +/* */ +/* Search for the tune structure, by pointer, in the list of those that are */ +/* dynamically added at run time. If found, adjust the list so that this */ +/* structure is no longer part of it. */ +/* ------------------------------------------------------------------------ */ +int fr_delipftune(oldtune) +ipftuneable_t *oldtune; +{ + ipftuneable_t *ta, **tap; + + for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) + if (ta == oldtune) { + *tap = oldtune->ipft_next; + oldtune->ipft_next = NULL; + return 0; + } + + return ESRCH; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipftune */ +/* Returns: int - 0 == success, else failure */ +/* Parameters: cmd(I) - ioctl command number */ +/* data(I) - pointer to ioctl data structure */ +/* */ +/* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ +/* three ioctls provide the means to access and control global variables */ +/* within IPFilter, allowing (for example) timeouts and table sizes to be */ +/* changed without rebooting, reloading or recompiling. The initialisation */ +/* and 'destruction' routines of the various components of ipfilter are all */ +/* each responsible for handling their own values being too big. */ +/* ------------------------------------------------------------------------ */ +int fr_ipftune(cmd, data) +ioctlcmd_t cmd; +void *data; +{ + ipftuneable_t *ta; + ipftune_t tu; + void *cookie; + int error; + + error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE); + if (error != 0) + return error; + + tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; + cookie = tu.ipft_cookie; + ta = NULL; + + switch (cmd) + { + case SIOCIPFGETNEXT : + /* + * If cookie is non-NULL, assume it to be a pointer to the last + * entry we looked at, so find it (if possible) and return a + * pointer to the next one after it. The last entry in the + * the table is a NULL entry, so when we get to it, set cookie + * to NULL and return that, indicating end of list, erstwhile + * if we come in with cookie set to NULL, we are starting anew + * at the front of the list. + */ + if (cookie != NULL) { + ta = fr_findtunebycookie(cookie, &tu.ipft_cookie); + } else { + ta = ipf_tuneables; + tu.ipft_cookie = ta + 1; + } + if (ta != NULL) { + /* + * Entry found, but does the data pointed to by that + * row fit in what we can return? + */ + if (ta->ipft_sz > sizeof(tu.ipft_un)) + return EINVAL; + + tu.ipft_vlong = 0; + if (ta->ipft_sz == sizeof(u_long)) + tu.ipft_vlong = *ta->ipft_plong; + else if (ta->ipft_sz == sizeof(u_int)) + tu.ipft_vint = *ta->ipft_pint; + else if (ta->ipft_sz == sizeof(u_short)) + tu.ipft_vshort = *ta->ipft_pshort; + else if (ta->ipft_sz == sizeof(u_char)) + tu.ipft_vchar = *ta->ipft_pchar; + + tu.ipft_sz = ta->ipft_sz; + tu.ipft_min = ta->ipft_min; + tu.ipft_max = ta->ipft_max; + tu.ipft_flags = ta->ipft_flags; + bcopy(ta->ipft_name, tu.ipft_name, + MIN(sizeof(tu.ipft_name), + strlen(ta->ipft_name) + 1)); + } + error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); + break; + + case SIOCIPFGET : + case SIOCIPFSET : + /* + * Search by name or by cookie value for a particular entry + * in the tuning paramter table. + */ + error = ESRCH; + if (cookie != NULL) { + ta = fr_findtunebycookie(cookie, NULL); + if (ta != NULL) + error = 0; + } else if (tu.ipft_name[0] != '\0') { + ta = fr_findtunebyname(tu.ipft_name); + if (ta != NULL) + error = 0; + } + if (error != 0) + break; + + if (cmd == (ioctlcmd_t)SIOCIPFGET) { + /* + * Fetch the tuning parameters for a particular value + */ + tu.ipft_vlong = 0; + if (ta->ipft_sz == sizeof(u_long)) + tu.ipft_vlong = *ta->ipft_plong; + else if (ta->ipft_sz == sizeof(u_int)) + tu.ipft_vint = *ta->ipft_pint; + else if (ta->ipft_sz == sizeof(u_short)) + tu.ipft_vshort = *ta->ipft_pshort; + else if (ta->ipft_sz == sizeof(u_char)) + tu.ipft_vchar = *ta->ipft_pchar; + tu.ipft_sz = ta->ipft_sz; + tu.ipft_min = ta->ipft_min; + tu.ipft_max = ta->ipft_max; + tu.ipft_flags = ta->ipft_flags; + error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); + + } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { + /* + * Set an internal parameter. The hard part here is + * getting the new value safely and correctly out of + * the kernel (given we only know its size, not type.) + */ + u_long in; + + if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && + (fr_running > 0)) { + error = EBUSY; + break; + } + + in = tu.ipft_vlong; + if (in < ta->ipft_min || in > ta->ipft_max) { + error = EINVAL; + break; + } + + if (ta->ipft_sz == sizeof(u_long)) { + tu.ipft_vlong = *ta->ipft_plong; + *ta->ipft_plong = in; + } else if (ta->ipft_sz == sizeof(u_int)) { + tu.ipft_vint = *ta->ipft_pint; + *ta->ipft_pint = (u_int)(in & 0xffffffff); + } else if (ta->ipft_sz == sizeof(u_short)) { + tu.ipft_vshort = *ta->ipft_pshort; + *ta->ipft_pshort = (u_short)(in & 0xffff); + } else if (ta->ipft_sz == sizeof(u_char)) { + tu.ipft_vchar = *ta->ipft_pchar; + *ta->ipft_pchar = (u_char)(in & 0xff); + } + error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); + } + break; + + default : + error = EINVAL; + break; } - ip = MTOD(m, char *) + ipoff; - if (fin->fin_dp != NULL) - fin->fin_dp = (char *)ip + dpoff; - return ip; + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_initialise */ +/* Returns: int - 0 == success, < 0 == failure */ +/* Parameters: None. */ +/* */ +/* Call of the initialise functions for all the various subsystems inside */ +/* of IPFilter. If any of them should fail, return immeadiately a failure */ +/* BUT do not try to recover from the error here. */ +/* ------------------------------------------------------------------------ */ +int fr_initialise() +{ + int i; + +#ifdef IPFILTER_LOG + i = fr_loginit(); + if (i < 0) + return -10 + i; +#endif + i = fr_natinit(); + if (i < 0) + return -20 + i; + + i = fr_stateinit(); + if (i < 0) + return -30 + i; + + i = fr_authinit(); + if (i < 0) + return -40 + i; + + i = fr_fraginit(); + if (i < 0) + return -50 + i; + + i = appr_init(); + if (i < 0) + return -60 + i; + +#ifdef IPFILTER_SYNC + i = ipfsync_init(); + if (i < 0) + return -70 + i; +#endif +#ifdef IPFILTER_SCAN + i = ipsc_init(); + if (i < 0) + return -80 + i; +#endif +#ifdef IPFILTER_LOOKUP + i = ip_lookup_init(); + if (i < 0) + return -90 + i; +#endif +#ifdef IPFILTER_COMPILED + ipfrule_add(); +#endif + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_deinitialise */ +/* Returns: None. */ +/* Parameters: None. */ +/* */ +/* Call all the various subsystem cleanup routines to deallocate memory or */ +/* destroy locks or whatever they've done that they need to now undo. */ +/* The order here IS important as there are some cross references of */ +/* internal data structures. */ +/* ------------------------------------------------------------------------ */ +void fr_deinitialise() +{ + fr_fragunload(); + fr_authunload(); + fr_natunload(); + fr_stateunload(); +#ifdef IPFILTER_SCAN + fr_scanunload(); +#endif + appr_unload(); + +#ifdef IPFILTER_COMPILED + ipfrule_remove(); +#endif + + (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); + (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); + (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); + (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE); + +#ifdef IPFILTER_LOOKUP + ip_lookup_unload(); +#endif + +#ifdef IPFILTER_LOG + fr_logunload(); +#endif +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_zerostats */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(O) - pointer to pointer for copying data back to */ +/* */ +/* Copies the current statistics out to userspace and then zero's the */ +/* current ones in the kernel. The lock is only held across the bzero() as */ +/* the copyout may result in paging (ie network activity.) */ +/* ------------------------------------------------------------------------ */ +int fr_zerostats(data) +caddr_t data; +{ + friostat_t fio; + int error; + + fr_getstat(&fio); + error = copyoutptr(&fio, data, sizeof(fio)); + if (error) + return EFAULT; + + WRITE_ENTER(&ipf_mutex); + bzero((char *)frstats, sizeof(*frstats) * 2); + RWLOCK_EXIT(&ipf_mutex); + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_resolvedest */ +/* Returns: Nil */ +/* Parameters: fdp(IO) - pointer to destination information to resolve */ +/* v(I) - IP protocol version to match */ +/* */ +/* Looks up an interface name in the frdest structure pointed to by fdp and */ +/* if a matching name can be found for the particular IP protocol version */ +/* then store the interface pointer in the frdest struct. If no match is */ +/* found, then set the interface pointer to be -1 as NULL is considered to */ +/* indicate there is no information at all in the structure. */ +/* ------------------------------------------------------------------------ */ +void fr_resolvedest(fdp, v) +frdest_t *fdp; +int v; +{ + void *ifp; + + ifp = NULL; + v = v; /* LINT */ + + if (*fdp->fd_ifname != '\0') { + ifp = GETIFP(fdp->fd_ifname, v); + if (ifp == NULL) + ifp = (void *)-1; + } + fdp->fd_ifp = ifp; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_icmp4errortype */ +/* Returns: int - 1 == success, 0 == failure */ +/* Parameters: icmptype(I) - ICMP type number */ +/* */ +/* Tests to see if the ICMP type number passed is an error type or not. */ +/* ------------------------------------------------------------------------ */ +int fr_icmp4errortype(icmptype) +int icmptype; +{ + + switch (icmptype) + { + case ICMP_SOURCEQUENCH : + case ICMP_PARAMPROB : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_UNREACH : + return 1; + default: + return 0; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_resolvenic */ +/* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ +/* pointer to interface structure for NIC */ +/* Parameters: name(I) - complete interface name */ +/* v(I) - IP protocol version */ +/* */ +/* Look for a network interface structure that firstly has a matching name */ +/* to that passed in and that is also being used for that IP protocol */ +/* version (necessary on some platforms where there are separate listings */ +/* for both IPv4 and IPv6 on the same physical NIC. */ +/* */ +/* One might wonder why name gets terminated with a \0 byte in here. The */ +/* reason is an interface name could get into the kernel structures of ipf */ +/* in any number of ways and so long as they all use the same sized array */ +/* to put the name in, it makes sense to ensure it gets null terminated */ +/* before it is used for its intended purpose - finding its match in the */ +/* kernel's list of configured interfaces. */ +/* */ +/* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */ +/* array for the name that is LIFNAMSIZ bytes (at least) in length. */ +/* ------------------------------------------------------------------------ */ +void *fr_resolvenic(name, v) +char *name; +int v; +{ + void *nic; + + if (name[0] == '\0') + return NULL; + + if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { + return NULL; + } + + name[LIFNAMSIZ - 1] = '\0'; + + nic = GETIFP(name, v); + if (nic == NULL) + nic = (void *)-1; + return nic; } -#endif /* _KERNEL */ diff --git a/contrib/ipfilter/ip_auth.c b/contrib/ipfilter/ip_auth.c index 566f203..b91c2e6 100644 --- a/contrib/ipfilter/ip_auth.c +++ b/contrib/ipfilter/ip_auth.c @@ -1,39 +1,49 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1998-2001 by Darren Reed & Guido van Rooij. + * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include <sys/errno.h> #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> #include <sys/file.h> -#if !defined(_KERNEL) && !defined(KERNEL) +#if !defined(_KERNEL) # include <stdio.h> # include <stdlib.h> # include <string.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> #else # include <sys/ioctl.h> #endif -#ifndef linux +#if !defined(linux) # include <sys/protosw.h> #endif #include <sys/socket.h> -#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +#if defined(_KERNEL) # include <sys/systm.h> -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) # include <sys/mbuf.h> # endif -#else +#endif +#if defined(__SVR4) || defined(__svr4__) # include <sys/filio.h> # include <sys/byteorder.h> # ifdef _KERNEL @@ -48,6 +58,9 @@ #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) # include <machine/cpu.h> #endif +#if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) +# include <sys/proc.h> +#endif #include <net/if.h> #ifdef sun # include <net/af.h> @@ -56,28 +69,29 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#ifndef KERNEL +#if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) # define KERNEL +# define _KERNEL # define NOT_KERNEL #endif -#ifndef linux +#if !defined(linux) # include <netinet/ip_var.h> #endif #ifdef NOT_KERNEL +# undef _KERNEL # undef KERNEL #endif -#ifdef __sgi -# ifdef IFF_DRVRLOCK /* IRIX6 */ -# include <sys/hashing.h> -# endif -#endif #include <netinet/tcp.h> -#if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */ +#if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ extern struct ifqueue ipintrq; /* ip packet input queue */ #else -# ifndef linux +# if !defined(__hpux) && !defined(linux) # if __FreeBSD_version >= 300000 # include <net/if_var.h> +# if __FreeBSD_version >= 500042 +# define IF_QFULL _IF_QFULL +# define IF_DROP _IF_DROP +# endif /* __FreeBSD_version >= 500042 */ # endif # include <netinet/in_var.h> # include <netinet/tcp_fsm.h> @@ -89,7 +103,7 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ #include <netinet/tcpip.h> #include "netinet/ip_fil.h" #include "netinet/ip_auth.h" -#if !SOLARIS && !defined(linux) +#if !defined(MENTAT) && !defined(linux) # include <net/netisr.h> # ifdef __FreeBSD__ # include <machine/cpufunc.h> @@ -97,58 +111,89 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ #endif #if (__FreeBSD_version >= 300000) # include <sys/malloc.h> -# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# if defined(_KERNEL) && !defined(IPFILTER_LKM) # include <sys/libkern.h> # include <sys/systm.h> # endif #endif +/* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.26 2003/09/22 12:37:04 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: ip_auth.c,v 2.73.2.3 2004/08/26 11:25:21 darrenr Exp"; #endif -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_auth, ipf_mutex; -extern kmutex_t ipf_authmx; -# if SOLARIS +#if SOLARIS extern kcondvar_t ipfauthwait; -# endif -#endif -#ifdef linux -static struct wait_queue *ipfauthwait = NULL; +#endif /* SOLARIS */ +#if defined(linux) && defined(_KERNEL) +wait_queue_head_t fr_authnext_linux; #endif int fr_authsize = FR_NUMAUTH; int fr_authused = 0; int fr_defaultauthage = 600; int fr_auth_lock = 0; +int fr_auth_init = 0; fr_authstat_t fr_authstats; -static frauth_t fr_auth[FR_NUMAUTH]; -mb_t *fr_authpkts[FR_NUMAUTH]; -static int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; -static frauthent_t *fae_list = NULL; +static frauth_t *fr_auth = NULL; +mb_t **fr_authpkts = NULL; +int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; +frauthent_t *fae_list = NULL; frentry_t *ipauth = NULL, *fr_authlist = NULL; +int fr_authinit() +{ + KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); + if (fr_auth != NULL) + bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); + else + return -1; + + KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); + if (fr_authpkts != NULL) + bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); + else + return -2; + + MUTEX_INIT(&ipf_authmx, "ipf auth log mutex"); + RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock"); +#if SOLARIS && defined(_KERNEL) + cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); +#endif +#if defined(linux) && defined(_KERNEL) + init_waitqueue_head(&fr_authnext_linux); +#endif + + fr_auth_init = 1; + + return 0; +} + + /* * Check if a packet has authorization. If the packet is found to match an * authorization result and that would result in a feedback loop (i.e. it * will end up returning FR_AUTH) then return FR_BLOCK instead. */ -u_32_t fr_checkauth(ip, fin) -ip_t *ip; +frentry_t *fr_checkauth(fin, passp) fr_info_t *fin; +u_32_t *passp; { - u_short id = ip->ip_id; frentry_t *fr; frauth_t *fra; u_32_t pass; + u_short id; + ip_t *ip; int i; if (fr_auth_lock || !fr_authused) - return 0; + return NULL; + + ip = fin->fin_ip; + id = ip->ip_id; READ_ENTER(&ipf_auth); for (i = fr_authstart; i != fr_authend; ) { @@ -163,7 +208,7 @@ fr_info_t *fin; /* * Avoid feedback loop. */ - if (!(pass = fra->fra_pass) || (pass & FR_AUTH)) + if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) pass = FR_BLOCK; /* * Create a dummy rule for the stateful checking to @@ -171,26 +216,26 @@ fr_info_t *fin; * trust from userland! */ if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && - (fin->fin_fi.fi_fl & FI_FRAG))) { + (fin->fin_flx & FI_FRAG))) { KMALLOC(fr, frentry_t *); if (fr) { bcopy((char *)fra->fra_info.fin_fr, - fr, sizeof(*fr)); + (char *)fr, sizeof(*fr)); fr->fr_grp = NULL; fr->fr_ifa = fin->fin_ifp; fr->fr_func = NULL; fr->fr_ref = 1; fr->fr_flags = pass; -#if BSD >= 199306 - fr->fr_oifa = NULL; -#endif + fr->fr_ifas[1] = NULL; + fr->fr_ifas[2] = NULL; + fr->fr_ifas[3] = NULL; } } else fr = fra->fra_info.fin_fr; fin->fin_fr = fr; RWLOCK_EXIT(&ipf_auth); WRITE_ENTER(&ipf_auth); - if (fr && fr != fra->fra_info.fin_fr) { + if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { fr->fr_next = fr_authlist; fr_authlist = fr; } @@ -201,7 +246,7 @@ fr_info_t *fin; while (fra->fra_index == -1) { i++; fra++; - if (i == FR_NUMAUTH) { + if (i == fr_authsize) { i = 0; fra = fr_auth; } @@ -215,15 +260,19 @@ fr_info_t *fin; } } RWLOCK_EXIT(&ipf_auth); - return pass; + if (passp != NULL) + *passp = pass; + ATOMIC_INC64(fr_authstats.fas_hits); + return fr; } i++; - if (i == FR_NUMAUTH) + if (i == fr_authsize) i = 0; } fr_authstats.fas_miss++; RWLOCK_EXIT(&ipf_auth); - return 0; + ATOMIC_INC64(fr_authstats.fas_miss); + return NULL; } @@ -232,15 +281,17 @@ 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) +int fr_newauth(m, fin) mb_t *m; fr_info_t *fin; -ip_t *ip; { -#if defined(_KERNEL) && SOLARIS - qif_t *qif = fin->fin_qif; +#if defined(_KERNEL) && defined(MENTAT) + qpktinfo_t *qpi = fin->fin_qpi; #endif frauth_t *fra; +#if !defined(sparc) && !defined(m68k) + ip_t *ip; +#endif int i; if (fr_auth_lock) @@ -252,7 +303,7 @@ ip_t *ip; RWLOCK_EXIT(&ipf_auth); return 0; } else { - if (fr_authused == FR_NUMAUTH) { + if (fr_authused == fr_authsize) { fr_authstats.fas_nospace++; RWLOCK_EXIT(&ipf_auth); return 0; @@ -262,21 +313,24 @@ ip_t *ip; fr_authstats.fas_added++; fr_authused++; i = fr_authend++; - if (fr_authend == FR_NUMAUTH) + if (fr_authend == fr_authsize) fr_authend = 0; RWLOCK_EXIT(&ipf_auth); + fra = fr_auth + i; fra->fra_index = i; fra->fra_pass = 0; fra->fra_age = fr_defaultauthage; bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); -#if SOLARIS && defined(_KERNEL) -# if !defined(sparc) +#if !defined(sparc) && !defined(m68k) /* * No need to copyback here as we want to undo the changes, not keep * them. */ - if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4)) + ip = fin->fin_ip; +# if defined(MENTAT) && defined(_KERNEL) + if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) +# endif { register u_short bo; @@ -285,42 +339,42 @@ ip_t *ip; bo = ip->ip_off; ip->ip_off = htons(bo); } -# endif - m->b_rptr -= qif->qf_off; +#endif +#if SOLARIS && defined(_KERNEL) + m->b_rptr -= qpi->qpi_off; fr_authpkts[i] = *(mblk_t **)fin->fin_mp; - fra->fra_q = qif->qf_q; + fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ cv_signal(&ipfauthwait); #else # if defined(BSD) && !defined(sparc) && (BSD >= 199306) - if (fin->fin_out == 0) { + if (!fin->fin_out) { ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); } # endif fr_authpkts[i] = m; - WAKEUP(&fr_authnext); + WAKEUP(&fr_authnext,0); #endif return 1; } -int fr_auth_ioctl(data, mode, cmd) +int fr_auth_ioctl(data, cmd, mode) caddr_t data; +ioctlcmd_t cmd; int mode; -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -u_long cmd; -#else -int cmd; -#endif { mb_t *m; -#if defined(_KERNEL) && !SOLARIS && \ +#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) struct ifqueue *ifq; +# ifdef USE_SPL int s; +# endif /* USE_SPL */ #endif frauth_t auth, *au = &auth, *fra; - int i, error = 0; + int i, error = 0, len; + char *t; switch (cmd) { @@ -329,81 +383,119 @@ int cmd; error = EPERM; break; } - 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 : - /* These commands go via request to fr_preauthcmd */ - error = EINVAL; + fr_lock(data, &fr_auth_lock); break; + case SIOCATHST: fr_authstats.fas_faelist = fae_list; - error = IWCOPYPTR((char *)&fr_authstats, data, - sizeof(fr_authstats)); + error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); break; + + case SIOCIPFFL: + SPL_NET(s); + WRITE_ENTER(&ipf_auth); + i = fr_authflush(); + RWLOCK_EXIT(&ipf_auth); + SPL_X(s); + error = copyoutptr((char *)&i, data, sizeof(i)); + break; + case SIOCAUTHW: - if (!(mode & FWRITE)) { - error = EPERM; - break; - } fr_authioctlloop: + error = fr_inobj(data, au, IPFOBJ_FRAUTH); READ_ENTER(&ipf_auth); if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { - error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data, - sizeof(frauth_t)); + error = fr_outobj(data, &fr_auth[fr_authnext], + IPFOBJ_FRAUTH); + if (auth.fra_len != 0 && auth.fra_buf != NULL) { + /* + * Copy packet contents out to user space if + * requested. Bail on an error. + */ + m = fr_authpkts[fr_authnext]; + len = MSGDSIZE(m); + if (len > auth.fra_len) + len = auth.fra_len; + auth.fra_len = len; + for (t = auth.fra_buf; m && (len > 0); ) { + i = MIN(M_LEN(m), len); + error = copyoutptr(MTOD(m, char *), + t, i); + len -= i; + t += i; + if (error != 0) + break; + } + } RWLOCK_EXIT(&ipf_auth); - if (error) + if (error != 0) break; - WRITE_ENTER(&ipf_auth); SPL_NET(s); + WRITE_ENTER(&ipf_auth); fr_authnext++; - if (fr_authnext == FR_NUMAUTH) + if (fr_authnext == fr_authsize) fr_authnext = 0; - SPL_X(s); RWLOCK_EXIT(&ipf_auth); + SPL_X(s); return 0; } RWLOCK_EXIT(&ipf_auth); + /* + * We exit ipf_global here because a program that enters in + * here will have a lock on it and goto sleep having this lock. + * If someone were to do an 'ipf -D' the system would then + * deadlock. The catch with releasing it here is that the + * caller of this function expects it to be held when we + * return so we have to reacquire it in here. + */ + RWLOCK_EXIT(&ipf_global); + + MUTEX_ENTER(&ipf_authmx); #ifdef _KERNEL # if SOLARIS - mutex_enter(&ipf_authmx); - if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) { - mutex_exit(&ipf_authmx); - return EINTR; + error = 0; + if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) + error = EINTR; +# else /* SOLARIS */ +# ifdef __hpux + { + lock_t *l; + + l = get_sleep_lock(&fr_authnext); + error = sleep(&fr_authnext, PZERO+1); + spinunlock(l); } - mutex_exit(&ipf_authmx); -# else +# else +# ifdef __osf__ + error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, + &ipf_authmx, MS_LOCK_SIMPLE); +# else error = SLEEP(&fr_authnext, "fr_authnext"); -# endif +# endif /* __osf__ */ +# endif /* __hpux */ +# endif /* SOLARIS */ #endif - if (!error) + MUTEX_EXIT(&ipf_authmx); + READ_ENTER(&ipf_global); + if (error == 0) { + READ_ENTER(&ipf_auth); goto fr_authioctlloop; + } break; + case SIOCAUTHR: - if (!(mode & FWRITE)) { - error = EPERM; - break; - } - error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth)); - if (error) + error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); + if (error != 0) return error; - WRITE_ENTER(&ipf_auth); SPL_NET(s); + WRITE_ENTER(&ipf_auth); i = au->fra_index; fra = fr_auth + i; - if ((i < 0) || (i > FR_NUMAUTH) || + if ((i < 0) || (i >= fr_authsize) || (fra->fra_info.fin_id != au->fra_info.fin_id)) { - SPL_X(s); RWLOCK_EXIT(&ipf_auth); - return EINVAL; + SPL_X(s); + return ESRCH; } m = fr_authpkts[i]; fra->fra_index = -2; @@ -411,63 +503,67 @@ fr_authioctlloop: fr_authpkts[i] = NULL; RWLOCK_EXIT(&ipf_auth); #ifdef _KERNEL - if (m && au->fra_info.fin_out) { -# if SOLARIS - error = (fr_qout(fra->fra_q, m) == 0) ? EINVAL : 0; -# else /* SOLARIS */ - struct route ro; - - bzero((char *)&ro, sizeof(ro)); -# if ((_BSDI_VERSION >= 199802) && (_BSDI_VERSION < 200005)) || \ - defined(__OpenBSD__) || (defined(IRIX) && (IRIX >= 605)) || \ - (__FreeBSD_version >= 470102) - error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL, - NULL); + if ((m != NULL) && (au->fra_info.fin_out != 0)) { +# ifdef MENTAT + error = !putq(fra->fra_q, m); +# else /* MENTAT */ +# ifdef linux # else - error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL); -# endif - if (ro.ro_rt) { - RTFREE(ro.ro_rt); - } -# endif /* SOLARIS */ - if (error) +# if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ + (defined(__sgi) && (IRIX >= 60500) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, + NULL); +# else + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); +# endif +# endif /* Linux */ +# endif /* MENTAT */ + if (error != 0) fr_authstats.fas_sendfail++; else fr_authstats.fas_sendok++; } else if (m) { -# if SOLARIS - error = (fr_qin(fra->fra_q, m) == 0) ? EINVAL : 0; -# else /* SOLARIS */ -# if __FreeBSD_version >= 501104 - netisr_dispatch(NETISR_IP, m); +# ifdef MENTAT + error = !putq(fra->fra_q, m); +# else /* MENTAT */ +# ifdef linux # else +# if __FreeBSD_version >= 501000 + netisr_dispatch(NETISR_IP, m); +# else +# if IRIX >= 60516 + ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; +# else ifq = &ipintrq; +# endif if (IF_QFULL(ifq)) { IF_DROP(ifq); - m_freem(m); + FREE_MB_T(m); error = ENOBUFS; } else { IF_ENQUEUE(ifq, m); -# if IRIX < 605 +# if IRIX < 60500 schednetisr(NETISR_IP); -# endif +# endif } -# endif -# endif /* SOLARIS */ - if (error) +# endif +# endif /* Linux */ +# endif /* MENTAT */ + if (error != 0) fr_authstats.fas_quefail++; else fr_authstats.fas_queok++; } else error = EINVAL; -# if SOLARIS - if (error) +# ifdef MENTAT + if (error != 0) error = EINVAL; -# else +# else /* MENTAT */ /* * If we experience an error which will result in the packet * not being processed, make sure we advance to the next one. - */ + */ if (error == ENOBUFS) { fr_authused--; fra->fra_index = -1; @@ -475,7 +571,7 @@ fr_authioctlloop: if (i == fr_authstart) { while (fra->fra_index == -1) { i++; - if (i == FR_NUMAUTH) + if (i == fr_authsize) i = 0; fr_authstart = i; if (i == fr_authend) @@ -487,10 +583,11 @@ fr_authioctlloop: } } } -# endif +# endif /* MENTAT */ #endif /* _KERNEL */ SPL_X(s); break; + default : error = EINVAL; break; @@ -509,41 +606,48 @@ void fr_authunload() frentry_t *fr, **frp; mb_t *m; - WRITE_ENTER(&ipf_auth); - for (i = 0; i < FR_NUMAUTH; i++) { - if ((m = fr_authpkts[i])) { - FREE_MB_T(m); - fr_authpkts[i] = NULL; - fr_auth[i].fra_index = -1; - } + if (fr_auth != NULL) { + KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); + fr_auth = NULL; } + if (fr_authpkts != NULL) { + for (i = 0; i < fr_authsize; i++) { + m = fr_authpkts[i]; + if (m != NULL) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + } + } + KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); + fr_authpkts = NULL; + } - for (faep = &fae_list; (fae = *faep); ) { + faep = &fae_list; + while ((fae = *faep) != NULL) { *faep = fae->fae_next; KFREE(fae); } ipauth = NULL; - RWLOCK_EXIT(&ipf_auth); - if (fr_authlist) { - /* - * We *MuST* reget ipf_auth because otherwise we won't get the - * locks in the right order and risk deadlock. - * We need ipf_mutex here to prevent a rule from using it - * inside fr_check(). - */ - WRITE_ENTER(&ipf_mutex); - WRITE_ENTER(&ipf_auth); - for (frp = &fr_authlist; (fr = *frp); ) { + if (fr_authlist != NULL) { + for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { if (fr->fr_ref == 1) { *frp = fr->fr_next; KFREE(fr); } else frp = &fr->fr_next; } - RWLOCK_EXIT(&ipf_auth); - RWLOCK_EXIT(&ipf_mutex); + } + + if (fr_auth_init == 1) { +# if SOLARIS && defined(_KERNEL) + cv_destroy(&ipfauthwait); +# endif + MUTEX_DESTROY(&ipf_authmx); + RW_DESTROY(&ipf_auth); + + fr_auth_init = 0; } } @@ -559,17 +663,18 @@ void fr_authexpire() register frauthent_t *fae, **faep; register frentry_t *fr, **frp; mb_t *m; -#if !SOLARIS && defined(_KERNEL) +# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL) int s; -#endif +# endif if (fr_auth_lock) return; SPL_NET(s); WRITE_ENTER(&ipf_auth); - for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { - if ((!--fra->fra_age) && (m = fr_authpkts[i])) { + for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { + fra->fra_age--; + if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { FREE_MB_T(m); fr_authpkts[i] = NULL; fr_auth[i].fra_index = -1; @@ -578,8 +683,9 @@ void fr_authexpire() } } - for (faep = &fae_list; (fae = *faep); ) { - if (!--fae->fae_age) { + for (faep = &fae_list; ((fae = *faep) != NULL); ) { + fae->fae_age--; + if (fae->fae_age == 0) { *faep = fae->fae_next; KFREE(fae); fr_authstats.fas_expire++; @@ -591,7 +697,7 @@ void fr_authexpire() else ipauth = NULL; - for (frp = &fr_authlist; (fr = *frp); ) { + for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { if (fr->fr_ref == 1) { *frp = fr->fr_next; KFREE(fr); @@ -603,52 +709,48 @@ void fr_authexpire() } int fr_preauthcmd(cmd, fr, frptr) -#if defined(__NetBSD__) || defined(__OpenBSD__) || \ - (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) -u_long cmd; -#else -int cmd; -#endif +ioctlcmd_t cmd; frentry_t *fr, **frptr; { frauthent_t *fae, **faep; int error = 0; -#if defined(KERNEL) && !SOLARIS +# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL) int s; #endif - if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) { - /* Should not happen */ - printf("fr_preauthcmd called with bad cmd 0x%lx", (u_long)cmd); + if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) return EIO; - } - for (faep = &fae_list; (fae = *faep); ) + for (faep = &fae_list; ((fae = *faep) != NULL); ) { if (&fae->fae_fr == fr) break; else faep = &fae->fae_next; - if (cmd == SIOCRMAFR) { - if (!fr || !frptr) + } + + if (cmd == (ioctlcmd_t)SIOCRMAFR) { + if (fr == NULL || frptr == NULL) error = EINVAL; - else if (!fae) + else if (fae == NULL) error = ESRCH; else { - WRITE_ENTER(&ipf_auth); SPL_NET(s); + WRITE_ENTER(&ipf_auth); *faep = fae->fae_next; - *frptr = fr->fr_next; - SPL_X(s); + if (ipauth == &fae->fae_fr) + ipauth = fae_list ? &fae_list->fae_fr : NULL; RWLOCK_EXIT(&ipf_auth); + SPL_X(s); + KFREE(fae); } - } else if (fr && frptr) { + } else if (fr != NULL && frptr != NULL) { KMALLOC(fae, frauthent_t *); if (fae != NULL) { bcopy((char *)fr, (char *)&fae->fae_fr, sizeof(*fr)); - WRITE_ENTER(&ipf_auth); SPL_NET(s); + WRITE_ENTER(&ipf_auth); fae->fae_age = fr_defaultauthage; fae->fae_fr.fr_hits = 0; fae->fae_fr.fr_next = *frptr; @@ -656,11 +758,47 @@ frentry_t *fr, **frptr; fae->fae_next = *faep; *faep = fae; ipauth = &fae_list->fae_fr; - SPL_X(s); RWLOCK_EXIT(&ipf_auth); + SPL_X(s); } else error = ENOMEM; } else error = EINVAL; return error; } + + +/* + * Flush held packets. + * Must already be properly SPL'ed and Locked on &ipf_auth. + * + */ +int fr_authflush() +{ + register int i, num_flushed; + mb_t *m; + + if (fr_auth_lock) + return -1; + + num_flushed = 0; + + for (i = 0 ; i < fr_authsize; i++) { + m = fr_authpkts[i]; + if (m != NULL) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + fr_auth[i].fra_index = -1; + /* perhaps add & use a flush counter inst.*/ + fr_authstats.fas_expire++; + fr_authused--; + num_flushed++; + } + } + + fr_authstart = 0; + fr_authend = 0; + fr_authnext = 0; + + return num_flushed; +} diff --git a/contrib/ipfilter/ip_auth.h b/contrib/ipfilter/ip_auth.h index e0cbf04..a39e7fd 100644 --- a/contrib/ipfilter/ip_auth.h +++ b/contrib/ipfilter/ip_auth.h @@ -1,9 +1,11 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1997-2001 by Darren Reed & Guido Van Rooij. * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_auth.h,v 2.3.2.6 2002/10/26 07:03:00 darrenr Exp $ + * Id: ip_auth.h,v 2.16 2003/07/25 12:29:56 darrenr Exp * */ #ifndef __IP_AUTH_H__ @@ -13,10 +15,12 @@ typedef struct frauth { int fra_age; + int fra_len; int fra_index; u_32_t fra_pass; fr_info_t fra_info; -#if SOLARIS + char *fra_buf; +#ifdef MENTAT queue_t *fra_q; #endif } frauth_t; @@ -44,20 +48,19 @@ typedef struct fr_authstat { extern frentry_t *ipauth; extern struct fr_authstat fr_authstats; extern int fr_defaultauthage; +extern int fr_authstart; +extern int fr_authend; extern int fr_authsize; extern int fr_authused; extern int fr_auth_lock; -extern u_32_t fr_checkauth __P((ip_t *, fr_info_t *)); +extern frentry_t *fr_checkauth __P((fr_info_t *, u_32_t *)); extern void fr_authexpire __P((void)); +extern int fr_authinit __P((void)); extern void fr_authunload __P((void)); -extern mb_t *fr_authpkts[]; -extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); -#if defined(__NetBSD__) || defined(__OpenBSD__) || \ - (__FreeBSD_version >= 300003) -extern int fr_preauthcmd __P((u_long, frentry_t *, frentry_t **)); -extern int fr_auth_ioctl __P((caddr_t, int, u_long)); -#else -extern int fr_preauthcmd __P((int, frentry_t *, frentry_t **)); -extern int fr_auth_ioctl __P((caddr_t, int, int)); -#endif +extern int fr_authflush __P((void)); +extern mb_t **fr_authpkts; +extern int fr_newauth __P((mb_t *, fr_info_t *)); +extern int fr_preauthcmd __P((ioctlcmd_t, frentry_t *, frentry_t **)); +extern int fr_auth_ioctl __P((caddr_t, ioctlcmd_t, int)); + #endif /* __IP_AUTH_H__ */ diff --git a/contrib/ipfilter/ip_compat.h b/contrib/ipfilter/ip_compat.h index 7674424..6ea3f70 100644 --- a/contrib/ipfilter/ip_compat.h +++ b/contrib/ipfilter/ip_compat.h @@ -1,10 +1,12 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.26.2.52 2004/06/09 00:01:14 darrenr Exp $ + * Id: ip_compat.h,v 2.142.2.25 2005/03/28 09:33:36 darrenr Exp */ #ifndef __IP_COMPAT_H__ @@ -22,25 +24,6 @@ # define const #endif -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif -#if SOLARIS -# if !defined(SOLARIS2) -# define SOLARIS2 3 /* Pick an old version */ -# endif -# if SOLARIS2 >= 8 -# ifndef USE_INET6 -# define USE_INET6 -# endif -# else -# undef USE_INET6 -# endif -#endif -#if defined(sun) && !(defined(__svr4__) || defined(__SVR4)) -# undef USE_INET6 -#endif - #if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL__) # undef KERNEL # undef _KERNEL @@ -50,27 +33,53 @@ # define __KERNEL__ #endif -#if defined(__SVR4) || defined(__svr4__) || defined(__sgi) -#define index strchr -# if !defined(KERNEL) -# define bzero(a,b) memset(a,0,b) -# define bcmp memcmp -# define bcopy(a,b,c) memmove(b,a,c) +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif +#if SOLARIS2 >= 8 +# ifndef USE_INET6 +# define USE_INET6 # endif #endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ + !defined(_KERNEL) && !defined(USE_INET6) && !defined(NOINET6) +# define USE_INET6 +#endif +#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000) && \ + !defined(_KERNEL) && !defined(USE_INET6) +# define USE_INET6 +# define IPFILTER_M_IPFILTER +#endif +#if defined(OpenBSD) && (OpenBSD >= 200206) && \ + !defined(_KERNEL) && !defined(USE_INET6) +# define USE_INET6 +#endif +#if defined(__osf__) +# define USE_INET6 +#endif +#if defined(linux) && (!defined(_KERNEL) || defined(CONFIG_IPV6)) +# define USE_INET6 +#endif +#if defined(HPUXREV) && (HPUXREV >= 1111) +# define USE_INET6 +#endif -#ifndef offsetof -#define offsetof(t,m) (int)((&((t *)0L)->m)) +#if defined(BSD) && (BSD < 199103) && defined(__osf__) +# undef BSD +# define BSD 199103 #endif -#if defined(__sgi) || defined(bsdi) -struct ether_addr { - u_char ether_addr_octet[6]; -}; +#if defined(__SVR4) || defined(__svr4__) || defined(__sgi) +# define index strchr +# if !defined(_KERNEL) +# define bzero(a,b) memset(a,0,b) +# define bcmp memcmp +# define bcopy(a,b,c) memmove(b,a,c) +# endif #endif -#ifndef LIFNAMSIZ -# ifdef IF_NAMESIZE +#ifndef LIFNAMSIZ +# ifdef IF_NAMESIZE # define LIFNAMSIZ IF_NAMESIZE # else # ifdef IFNAMSIZ @@ -81,6 +90,12 @@ struct ether_addr { # endif #endif +#if defined(__sgi) || defined(bsdi) || defined(__hpux) || defined(hpux) +struct ether_addr { + u_char ether_addr_octet[6]; +}; +#endif + #if defined(__sgi) && !defined(IPFILTER_LKM) # ifdef __STDC__ # define IPL_EXTERN(ep) ipfilter##ep @@ -95,233 +110,1543 @@ struct ether_addr { # endif #endif -#ifdef __sgi -# include <sys/debug.h> -#endif - -#ifdef linux -# include <sys/sysmacros.h> -#endif - /* * This is a workaround for <sys/uio.h> troubles on FreeBSD and OpenBSD. */ -#ifndef _KERNEL -# define ADD_KERNEL -# define _KERNEL -# define KERNEL -#endif -#ifdef __OpenBSD__ +#ifndef linux +# ifndef _KERNEL +# define ADD_KERNEL +# define _KERNEL +# define KERNEL +# endif +# ifdef __OpenBSD__ struct file; -#endif -#include <sys/uio.h> -#ifdef ADD_KERNEL -# undef _KERNEL -# undef KERNEL +# endif +# include <sys/uio.h> +# ifdef ADD_KERNEL +# undef _KERNEL +# undef KERNEL +# endif #endif -#if SOLARIS -# define MTYPE(m) ((m)->b_datap->db_type) -# if SOLARIS2 >= 4 -# include <sys/isa_defs.h> -# endif + +/* ----------------------------------------------------------------------- */ +/* S O L A R I S */ +/* ----------------------------------------------------------------------- */ +#if SOLARIS +# define MENTAT 1 +# include <sys/cmn_err.h> +# include <sys/isa_defs.h> +# include <sys/stream.h> # include <sys/ioccom.h> # include <sys/sysmacros.h> # include <sys/kmem.h> +# if SOLARIS2 >= 10 +# include <sys/procset.h> +# include <sys/proc.h> +# include <sys/devops.h> +# include <sys/ddi_impldefs.h> +# endif /* * because Solaris 2 defines these in two places :-/ */ +# ifndef KERNEL +# define _KERNEL +# undef RES_INIT +# endif /* _KERNEL */ + +# if SOLARIS2 >= 8 +# include <netinet/ip6.h> +# include <netinet/icmp6.h> +# endif + +# include <inet/common.h> +/* These 5 are defined in <inet/ip.h> and <netinet/ip.h> */ # undef IPOPT_EOL # undef IPOPT_NOP # undef IPOPT_LSRR # undef IPOPT_RR # undef IPOPT_SSRR +# ifdef i386 +# define _SYS_PROMIF_H +# endif +# include <inet/ip.h> +# undef COPYOUT +# include <inet/ip_ire.h> # 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 */ +# endif # if SOLARIS2 >= 8 +# define SNPRINTF snprintf + # include <inet/ip_if.h> -# include <netinet/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 +struct ip6_ext { + u_char ip6e_nxt; + u_char ip6e_len; +}; +# endif /* SOLARIS2 >= 8 */ + +# if SOLARIS2 >= 6 +# include <sys/atomic.h> +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; # endif -# define M_BLEN(m) ((m)->b_wptr - (m)->b_rptr) - -typedef struct qif { - struct qif *qf_next; - ill_t *qf_ill; - kmutex_t qf_lock; - void *qf_iptr; - void *qf_optr; - queue_t *qf_in; - queue_t *qf_out; - void *qf_data; /* layer 3 header pointer */ - struct qinit *qf_wqinfo; - struct qinit *qf_rqinfo; - struct qinit qf_wqinit; - struct qinit qf_rqinit; - mblk_t *qf_m; /* These three fields are for passing data up from */ - queue_t *qf_q; /* fr_qin and fr_qout to the packet processing. */ - size_t qf_off; - size_t qf_len; /* this field is used for in ipfr_fastroute */ - char qf_name[LIFNAMSIZ]; - /* - * in case the ILL has disappeared... - */ - size_t qf_hl; /* header length */ - int qf_sap; -# if SOLARIS2 >= 8 - int qf_tunoff; /* tunnel offset */ -#endif - size_t qf_incnt; - size_t qf_outcnt; -} qif_t; -#else /* SOLARIS */ -# if !defined(__sgi) -typedef int minor_t; +# define U_32_T 1 + +# ifdef _KERNEL +# define KRWLOCK_T krwlock_t +# define KMUTEX_T kmutex_t +# include "qif.h" +# include "pfil.h" +# if SOLARIS2 >= 6 +# 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 /* SOLARIS2 == 6 */ +# 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)--; \ + mutex_exit(&ipf_rw); } +# endif /* SOLARIS2 >= 6 */ +# define USE_MUTEXES +# define MUTEX_ENTER(x) mutex_enter(&(x)->ipf_lk) +# define READ_ENTER(x) rw_enter(&(x)->ipf_lk, RW_READER) +# define WRITE_ENTER(x) rw_enter(&(x)->ipf_lk, RW_WRITER) +# define MUTEX_DOWNGRADE(x) rw_downgrade(&(x)->ipf_lk) +# define RWLOCK_INIT(x, y) rw_init(&(x)->ipf_lk, (y), \ + RW_DRIVER, NULL) +# define RWLOCK_EXIT(x) rw_exit(&(x)->ipf_lk) +# define RW_DESTROY(x) rw_destroy(&(x)->ipf_lk) +# define MUTEX_INIT(x, y) mutex_init(&(x)->ipf_lk, (y), \ + MUTEX_DRIVER, NULL) +# define MUTEX_DESTROY(x) mutex_destroy(&(x)->ipf_lk) +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) +# define MUTEX_EXIT(x) mutex_exit(&(x)->ipf_lk) +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) (void) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) (void) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +# ifdef sparc +# define ntohs(x) (x) +# define ntohl(x) (x) +# define htons(x) (x) +# define htonl(x) (x) +# endif /* sparc */ +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define GET_MINOR(x) getminor(x) +extern void *get_unit __P((char *, int)); +# define GETIFP(n, v) get_unit(n, v) +# define IFNAME(x) ((qif_t *)x)->qf_name +# define COPYIFNAME(x, b) \ + (void) strncpy(b, ((qif_t *)x)->qf_name, \ + LIFNAMSIZ) +# define GETKTIME(x) uniqtime((struct timeval *)x) +# define MSGDSIZE(x) msgdsize(x) +# define M_LEN(x) ((x)->b_wptr - (x)->b_rptr) +# define M_DUPLICATE(x) dupmsg((x)) +# define MTOD(m,t) ((t)((m)->b_rptr)) +# define MTYPE(m) ((m)->b_datap->db_type) +# define FREE_MB_T(m) freemsg(m) +# define m_next b_cont +# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7) +# define IPF_PANIC(x,y) if (x) { printf y; cmn_err(CE_PANIC, "ipf_panic"); } +typedef mblk_t mb_t; +# endif /* _KERNEL */ + +# if (SOLARIS2 >= 7) +# ifdef lint +# define ALIGN32(ptr) (ptr ? 0L : 0L) +# define ALIGN16(ptr) (ptr ? 0L : 0L) +# else +# define ALIGN32(ptr) (ptr) +# define ALIGN16(ptr) (ptr) +# endif +# endif + +# if SOLARIS2 < 6 +typedef struct uio uio_t; # endif +typedef int ioctlcmd_t; + +# define OS_RECOGNISED 1 + #endif /* SOLARIS */ -#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) -#ifndef IP_OFFMASK -#define IP_OFFMASK 0x1fff -#endif +/* ----------------------------------------------------------------------- */ +/* H P U X */ +/* ----------------------------------------------------------------------- */ +#ifdef __hpux +# define MENTAT 1 +# include <sys/sysmacros.h> +# include <sys/spinlock.h> +# include <sys/lock.h> +# include <sys/stream.h> +# ifdef USE_INET6 +# include <netinet/if_ether.h> +# include <netinet/ip6.h> +# include <netinet/icmp6.h> +typedef struct ip6_hdr ip6_t; +# endif -#if BSD > 199306 -# define USE_QUAD_T -# define U_QUAD_T u_quad_t -# define QUAD_T quad_t -#else /* BSD > 199306 */ -# define U_QUAD_T u_long -# define QUAD_T long -#endif /* BSD > 199306 */ +# ifdef _KERNEL +# define SNPRINTF sprintf +# if (HPUXREV >= 1111) +# define IPL_SELECT +# ifdef IPL_SELECT +# include <machine/sys/user.h> +# include <sys/kthread_iface.h> +# define READ_COLLISION 0x01 + +typedef struct iplog_select_s { + kthread_t *read_waiter; + int state; +} iplog_select_t; +# endif +# endif +# define GETKTIME(x) uniqtime((struct timeval *)x) -#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) -# include <sys/param.h> -# ifndef __FreeBSD_version -# ifdef IPFILTER_LKM -# include <osreldate.h> +# if HPUXREV == 1111 +# include "kern_svcs.h" +# else +# include <sys/kern_svcs.h> +# endif +# undef ti_flags +# undef TCP_NODELAY +# undef TCP_MAXSEG +# include <sys/reg.h> +# include "../netinet/ip_info.h" +/* + * According to /usr/include/sys/spinlock.h on HP-UX 11.00, these functions + * are available. Attempting to use them actually results in unresolved + * symbols when it comes time to load the module. + * This has been fixed! Yipee! + */ +# if 1 +# ifdef __LP64__ +# define ATOMIC_INCL(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_DECL(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1) +# else +# define ATOMIC_INCL(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_DECL(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1) +# endif +# define ATOMIC_INC64(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_INC32(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_INC16(x) lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_DEC64(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1) +# define ATOMIC_DEC32(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1) +# define ATOMIC_DEC16(x) lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), -1) +# else /* 0 */ +# define ATOMIC_INC64(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC64(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INC32(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC32(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INCL(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DECL(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# endif +# define ip_cksum ip_csuma +# define memcpy(a,b,c) bcopy((caddr_t)b, (caddr_t)a, c) +# define USE_MUTEXES +# define MUTEX_INIT(x, y) initlock(&(x)->ipf_lk, 0, 0, (y)) +# define MUTEX_ENTER(x) spinlock(&(x)->ipf_lk) +# define MUTEX_EXIT(x) spinunlock(&(x)->ipf_lk); +# define MUTEX_DESTROY(x) +# define MUTEX_NUKE(x) bzero((char *)(x), sizeof(*(x))) +# define KMUTEX_T lock_t +# define kmutex_t lock_t /* for pfil.h */ +# define krwlock_t lock_t /* for pfil.h */ +/* + * The read-write lock implementation in HP-UX 11.0 is crippled - it can + * only be used by threads working in a user context! + * This has been fixed! Yipee! (Or at least it does in 11.00, not 11.11..) + */ +# if HPUXREV < 1111 +# define MUTEX_DOWNGRADE(x) lock_write_to_read(x) +# define KRWLOCK_T struct rw_lock +# define READ_ENTER(x) lock_read(&(x)->ipf_lk) +# define WRITE_ENTER(x) lock_write(&(x)->ipf_lk) +# if HPUXREV >= 1111 +# define RWLOCK_INIT(x, y) rwlock_init4(&(x)->ipf_lk, 0, RWLCK_CANSLEEP, 0, y) +# else +# define RWLOCK_INIT(x, y) lock_init3(&(x)->ipf_lk, 0, 1, 0, 0, y) +# endif +# define RWLOCK_EXIT(x) lock_done(&(x)->ipf_lk) # else -# include <sys/osreldate.h> +# define KRWLOCK_T lock_t +# define KMUTEX_T lock_t +# define READ_ENTER(x) MUTEX_ENTER(x) +# define WRITE_ENTER(x) MUTEX_ENTER(x) +# define MUTEX_DOWNGRADE(x) +# define RWLOCK_INIT(x, y) initlock(&(x)->ipf_lk, 0, 0, y) +# define RWLOCK_EXIT(x) MUTEX_EXIT(x) +# endif +# define RW_DESTROY(x) +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# if HPUXREV >= 1111 +# define BCOPYIN(a,b,c) 0; bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) 0; bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# else +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# endif +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +extern void *get_unit __P((char *, int)); +# define GETIFP(n, v) get_unit(n, v) +# define IFNAME(x, b) ((ill_t *)x)->ill_name +# define COPYIFNAME(x, b) \ + (void) strncpy(b, ((qif_t *)x)->qf_name, \ + LIFNAMSIZ) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define SLEEP(id, n) { lock_t *_l = get_sleep_lock((caddr_t)id); \ + sleep(id, PZERO+1); \ + spinunlock(_l); \ + } +# define WAKEUP(id,x) { lock_t *_l = get_sleep_lock((caddr_t)id); \ + wakeup(id + x); \ + spinunlock(_l); \ + } +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_IOSYS, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_IOSYS, M_NOWAIT) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define MSGDSIZE(x) msgdsize(x) +# define M_LEN(x) ((x)->b_wptr - (x)->b_rptr) +# define M_DUPLICATE(x) dupmsg((x)) +# define MTOD(m,t) ((t)((m)->b_rptr)) +# define MTYPE(m) ((m)->b_datap->db_type) +# define FREE_MB_T(m) freemsg(m) +# define m_next b_cont +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef mblk_t mb_t; + +# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7) + +# include "qif.h" +# include "pfil.h" + +# else /* _KERNEL */ + +typedef unsigned char uchar_t; + +# ifndef _SYS_STREAM_INCLUDED +typedef char * mblk_t; +typedef void * queue_t; +typedef u_long ulong; # endif +# include <netinet/ip_info.h> + +# endif /* _KERNEL */ + +# ifdef lint +# define ALIGN32(ptr) (ptr ? 0L : 0L) +# define ALIGN16(ptr) (ptr ? 0L : 0L) +# else +# define ALIGN32(ptr) (ptr) +# define ALIGN16(ptr) (ptr) # endif -# ifdef IPFILTER_LKM -# define ACTUALLY_LKM_NOT_KERNEL + +typedef struct uio uio_t; +typedef int ioctlcmd_t; +typedef int minor_t; +typedef unsigned int u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 + +#endif /* __hpux */ + +/* ----------------------------------------------------------------------- */ +/* I R I X */ +/* ----------------------------------------------------------------------- */ +#ifdef __sgi +# undef MENTAT +# if IRIX < 60500 +typedef struct uio uio_t; # endif -# if defined(__FreeBSD_version) && (__FreeBSD_version < 300000) -# include <machine/spl.h> +typedef int ioctlcmd_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# ifdef INET6 +# define USE_INET6 +# endif + +# define hz HZ +# include <sys/ksynch.h> +# define IPF_LOCK_PL plhi +# include <sys/sema.h> +# undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; + +# ifdef MUTEX_INIT +# define KMUTEX_T mutex_t # else -# if (__FreeBSD_version >= 300000) && (__FreeBSD_version < 400000) -# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) -# define ACTUALLY_LKM_NOT_KERNEL -# endif +# define KMUTEX_T kmutex_t +# define KRWLOCK_T kmutex_t +# endif + +# ifdef _KERNEL +# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)++; MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)--; MUTEX_EXIT(&ipf_rw); } +# define USE_MUTEXES +# ifdef MUTEX_INIT +# include <sys/atomic_ops.h> +# define ATOMIC_INCL(x) atomicAddUlong(&(x), 1) +# define ATOMIC_INC64(x) atomicAddUint64(&(x), 1) +# define ATOMIC_INC32(x) atomicAddUint(&(x), 1) +# define ATOMIC_INC16 ATOMIC_INC +# define ATOMIC_DECL(x) atomicAddUlong(&(x), -1) +# define ATOMIC_DEC64(x) atomicAddUint64(&(x), -1) +# define ATOMIC_DEC32(x) atomicAddUint(&(x), -1) +# define ATOMIC_DEC16 ATOMIC_DEC +# undef MUTEX_INIT +# define MUTEX_INIT(x, y) mutex_init(&(x)->ipf_lk, \ + MUTEX_DEFAULT, y) +# undef MUTEX_ENTER +# define MUTEX_ENTER(x) mutex_lock(&(x)->ipf_lk, 0) +# undef MUTEX_EXIT +# define MUTEX_EXIT(x) mutex_unlock(&(x)->ipf_lk) +# undef MUTEX_DESTROY +# define MUTEX_DESTROY(x) mutex_destroy(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) mrdemote(&(x)->ipf_lk) +# define KRWLOCK_T mrlock_t +# define RWLOCK_INIT(x, y) mrinit(&(x)->ipf_lk, y) +# undef RW_DESTROY +# define RW_DESTROY(x) mrfree(&(x)->ipf_lk) +# define READ_ENTER(x) RW_RDLOCK(&(x)->ipf_lk) +# define WRITE_ENTER(x) RW_WRLOCK(&(x)->ipf_lk) +# define RWLOCK_EXIT(x) RW_UNLOCK(&(x)->ipf_lk) +# else +# define READ_ENTER(x) MUTEX_ENTER(&(x)->ipf_lk) +# define WRITE_ENTER(x) MUTEX_ENTER(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_EXIT(x) MUTEX_EXIT(&(x)->ipf_lk) +# define MUTEX_EXIT(x) UNLOCK((x)->ipf_lk.l, (x)->ipf_lk.pl); +# define MUTEX_INIT(x,y) (x)->ipf_lk.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->ipf_lk.l) +# define MUTEX_ENTER(x) (x)->ipf_lk.pl = LOCK((x)->ipf_lk.l, \ + IPF_LOCK_PL); # endif +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) +# define FREE_MB_T(m) m_freem(m) +# define MTOD(m,t) mtod(m,t) +# define COPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define COPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define SLEEP(id, n) sleep((id), PZERO+1) +# define WAKEUP(id,x) wakeup(id+x) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define GETIFP(n,v) ifunit(n) +# include <sys/kmem.h> +# include <sys/ddi.h> +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define GET_MINOR(x) getminor(x) +# define USE_SPL 1 +# define SPL_IMP(x) (x) = splimp() +# define SPL_NET(x) (x) = splnet() +# define SPL_X(x) (void) splx(x) +extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); +extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define GETKTIME(x) microtime((struct timeval *)x) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# else +# undef RW_DESTROY +# undef MUTEX_INIT +# undef MUTEX_DESTROY +# endif /* _KERNEL */ + +# define OS_RECOGNISED 1 + +#endif /* __sgi */ + +/* ----------------------------------------------------------------------- */ +/* T R U 6 4 */ +/* ----------------------------------------------------------------------- */ +#ifdef __osf__ +# undef MENTAT + +# include <kern/lock.h> +# include <sys/sysmacros.h> + +# ifdef _KERNEL +# define KMUTEX_T simple_lock_data_t +# define KRWLOCK_T lock_data_t +# include <net/net_globals.h> +# define USE_MUTEXES +# define READ_ENTER(x) lock_read(&(x)->ipf_lk) +# define WRITE_ENTER(x) lock_write(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) lock_write_to_read(&(x)->ipf_lk) +# define RWLOCK_INIT(x, y) lock_init(&(x)->ipf_lk, TRUE) +# define RWLOCK_EXIT(x) lock_done(&(x)->ipf_lk) +# define RW_DESTROY(x) lock_terminate(&(x)->ipf_lk) +# define MUTEX_ENTER(x) simple_lock(&(x)->ipf_lk) +# define MUTEX_INIT(x, y) simple_lock_init(&(x)->ipf_lk) +# define MUTEX_DESTROY(x) simple_lock_terminate(&(x)->ipf_lk) +# define MUTEX_EXIT(x) simple_unlock(&(x)->ipf_lk) +# define MUTEX_NUKE(x) bzero(x, sizeof(*(x))) +# define ATOMIC_INC64(x) atomic_incq((uint64_t*)&(x)) +# define ATOMIC_DEC64(x) atomic_decq((uint64_t*)&(x)) +# define ATOMIC_INC32(x) atomic_incl((uint32_t*)&(x)) +# define ATOMIC_DEC32(x) atomic_decl((uint32_t*)&(x)) +# define ATOMIC_INC16(x) { simple_lock(&ipf_rw); (x)++; \ + simple_unlock(&ipf_rw); } +# define ATOMIC_DEC16(x) { simple_lock(&ipf_rw); (x)--; \ + simple_unlock(&ipf_rw); } +# define ATOMIC_INCL(x) atomic_incl((uint32_t*)&(x)) +# define ATOMIC_DECL(x) atomic_decl((uint32_t*)&(x)) +# define ATOMIC_INC(x) { simple_lock(&ipf_rw); (x)++; \ + simple_unlock(&ipf_rw); } +# define ATOMIC_DEC(x) { simple_lock(&ipf_rw); (x)--; \ + simple_unlock(&ipf_rw); } +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a, b, d) +# define FREE_MB_T(m) m_freem(m) +# define MTOD(m,t) mtod(m,t) +# define GETIFP(n, v) ifunit(n) +# define GET_MINOR getminor +# define WAKEUP(id,x) wakeup(id + x) +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFILT, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFILT, \ + ((c) > 4096) ? M_WAITOK : M_NOWAIT) +# define KFREE(x) FREE((x), M_PFILT) +# define KFREES(x,s) FREE((x), M_PFILT) +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define GETKTIME(x) microtime((struct timeval *)x) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# endif /* _KERNEL */ + +# if (defined(_KERNEL) || defined(_NO_BITFIELDS) || (__STDC__ == 1)) +# define IP_V(x) ((x)->ip_vhl >> 4) +# define IP_HL(x) ((x)->ip_vhl & 0xf) +# define IP_V_A(x,y) (x)->ip_vhl |= (((y) << 4) & 0xf0) +# define IP_HL_A(x,y) (x)->ip_vhl |= ((y) & 0xf) +# define TCP_X2(x) ((x)->th_xoff & 0xf) +# define TCP_X2_A(x,y) (x)->th_xoff |= ((y) & 0xf) +# define TCP_OFF(x) ((x)->th_xoff >> 4) +# define TCP_OFF_A(x,y) (x)->th_xoff |= (((y) << 4) & 0xf0) # endif -#endif /* __FreeBSD__ && KERNEL */ -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 500000) && \ - defined(_KERNEL) -# include <machine/in_cksum.h> -#endif +/* + * These are from's Solaris' #defines for little endian. + */ +#define IP6F_MORE_FRAG 0x0100 +#define IP6F_RESERVED_MASK 0x0600 +#define IP6F_OFF_MASK 0xf8ff + +struct ip6_ext { + u_char ip6e_nxt; + u_char ip6e_len; +}; +typedef int ioctlcmd_t; /* - * These operating systems already take care of the problem for us. + * Really, any arch where sizeof(long) != sizeof(int). */ -#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ - defined(__sgi) -typedef u_int32_t u_32_t; +typedef unsigned int u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* __osf__ */ + +/* ----------------------------------------------------------------------- */ +/* N E T B S D */ +/* ----------------------------------------------------------------------- */ +#ifdef __NetBSD__ # if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "bpfilter.h" # 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 +# define USE_INET6 +# endif +# if (__NetBSD_Version__ >= 105000000) +# define HAVE_M_PULLDOWN 1 +# endif +# endif + +# ifdef _KERNEL +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define GETKTIME(x) microtime((struct timeval *)x) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +typedef struct mbuf mb_t; +# endif /* _KERNEL */ +# if (NetBSD <= 1991011) && (NetBSD >= 199606) +# define IFNAME(x) ((struct ifnet *)x)->if_xname +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) +# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index)&7) +# else +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) # endif -# if !defined(_KERNEL) && !defined(IPFILTER_LKM) && !defined(USE_INET6) -# if (defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ - !defined(NOINET6)) || \ - (defined(OpenBSD) && (OpenBSD >= 200111)) || \ - (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000)) + +typedef struct uio uio_t; +typedef u_long ioctlcmd_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* __NetBSD__ */ + + +/* ----------------------------------------------------------------------- */ +/* F R E E B S D */ +/* ----------------------------------------------------------------------- */ +#ifdef __FreeBSD__ +# if defined(_KERNEL) && !defined(IPFILTER_LKM) && !defined(KLD_MODULE) +# if (__FreeBSD_version >= 500000) +# include "opt_bpf.h" +# else +# include "bpf.h" +# endif +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) +# include "opt_inet6.h" +# endif +# if defined(INET6) && !defined(USE_INET6) # define USE_INET6 # endif # endif -#else + +# if defined(_KERNEL) +# if (__FreeBSD_version >= 400000) /* - * Really, any arch where sizeof(long) != sizeof(int). + * When #define'd, the 5.2.1 kernel panics when used with the ftp proxy. + * There may be other, safe, kernels but this is not extensively tested yet. */ -# if defined(__alpha__) || defined(__alpha) || defined(_LP64) -typedef unsigned int u_32_t; -# else -# if SOLARIS2 >= 6 -typedef uint32_t u_32_t; +# define HAVE_M_PULLDOWN +# endif +# if !defined(IPFILTER_LKM) && (__FreeBSD_version >= 300000) +# include "opt_ipfilter.h" +# endif +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) + +# if (__FreeBSD_version >= 500043) +# define NETBSD_PF +# endif +# endif /* _KERNEL */ + +# if (__FreeBSD_version >= 500043) +# include <sys/mutex.h> +# include <sys/sx.h> +/* + * Whilst the sx(9) locks on FreeBSD have the right semantics and interface + * for what we want to use them for, despite testing showing they work - + * with a WITNESS kernel, it generates LOR messages. + */ +# define KMUTEX_T struct mtx +# if 1 +# define KRWLOCK_T struct mtx # else -typedef unsigned int u_32_t; +# define KRWLOCK_T struct sx # 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> +# if (__FreeBSD_version >= 501113) +# include <net/if_var.h> +# define IFNAME(x) ((struct ifnet *)x)->if_xname +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) +# endif +# if (__FreeBSD_version >= 500043) +# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index) & 7) +# else +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# endif + +# ifdef _KERNEL +# define GETKTIME(x) microtime((struct timeval *)x) + +# if (__FreeBSD_version >= 500002) +# include <netinet/in_systm.h> +# include <netinet/ip.h> +# include <machine/in_cksum.h> +# endif + +# if (__FreeBSD_version >= 500043) +# define USE_MUTEXES +# define MUTEX_ENTER(x) mtx_lock(&(x)->ipf_lk) +# define MUTEX_EXIT(x) mtx_unlock(&(x)->ipf_lk) +# define MUTEX_INIT(x,y) mtx_init(&(x)->ipf_lk, (y), NULL,\ + MTX_DEF) +# define MUTEX_DESTROY(x) mtx_destroy(&(x)->ipf_lk) +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) +/* + * Whilst the sx(9) locks on FreeBSD have the right semantics and interface + * for what we want to use them for, despite testing showing they work - + * with a WITNESS kernel, it generates LOR messages. + */ +# if 1 +# define READ_ENTER(x) mtx_lock(&(x)->ipf_lk) +# define WRITE_ENTER(x) mtx_lock(&(x)->ipf_lk) +# define RWLOCK_EXIT(x) mtx_unlock(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_INIT(x,y) mtx_init(&(x)->ipf_lk, (y), NULL,\ + MTX_DEF) +# define RW_DESTROY(x) mtx_destroy(&(x)->ipf_lk) +# else +# define READ_ENTER(x) sx_slock(&(x)->ipf_lk) +# define WRITE_ENTER(x) sx_xlock(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) sx_downgrade(&(x)->ipf_lk) +# define RWLOCK_INIT(x, y) sx_init(&(x)->ipf_lk, (y)) +# define RW_DESTROY(x) sx_destroy(&(x)->ipf_lk) +# ifdef sx_unlock +# define RWLOCK_EXIT(x) sx_unlock(x) +# else +# define RWLOCK_EXIT(x) do { \ + if ((x)->ipf_lk.sx_cnt < 0) \ + sx_xunlock(&(x)->ipf_lk); \ + else \ + sx_sunlock(&(x)->ipf_lk); \ + } while (0) +# endif +# endif +# include <machine/atomic.h> +# define ATOMIC_INC(x) { mtx_lock(&ipf_rw.ipf_lk); (x)++; \ + mtx_unlock(&ipf_rw.ipf_lk); } +# define ATOMIC_DEC(x) { mtx_lock(&ipf_rw.ipf_lk); (x)--; \ + mtx_unlock(&ipf_rw.ipf_lk); } +# define ATOMIC_INCL(x) atomic_add_long(&(x), 1) +# define ATOMIC_INC64(x) ATOMIC_INC(x) +# define ATOMIC_INC32(x) atomic_add_32(&(x), 1) +# define ATOMIC_INC16(x) atomic_add_16(&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long(&(x), -1) +# define ATOMIC_DEC64(x) ATOMIC_DEC(x) +# define ATOMIC_DEC32(x) atomic_add_32(&(x), -1) +# define ATOMIC_DEC16(x) atomic_add_16(&(x), -1) +# define SPL_X(x) ; +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +extern int in_cksum __P((struct mbuf *, int)); +# endif /* __FreeBSD_version >= 500043 */ +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# endif /* _KERNEL */ + +# if __FreeBSD__ < 3 +# include <machine/spl.h> +# else +# if __FreeBSD__ == 3 +# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) +# define ACTUALLY_LKM_NOT_KERNEL +# endif # endif -typedef struct ip6_hdr ip6_t; # endif -# include <netinet/icmp6.h> -union i6addr { - u_32_t i6[4]; - struct in_addr in4; - struct in6_addr in6; + +# if (__FreeBSD_version >= 300000) +typedef u_long ioctlcmd_t; +# else +typedef int ioctlcmd_t; +# endif +typedef struct uio uio_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* __FreeBSD__ */ + + +/* ----------------------------------------------------------------------- */ +/* O P E N B S D */ +/* ----------------------------------------------------------------------- */ +#ifdef __OpenBSD__ +# ifdef INET6 +# define USE_INET6 +# endif + +# ifdef _KERNEL +# if !defined(IPFILTER_LKM) +# include "bpfilter.h" +# endif +# if (OpenBSD >= 200311) +# define SNPRINTF snprintf +# if defined(USE_INET6) +# include "netinet6/in6_var.h" +# include "netinet6/nd6.h" +# endif +# endif +# if (OpenBSD >= 200012) +# define HAVE_M_PULLDOWN 1 +# endif +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define GETKTIME(x) microtime((struct timeval *)x) +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# endif /* _KERNEL */ +# if (OpenBSD >= 199603) +# define IFNAME(x, b) ((struct ifnet *)x)->if_xname +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) +# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index)&7) +# else +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# endif + +typedef struct uio uio_t; +typedef u_long ioctlcmd_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* __OpenBSD__ */ + + +/* ----------------------------------------------------------------------- */ +/* B S D O S */ +/* ----------------------------------------------------------------------- */ +#ifdef _BSDI_VERSION +# ifdef INET6 +# define USE_INET6 +# endif + +# ifdef _KERNEL +# define GETKTIME(x) microtime((struct timeval *)x) +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +typedef struct mbuf mb_t; +# endif /* _KERNEL */ + +# if (_BSDI_VERSION >= 199701) +typedef u_long ioctlcmd_t; +# else +typedef int ioctlcmd_t; +# endif +typedef u_int32_t u_32_t; +# define U_32_T 1 + +#endif /* _BSDI_VERSION */ + + +/* ----------------------------------------------------------------------- */ +/* S U N O S 4 */ +/* ----------------------------------------------------------------------- */ +#if defined(sun) && !defined(OS_RECOGNISED) /* SunOS4 */ +# ifdef _KERNEL +# include <sys/kmem_alloc.h> +# define GETKTIME(x) uniqtime((struct timeval *)x) +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# define GETIFP(n, v) ifunit(n, IFNAMSIZ) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define SLEEP(id, n) sleep((id), PZERO+1) +# define WAKEUP(id,x) wakeup(id + x) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } + +extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); +extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); + +typedef struct mbuf mb_t; +# endif + +typedef struct uio uio_t; +typedef int ioctlcmd_t; +typedef int minor_t; +typedef unsigned int u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 + +#endif /* SunOS 4 */ + +/* ----------------------------------------------------------------------- */ +/* L I N U X */ +/* ----------------------------------------------------------------------- */ +#if defined(linux) && !defined(OS_RECOGNISED) +#include <linux/config.h> +#include <linux/version.h> +# if LINUX >= 20600 +# define HDR_T_PRIVATE 1 +# endif +# undef USE_INET6 +# ifdef USE_INET6 +struct ip6_ext { + u_char ip6e_nxt; + u_char ip6e_len; }; -#else -union i6addr { - u_32_t i6[4]; - struct in_addr in4; +# endif + +# ifdef _KERNEL +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYIN(a,b,c) copy_from_user((caddr_t)(b), (caddr_t)(a), (c)) +# define COPYOUT(a,b,c) copy_to_user((caddr_t)(b), (caddr_t)(a), (c)) +# define FREE_MB_T(m) kfree_skb(m) +# define GETKTIME(x) do_gettimeofday((struct timeval *)x) +# define SLEEP(x,s) 0, interruptible_sleep_on(x##_linux) +# define WAKEUP(x,y) wake_up(x##_linux + y) +# define UIOMOVE(a,b,c,d) uiomove(a,b,c,d) +# define USE_MUTEXES +# define KRWLOCK_T rwlock_t +# define KMUTEX_T spinlock_t +# define MUTEX_INIT(x,y) spin_lock_init(&(x)->ipf_lk) +# define MUTEX_ENTER(x) spin_lock(&(x)->ipf_lk) +# define MUTEX_EXIT(x) spin_unlock(&(x)->ipf_lk) +# define MUTEX_DESTROY(x) do { } while (0) +# define MUTEX_NUKE(x) bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk)) +# define READ_ENTER(x) ipf_read_enter(x) +# define WRITE_ENTER(x) ipf_write_enter(x) +# define RWLOCK_INIT(x,y) rwlock_init(&(x)->ipf_lk) +# define RW_DESTROY(x) do { } while (0) +# define RWLOCK_EXIT(x) ipf_rw_exit(x) +# define MUTEX_DOWNGRADE(x) ipf_rw_downgrade(x) +# define ATOMIC_INCL(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DECL(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_INC64(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_INC32(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_INC16(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DEC64(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DEC32(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DEC16(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define SPL_IMP(x) do { } while (0) +# define SPL_NET(x) do { } while (0) +# define SPL_X(x) do { } while (0) +# define IFNAME(x) ((struct net_device*)x)->name +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct net_device *)fin->fin_ifp)->ifindex) & 7) +typedef struct sk_buff mb_t; +extern void m_copydata __P((mb_t *, int, int, caddr_t)); +extern void m_copyback __P((mb_t *, int, int, caddr_t)); +extern void m_adj __P((mb_t *, int)); +extern mb_t *m_pullup __P((mb_t *, int)); +# define mbuf sk_buff + +# define mtod(m, t) ((t)(m)->data) +# define m_len len +# define m_next next +# define M_DUPLICATE(m) skb_clone((m), in_interrupt() ? GFP_ATOMIC : \ + GFP_KERNEL) +# define MSGDSIZE(m) (m)->len +# define M_LEN(m) (m)->len + +# define splnet(x) ; +# define printf printk +# define bcopy(s,d,z) memmove(d, s, z) +# define bzero(s,z) memset(s, 0, z) +# define bcmp(a,b,z) memcmp(a, b, z) + +# define ifnet net_device +# define if_xname name +# define if_unit ifindex + +# define KMALLOC(x,t) (x) = (t)kmalloc(sizeof(*(x)), \ + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) +# define KFREE(x) kfree(x) +# define KMALLOCS(x,t,s) (x) = (t)kmalloc((s), \ + in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) +# define KFREES(x,s) kfree(x) + +# define GETIFP(n,v) dev_get_by_name(n) + +# else +# include <net/ethernet.h> + +struct mbuf { }; + +# ifndef _NET_ROUTE_H +struct rtentry { +}; +# endif + +struct ifnet { + char if_xname[IFNAMSIZ]; + int if_unit; + int (* if_output) __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); + struct ifaddr *if_addrlist; +}; +# define IFNAME(x) ((struct ifnet *)x)->if_xname + +# endif /* _KERNEL */ + +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) + +# include <linux/fs.h> +# define FWRITE FMODE_WRITE +# define FREAD FMODE_READ + +# define __USE_MISC 1 +# define __FAVOR_BSD 1 + +typedef struct uio { + struct iovec *uio_iov; + void *uio_file; + char *uio_buf; + int uio_iovcnt; + int uio_offset; + size_t uio_resid; + int uio_rw; +} uio_t; + +extern int uiomove __P((caddr_t, size_t, int, struct uio *)); + +# define UIO_READ 1 +# define UIO_WRITE 2 + +typedef u_long ioctlcmd_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 + +#endif + + +#ifndef OS_RECOGNISED +#error ip_compat.h does not recognise this platform/OS. #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) -#define IP6_ISZERO(a) ((((union i6addr *)(a))->i6[0] | \ - ((union i6addr *)(a))->i6[1] | \ - ((union i6addr *)(a))->i6[2] | \ - ((union i6addr *)(a))->i6[3]) == 0) -#define IP6_NOTZERO(a) ((((union i6addr *)(a))->i6[0] | \ - ((union i6addr *)(a))->i6[1] | \ - ((union i6addr *)(a))->i6[2] | \ - ((union i6addr *)(a))->i6[3]) != 0) + +/* ----------------------------------------------------------------------- */ +/* G E N E R I C */ +/* ----------------------------------------------------------------------- */ +#ifndef OS_RECOGNISED +#endif + +/* + * For BSD kernels, if bpf is in the kernel, enable ipfilter to use bpf in + * filter rules. + */ +#if !defined(IPFILTER_BPF) && ((NBPF > 0) || (NBPFILTER > 0)) +# define IPFILTER_BPF +#endif + +/* + * Userland locking primitives + */ +typedef struct { + char *eMm_owner; + char *eMm_heldin; + u_int eMm_magic; + int eMm_held; + int eMm_heldat; +#ifdef __hpux + char eMm_fill[8]; +#endif +} eMmutex_t; + +typedef struct { + char *eMrw_owner; + char *eMrw_heldin; + u_int eMrw_magic; + short eMrw_read; + short eMrw_write; + int eMrw_heldat; +#ifdef __hpux + char eMm_fill[24]; +#endif +} eMrwlock_t; + +typedef union { +#ifdef KMUTEX_T + struct { + KMUTEX_T ipf_slk; + char *ipf_lname; + } ipf_lkun_s; +#endif + eMmutex_t ipf_emu; +} ipfmutex_t; + +typedef union { +#ifdef KRWLOCK_T + struct { + KRWLOCK_T ipf_slk; + char *ipf_lname; + int ipf_sr; + int ipf_sw; + u_int ipf_magic; + } ipf_lkun_s; +#endif + eMrwlock_t ipf_emu; +} ipfrwlock_t; + +#define ipf_lk ipf_lkun_s.ipf_slk +#define ipf_lname ipf_lkun_s.ipf_lname +#define ipf_isr ipf_lkun_s.ipf_sr +#define ipf_isw ipf_lkun_s.ipf_sw +#define ipf_magic ipf_lkun_s.ipf_magic + +#if !defined(__GNUC__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version >= 503000)) +# ifndef INLINE +# define INLINE +# endif +#else +# define INLINE __inline__ +#endif + +#if defined(linux) && defined(_KERNEL) +extern INLINE void ipf_read_enter __P((ipfrwlock_t *)); +extern INLINE void ipf_write_enter __P((ipfrwlock_t *)); +extern INLINE void ipf_rw_exit __P((ipfrwlock_t *)); +extern INLINE void ipf_rw_downgrade __P((ipfrwlock_t *)); +#endif + +/* + * In a non-kernel environment, there are a lot of macros that need to be + * filled in to be null-ops or to point to some compatibility function, + * somewhere in userland. + */ +#ifndef _KERNEL +typedef struct mb_s { + struct mb_s *mb_next; + int mb_len; + u_long mb_buf[2048]; +} mb_t; +# undef m_next +# define m_next mb_next +# define MSGDSIZE(x) (x)->mb_len /* XXX - from ipt.c */ +# define M_LEN(x) (x)->mb_len +# define M_DUPLICATE(x) (x) +# define GETKTIME(x) gettimeofday((struct timeval *)(x), NULL) +# define MTOD(m, t) ((t)(m)->mb_buf) +# define FREE_MB_T(x) +# define SLEEP(x,y) 1; +# define WAKEUP(x,y) ; +# define IPF_PANIC(x,y) ; +# define PANIC(x,y) ; +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# define SPL_X(x) ; +# define KMALLOC(a,b) (a) = (b)malloc(sizeof(*a)) +# define KMALLOCS(a,b,c) (a) = (b)malloc(c) +# define KFREE(x) free(x) +# define KFREES(x,s) free(x) +# define GETIFP(x, v) get_unit(x,v) +# define COPYIN(a,b,c) (bcopy((a), (b), (c)), 0) +# define COPYOUT(a,b,c) (bcopy((a), (b), (c)), 0) +# define BCOPYIN(a,b,c) (bcopy((a), (b), (c)), 0) +# define BCOPYOUT(a,b,c) (bcopy((a), (b), (c)), 0) +# define COPYDATA(m, o, l, b) bcopy(MTOD((mb_t *)m, char *) + (o), \ + (b), (l)) +# define COPYBACK(m, o, l, b) bcopy((b), \ + MTOD((mb_t *)m, char *) + (o), \ + (l)) +# define UIOMOVE(a,b,c,d) ipfuiomove(a,b,c,d) +extern void m_copydata __P((mb_t *, int, int, caddr_t)); +extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); +# ifndef CACHE_HASH +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# endif + +# define MUTEX_DESTROY(x) eMmutex_destroy(&(x)->ipf_emu) +# define MUTEX_ENTER(x) eMmutex_enter(&(x)->ipf_emu, \ + __FILE__, __LINE__) +# define MUTEX_EXIT(x) eMmutex_exit(&(x)->ipf_emu) +# define MUTEX_INIT(x,y) eMmutex_init(&(x)->ipf_emu, y) +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) + +# define MUTEX_DOWNGRADE(x) eMrwlock_downgrade(&(x)->ipf_emu, \ + __FILE__, __LINE__) +# define READ_ENTER(x) eMrwlock_read_enter(&(x)->ipf_emu, \ + __FILE__, __LINE__) +# define RWLOCK_INIT(x, y) eMrwlock_init(&(x)->ipf_emu, y) +# define RWLOCK_EXIT(x) eMrwlock_exit(&(x)->ipf_emu) +# define RW_DESTROY(x) eMrwlock_destroy(&(x)->ipf_emu) +# define WRITE_ENTER(x) eMrwlock_write_enter(&(x)->ipf_emu, \ + __FILE__, \ + __LINE__) + +# define USE_MUTEXES 1 + +extern void eMmutex_destroy __P((eMmutex_t *)); +extern void eMmutex_enter __P((eMmutex_t *, char *, int)); +extern void eMmutex_exit __P((eMmutex_t *)); +extern void eMmutex_init __P((eMmutex_t *, char *)); +extern void eMrwlock_destroy __P((eMrwlock_t *)); +extern void eMrwlock_exit __P((eMrwlock_t *)); +extern void eMrwlock_init __P((eMrwlock_t *, char *)); +extern void eMrwlock_read_enter __P((eMrwlock_t *, char *, int)); +extern void eMrwlock_write_enter __P((eMrwlock_t *, char *, int)); +extern void eMrwlock_downgrade __P((eMrwlock_t *, char *, int)); + +#endif + +#define MAX_IPV4HDR ((0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8) + +#ifndef IP_OFFMASK +# define IP_OFFMASK 0x1fff +#endif + + +/* + * On BSD's use quad_t as a guarantee for getting at least a 64bit sized + * object. + */ +#if BSD > 199306 +# define USE_QUAD_T +# define U_QUAD_T u_quad_t +# define QUAD_T quad_t +#else /* BSD > 199306 */ +# define U_QUAD_T u_long +# define QUAD_T long +#endif /* BSD > 199306 */ + + +#ifdef USE_INET6 +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ + defined(__osf__) || defined(linux) +# include <netinet/ip6.h> +# include <netinet/icmp6.h> +# if !defined(linux) +# if defined(_KERNEL) && !defined(__osf__) +# include <netinet6/ip6_var.h> +# endif +# endif +typedef struct ip6_hdr ip6_t; +# endif +#endif #ifndef MAX -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +# define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#if defined(_KERNEL) +# ifdef MENTAT +# define COPYDATA mb_copydata +# define COPYBACK mb_copyback +# else +# define COPYDATA m_copydata +# define COPYBACK m_copyback +# endif +# if (BSD >= 199306) || defined(__FreeBSD__) +# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105180000)) || \ + defined(__FreeBSD__) || (defined(OpenBSD) && (OpenBSD < 200206)) || \ + defined(_BSDI_VERSION) +# include <vm/vm.h> +# endif +# if !defined(__FreeBSD__) || (defined (__FreeBSD_version) && \ + (__FreeBSD_version >= 300000)) +# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105180000)) || \ + (defined(OpenBSD) && (OpenBSD >= 200111)) +# include <uvm/uvm_extern.h> +# else +# include <vm/vm_extern.h> +extern vm_map_t kmem_map; +# endif +# include <sys/proc.h> +# else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ +# include <vm/vm_kern.h> +# endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ + +# ifdef IPFILTER_M_IPFILTER +# include <sys/malloc.h> +MALLOC_DECLARE(M_IPFILTER); +# define _M_IPF M_IPFILTER +# else /* IPFILTER_M_IPFILTER */ +# ifdef M_PFIL +# define _M_IPF M_PFIL +# else +# ifdef M_IPFILTER +# define _M_IPF M_IPFILTER +# else +# define _M_IPF M_TEMP +# endif /* M_IPFILTER */ +# endif /* M_PFIL */ +# endif /* IPFILTER_M_IPFILTER */ +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), _M_IPF, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), _M_IPF, M_NOWAIT) +# define KFREE(x) FREE((x), _M_IPF) +# define KFREES(x,s) FREE((x), _M_IPF) +# define UIOMOVE(a,b,c,d) uiomove(a,b,d) +# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0) +# define WAKEUP(id,x) wakeup(id+x) +# define GETIFP(n, v) ifunit(n) +# endif /* (Free)BSD */ + +# if !defined(USE_MUTEXES) && !defined(SPL_NET) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \ + (defined(OpenBSD) && (OpenBSD >= 200006)) +# define SPL_NET(x) x = splsoftnet() +# else +# define SPL_IMP(x) x = splimp() +# define SPL_NET(x) x = splnet() +# endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */ +# define SPL_X(x) (void) splx(x) +# endif /* !USE_MUTEXES */ + +# ifndef FREE_MB_T +# define FREE_MB_T(m) m_freem(m) +# endif + +# ifndef MTOD +# define MTOD(m,t) mtod(m,t) +# endif + +# ifndef COPYIN +# define COPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define COPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# endif + +# ifndef KMALLOC +# define KMALLOC(a,b) (a) = (b)new_kmem_alloc(sizeof(*(a)), \ + KMEM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) +# endif + +# ifndef GET_MINOR +# define GET_MINOR(x) minor(x) +# endif +# define PANIC(x,y) if (x) panic y +#endif /* _KERNEL */ + +#ifndef IFNAME +# define IFNAME(x) ((struct ifnet *)x)->if_name +#endif +#ifndef COPYIFNAME +# define NEED_FRGETIFNAME +extern char *fr_getifname __P((struct ifnet *, char *)); +# define COPYIFNAME(x, b) \ + fr_getifname((struct ifnet *)x, b) +#endif + +#ifndef ASSERT +# define ASSERT(x) #endif /* + * Because the ctype(3) posix definition, if used "safely" in code everywhere, + * would mean all normal code that walks through strings needed casts. Yuck. + */ +#define ISALNUM(x) isalnum((u_char)(x)) +#define ISALPHA(x) isalpha((u_char)(x)) +#define ISASCII(x) isascii((u_char)(x)) +#define ISDIGIT(x) isdigit((u_char)(x)) +#define ISPRINT(x) isprint((u_char)(x)) +#define ISSPACE(x) isspace((u_char)(x)) +#define ISUPPER(x) isupper((u_char)(x)) +#define ISXDIGIT(x) isxdigit((u_char)(x)) +#define ISLOWER(x) islower((u_char)(x)) +#define TOUPPER(x) toupper((u_char)(x)) +#define TOLOWER(x) tolower((u_char)(x)) + +/* + * If mutexes aren't being used, turn all the mutex functions into null-ops. + */ +#if !defined(USE_MUTEXES) +# define USE_SPL 1 +# undef RW_DESTROY +# undef MUTEX_INIT +# undef MUTEX_NUKE +# undef MUTEX_DESTROY +# define MUTEX_ENTER(x) ; +# define READ_ENTER(x) ; +# define WRITE_ENTER(x) ; +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_INIT(x, y) ; +# define RWLOCK_EXIT(x) ; +# define RW_DESTROY(x) ; +# define MUTEX_EXIT(x) ; +# define MUTEX_INIT(x,y) ; +# define MUTEX_DESTROY(x) ; +# define MUTEX_NUKE(x) ; +#endif /* !USE_MUTEXES */ +#ifndef ATOMIC_INC +# define ATOMIC_INC(x) (x)++ +# define ATOMIC_DEC(x) (x)-- +#endif + +/* + * If there are no atomic operations for bit sizes defined, define them to all + * use a generic one that works for all sizes. + */ +#ifndef ATOMIC_INCL +# 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 + +#ifndef HDR_T_PRIVATE +typedef struct tcphdr tcphdr_t; +typedef struct udphdr udphdr_t; +#endif +typedef struct icmp icmphdr_t; +typedef struct ip ip_t; +typedef struct ether_header ether_header_t; +typedef struct tcpiphdr tcpiphdr_t; + +#ifndef FR_GROUPLEN +# define FR_GROUPLEN 16 +#endif + +#ifdef offsetof +# undef offsetof +#endif +#ifndef offsetof +# define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif + +/* + * This set of macros has been brought about because on Tru64 it is not + * possible to easily assign or examine values in a structure that are + * bit fields. + */ +#ifndef IP_V +# define IP_V(x) (x)->ip_v +#endif +#ifndef IP_V_A +# define IP_V_A(x,y) (x)->ip_v = (y) +#endif +#ifndef IP_HL +# define IP_HL(x) (x)->ip_hl +#endif +#ifndef IP_HL_A +# define IP_HL_A(x,y) (x)->ip_hl = (y) +#endif +#ifndef TCP_X2 +# define TCP_X2(x) (x)->th_x2 +#endif +#ifndef TCP_X2_A +# define TCP_X2_A(x,y) (x)->th_x2 = (y) +#endif +#ifndef TCP_OFF +# define TCP_OFF(x) (x)->th_off +#endif +#ifndef TCP_OFF_A +# define TCP_OFF_A(x,y) (x)->th_off = (y) +#endif +#define IPMINLEN(i, h) ((i)->ip_len >= (IP_HL(i) * 4 + sizeof(struct h))) + + +/* + * XXX - This is one of those *awful* hacks which nobody likes + */ +#ifdef ultrix +#define A_A +#else +#define A_A & +#endif + +#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|\ + TH_ECN|TH_CWR) + +#if (BSD >= 199306) && !defined(m_act) +# define m_act m_nextpkt +#endif + +/* * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108. * * Basic Option @@ -355,320 +1680,87 @@ union i6addr { /* * IP option #defines */ -/*#define IPOPT_RR 7 */ +#undef IPOPT_RR +#define IPOPT_RR 7 +#undef IPOPT_ZSU #define IPOPT_ZSU 10 /* ZSU */ +#undef IPOPT_MTUP #define IPOPT_MTUP 11 /* MTUP */ +#undef IPOPT_MTUR #define IPOPT_MTUR 12 /* MTUR */ +#undef IPOPT_ENCODE #define IPOPT_ENCODE 15 /* ENCODE */ -/*#define IPOPT_TS 68 */ +#undef IPOPT_TS +#define IPOPT_TS 68 +#undef IPOPT_TR #define IPOPT_TR 82 /* TR */ -/*#define IPOPT_SECURITY 130 */ -/*#define IPOPT_LSRR 131 */ +#undef IPOPT_SECURITY +#define IPOPT_SECURITY 130 +#undef IPOPT_LSRR +#define IPOPT_LSRR 131 +#undef IPOPT_E_SEC #define IPOPT_E_SEC 133 /* E-SEC */ +#undef IPOPT_CIPSO #define IPOPT_CIPSO 134 /* CIPSO */ -/*#define IPOPT_SATID 136 */ +#undef IPOPT_SATID +#define IPOPT_SATID 136 #ifndef IPOPT_SID # define IPOPT_SID IPOPT_SATID #endif -/*#define IPOPT_SSRR 137 */ +#undef IPOPT_SSRR +#define IPOPT_SSRR 137 +#undef IPOPT_ADDEXT #define IPOPT_ADDEXT 147 /* ADDEXT */ +#undef IPOPT_VISA #define IPOPT_VISA 142 /* VISA */ +#undef IPOPT_IMITD #define IPOPT_IMITD 144 /* IMITD */ +#undef IPOPT_EIP #define IPOPT_EIP 145 /* EIP */ +#undef IPOPT_RTRALRT +#define IPOPT_RTRALRT 148 /* RTRALRT */ +#undef IPOPT_SDB +#define IPOPT_SDB 149 +#undef IPOPT_NSAPA +#define IPOPT_NSAPA 150 +#undef IPOPT_DPS +#define IPOPT_DPS 151 +#undef IPOPT_UMP +#define IPOPT_UMP 152 +#undef IPOPT_FINN #define IPOPT_FINN 205 /* FINN */ -#ifndef TCPOPT_WSCALE -# define TCPOPT_WSCALE 3 +#ifndef TCPOPT_EOL +# define TCPOPT_EOL 0 #endif - -/* - * Build some macros and #defines to enable the same code to compile anywhere - * Well, that's the idea, anyway :-) - */ -#if SOLARIS -typedef mblk_t mb_t; -# if SOLARIS2 >= 7 -# ifdef lint -# define ALIGN32(ptr) (ptr ? 0L : 0L) -# define ALIGN16(ptr) (ptr ? 0L : 0L) -# else -# define ALIGN32(ptr) (ptr) -# define ALIGN16(ptr) (ptr) -# endif -# endif -#else -typedef struct mbuf mb_t; -#endif /* SOLARIS */ - -#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 +#ifndef TCPOPT_NOP +# define TCPOPT_NOP 1 #endif -#ifdef __sgi -# define hz HZ -# include <sys/ksynch.h> -# define IPF_LOCK_PL plhi -# include <sys/sema.h> -#undef kmutex_t -typedef struct { - lock_t *l; - int pl; -} kmutex_t; -# undef MUTEX_INIT -# undef MUTEX_DESTROY +#ifndef TCPOPT_MAXSEG +# define TCPOPT_MAXSEG 2 +#endif +#ifndef TCPOLEN_MAXSEG +# define TCPOLEN_MAXSEG 4 +#endif +#ifndef TCPOPT_WINDOW +# define TCPOPT_WINDOW 3 +#endif +#ifndef TCPOLEN_WINDOW +# define TCPOLEN_WINDOW 3 +#endif +#ifndef TCPOPT_SACK_PERMITTED +# define TCPOPT_SACK_PERMITTED 4 +#endif +#ifndef TCPOLEN_SACK_PERMITTED +# define TCPOLEN_SACK_PERMITTED 2 +#endif +#ifndef TCPOPT_SACK +# define TCPOPT_SACK 5 +#endif +#ifndef TCPOPT_TIMESTAMP +# define TCPOPT_TIMESTAMP 8 #endif -#ifdef KERNEL -# if SOLARIS -# 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 IRE_CACHE IRE_ROUTE -# define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ - mutex_exit(&ipf_rw); } -# 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 -# define READ_ENTER(x) rw_enter(x, RW_READER) -# define WRITE_ENTER(x) rw_enter(x, RW_WRITER) -# define RW_UPGRADE(x) { if (rw_tryupgrade(x) == 0) { \ - rw_exit(x); \ - rw_enter(x, RW_WRITER); } \ - } -# define MUTEX_DOWNGRADE(x) rw_downgrade(x) -# define RWLOCK_INIT(x, y, z) rw_init((x), (y), RW_DRIVER, (z)) -# define RWLOCK_EXIT(x) rw_exit(x) -# define RW_DESTROY(x) rw_destroy(x) -# else -# define KRWLOCK_T kmutex_t -# define READ_ENTER(x) mutex_enter(x) -# define WRITE_ENTER(x) mutex_enter(x) -# define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) -# 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((caddr_t)(a), (caddr_t)(b), (c)) -# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define IRCOPYPTR ircopyptr -# define IWCOPYPTR iwcopyptr -# define FREE_MB_T(m) freemsg(m) -# define SPL_NET(x) ; -# define SPL_IMP(x) ; -# undef SPL_X -# define SPL_X(x) ; -# ifdef sparc -# define ntohs(x) (x) -# define ntohl(x) (x) -# define htons(x) (x) -# define htonl(x) (x) -# endif /* sparc */ -# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) -# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) -# define GET_MINOR(x) getminor(x) -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 ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ - (x)++; MUTEX_EXIT(&ipf_rw); } -# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ - (x)--; MUTEX_EXIT(&ipf_rw); } -# define MUTEX_ENTER(x) (x)->pl = LOCK((x)->l, IPF_LOCK_PL); -# define KRWLOCK_T kmutex_t -# define READ_ENTER(x) MUTEX_ENTER(x) -# 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 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 MUTEX_DOWNGRADE(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 M_BLEN(m) (m)->m_len -# 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/time.h> -# include <sys/kmem_alloc.h> -# define GETUNIT(n, v) ifunit(n, IFNAMSIZ) -# define IFNAME(x) ((struct ifnet *)x)->if_name -# endif -# else -# ifndef linux -# 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 USE_GETIFNAME 1 -# define IFNAME(x) get_ifname((struct ifnet *)x) -extern char *get_ifname __P((struct ifnet *)); -# endif -# endif -# endif /* sun */ - -# if defined(sun) && !defined(linux) || defined(__sgi) -# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) -# define SLEEP(id, n) sleep((id), PZERO+1) -# define WAKEUP(id) wakeup(id) -# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) -# define KFREES(x,s) kmem_free((char *)(x), (s)) -# if !SOLARIS -extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); -extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); -# endif -# ifdef __sgi -# include <sys/kmem.h> -# include <sys/ddi.h> -# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) -# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) -# define GET_MINOR(x) getminor(x) -# else -# if !SOLARIS -# define KMALLOC(a,b) (a) = (b)new_kmem_alloc(sizeof(*(a)), \ - KMEM_NOSLEEP) -# define KMALLOCS(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) -# endif /* SOLARIS */ -# endif /* __sgi */ -# endif /* sun && !linux */ -# ifndef GET_MINOR -# define GET_MINOR(x) minor(x) -# endif -# if (BSD >= 199306) || defined(__FreeBSD__) -# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105180000)) || \ - defined(__FreeBSD__) || (defined(OpenBSD) && (OpenBSD < 200206)) || \ - defined(_BSDI_VERSION) -# include <vm/vm.h> -# endif -# if !defined(__FreeBSD__) || (defined (__FreeBSD_version) && \ - (__FreeBSD_version >= 300000)) -# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105180000)) || \ - (defined(OpenBSD) && (OpenBSD >= 200111)) -# include <uvm/uvm_extern.h> -# else -# include <vm/vm_extern.h> -extern vm_map_t kmem_map; -# endif -# include <sys/proc.h> -# else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ -# include <vm/vm_kern.h> -# endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ -# ifdef M_PFIL -# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFIL, M_NOWAIT) -# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) -# define KFREE(x) FREE((x), M_PFIL) -# define KFREES(x,s) FREE((x), M_PFIL) -# else -# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT) -# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT) -# define KFREE(x) FREE((x), M_TEMP) -# define KFREES(x,s) FREE((x), M_TEMP) -# endif /* M_PFIL */ -# define UIOMOVE(a,b,c,d) uiomove(a,b,d) -# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0) -# define WAKEUP(id) wakeup(id) -# endif /* BSD */ -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \ - (defined(OpenBSD) && (OpenBSD >= 200006)) -# define SPL_NET(x) x = splsoftnet() -# define SPL_X(x) (void) splx(x) -# else -# if !SOLARIS && !defined(linux) -# define SPL_IMP(x) x = splimp() -# define SPL_NET(x) x = splnet() -# define SPL_X(x) (void) splx(x) -# endif -# endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */ -# define PANIC(x,y) if (x) panic y -#else /* KERNEL */ -# define SLEEP(x,y) 1 -# define WAKEUP(x) ; -# define PANIC(x,y) ; -# define ATOMIC_INC(x) (x)++ -# 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) ; -# define RWLOCK_EXIT(x) ; -# define MUTEX_EXIT(x) ; -# define SPL_NET(x) ; -# define SPL_IMP(x) ; -# undef SPL_X -# define SPL_X(x) ; -# define KMALLOC(a,b) (a) = (b)malloc(sizeof(*a)) -# define KMALLOCS(a,b,c) (a) = (b)malloc(c) -# define KFREE(x) free(x) -# define KFREES(x,s) free(x) -# define FREE_MB_T(x) ; -# 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 -# define IFNAME(x) get_ifname((struct ifnet *)x) -# define UIOMOVE(a,b,c,d) ipfuiomove(a,b,c,d) -# include <sys/time.h> -extern void m_copydata __P((mb_t *, int, int, caddr_t)); -extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); -#endif /* KERNEL */ -/* - * These #ifdef's are here mainly for linux, but who knows, they may - * not be in other places or maybe one day linux will grow up and some - * of these will turn up there too. - */ #ifndef ICMP_MINLEN # define ICMP_MINLEN 8 #endif @@ -720,6 +1812,9 @@ extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); #ifndef ICMP_UNREACH_ADMIN_PROHIBIT # define ICMP_UNREACH_ADMIN_PROHIBIT 13 #endif +#ifndef ICMP_UNREACH_FILTER +# define ICMP_UNREACH_FILTER 13 +#endif #ifndef ICMP_UNREACH_HOST_PRECEDENCE # define ICMP_UNREACH_HOST_PRECEDENCE 14 #endif @@ -858,6 +1953,9 @@ extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); #ifndef TH_URG # define TH_URG 0x20 #endif +#undef TH_ACKMASK +#define TH_ACKMASK (TH_FIN|TH_SYN|TH_RST|TH_ACK) + #ifndef IPOPT_EOL # define IPOPT_EOL 0 #endif @@ -906,313 +2004,48 @@ extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); #ifndef IPOPT_OLEN # define IPOPT_OLEN 1 #endif +#ifndef IPPROTO_HOPOPTS +# define IPPROTO_HOPOPTS 0 +#endif +#ifndef IPPROTO_ENCAP +# define IPPROTO_ENCAP 4 +#endif +#ifndef IPPROTO_IPV6 +# define IPPROTO_IPV6 41 +#endif +#ifndef IPPROTO_ROUTING +# define IPPROTO_ROUTING 43 +#endif +#ifndef IPPROTO_FRAGMENT +# define IPPROTO_FRAGMENT 44 +#endif #ifndef IPPROTO_GRE # define IPPROTO_GRE 47 /* GRE encaps RFC 1701 */ #endif #ifndef IPPROTO_ESP # define IPPROTO_ESP 50 #endif +#ifndef IPPROTO_AH +# define IPPROTO_AH 51 +#endif #ifndef IPPROTO_ICMPV6 # define IPPROTO_ICMPV6 58 #endif - -#ifdef linux -#include <linux/in_systm.h> -/* - * TCP States - */ -#define TCPS_CLOSED 0 /* closed */ -#define TCPS_LISTEN 1 /* listening for connection */ -#define TCPS_SYN_SENT 2 /* active, have sent syn */ -#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ -/* states < TCPS_ESTABLISHED are those where connections not established */ -#define TCPS_ESTABLISHED 4 /* established */ -#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ -/* states > TCPS_CLOSE_WAIT are those where user has closed */ -#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ -#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ -/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ -#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ - -/* - * file flags. - */ -#ifdef WRITE -#define FWRITE WRITE -#define FREAD READ -#else -#define FWRITE _IOC_WRITE -#define FREAD _IOC_READ +#ifndef IPPROTO_NONE +# define IPPROTO_NONE 59 #endif -/* - * mbuf related problems. - */ -#define mtod(m,t) (t)((m)->data) -#define m_len len -#define m_next next - -#ifdef IP_DF -#undef IP_DF -#endif -#define IP_DF 0x4000 - -typedef struct { - __u16 th_sport; - __u16 th_dport; - __u32 th_seq; - __u32 th_ack; -# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ - defined(__vax__) - __u8 th_res:4; - __u8 th_off:4; -#else - __u8 th_off:4; - __u8 th_res:4; -#endif - __u8 th_flags; - __u16 th_win; - __u16 th_sum; - __u16 th_urp; -} tcphdr_t; - -typedef struct { - __u16 uh_sport; - __u16 uh_dport; - __u16 uh_ulen; - __u16 uh_sum; -} udphdr_t; - -typedef struct { -# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ - defined(__vax__) - __u8 ip_hl:4; - __u8 ip_v:4; -# else - __u8 ip_v:4; - __u8 ip_hl:4; -# endif - __u8 ip_tos; - __u16 ip_len; - __u16 ip_id; - __u16 ip_off; - __u8 ip_ttl; - __u8 ip_p; - __u16 ip_sum; - struct in_addr ip_src; - struct in_addr ip_dst; -} ip_t; - -/* - * Structure of an icmp header. - */ -typedef struct icmp { - __u8 icmp_type; /* type of message, see below */ - __u8 icmp_code; /* type sub code */ - __u16 icmp_cksum; /* ones complement cksum of struct */ - union { - __u8 ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - __u16 icd_id; - __u16 icd_seq; - } ih_idseq; - int ih_void; - } icmp_hun; -# define icmp_pptr icmp_hun.ih_pptr -# define icmp_gwaddr icmp_hun.ih_gwaddr -# define icmp_id icmp_hun.ih_idseq.icd_id -# define icmp_seq icmp_hun.ih_idseq.icd_seq -# define icmp_void icmp_hun.ih_void - union { - struct id_ts { - n_time its_otime; - n_time its_rtime; - n_time its_ttime; - } id_ts; - struct id_ip { - ip_t idi_ip; - /* options and then 64 bits of data */ - } id_ip; - u_long id_mask; - char id_data[1]; - } icmp_dun; -# define icmp_otime icmp_dun.id_ts.its_otime -# define icmp_rtime icmp_dun.id_ts.its_rtime -# define icmp_ttime icmp_dun.id_ts.its_ttime -# define icmp_ip icmp_dun.id_ip.idi_ip -# define icmp_mask icmp_dun.id_mask -# define icmp_data icmp_dun.id_data -} icmphdr_t; - -# ifndef LINUX_IPOVLY -# define LINUX_IPOVLY -struct ipovly { - caddr_t ih_next, ih_prev; /* for protocol sequence q's */ - u_char ih_x1; /* (unused) */ - u_char ih_pr; /* protocol */ - short ih_len; /* protocol length */ - struct in_addr ih_src; /* source internet address */ - struct in_addr ih_dst; /* destination internet address */ -}; -# endif - -typedef struct { - __u8 ether_dhost[6]; - __u8 ether_shost[6]; - __u16 ether_type; -} ether_header_t; - -typedef struct uio { - int uio_resid; - int uio_rw; - caddr_t uio_buf; -} uio_t; - -# define UIO_READ 0 -# define UIO_WRITE 1 -# define UIOMOVE(a, b, c, d) uiomove(a,b,c,d) - -/* - * For masking struct ifnet onto struct device - */ -# define if_name name - -# ifdef KERNEL -# define GETUNIT(x, v) dev_get(x) -# define FREE_MB_T(m) kfree_skb(m, FREE_WRITE) -# define uniqtime do_gettimeofday -# undef INT_MAX -# undef UINT_MAX -# undef LONG_MAX -# undef ULONG_MAX -# include <linux/netdevice.h> -# define SPL_X(x) -# define SPL_NET(x) -# define SPL_IMP(x) - -# define bcmp(a,b,c) memcmp(a,b,c) -# define bcopy(a,b,c) memcpy(b,a,c) -# define bzero(a,c) memset(a,0,c) - -# define UNITNAME(n) dev_get((n)) - -# define KMALLOC(a,b) (a) = (b)kmalloc(sizeof(*(a)), GFP_ATOMIC) -# 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(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 -# undef UINT_MAX -# undef LONG_MAX -# undef ULONG_MAX -# define s8 __s8 -# define u8 __u8 -# define s16 __s16 -# define u16 __u16 -# define s32 __s32 -# define u32 __u32 -# include <linux/netdevice.h> -# undef __KERNEL__ -# endif -# define ifnet device -#else -typedef struct tcphdr tcphdr_t; -typedef struct udphdr udphdr_t; -typedef struct icmp icmphdr_t; -typedef struct ip ip_t; -typedef struct ether_header ether_header_t; -#endif /* linux */ -typedef struct tcpiphdr tcpiphdr_t; - -#if defined(hpux) || defined(linux) -struct ether_addr { - char ether_addr_octet[6]; -}; +#ifndef IPPROTO_DSTOPTS +# define IPPROTO_DSTOPTS 60 #endif - -/* - * XXX - This is one of those *awful* hacks which nobody likes - */ -#ifdef ultrix -#define A_A -#else -#define A_A & +#ifndef IPPROTO_FRAGMENT +# define IPPROTO_FRAGMENT 44 #endif - -#if (BSD >= 199306) && !defined(m_act) -# define m_act m_nextpkt -#endif - #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, - * the last 64 bits is dependant on that being available. - */ -#define ICMPERR_ICMPHLEN 8 -#define ICMPERR_IPICMPHLEN (20 + 8) -#define ICMPERR_MINPKTLEN (20 + 8 + 20) -#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) -#define ICMP6_MINLEN 8 -#define ICMP6ERR_IPICMPHLEN (40 + 8) -#define ICMP6ERR_MINPKTLEN (40 + 8 + 40) - #ifndef ICMP6_DST_UNREACH # define ICMP6_DST_UNREACH 1 #endif @@ -1384,6 +2217,79 @@ struct ether_addr { #endif #define TH_ECNALL (TH_ECN|TH_CWR) -#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|TH_ECN|TH_CWR) +/* + * TCP States + */ +#define IPF_TCPS_CLOSED 0 /* closed */ +#define IPF_TCPS_LISTEN 1 /* listening for connection */ +#define IPF_TCPS_SYN_SENT 2 /* active, have sent syn */ +#define IPF_TCPS_SYN_RECEIVED 3 /* have send and received syn */ +#define IPF_TCPS_HALF_ESTAB 4 /* for connections not fully "up" */ +/* states < IPF_TCPS_ESTABLISHED are those where connections not established */ +#define IPF_TCPS_ESTABLISHED 5 /* established */ +#define IPF_TCPS_CLOSE_WAIT 6 /* rcvd fin, waiting for close */ +/* states > IPF_TCPS_CLOSE_WAIT are those where user has closed */ +#define IPF_TCPS_FIN_WAIT_1 7 /* have closed, sent fin */ +#define IPF_TCPS_CLOSING 8 /* closed xchd FIN; await FIN ACK */ +#define IPF_TCPS_LAST_ACK 9 /* had fin and close; await FIN ACK */ +/* states > IPF_TCPS_CLOSE_WAIT && < IPF_TCPS_FIN_WAIT_2 await ACK of FIN */ +#define IPF_TCPS_FIN_WAIT_2 10 /* have closed, fin is acked */ +#define IPF_TCPS_TIME_WAIT 11 /* in 2*msl quiet wait after close */ +#define IPF_TCP_NSTATES 12 + +#define TCP_MSL 120 + +#undef ICMP_MAX_UNREACH +#define ICMP_MAX_UNREACH 14 +#undef ICMP_MAXTYPE +#define ICMP_MAXTYPE 18 + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +#ifndef LOG_FTP +# define LOG_FTP (11<<3) +#endif +#ifndef LOG_AUTHPRIV +# define LOG_AUTHPRIV (10<<3) +#endif +#ifndef LOG_AUDIT +# define LOG_AUDIT (13<<3) +#endif +#ifndef LOG_NTP +# define LOG_NTP (12<<3) +#endif +#ifndef LOG_SECURITY +# define LOG_SECURITY (13<<3) +#endif +#ifndef LOG_LFMT +# define LOG_LFMT (14<<3) +#endif +#ifndef LOG_CONSOLE +# define LOG_CONSOLE (14<<3) +#endif + +/* + * 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, + * the last 64 bits is dependant on that being available. + */ +#define ICMPERR_ICMPHLEN 8 +#define ICMPERR_IPICMPHLEN (20 + 8) +#define ICMPERR_MINPKTLEN (20 + 8 + 20) +#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) +#define ICMP6ERR_MINPKTLEN (40 + 8) +#define ICMP6ERR_IPICMPHLEN (40 + 8 + 40) + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifdef IPF_DEBUG +# define DPRINT(x) printf x +#else +# define DPRINT(x) +#endif #endif /* __IP_COMPAT_H__ */ diff --git a/contrib/ipfilter/ip_fil.c b/contrib/ipfilter/ip_fil.c index 00e8565..a790c02 100644 --- a/contrib/ipfilter/ip_fil.c +++ b/contrib/ipfilter/ip_fil.c @@ -1,75 +1,80 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ip_fil.c,v 2.133.2.9 2005/01/08 14:22:18 darrenr Exp"; +#endif + #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif -#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) && !defined(_LKM) -# include "opt_ipfilter_log.h" -#endif #if defined(__FreeBSD__) && !defined(__FreeBSD_version) -# if !defined(_KERNEL) || defined(IPFILTER_LKM) -# include <osreldate.h> +# if defined(IPFILTER_LKM) +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif # endif #endif -#if defined(__sgi) && (IRIX > 602) -# define _KMEMUSER -# include <sys/ptimers.h> -#endif -#ifndef _KERNEL -# include <stdio.h> -# include <string.h> -# include <stdlib.h> -# include <ctype.h> -# include <fcntl.h> -#endif #include <sys/errno.h> +#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL) +# include <sys/kern_svcs.h> +#endif #include <sys/types.h> +#define _KERNEL +#define KERNEL +#ifdef __OpenBSD__ +struct file; +#endif +#include <sys/uio.h> +#undef _KERNEL +#undef KERNEL #include <sys/file.h> -#if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include <sys/fcntl.h> -# include <sys/filio.h> -#else -# include <sys/ioctl.h> +#include <sys/ioctl.h> +#ifdef __sgi +# include <sys/ptimers.h> #endif #include <sys/time.h> -#ifdef _KERNEL -# include <sys/systm.h> -#endif #if !SOLARIS # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include <sys/dirent.h> # else # include <sys/dir.h> # endif -# include <sys/mbuf.h> #else # include <sys/filio.h> #endif -#include <sys/protosw.h> +#ifndef linux +# include <sys/protosw.h> +#endif #include <sys/socket.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <arpa/inet.h> + +#ifdef __hpux +# define _NET_ROUTE_INCLUDED +#endif #include <net/if.h> #ifdef sun # include <net/af.h> #endif #if __FreeBSD_version >= 300000 # include <net/if_var.h> -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include "opt_ipfilter.h" -# endif #endif #ifdef __sgi #include <sys/debug.h> @@ -77,101 +82,84 @@ #include <sys/hashing.h> # endif #endif +#if defined(__FreeBSD__) +# include "radix_ipf.h" +#endif #include <net/route.h> #include <netinet/in.h> -#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ +#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \ + !defined(__hpux) && !defined(linux) # include <netinet/in_var.h> #endif #include <netinet/in_systm.h> #include <netinet/ip.h> -#include <netinet/ip_var.h> +#if !defined(linux) +# include <netinet/ip_var.h> +#endif #include <netinet/tcp.h> +#if defined(__osf__) +# include <netinet/tcp_timer.h> +#endif +#if defined(__osf__) || defined(__hpux) || defined(__sgi) +# include "radix_ipf_local.h" +# define _RADIX_H_ +#endif #include <netinet/udp.h> #include <netinet/tcpip.h> #include <netinet/ip_icmp.h> -#ifndef _KERNEL -# include <unistd.h> -# include <syslog.h> +#include <unistd.h> +#include <syslog.h> +#ifdef __hpux +# undef _NET_ROUTE_INCLUDED #endif #include "netinet/ip_compat.h" -#ifdef USE_INET6 -# include <netinet/icmp6.h> -# if !SOLARIS -# include <netinet6/ip6protosw.h> -# include <netinet6/nd6.h> -# endif -#endif #include "netinet/ip_fil.h" #include "netinet/ip_nat.h" #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" #include "netinet/ip_auth.h" -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) -# include <sys/malloc.h> +#ifdef IPFILTER_SYNC +#include "netinet/ip_sync.h" #endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) +#ifdef IPFILTER_SCAN +#include "netinet/ip_scan.h" #endif -#if !SOLARIS && defined(_KERNEL) && !defined(__sgi) -# include <sys/kernel.h> -extern int ip_optcopy __P((struct ip *, struct ip *)); +#include "netinet/ip_pool.h" +#ifdef IPFILTER_COMPILED +# include "netinet/ip_rules.h" #endif -#if defined(OpenBSD) && (OpenBSD >= 200211) && defined(_KERNEL) -extern int ip6_getpmtu(struct route_in6 *, struct route_in6 *, - struct ifnet *, struct in6_addr *, u_long *); +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> #endif - -#if !defined(lint) -static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.76 2004/05/12 23:21:03 darrenr Exp $"; +#ifdef __hpux +struct rtentry; #endif +#include "md5.h" +#if !defined(__osf__) extern struct protosw inetsw[]; +#endif -#ifndef _KERNEL -# include "ipt.h" +#include "ipt.h" static struct ifnet **ifneta = NULL; static int nifs = 0; -#else -# if (BSD < 199306) || defined(__sgi) -extern int tcp_ttl; -# endif -#endif - -#ifdef ICMP_UNREACH_FILTER_PROHIB -int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB; -#else -int ipl_unreach = ICMP_UNREACH_FILTER; -#endif -u_long ipl_frouteok[2] = {0, 0}; 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((ip_t *, fr_info_t *, struct mbuf **)); -# ifdef USE_INET6 -static int ipfr_fastroute6 __P((struct mbuf *, struct mbuf **, - fr_info_t *, frdest_t *)); -# endif -# ifdef __sgi -extern int tcp_mtudisc; -extern kmutex_t ipf_rw; -extern KRWLOCK_T ipf_mutex; -# endif -#else +static void fr_setifpaddr __P((struct ifnet *, char *)); void init_ifp __P((void)); -# if defined(__sgi) && (IRIX < 605) +#if defined(__sgi) && (IRIX < 60500) static int no_output __P((struct ifnet *, struct mbuf *, struct sockaddr *)); static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *)); +#else +# if TRU64 >= 1885 +static int no_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *, char *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *, char *)); # else static int no_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); @@ -179,423 +167,20 @@ static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); # endif #endif -int fr_running = 0; - -#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 defined(__OpenBSD__) -# include <sys/timeout.h> -struct timeout ipfr_slowtimer_ch; -#endif -#if defined(__sgi) && defined(_KERNEL) -toid_t ipfr_slowtimer_ch; -#endif - -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) && \ - defined(_KERNEL) -# include <sys/conf.h> -const struct cdevsw ipl_cdevsw = { - iplopen, iplclose, iplread, nowrite, iplioctl, - nostop, notty, nopoll, nommap, -}; -#endif - -#if (_BSDI_VERSION >= 199510) && defined(_KERNEL) -# include <sys/device.h> -# include <sys/conf.h> - -struct cfdriver iplcd = { - NULL, "ipl", NULL, NULL, DV_DULL, 0 -}; - -struct devsw iplsw = { - &iplcd, - iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap, - nostrat, nodump, nopsize, 0, - nostop -}; -#endif /* _BSDI_VERSION >= 199510 && _KERNEL */ - -#if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701) -# include <sys/conf.h> -# if defined(NETBSD_PF) -# include <net/pfil.h> -/* - * We provide the fr_checkp name just to minimize changes later. - */ -int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); -# endif /* NETBSD_PF */ -#endif /* __NetBSD__ */ - - -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) && \ - defined(_KERNEL) -# include <net/pfil.h> - -static int fr_check_wrapper(void *, struct mbuf **, struct ifnet *, int ); - -static int fr_check_wrapper(arg, mp, ifp, dir) -void *arg; -struct mbuf **mp; -struct ifnet *ifp; -int dir; -{ - struct ip *ip = mtod(*mp, struct ip *); - int rv, hlen = ip->ip_hl << 2; - -#if defined(M_CSUM_TCPv4) - /* - * If the packet is out-bound, we can't delay checksums - * here. For in-bound, the checksum has already been - * validated. - */ - if (dir == PFIL_OUT) { - if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) { - in_delayed_cksum(*mp); - (*mp)->m_pkthdr.csum_flags &= - ~(M_CSUM_TCPv4|M_CSUM_UDPv4); - } - } -#endif /* M_CSUM_TCPv4 */ - - /* - * We get the packet with all fields in network byte - * order. We expect ip_len and ip_off to be in host - * order. We frob them, call the filter, then frob - * them back. - * - * Note, we don't need to update the checksum, because - * it has already been verified. - */ - NTOHS(ip->ip_len); - NTOHS(ip->ip_off); - - rv = fr_check(ip, hlen, ifp, (dir == PFIL_OUT), mp); - - if (rv == 0 && *mp != NULL) { - ip = mtod(*mp, struct ip *); - HTONS(ip->ip_len); - HTONS(ip->ip_off); - } - - return (rv); -} - -# ifdef USE_INET6 -# include <netinet/ip6.h> - -static int fr_check_wrapper6(void *, struct mbuf **, struct ifnet *, int ); - -static int fr_check_wrapper6(arg, mp, ifp, dir) -void *arg; -struct mbuf **mp; -struct ifnet *ifp; -int dir; -{ - - return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), - ifp, (dir == PFIL_OUT), mp)); -} -# endif -#endif /* __NetBSD_Version >= 105110000 && _KERNEL */ -#ifdef _KERNEL -# if defined(IPFILTER_LKM) && !defined(__sgi) -int iplidentify(s) -char *s; -{ - if (strcmp(s, "ipl") == 0) - return 1; - return 0; -} -# endif /* IPFILTER_LKM */ - - -/* - * Try to detect the case when compiling for NetBSD with pseudo-device - */ -# if defined(__NetBSD__) && defined(PFIL_HOOKS) -void -ipfilterattach(count) -int count; -{ - - /* - * Do nothing here, really. The filter will be enabled - * by the SIOCFRENB ioctl. - */ -} -# endif -# if defined(__NetBSD__) || defined(__OpenBSD__) -int ipl_enable() -# else int iplattach() -# endif { - char *defpass; - int s; -# if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)) - int error = 0; -# endif -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) - struct pfil_head *ph_inet; -# ifdef USE_INET6 - struct pfil_head *ph_inet6; -# endif -#endif - - SPL_NET(s); - if (fr_running || (fr_checkp == fr_check)) { - printf("IP Filter: already initialized\n"); - SPL_X(s); - return EBUSY; - } - -# ifdef IPFILTER_LOG - ipflog_init(); -# endif - if (nat_init() == -1) { - SPL_X(s); - return EIO; - } - if (fr_stateinit() == -1) { - SPL_X(s); - return EIO; - } - if (appr_init() == -1) { - SPL_X(s); - return EIO; - } - -# ifdef NETBSD_PF -# if (__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) -# if __NetBSD_Version__ >= 105110000 - ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); -# ifdef USE_INET6 - ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); -# endif - if (ph_inet == NULL -# ifdef USE_INET6 - && ph_inet6 == NULL -# endif - ) - return ENODEV; - - if (ph_inet != NULL) - error = pfil_add_hook((void *)fr_check_wrapper, NULL, - PFIL_IN|PFIL_OUT, ph_inet); - else - error = 0; -# else - error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif - if (error) { -# ifdef USE_INET6 - goto pfil_error; -# else - SPL_X(s); - appr_unload(); - ip_natunload(); - fr_stateunload(); - return error; -# endif - } -# else - pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); -# endif -# ifdef USE_INET6 -# if __NetBSD_Version__ >= 105110000 - if (ph_inet6 != NULL) - error = pfil_add_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); - else - error = 0; - if (error) { - pfil_remove_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); -# else - error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); - if (error) { - pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif -pfil_error: - SPL_X(s); - 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 - - bzero((char *)frcache, sizeof(frcache)); - fr_savep = fr_checkp; - fr_checkp = fr_check; fr_running = 1; - - SPL_X(s); - if (fr_pass & FR_PASS) - defpass = "pass"; - else if (fr_pass & FR_BLOCK) - defpass = "block"; - else - defpass = "no-match -> block"; - - printf("%s initialized. Default = %s all, Logging = %s\n", - ipfilter_version, defpass, -# ifdef IPFILTER_LOG - "enabled"); -# else - "disabled"); -# endif -#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 defined(__OpenBSD__) - timeout_set(&ipfr_slowtimer_ch, ipfr_slowtimer, NULL); - timeout_add(&ipfr_slowtimer_ch, hz/2); -# else -# if (__FreeBSD_version >= 300000) || defined(__sgi) - ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); -# else - timeout(ipfr_slowtimer, NULL, hz/2); -# endif -# endif -# endif -#endif return 0; } -/* - * Disable the filter by removing the hooks from the IP input/output - * stream. - */ -# if defined(__NetBSD__) -int ipl_disable() -# else int ipldetach() -# endif { - int s, i; -#if defined(NETBSD_PF) && \ - ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011)) - int error = 0; -# if __NetBSD_Version__ >= 105150000 - struct pfil_head *ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); -# ifdef USE_INET6 - struct pfil_head *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); -# endif -# endif -#endif - -#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_ch); -# else -# if defined(__OpenBSD__) - timeout_del(&ipfr_slowtimer_ch); -# else - untimeout(ipfr_slowtimer, NULL); -# endif /* OpenBSD */ -# endif /* __sgi */ -# endif /* FreeBSD */ -# endif /* NetBSD */ -#endif - SPL_NET(s); - if (!fr_running) - { - printf("IP Filter: not initialized\n"); - SPL_X(s); - return 0; - } - - printf("%s unloaded\n", ipfilter_version); - - fr_checkp = fr_savep; - i = frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); - i += frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); - fr_running = 0; - -# ifdef NETBSD_PF -# if ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011)) -# if __NetBSD_Version__ >= 105110000 - if (ph_inet != NULL) - error = pfil_remove_hook((void *)fr_check_wrapper, NULL, - PFIL_IN|PFIL_OUT, ph_inet); - else - error = 0; -# else - error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif - if (error) { - SPL_X(s); - return error; - } -# else - pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); -# endif -# ifdef USE_INET6 -# if __NetBSD_Version__ >= 105110000 - if (ph_inet6 != NULL) - error = pfil_remove_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); - else - error = 0; -# else - error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); -# endif - if (error) { - SPL_X(s); - return error; - } -# endif -# endif - -# ifdef __sgi - ipfilter_sgi_detach(); -# endif - - appr_unload(); - ipfr_unload(); - ip_natunload(); - fr_stateunload(); - fr_authunload(); - - SPL_X(s); + fr_running = -1; return 0; } -#endif /* _KERNEL */ static int frzerostats(data) @@ -605,7 +190,7 @@ caddr_t data; int error; fr_getstat(&fio); - error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + error = copyoutptr(&fio, data, sizeof(fio)); if (error) return EFAULT; @@ -618,65 +203,29 @@ caddr_t data; /* * Filter ioctl interface. */ -#ifdef __sgi -int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode -# ifdef _KERNEL - , cred_t *cp, int *rp -# endif -) -#else -int IPL_EXTERN(ioctl)(dev, cmd, data, mode -# if (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \ - (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \ - defined(__OpenBSD__))) -, p) -struct proc *p; -# else -) -# endif -dev_t dev; -# if defined(__NetBSD__) || defined(__OpenBSD__) || \ - (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) -u_long cmd; -# else -int cmd; -# endif +int iplioctl(dev, cmd, data, mode) +int dev; +ioctlcmd_t cmd; caddr_t data; int mode; -#endif /* __sgi */ { -#if defined(_KERNEL) && !SOLARIS - int s; -#endif int error = 0, unit = 0, tmp; + friostat_t fio; -#if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel >= 3) && (mode & FWRITE)) - return EPERM; -#endif -#ifdef _KERNEL - unit = GET_MINOR(dev); - if ((IPL_LOGMAX < unit) || (unit < 0)) - return ENXIO; -#else unit = dev; -#endif - - if (fr_running == 0 && (cmd != SIOCFRENB || unit != IPL_LOGIPF)) - return ENODEV; SPL_NET(s); if (unit == IPL_LOGNAT) { - if (fr_running) - error = nat_ioctl(data, cmd, mode); + if (fr_running > 0) + error = fr_nat_ioctl(data, cmd, mode); else error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSTATE) { - if (fr_running) + if (fr_running > 0) error = fr_state_ioctl(data, cmd, mode); else error = EIO; @@ -684,66 +233,93 @@ int mode; return error; } if (unit == IPL_LOGAUTH) { - if (!fr_running) - error = EIO; - else - if ((cmd == SIOCADAFR) || (cmd == SIOCRMAFR)) { - if (!(mode & FWRITE)) { + if (fr_running > 0) { + if ((cmd == (ioctlcmd_t)SIOCADAFR) || + (cmd == (ioctlcmd_t)SIOCRMAFR)) { + if (!(mode & FWRITE)) { error = EPERM; } else { error = frrequest(unit, cmd, data, - fr_active); + fr_active, 1); } } else { error = fr_auth_ioctl(data, mode, cmd); } + } else + error = EIO; + SPL_X(s); + return error; + } + if (unit == IPL_LOGSYNC) { +#ifdef IPFILTER_SYNC + if (fr_running > 0) + error = fr_sync_ioctl(data, cmd, mode); + else +#endif + error = EIO; + SPL_X(s); + return error; + } + if (unit == IPL_LOGSCAN) { +#ifdef IPFILTER_SCAN + if (fr_running > 0) + error = fr_scan_ioctl(data, cmd, mode); + else +#endif + error = EIO; + SPL_X(s); + return error; + } + if (unit == IPL_LOGLOOKUP) { + if (fr_running > 0) + error = ip_lookup_ioctl(data, cmd, mode); + else + error = EIO; SPL_X(s); return error; } - switch (cmd) { + switch (cmd) + { case FIONREAD : #ifdef IPFILTER_LOG - error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, + error = COPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data, sizeof(iplused[IPL_LOGIPF])); #endif break; -#if (!defined(IPFILTER_LKM) || defined(__NetBSD__)) && defined(_KERNEL) case SIOCFRENB : - { - u_int enable; - if (!(mode & FWRITE)) error = EPERM; else { - error = IRCOPY(data, (caddr_t)&enable, sizeof(enable)); + error = COPYIN(data, &tmp, sizeof(tmp)); if (error) break; - if (enable) -# if defined(__NetBSD__) || defined(__OpenBSD__) - error = ipl_enable(); -# else + if (tmp) error = iplattach(); -# endif else -# if defined(__NetBSD__) - error = ipl_disable(); -# else error = ipldetach(); -# endif } break; - } -#endif + case SIOCIPFSET : + if (!(mode & FWRITE)) { + error = EPERM; + break; + } + case SIOCIPFGETNEXT : + case SIOCIPFGET : + error = fr_ipftune(cmd, (void *)data); + break; case SIOCSETFF : if (!(mode & FWRITE)) error = EPERM; else - error = IRCOPY(data, (caddr_t)&fr_flags, - sizeof(fr_flags)); + error = COPYIN(data, &fr_flags, sizeof(fr_flags)); break; case SIOCGETFF : - error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); + error = COPYOUT(&fr_flags, data, sizeof(fr_flags)); + break; + case SIOCFUNCL : + error = fr_resolvefunc(data); break; case SIOCINAFR : case SIOCRMAFR : @@ -752,7 +328,7 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else - error = frrequest(unit, cmd, data, fr_active); + error = frrequest(unit, cmd, data, fr_active, 1); break; case SIOCINIFR : case SIOCRMIFR : @@ -760,7 +336,7 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else - error = frrequest(unit, cmd, data, 1 - fr_active); + error = frrequest(unit, cmd, data, 1 - fr_active, 1); break; case SIOCSWAPA : if (!(mode & FWRITE)) @@ -772,15 +348,9 @@ int mode; } break; case SIOCGETFS : - { - friostat_t fio; - fr_getstat(&fio); - error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); - if (error) - error = EFAULT; + error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); break; - } case SIOCFRZST : if (!(mode & FWRITE)) error = EPERM; @@ -791,11 +361,10 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else { - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + error = COPYIN(data, &tmp, sizeof(tmp)); if (!error) { tmp = frflush(unit, 4, tmp); - error = IWCOPY((caddr_t)&tmp, data, - sizeof(tmp)); + error = COPYOUT(&tmp, data, sizeof(tmp)); } } break; @@ -804,18 +373,17 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else { - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + error = COPYIN(data, &tmp, sizeof(tmp)); if (!error) { tmp = frflush(unit, 6, tmp); - error = IWCOPY((caddr_t)&tmp, data, - sizeof(tmp)); + error = COPYOUT(&tmp, data, sizeof(tmp)); } } break; #endif case SIOCSTLCK : - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - if (!error) { + error = COPYIN(data, &tmp, sizeof(tmp)); + if (error == 0) { fr_state_lock = tmp; fr_nat_lock = tmp; fr_frag_lock = tmp; @@ -832,19 +400,13 @@ int mode; break; #endif /* IPFILTER_LOG */ case SIOCGFRST : - error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, - sizeof(ipfrstat_t)); - if (error) - error = EFAULT; + error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT); break; case SIOCFRSYN : if (!(mode & FWRITE)) error = EPERM; else { -#if defined(_KERNEL) && defined(__sgi) - ipfsync(); -#endif - frsync(); + frsync(NULL); } break; default : @@ -889,1251 +451,159 @@ void *ifp; f->fr_ifa = (void *)-1; #endif RWLOCK_EXIT(&ipf_mutex); - ip_natsync(ifp); + fr_natsync(ifp); } -static int frrequest(unit, req, data, set) -int unit; -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -u_long req; +#if defined(__sgi) && (IRIX < 60500) +static int no_output(ifp, m, s) #else -int req; -#endif -int set; -caddr_t data; -{ - register frentry_t *fp, *f, **fprev; - register frentry_t **ftail; - frgroup_t *fg = NULL; - int error = 0, in, i; - u_int *p, *pp; - frentry_t frd; - frdest_t *fdp; - u_int group; - - fp = &frd; - error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); - if (error) - return EFAULT; - fp->fr_ref = 0; -#if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel > 0) && (fp->fr_func != NULL)) - return EPERM; -#endif - - /* - * Check that the group number does exist and that if a head group - * has been specified, doesn't exist. - */ - if ((req != SIOCZRLST) && ((req == SIOCINAFR) || (req == SIOCINIFR) || - (req == SIOCADAFR) || (req == SIOCADIFR)) && fp->fr_grhead && - fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL)) - return EEXIST; - if ((req != SIOCZRLST) && fp->fr_group && - !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL)) - return ESRCH; - - in = (fp->fr_flags & FR_INQUE) ? 0 : 1; - - if (unit == IPL_LOGAUTH) - ftail = fprev = &ipauth; - 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)) && (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; - - if ((group = fp->fr_group)) { - if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL))) - return ESRCH; - ftail = fprev = fg->fg_start; - } - - bzero((char *)frcache, sizeof(frcache[0]) * 2); - - for (i = 0; i < 4; i++) { - if ((fp->fr_ifnames[i][1] == '\0') && - ((fp->fr_ifnames[i][0] == '-') || - (fp->fr_ifnames[i][0] == '*'))) { - fp->fr_ifas[i] = NULL; - } else if (*fp->fr_ifnames[i]) { - fp->fr_ifas[i] = GETUNIT(fp->fr_ifnames[i], fp->fr_v); - if (!fp->fr_ifas[i]) - fp->fr_ifas[i] = (void *)-1; - } - } - - fdp = &fp->fr_dif; - fp->fr_flags &= ~FR_DUP; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; - else - fp->fr_flags |= FR_DUP; - } - - fdp = &fp->fr_tif; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; - } - - /* - * 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 ((fp->fr_cksum == f->fr_cksum) && - !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ)) - break; - - /* - * If zero'ing statistics, copy current to caller and zero. - */ - if (req == SIOCZRLST) { - if (!f) - return ESRCH; - error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); - if (error) - return EFAULT; - f->fr_hits = 0; - f->fr_bytes = 0; - return 0; - } - - if (!f) { - if (req != SIOCINAFR && req != SIOCINIFR) - while ((f = *ftail)) - ftail = &f->fr_next; - else { - ftail = fprev; - if (fp->fr_hits) { - while (--fp->fr_hits && (f = *ftail)) - ftail = &f->fr_next; - } - f = NULL; - } - } - - if (req == SIOCRMAFR || req == SIOCRMIFR) { - if (!f) - error = ESRCH; - else { - /* - * 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--; - if (unit == IPL_LOGAUTH) { - return fr_preauthcmd(req, f, ftail); - } - if (f->fr_grhead) - fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, - unit, set); - fixskip(fprev, f, -1); - *ftail = f->fr_next; - f->fr_next = NULL; - f->fr_ref--; - if (f->fr_ref == 0) - KFREE(f); - } - } else { - if (f) - error = EEXIST; - else { - if (unit == IPL_LOGAUTH) { - return fr_preauthcmd(req, fp, ftail); - } - KMALLOC(f, frentry_t *); - if (f != NULL) { - if (fg && fg->fg_head) - fg->fg_head->fr_ref++; - bcopy((char *)fp, (char *)f, sizeof(*f)); - f->fr_ref = 1; - f->fr_hits = 0; - f->fr_next = *ftail; - *ftail = f; - if (req == SIOCINIFR || req == SIOCINAFR) - fixskip(fprev, f, 1); - f->fr_grp = NULL; - if ((group = f->fr_grhead)) - fg = fr_addgroup(group, f, unit, set); - } else - error = ENOMEM; - } - } - return (error); -} - - -#ifdef _KERNEL -/* - * routines below for saving IP headers to buffer - */ -# ifdef __sgi -# ifdef _KERNEL -int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp) -# else -int IPL_EXTERN(open)(dev_t dev, int flags) -# endif -# else -int IPL_EXTERN(open)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) -, devtype, p) -int devtype; -struct proc *p; -# else -) -# endif -dev_t dev; -int flags; -# endif /* __sgi */ -{ -# if defined(__sgi) && defined(_KERNEL) - u_int min = geteminor(*pdev); +# if TRU64 >= 1885 +static int no_output (ifp, m, s, rt, cp) +char *cp; # else - u_int min = GET_MINOR(dev); +static int no_output(ifp, m, s, rt) # endif - - if (IPL_LOGMAX < min) - min = ENXIO; - else - min = 0; - return min; -} - - -# ifdef __sgi -int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp) -#else -int IPL_EXTERN(close)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) -, devtype, p) -int devtype; -struct proc *p; -# else -) -# endif -dev_t dev; -int flags; -# endif /* __sgi */ -{ - u_int min = GET_MINOR(dev); - - if (IPL_LOGMAX < min) - min = ENXIO; - else - min = 0; - return min; -} - -/* - * iplread/ipllog - * both of these must operate with at least splnet() lest they be - * called during packet processing and cause an inconsistancy to appear in - * the filter lists. - */ -# ifdef __sgi -int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp) -# else -# if BSD >= 199306 -int IPL_EXTERN(read)(dev, uio, ioflag) -int ioflag; -# else -int IPL_EXTERN(read)(dev, uio) -# endif -dev_t dev; -register struct uio *uio; -# endif /* __sgi */ +struct rtentry *rt; +#endif +struct ifnet *ifp; +struct mbuf *m; +struct sockaddr *s; { -# ifdef IPFILTER_LOG - return ipflog_read(GET_MINOR(dev), uio); -# else - return ENXIO; -# endif + return 0; } -/* - * 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(oip, fin) -struct ip *oip; -fr_info_t *fin; -{ - struct tcphdr *tcp, *tcp2; - int tlen = 0, hlen; - struct mbuf *m; -#ifdef USE_INET6 - ip6_t *ip6, *oip6 = (ip6_t *)oip; -#endif - ip_t *ip; - - tcp = (struct tcphdr *)fin->fin_dp; - if (tcp->th_flags & TH_RST) - return -1; /* feedback loop */ -# if (BSD < 199306) || defined(__sgi) - m = m_get(M_DONTWAIT, MT_HEADER); -# else - m = m_gethdr(M_DONTWAIT, MT_HEADER); -# endif - if (m == NULL) - return ENOBUFS; - if (m == NULL) - return -1; - - tlen = fin->fin_dlen - (tcp->th_off << 2) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - -#ifdef USE_INET6 - hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); +#if defined(__sgi) && (IRIX < 60500) +static int write_output(ifp, m, s) #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 - ip = mtod(m, struct ip *); -# ifdef USE_INET6 - ip6 = (ip6_t *)ip; -# endif - bzero((char *)ip, sizeof(*tcp2) + hlen); - tcp2 = (struct tcphdr *)((char *)ip + hlen); - - tcp2->th_sport = tcp->th_dport; - tcp2->th_dport = tcp->th_sport; - if (tcp->th_flags & TH_ACK) { - tcp2->th_seq = tcp->th_ack; - tcp2->th_flags = TH_RST; - } else { - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); - tcp2->th_flags = TH_RST|TH_ACK; - } - tcp2->th_off = sizeof(*tcp2) >> 2; -# 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); -} - - -/* - * Send an IP(v4/v6) datagram out into the network - */ -static int send_ip(oip, fin, mp) -ip_t *oip; -fr_info_t *fin; -struct mbuf **mp; -{ - struct mbuf *m = *mp; - int error, hlen; - fr_info_t frn; - ip_t *ip; - - bzero((char *)&frn, sizeof(frn)); - frn.fin_ifp = fin->fin_ifp; - frn.fin_v = fin->fin_v; - frn.fin_out = fin->fin_out; - frn.fin_mp = mp; - - ip = mtod(m, ip_t *); - hlen = sizeof(*ip); - - 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; - -# if defined(__NetBSD__) || \ - (defined(__OpenBSD__) && (OpenBSD >= 200012)) - if (ip_mtudisc != 0) - ip->ip_off = IP_DF; -# else -# if defined(__sgi) - if (ip->ip_p == IPPROTO_TCP && tcp_mtudisc != 0) - ip->ip_off = IP_DF; -# endif -# endif - -# if (BSD < 199306) || defined(__sgi) - ip->ip_ttl = tcp_ttl; +# if TRU64 >= 1885 +static int write_output (ifp, m, s, rt, cp) +char *cp; # else - ip->ip_ttl = ip_defttl; +static int write_output(ifp, m, s, rt) # endif - ip->ip_sum = 0; - frn.fin_dp = (char *)(ip + 1); - } -# ifdef USE_INET6 - else if (ip->ip_v == 6) { - ip6_t *ip6 = (ip6_t *)ip; - - hlen = sizeof(*ip6); - ip6->ip6_hlim = 127; - frn.fin_dp = (char *)(ip6 + 1); - } -# endif -# ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -# endif - - if (fr_makefrip(hlen, ip, &frn) == 0) - error = ipfr_fastroute(m, mp, &frn, NULL); - else - error = EINVAL; - return error; -} - - -int send_icmp_err(oip, type, fin, dst) -ip_t *oip; -int type; -fr_info_t *fin; -int dst; -{ - int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code; - u_short shlen, slen = 0, soff = 0; - struct in_addr dst4; - struct icmp *icmp; - struct mbuf *m; - void *ifp; -#ifdef USE_INET6 - ip6_t *ip6, *oip6 = (ip6_t *)oip; - struct in6_addr dst6; +struct rtentry *rt; #endif +struct ifnet *ifp; +struct mbuf *m; +struct sockaddr *s; +{ + char fname[32]; + mb_t *mb; ip_t *ip; + int fd; - 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 ((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; - } - -# if (BSD < 199306) || defined(__sgi) - avail = MLEN; - m = m_get(M_DONTWAIT, MT_HEADER); -# else - avail = MHLEN; - m = m_gethdr(M_DONTWAIT, MT_HEADER); -# endif - 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->m_flags & M_EXT) == 0) { - m_freem(m); - return ENOBUFS; - } -# ifdef M_TRAILINGSPACE - m->m_len = 0; - avail = M_TRAILINGSPACE(m); -# else - avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; -# endif - xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), - avail - hlen - sizeof(*icmp) - max_linkhdr); - if (dst == 0) { - if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1) - return -1; - } else - dst6 = oip6->ip6_dst; - } -#endif + mb = (mb_t *)m; + ip = MTOD(mb, ip_t *); - iclen = hlen + sizeof(*icmp); -# if BSD >= 199306 - avail -= (max_linkhdr + iclen); - m->m_data += max_linkhdr; - m->m_pkthdr.rcvif = (struct ifnet *)0; - if (xtra > avail) - xtra = avail; - iclen += xtra; - m->m_pkthdr.len = iclen; +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + sprintf(fname, "/tmp/%s", ifp->if_xname); #else - avail -= (m->m_off + iclen); - if (xtra > avail) - xtra = avail; - iclen += xtra; + sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); #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 = fin->fin_icode; - icmp->icmp_cksum = 0; -#ifdef icmp_nextmtu - if (type == ICMP_UNREACH && - fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) - icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu); -#endif - - if (avail) { - slen = oip->ip_len; - oip->ip_len = htons(oip->ip_len); - soff = oip->ip_off; - oip->ip_off = htons(oip->ip_off); - bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); - oip->ip_len = slen; - oip->ip_off = soff; - avail -= MIN(ohlen, avail); - } - -#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; - } - - shlen = fin->fin_hlen; - fin->fin_hlen = hlen; - err = send_ip(oip, fin, &m); - fin->fin_hlen = shlen; - - return err; -} - - -# if !defined(IPFILTER_LKM) && !defined(__sgi) && \ - (!defined(__FreeBSD_version) || (__FreeBSD_version < 300000)) -# if (BSD < 199306) -int iplinit __P((void)); - -int -# else -void iplinit __P((void)); - -void -# endif -iplinit() -{ - -# if defined(__NetBSD__) || defined(__OpenBSD__) - if (ipl_enable() != 0) -# else - if (iplattach() != 0) -# endif - { - printf("IP Filter failed to attach\n"); + fd = open(fname, O_WRONLY|O_APPEND); + if (fd == -1) { + perror("open"); + return -1; } - ip_init(); + write(fd, (char *)ip, ntohs(ip->ip_len)); + close(fd); + return 0; } -# endif /* ! __NetBSD__ */ -/* - * Return the length of the entire mbuf. - */ -size_t mbufchainlen(m0) -register struct mbuf *m0; +static void fr_setifpaddr(ifp, addr) +struct ifnet *ifp; +char *addr; { -#if BSD >= 199306 - return m0->m_pkthdr.len; +#ifdef __sgi + struct in_ifaddr *ifa; #else - register size_t len = 0; - - for (; m0; m0 = m0->m_next) - len += m0->m_len; - return len; + struct ifaddr *ifa; #endif -} - - -int ipfr_fastroute(m0, mpp, fin, fdp) -struct mbuf *m0, **mpp; -fr_info_t *fin; -frdest_t *fdp; -{ - register struct ip *ip, *mhip; - register struct mbuf *m = m0; - register struct route *ro; - int len, off, error = 0, hlen, code, sout; - struct ifnet *ifp, *sifp; - struct sockaddr_in *dst; - struct route iproute; - frentry_t *fr; - - ip = NULL; - ro = NULL; - ifp = NULL; - ro = &iproute; - ro->ro_rt = NULL; -#ifdef USE_INET6 - if (fin->fin_v == 6) { - error = ipfr_fastroute6(m0, mpp, fin, fdp); - if (error != 0) - goto bad; - goto done; - } +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + if (ifp->if_addrlist.tqh_first != NULL) #else - if (fin->fin_v == 6) - goto bad; -#endif - -#ifdef M_WRITABLE - /* - * HOT FIX/KLUDGE: - * - * If the mbuf we're about to send is not writable (because of - * a cluster reference, for example) we'll need to make a copy - * of it since this routine modifies the contents. - * - * If you have non-crappy network hardware that can transmit data - * from the mbuf, rather than making a copy, this is gonna be a - * problem. - */ - if (M_WRITABLE(m) == 0) { - if ((m0 = m_dup(m, M_DONTWAIT)) != NULL) { - m_freem(*mpp); - *mpp = m0; - m = m0; - } else { - error = ENOBUFS; - m_freem(*mpp); - goto done; - } - } -#endif - - hlen = fin->fin_hlen; - ip = mtod(m0, struct ip *); - -#if defined(__NetBSD__) && defined(M_CSUM_IPv4) - /* - * Clear any in-bound checksum flags for this packet. - */ -# if (__NetBSD_Version__ > 105009999) - m0->m_pkthdr.csum_flags = 0; +# ifdef __sgi + if (ifp->in_ifaddr != NULL) # else - m0->m_pkthdr.csuminfo = 0; + if (ifp->if_addrlist != NULL) # endif -#endif /* __NetBSD__ && M_CSUM_IPv4 */ - - /* - * Route packet. - */ -#if (defined(IRIX) && (IRIX >= 605)) - ROUTE_RDLOCK(); #endif - bzero((caddr_t)ro, sizeof (*ro)); - dst = (struct sockaddr_in *)&ro->ro_dst; - dst->sin_family = AF_INET; - dst->sin_addr = ip->ip_dst; - - fr = fin->fin_fr; - if (fdp != NULL) - ifp = fdp->fd_ifp; - else - ifp = fin->fin_ifp; + return; - /* - * In case we're here due to "to <if>" being used with "keep state", - * check that we're going in the correct direction. - */ - if ((fr != NULL) && (fin->fin_rev != 0)) { - if ((ifp != NULL) && (fdp == &fr->fr_tif)) { -# if (defined(IRIX) && (IRIX >= 605)) - ROUTE_UNLOCK(); -# endif - return 0; - } - } else if (fdp != NULL) { - if (fdp->fd_ip.s_addr != 0) - dst->sin_addr = fdp->fd_ip; - } - -# if BSD >= 199306 - dst->sin_len = sizeof(*dst); -# endif -# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ - !defined(__OpenBSD__) -# ifdef RTF_CLONING - rtalloc_ign(ro, RTF_CLONING); -# else - rtalloc_ign(ro, RTF_PRCLONING); -# endif -# else - rtalloc(ro); -# endif - - if (!ifp) { - if (!fr || !(fr->fr_flags & FR_FASTROUTE)) { - error = -2; -# if (defined(IRIX) && (IRIX >= 605)) - ROUTE_UNLOCK(); -# endif - goto bad; - } - } - - if ((ifp == NULL) && (ro->ro_rt != NULL)) - ifp = ro->ro_rt->rt_ifp; - - if ((ro->ro_rt == NULL) || (ifp == NULL)) { - if (in_localaddr(ip->ip_dst)) - error = EHOSTUNREACH; - else - error = ENETUNREACH; -# if (defined(IRIX) && (IRIX >= 605)) - ROUTE_UNLOCK(); -# endif - goto bad; - } - - if (ro->ro_rt->rt_flags & RTF_GATEWAY) { -#if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) - dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; + ifa = (struct ifaddr *)malloc(sizeof(*ifa)); +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + ifp->if_addrlist.tqh_first = ifa; #else - dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; -#endif - } - ro->ro_rt->rt_use++; - -#if (defined(IRIX) && (IRIX > 602)) - ROUTE_UNLOCK(); -#endif - - /* - * For input packets which are being "fastrouted", they won't - * go back through output filtering and miss their chance to get - * NAT'd and counted. - */ - if (fin->fin_out == 0) { - sifp = fin->fin_ifp; - sout = fin->fin_out; - fin->fin_ifp = ifp; - fin->fin_out = 1; - if ((fin->fin_fr = ipacct[1][fr_active]) && - (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INCL(frstats[1].fr_acct); - } - fin->fin_fr = NULL; - if (!fr || !(fr->fr_flags & FR_RETMASK)) - (void) fr_checkstate(ip, fin); - - switch (ip_natout(ip, fin)) - { - case 0 : - break; - case 1 : - ip->ip_sum = 0; - break; - case -1 : - error = EINVAL; - goto done; - break; - } - - fin->fin_ifp = sifp; - fin->fin_out = sout; - } else - ip->ip_sum = 0; - - /* - * If small enough for interface, can just send directly. - */ - if (ip->ip_len <= ifp->if_mtu) { -# ifndef sparc -# if (!defined(__FreeBSD__) && !(_BSDI_VERSION >= 199510)) && \ - !(__NetBSD_Version__ >= 105110000) - ip->ip_id = htons(ip->ip_id); -# endif - ip->ip_len = htons(ip->ip_len); - ip->ip_off = htons(ip->ip_off); -# endif -# if defined(__NetBSD__) && defined(M_CSUM_IPv4) -# if (__NetBSD_Version__ > 105009999) - if (ifp->if_csum_flags_tx & IFCAP_CSUM_IPv4) - m->m_pkthdr.csum_flags |= M_CSUM_IPv4; - else if (ip->ip_sum == 0) - ip->ip_sum = in_cksum(m, hlen); -# else - if (ifp->if_capabilities & IFCAP_CSUM_IPv4) - m->m_pkthdr.csuminfo |= M_CSUM_IPv4; - else if (ip->ip_sum == 0) - ip->ip_sum = in_cksum(m, hlen); -# endif -# else - if (!ip->ip_sum) - ip->ip_sum = in_cksum(m, hlen); -# endif /* __NetBSD__ && M_CSUM_IPv4 */ -# if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) -# ifdef IRIX - IFNET_UPPERLOCK(ifp); -# endif - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, - ro->ro_rt); -# ifdef IRIX - IFNET_UPPERUNLOCK(ifp); -# endif -# else - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); -# endif - goto done; - } - - /* - * Too large for interface; fragment if possible. - * Must be able to put at least 8 bytes per fragment. - */ - if (ip->ip_off & IP_DF) { - error = EMSGSIZE; - goto bad; - } - len = (ifp->if_mtu - hlen) &~ 7; - if (len < 8) { - error = EMSGSIZE; - goto bad; - } - - { - int mhlen, firstlen = len; - struct mbuf **mnext = &m->m_act; - - /* - * Loop through length of segment after first fragment, - * make new header and copy data of each part and link onto chain. - */ - m0 = m; - mhlen = sizeof (struct ip); - for (off = hlen + len; off < ip->ip_len; off += len) { -# ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); -# else - MGET(m, M_DONTWAIT, MT_HEADER); -# endif - if (m == 0) { - error = ENOBUFS; - goto bad; - } -# if BSD >= 199306 - m->m_data += max_linkhdr; -# else - m->m_off = MMAXOFF - hlen; -# endif - mhip = mtod(m, struct ip *); - bcopy((char *)ip, (char *)mhip, sizeof(*ip)); - if (hlen > sizeof (struct ip)) { - mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); - mhip->ip_hl = mhlen >> 2; - } - m->m_len = mhlen; - mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); - if (ip->ip_off & IP_MF) - mhip->ip_off |= IP_MF; - if (off + len >= ip->ip_len) - len = ip->ip_len - off; - else - mhip->ip_off |= IP_MF; - mhip->ip_len = htons((u_short)(len + mhlen)); - m->m_next = m_copy(m0, off, len); - if (m->m_next == 0) { - error = ENOBUFS; /* ??? */ - goto sendorfree; - } -# if BSD >= 199306 - m->m_pkthdr.len = mhlen + len; - m->m_pkthdr.rcvif = NULL; -# endif - mhip->ip_off = htons((u_short)mhip->ip_off); - mhip->ip_sum = 0; - mhip->ip_sum = in_cksum(m, mhlen); - *mnext = m; - mnext = &m->m_act; - } - /* - * Update first fragment by trimming what's been copied out - * and updating header, then send each fragment (in order). - */ - m_adj(m0, hlen + firstlen - ip->ip_len); - ip->ip_len = htons((u_short)(hlen + firstlen)); - ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m0, hlen); -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_act; - m->m_act = 0; - if (error == 0) -# if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst, ro->ro_rt); -# else - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst); -# endif - else - m_freem(m); - } - } -done: - if (!error) - ipl_frouteok[0]++; - else - ipl_frouteok[1]++; - - if (ro->ro_rt != NULL) { - RTFREE(ro->ro_rt); - } - *mpp = NULL; - return error; -bad: - if ((error == EMSGSIZE) && (fin->fin_v == 4)) { - 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; -} - - -/* - * Return true or false depending on whether the route to the - * given IP address uses the same interface as the one passed. - */ -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; -# if (BSD >= 199306) - dst->sin_len = sizeof(*dst); -# endif - 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 +# ifdef __sgi + ifp->in_ifaddr = ifa; # else - rtalloc(&iproute); + ifp->if_addrlist = ifa; # endif - if (iproute.ro_rt == NULL) - return 0; - return (ifp == iproute.ro_rt->rt_ifp); -} - - -# ifdef USE_GETIFNAME -char * -get_ifname(ifp) -struct ifnet *ifp; -{ - static char workbuf[64]; - - sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); - return workbuf; -} -# endif - - -# if defined(USE_INET6) -/* - * This is the IPv6 specific fastroute code. It doesn't clean up the mbuf's - * or ensure that it is an IPv6 packet that is being forwarded, those are - * expected to be done by the called (ipfr_fastroute). - */ -static int ipfr_fastroute6(m0, mpp, fin, fdp) -struct mbuf *m0, **mpp; -fr_info_t *fin; -frdest_t *fdp; -{ - struct route_in6 ip6route; - struct sockaddr_in6 *dst6; - struct route_in6 *ro; - struct ifnet *ifp; - frentry_t *fr; -#if defined(OpenBSD) && (OpenBSD >= 200211) - struct route_in6 *ro_pmtu = NULL; - struct in6_addr finaldst; - ip6_t *ip6; -#endif - u_long mtu; - int error; - - ro = &ip6route; - fr = fin->fin_fr; - bzero((caddr_t)ro, sizeof(*ro)); - dst6 = (struct sockaddr_in6 *)&ro->ro_dst; - dst6->sin6_family = AF_INET6; - dst6->sin6_len = sizeof(struct sockaddr_in6); - dst6->sin6_addr = fin->fin_fi.fi_dst.in6; - - if (fdp != NULL) - ifp = fdp->fd_ifp; - else - ifp = fin->fin_ifp; - - if ((fr != NULL) && (fin->fin_rev != 0)) { - if ((ifp != NULL) && (fdp == &fr->fr_tif)) - return 0; - } else if (fdp != NULL) { - if (IP6_NOTZERO(&fdp->fd_ip6)) - dst6->sin6_addr = fdp->fd_ip6.in6; - } - if (ifp == NULL) - return -2; - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - /* KAME */ - if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) - dst6->sin6_addr.s6_addr16[1] = htons(ifp->if_index); #endif - rtalloc((struct route *)ro); - if ((ifp == NULL) && (ro->ro_rt != NULL)) - ifp = ro->ro_rt->rt_ifp; + if (ifa != NULL) { + struct sockaddr_in *sin; - if ((ro->ro_rt == NULL) || (ifp == NULL) || - (ifp != ro->ro_rt->rt_ifp)) { - error = EHOSTUNREACH; - } else { - if (ro->ro_rt->rt_flags & RTF_GATEWAY) - dst6 = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway; - ro->ro_rt->rt_use++; - -#if defined(OpenBSD) && (OpenBSD >= 200211) - ip6 = mtod(m0, ip6_t *); - ro_pmtu = ro; - finaldst = ip6->ip6_dst; - error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu); - if (error == 0) { +#ifdef __sgi + sin = (struct sockaddr_in *)&ifa->ia_addr; #else -# ifdef IN6_LINKMTU - mtu = IN6_LINKMTU(ifp); -# else -# ifdef ND_IFINFO - mtu = ND_IFINFO(ifp)->linkmtu; -# else - mtu = nd_ifinfo[ifp->if_index].linkmtu; -# endif -# endif -#endif - if (m0->m_pkthdr.len <= mtu) - error = nd6_output(ifp, fin->fin_ifp, m0, - dst6, ro->ro_rt); - else - error = EMSGSIZE; -#if defined(OpenBSD) && (OpenBSD >= 200211) - } + sin = (struct sockaddr_in *)&ifa->ifa_addr; #endif + sin->sin_addr.s_addr = inet_addr(addr); + if (sin->sin_addr.s_addr == 0) + abort(); } - - if (ro->ro_rt != NULL) { - RTFREE(ro->ro_rt); - } - return error; } -# endif -#else /* #ifdef _KERNEL */ - -# if defined(__sgi) && (IRIX < 605) -static int no_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s)) -# else -static int no_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s, struct rtentry *rt)) -# endif +struct ifnet *get_unit(name, v) +char *name; +int v; { - return 0; -} + struct ifnet *ifp, **ifpp, **old_ifneta; + char *addr; +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + if (name == NULL) + name = "anon0"; -# ifdef __STDC__ -# if defined(__sgi) && (IRIX < 605) -static int write_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s)) -# else -static int write_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s, struct rtentry *rt)) -# endif -{ - ip_t *ip = (ip_t *)m; -# else -static int write_output(ifp, ip) -struct ifnet *ifp; -ip_t *ip; -{ -# endif - char fname[32]; - int fd; + addr = strchr(name, '='); + if (addr != NULL) + *addr++ = '\0'; -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - sprintf(fname, "%s", ifp->if_xname); -# else - sprintf(fname, "%s%d", ifp->if_name, ifp->if_unit); -# endif - fd = open(fname, O_WRONLY|O_APPEND); - if (fd == -1) { - perror("open"); - return -1; + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { + if (!strcmp(name, ifp->if_xname)) { + if (addr != NULL) + fr_setifpaddr(ifp, addr); + return ifp; + } } - write(fd, (char *)ip, ntohs(ip->ip_len)); - close(fd); - return 0; -} - - -char *get_ifname(ifp) -struct ifnet *ifp; -{ -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - return ifp->if_xname; -# else - static char fullifname[LIFNAMSIZ]; - - sprintf(fullifname, "%s%d", ifp->if_name, ifp->if_unit); - return fullifname; -# endif -} - +#else + char *s, ifname[LIFNAMSIZ+1]; -struct ifnet *get_unit(ifname, v) -char *ifname; -int v; -{ - struct ifnet *ifp, **ifa, **old_ifneta; + if (name == NULL) + name = "anon0"; - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - if (!strncmp(ifname, ifp->if_xname, sizeof(ifp->if_xname))) -# else - char fullname[LIFNAMSIZ]; + addr = strchr(name, '='); + if (addr != NULL) + *addr++ = '\0'; - sprintf(fullname, "%s%d", ifp->if_name, ifp->if_unit); - if (!strcmp(ifname, fullname)) -# endif + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { + COPYIFNAME(ifp, ifname); + if (!strcmp(name, ifname)) { + if (addr != NULL) + fr_setifpaddr(ifp, addr); return ifp; + } } +#endif if (!ifneta) { ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); @@ -2150,7 +620,7 @@ int v; old_ifneta = ifneta; nifs++; ifneta = (struct ifnet **)realloc(ifneta, - (nifs + 1) * sizeof(*ifa)); + (nifs + 1) * sizeof(ifp)); if (!ifneta) { free(old_ifneta); nifs = 0; @@ -2165,36 +635,59 @@ int v; } ifp = ifneta[nifs - 1]; -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - strncpy(ifp->if_xname, ifname, sizeof(ifp->if_xname)); -# else - ifp->if_name = strdup(ifname); - - ifname = ifp->if_name; - while (*ifname && !isdigit(*ifname)) - ifname++; - if (*ifname && isdigit(*ifname)) { - ifp->if_unit = atoi(ifname); - *ifname = '\0'; - } else +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + (void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname)); +#else + for (s = name; *s && !ISDIGIT(*s); s++) + ; + if (*s && ISDIGIT(*s)) { + ifp->if_unit = atoi(s); + ifp->if_name = (char *)malloc(s - name + 1); + (void) strncpy(ifp->if_name, name, s - name); + ifp->if_name[s - name] = '\0'; + } else { + ifp->if_name = strdup(name); ifp->if_unit = -1; -# endif + } +#endif ifp->if_output = no_output; + + if (addr != NULL) { + fr_setifpaddr(ifp, addr); + } + return ifp; } +char *get_ifname(ifp) +struct ifnet *ifp; +{ + static char ifname[LIFNAMSIZ]; + +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + sprintf(ifname, "%s", ifp->if_xname); +#else + sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); +#endif + return ifname; +} + + void init_ifp() { - struct ifnet *ifp, **ifa; + struct ifnet *ifp, **ifpp; char fname[32]; int fd; -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s", ifp->if_xname); fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); @@ -2203,9 +696,9 @@ void init_ifp() else close(fd); } -# else +#else - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); @@ -2214,12 +707,37 @@ void init_ifp() else close(fd); } +#endif +} + + +int fr_fastroute(m, mpp, fin, fdp) +mb_t *m, **mpp; +fr_info_t *fin; +frdest_t *fdp; +{ + struct ifnet *ifp = fdp->fd_ifp; + ip_t *ip = fin->fin_ip; + + if (!ifp) + return 0; /* no routing table out here */ + + ip->ip_len = htons((u_short)ip->ip_len); + ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; +#if defined(__sgi) && (IRIX < 60500) + (*ifp->if_output)(ifp, (void *)ip, NULL); +# if TRU64 >= 1885 + (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0); +# else + (*ifp->if_output)(ifp, (void *)m, NULL, 0); # endif +#endif + return 0; } -int send_reset(ip, fin) -ip_t *ip; +int fr_send_reset(fin) fr_info_t *fin; { verbose("- TCP RST sent\n"); @@ -2227,22 +745,30 @@ fr_info_t *fin; } -int send_icmp_err(ip, code, fin, dst) -ip_t *ip; -int code; +int fr_send_icmp_err(type, fin, dst) +int type; fr_info_t *fin; int dst; { - verbose("- ICMP UNREACHABLE sent\n"); + verbose("- ICMP unreachable sent\n"); return 0; } -void frsync() +void frsync(ifp) +void *ifp; { return; } + +void m_freem(m) +mb_t *m; +{ + return; +} + + void m_copydata(m, off, len, cp) mb_t *m; int off, len; @@ -2290,4 +816,152 @@ struct uio *uio; } return 0; } -#endif /* _KERNEL */ + + +u_32_t fr_newisn(fin) +fr_info_t *fin; +{ + static int iss_seq_off = 0; + u_char hash[16]; + u_32_t newiss; + MD5_CTX ctx; + + /* + * Compute the base value of the ISS. It is a hash + * of (saddr, sport, daddr, dport, secret). + */ + MD5Init(&ctx); + + MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, + sizeof(fin->fin_fi.fi_src)); + MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, + sizeof(fin->fin_fi.fi_dst)); + MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); + + /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */ + + MD5Final(hash, &ctx); + + memcpy(&newiss, hash, sizeof(newiss)); + + /* + * Now increment our "timer", and add it in to + * the computed value. + * + * XXX Use `addin'? + * XXX TCP_ISSINCR too large to use? + */ + iss_seq_off += 0x00010000; + newiss += iss_seq_off; + return newiss; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_nextipid */ +/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Returns the next IPv4 ID to use for this packet. */ +/* ------------------------------------------------------------------------ */ +INLINE u_short fr_nextipid(fin) +fr_info_t *fin; +{ + static u_short ipid = 0; + u_short id; + + MUTEX_ENTER(&ipf_rw); + id = ipid++; + MUTEX_EXIT(&ipf_rw); + + return id; +} + + +INLINE void fr_checkv4sum(fin) +fr_info_t *fin; +{ + if (fr_checkl4sum(fin) == -1) + fin->fin_flx |= FI_BAD; +} + + +#ifdef USE_INET6 +INLINE void fr_checkv6sum(fin) +fr_info_t *fin; +{ + if (fr_checkl4sum(fin) == -1) + fin->fin_flx |= FI_BAD; +} +#endif + + +/* + * See above for description, except that all addressing is in user space. + */ +int copyoutptr(src, dst, size) +void *src, *dst; +size_t size; +{ + caddr_t ca; + + bcopy(dst, (char *)&ca, sizeof(ca)); + bcopy(src, ca, size); + return 0; +} + + +/* + * See above for description, except that all addressing is in user space. + */ +int copyinptr(src, dst, size) +void *src, *dst; +size_t size; +{ + caddr_t ca; + + bcopy(src, (char *)&ca, sizeof(ca)); + bcopy(ca, dst, size); + return 0; +} + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(v, atype, ifptr, inp, inpmask) +int v, atype; +void *ifptr; +struct in_addr *inp, *inpmask; +{ + struct ifnet *ifp = ifptr; +#ifdef __sgi + struct in_ifaddr *ifa; +#else + struct ifaddr *ifa; +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + ifa = ifp->if_addrlist.tqh_first; +#else +# ifdef __sgi + ifa = (struct in_ifaddr *)ifp->in_ifaddr; +# else + ifa = ifp->if_addrlist; +# endif +#endif + if (ifa != NULL) { + struct sockaddr_in *sin, mask; + + mask.sin_addr.s_addr = 0xffffffff; + +#ifdef __sgi + sin = (struct sockaddr_in *)&ifa->ia_addr; +#else + sin = (struct sockaddr_in *)&ifa->ifa_addr; +#endif + + return fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask); + } + return 0; +} diff --git a/contrib/ipfilter/ip_fil.h b/contrib/ipfilter/ip_fil.h index 73099ec..2aacb3f 100644 --- a/contrib/ipfilter/ip_fil.h +++ b/contrib/ipfilter/ip_fil.h @@ -1,31 +1,21 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1993-2002 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.29.2.35 2003/06/07 11:56:02 darrenr Exp $ + * Id: ip_fil.h,v 2.170.2.18 2005/03/28 10:47:52 darrenr Exp */ #ifndef __IP_FIL_H__ #define __IP_FIL_H__ -/* - * Pathnames for various IP Filter control devices. Used by LKM - * and userland, so defined here. - */ -#define IPNAT_NAME "/dev/ipnat" -#define IPSTATE_NAME "/dev/ipstate" -#define IPAUTH_NAME "/dev/ipauth" - #ifndef SOLARIS # define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif - #ifndef __P # ifdef __STDC__ # define __P(x) x @@ -34,137 +24,321 @@ # endif #endif -#ifndef offsetof -# define offsetof(t,m) (int)((&((t *)0L)->m)) -#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 ipfobj) +# define SIOCRMAFR _IOW('r', 61, struct ipfobj) # define SIOCSETFF _IOW('r', 62, u_int) # define SIOCGETFF _IOR('r', 63, u_int) -# define SIOCGETFS _IOWR('r', 64, struct friostat *) +# define SIOCGETFS _IOWR('r', 64, struct ipfobj) # 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 ipfobj) +# define SIOCRMIFR _IOW('r', 68, struct ipfobj) # 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 ipfobj) +# define SIOCINIFR _IOW('r', 71, struct ipfobj) # 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 frauth *) -# define SIOCAUTHR _IOWR('r', 77, struct frauth *) -# define SIOCATHST _IOWR('r', 78, struct fr_authstat *) +# define SIOCFRZST _IOWR('r', 74, struct ipfobj) +# define SIOCZRLST _IOWR('r', 75, struct ipfobj) +# define SIOCAUTHW _IOWR('r', 76, struct ipfobj) +# define SIOCAUTHR _IOWR('r', 77, struct ipfobj) +# define SIOCATHST _IOWR('r', 78, struct ipfobj) # 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 *) -# define SIOCIPFL6 _IOWR('r', 84, int) +# define SIOCSTPUT _IOWR('r', 80, struct ipfobj) +# define SIOCSTGET _IOWR('r', 81, struct ipfobj) +# define SIOCSTGSZ _IOWR('r', 82, struct ipfobj) +# define SIOCGFRST _IOWR('r', 83, struct ipfobj) +# define SIOCSETLG _IOWR('r', 84, int) +# define SIOCGETLG _IOWR('r', 85, int) +# define SIOCFUNCL _IOWR('r', 86, struct ipfunc_resolve) +# define SIOCIPFGETNEXT _IOWR('r', 87, struct ipfobj) +# define SIOCIPFGET _IOWR('r', 88, struct ipfobj) +# define SIOCIPFSET _IOWR('r', 89, struct ipfobj) +# define SIOCIPFL6 _IOWR('r', 90, int) #else -# define SIOCADAFR _IOW(r, 60, struct frentry *) -# define SIOCRMAFR _IOW(r, 61, struct frentry *) +# define SIOCADAFR _IOW(r, 60, struct ipfobj) +# define SIOCRMAFR _IOW(r, 61, struct ipfobj) # define SIOCSETFF _IOW(r, 62, u_int) # define SIOCGETFF _IOR(r, 63, u_int) -# define SIOCGETFS _IOWR(r, 64, struct friostat *) +# define SIOCGETFS _IOWR(r, 64, struct ipfobj) # 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 ipfobj) +# define SIOCRMIFR _IOW(r, 68, struct ipfobj) # 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 ipfobj) +# define SIOCINIFR _IOW(r, 71, struct ipfobj) # 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 frauth *) -# define SIOCAUTHR _IOWR(r, 77, struct frauth *) -# define SIOCATHST _IOWR(r, 78, struct fr_authstat *) +# define SIOCFRZST _IOWR(r, 74, struct ipfobj) +# define SIOCZRLST _IOWR(r, 75, struct ipfobj) +# define SIOCAUTHW _IOWR(r, 76, struct ipfobj) +# define SIOCAUTHR _IOWR(r, 77, struct ipfobj) +# define SIOCATHST _IOWR(r, 78, struct ipfobj) # 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 *) -# define SIOCIPFL6 _IOWR(r, 84, int) +# define SIOCSTPUT _IOWR(r, 80, struct ipfobj) +# define SIOCSTGET _IOWR(r, 81, struct ipfobj) +# define SIOCSTGSZ _IOWR(r, 82, struct ipfobj) +# define SIOCGFRST _IOWR(r, 83, struct ipfobj) +# define SIOCSETLG _IOWR(r, 84, int) +# define SIOCGETLG _IOWR(r, 85, int) +# define SIOCFUNCL _IOWR(r, 86, struct ipfunc_resolve) +# define SIOCIPFGETNEXT _IOWR(r, 87, struct ipfobj) +# define SIOCIPFGET _IOWR(r, 88, struct ipfobj) +# define SIOCIPFSET _IOWR(r, 89, struct ipfobj) +# define SIOCIPFL6 _IOWR(r, 90, int) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR #define SIOCINSFR SIOCINAFR +struct ipscan; +struct ifnet; + + +typedef int (* lookupfunc_t) __P((void *, int, void *)); + +/* + * i6addr is used as a container for both IPv4 and IPv6 addresses, as well + * as other types of objects, depending on its qualifier. + */ +#ifdef USE_INET6 +typedef union i6addr { + u_32_t i6[4]; + struct in_addr in4; + struct in6_addr in6; + void *vptr[2]; + lookupfunc_t lptr[2]; +} i6addr_t; +#else +typedef union i6addr { + u_32_t i6[4]; + struct in_addr in4; + void *vptr[2]; + lookupfunc_t lptr[2]; +} i6addr_t; +#endif + +#define in4_addr in4.s_addr +#define iplookupnum i6[0] +#define iplookuptype i6[1] +/* + * NOTE: These DO overlap the above on 64bit systems and this IS recognised. + */ +#define iplookupptr vptr[0] +#define iplookupfunc lptr[1] + +#define I60(x) (((i6addr_t *)(x))->i6[0]) +#define I61(x) (((i6addr_t *)(x))->i6[1]) +#define I62(x) (((i6addr_t *)(x))->i6[2]) +#define I63(x) (((i6addr_t *)(x))->i6[3]) +#define HI60(x) ntohl(((i6addr_t *)(x))->i6[0]) +#define HI61(x) ntohl(((i6addr_t *)(x))->i6[1]) +#define HI62(x) ntohl(((i6addr_t *)(x))->i6[2]) +#define HI63(x) ntohl(((i6addr_t *)(x))->i6[3]) + +#define IP6_EQ(a,b) ((I63(a) == I63(b)) && (I62(a) == I62(b)) && \ + (I61(a) == I61(b)) && (I60(a) == I60(b))) +#define IP6_NEQ(a,b) ((I63(a) != I63(b)) || (I62(a) != I62(b)) || \ + (I61(a) != I61(b)) || (I60(a) != I60(b))) +#define IP6_ISZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) == 0) +#define IP6_NOTZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) != 0) +#define IP6_GT(a,b) (HI60(a) > HI60(b) || (HI60(a) == HI60(b) && \ + (HI61(a) > HI61(b) || (HI61(a) == HI61(b) && \ + (HI62(a) > HI62(b) || (HI62(a) == HI62(b) && \ + HI63(a) > HI63(b))))))) +#define IP6_LT(a,b) (HI60(a) < HI60(b) || (HI60(a) == HI60(b) && \ + (HI61(a) < HI61(b) || (HI61(a) == HI61(b) && \ + (HI62(a) < HI62(b) || (HI62(a) == HI62(b) && \ + HI63(a) < HI63(b))))))) +#define NLADD(n,x) htonl(ntohl(n) + (x)) +#define IP6_INC(a) \ + { i6addr_t *_i6 = (i6addr_t *)(a); \ + _i6->i6[0] = NLADD(_i6->i6[0], 1); \ + if (_i6->i6[0] == 0) { \ + _i6->i6[0] = NLADD(_i6->i6[1], 1); \ + if (_i6->i6[1] == 0) { \ + _i6->i6[0] = NLADD(_i6->i6[2], 1); \ + if (_i6->i6[2] == 0) { \ + _i6->i6[0] = NLADD(_i6->i6[3], 1); \ + } \ + } \ + } \ + } +#define IP6_ADD(a,x,d) \ + { i6addr_t *_s = (i6addr_t *)(a); \ + i6addr_t *_d = (i6addr_t *)(d); \ + _d->i6[0] = NLADD(_s->i6[0], x); \ + if (ntohl(_d->i6[0]) < ntohl(_s->i6[0])) { \ + _d->i6[1] = NLADD(_d->i6[1], 1); \ + if (ntohl(_d->i6[1]) < ntohl(_s->i6[1])) { \ + _d->i6[2] = NLADD(_d->i6[2], 1); \ + if (ntohl(_d->i6[2]) < ntohl(_s->i6[2])) { \ + _d->i6[3] = NLADD(_d->i6[3], 1); \ + } \ + } \ + } \ + } +#define IP6_AND(a,b,d) { i6addr_t *_s1 = (i6addr_t *)(a); \ + i6addr_t *_s2 = (i6addr_t *)(d); \ + i6addr_t *_d = (i6addr_t *)(d); \ + _d->i6[0] = _s1->i6[0] & _s2->i6[0]; \ + _d->i6[1] = _s1->i6[1] & _s2->i6[1]; \ + _d->i6[2] = _s1->i6[2] & _s2->i6[2]; \ + _d->i6[3] = _s1->i6[3] & _s2->i6[3]; \ + } +#define IP6_MERGE(a,b,c) \ + { i6addr_t *_d, *_s1, *_s2; \ + _d = (i6addr_t *)(a); \ + _s1 = (i6addr_t *)(b); \ + _s2 = (i6addr_t *)(c); \ + _d->i6[0] |= _s1->i6[0] & ~_s2->i6[0]; \ + _d->i6[1] |= _s1->i6[1] & ~_s2->i6[1]; \ + _d->i6[2] |= _s1->i6[2] & ~_s2->i6[2]; \ + _d->i6[2] |= _s1->i6[3] & ~_s2->i6[3]; \ + } + + typedef struct fr_ip { u_32_t fi_v:4; /* IP version */ - u_32_t fi_fl:4; /* packet flags */ + u_32_t fi_xx:4; /* spare */ 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 */ + i6addr_t fi_src; /* source address from packet */ + i6addr_t fi_dst; /* destination address from packet */ u_short fi_secmsk; /* bitmask composed from IP security options */ u_short fi_auth; /* authentication code from IP sec. options */ + u_32_t fi_flx; /* packet flags */ + u_32_t fi_tcpmsk; /* TCP options set/reset */ + u_32_t fi_res1; /* RESERVED */ } fr_ip_t; -#define FI_OPTIONS (FF_OPTIONS >> 24) -#define FI_TCPUDP (FF_TCPUDP >> 24) /* TCP/UCP implied comparison*/ -#define FI_FRAG (FF_FRAG >> 24) -#define FI_SHORT (FF_SHORT >> 24) -#define FI_CMP (FI_OPTIONS|FI_TCPUDP|FI_SHORT) +/* + * For use in fi_flx + */ +#define FI_TCPUDP 0x0001 /* TCP/UCP implied comparison*/ +#define FI_OPTIONS 0x0002 +#define FI_FRAG 0x0004 +#define FI_SHORT 0x0008 +#define FI_NATED 0x0010 +#define FI_MULTICAST 0x0020 +#define FI_BROADCAST 0x0040 +#define FI_MBCAST 0x0080 +#define FI_STATE 0x0100 +#define FI_BADNAT 0x0200 +#define FI_BAD 0x0400 +#define FI_OOW 0x0800 /* Out of state window, else match */ +#define FI_ICMPERR 0x1000 +#define FI_FRAGBODY 0x2000 +#define FI_BADSRC 0x4000 +#define FI_LOWTTL 0x8000 +#define FI_CMP 0xcfe3 /* Not FI_FRAG,FI_NATED,FI_FRAGTAIL */ +#define FI_ICMPCMP 0x0003 /* Flags we can check for ICMP error packets */ +#define FI_WITH 0xeffe /* Not FI_TCPUDP */ +#define FI_V6EXTHDR 0x10000 +#define FI_COALESCE 0x20000 +#define FI_NOCKSUM 0x20000000 /* don't do a L4 checksum validation */ +#define FI_DONTCACHE 0x40000000 /* don't cache the result */ +#define FI_IGNORE 0x80000000 #define fi_saddr fi_src.in4.s_addr #define fi_daddr fi_dst.in4.s_addr +#define fi_srcnum fi_src.iplookupnum +#define fi_dstnum fi_dst.iplookupnum +#define fi_srctype fi_src.iplookuptype +#define fi_dsttype fi_dst.iplookuptype +#define fi_srcptr fi_src.iplookupptr +#define fi_dstptr fi_dst.iplookupptr +#define fi_srcfunc fi_src.iplookupfunc +#define fi_dstfunc fi_dst.iplookupfunc /* * These are both used by the state and NAT code to indicate that one port or * the other should be treated as a wildcard. + * NOTE: When updating, check bit masks in ip_state.h and update there too. */ -#define FI_W_SPORT 0x00000100 -#define FI_W_DPORT 0x00000200 -#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 /* Create a filter rule */ -#define FI_IGNOREPKT 0x00002000 /* Do not treat as a real packet */ -#define FI_NORULE 0x00004000 /* Not direct a result of a rule */ +#define SI_W_SPORT 0x00000100 +#define SI_W_DPORT 0x00000200 +#define SI_WILDP (SI_W_SPORT|SI_W_DPORT) +#define SI_W_SADDR 0x00000400 +#define SI_W_DADDR 0x00000800 +#define SI_WILDA (SI_W_SADDR|SI_W_DADDR) +#define SI_NEWFR 0x00001000 +#define SI_CLONE 0x00002000 +#define SI_CLONED 0x00004000 + typedef struct fr_info { void *fin_ifp; /* interface packet is `on' */ - struct fr_ip fin_fi; /* IP Packet summary */ - u_short fin_data[2]; /* TCP/UDP ports, ICMP code/type */ - u_int fin_out; /* in or out ? 1 == out, 0 == in */ + fr_ip_t fin_fi; /* IP Packet summary */ + union { + u_short fid_16[2]; /* TCP/UDP ports, ICMP code/type */ + u_32_t fid_32; + } fin_dat; + int fin_out; /* in or out ? 1 == out, 0 == in */ + int fin_rev; /* state only: 1 = reverse */ u_short fin_hlen; /* length of IP header in bytes */ - u_char fin_rev; /* state only: 1 = reverse */ u_char fin_tcpf; /* TCP header flags (SYN, ACK, etc) */ - u_int fin_icode; /* ICMP error to return */ + u_char fin_icode; /* ICMP error to return */ u_32_t fin_rule; /* rule # last matched */ - u_32_t fin_group; /* group number, -1 for none */ + char fin_group[FR_GROUPLEN]; /* group number, -1 for none */ struct frentry *fin_fr; /* last matching rule */ - char *fin_dp; /* start of data past IP header */ - u_short fin_plen; - u_short fin_off; - u_short fin_dlen; /* length of data portion of packet */ + void *fin_dp; /* start of data past IP header */ + int fin_dlen; /* length of data portion of packet */ + int fin_plen; + int fin_ipoff; /* # bytes from buffer start to hdr */ u_short fin_id; /* IP packet id field */ - u_int fin_misc; + u_short fin_off; + int fin_depth; /* Group nesting depth */ + int fin_error; /* Error code to return */ + void *fin_nat; + void *fin_state; + void *fin_nattag; + ip_t *fin_ip; mb_t **fin_mp; /* pointer to pointer to mbuf */ -#if SOLARIS - void *fin_qfm; /* pointer to mblk where pkt starts */ - void *fin_qif; + mb_t *fin_m; /* pointer to mbuf */ +#ifdef MENTAT + mb_t *fin_qfm; /* pointer to mblk where pkt starts */ + void *fin_qpi; +#endif +#ifdef __sgi + void *fin_hbuf; #endif } fr_info_t; #define fin_v fin_fi.fi_v #define fin_p fin_fi.fi_p -#define fin_saddr fin_fi.fi_saddr +#define fin_flx fin_fi.fi_flx +#define fin_optmsk fin_fi.fi_optmsk +#define fin_secmsk fin_fi.fi_secmsk +#define fin_auth fin_fi.fi_auth #define fin_src fin_fi.fi_src.in4 -#define fin_daddr fin_fi.fi_daddr +#define fin_src6 fin_fi.fi_src.in6 +#define fin_saddr fin_fi.fi_saddr #define fin_dst fin_fi.fi_dst.in4 -#define fin_fl fin_fi.fi_fl +#define fin_dst6 fin_fi.fi_dst.in6 +#define fin_daddr fin_fi.fi_daddr +#define fin_data fin_dat.fid_16 +#define fin_sport fin_dat.fid_16[0] +#define fin_dport fin_dat.fid_16[1] +#define fin_ports fin_dat.fid_32 + +#define IPF_IN 0 +#define IPF_OUT 1 + +typedef struct frentry *(*ipfunc_t) __P((fr_info_t *, u_32_t *)); +typedef int (*ipfuncinit_t) __P((struct frentry *)); + +typedef struct ipfunc_resolve { + char ipfu_name[32]; + ipfunc_t ipfu_addr; + ipfuncinit_t ipfu_init; +} ipfunc_resolve_t; /* * Size for compares on fr_info structures @@ -173,36 +347,66 @@ typedef struct fr_info { #define FI_LCSIZE offsetof(fr_info_t, fin_dp) /* - * For fin_misc + * Size for copying cache fr_info structure */ -#define FM_BADSTATE 0x00000001 +#define FI_COPYSIZE offsetof(fr_info_t, fin_dp) /* - * Size for copying cache fr_info structure + * Structure for holding IPFilter's tag information */ -#define FI_COPYSIZE offsetof(fr_info_t, fin_dp) +#define IPFTAG_LEN 16 +typedef struct { + union { + u_32_t iptu_num[4]; + char iptu_tag[IPFTAG_LEN]; + } ipt_un; + int ipt_not; +} ipftag_t; + +#define ipt_tag ipt_un.iptu_tag +#define ipt_num ipt_un.iptu_num + +/* + * This structure is used to hold information about the next hop for where + * to forward a packet. + */ typedef struct frdest { void *fd_ifp; - union i6addr fd_ip6; + i6addr_t fd_ip6; char fd_ifname[LIFNAMSIZ]; -#if SOLARIS - mb_t *fd_mp; /* cache resolver for to/dup-to */ -#endif } frdest_t; #define fd_ip fd_ip6.in4 +/* + * This structure holds information about a port comparison. + */ 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; +#define FR_NONE 0 +#define FR_EQUAL 1 +#define FR_NEQUAL 2 +#define FR_LESST 3 +#define FR_GREATERT 4 +#define FR_LESSTE 5 +#define FR_GREATERTE 6 +#define FR_OUTRANGE 7 +#define FR_INRANGE 8 +#define FR_INCRANGE 9 + +/* + * Structure containing all the relevant TCP things that can be checked in + * a filter rule. + */ typedef struct frtuc { - u_char ftu_tcpfm; /* tcp flags mask */ - u_char ftu_tcpf; /* tcp flags */ + u_char ftu_tcpfm; /* tcp flags mask */ + u_char ftu_tcpf; /* tcp flags */ frpcmp_t ftu_src; frpcmp_t ftu_dst; } frtuc_t; @@ -214,47 +418,123 @@ typedef struct frtuc { #define ftu_stop ftu_src.frp_top #define ftu_dtop ftu_dst.frp_top +#define FR_TCPFMAX 0x3f + +/* + * This structure makes up what is considered to be the IPFilter specific + * matching components of a filter rule, as opposed to the data structures + * used to define the result which are in frentry_t and not here. + */ +typedef struct fripf { + fr_ip_t fri_ip; + fr_ip_t fri_mip; /* mask structure */ + + u_short fri_icmpm; /* data for ICMP packets (mask) */ + u_short fri_icmp; + + frtuc_t fri_tuc; + int fri_satype; /* addres type */ + int fri_datype; /* addres type */ + int fri_sifpidx; /* doing dynamic addressing */ + int fri_difpidx; /* index into fr_ifps[] to use when */ +} fripf_t; + +#define fri_dstnum fri_ip.fi_dstnum +#define fri_srcnum fri_mip.fi_srcnum +#define fri_dstptr fri_ip.fi_dstptr +#define fri_srcptr fri_mip.fi_srcptr + +#define FRI_NORMAL 0 /* Normal address */ +#define FRI_DYNAMIC 1 /* dynamic address */ +#define FRI_LOOKUP 2 /* address is a pool # */ +#define FRI_RANGE 3 /* address/mask is a range */ +#define FRI_NETWORK 4 /* network address from if */ +#define FRI_BROADCAST 5 /* broadcast address from if */ +#define FRI_PEERADDR 6 /* Peer address for P-to-P */ +#define FRI_NETMASKED 7 /* network address with netmask from if */ + + +typedef struct frentry * (* frentfunc_t) __P((fr_info_t *)); + typedef struct frentry { + ipfmutex_t fr_lock; struct frentry *fr_next; - struct frentry *fr_grp; - int fr_ref; /* reference count - for grouping */ + struct frentry **fr_grp; + struct ipscan *fr_isc; void *fr_ifas[4]; + void *fr_ptr; /* for use with fr_arg */ + char *fr_comment; /* text comment for rule */ + int fr_ref; /* reference count - for grouping */ + int fr_statecnt; /* state count - for limit rules */ /* * These are only incremented when a packet matches this rule and * it is the last match */ U_QUAD_T fr_hits; U_QUAD_T fr_bytes; + /* - * Fields after this may not change whilst in the kernel. + * For PPS rate limiting */ - struct fr_ip fr_ip; - struct fr_ip fr_mip; /* mask structure */ - + struct timeval fr_lastpkt; + int fr_curpps; - u_short fr_icmpm; /* data for ICMP packets (mask) */ - u_short fr_icmp; + union { + void *fru_data; + caddr_t fru_caddr; + fripf_t *fru_ipf; + frentfunc_t fru_func; + } fr_dun; - u_int fr_age[2]; /* aging for state */ - frtuc_t fr_tuc; - u_32_t fr_group; /* group to which this rule belongs */ - u_32_t fr_grhead; /* group # which this rule starts */ + /* + * Fields after this may not change whilst in the kernel. + */ + ipfunc_t fr_func; /* call this function */ + int fr_dsize; + int fr_pps; + int fr_statemax; /* max reference count */ + int fr_flineno; /* line number from conf file */ + u_32_t fr_type; u_32_t fr_flags; /* per-rule flags && options (see below) */ - u_int fr_skip; /* # of rules to skip */ + u_32_t fr_logtag; /* user defined log tag # */ + u_32_t fr_collect; /* collection number */ + u_int fr_arg; /* misc. numeric arg for rule */ u_int fr_loglevel; /* syslog log facility + priority */ - int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ - int fr_sap; /* For solaris only */ + u_int fr_age[2]; /* non-TCP timeouts */ + u_char fr_v; u_char fr_icode; /* return ICMP code */ + char fr_group[FR_GROUPLEN]; /* group to which this rule belongs */ + char fr_grhead[FR_GROUPLEN]; /* group # which this rule starts */ + ipftag_t fr_nattag; char fr_ifnames[4][LIFNAMSIZ]; - struct frdest fr_tif; /* "to" interface */ - struct frdest fr_dif; /* duplicate packet interfaces */ + char fr_isctag[16]; + frdest_t fr_tifs[2]; /* "to"/"reply-to" interface */ + frdest_t fr_dif; /* duplicate packet interface */ + /* + * This must be last and will change after loaded into the kernel. + */ u_int fr_cksum; /* checksum on filter rules for performance */ } frentry_t; -#define fr_v fr_ip.fi_v +#define fr_caddr fr_dun.fru_caddr +#define fr_data fr_dun.fru_data +#define fr_dfunc fr_dun.fru_func +#define fr_ipf fr_dun.fru_ipf +#define fr_ip fr_ipf->fri_ip +#define fr_mip fr_ipf->fri_mip +#define fr_icmpm fr_ipf->fri_icmpm +#define fr_icmp fr_ipf->fri_icmp +#define fr_tuc fr_ipf->fri_tuc +#define fr_satype fr_ipf->fri_satype +#define fr_datype fr_ipf->fri_datype +#define fr_sifpidx fr_ipf->fri_sifpidx +#define fr_difpidx fr_ipf->fri_difpidx #define fr_proto fr_ip.fi_p +#define fr_mproto fr_mip.fi_p #define fr_ttl fr_ip.fi_ttl +#define fr_mttl fr_mip.fi_ttl #define fr_tos fr_ip.fi_tos +#define fr_mtos fr_mip.fi_tos #define fr_tcpfm fr_tuc.ftu_tcpfm #define fr_tcpf fr_tuc.ftu_tcpf #define fr_scmp fr_tuc.ftu_scmp @@ -264,58 +544,110 @@ typedef struct frentry { #define fr_stop fr_tuc.ftu_stop #define fr_dtop fr_tuc.ftu_dtop #define fr_dst fr_ip.fi_dst.in4 +#define fr_daddr fr_ip.fi_dst.in4.s_addr #define fr_src fr_ip.fi_src.in4 +#define fr_saddr fr_ip.fi_src.in4.s_addr #define fr_dmsk fr_mip.fi_dst.in4 +#define fr_dmask fr_mip.fi_dst.in4.s_addr #define fr_smsk fr_mip.fi_src.in4 +#define fr_smask fr_mip.fi_src.in4.s_addr +#define fr_dstnum fr_ip.fi_dstnum +#define fr_srcnum fr_ip.fi_srcnum +#define fr_dsttype fr_ip.fi_dsttype +#define fr_srctype fr_ip.fi_srctype +#define fr_dstptr fr_mip.fi_dstptr +#define fr_srcptr fr_mip.fi_srcptr +#define fr_dstfunc fr_mip.fi_dstfunc +#define fr_srcfunc fr_mip.fi_srcfunc +#define fr_optbits fr_ip.fi_optmsk +#define fr_optmask fr_mip.fi_optmsk +#define fr_secbits fr_ip.fi_secmsk +#define fr_secmask fr_mip.fi_secmsk +#define fr_authbits fr_ip.fi_auth +#define fr_authmask fr_mip.fi_auth +#define fr_flx fr_ip.fi_flx +#define fr_mflx fr_mip.fi_flx #define fr_ifname fr_ifnames[0] #define fr_oifname fr_ifnames[2] #define fr_ifa fr_ifas[0] #define fr_oifa fr_ifas[2] +#define fr_tif fr_tifs[0] +#define fr_rif fr_tifs[1] + +#define FR_NOLOGTAG 0 -#define FR_CMPSIZ (sizeof(struct frentry) - offsetof(frentry_t, fr_ip)) +#ifndef offsetof +#define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif +#define FR_CMPSIZ (sizeof(struct frentry) - \ + offsetof(struct frentry, fr_func)) + +/* + * fr_type + */ +#define FR_T_NONE 0 +#define FR_T_IPF 1 /* IPF structures */ +#define FR_T_BPFOPC 2 /* BPF opcode */ +#define FR_T_CALLFUNC 3 /* callout to function in fr_func only */ +#define FR_T_COMPIPF 4 /* compiled C code */ +#define FR_T_BUILTIN 0x80000000 /* rule is in kernel space */ /* * fr_flags */ +#define FR_CALL 0x00000 /* call rule */ #define FR_BLOCK 0x00001 /* do not allow packet to pass */ #define FR_PASS 0x00002 /* allow packet to pass */ -#define FR_OUTQUE 0x00004 /* outgoing packets */ -#define FR_INQUE 0x00008 /* ingoing packets */ +#define FR_AUTH 0x00003 /* use authentication */ +#define FR_PREAUTH 0x00004 /* require preauthentication */ +#define FR_ACCOUNT 0x00005 /* Accounting rule */ +#define FR_SKIP 0x00006 /* skip rule */ +#define FR_DIVERT 0x00007 /* divert rule */ +#define FR_CMDMASK 0x0000f #define FR_LOG 0x00010 /* Log */ #define FR_LOGB 0x00011 /* Log-fail */ #define FR_LOGP 0x00012 /* Log-pass */ -#define FR_NOTSRCIP 0x00020 /* not the src IP# */ -#define FR_NOTDSTIP 0x00040 /* not the dst IP# */ -#define FR_RETRST 0x00080 /* Return TCP RST packet - reset connection */ -#define FR_RETICMP 0x00100 /* Return ICMP unreachable packet */ -#define FR_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */ -#define FR_NOMATCH 0x00200 /* no match occured */ -#define FR_ACCOUNT 0x00400 /* count packet bytes */ -#define FR_KEEPFRAG 0x00800 /* keep fragment information */ -#define FR_KEEPSTATE 0x01000 /* keep `connection' state information */ -#define FR_INACTIVE 0x02000 -#define FR_QUICK 0x04000 /* match & stop processing list */ -#define FR_FASTROUTE 0x08000 /* bypass normal routing */ -#define FR_CALLNOW 0x10000 /* call another function (fr_func) if matches */ -#define FR_DUP 0x20000 /* duplicate packet */ +#define FR_LOGMASK (FR_LOG|FR_CMDMASK) +#define FR_CALLNOW 0x00020 /* call another function (fr_func) if matches */ +#define FR_NOTSRCIP 0x00040 +#define FR_NOTDSTIP 0x00080 +#define FR_QUICK 0x00100 /* match & stop processing list */ +#define FR_KEEPFRAG 0x00200 /* keep fragment information */ +#define FR_KEEPSTATE 0x00400 /* keep `connection' state information */ +#define FR_FASTROUTE 0x00800 /* bypass normal routing */ +#define FR_RETRST 0x01000 /* Return TCP RST packet - reset connection */ +#define FR_RETICMP 0x02000 /* Return ICMP unreachable packet */ +#define FR_FAKEICMP 0x03000 /* Return ICMP unreachable with fake source */ +#define FR_OUTQUE 0x04000 /* outgoing packets */ +#define FR_INQUE 0x08000 /* ingoing packets */ +#define FR_LOGBODY 0x10000 /* Log the body */ +#define FR_LOGFIRST 0x20000 /* Log the first byte if state held */ #define FR_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */ -#define FR_LOGBODY 0x80000 /* Log the body */ -#define FR_LOGFIRST 0x100000 /* Log the first byte if state held */ -#define FR_AUTH 0x200000 /* use authentication */ -#define FR_PREAUTH 0x400000 /* require preauthentication */ -#define FR_DONTCACHE 0x800000 /* don't cache the result */ +#define FR_DUP 0x80000 /* duplicate packet */ +#define FR_FRSTRICT 0x100000 /* strict frag. cache */ +#define FR_STSTRICT 0x200000 /* strict keep state */ +#define FR_NEWISN 0x400000 /* new ISN for outgoing TCP */ +#define FR_NOICMPERR 0x800000 /* do not match ICMP errors in state */ +#define FR_STATESYNC 0x1000000 /* synchronize state to slave */ +#define FR_NOMATCH 0x8000000 /* no match occured */ + /* 0x10000000 FF_LOGPASS */ + /* 0x20000000 FF_LOGBLOCK */ + /* 0x40000000 FF_LOGNOMATCH */ + /* 0x80000000 FF_BLOCKNONIP */ +#define FR_COPIED 0x40000000 /* copied from user space */ +#define FR_INACTIVE 0x80000000 /* only used when flush'ing rules */ -#define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB) #define FR_RETMASK (FR_RETICMP|FR_RETRST|FR_FAKEICMP) +#define FR_ISBLOCK(x) (((x) & FR_CMDMASK) == FR_BLOCK) +#define FR_ISPASS(x) (((x) & FR_CMDMASK) == FR_PASS) +#define FR_ISAUTH(x) (((x) & FR_CMDMASK) == FR_AUTH) +#define FR_ISPREAUTH(x) (((x) & FR_CMDMASK) == FR_PREAUTH) +#define FR_ISACCOUNT(x) (((x) & FR_CMDMASK) == FR_ACCOUNT) +#define FR_ISSKIP(x) (((x) & FR_CMDMASK) == FR_SKIP) +#define FR_ISNOMATCH(x) ((x) & FR_NOMATCH) +#define FR_INOUT (FR_INQUE|FR_OUTQUE) /* - * These correspond to #define's for FI_* and are stored in fr_flags - */ -#define FF_OPTIONS 0x01000000 -#define FF_TCPUDP 0x02000000 -#define FF_FRAG 0x04000000 -#define FF_SHORT 0x08000000 -/* * recognized flags for SIOCGETFF and SIOCSETFF, and get put in fr_flags */ #define FF_LOGPASS 0x10000000 @@ -324,16 +656,40 @@ typedef struct frentry { #define FF_LOGGING (FF_LOGPASS|FF_LOGBLOCK|FF_LOGNOMATCH) #define FF_BLOCKNONIP 0x80000000 /* Solaris2 Only */ -#define FR_NONE 0 -#define FR_EQUAL 1 -#define FR_NEQUAL 2 -#define FR_LESST 3 -#define FR_GREATERT 4 -#define FR_LESSTE 5 -#define FR_GREATERTE 6 -#define FR_OUTRANGE 7 -#define FR_INRANGE 8 +/* + * Structure that passes information on what/how to flush to the kernel. + */ +typedef struct ipfflush { + int ipflu_how; + int ipflu_arg; +} ipfflush_t; + + +/* + * + */ +typedef struct ipfgetctl { + u_int ipfg_min; /* min value */ + u_int ipfg_current; /* current value */ + u_int ipfg_max; /* max value */ + u_int ipfg_default; /* default value */ + u_int ipfg_steps; /* value increments */ + char ipfg_name[40]; /* tag name for this control */ +} ipfgetctl_t; + +typedef struct ipfsetctl { + int ipfs_which; /* 0 = min 1 = current 2 = max 3 = default */ + u_int ipfs_value; /* min value */ + char ipfs_name[40]; /* tag name for this control */ +} ipfsetctl_t; + + +/* + * Some of the statistics below are in their own counters, but most are kept + * in this single structure so that they can all easily be collected and + * copied back as required. + */ typedef struct filterstats { u_long fr_pass; /* packets allowed */ u_long fr_block; /* packets denied */ @@ -356,59 +712,13 @@ typedef struct filterstats { u_long fr_pull[2]; /* good and bad pullup attempts */ u_long fr_badsrc; /* source received doesn't match route */ u_long fr_badttl; /* TTL in packet doesn't reach minimum */ -#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 */ + u_long fr_ipv6; /* IPv6 packets in/out */ + u_long fr_ppshit; /* dropped because of pps ceiling */ + u_long fr_ipud; /* IP id update failures */ } filterstats_t; /* - * For SIOCGETFS - */ -typedef struct friostat { - struct filterstats f_st[2]; - struct frentry *f_fin[2]; - 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]; - int f_defpass; /* default pass - from fr_pass */ - 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 */ - char f_version[32]; /* version string */ - int f_locks[4]; -} friostat_t; - -typedef struct optlist { - u_short ol_val; - int ol_bit; -} optlist_t; - - -/* - * Group list structure. - */ -typedef struct frgroup { - u_32_t fg_num; - struct frgroup *fg_next; - struct frentry *fg_head; - struct frentry **fg_start; -} frgroup_t; - - -/* * Log structure. Each packet header logged is prepended by one of these. * Following this in the log records read from the device will be an ipflog * structure which is then followed by any packet data. @@ -416,40 +726,39 @@ typedef struct frgroup { typedef struct iplog { u_32_t ipl_magic; u_int ipl_count; - struct timeval ipl_tv; + struct timeval ipl_time; size_t ipl_dsize; struct iplog *ipl_next; } iplog_t; -#define ipl_sec ipl_tv.tv_sec -#define ipl_usec ipl_tv.tv_usec +#define ipl_sec ipl_time.tv_sec +#define ipl_usec ipl_time.tv_usec -#define IPL_MAGIC 0x49504c4d /* 'IPLM' */ +#define IPL_MAGIC 0x49504c4d /* 'IPLM' */ +#define IPL_MAGIC_NAT 0x49504c4e /* 'IPLN' */ +#define IPL_MAGIC_STATE 0x49504c53 /* 'IPLS' */ #define IPLOG_SIZE sizeof(iplog_t) typedef struct ipflog { #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) - char fl_ifname[LIFNAMSIZ]; #else u_int fl_unit; - char fl_ifname[LIFNAMSIZ]; #endif - u_char fl_plen; /* extra data after hlen */ - u_char fl_hlen; /* length of IP headers saved */ - 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; + u_32_t fl_logtag; + ipftag_t fl_nattag; + u_short fl_plen; /* extra data after hlen */ + u_short fl_loglevel; /* syslog log level */ + char fl_group[FR_GROUPLEN]; + u_char fl_hlen; /* length of IP headers saved */ u_char fl_dir; - u_char fl_pad[3]; + u_char fl_xxx[2]; /* pad */ + char fl_ifname[LIFNAMSIZ]; } ipflog_t; - -#ifndef ICMP_UNREACH_FILTER -# define ICMP_UNREACH_FILTER 13 -#endif - #ifndef IPF_LOGGING # define IPF_LOGGING 0 #endif @@ -457,8 +766,14 @@ typedef struct ipflog { # define IPF_DEFAULT_PASS FR_PASS #endif -#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) -#define IPLLOGSIZE 8192 +#define DEFAULT_IPFLOGSIZE 8192 +#ifndef IPFILTER_LOGSIZE +# define IPFILTER_LOGSIZE DEFAULT_IPFLOGSIZE +#else +# if IPFILTER_LOGSIZE < DEFAULT_IPFLOGSIZE +# error IPFILTER_LOGSIZE too small. Must be >= DEFAULT_IPFLOGSIZE +# endif +#endif #define IPF_OPTCOPY 0x07ff00 /* bit mask of copied options */ @@ -473,15 +788,309 @@ typedef struct ipflog { # define IPL_NAME "/dev/ipl" # endif #endif -#define IPL_NAT IPNAT_NAME -#define IPL_STATE IPSTATE_NAME -#define IPL_AUTH IPAUTH_NAME +/* + * Pathnames for various IP Filter control devices. Used by LKM + * and userland, so defined here. + */ +#define IPNAT_NAME "/dev/ipnat" +#define IPSTATE_NAME "/dev/ipstate" +#define IPAUTH_NAME "/dev/ipauth" +#define IPSYNC_NAME "/dev/ipsync" +#define IPSCAN_NAME "/dev/ipscan" +#define IPLOOKUP_NAME "/dev/iplookup" #define IPL_LOGIPF 0 /* Minor device #'s for accessing logs */ #define IPL_LOGNAT 1 #define IPL_LOGSTATE 2 #define IPL_LOGAUTH 3 -#define IPL_LOGMAX 3 +#define IPL_LOGSYNC 4 +#define IPL_LOGSCAN 5 +#define IPL_LOGLOOKUP 6 +#define IPL_LOGCOUNT 7 +#define IPL_LOGMAX 7 +#define IPL_LOGSIZE IPL_LOGMAX + 1 +#define IPL_LOGALL -1 +#define IPL_LOGNONE -2 + +/* + * For SIOCGETFS + */ +typedef struct friostat { + struct filterstats f_st[2]; + struct frentry *f_ipf[2][2]; + struct frentry *f_acct[2][2]; + struct frentry *f_ipf6[2][2]; + struct frentry *f_acct6[2][2]; + struct frentry *f_auth; + struct frgroup *f_groups[IPL_LOGSIZE][2]; + u_long f_froute[2]; + u_long f_ticks; + int f_locks[IPL_LOGMAX]; + size_t f_kmutex_sz; + size_t f_krwlock_sz; + int f_defpass; /* default pass - from fr_pass */ + int f_active; /* 1 or 0 - active rule set */ + int f_running; /* 1 if running, else 0 */ + int f_logging; /* 1 if enabled, else 0 */ + int f_features; + char f_version[32]; /* version string */ +} friostat_t; + +#define f_fin f_ipf[0] +#define f_fin6 f_ipf6[0] +#define f_fout f_ipf[1] +#define f_fout6 f_ipf6[1] +#define f_acctin f_acct[0] +#define f_acctin6 f_acct6[0] +#define f_acctout f_acct[1] +#define f_acctout6 f_acct6[1] + +#define IPF_FEAT_LKM 0x001 +#define IPF_FEAT_LOG 0x002 +#define IPF_FEAT_LOOKUP 0x004 +#define IPF_FEAT_BPF 0x008 +#define IPF_FEAT_COMPILED 0x010 +#define IPF_FEAT_CKSUM 0x020 +#define IPF_FEAT_SYNC 0x040 +#define IPF_FEAT_SCAN 0x080 +#define IPF_FEAT_IPV6 0x100 + +typedef struct optlist { + u_short ol_val; + int ol_bit; +} optlist_t; + + +/* + * Group list structure. + */ +typedef struct frgroup { + struct frgroup *fg_next; + struct frentry *fg_head; + struct frentry *fg_start; + u_32_t fg_flags; + int fg_ref; + char fg_name[FR_GROUPLEN]; +} frgroup_t; + +#define FG_NAME(g) (*(g)->fg_name == '\0' ? "" : (g)->fg_name) + + +/* + * Used by state and NAT tables + */ +typedef struct icmpinfo { + u_short ici_id; + u_short ici_seq; + u_char ici_type; +} icmpinfo_t; + +typedef struct udpinfo { + u_short us_sport; + u_short us_dport; +} udpinfo_t; + + +typedef struct tcpdata { + u_32_t td_end; + u_32_t td_maxend; + u_32_t td_maxwin; + u_32_t td_winscale; + u_32_t td_maxseg; + int td_winflags; +} tcpdata_t; + +#define TCP_WSCALE_MAX 14 + +#define TCP_WSCALE_SEEN 0x00000001 +#define TCP_WSCALE_FIRST 0x00000002 + + +typedef struct tcpinfo { + u_short ts_sport; + u_short ts_dport; + tcpdata_t ts_data[2]; +} tcpinfo_t; + + +struct grebits { + u_32_t grb_C:1; + u_32_t grb_R:1; + u_32_t grb_K:1; + u_32_t grb_S:1; + u_32_t grb_s:1; + u_32_t grb_recur:1; + u_32_t grb_A:1; + u_32_t grb_flags:3; + u_32_t grb_ver:3; + u_short grb_ptype; +}; + +typedef struct grehdr { + union { + struct grebits gru_bits; + u_short gru_flags; + } gr_un; + u_short gr_len; + u_short gr_call; +} grehdr_t; + +#define gr_flags gr_un.gru_flags +#define gr_bits gr_un.gru_bits +#define gr_ptype gr_bits.grb_ptype +#define gr_C gr_bits.grb_C +#define gr_R gr_bits.grb_R +#define gr_K gr_bits.grb_K +#define gr_S gr_bits.grb_S +#define gr_s gr_bits.grb_s +#define gr_recur gr_bits.grb_recur +#define gr_A gr_bits.grb_A +#define gr_ver gr_bits.grb_ver + + +typedef struct greinfo { + u_short gs_call[2]; + u_short gs_flags; + u_short gs_ptype; +} greinfo_t; + +#define GRE_REV(x) ((ntohs(x) >> 13) & 7) + + +/* + * Timeout tail queue list member + */ +typedef struct ipftqent { + struct ipftqent **tqe_pnext; + struct ipftqent *tqe_next; + struct ipftq *tqe_ifq; + void *tqe_parent; /* pointer back to NAT/state struct */ + u_long tqe_die; /* when this entriy is to die */ + u_long tqe_touched; + int tqe_flags; + int tqe_state[2]; /* current state of this entry */ +} ipftqent_t; + +#define TQE_RULEBASED 0x00000001 + + +/* + * Timeout tail queue head for IPFilter + */ +typedef struct ipftq { + ipfmutex_t ifq_lock; + u_int ifq_ttl; + ipftqent_t *ifq_head; + ipftqent_t **ifq_tail; + struct ipftq *ifq_next; + struct ipftq **ifq_pnext; + int ifq_ref; + u_int ifq_flags; +} ipftq_t; + +#define IFQF_USER 0x01 /* User defined aging */ +#define IFQF_DELETE 0x02 /* Marked for deletion */ +#define IFQF_PROXY 0x04 /* Timeout queue in use by a proxy */ + +#define IPF_HZ_MULT 1 +#define IPF_HZ_DIVIDE 2 /* How many times a second ipfilter */ + /* checks its timeout queues. */ +#define IPF_TTLVAL(x) (((x) / IPF_HZ_MULT) * IPF_HZ_DIVIDE) + +/* + * Structure to define address for pool lookups. + */ +typedef struct { + u_char adf_len; + i6addr_t adf_addr; +} addrfamily_t; + + +/* + * Object structure description. For passing through in ioctls. + */ +typedef struct ipfobj { + u_32_t ipfo_rev; /* IPFilter version number */ + u_32_t ipfo_size; /* size of object at ipfo_ptr */ + void *ipfo_ptr; /* pointer to object */ + int ipfo_type; /* type of object being pointed to */ + int ipfo_offset; /* bytes from ipfo_ptr where to start */ + u_char ipfo_xxxpad[32]; /* reserved for future use */ +} ipfobj_t; + +#define IPFOBJ_FRENTRY 0 /* struct frentry */ +#define IPFOBJ_IPFSTAT 1 /* struct friostat */ +#define IPFOBJ_IPFINFO 2 /* struct fr_info */ +#define IPFOBJ_AUTHSTAT 3 /* struct fr_authstat */ +#define IPFOBJ_FRAGSTAT 4 /* struct ipfrstat */ +#define IPFOBJ_IPNAT 5 /* struct ipnat */ +#define IPFOBJ_NATSTAT 6 /* struct natstat */ +#define IPFOBJ_STATESAVE 7 /* struct ipstate_save */ +#define IPFOBJ_NATSAVE 8 /* struct nat_save */ +#define IPFOBJ_NATLOOKUP 9 /* struct natlookup */ +#define IPFOBJ_IPSTATE 10 /* struct ipstate */ +#define IPFOBJ_STATESTAT 11 /* struct ips_stat */ +#define IPFOBJ_FRAUTH 12 /* struct frauth */ +#define IPFOBJ_TUNEABLE 13 /* struct ipftune */ + + +typedef union ipftunevalptr { + void *ipftp_void; + u_long *ipftp_long; + u_int *ipftp_int; + u_short *ipftp_short; + u_char *ipftp_char; +} ipftunevalptr_t; + +typedef struct ipftuneable { + ipftunevalptr_t ipft_una; + char *ipft_name; + u_long ipft_min; + u_long ipft_max; + int ipft_sz; + int ipft_flags; + struct ipftuneable *ipft_next; +} ipftuneable_t; + +#define ipft_addr ipft_una.ipftp_void +#define ipft_plong ipft_una.ipftp_long +#define ipft_pint ipft_una.ipftp_int +#define ipft_pshort ipft_una.ipftp_short +#define ipft_pchar ipft_una.ipftp_char + +#define IPFT_RDONLY 1 /* read-only */ +#define IPFT_WRDISABLED 2 /* write when disabled only */ + +typedef union ipftuneval { + u_long ipftu_long; + u_int ipftu_int; + u_short ipftu_short; + u_char ipftu_char; +} ipftuneval_t; + +typedef struct ipftune { + void *ipft_cookie; + ipftuneval_t ipft_un; + u_long ipft_min; + u_long ipft_max; + int ipft_sz; + int ipft_flags; + char ipft_name[80]; +} ipftune_t; + +#define ipft_vlong ipft_un.ipftu_long +#define ipft_vint ipft_un.ipftu_int +#define ipft_vshort ipft_un.ipftu_short +#define ipft_vchar ipft_un.ipftu_char + + +/* +** HPUX Port +*/ +#ifdef __hpux +/* HP-UX locking sequence deadlock detection module lock MAJOR ID */ +# define IPF_SMAJ 0 /* temp assignment XXX, not critical */ +#endif #if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \ (__FreeBSD_version >= 220000) @@ -494,7 +1103,8 @@ typedef struct ipflog { * with this! */ #if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \ - (defined(NetBSD1_2) && NetBSD1_2 > 1) + (defined(NetBSD1_2) && NetBSD1_2 > 1) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 500043)) # if (NetBSD >= 199905) # define PFIL_HOOKS # endif @@ -503,63 +1113,62 @@ typedef struct ipflog { # endif #endif - #ifndef _KERNEL -extern char *get_ifname __P((struct ifnet *)); -extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +extern int fr_check __P((struct ip *, int, void *, int, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); -extern int send_reset __P((ip_t *, fr_info_t *)); -extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); extern int ipf_log __P((void)); extern struct ifnet *get_unit __P((char *, int)); -extern int mbuflen __P((mb_t *)); +extern char *get_ifname __P((struct ifnet *)); # if defined(__NetBSD__) || defined(__OpenBSD__) || \ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) -extern int iplioctl __P((dev_t, u_long, caddr_t, int)); +extern int iplioctl __P((int, ioctlcmd_t, caddr_t, int)); # else -extern int iplioctl __P((dev_t, int, caddr_t, int)); +extern int iplioctl __P((int, ioctlcmd_t, caddr_t, int)); # endif extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); +extern void m_freem __P((mb_t *)); #else /* #ifndef _KERNEL */ # if defined(__NetBSD__) && defined(PFIL_HOOKS) extern void ipfilterattach __P((int)); # endif -extern int iplattach __P((void)); extern int ipl_enable __P((void)); extern int ipl_disable __P((void)); -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 **)); -# if SOLARIS2 >= 7 +# ifdef MENTAT +extern int fr_check __P((struct ip *, int, void *, int, void *, + mblk_t **)); +# if SOLARIS +# if SOLARIS2 >= 7 extern int iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *)); -# else +# else extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *)); -# endif +# endif extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); +extern int iplread __P((dev_t, uio_t *, cred_t *)); +extern int iplwrite __P((dev_t, uio_t *, cred_t *)); +# endif +# ifdef __hpux +extern int iplopen __P((dev_t, int, intptr_t, int)); +extern int iplclose __P((dev_t, int, int)); +extern int iplioctl __P((dev_t, int, caddr_t, int)); +extern int iplread __P((dev_t, uio_t *)); +extern int iplwrite __P((dev_t, uio_t *)); +extern int iplselect __P((dev_t, int)); +# endif extern int ipfsync __P((void)); -extern int ipfr_fastroute __P((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 *)); -extern int iplread __P((dev_t, struct uio *, cred_t *)); -# else /* SOLARIS */ -extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +# else /* MENTAT */ +extern int fr_check __P((struct ip *, int, void *, int, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); -extern int ipfr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi # include <sys/cred.h> extern int iplioctl __P((dev_t, int, caddr_t, 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 iplread __P((dev_t, struct uio *, cred_t *)); +extern int iplread __P((dev_t, uio_t *, cred_t *)); +extern int iplwrite __P((dev_t, uio_t *, cred_t *)); extern int ipfsync __P((void)); extern int ipfilter_sgi_attach __P((void)); extern void ipfilter_sgi_detach __P((void)); @@ -572,88 +1181,188 @@ extern int iplidentify __P((char *)); (NetBSD >= 199511) || defined(__OpenBSD__) # if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || \ defined(__OpenBSD__) || (__FreeBSD_version >= 300000) +# if (__FreeBSD_version >= 500024) +# if (__FreeBSD_version >= 502116) +extern int iplioctl __P((struct cdev*, u_long, caddr_t, int, struct thread *)); +# else +extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct thread *)); +# endif /* __FreeBSD_version >= 502116 */ +# else extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +# endif /* __FreeBSD_version >= 500024 */ # else extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); # endif +# if (__FreeBSD_version >= 500024) +# if (__FreeBSD_version >= 502116) +extern int iplopen __P((struct cdev*, int, int, struct thread *)); +extern int iplclose __P((struct cdev*, int, int, struct thread *)); +# else +extern int iplopen __P((dev_t, int, int, struct thread *)); +extern int iplclose __P((dev_t, int, int, struct thread *)); +# endif /* __FreeBSD_version >= 502116 */ +# else extern int iplopen __P((dev_t, int, int, struct proc *)); extern int iplclose __P((dev_t, int, int, struct proc *)); +# endif /* __FreeBSD_version >= 500024 */ # else -# ifndef linux +# ifdef linux +extern int iplioctl __P((struct inode *, struct file *, u_int, u_long)); +# else extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); extern int iplioctl __P((dev_t, int, caddr_t, int)); -# else -extern int iplioctl(struct inode *, struct file *, u_int, u_long); -extern int iplopen __P((struct inode *, struct file *)); -extern void iplclose __P((struct inode *, struct file *)); -# endif /* !linux */ +# endif # endif /* (_BSDI_VERSION >= 199510) */ # if BSD >= 199306 +# if (__FreeBSD_version >= 502116) +extern int iplread __P((struct cdev*, struct uio *, int)); +extern int iplwrite __P((struct cdev*, struct uio *, int)); +# else extern int iplread __P((dev_t, struct uio *, int)); +extern int iplwrite __P((dev_t, struct uio *, int)); +# endif /* __FreeBSD_version >= 502116 */ # else # ifndef linux extern int iplread __P((dev_t, struct uio *)); -# else -extern int iplread(struct inode *, struct file *, char *, int); -# endif /* !linux */ +extern int iplwrite __P((dev_t, struct uio *)); +# endif # endif /* BSD >= 199306 */ # endif /* __ sgi */ -# endif /* SOLARIS */ +# endif /* MENTAT */ + #endif /* #ifndef _KERNEL */ +extern ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_hostmap; +extern ipfmutex_t ipf_timeoutlock, ipf_stinsert, ipf_natio, ipf_nat_new; +extern ipfrwlock_t ipf_mutex, ipf_global, ip_poolrw, ipf_ipidfrag; +extern ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; + 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 count4bits __P((u_32_t)); +extern int frrequest __P((int, ioctlcmd_t, caddr_t, int, int)); +extern char *getifname __P((struct ifnet *)); +extern int iplattach __P((void)); extern int ipldetach __P((void)); extern u_short ipf_cksum __P((u_short *, int)); -extern int ircopyptr __P((void *, void *, size_t)); -extern int iwcopyptr __P((void *, void *, size_t)); +extern int copyinptr __P((void *, void *, size_t)); +extern int copyoutptr __P((void *, void *, size_t)); +extern int fr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *)); +extern int fr_inobj __P((void *, void *, int)); +extern int fr_inobjsz __P((void *, void *, int, int)); +extern int fr_ioctlswitch __P((int, void *, ioctlcmd_t, int)); +extern int fr_ipftune __P((ioctlcmd_t, void *)); +extern int fr_outobj __P((void *, void *, int)); +extern int fr_outobjsz __P((void *, void *, int, int)); +extern void *fr_pullup __P((mb_t *, fr_info_t *, int)); +extern void fr_resolvedest __P((struct frdest *, int)); +extern int fr_resolvefunc __P((void *)); +extern void *fr_resolvenic __P((char *, int)); +extern int fr_send_icmp_err __P((int, fr_info_t *, int)); +extern int fr_send_reset __P((fr_info_t *)); +#if (__FreeBSD_version < 490000) || !defined(_KERNEL) +extern int ppsratecheck __P((struct timeval *, int *, int)); +#endif +extern ipftq_t *fr_addtimeoutqueue __P((ipftq_t **, u_int)); +extern void fr_deletequeueentry __P((ipftqent_t *)); +extern int fr_deletetimeoutqueue __P((ipftq_t *)); +extern void fr_freetimeoutqueue __P((ipftq_t *)); +extern void fr_movequeue __P((ipftqent_t *, ipftq_t *, ipftq_t *)); +extern void fr_queueappend __P((ipftqent_t *, ipftq_t *, void *)); +extern void fr_queueback __P((ipftqent_t *)); +extern void fr_queuefront __P((ipftqent_t *)); +extern void fr_checkv4sum __P((fr_info_t *)); +extern int fr_checkl4sum __P((fr_info_t *)); +extern int fr_ifpfillv4addr __P((int, struct sockaddr_in *, + struct sockaddr_in *, struct in_addr *, + struct in_addr *)); +extern int fr_coalesce __P((fr_info_t *)); +#ifdef USE_INET6 +extern void fr_checkv6sum __P((fr_info_t *)); +extern int fr_ifpfillv6addr __P((int, struct sockaddr_in6 *, + struct sockaddr_in6 *, struct in_addr *, + struct in_addr *)); +#endif + +extern int fr_addipftune __P((ipftuneable_t *)); +extern int fr_delipftune __P((ipftuneable_t *)); -extern void ipflog_init __P((void)); +extern int frflush __P((minor_t, int, int)); +extern void frsync __P((void *)); +extern frgroup_t *fr_addgroup __P((char *, void *, u_32_t, minor_t, int)); +extern int fr_derefrule __P((frentry_t **)); +extern void fr_delgroup __P((char *, minor_t, int)); +extern frgroup_t *fr_findgroup __P((char *, minor_t, int, frgroup_t ***)); + +extern int fr_loginit __P((void)); extern int ipflog_clear __P((minor_t)); -extern int ipflog __P((u_int, ip_t *, fr_info_t *, mb_t *)); +extern int ipflog_read __P((minor_t, uio_t *)); +extern int ipflog __P((fr_info_t *, u_int)); extern int ipllog __P((int, fr_info_t *, void **, size_t *, int *, int)); -extern int ipflog_read __P((minor_t, struct uio *)); +extern void fr_logunload __P((void)); + +extern frentry_t *fr_acctpkt __P((fr_info_t *, u_32_t *)); +extern int fr_copytolog __P((int, char *, int)); +extern u_short fr_cksum __P((mb_t *, ip_t *, int, void *)); +extern void fr_deinitialise __P((void)); +extern frentry_t *fr_dolog __P((fr_info_t *, u_32_t *)); +extern frentry_t *fr_dstgrpmap __P((fr_info_t *, u_32_t *)); +extern void fr_fixskip __P((frentry_t **, frentry_t *, int)); +extern void fr_forgetifp __P((void *)); +extern frentry_t *fr_getrulen __P((int, char *, u_32_t)); +extern void fr_getstat __P((struct friostat *)); +extern int fr_icmp4errortype __P((int)); +extern int fr_ifpaddr __P((int, int, void *, + struct in_addr *, struct in_addr *)); +extern int fr_initialise __P((void)); +extern void fr_lock __P((caddr_t, int *)); +extern int fr_makefrip __P((int, ip_t *, fr_info_t *)); +extern int fr_matchtag __P((ipftag_t *, ipftag_t *)); +extern int fr_matchicmpqueryreply __P((int, icmpinfo_t *, + struct icmp *, int)); +extern u_32_t fr_newisn __P((fr_info_t *)); +extern u_short fr_nextipid __P((fr_info_t *)); +extern int fr_rulen __P((int, frentry_t *)); +extern int fr_scanlist __P((fr_info_t *, u_32_t)); +extern frentry_t *fr_srcgrpmap __P((fr_info_t *, u_32_t *)); +extern int fr_tcpudpchk __P((fr_info_t *, frtuc_t *)); +extern int fr_verifysrc __P((fr_info_t *fin)); +extern int fr_zerostats __P((char *)); -extern int frflush __P((minor_t, int, int)); -extern void frsync __P((void)); -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 int fr_makefrip __P((int, ip_t *, fr_info_t *)); -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 u_long fr_frouteok[2]; extern int fr_pass; extern int fr_flags; extern int fr_active; extern int fr_chksrc; extern int fr_minttl; -extern int fr_minttllog; -extern fr_info_t frcache[2]; +extern int fr_refcnt; +extern int fr_control_forwarding; +extern int fr_update_ipid; +extern int nat_logging; +extern int ipstate_logging; +extern int ipl_suppress; +extern int ipl_buffer_sz; +extern int ipl_logmax; +extern int ipl_logall; +extern int ipl_logsize; +extern u_long fr_ticks; +extern fr_info_t frcache[2][8]; extern char ipfilter_version[]; extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; -extern size_t iplused[IPL_LOGMAX + 1]; +extern int iplused[IPL_LOGMAX + 1]; 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]; +extern int icmpreplytype6[ICMP6_MAXTYPE + 1]; #endif -extern struct frgroup *ipfgroups[3][2]; +extern int icmpreplytype4[ICMP_MAXTYPE + 1]; +extern struct frgroup *ipfgroups[IPL_LOGSIZE][2]; extern struct filterstats frstats[]; +extern frentry_t *ipfrule_match __P((fr_info_t *)); +extern u_char ipf_iss_secret[32]; +extern ipftuneable_t ipf_tuneables[]; #endif /* __IP_FIL_H__ */ diff --git a/contrib/ipfilter/ip_fil_freebsd.c b/contrib/ipfilter/ip_fil_freebsd.c new file mode 100644 index 0000000..3b36b93 --- /dev/null +++ b/contrib/ipfilter/ip_fil_freebsd.c @@ -0,0 +1,1692 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ip_fil_freebsd.c,v 2.53.2.25 2005/02/01 03:15:56 darrenr Exp"; +#endif + +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ + !defined(KLD_MODULE) && !defined(IPFILTER_LKM) +# include "opt_inet6.h" +#endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \ + !defined(KLD_MODULE) && !defined(IPFILTER_LKM) +# include "opt_random_ip_id.h" +#endif +#include <sys/param.h> +#if defined(__FreeBSD__) && !defined(__FreeBSD_version) +# if defined(IPFILTER_LKM) +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +# endif +#endif +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/file.h> +#if __FreeBSD_version >= 220000 +# include <sys/fcntl.h> +# include <sys/filio.h> +#else +# include <sys/ioctl.h> +#endif +#include <sys/time.h> +#include <sys/systm.h> +#if (__FreeBSD_version >= 300000) +# include <sys/dirent.h> +#else +# include <sys/dir.h> +#endif +#if !defined(__hpux) +# include <sys/mbuf.h> +#endif +#include <sys/protosw.h> +#include <sys/socket.h> + +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +# if !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif +#endif +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#if defined(__osf__) +# include <netinet/tcp_timer.h> +#endif +#include <netinet/udp.h> +#include <netinet/tcpip.h> +#include <netinet/ip_icmp.h> +#ifndef _KERNEL +# include "netinet/ipf.h" +#endif +#include "netinet/ip_compat.h" +#ifdef USE_INET6 +# include <netinet/icmp6.h> +#endif +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_auth.h" +#ifdef IPFILTER_SYNC +#include "netinet/ip_sync.h" +#endif +#ifdef IPFILTER_SCAN +#include "netinet/ip_scan.h" +#endif +#include "netinet/ip_pool.h" +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +#endif +#include <sys/kernel.h> +#ifdef CSUM_DATA_VALID +#include <machine/in_cksum.h> +#endif +extern int ip_optcopy __P((struct ip *, struct ip *)); + +#if (__FreeBSD_version > 460000) +extern int path_mtu_discovery; +#endif + +# ifdef IPFILTER_M_IPFILTER +MALLOC_DEFINE(M_IPFILTER, "IP Filter", "IP Filter packet filter data structures"); +# endif + + +#if !defined(__osf__) +extern struct protosw inetsw[]; +#endif + +static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); +static int fr_send_ip __P((fr_info_t *, mb_t *, mb_t **)); +# ifdef USE_MUTEXES +ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; +ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; +ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag; +ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; +# endif +int ipf_locks_done = 0; + +#if (__FreeBSD_version >= 300000) +struct callout_handle fr_slowtimer_ch; +#endif + +#if (__FreeBSD_version >= 500011) +# include <sys/conf.h> +# if defined(NETBSD_PF) +# include <net/pfil.h> +# include <netinet/ipprotosw.h> +/* + * We provide the fr_checkp name just to minimize changes later. + */ +int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); +# endif /* NETBSD_PF */ +#endif /* __FreeBSD_version >= 500011 */ + + +#if (__FreeBSD_version >= 501108) && defined(_KERNEL) + +static int +fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) +{ + struct ip *ip = mtod(*mp, struct ip *); + return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp); +} + +# ifdef USE_INET6 +# include <netinet/ip6.h> + +static int +fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) +{ + return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), + ifp, (dir == PFIL_OUT), mp)); +} +# endif +#endif /* __FreeBSD_version >= 501108 */ +#if defined(IPFILTER_LKM) +int iplidentify(s) +char *s; +{ + if (strcmp(s, "ipl") == 0) + return 1; + return 0; +} +#endif /* IPFILTER_LKM */ + + +int iplattach() +{ +#ifdef USE_SPL + int s; +#endif +#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) + int error = 0; +# if __FreeBSD_version >= 501108 + struct pfil_head *ph_inet; +# ifdef USE_INET6 + struct pfil_head *ph_inet6; +# endif +# endif +#endif + + SPL_NET(s); + if (fr_running > 0) { + SPL_X(s); + return EBUSY; + } + + MUTEX_INIT(&ipf_rw, "ipf rw mutex"); + RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); + MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex"); + RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); + RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); + ipf_locks_done = 1; + + if (fr_initialise() < 0) { + SPL_X(s); + return EIO; + } + + +# ifdef NETBSD_PF +# if __FreeBSD_version >= 500011 +# if __FreeBSD_version >= 501108 + ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); +# ifdef USE_INET6 + ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); +# endif + if (ph_inet == NULL +# ifdef USE_INET6 + && ph_inet6 == NULL +# endif + ) + return ENODEV; + + if (ph_inet != NULL) + error = pfil_add_hook((void *)fr_check_wrapper, NULL, + PFIL_IN|PFIL_OUT, ph_inet); + else + error = 0; +# else + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +# endif + if (error) { +# ifdef USE_INET6 + goto pfil_error; +# else + fr_deinitialise(); + SPL_X(s); + return error; +# endif + } +# else + pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 +# if __FreeBSD_version >= 501108 + if (ph_inet6 != NULL) + error = pfil_add_hook((void *)fr_check_wrapper6, NULL, + PFIL_IN|PFIL_OUT, ph_inet6); + else + error = 0; + if (error) { + pfil_remove_hook((void *)fr_check_wrapper6, NULL, + PFIL_IN|PFIL_OUT, ph_inet6); +# else + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); + if (error) { + pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +# endif +pfil_error: + fr_deinitialise(); + SPL_X(s); + return error; + } +# endif +# endif + if (fr_checkp != fr_check) { + fr_savep = fr_checkp; + fr_checkp = fr_check; + } + + bzero((char *)frcache, sizeof(frcache)); + fr_running = 1; + + if (fr_control_forwarding & 1) + ipforwarding = 1; + + SPL_X(s); +#if (__FreeBSD_version >= 300000) + fr_slowtimer_ch = timeout(fr_slowtimer, NULL, + (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); +#else + timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT); +#endif + return 0; +} + + +/* + * Disable the filter by removing the hooks from the IP input/output + * stream. + */ +int ipldetach() +{ +#ifdef USE_SPL + int s; +#endif +#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011) + int error = 0; +# if __FreeBSD_version >= 501108 + struct pfil_head *ph_inet; +# ifdef USE_INET6 + struct pfil_head *ph_inet6; +# endif +# endif +#endif + + if (fr_control_forwarding & 2) + ipforwarding = 0; + + SPL_NET(s); + +#if (__FreeBSD_version >= 300000) + if (fr_slowtimer_ch.callout != NULL) + untimeout(fr_slowtimer, NULL, fr_slowtimer_ch); + bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch)); +#else + untimeout(fr_slowtimer, NULL); +#endif /* FreeBSD */ + +#ifndef NETBSD_PF + if (fr_checkp != NULL) + fr_checkp = fr_savep; + fr_savep = NULL; +#endif + +#ifdef NETBSD_PF +# if (__FreeBSD_version >= 500011) +# if (__FreeBSD_version >= 501108) + ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); + if (ph_inet != NULL) + error = pfil_remove_hook((void *)fr_check_wrapper, NULL, + PFIL_IN|PFIL_OUT, ph_inet); + else + error = 0; +# else + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +# endif + if (error) { + SPL_X(s); + return error; + } +# else + pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 +# if (__FreeBSD_version >= 501108) + ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); + if (ph_inet6 != NULL) + error = pfil_remove_hook((void *)fr_check_wrapper6, NULL, + PFIL_IN|PFIL_OUT, ph_inet6); + else + error = 0; +# else + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); +# endif + if (error) { + SPL_X(s); + return error; + } +# endif +#endif + fr_deinitialise(); + + fr_running = -2; + + (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); + (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); + + if (ipf_locks_done == 1) { + MUTEX_DESTROY(&ipf_timeoutlock); + MUTEX_DESTROY(&ipf_rw); + RW_DESTROY(&ipf_mutex); + RW_DESTROY(&ipf_ipidfrag); + RW_DESTROY(&ipf_global); + ipf_locks_done = 0; + } + + SPL_X(s); + + return 0; +} + + +/* + * Filter ioctl interface. + */ +int iplioctl(dev, cmd, data, mode +# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000)) +, p) +# if (__FreeBSD_version >= 500024) +struct thread *p; +# else +struct proc *p; +# endif /* __FreeBSD_version >= 500024 */ +# else +) +# endif +#if defined(_KERNEL) && (__FreeBSD_version >= 502116) +struct cdev *dev; +#else +dev_t dev; +#endif +ioctlcmd_t cmd; +caddr_t data; +int mode; +{ +#ifdef USE_SPL + int s; +#endif + int error = 0, unit = 0, tmp; + friostat_t fio; + +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel >= 2) && (mode & FWRITE)) + return EPERM; +#endif + + unit = GET_MINOR(dev); + if ((IPL_LOGMAX < unit) || (unit < 0)) + return ENXIO; + + if (fr_running <= 0) { + if (unit != IPL_LOGIPF) + return EIO; + if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && + cmd != SIOCIPFSET && cmd != SIOCFRENB && + cmd != SIOCGETFS && cmd != SIOCGETFF) + return EIO; + } + + SPL_NET(s); + + error = fr_ioctlswitch(unit, data, cmd, mode); + if (error != -1) { + SPL_X(s); + return error; + } + error = 0; + + switch (cmd) + { + case FIONREAD : +#ifdef IPFILTER_LOG + BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data, + sizeof(iplused[IPL_LOGIPF])); +#endif + break; + case SIOCFRENB : + if (!(mode & FWRITE)) + error = EPERM; + else { + BCOPYIN(data, &tmp, sizeof(tmp)); + if (tmp) { + if (fr_running > 0) + error = 0; + else + error = iplattach(); + if (error == 0) + fr_running = 1; + else + (void) ipldetach(); + } else { + error = ipldetach(); + if (error == 0) + fr_running = -1; + } + } + break; + case SIOCIPFSET : + if (!(mode & FWRITE)) { + error = EPERM; + break; + } + case SIOCIPFGETNEXT : + case SIOCIPFGET : + error = fr_ipftune(cmd, data); + break; + case SIOCSETFF : + if (!(mode & FWRITE)) + error = EPERM; + else + BCOPYIN(data, &fr_flags, sizeof(fr_flags)); + break; + case SIOCGETFF : + BCOPYOUT(&fr_flags, data, sizeof(fr_flags)); + break; + case SIOCFUNCL : + error = fr_resolvefunc(data); + break; + case SIOCINAFR : + case SIOCRMAFR : + case SIOCADAFR : + case SIOCZRLST : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frrequest(unit, cmd, data, fr_active, 1); + break; + case SIOCINIFR : + case SIOCRMIFR : + case SIOCADIFR : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frrequest(unit, cmd, data, 1 - fr_active, 1); + break; + case SIOCSWAPA : + if (!(mode & FWRITE)) + error = EPERM; + else { + bzero((char *)frcache, sizeof(frcache[0]) * 2); + *(u_int *)data = fr_active; + fr_active = 1 - fr_active; + } + break; + case SIOCGETFS : + fr_getstat(&fio); + error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); + break; + case SIOCFRZST : + if (!(mode & FWRITE)) + error = EPERM; + else + error = fr_zerostats(data); + break; + case SIOCIPFFL : + if (!(mode & FWRITE)) + error = EPERM; + else { + BCOPYIN(data, &tmp, sizeof(tmp)); + tmp = frflush(unit, 4, tmp); + BCOPYOUT(&tmp, data, sizeof(tmp)); + } + break; +#ifdef USE_INET6 + case SIOCIPFL6 : + if (!(mode & FWRITE)) + error = EPERM; + else { + BCOPYIN(data, &tmp, sizeof(tmp)); + tmp = frflush(unit, 6, tmp); + BCOPYOUT(&tmp, data, sizeof(tmp)); + } + break; +#endif + case SIOCSTLCK : + BCOPYIN(data, &tmp, sizeof(tmp)); + fr_state_lock = tmp; + fr_nat_lock = tmp; + fr_frag_lock = tmp; + fr_auth_lock = tmp; + break; +#ifdef IPFILTER_LOG + case SIOCIPFFB : + if (!(mode & FWRITE)) + error = EPERM; + else + *(int *)data = ipflog_clear(unit); + break; +#endif /* IPFILTER_LOG */ + case SIOCGFRST : + error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT); + break; + case SIOCFRSYN : + if (!(mode & FWRITE)) + error = EPERM; + else { + frsync(NULL); + } + break; + default : + error = EINVAL; + break; + } + SPL_X(s); + return error; +} + + +#if 0 +void fr_forgetifp(ifp) +void *ifp; +{ + register frentry_t *f; + + WRITE_ENTER(&ipf_mutex); + for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + 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); + fr_natsync(ifp); +} +#endif + + +/* + * routines below for saving IP headers to buffer + */ +int iplopen(dev, flags +#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) +, devtype, p) +int devtype; +# if (__FreeBSD_version >= 500024) +struct thread *p; +# else +struct proc *p; +# endif /* __FreeBSD_version >= 500024 */ +#else +) +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 502116) +struct cdev *dev; +#else +dev_t dev; +#endif +int flags; +{ + u_int min = GET_MINOR(dev); + + if (IPL_LOGMAX < min) + min = ENXIO; + else + min = 0; + return min; +} + + +int iplclose(dev, flags +#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL) +, devtype, p) +int devtype; +# if (__FreeBSD_version >= 500024) +struct thread *p; +# else +struct proc *p; +# endif /* __FreeBSD_version >= 500024 */ +#else +) +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 502116) +struct cdev *dev; +#else +dev_t dev; +#endif +int flags; +{ + u_int min = GET_MINOR(dev); + + if (IPL_LOGMAX < min) + min = ENXIO; + else + min = 0; + return min; +} + +/* + * iplread/ipllog + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +#if (BSD >= 199306) +int iplread(dev, uio, ioflag) +int ioflag; +#else +int iplread(dev, uio) +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 502116) +struct cdev *dev; +#else +dev_t dev; +#endif +register struct uio *uio; +{ + +# ifdef IPFILTER_SYNC + if (GET_MINOR(dev) == IPL_LOGSYNC) + return ipfsync_read(uio); +# endif + +#ifdef IPFILTER_LOG + return ipflog_read(GET_MINOR(dev), uio); +#else + return ENXIO; +#endif +} + + +/* + * iplwrite + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +#if (BSD >= 199306) +int iplwrite(dev, uio, ioflag) +int ioflag; +#else +int iplwrite(dev, uio) +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 502116) +struct cdev *dev; +#else +dev_t dev; +#endif +register struct uio *uio; +{ + +#ifdef IPFILTER_SYNC + if (GET_MINOR(dev) == IPL_LOGSYNC) + return ipfsync_write(uio); +#endif + return ENXIO; +} + + +/* + * fr_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 fr_send_reset(fin) +fr_info_t *fin; +{ + struct tcphdr *tcp, *tcp2; + int tlen = 0, hlen; + struct mbuf *m; +#ifdef USE_INET6 + ip6_t *ip6; +#endif + ip_t *ip; + + tcp = fin->fin_dp; + if (tcp->th_flags & TH_RST) + return -1; /* feedback loop */ + +#ifndef IPFILTER_CKSUM + if (fr_checkl4sum(fin) == -1) + return -1; +#endif + + tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + +#ifdef USE_INET6 + hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); +#else + hlen = sizeof(ip_t); +#endif +#ifdef MGETHDR + MGETHDR(m, M_DONTWAIT, MT_HEADER); +#else + MGET(m, M_DONTWAIT, MT_HEADER); +#endif + if (m == NULL) + return -1; + if (sizeof(*tcp2) + hlen > MLEN) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + FREE_MB_T(m); + return -1; + } + } + + m->m_len = sizeof(*tcp2) + hlen; +#if (BSD >= 199103) + m->m_data += max_linkhdr; + m->m_pkthdr.len = m->m_len; + m->m_pkthdr.rcvif = (struct ifnet *)0; +#endif + ip = mtod(m, struct ip *); + bzero((char *)ip, hlen); +#ifdef USE_INET6 + ip6 = (ip6_t *)ip; +#endif + tcp2 = (struct tcphdr *)((char *)ip + hlen); + tcp2->th_sport = tcp->th_dport; + tcp2->th_dport = tcp->th_sport; + + if (tcp->th_flags & TH_ACK) { + tcp2->th_seq = tcp->th_ack; + tcp2->th_flags = TH_RST; + tcp2->th_ack = 0; + } else { + tcp2->th_seq = 0; + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_flags = TH_RST|TH_ACK; + } + TCP_X2_A(tcp2, 0); + TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); + tcp2->th_win = tcp->th_win; + tcp2->th_sum = 0; + tcp2->th_urp = 0; + +#ifdef USE_INET6 + if (fin->fin_v == 6) { + ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; + ip6->ip6_plen = htons(sizeof(struct tcphdr)); + ip6->ip6_nxt = IPPROTO_TCP; + ip6->ip6_hlim = 0; + ip6->ip6_src = fin->fin_dst6; + ip6->ip6_dst = fin->fin_src6; + tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, + sizeof(*ip6), sizeof(*tcp2)); + return fr_send_ip(fin, m, &m); + } +#endif + ip->ip_p = IPPROTO_TCP; + ip->ip_len = htons(sizeof(struct tcphdr)); + ip->ip_src.s_addr = fin->fin_daddr; + ip->ip_dst.s_addr = fin->fin_saddr; + tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); + ip->ip_len = hlen + sizeof(*tcp2); + return fr_send_ip(fin, m, &m); +} + + +static int fr_send_ip(fin, m, mpp) +fr_info_t *fin; +mb_t *m, **mpp; +{ + fr_info_t fnew; + ip_t *ip, *oip; + int hlen; + + ip = mtod(m, ip_t *); + bzero((char *)&fnew, sizeof(fnew)); + + IP_V_A(ip, fin->fin_v); + switch (fin->fin_v) + { + case 4 : + fnew.fin_v = 4; + oip = fin->fin_ip; + IP_HL_A(ip, sizeof(*oip) >> 2); + ip->ip_tos = oip->ip_tos; + ip->ip_id = fin->fin_ip->ip_id; +#if (__FreeBSD_version > 460000) + ip->ip_off = path_mtu_discovery ? IP_DF : 0; +#else + ip->ip_off = 0; +#endif + ip->ip_ttl = ip_defttl; + ip->ip_sum = 0; + hlen = sizeof(*oip); + break; +#ifdef USE_INET6 + case 6 : + { + ip6_t *ip6 = (ip6_t *)ip; + + ip6->ip6_vfc = 0x60; + ip6->ip6_hlim = IPDEFTTL; + + fnew.fin_v = 6; + hlen = sizeof(*ip6); + break; + } +#endif + default : + return EINVAL; + } +#ifdef IPSEC + m->m_pkthdr.rcvif = NULL; +#endif + + fnew.fin_ifp = fin->fin_ifp; + fnew.fin_flx = FI_NOCKSUM; + fnew.fin_m = m; + fnew.fin_ip = ip; + fnew.fin_mp = mpp; + fnew.fin_hlen = hlen; + fnew.fin_dp = (char *)ip + hlen; + (void) fr_makefrip(hlen, ip, &fnew); + + return fr_fastroute(m, mpp, &fnew, NULL); +} + + +int fr_send_icmp_err(type, fin, dst) +int type; +fr_info_t *fin; +int dst; +{ + int err, hlen, xtra, iclen, ohlen, avail, code; + struct in_addr dst4; + struct icmp *icmp; + struct mbuf *m; + void *ifp; +#ifdef USE_INET6 + ip6_t *ip6; + struct in6_addr dst6; +#endif + ip_t *ip, *ip2; + + 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 + +#ifndef IPFILTER_CKSUM + if (fr_checkl4sum(fin) == -1) + return -1; +#endif +#ifdef MGETHDR + MGETHDR(m, M_DONTWAIT, MT_HEADER); +#else + MGET(m, M_DONTWAIT, MT_HEADER); +#endif + if (m == NULL) + return -1; + avail = MHLEN; + + xtra = 0; + hlen = 0; + ohlen = 0; + ifp = fin->fin_ifp; + if (fin->fin_v == 4) { + if ((fin->fin_p == IPPROTO_ICMP) && + !(fin->fin_flx & FI_SHORT)) + switch (ntohs(fin->fin_data[0]) >> 8) + { + case ICMP_ECHO : + case ICMP_TSTAMP : + case ICMP_IREQ : + case ICMP_MASKREQ : + break; + default : + FREE_MB_T(m); + return 0; + } + + if (dst == 0) { + if (fr_ifpaddr(4, FRI_NORMAL, ifp, + &dst4, NULL) == -1) { + FREE_MB_T(m); + return -1; + } + } else + dst4.s_addr = fin->fin_daddr; + + hlen = sizeof(ip_t); + ohlen = fin->fin_hlen; + if (fin->fin_hlen < fin->fin_plen) + xtra = MIN(fin->fin_dlen, 8); + else + xtra = 0; + } + +#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]; + + if (hlen + sizeof(*icmp) + max_linkhdr + + fin->fin_plen > avail) { + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + FREE_MB_T(m); + return -1; + } + avail = MCLBYTES; + } + xtra = MIN(fin->fin_plen, + avail - hlen - sizeof(*icmp) - max_linkhdr); + if (dst == 0) { + if (fr_ifpaddr(6, FRI_NORMAL, ifp, + (struct in_addr *)&dst6, NULL) == -1) { + FREE_MB_T(m); + return -1; + } + } else + dst6 = fin->fin_dst6; + } +#endif + else { + FREE_MB_T(m); + return -1; + } + + iclen = hlen + sizeof(*icmp); + avail -= (max_linkhdr + iclen); + if (avail < 0) { + FREE_MB_T(m); + return -1; + } + if (xtra > avail) + xtra = avail; + iclen += xtra; + m->m_data += max_linkhdr; + m->m_pkthdr.rcvif = (struct ifnet *)0; + m->m_pkthdr.len = iclen; + m->m_len = iclen; + ip = mtod(m, ip_t *); + icmp = (struct icmp *)((char *)ip + hlen); + ip2 = (ip_t *)&icmp->icmp_ip; + + icmp->icmp_type = type; + icmp->icmp_code = fin->fin_icode; + icmp->icmp_cksum = 0; +#ifdef icmp_nextmtu + if (type == ICMP_UNREACH && + fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) + icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu); +#endif + + bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); + +#ifdef USE_INET6 + ip6 = (ip6_t *)ip; + if (fin->fin_v == 6) { + ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; + ip6->ip6_plen = htons(iclen - hlen); + ip6->ip6_nxt = IPPROTO_ICMPV6; + ip6->ip6_hlim = 0; + ip6->ip6_src = dst6; + ip6->ip6_dst = fin->fin_src6; + if (xtra > 0) + bcopy((char *)fin->fin_ip + ohlen, + (char *)&icmp->icmp_ip + ohlen, xtra); + icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, + sizeof(*ip6), iclen - hlen); + } else +#endif + { + ip2->ip_len = htons(ip2->ip_len); + ip2->ip_off = htons(ip2->ip_off); + ip->ip_p = IPPROTO_ICMP; + ip->ip_src.s_addr = dst4.s_addr; + ip->ip_dst.s_addr = fin->fin_saddr; + + if (xtra > 0) + bcopy((char *)fin->fin_ip + ohlen, + (char *)&icmp->icmp_ip + ohlen, xtra); + icmp->icmp_cksum = ipf_cksum((u_short *)icmp, + sizeof(*icmp) + 8); + ip->ip_len = iclen; + ip->ip_p = IPPROTO_ICMP; + } + err = fr_send_ip(fin, m, &m); + return err; +} + + +#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) +# if (BSD < 199306) +int iplinit __P((void)); + +int +# else +void iplinit __P((void)); + +void +# endif +iplinit() +{ + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); + ip_init(); +} +#endif /* __FreeBSD_version < 300000 */ + + +int fr_fastroute(m0, mpp, fin, fdp) +mb_t *m0, **mpp; +fr_info_t *fin; +frdest_t *fdp; +{ + register struct ip *ip, *mhip; + register struct mbuf *m = m0; + register struct route *ro; + int len, off, error = 0, hlen, code; + struct ifnet *ifp, *sifp; + struct sockaddr_in *dst; + struct route iproute; + u_short ip_off; + frentry_t *fr; + +#ifdef M_WRITABLE + /* + * HOT FIX/KLUDGE: + * + * If the mbuf we're about to send is not writable (because of + * a cluster reference, for example) we'll need to make a copy + * of it since this routine modifies the contents. + * + * If you have non-crappy network hardware that can transmit data + * from the mbuf, rather than making a copy, this is gonna be a + * problem. + */ + if (M_WRITABLE(m) == 0) { + if ((m0 = m_dup(m, M_DONTWAIT)) != 0) { + FREE_MB_T(m); + m = m0; + *mpp = m; + } else { + error = ENOBUFS; + FREE_MB_T(m); + *mpp = NULL; + fr_frouteok[1]++; + } + } +#endif + +#ifdef USE_INET6 + if (fin->fin_v == 6) { + /* + * currently "to <if>" and "to <if>:ip#" are not supported + * for IPv6 + */ +#if (__FreeBSD_version >= 490000) + return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); +#else + return ip6_output(m0, NULL, NULL, 0, NULL, NULL); +#endif + } +#endif + + hlen = fin->fin_hlen; + ip = mtod(m0, struct ip *); + + /* + * Route packet. + */ + ro = &iproute; + bzero((caddr_t)ro, sizeof (*ro)); + dst = (struct sockaddr_in *)&ro->ro_dst; + dst->sin_family = AF_INET; + dst->sin_addr = ip->ip_dst; + + fr = fin->fin_fr; + if (fdp != NULL) + ifp = fdp->fd_ifp; + else + ifp = fin->fin_ifp; + + if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) { + error = -2; + goto bad; + } + + /* + * In case we're here due to "to <if>" being used with "keep state", + * check that we're going in the correct direction. + */ + if ((fr != NULL) && (fin->fin_rev != 0)) { + if ((ifp != NULL) && (fdp == &fr->fr_tif)) + return -1; + } + if (fdp != NULL) { + if (fdp->fd_ip.s_addr != 0) + dst->sin_addr = fdp->fd_ip; + } + + dst->sin_len = sizeof(*dst); + rtalloc(ro); + + if ((ifp == NULL) && (ro->ro_rt != NULL)) + ifp = ro->ro_rt->rt_ifp; + + if ((ro->ro_rt == NULL) || (ifp == NULL)) { + if (in_localaddr(ip->ip_dst)) + error = EHOSTUNREACH; + else + error = ENETUNREACH; + goto bad; + } + if (ro->ro_rt->rt_flags & RTF_GATEWAY) + dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; + if (ro->ro_rt) + ro->ro_rt->rt_use++; + + /* + * For input packets which are being "fastrouted", they won't + * go back through output filtering and miss their chance to get + * NAT'd and counted. + */ + if (fin->fin_out == 0) { + sifp = fin->fin_ifp; + fin->fin_ifp = ifp; + fin->fin_out = 1; + (void) fr_acctpkt(fin, NULL); + fin->fin_fr = NULL; + if (!fr || !(fr->fr_flags & FR_RETMASK)) { + u_32_t pass; + + (void) fr_checkstate(fin, &pass); + } + + switch (fr_checknatout(fin, NULL)) + { + case 0 : + break; + case 1 : + ip->ip_sum = 0; + break; + case -1 : + error = -1; + goto done; + break; + } + + fin->fin_ifp = sifp; + fin->fin_out = 0; + } else + ip->ip_sum = 0; + /* + * If small enough for interface, can just send directly. + */ + if (ip->ip_len <= ifp->if_mtu) { + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + + if (!ip->ip_sum) + ip->ip_sum = in_cksum(m, hlen); + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, + ro->ro_rt); + goto done; + } + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + ip_off = ntohs(ip->ip_off); + if (ip_off & IP_DF) { + error = EMSGSIZE; + goto bad; + } + len = (ifp->if_mtu - hlen) &~ 7; + if (len < 8) { + error = EMSGSIZE; + goto bad; + } + + { + int mhlen, firstlen = len; + struct mbuf **mnext = &m->m_act; + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof (struct ip); + for (off = hlen + len; off < ip->ip_len; off += len) { +#ifdef MGETHDR + MGETHDR(m, M_DONTWAIT, MT_HEADER); +#else + MGET(m, M_DONTWAIT, MT_HEADER); +#endif + if (m == 0) { + m = m0; + error = ENOBUFS; + goto bad; + } + m->m_data += max_linkhdr; + mhip = mtod(m, struct ip *); + bcopy((char *)ip, (char *)mhip, sizeof(*ip)); + if (hlen > sizeof (struct ip)) { + mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + IP_HL_A(mhip, mhlen >> 2); + } + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + ip_off; + if (off + len >= ip->ip_len) + len = ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_short)(len + mhlen)); + m->m_next = m_copy(m0, off, len); + if (m->m_next == 0) { + error = ENOBUFS; /* ??? */ + goto sendorfree; + } + m->m_pkthdr.len = mhlen + len; + m->m_pkthdr.rcvif = NULL; + mhip->ip_off = htons((u_short)mhip->ip_off); + mhip->ip_sum = 0; + mhip->ip_sum = in_cksum(m, mhlen); + *mnext = m; + mnext = &m->m_act; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m_adj(m0, hlen + firstlen - ip->ip_len); + ip->ip_len = htons((u_short)(hlen + firstlen)); + ip->ip_off = htons((u_short)IP_MF); + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m0, hlen); +sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_act; + m->m_act = 0; + if (error == 0) + error = (*ifp->if_output)(ifp, m, + (struct sockaddr *)dst, ro->ro_rt); + else + FREE_MB_T(m); + } + } +done: + if (!error) + fr_frouteok[0]++; + else + fr_frouteok[1]++; + + if (ro->ro_rt) { + RTFREE(ro->ro_rt); + } + *mpp = NULL; + return 0; +bad: + if (error == EMSGSIZE) { + sifp = fin->fin_ifp; + code = fin->fin_icode; + fin->fin_icode = ICMP_UNREACH_NEEDFRAG; + fin->fin_ifp = ifp; + (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1); + fin->fin_ifp = sifp; + fin->fin_icode = code; + } + FREE_MB_T(m); + goto done; +} + + +int fr_verifysrc(fin) +fr_info_t *fin; +{ + struct sockaddr_in *dst; + struct route iproute; + + bzero((char *)&iproute, sizeof(iproute)); + dst = (struct sockaddr_in *)&iproute.ro_dst; + dst->sin_len = sizeof(*dst); + dst->sin_family = AF_INET; + dst->sin_addr = fin->fin_src; + rtalloc(&iproute); + if (iproute.ro_rt == NULL) + return 0; + return (fin->fin_ifp == iproute.ro_rt->rt_ifp); +} + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(v, atype, ifptr, inp, inpmask) +int v, atype; +void *ifptr; +struct in_addr *inp, *inpmask; +{ +#ifdef USE_INET6 + struct in6_addr *inp6 = NULL; +#endif + struct sockaddr *sock, *mask; + struct sockaddr_in *sin; + struct ifaddr *ifa; + struct ifnet *ifp; + + if ((ifptr == NULL) || (ifptr == (void *)-1)) + return -1; + + sin = NULL; + ifp = ifptr; + + if (v == 4) + inp->s_addr = 0; +#ifdef USE_INET6 + else if (v == 6) + bzero((char *)inp, sizeof(struct in6_addr)); +#endif +#if (__FreeBSD_version >= 300000) + ifa = TAILQ_FIRST(&ifp->if_addrhead); +#else + ifa = ifp->if_addrlist; +#endif /* __FreeBSD_version >= 300000 */ + + sock = ifa->ifa_addr; + while (sock != NULL && ifa != NULL) { + sin = (struct sockaddr_in *)sock; + 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 + ifa = ifa->ifa_next; +#endif /* __FreeBSD_version >= 300000 */ + if (ifa != NULL) + sock = ifa->ifa_addr; + } + + if (ifa == NULL || sin == NULL) + return -1; + + mask = ifa->ifa_netmask; + if (atype == FRI_BROADCAST) + sock = ifa->ifa_broadaddr; + else if (atype == FRI_PEERADDR) + sock = ifa->ifa_dstaddr; + +#ifdef USE_INET6 + if (v == 6) { + return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock, + (struct sockaddr_in6 *)mask, + inp, inpmask); + } +#endif + return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock, + (struct sockaddr_in *)mask, inp, inpmask); +} + + +u_32_t fr_newisn(fin) +fr_info_t *fin; +{ + u_32_t newiss; +#if (__FreeBSD_version >= 400000) + newiss = arc4random(); +#else + static iss_seq_off = 0; + u_char hash[16]; + MD5_CTX ctx; + + /* + * Compute the base value of the ISS. It is a hash + * of (saddr, sport, daddr, dport, secret). + */ + MD5Init(&ctx); + + MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, + sizeof(fin->fin_fi.fi_src)); + MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, + sizeof(fin->fin_fi.fi_dst)); + MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); + + MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); + + MD5Final(hash, &ctx); + + memcpy(&newiss, hash, sizeof(newiss)); + + /* + * Now increment our "timer", and add it in to + * the computed value. + * + * XXX Use `addin'? + * XXX TCP_ISSINCR too large to use? + */ + iss_seq_off += 0x00010000; + newiss += iss_seq_off; +#endif + return newiss; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_nextipid */ +/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Returns the next IPv4 ID to use for this packet. */ +/* ------------------------------------------------------------------------ */ +u_short fr_nextipid(fin) +fr_info_t *fin; +{ +#ifndef RANDOM_IP_ID + static u_short ipid = 0; + u_short id; + + MUTEX_ENTER(&ipf_rw); + id = ipid++; + MUTEX_EXIT(&ipf_rw); +#else + u_short id; + + id = ip_randomid(); +#endif + + return id; +} + + +INLINE void fr_checkv4sum(fin) +fr_info_t *fin; +{ +#ifdef CSUM_DATA_VALID + int manual = 0; + u_short sum; + ip_t *ip; + mb_t *m; + + if ((fin->fin_flx & FI_NOCKSUM) != 0) + return; + + m = fin->fin_m; + if (m == NULL) { + manual = 1; + goto skipauto; + } + ip = fin->fin_ip; + + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) { + if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) + sum = m->m_pkthdr.csum_data; + else + sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htonl(m->m_pkthdr.csum_data + + fin->fin_ip->ip_len + fin->fin_p)); + sum ^= 0xffff; + if (sum != 0) + fin->fin_flx |= FI_BAD; + } else + manual = 1; +skipauto: +# ifdef IPFILTER_CKSUM + if (manual != 0) + if (fr_checkl4sum(fin) == -1) + fin->fin_flx |= FI_BAD; +# else + ; +# endif +#else +# ifdef IPFILTER_CKSUM + if (fr_checkl4sum(fin) == -1) + fin->fin_flx |= FI_BAD; +# endif +#endif +} + + +#ifdef USE_INET6 +INLINE void fr_checkv6sum(fin) +fr_info_t *fin; +{ +# ifdef IPFILTER_CKSUM + if (fr_checkl4sum(fin) == -1) + fin->fin_flx |= FI_BAD; +# endif +} +#endif /* USE_INET6 */ + + +size_t mbufchainlen(m0) +struct mbuf *m0; +{ + size_t len; + + if ((m0->m_flags & M_PKTHDR) != 0) { + len = m0->m_pkthdr.len; + } else { + struct mbuf *m; + + for (m = m0, len = 0; m != NULL; m = m->m_next) + len += m->m_len; + } + return len; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_pullup */ +/* Returns: NULL == pullup failed, else pointer to protocol header */ +/* Parameters: m(I) - pointer to buffer where data packet starts */ +/* fin(I) - pointer to packet information */ +/* len(I) - number of bytes to pullup */ +/* */ +/* Attempt to move at least len bytes (from the start of the buffer) into a */ +/* single buffer for ease of access. Operating system native functions are */ +/* used to manage buffers - if necessary. If the entire packet ends up in */ +/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ +/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ +/* and ONLY if the pullup succeeds. */ +/* */ +/* We assume that 'min' is a pointer to a buffer that is part of the chain */ +/* of buffers that starts at *fin->fin_mp. */ +/* ------------------------------------------------------------------------ */ +void *fr_pullup(min, fin, len) +mb_t *min; +fr_info_t *fin; +int len; +{ + int out = fin->fin_out, dpoff, ipoff; + mb_t *m = min; + char *ip; + + if (m == NULL) + return NULL; + + ip = (char *)fin->fin_ip; + if ((fin->fin_flx & FI_COALESCE) != 0) + return ip; + + ipoff = fin->fin_ipoff; + if (fin->fin_dp != NULL) + dpoff = (char *)fin->fin_dp - (char *)ip; + else + dpoff = 0; + + if (M_LEN(m) < len) { +#ifdef MHLEN + /* + * Assume that M_PKTHDR is set and just work with what is left + * rather than check.. + * Should not make any real difference, anyway. + */ + if (len > MHLEN) +#else + if (len > MLEN) +#endif + { +#ifdef HAVE_M_PULLDOWN + if (m_pulldown(m, 0, len, NULL) == NULL) + m = NULL; +#else + FREE_MB_T(*fin->fin_mp); + m = NULL; +#endif + } else + { + m = m_pullup(m, len); + } + *fin->fin_mp = m; + fin->fin_m = m; + if (m == NULL) { + ATOMIC_INCL(frstats[out].fr_pull[1]); + return NULL; + } + ip = MTOD(m, char *) + ipoff; + } + + ATOMIC_INCL(frstats[out].fr_pull[0]); + fin->fin_ip = (ip_t *)ip; + if (fin->fin_dp != NULL) + fin->fin_dp = (char *)fin->fin_ip + dpoff; + + if (len == fin->fin_plen) + fin->fin_flx |= FI_COALESCE; + return ip; +} diff --git a/contrib/ipfilter/ip_frag.c b/contrib/ipfilter/ip_frag.c index 73f98c4..087ca19 100644 --- a/contrib/ipfilter/ip_frag.c +++ b/contrib/ipfilter/ip_frag.c @@ -1,45 +1,55 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif - -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include <sys/errno.h> #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> #include <sys/file.h> -#if !defined(_KERNEL) && !defined(KERNEL) +#ifdef __hpux +# include <sys/timeout.h> +#endif +#if !defined(_KERNEL) # include <stdio.h> # include <string.h> # include <stdlib.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> #else # include <sys/ioctl.h> #endif -#ifndef linux +#if !defined(linux) # include <sys/protosw.h> #endif #include <sys/socket.h> -#if defined(_KERNEL) && !defined(linux) +#if defined(_KERNEL) # include <sys/systm.h> +# if !defined(__SVR4) && !defined(__svr4__) +# include <sys/mbuf.h> +# endif #endif #if !defined(__SVR4) && !defined(__svr4__) # if defined(_KERNEL) && !defined(__sgi) # include <sys/kernel.h> # endif -# ifndef linux -# include <sys/mbuf.h> -# endif #else # include <sys/byteorder.h> # ifdef _KERNEL @@ -56,7 +66,7 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#ifndef linux +#if !defined(linux) # include <netinet/ip_var.h> #endif #include <netinet/tcp.h> @@ -69,63 +79,129 @@ #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_auth.h" +#include "netinet/ip_proxy.h" #if (__FreeBSD_version >= 300000) # include <sys/malloc.h> -# if (defined(KERNEL) || defined(_KERNEL)) +# if defined(_KERNEL) # ifndef IPFILTER_LKM # include <sys/libkern.h> # include <sys/systm.h> # endif -extern struct callout_handle ipfr_slowtimer_ch; +extern struct callout_handle fr_slowtimer_ch; # endif #endif #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) # include <sys/callout.h> -extern struct callout ipfr_slowtimer_ch; +extern struct callout fr_slowtimer_ch; #endif #if defined(__OpenBSD__) # include <sys/timeout.h> -extern struct timeout ipfr_slowtimer_ch; +extern struct timeout fr_slowtimer_ch; #endif +/* END OF INCLUDES */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.28 2003/06/11 22:28:15 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77 2004/01/27 00:24:54 darrenr Exp"; #endif -static ipfr_t *ipfr_heads[IPFT_SIZE]; -static ipfr_t *ipfr_nattab[IPFT_SIZE]; +static ipfr_t *ipfr_list = NULL; +static ipfr_t **ipfr_tail = &ipfr_list; +static ipfr_t **ipfr_heads; + +static ipfr_t *ipfr_natlist = NULL; +static ipfr_t **ipfr_nattail = &ipfr_natlist; +static ipfr_t **ipfr_nattab; + +static ipfr_t *ipfr_ipidlist = NULL; +static ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; +static ipfr_t **ipfr_ipidtab; + static ipfrstat_t ipfr_stats; static int ipfr_inuse = 0; +int ipfr_size = IPFT_SIZE; int fr_ipfrttl = 120; /* 60 seconds */ int fr_frag_lock = 0; +int fr_frag_init = 0; +u_long fr_ticks = 0; -#ifdef _KERNEL -# if SOLARIS2 >= 7 -extern timeout_id_t ipfr_timer_id; -# else -extern int ipfr_timer_id; -# endif -#endif -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat, ipf_mutex; -# if SOLARIS -extern KRWLOCK_T ipf_solaris; -# else -KRWLOCK_T ipf_solaris; -# endif -extern kmutex_t ipf_rw; -#endif +static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); +static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); +static void fr_fragdelete __P((ipfr_t *, ipfr_t ***)); + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fraginit */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: Nil */ +/* */ +/* Initialise the hash tables for the fragment cache lookups. */ +/* ------------------------------------------------------------------------ */ +int fr_fraginit() +{ + KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); + if (ipfr_heads == NULL) + return -1; + bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *)); + + KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); + if (ipfr_nattab == NULL) + return -1; + bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); + + KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); + if (ipfr_ipidtab == NULL) + return -1; + bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); + + RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock"); + fr_frag_init = 1; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Free all memory allocated whilst running and from initialisation. */ +/* ------------------------------------------------------------------------ */ +void fr_fragunload() +{ + if (fr_frag_init == 1) { + fr_fragclear(); + + RW_DESTROY(&ipf_frag); + fr_frag_init = 0; + } + + if (ipfr_heads != NULL) + KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *)); + ipfr_heads = NULL; + + if (ipfr_nattab != NULL) + KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); + ipfr_nattab = NULL; -static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, ipfr_t **)); -static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **)); -static void ipfr_delete __P((ipfr_t *)); + if (ipfr_ipidtab != NULL) + KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); + ipfr_ipidtab = NULL; +} -ipfrstat_t *ipfr_fragstats() +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragstats */ +/* Returns: ipfrstat_t* - pointer to struct with current frag stats */ +/* Parameters: Nil */ +/* */ +/* Updates ipfr_stats with current information and returns a pointer to it */ +/* ------------------------------------------------------------------------ */ +ipfrstat_t *fr_fragstats() { ipfr_stats.ifs_table = ipfr_heads; ipfr_stats.ifs_nattab = ipfr_nattab; @@ -134,24 +210,36 @@ ipfrstat_t *ipfr_fragstats() } -/* - * add a new entry to the fragment cache, registering it as having come - * through this box, with the result of the filter operation. - */ -static ipfr_t *ipfr_new(ip, fin, table) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: ipfr_newfrag */ +/* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* table(I) - pointer to frag table to add to */ +/* */ +/* Add a new entry to the fragment cache, registering it as having come */ +/* through this box, with the result of the filter operation. */ +/* ------------------------------------------------------------------------ */ +static ipfr_t *ipfr_newfrag(fin, pass, table) fr_info_t *fin; +u_32_t pass; ipfr_t *table[]; { - ipfr_t **fp, *fra, frag; + ipfr_t *fra, frag; u_int idx, off; + ip_t *ip; if (ipfr_inuse >= IPFT_SIZE) return NULL; - if (!(fin->fin_fl & FI_FRAG)) + if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) return NULL; + ip = fin->fin_ip; + + if (pass & FR_FRSTRICT) + if ((ip->ip_off & IP_OFFMASK) != 0) + return NULL; + frag.ipfr_p = ip->ip_p; idx = ip->ip_p; frag.ipfr_id = ip->ip_id; @@ -172,10 +260,10 @@ ipfr_t *table[]; /* * first, make sure it isn't already there... */ - for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next) - if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, + for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) + if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ)) { - ATOMIC_INCL(ipfr_stats.ifs_exists); + ipfr_stats.ifs_exists++; return NULL; } @@ -185,105 +273,165 @@ ipfr_t *table[]; */ KMALLOC(fra, ipfr_t *); if (fra == NULL) { - ATOMIC_INCL(ipfr_stats.ifs_nomem); + ipfr_stats.ifs_nomem++; return NULL; } - if ((fra->ipfr_rule = fin->fin_fr) != NULL) { - ATOMIC_INC32(fin->fin_fr->fr_ref); - } - + if ((fra->ipfr_rule = fin->fin_fr) != NULL) + fin->fin_fr->fr_ref++; /* * Insert the fragment into the fragment table, copy the struct used * in the search using bcopy rather than reassign each field. * Set the ttl to the default. */ - if ((fra->ipfr_next = table[idx])) - table[idx]->ipfr_prev = fra; - fra->ipfr_prev = NULL; + if ((fra->ipfr_hnext = table[idx]) != NULL) + table[idx]->ipfr_hprev = &fra->ipfr_hnext; + fra->ipfr_hprev = table + idx; fra->ipfr_data = NULL; table[idx] = fra; - bcopy((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ); - fra->ipfr_ttl = fr_ipfrttl; + bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); + fra->ipfr_ttl = fr_ticks + fr_ipfrttl; + /* * Compute the offset of the expected start of the next packet. */ off = ip->ip_off & IP_OFFMASK; - if (!off) + if (off == 0) fra->ipfr_seen0 = 1; fra->ipfr_off = off + (fin->fin_dlen >> 3); - ATOMIC_INCL(ipfr_stats.ifs_new); - ATOMIC_INC32(ipfr_inuse); + fra->ipfr_pass = pass; + ipfr_stats.ifs_new++; + ipfr_inuse++; return fra; } -int ipfr_newfrag(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_newfrag */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Add a new entry to the fragment cache table based on the current packet */ +/* ------------------------------------------------------------------------ */ +int fr_newfrag(fin, pass) +u_32_t pass; fr_info_t *fin; { - ipfr_t *ipf; + ipfr_t *fra; - if ((ip->ip_v != 4) || (fr_frag_lock)) + if ((fin->fin_v != 4) || (fr_frag_lock != 0)) return -1; + WRITE_ENTER(&ipf_frag); - ipf = ipfr_new(ip, fin, ipfr_heads); - RWLOCK_EXIT(&ipf_frag); - if (ipf == NULL) { - ATOMIC_INCL(frstats[fin->fin_out].fr_bnfr); - return -1; + fra = ipfr_newfrag(fin, pass, ipfr_heads); + if (fra != NULL) { + *ipfr_tail = fra; + fra->ipfr_prev = ipfr_tail; + ipfr_tail = &fra->ipfr_next; + if (ipfr_list == NULL) + ipfr_list = fra; + fra->ipfr_next = NULL; } - ATOMIC_INCL(frstats[fin->fin_out].fr_nfr); - return 0; + RWLOCK_EXIT(&ipf_frag); + return fra ? 0 : -1; } -int ipfr_nat_newfrag(ip, fin, nat) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_nat_newfrag */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* */ +/* Create a new NAT fragment cache entry based on the current packet and */ +/* the NAT structure for this "session". */ +/* ------------------------------------------------------------------------ */ +int fr_nat_newfrag(fin, pass, nat) fr_info_t *fin; +u_32_t pass; nat_t *nat; { - ipfr_t *ipf; - int off; + ipfr_t *fra; - if ((ip->ip_v != 4) || (fr_frag_lock)) - return -1; - - off = fin->fin_off; - off <<= 3; - if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) - return -1; + if ((fin->fin_v != 4) || (fr_frag_lock != 0)) + return 0; WRITE_ENTER(&ipf_natfrag); - ipf = ipfr_new(ip, fin, ipfr_nattab); - if (ipf != NULL) { - ipf->ipfr_data = nat; - nat->nat_data = ipf; + fra = ipfr_newfrag(fin, pass, ipfr_nattab); + if (fra != NULL) { + fra->ipfr_data = nat; + nat->nat_data = fra; + *ipfr_nattail = fra; + fra->ipfr_prev = ipfr_nattail; + ipfr_nattail = &fra->ipfr_next; + fra->ipfr_next = NULL; } RWLOCK_EXIT(&ipf_natfrag); - return ipf ? 0 : -1; + return fra ? 0 : -1; } -/* - * check the fragment cache to see if there is already a record of this packet - * with its filter result known. - */ -static ipfr_t *ipfr_lookup(ip, fin, table) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipid_newfrag */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: fin(I) - pointer to packet information */ +/* ipid(I) - new IP ID for this fragmented packet */ +/* */ +/* Create a new fragment cache entry for this packet and store, as a data */ +/* pointer, the new IP ID value. */ +/* ------------------------------------------------------------------------ */ +int fr_ipid_newfrag(fin, ipid) +fr_info_t *fin; +u_32_t ipid; +{ + ipfr_t *fra; + + if ((fin->fin_v != 4) || (fr_frag_lock)) + return 0; + + WRITE_ENTER(&ipf_ipidfrag); + fra = ipfr_newfrag(fin, 0, ipfr_ipidtab); + if (fra != NULL) { + fra->ipfr_data = (void *)ipid; + *ipfr_ipidtail = fra; + fra->ipfr_prev = ipfr_ipidtail; + ipfr_ipidtail = &fra->ipfr_next; + fra->ipfr_next = NULL; + } + RWLOCK_EXIT(&ipf_ipidfrag); + return fra ? 0 : -1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fraglookup */ +/* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ +/* matching entry in the frag table, else NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* table(I) - pointer to fragment cache table to search */ +/* */ +/* Check the fragment cache to see if there is already a record of this */ +/* packet with its filter result known. */ +/* ------------------------------------------------------------------------ */ +static ipfr_t *fr_fraglookup(fin, table) fr_info_t *fin; ipfr_t *table[]; { - ipfr_t *f, frag; + ipfr_t *f, frag; u_int idx; - + ip_t *ip; + + if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) + return NULL; + /* * For fragments, we record protocol, packet id, TOS and both IP#'s * (these should all be the same for all fragments of a packet). * * build up a hash value to index the table with. */ + ip = fin->fin_ip; frag.ipfr_p = ip->ip_p; idx = ip->ip_p; frag.ipfr_id = ip->ip_id; @@ -304,48 +452,71 @@ ipfr_t *table[]; /* * check the table, careful to only compare the right amount of data */ - for (f = table[idx]; f; f = f->ipfr_next) - if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src, + for (f = table[idx]; f; f = f->ipfr_hnext) + if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, IPFR_CMPSZ)) { - u_short atoff, off; + u_short off; - off = fin->fin_off; + /* + * We don't want to let short packets match because + * they could be compromising the security of other + * rules that want to match on layer 4 fields (and + * can't because they have been fragmented off.) + * Why do this check here? The counter acts as an + * indicator of this kind of attack, whereas if it was + * elsewhere, it wouldn't know if other matching + * packets had been seen. + */ + if (fin->fin_flx & FI_SHORT) { + ATOMIC_INCL(ipfr_stats.ifs_short); + continue; + } /* * XXX - We really need to be guarding against the * retransmission of (src,dst,id,offset-range) here * because a fragmented packet is never resent with - * the same IP ID#. + * the same IP ID# (or shouldn't). */ + off = ip->ip_off & IP_OFFMASK; if (f->ipfr_seen0) { - if (!off || (fin->fin_fl & FI_SHORT)) + if (off == 0) { + ATOMIC_INCL(ipfr_stats.ifs_retrans0); continue; - } else if (!off) + } + } else if (off == 0) f->ipfr_seen0 = 1; if (f != table[idx]) { + ipfr_t **fp; + + /* + * Move fragment info. to the top of the list + * to speed up searches. First, delink... + */ + fp = f->ipfr_hprev; + (*fp) = f->ipfr_hnext; + if (f->ipfr_hnext != NULL) + f->ipfr_hnext->ipfr_hprev = fp; /* - * move fragment info. to the top of the list - * to speed up searches. + * Then put back at the top of the chain. */ - if ((f->ipfr_prev->ipfr_next = f->ipfr_next)) - f->ipfr_next->ipfr_prev = f->ipfr_prev; - f->ipfr_next = table[idx]; - table[idx]->ipfr_prev = f; - f->ipfr_prev = NULL; + f->ipfr_hnext = table[idx]; + table[idx]->ipfr_hprev = &f->ipfr_hnext; + f->ipfr_hprev = table + idx; table[idx] = f; } - atoff = off + (fin->fin_dlen >> 3); + /* * If we've follwed the fragments, and this is the * last (in order), shrink expiration time. */ if (off == f->ipfr_off) { if (!(ip->ip_off & IP_MF)) - f->ipfr_ttl = 1; - else - f->ipfr_off = atoff; - } + f->ipfr_ttl = fr_ticks + 1; + f->ipfr_off = (fin->fin_dlen >> 3) + off; + } else if (f->ipfr_pass & FR_FRSTRICT) + continue; ATOMIC_INCL(ipfr_stats.ifs_hits); return f; } @@ -353,33 +524,30 @@ ipfr_t *table[]; } -/* - * functional interface for NAT lookups of the NAT fragment cache - */ -nat_t *ipfr_nat_knownfrag(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_nat_knownfrag */ +/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ +/* match found, else NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Functional interface for NAT lookups of the NAT fragment cache */ +/* ------------------------------------------------------------------------ */ +nat_t *fr_nat_knownfrag(fin) fr_info_t *fin; { - ipfr_t *ipf; - nat_t *nat; - int off; - - if ((fin->fin_v != 4) || (fr_frag_lock)) - return NULL; + nat_t *nat; + ipfr_t *ipf; - off = fin->fin_off; - off <<= 3; - if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) + if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist) return NULL; - READ_ENTER(&ipf_natfrag); - ipf = ipfr_lookup(ip, fin, ipfr_nattab); + ipf = fr_fraglookup(fin, ipfr_nattab); if (ipf != NULL) { nat = ipf->ipfr_data; /* * This is the last fragment for this packet. */ - if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) { nat->nat_data = NULL; ipf->ipfr_data = NULL; } @@ -390,136 +558,196 @@ fr_info_t *fin; } -/* - * functional interface for normal lookups of the fragment cache - */ -frentry_t *ipfr_knownfrag(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipid_knownfrag */ +/* Returns: u_32_t - IPv4 ID for this packet if match found, else */ +/* return 0xfffffff to indicate no match. */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Functional interface for IP ID lookups of the IP ID fragment cache */ +/* ------------------------------------------------------------------------ */ +u_32_t fr_ipid_knownfrag(fin) fr_info_t *fin; { - frentry_t *fr; - ipfr_t *fra; - int off; + ipfr_t *ipf; + u_32_t id; - if ((fin->fin_v != 4) || (fr_frag_lock)) - return NULL; + if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist) + return 0xffffffff; + + READ_ENTER(&ipf_ipidfrag); + ipf = fr_fraglookup(fin, ipfr_ipidtab); + if (ipf != NULL) + id = (u_32_t)ipf->ipfr_data; + else + id = 0xffffffff; + RWLOCK_EXIT(&ipf_ipidfrag); + return id; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_knownfrag */ +/* Returns: frentry_t* - pointer to filter rule if a match is found in */ +/* the frag cache table, else NULL. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(O) - pointer to where to store rule flags resturned */ +/* */ +/* Functional interface for normal lookups of the fragment cache. If a */ +/* match is found, return the rule pointer and flags from the rule, except */ +/* that if FR_LOGFIRST is set, reset FR_LOG. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_knownfrag(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + frentry_t *fr = NULL; + ipfr_t *fra; + u_32_t pass; - off = fin->fin_off; - off <<= 3; - if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) + if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL)) return NULL; READ_ENTER(&ipf_frag); - fra = ipfr_lookup(ip, fin, ipfr_heads); - if (fra != NULL) + fra = fr_fraglookup(fin, ipfr_heads); + if (fra != NULL) { fr = fra->ipfr_rule; - else - fr = NULL; + fin->fin_fr = fr; + if (fr != NULL) { + pass = fr->fr_flags; + if ((pass & FR_LOGFIRST) != 0) + pass &= ~(FR_LOGFIRST|FR_LOG); + *passp = pass; + } + } RWLOCK_EXIT(&ipf_frag); return fr; } -/* - * forget any references to this external object. - */ -void ipfr_forget(ptr) +/* ------------------------------------------------------------------------ */ +/* Function: fr_forget */ +/* Returns: Nil */ +/* Parameters: ptr(I) - pointer to data structure */ +/* */ +/* Search through all of the fragment cache entries and wherever a pointer */ +/* is found to match ptr, reset it to NULL. */ +/* ------------------------------------------------------------------------ */ +void fr_forget(ptr) void *ptr; { ipfr_t *fr; - int idx; WRITE_ENTER(&ipf_frag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next) - if (fr->ipfr_data == ptr) - fr->ipfr_data = NULL; - + for (fr = ipfr_list; fr; fr = fr->ipfr_next) + if (fr->ipfr_data == ptr) + fr->ipfr_data = NULL; RWLOCK_EXIT(&ipf_frag); } -/* - * forget any references to this external object. - */ -void ipfr_forgetnat(nat) -void *nat; +/* ------------------------------------------------------------------------ */ +/* Function: fr_forgetnat */ +/* Returns: Nil */ +/* Parameters: ptr(I) - pointer to data structure */ +/* */ +/* Search through all of the fragment cache entries for NAT and wherever a */ +/* pointer is found to match ptr, reset it to NULL. */ +/* ------------------------------------------------------------------------ */ +void fr_forgetnat(ptr) +void *ptr; { ipfr_t *fr; - int idx; WRITE_ENTER(&ipf_natfrag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fr = ipfr_nattab[idx]; fr; fr = fr->ipfr_next) - if (fr->ipfr_data == nat) - fr->ipfr_data = NULL; - + for (fr = ipfr_natlist; fr; fr = fr->ipfr_next) + if (fr->ipfr_data == ptr) + fr->ipfr_data = NULL; RWLOCK_EXIT(&ipf_natfrag); } -static void ipfr_delete(fra) -ipfr_t *fra; +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragdelete */ +/* Returns: Nil */ +/* Parameters: fra(I) - pointer to fragment structure to delete */ +/* tail(IO) - pointer to the pointer to the tail of the frag */ +/* list */ +/* */ +/* Remove a fragment cache table entry from the table & list. Also free */ +/* the filter rule it is associated with it if it is no longer used as a */ +/* result of decreasing the reference count. */ +/* ------------------------------------------------------------------------ */ +static void fr_fragdelete(fra, tail) +ipfr_t *fra, ***tail; { frentry_t *fr; fr = fra->ipfr_rule; - if (fr != NULL) { - ATOMIC_DEC32(fr->fr_ref); - if (fr->fr_ref == 0) - KFREE(fr); - } - if (fra->ipfr_prev) - fra->ipfr_prev->ipfr_next = fra->ipfr_next; + if (fr != NULL) + (void)fr_derefrule(&fr); + if (fra->ipfr_next) fra->ipfr_next->ipfr_prev = fra->ipfr_prev; + *fra->ipfr_prev = fra->ipfr_next; + if (*tail == &fra->ipfr_next) + *tail = fra->ipfr_prev; + + if (fra->ipfr_hnext) + fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; + *fra->ipfr_hprev = fra->ipfr_hnext; KFREE(fra); } -/* - * Free memory in use by fragment state info. kept. - */ -void ipfr_unload() +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragclear */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Free memory in use by fragment state information kept. Do the normal */ +/* fragment state stuff first and then the NAT-fragment table. */ +/* ------------------------------------------------------------------------ */ +void fr_fragclear() { - ipfr_t **fp, *fra; + ipfr_t *fra; nat_t *nat; - int idx; WRITE_ENTER(&ipf_frag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fra = *fp); ) { - *fp = fra->ipfr_next; - ipfr_delete(fra); - } + while ((fra = ipfr_list) != NULL) + fr_fragdelete(fra, &ipfr_tail); + ipfr_tail = &ipfr_list; RWLOCK_EXIT(&ipf_frag); WRITE_ENTER(&ipf_nat); WRITE_ENTER(&ipf_natfrag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { - *fp = fra->ipfr_next; - nat = fra->ipfr_data; - if (nat != NULL) { - if (nat->nat_data == fra) - nat->nat_data = NULL; - } - ipfr_delete(fra); + while ((fra = ipfr_natlist) != NULL) { + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; } + fr_fragdelete(fra, &ipfr_nattail); + } + ipfr_nattail = &ipfr_natlist; RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); } -void ipfr_fragexpire() +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragexpire */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Expire entries in the fragment cache table that have been there too long */ +/* ------------------------------------------------------------------------ */ +void fr_fragexpire() { ipfr_t **fp, *fra; nat_t *nat; - int idx; -#if defined(_KERNEL) -# if !SOLARIS +#if defined(USE_SPL) && defined(_KERNEL) int s; -# endif #endif if (fr_frag_lock) @@ -527,25 +755,29 @@ void ipfr_fragexpire() SPL_NET(s); WRITE_ENTER(&ipf_frag); - /* * Go through the entire table, looking for entries to expire, - * decreasing the ttl by one for each entry. If it reaches 0, - * remove it from the chain and free it. + * which is indicated by the ttl being less than or equal to fr_ticks. */ - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fra = *fp); ) { - --fra->ipfr_ttl; - if (fra->ipfr_ttl == 0) { - *fp = fra->ipfr_next; - ipfr_delete(fra); - ATOMIC_INCL(ipfr_stats.ifs_expire); - ATOMIC_DEC32(ipfr_inuse); - } else - fp = &fra->ipfr_next; - } + for (fp = &ipfr_list; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + fr_fragdelete(fra, &ipfr_tail); + ipfr_stats.ifs_expire++; + ipfr_inuse--; + } RWLOCK_EXIT(&ipf_frag); + WRITE_ENTER(&ipf_ipidfrag); + for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + fr_fragdelete(fra, &ipfr_ipidtail); + ipfr_stats.ifs_expire++; + ipfr_inuse--; + } + RWLOCK_EXIT(&ipf_ipidfrag); + /* * Same again for the NAT table, except that if the structure also * still points to a NAT structure, and the NAT structure points back @@ -555,83 +787,72 @@ void ipfr_fragexpire() */ WRITE_ENTER(&ipf_nat); WRITE_ENTER(&ipf_natfrag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { - --fra->ipfr_ttl; - if (fra->ipfr_ttl == 0) { - ATOMIC_INCL(ipfr_stats.ifs_expire); - ATOMIC_DEC32(ipfr_inuse); - nat = fra->ipfr_data; - if (nat != NULL) { - if (nat->nat_data == fra) - nat->nat_data = NULL; - } - *fp = fra->ipfr_next; - ipfr_delete(fra); - } else - fp = &fra->ipfr_next; + for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; } + fr_fragdelete(fra, &ipfr_nattail); + ipfr_stats.ifs_expire++; + ipfr_inuse--; + } 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. - */ -#ifdef _KERNEL -# if (BSD >= 199306) || SOLARIS || defined(__sgi) -# if defined(SOLARIS2) && (SOLARIS2 < 7) -void ipfr_slowtimer() -# else -void ipfr_slowtimer __P((void *ptr)) -# endif +/* ------------------------------------------------------------------------ */ +/* Function: fr_slowtimer */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Slowly expire held state for fragments. Timeouts are set * in */ +/* expectation of this being called twice per second. */ +/* ------------------------------------------------------------------------ */ +#if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ + !defined(__osf__)) +# if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) +void fr_slowtimer __P((void *ptr)) # else -int ipfr_slowtimer() +int fr_slowtimer() # endif -#else -void ipfr_slowtimer() -#endif { -#if defined(_KERNEL) && SOLARIS - extern int fr_running; - - if (fr_running <= 0) - return; - READ_ENTER(&ipf_solaris); -#endif + READ_ENTER(&ipf_global); -#if defined(__sgi) && defined(_KERNEL) - ipfilter_sgi_intfsync(); -#endif - - ipfr_fragexpire(); + fr_fragexpire(); fr_timeoutstate(); - ip_natexpire(); + fr_natexpire(); fr_authexpire(); -#if defined(_KERNEL) -# if SOLARIS - ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); - RWLOCK_EXIT(&ipf_solaris); -# else + fr_ticks++; + if (fr_running <= 0) + goto done; +# ifdef _KERNEL # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) - callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); + callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); # else -# if (__FreeBSD_version >= 300000) - ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# if defined(__OpenBSD__) + timeout_add(&fr_slowtimer_ch, hz/2); # else -# if defined(__OpenBSD__) - timeout_add(&ipfr_slowtimer_ch, hz/2); +# if (__FreeBSD_version >= 300000) + fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); # else - timeout(ipfr_slowtimer, NULL, hz/2); -# endif -# endif -# if (BSD < 199306) && !defined(__sgi) - return 0; -# endif /* FreeBSD */ +# ifdef linux + ; +# else + timeout(fr_slowtimer, NULL, hz/2); +# endif +# endif /* FreeBSD */ +# endif /* OpenBSD */ # endif /* NetBSD */ -# endif /* SOLARIS */ -#endif /* defined(_KERNEL) */ +# endif +done: + RWLOCK_EXIT(&ipf_global); +# if (BSD < 199103) || !defined(_KERNEL) + return 0; +# endif } +#endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ diff --git a/contrib/ipfilter/ip_frag.h b/contrib/ipfilter/ip_frag.h index 925f285..786a088 100644 --- a/contrib/ipfilter/ip_frag.h +++ b/contrib/ipfilter/ip_frag.h @@ -1,10 +1,12 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.4.2.8 2003/06/11 22:28:16 darrenr Exp $ + * Id: ip_frag.h,v 2.23.2.1 2004/03/29 16:21:56 darrenr Exp */ #ifndef __IP_FRAG_H__ @@ -13,17 +15,19 @@ #define IPFT_SIZE 257 typedef struct ipfr { - struct ipfr *ipfr_next, *ipfr_prev; + struct ipfr *ipfr_hnext, **ipfr_hprev; + struct ipfr *ipfr_next, **ipfr_prev; void *ipfr_data; + void *ipfr_ifp; struct in_addr ipfr_src; struct in_addr ipfr_dst; - void *ipfr_ifp; u_32_t ipfr_optmsk; u_short ipfr_secmsk; u_short ipfr_auth; u_short ipfr_id; u_char ipfr_p; u_char ipfr_tos; + u_32_t ipfr_pass; u_short ipfr_off; u_char ipfr_ttl; u_char ipfr_seen0; @@ -38,37 +42,45 @@ typedef struct ipfrstat { u_long ifs_hits; u_long ifs_expire; u_long ifs_inuse; + u_long ifs_retrans0; + u_long ifs_short; struct ipfr **ifs_table; struct ipfr **ifs_nattab; } ipfrstat_t; -#define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_off) - \ - offsetof(ipfr_t, ipfr_src)) +#define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_pass) - \ + offsetof(ipfr_t, ipfr_ifp)) +extern int ipfr_size; 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 *)); -extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, struct nat *)); -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_forgetnat __P((void *)); -extern void ipfr_unload __P((void)); -extern void ipfr_fragexpire __P((void)); +extern int fr_fraginit __P((void)); +extern void fr_fragunload __P((void)); +extern ipfrstat_t *fr_fragstats __P((void)); + +extern int fr_newfrag __P((fr_info_t *, u_32_t)); +extern frentry_t *fr_knownfrag __P((fr_info_t *, u_32_t *)); + +extern int fr_nat_newfrag __P((fr_info_t *, u_32_t, struct nat *)); +extern nat_t *fr_nat_knownfrag __P((fr_info_t *)); + +extern int fr_ipid_newfrag __P((fr_info_t *, u_32_t)); +extern u_32_t fr_ipid_knownfrag __P((fr_info_t *)); + +extern void fr_forget __P((void *)); +extern void fr_forgetnat __P((void *)); +extern void fr_fragclear __P((void)); +extern void fr_fragexpire __P((void)); -#ifdef _KERNEL -# if (BSD >= 199306) || SOLARIS || defined(__sgi) -# if defined(SOLARIS2) && (SOLARIS2 < 7) -extern void ipfr_slowtimer __P((void)); -# else -extern void ipfr_slowtimer __P((void *)); -# endif +#if defined(_KERNEL) && ((BSD >= 199306) || SOLARIS || defined(__sgi) \ + || defined(__osf__) || (defined(__sgi) && (IRIX >= 60500))) +# if defined(SOLARIS2) && (SOLARIS2 < 7) +extern void fr_slowtimer __P((void)); # else -extern int ipfr_slowtimer __P((void)); -# endif /* (BSD >= 199306) || SOLARIS */ +extern void fr_slowtimer __P((void *)); +# endif #else -extern void ipfr_slowtimer __P((void)); -#endif /* _KERNEL */ +extern int fr_slowtimer __P((void)); +#endif -#endif /* __IP_FIL_H__ */ +#endif /* __IP_FRAG_H__ */ diff --git a/contrib/ipfilter/ip_ftp_pxy.c b/contrib/ipfilter/ip_ftp_pxy.c index ae158de..5bdc18a 100644 --- a/contrib/ipfilter/ip_ftp_pxy.c +++ b/contrib/ipfilter/ip_ftp_pxy.c @@ -1,18 +1,15 @@ +/* $NetBSD$ */ + /* + * Copyright (C) 1997-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.47 2004/06/21 11:48:07 darrenr Exp $ + * Id: ip_ftp_pxy.c,v 2.88.2.15 2005/03/19 19:38:10 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') && ((unsigned)(x) <= 'Z')) -#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) -#define isalpha(x) (isupper(x) || islower(x)) -#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') #define IPF_FTP_PROXY @@ -20,7 +17,8 @@ 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! */ +#define IPF_MIN229LEN 47 +#define IPF_MAX229LEN 51 #define FTPXY_GO 0 #define FTPXY_INIT 1 @@ -46,23 +44,53 @@ extern kmutex_t ipf_rw; 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_in __P((fr_info_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 *)); +void ippr_ftp_fini __P((void)); +int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *)); int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_epsv __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_process __P((fr_info_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((ftpinfo_t *, int, char *, size_t)); int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t)); int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t)); u_short ippr_ftp_atoi __P((char **)); +int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, + u_int, char *, char *, u_int)); -static frentry_t ftppxyfr; + +int ftp_proxy_init = 0; int ippr_ftp_pasvonly = 0; -int ippr_ftp_insecure = 0; -int ippr_ftp_forcepasv = 0; +int ippr_ftp_insecure = 0; /* Do not require logins before transfers */ +int ippr_ftp_pasvrdr = 0; +int ippr_ftp_forcepasv = 0; /* PASV must be last command prior to 227 */ +#if defined(_KERNEL) +int ippr_ftp_debug = 0; +#else +int ippr_ftp_debug = 2; +#endif +/* + * 1 - security + * 2 - errors + * 3 - error debugging + * 4 - parsing errors + * 5 - parsing info + * 6 - parsing debug + */ + +static frentry_t ftppxyfr; +static ipftuneable_t ftptune = { + { &ippr_ftp_debug }, + "ippr_ftp_debug", + 0, + 10, + sizeof(ippr_ftp_debug), + 0, + NULL +}; /* @@ -73,13 +101,27 @@ int ippr_ftp_init() bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); ftppxyfr.fr_ref = 1; ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex"); + ftp_proxy_init = 1; + (void) fr_addipftune(&ftptune); + return 0; } -int ippr_ftp_new(fin, ip, aps, nat) +void ippr_ftp_fini() +{ + (void) fr_delipftune(&ftptune); + + if (ftp_proxy_init == 1) { + MUTEX_DESTROY(&ftppxyfr.fr_lock); + ftp_proxy_init = 0; + } +} + + +int ippr_ftp_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { @@ -89,6 +131,10 @@ nat_t *nat; KMALLOC(ftp, ftpinfo_t *); if (ftp == NULL) return -1; + + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_data = ftp; aps->aps_psiz = sizeof(ftpinfo_t); @@ -100,6 +146,7 @@ nat_t *nat; f->ftps_rptr = f->ftps_buf; f->ftps_wptr = f->ftps_buf; ftp->ftp_passok = FTPXY_INIT; + ftp->ftp_incok = 0; return 0; } @@ -113,30 +160,28 @@ int dlen; { tcphdr_t *tcp, tcph, *tcp2 = &tcph; char newbuf[IPF_FTPBUFSZ], *s; + struct in_addr swip, swip2; u_int a1, a2, a3, a4; - struct in_addr swip; + int inc, off, flags; u_short a5, a6, sp; size_t nlen, olen; fr_info_t fi; - int inc, off; - nat_t *ipn; + nat_t *nat2; mb_t *m; -#if SOLARIS && defined(_KERNEL) - mb_t *m1; -#endif + m = fin->fin_m; tcp = (tcphdr_t *)fin->fin_dp; + off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; + /* * Check for client sending out PORT message. */ if (dlen < IPF_MINPORTLEN) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", dlen); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", + dlen); return 0; } - off = fin->fin_hlen + (tcp->th_off << 2); /* * Skip the PORT command + space */ @@ -146,36 +191,36 @@ int dlen; */ a1 = ippr_ftp_atoi(&s); if (s == NULL) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(1) failed\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1); return 0; } a2 = ippr_ftp_atoi(&s); if (s == NULL) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(2) failed\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2); return 0; } + /* - * check that IP address in the PORT/PASV reply is the same as the + * Check that IP address in the PORT/PASV reply is the same as the * sender of the command - prevents using PORT for port scanning. */ a1 <<= 16; a1 |= a2; - if (a1 != ntohl(nat->nat_inip.s_addr)) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_port:a1 != nat->nat_inip\n"); -#endif - return 0; + if (((nat->nat_dir == NAT_OUTBOUND) && + (a1 != ntohl(nat->nat_inip.s_addr))) || + ((nat->nat_dir == NAT_INBOUND) && + (a1 != ntohl(nat->nat_oip.s_addr)))) { + if (ippr_ftp_debug > 0) + printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1"); + return APR_ERR(1); } a5 = ippr_ftp_atoi(&s); if (s == NULL) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(3) failed\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3); return 0; } if (*s == ')') @@ -190,26 +235,39 @@ int dlen; s += 2; a6 = a5 & 0xff; } else { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_port:missing cr-lf\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_port:missing %s\n", "cr-lf"); return 0; } + a5 >>= 8; a5 &= 0xff; + sp = a5 << 8 | a6; + /* + * Don't allow the PORT command to specify a port < 1024 due to + * security crap. + */ + if (sp < 1024) { + if (ippr_ftp_debug > 0) + printf("ippr_ftp_port:sp(%d) < 1024\n", sp); + return 0; + } /* * Calculate new address parts for PORT command */ - a1 = ntohl(ip->ip_src.s_addr); + if (nat->nat_dir == NAT_INBOUND) + a1 = ntohl(nat->nat_oip.s_addr); + else + a1 = ntohl(ip->ip_src.s_addr); a2 = (a1 >> 16) & 0xff; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; olen = s - f->ftps_rptr; /* DO NOT change this to snprintf! */ -#if defined(OpenBSD) && (200311 >= 200311) - (void) snprintf(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", - "PORT", a1, a2, a3, a4, a5, a6); +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", + "PORT", a1, a2, a3, a4, a5, a6); #else (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "PORT", a1, a2, a3, a4, a5, a6); @@ -218,87 +276,34 @@ int dlen; nlen = strlen(newbuf); inc = nlen - olen; if ((inc + ip->ip_len) > 65535) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", inc); -#endif + if (ippr_ftp_debug > 0) + printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", + inc); return 0; } #if !defined(_KERNEL) - m = *fin->fin_mp; - bcopy(newbuf, (char *)m + off, nlen); + bcopy(newbuf, MTOD(m, char *) + off, nlen); #else -# 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)) { - mblk_t *nm; - - /* alloc enough to keep same trailer space for lower driver */ - nm = allocb(nlen, BPRI_MED); - PANIC((!nm),("ippr_ftp_out: allocb failed")); - - nm->b_band = m1->b_band; - nm->b_wptr += nlen; - - m1->b_wptr -= olen; - PANIC((m1->b_wptr < m1->b_rptr), - ("ippr_ftp_out: cannot handle fragmented data block")); - - linkb(m1, nm); - } else { - if (m1->b_datap->db_struiolim == m1->b_wptr) - m1->b_datap->db_struiolim += inc; - m1->b_datap->db_struioflag &= ~STRUIO_IP; - m1->b_wptr += inc; - } - copyin_mblk(m, off, nlen, newbuf); -# else - m = *fin->fin_mp; +# if defined(MENTAT) + if (inc < 0) + (void)adjmsg(m, inc); +# else /* defined(MENTAT) */ + /* + * m_adj takes care of pkthdr.len, if required and treats inc<0 to + * mean remove -len bytes from the end of the packet. + * The mbuf chain will be extended if necessary by m_copyback(). + */ if (inc < 0) m_adj(m, inc); - /* the mbuf chain will be extended if necessary by m_copyback() */ - m_copyback(m, off, nlen, newbuf); -# ifdef M_PKTHDR - if (!(m->m_flags & M_PKTHDR)) - m->m_pkthdr.len += inc; -# endif -# endif -#endif - if (inc != 0) { -#if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL) - register u_32_t sum1, sum2; - - sum1 = ip->ip_len; - sum2 = ip->ip_len + inc; +# endif /* defined(MENTAT) */ +#endif /* !defined(_KERNEL) */ + COPYBACK(m, off, nlen, newbuf); - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sum2 -= sum1; - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - fix_outcksum(fin, &ip->ip_sum, sum2); -#endif + if (inc != 0) { ip->ip_len += inc; - } - - /* - * Add skeleton NAT entry for connection which will come back the - * other way. - */ - sp = (a5 << 8 | a6); - /* - * Don't allow the PORT command to specify a port < 1024 due to - * security crap. - */ - if (sp < 1024) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_port:sp(%d) < 1024\n", sp); -#endif - return 0; + fin->fin_dlen += inc; + fin->fin_plen += inc; } /* @@ -307,11 +312,22 @@ int dlen; * mapping. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_flx |= FI_IGNORE; fi.fin_data[0] = sp; fi.fin_data[1] = fin->fin_data[1] - 1; - ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, 0); - if (ipn == NULL) { + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + if (nat->nat_dir == NAT_OUTBOUND) + nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + else + nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + if (nat2 == NULL) { int slen; slen = ip->ip_len; @@ -319,28 +335,61 @@ int dlen; bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = htons(sp); - tcp2->th_off = 5; + TCP_OFF_A(tcp2, 5); tcp2->th_flags = TH_SYN; tcp2->th_dport = 0; /* XXX - don't specify remote port */ fi.fin_data[1] = 0; fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); fi.fin_dp = (char *)tcp2; fi.fin_fr = &ftppxyfr; - fi.fin_out = 1; + fi.fin_out = nat->nat_dir; + fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; swip = ip->ip_src; - fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; - ip->ip_src = nat->nat_inip; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_W_DPORT|FI_IGNOREPKT); + swip2 = ip->ip_dst; + if (nat->nat_dir == NAT_OUTBOUND) { + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; + ip->ip_src = nat->nat_inip; + } else if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; + ip->ip_src = nat->nat_oip; + } + + flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; + if (nat->nat_dir == NAT_INBOUND) + flags |= NAT_NOTRULEPORT; + nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir); + + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_TCP); + nat_update(&fi, nat2, nat->nat_ptr); + fi.fin_ifp = NULL; + if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; + ip->ip_dst = nat->nat_inip; + } + (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); } ip->ip_len = slen; ip->ip_src = swip; + ip->ip_dst = swip2; + } else { + ipstate_t *is; + + nat_update(&fi, nat2, nat->nat_ptr); + READ_ENTER(&ipf_state); + is = nat2->nat_state; + if (is != NULL) { + MUTEX_ENTER(&is->is_lock); + (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, + is->is_flags); + MUTEX_EXIT(&is->is_lock); + } + RWLOCK_EXIT(&ipf_state); } - return inc; + return APR_INC(inc); } @@ -362,8 +411,8 @@ int dlen; for (i = 0; (i < 5) && (i < dlen); i++) { c = rptr[i]; - if (isalpha(c)) { - cmd[i] = toupper(c); + if (ISALPHA(c)) { + cmd[i] = TOUPPER(c); } else { cmd[i] = c; } @@ -422,23 +471,17 @@ nat_t *nat; ftpinfo_t *ftp; int dlen; { - tcphdr_t *tcp, tcph, *tcp2 = &tcph; - struct in_addr swip, swip2; - u_int a1, a2, a3, a4; - u_short a5, a6, dp; - fr_info_t fi; + u_int a1, a2, a3, a4, data_ip; + char newbuf[IPF_FTPBUFSZ]; + char *s, *brackets[2]; + u_short a5, a6; ftpside_t *f; - nat_t *ipn; - int inc; - char *s; if (ippr_ftp_forcepasv != 0 && ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n", - ftp->ftp_side[0].ftps_cmds); -#endif + if (ippr_ftp_debug > 0) + printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n", + ftp->ftp_side[0].ftps_cmds); return 0; } @@ -449,63 +492,67 @@ int dlen; * Check for PASV reply message. */ if (dlen < IPF_MIN227LEN) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", dlen); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", + dlen); return 0; } else if (strncmp(f->ftps_rptr, "227 Entering Passive Mod", PASV_REPLEN)) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_pasv:227 reply wrong\n"); -#endif + if (ippr_ftp_debug > 0) + printf("ippr_ftp_pasv:%d reply wrong\n", 227); return 0; } - tcp = (tcphdr_t *)fin->fin_dp; - + brackets[0] = ""; + brackets[1] = ""; /* * Skip the PASV reply + space */ s = f->ftps_rptr + PASV_REPLEN; - while (*s && !isdigit(*s)) + while (*s && !ISDIGIT(*s)) { + if (*s == '(') { + brackets[0] = "("; + brackets[1] = ")"; + } s++; + } + /* * Pick out the address components, two at a time. */ a1 = ippr_ftp_atoi(&s); if (s == NULL) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(1) failed\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1); return 0; } a2 = ippr_ftp_atoi(&s); if (s == NULL) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(2) failed\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2); 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. + * check that IP address in the PASV reply is the same as the + * sender of the command - prevents using PASV for port scanning. */ a1 <<= 16; a1 |= a2; - if (a1 != ntohl(nat->nat_oip.s_addr)) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_pasv:a1 != nat->nat_oip\n"); -#endif + + if (((nat->nat_dir == NAT_INBOUND) && + (a1 != ntohl(nat->nat_inip.s_addr))) || + ((nat->nat_dir == NAT_OUTBOUND) && + (a1 != ntohl(nat->nat_oip.s_addr)))) { + if (ippr_ftp_debug > 0) + printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1"); return 0; } a5 = ippr_ftp_atoi(&s); if (s == NULL) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(3) failed\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3); return 0; } @@ -520,97 +567,123 @@ int dlen; */ if ((*s == '\r') && (*(s + 1) == '\n')) { s += 2; - a6 = a5 & 0xff; } else { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_pasv:missing cr-lf\n"); -#endif + if (ippr_ftp_debug > 1) + printf("ippr_ftp_pasv:missing %s", "cr-lf\n"); return 0; } + + a6 = a5 & 0xff; a5 >>= 8; /* * Calculate new address parts for 227 reply */ - a1 = ntohl(ip->ip_src.s_addr); + if (nat->nat_dir == NAT_INBOUND) { + data_ip = nat->nat_outip.s_addr; + a1 = ntohl(data_ip); + } else + data_ip = htonl(a1); + a2 = (a1 >> 16) & 0xff; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; - 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 !defined(_KERNEL) - m = *fin->fin_mp; - m_copyback(m, off, nlen, newbuf); +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n", + "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, + a5, a6, brackets[1]); #else -# 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)) { - mblk_t *nm; + (void) sprintf(newbuf, "%s %s%u,%u,%u,%u,%u,%u%s\r\n", + "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, + a5, a6, brackets[1]); +#endif + return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6), + newbuf, s, data_ip); +} - /* alloc enough to keep same trailer space for lower driver */ - nm = allocb(nlen, BPRI_MED); - PANIC((!nm),("ippr_ftp_out: allocb failed")); +int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpside_t *f; +u_int port; +char *newmsg; +char *s; +u_int data_ip; +{ + int inc, off, nflags, sflags; + tcphdr_t *tcp, tcph, *tcp2; + struct in_addr swip, swip2; + struct in_addr data_addr; + size_t nlen, olen; + fr_info_t fi; + nat_t *nat2; + mb_t *m; - nm->b_band = m1->b_band; - nm->b_wptr += nlen; + m = fin->fin_m; + tcp = (tcphdr_t *)fin->fin_dp; + off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; - m1->b_wptr -= olen; - PANIC((m1->b_wptr < m1->b_rptr), - ("ippr_ftp_out: cannot handle fragmented data block")); + data_addr.s_addr = data_ip; + tcp2 = &tcph; + inc = 0; - linkb(m1, nm); - } else { - m1->b_wptr += inc; + + olen = s - f->ftps_rptr; + nlen = strlen(newmsg); + inc = nlen - olen; + if ((inc + ip->ip_len) > 65535) { + if (ippr_ftp_debug > 0) + printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n", + inc); + return 0; } - /*copyin_mblk(m, off, nlen, newbuf);*/ -# else /* SOLARIS */ - m = *fin->fin_mp; + +#if !defined(_KERNEL) + bcopy(newmsg, MTOD(m, char *) + off, nlen); +#else +# if defined(MENTAT) + if (inc < 0) + (void)adjmsg(m, inc); +# else /* defined(MENTAT) */ + /* + * m_adj takes care of pkthdr.len, if required and treats inc<0 to + * mean remove -len bytes from the end of the packet. + * The mbuf chain will be extended if necessary by m_copyback(). + */ if (inc < 0) m_adj(m, inc); - /* the mbuf chain will be extended if necessary by m_copyback() */ - /*m_copyback(m, off, nlen, newbuf);*/ -# endif /* SOLARIS */ -#endif /* _KERNEL */ - if (inc != 0) { -#if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL) - register u_32_t sum1, sum2; +# endif /* defined(MENTAT) */ +#endif /* !defined(_KERNEL) */ + COPYBACK(m, off, nlen, newmsg); - sum1 = ip->ip_len; - sum2 = ip->ip_len + inc; - - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sum2 -= sum1; - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - fix_outcksum(fin, &ip->ip_sum, sum2); -#endif /* SOLARIS || defined(__sgi) */ + if (inc != 0) { ip->ip_len += inc; + fin->fin_dlen += inc; + fin->fin_plen += inc; } -#endif /* 0 */ /* * Add skeleton NAT entry for connection which will come back the * other way. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_flx |= FI_IGNORE; fi.fin_data[0] = 0; - dp = htons(fin->fin_data[1] - 1); - fi.fin_data[1] = ntohs(dp); - ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, 0); - if (ipn == NULL) { + fi.fin_data[1] = port; + nflags = IPN_TCP|SI_W_SPORT; + if (ippr_ftp_pasvrdr && f->ftps_ifp) + nflags |= SI_W_DPORT; + if (nat->nat_dir == NAT_OUTBOUND) + nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH, + nat->nat_p, nat->nat_inip, nat->nat_oip); + else + nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH, + nat->nat_p, nat->nat_inip, nat->nat_oip); + if (nat2 == NULL) { int slen; slen = ip->ip_len; @@ -618,31 +691,65 @@ int dlen; bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = 0; /* XXX - fake it for nat_new */ - tcp2->th_off = 5; + TCP_OFF_A(tcp2, 5); tcp2->th_flags = TH_SYN; - fi.fin_data[1] = a5 << 8 | a6; + fi.fin_data[1] = port; fi.fin_dlen = sizeof(*tcp2); - tcp2->th_dport = htons(fi.fin_data[1]); + tcp2->th_dport = htons(port); fi.fin_data[0] = 0; fi.fin_dp = (char *)tcp2; + fi.fin_plen = fi.fin_hlen + sizeof(*tcp); fi.fin_fr = &ftppxyfr; - fi.fin_out = 1; + fi.fin_out = nat->nat_dir; + fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; swip = ip->ip_src; swip2 = ip->ip_dst; - fi.fin_fi.fi_daddr = ip->ip_src.s_addr; - fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; - ip->ip_dst = ip->ip_src; - ip->ip_src = nat->nat_inip; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_W_SPORT|FI_IGNOREPKT); + if (nat->nat_dir == NAT_OUTBOUND) { + fi.fin_fi.fi_daddr = data_addr.s_addr; + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; + ip->ip_dst = data_addr; + ip->ip_src = nat->nat_inip; + } else if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; + fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; + ip->ip_src = nat->nat_oip; + ip->ip_dst = nat->nat_outip; } + + sflags = nflags; + nflags |= NAT_SLAVE; + if (nat->nat_dir == NAT_INBOUND) + nflags |= NAT_NOTRULEPORT; + nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_TCP); + nat_update(&fi, nat2, nat->nat_ptr); + fi.fin_ifp = NULL; + if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; + ip->ip_dst = nat->nat_inip; + } + (void) fr_addstate(&fi, &nat2->nat_state, sflags); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + } + ip->ip_len = slen; ip->ip_src = swip; ip->ip_dst = swip2; + } else { + ipstate_t *is; + + nat_update(&fi, nat2, nat->nat_ptr); + READ_ENTER(&ipf_state); + is = nat2->nat_state; + if (is != NULL) { + MUTEX_ENTER(&is->is_lock); + (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, + is->is_flags); + MUTEX_EXIT(&is->is_lock); + } + RWLOCK_EXIT(&ipf_state); } return inc; } @@ -664,13 +771,19 @@ int dlen; rptr = f->ftps_rptr; wptr = f->ftps_wptr; - if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2))) + if (*rptr == ' ') + goto server_cmd_ok; + if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) return 0; if (ftp->ftp_passok == FTPXY_GO) { if (!strncmp(rptr, "227 ", 4)) inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen); + else if (!strncmp(rptr, "229 ", 4)) + inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen); + } else if (ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) { + inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); } else if (*rptr == '5' || *rptr == '4') ftp->ftp_passok = FTPXY_INIT; else if (ftp->ftp_incok) { @@ -695,6 +808,7 @@ int dlen; } } } +server_cmd_ok: ftp->ftp_incok = 0; while ((*rptr++ != '\n') && (rptr < wptr)) @@ -713,35 +827,38 @@ ftpside_t *ftps; char *buf; size_t len; { - register char *s, c; + register char *s, c, pc; register size_t i = len; char cmd[5]; + s = buf; + + if (ftps->ftps_junk == 1) + return 1; + if (i < 5) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_client_valid:i(%lu) < 5\n", - (u_long)i); -#endif + if (ippr_ftp_debug > 3) + printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i); return 2; } - s = buf; - c = *s++; + i--; + c = *s++; - if (isalpha(c)) { - cmd[0] = toupper(c); + if (ISALPHA(c)) { + cmd[0] = TOUPPER(c); c = *s++; i--; - if (isalpha(c)) { - cmd[1] = toupper(c); + if (ISALPHA(c)) { + cmd[1] = TOUPPER(c); c = *s++; i--; - if (isalpha(c)) { - cmd[2] = toupper(c); + if (ISALPHA(c)) { + cmd[2] = TOUPPER(c); c = *s++; i--; - if (isalpha(c)) { - cmd[3] = toupper(c); + if (ISALPHA(c)) { + cmd[3] = TOUPPER(c); c = *s++; i--; if ((c != ' ') && (c != '\r')) @@ -754,17 +871,18 @@ size_t len; goto bad_client_command; } else { bad_client_command: -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_client_valid:bad cmd:len %lu i %lu c 0x%x\n", - (u_long)i, (u_long)len, c); -#endif + if (ippr_ftp_debug > 3) + printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", + "ippr_ftp_client_valid", + ftps->ftps_junk, (int)len, (int)i, c, + (int)len, (int)len, buf); return 1; } for (; i; i--) { + pc = c; c = *s++; - if (c == '\n') { + if ((pc == '\r') && (c == '\n')) { cmd[4] = '\0'; if (!strcmp(cmd, "PASV")) ftps->ftps_cmds = FTPXY_C_PASV; @@ -773,8 +891,9 @@ bad_client_command: return 0; } } -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_client_valid:junk after cmd[%s]\n", buf); +#if !defined(_KERNEL) + printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n", + (int)len, (int)len, buf); #endif return 2; } @@ -785,26 +904,36 @@ ftpside_t *ftps; char *buf; size_t len; { - register char *s, c; + register char *s, c, pc; register size_t i = len; int cmd; - if (i < 5) - return 2; s = buf; - c = *s++; cmd = 0; + + if (ftps->ftps_junk == 1) + return 1; + + if (i < 5) { + if (ippr_ftp_debug > 3) + printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i); + return 2; + } + + c = *s++; i--; + if (c == ' ') + goto search_eol; - if (isdigit(c)) { + if (ISDIGIT(c)) { cmd = (c - '0') * 100; c = *s++; i--; - if (isdigit(c)) { + if (ISDIGIT(c)) { cmd += (c - '0') * 10; c = *s++; i--; - if (isdigit(c)) { + if (ISDIGIT(c)) { cmd += (c - '0'); c = *s++; i--; @@ -816,24 +945,25 @@ size_t len; goto bad_server_command; } else { bad_server_command: -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_server_valid:bad cmd:len %lu i %lu c 0x%x\n", - (u_long)i, (u_long)len, c); -#endif + if (ippr_ftp_debug > 3) + printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", + "ippr_ftp_server_valid", + ftps->ftps_junk, (int)len, (int)i, + c, (int)len, (int)len, buf); return 1; } - +search_eol: for (; i; i--) { + pc = c; c = *s++; - if (c == '\n') { + if ((pc == '\r') && (c == '\n')) { ftps->ftps_cmds = cmd; return 0; } } -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, "ippr_ftp_server_valid:junk after cmd[%s]\n", buf); -#endif + if (ippr_ftp_debug > 3) + printf("ippr_ftp_server_valid:junk after cmd[%*.*s]\n", + (int)len, (int)len, buf); return 2; } @@ -858,48 +988,54 @@ size_t len; /* + * For map rules, the following applies: * rv == 0 for outbound processing, * rv == 1 for inbound processing. + * For rdr rules, the following applies: + * rv == 0 for inbound processing, + * rv == 1 for outbound processing. */ -int ippr_ftp_process(fin, ip, nat, ftp, rv) +int ippr_ftp_process(fin, nat, ftp, rv) fr_info_t *fin; -ip_t *ip; nat_t *nat; ftpinfo_t *ftp; int rv; { int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff; + char *rptr, *wptr, *s; u_32_t thseq, thack; - char *rptr, *wptr; ap_session_t *aps; ftpside_t *f, *t; tcphdr_t *tcp; + ip_t *ip; mb_t *m; + m = fin->fin_m; + ip = fin->fin_ip; tcp = (tcphdr_t *)fin->fin_dp; - off = fin->fin_hlen + (tcp->th_off << 2); -#if SOLARIS && defined(_KERNEL) - m = fin->fin_qfm; -#else - m = *fin->fin_mp; -#endif + off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; + + f = &ftp->ftp_side[rv]; + t = &ftp->ftp_side[1 - rv]; + thseq = ntohl(tcp->th_seq); + thack = ntohl(tcp->th_ack); -#ifndef _KERNEL - mlen = mbuflen(m); +#ifdef __sgi + mlen = fin->fin_plen - off; #else -# if SOLARIS - mlen = msgdsize(m); -# else - mlen = mbufchainlen(m); -# endif + mlen = MSGDSIZE(m) - off; #endif - mlen -= off; + if (ippr_ftp_debug > 4) + printf("ippr_ftp_process: mlen %d\n", mlen); + if (mlen <= 0) { + if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { + f->ftps_seq[0] = thseq + 1; + t->ftps_seq[0] = thack; + } + return 0; + } aps = nat->nat_aps; - t = &ftp->ftp_side[1 - rv]; - f = &ftp->ftp_side[rv]; - thseq = ntohl(tcp->th_seq); - thack = ntohl(tcp->th_ack); sel = aps->aps_sel[1 - rv]; sel2 = aps->aps_sel[rv]; @@ -911,19 +1047,17 @@ int rv; if (aps->aps_ackmin[sel2] > ackoff + thack) ackoff = aps->aps_ackoff[!sel2]; } else { -#if PROXY_DEBUG - printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, - aps->aps_ackmin[sel]); -#endif seqoff = aps->aps_ackoff[sel]; + if (ippr_ftp_debug > 2) + printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, + aps->aps_ackmin[sel]); if (aps->aps_ackmin[sel] > seqoff + thseq) seqoff = aps->aps_ackoff[!sel]; -#if PROXY_DEBUG - printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, - aps->aps_seqmin[sel2]); -#endif ackoff = aps->aps_seqoff[sel2]; + if (ippr_ftp_debug > 2) + printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, + aps->aps_seqmin[sel2]); if (ackoff > 0) { if (aps->aps_seqmin[sel2] > ackoff + thack) ackoff = aps->aps_seqoff[!sel2]; @@ -932,26 +1066,27 @@ int rv; ackoff = aps->aps_seqoff[!sel2]; } } -#if PROXY_DEBUG - printf("%s: %x seq %x/%d ack %x/%d len %d\n", rv ? "IN" : "OUT", - tcp->th_flags, thseq, seqoff, thack, ackoff, mlen); - printf("sel %d seqmin %x/%x offset %d/%d\n", sel, - aps->aps_seqmin[sel], aps->aps_seqmin[sel2], - aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); - printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, - aps->aps_ackmin[sel], aps->aps_ackmin[sel2], - aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); -#endif + if (ippr_ftp_debug > 2) { + printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n", + rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff, + thack, ackoff, mlen, fin->fin_plen, off); + printf("sel %d seqmin %x/%x offset %d/%d\n", sel, + aps->aps_seqmin[sel], aps->aps_seqmin[sel2], + aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); + printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, + aps->aps_ackmin[sel], aps->aps_ackmin[sel2], + aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); + } /* * 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 PROXY_DEBUG - printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", - rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); -#endif + if (ippr_ftp_debug > 2) { + printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", + rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); + } ok = 0; if (t->ftps_seq[0] == 0) { @@ -980,33 +1115,35 @@ int rv; } } -#if PROXY_DEBUG - if (!ok) - printf("not ok\n"); -#endif + if (ippr_ftp_debug > 2) { + if (!ok) + printf("%s ok\n", "not"); + } if (!mlen) { if (t->ftps_seq[0] + ackoff != thack) { -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_process:seq[0](%x) + ackoff(%x) != thack(%x)\n", - t->ftps_seq[0], ackoff, thack); -#endif + if (ippr_ftp_debug > 1) { + printf("%s:seq[0](%x) + (%x) != (%x)\n", + "ippr_ftp_process", t->ftps_seq[0], + ackoff, thack); + } return APR_ERR(1); } -#if PROXY_DEBUG - printf("f:seq[0] %x seq[1] %x\n", f->ftps_seq[0], f->ftps_seq[1]); -#endif + if (ippr_ftp_debug > 2) { + printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n", + f->ftps_seq[0], f->ftps_seq[1]); + } + if (tcp->th_flags & TH_FIN) { if (thseq == f->ftps_seq[1]) { f->ftps_seq[0] = f->ftps_seq[1] - seqoff; f->ftps_seq[1] = thseq + 1 - seqoff; } else { -#if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL)) - printf("FIN: thseq %x seqoff %d ftps_seq %x\n", - thseq, seqoff, f->ftps_seq[0]); -#endif + if (ippr_ftp_debug > 1) { + printf("FIN: thseq %x seqoff %d ftps_seq %x\n", + thseq, seqoff, f->ftps_seq[0]); + } return APR_ERR(1); } } @@ -1027,15 +1164,15 @@ int rv; if (ok == 0) { inc = thseq - f->ftps_seq[0]; -#if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL)) - printf("inc %d sel %d rv %d\n", inc, sel, rv); - printf("th_seq %x ftps_seq %x/%x\n", thseq, f->ftps_seq[0], - f->ftps_seq[1]); - printf("ackmin %x ackoff %d\n", (u_int)aps->aps_ackmin[sel], - aps->aps_ackoff[sel]); - printf("seqmin %x seqoff %d\n", (u_int)aps->aps_seqmin[sel], - aps->aps_seqoff[sel]); -#endif + if (ippr_ftp_debug > 1) { + printf("inc %d sel %d rv %d\n", inc, sel, rv); + printf("th_seq %x ftps_seq %x/%x\n", + thseq, f->ftps_seq[0], f->ftps_seq[1]); + printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], + aps->aps_ackoff[sel]); + printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], + aps->aps_seqoff[sel]); + } return APR_ERR(1); } @@ -1048,31 +1185,62 @@ int rv; f->ftps_len = mlen; while (mlen > 0) { - len = MIN(mlen, FTP_BUFSZ / 2); - -#if !defined(_KERNEL) - bcopy((char *)m + off, wptr, len); -#else -# if SOLARIS - copyout_mblk(m, off, len, wptr); -# else - m_copydata(m, off, len, wptr); -# endif -#endif + len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); + COPYDATA(m, off, len, wptr); mlen -= len; off += len; wptr += len; + + if (ippr_ftp_debug > 3) + printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n", + "ippr_ftp_process", + len, mlen, off, (u_long)wptr, f->ftps_junk, + len, len, rptr); + f->ftps_wptr = wptr; - if (f->ftps_junk == 2) + if (f->ftps_junk != 0) { + i = f->ftps_junk; f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, wptr - rptr); + if (ippr_ftp_debug > 5) + printf("%s:junk %d -> %d\n", + "ippr_ftp_process", i, f->ftps_junk); + + if (f->ftps_junk != 0) { + if (wptr - rptr == sizeof(f->ftps_buf)) { + if (ippr_ftp_debug > 4) + printf("%s:full buffer\n", + "ippr_ftp_process"); + f->ftps_rptr = f->ftps_buf; + f->ftps_wptr = f->ftps_buf; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + /* + * Because we throw away data here that + * we would otherwise parse, set the + * junk flag to indicate just ignore + * any data upto the next CRLF. + */ + f->ftps_junk = 1; + continue; + } + } + } + while ((f->ftps_junk == 0) && (wptr > rptr)) { - f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, - wptr - rptr); + len = wptr - rptr; + f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len); + + if (ippr_ftp_debug > 3) { + printf("%s=%d len %d rv %d ptr %lx/%lx ", + "ippr_ftp_valid", + f->ftps_junk, len, rv, (u_long)rptr, + (u_long)wptr); + printf("buf [%*.*s]\n", len, len, rptr); + } + if (f->ftps_junk == 0) { - f->ftps_cmds++; - len = wptr - rptr; f->ftps_rptr = rptr; if (rv) inc += ippr_ftp_server(fin, ip, nat, @@ -1091,66 +1259,56 @@ int rv; */ if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) { /* f->ftps_seq[1] += inc; */ -#if !defined(_KERNEL) && !defined(KERNEL) - fprintf(stdout, - "ippr_ftp_process:cmds == 0 junk == 1\n"); -#endif + + if (ippr_ftp_debug > 1) + printf("%s:cmds == 0 junk == 1\n", + "ippr_ftp_process"); return APR_ERR(2); } - while ((f->ftps_junk == 1) && (rptr < wptr)) { - while ((rptr < wptr) && (*rptr != '\r')) - rptr++; - - if (*rptr == '\r') { - if (rptr + 1 < wptr) { - if (*(rptr + 1) == '\n') { - rptr += 2; - f->ftps_junk = 0; - } else - rptr++; - } else + if ((f->ftps_junk != 0) && (rptr < wptr)) { + for (s = rptr; s < wptr; s++) { + if ((*s == '\r') && (s + 1 < wptr) && + (*(s + 1) == '\n')) { + rptr = s + 2; + f->ftps_junk = 0; break; + } } } - 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_junk = 1; - rptr = wptr = f->ftps_buf; - } else { - bcopy(rptr, f->ftps_buf, i); - wptr = f->ftps_buf + i; - rptr = f->ftps_buf; - } + /* + * Compact the buffer back to the start. The junk + * flag should already be set and because we're not + * throwing away any data, it is preserved from its + * current state. + */ + if (rptr > f->ftps_buf) { + bcopy(rptr, f->ftps_buf, len); + wptr -= rptr - f->ftps_buf; + rptr = f->ftps_buf; } - f->ftps_rptr = rptr; - f->ftps_wptr = wptr; } + f->ftps_rptr = rptr; + f->ftps_wptr = wptr; } /* f->ftps_seq[1] += inc; */ if (tcp->th_flags & TH_FIN) f->ftps_seq[1]++; -#if PROXY_DEBUG -# ifndef _KERNEL - mlen = mbuflen(m); -# else -# if SOLARIS - mlen = msgdsize(m); -# else - mlen = mbufchainlen(m); -# endif -# endif - mlen -= off; - printf("ftps_seq[1] = %x inc %d len %d\n", f->ftps_seq[1], inc, mlen); + if (ippr_ftp_debug > 3) { +#ifdef __sgi + mlen = fin->fin_plen; +#else + mlen = MSGDSIZE(m); #endif + mlen -= off; + printf("ftps_seq[1] = %x inc %d len %d\n", + f->ftps_seq[1], inc, mlen); + } f->ftps_rptr = rptr; f->ftps_wptr = wptr; @@ -1158,33 +1316,43 @@ int rv; } -int ippr_ftp_out(fin, ip, aps, nat) +int ippr_ftp_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { ftpinfo_t *ftp; + int rev; ftp = aps->aps_data; if (ftp == NULL) return 0; - return ippr_ftp_process(fin, ip, nat, ftp, 0); + + rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; + if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) + ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; + + return ippr_ftp_process(fin, nat, ftp, rev); } -int ippr_ftp_in(fin, ip, aps, nat) +int ippr_ftp_in(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { ftpinfo_t *ftp; + int rev; ftp = aps->aps_data; if (ftp == NULL) return 0; - return ippr_ftp_process(fin, ip, nat, ftp, 1); + + rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; + if (ftp->ftp_side[rev].ftps_ifp == NULL) + ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; + + return ippr_ftp_process(fin, nat, ftp, 1 - rev); } @@ -1200,7 +1368,7 @@ char **ptr; register char *s = *ptr, c; register u_char i = 0, j = 0; - while ((c = *s++) && isdigit(c)) { + while (((c = *s++) != '\0') && ISDIGIT(c)) { i *= 10; i += c - '0'; } @@ -1208,7 +1376,7 @@ char **ptr; *ptr = NULL; return 0; } - while ((c = *s++) && isdigit(c)) { + while (((c = *s++) != '\0') && ISDIGIT(c)) { j *= 10; j += c - '0'; } @@ -1217,3 +1385,70 @@ char **ptr; j &= 0xff; return (i << 8) | j; } + + +int ippr_ftp_epsv(fin, ip, nat, f, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpside_t *f; +int dlen; +{ + char newbuf[IPF_FTPBUFSZ]; + char *s; + u_short ap = 0; + +#define EPSV_REPLEN 33 + /* + * Check for EPSV reply message. + */ + if (dlen < IPF_MIN229LEN) + return (0); + else if (strncmp(f->ftps_rptr, + "229 Entering Extended Passive Mode", EPSV_REPLEN)) + return (0); + + /* + * Skip the EPSV command + space + */ + s = f->ftps_rptr + 33; + while (*s && !ISDIGIT(*s)) + s++; + + /* + * As per RFC 2428, there are no addres components in the EPSV + * response. So we'll go straight to getting the port. + */ + while (*s && ISDIGIT(*s)) { + ap *= 10; + ap += *s++ - '0'; + } + + if (!s) + return 0; + + if (*s == '|') + s++; + if (*s == ')') + s++; + if (*s == '\n') + s--; + /* + * check for CR-LF at the end. + */ + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; + } else + return 0; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", + "229 Entering Extended Passive Mode", ap); +#else + (void) sprintf(newbuf, "%s (|||%u|)\r\n", + "229 Entering Extended Passive Mode", ap); +#endif + + return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s, + ip->ip_src.s_addr); +} diff --git a/contrib/ipfilter/ip_h323_pxy.c b/contrib/ipfilter/ip_h323_pxy.c index 8d8ef92..b6e7c7b 100644 --- a/contrib/ipfilter/ip_h323_pxy.c +++ b/contrib/ipfilter/ip_h323_pxy.c @@ -1,6 +1,8 @@ +/* $NetBSD$ */ + /* * Copyright 2001, QNX Software Systems Ltd. All Rights Reserved - * + * * This source code has been published by QNX Software Systems Ltd. (QSSL). * However, any use, reproduction, modification, distribution or transfer of * this software, or any software which includes or is based upon any of this @@ -14,7 +16,7 @@ /* * Simple H.323 proxy - * + * * by xtang@canada.com * ported to ipfilter 3.4.20 by Michael Grant mg-ipf@grant.org */ @@ -23,33 +25,34 @@ # include <sys/fcntl.h> # include <sys/filio.h> #else -# include <sys/ioctl.h> +# ifndef linux +# include <sys/ioctl.h> +# endif #endif #define IPF_H323_PROXY int ippr_h323_init __P((void)); -int ippr_h323_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_h323_fini __P((void)); +int ippr_h323_new __P((fr_info_t *, ap_session_t *, nat_t *)); void ippr_h323_del __P((ap_session_t *)); -int ippr_h323_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_h323_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_h323_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_h323_in __P((fr_info_t *, ap_session_t *, nat_t *)); -int ippr_h245_init __P((void)); -int ippr_h245_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_h245_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_h245_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_h245_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_h245_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_h245_in __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t h323_fr; -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_nat; -#endif -static int find_port __P((int, u_char *, int datlen, int *, u_short *)); +int h323_proxy_init = 0; + +static int find_port __P((int, caddr_t, int datlen, int *, u_short *)); static int find_port(ipaddr, data, datlen, off, port) int ipaddr; -unsigned char *data; +caddr_t data; int datlen, *off; unsigned short *port; { @@ -85,17 +88,30 @@ int ippr_h323_init() bzero((char *)&h323_fr, sizeof(h323_fr)); h323_fr.fr_ref = 1; h323_fr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&h323_fr.fr_lock, "H323 proxy rule lock"); + h323_proxy_init = 1; return 0; } -int ippr_h323_new(fin, ip, aps, nat) +void ippr_h323_fini() +{ + if (h323_proxy_init == 1) { + MUTEX_DESTROY(&h323_fr.fr_lock); + h323_proxy_init = 0; + } +} + + +int ippr_h323_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_data = NULL; aps->aps_psiz = 0; @@ -111,17 +127,18 @@ ap_session_t *aps; if (aps->aps_data) { for (i = 0, ipn = aps->aps_data; - i < (aps->aps_psiz / sizeof(ipnat_t)); + i < (aps->aps_psiz / sizeof(ipnat_t)); i++, ipn = (ipnat_t *)((char *)ipn + sizeof(*ipn))) { - /* + /* * Check the comment in ippr_h323_in() function, - * just above nat_ioctl() call. + * just above fr_nat_ioctl() call. * We are lucky here because this function is not * called with ipf_nat locked. */ - if (nat_ioctl((caddr_t)ipn, SIOCRMNAT, NAT_SYSSPACE| - NAT_LOCKHELD|FWRITE) == -1) { + if (fr_nat_ioctl((caddr_t)ipn, SIOCRMNAT, NAT_SYSSPACE| + NAT_LOCKHELD|FWRITE) == -1) { + /*EMPTY*/; /* log the error */ } } @@ -134,32 +151,23 @@ ap_session_t *aps; } -int ippr_h323_out(fin, ip, aps, nat) +int ippr_h323_in(fin, aps, nat) fr_info_t *fin; -ip_t *ip; -ap_session_t *aps; -nat_t *nat; -{ - return 0; -} - - -int ippr_h323_in(fin, ip, aps, nat) -fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { int ipaddr, off, datlen; unsigned short port; - unsigned char *data; + caddr_t data; tcphdr_t *tcp; - + ip_t *ip; + + ip = fin->fin_ip; tcp = (tcphdr_t *)fin->fin_dp; ipaddr = ip->ip_src.s_addr; - data = (unsigned char *)tcp + (tcp->th_off << 2); - datlen = fin->fin_dlen - (tcp->th_off << 2); + data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); + datlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); if (find_port(ipaddr, data, datlen, &off, &port) == 0) { ipnat_t *ipn; char *newarray; @@ -173,27 +181,27 @@ nat_t *nat; return -1; } ipn = (ipnat_t *)&newarray[aps->aps_psiz]; - bcopy(nat->nat_ptr, ipn, sizeof(ipnat_t)); - strncpy(ipn->in_plabel, "h245", APR_LABELLEN); + bcopy((caddr_t)nat->nat_ptr, (caddr_t)ipn, sizeof(ipnat_t)); + (void) strncpy(ipn->in_plabel, "h245", APR_LABELLEN); ipn->in_inip = nat->nat_inip.s_addr; ipn->in_inmsk = 0xffffffff; ipn->in_dport = htons(port); - /* - * we got a problem here. we need to call nat_ioctl() to add + /* + * we got a problem here. we need to call fr_nat_ioctl() to add * the h245 proxy rule, but since we already hold (READ locked) - * the nat table rwlock (ipf_nat), if we go into nat_ioctl(), + * the nat table rwlock (ipf_nat), if we go into fr_nat_ioctl(), * it will try to WRITE lock it. This will causing dead lock * on RTP. - * + * * The quick & dirty solution here is release the read lock, - * call nat_ioctl() and re-lock it. + * call fr_nat_ioctl() and re-lock it. * A (maybe better) solution is do a UPGRADE(), and instead - * of calling nat_ioctl(), we add the nat rule ourself. + * of calling fr_nat_ioctl(), we add the nat rule ourself. */ RWLOCK_EXIT(&ipf_nat); - if (nat_ioctl((caddr_t)ipn, SIOCADNAT, - NAT_SYSSPACE|FWRITE) == -1) { + if (fr_nat_ioctl((caddr_t)ipn, SIOCADNAT, + NAT_SYSSPACE|FWRITE) == -1) { READ_ENTER(&ipf_nat); return -1; } @@ -209,87 +217,80 @@ nat_t *nat; } -int ippr_h245_init() -{ - return 0; -} - - -int ippr_h245_new(fin, ip, aps, nat) +int ippr_h245_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_data = NULL; aps->aps_psiz = 0; return 0; } -int ippr_h245_out(fin, ip, aps, nat) +int ippr_h245_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { int ipaddr, off, datlen; - u_short port; - unsigned char *data; tcphdr_t *tcp; - + caddr_t data; + u_short port; + ip_t *ip; + + aps = aps; /* LINT */ + + ip = fin->fin_ip; tcp = (tcphdr_t *)fin->fin_dp; ipaddr = nat->nat_inip.s_addr; - data = (unsigned char *)tcp + (tcp->th_off << 2); - datlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2); + data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); + datlen = ip->ip_len - fin->fin_hlen - (TCP_OFF(tcp) << 2); if (find_port(ipaddr, data, datlen, &off, &port) == 0) { fr_info_t fi; - nat_t *ipn; + nat_t *nat2; /* port = htons(port); */ - ipn = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP, - ip->ip_src, ip->ip_dst, 1); - if (ipn == NULL) { + nat2 = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP, + ip->ip_src, ip->ip_dst); + if (nat2 == NULL) { struct ip newip; struct udphdr udp; - bcopy(ip, &newip, sizeof(newip)); + bcopy((caddr_t)ip, (caddr_t)&newip, sizeof(newip)); newip.ip_len = fin->fin_hlen + sizeof(udp); newip.ip_p = IPPROTO_UDP; newip.ip_src = nat->nat_inip; - bzero(&udp, sizeof(udp)); + bzero((char *)&udp, sizeof(udp)); udp.uh_sport = port; - bcopy(fin, &fi, sizeof(fi)); + bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi)); fi.fin_fi.fi_p = IPPROTO_UDP; fi.fin_data[0] = port; fi.fin_data[1] = 0; fi.fin_dp = (char *)&udp; - - ipn = nat_new(&fi, &newip, nat->nat_ptr, NULL, - IPN_UDP|FI_W_DPORT, NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_ptr->in_hits++; + + nat2 = nat_new(&fi, nat->nat_ptr, NULL, + NAT_SLAVE|IPN_UDP|SI_W_DPORT, + NAT_OUTBOUND); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_UDP); + nat_update(&fi, nat2, nat2->nat_ptr); + + nat2->nat_ptr->in_hits++; #ifdef IPFILTER_LOG - nat_log(ipn, (u_int)(nat->nat_ptr->in_redir)); + nat_log(nat2, (u_int)(nat->nat_ptr->in_redir)); #endif - bcopy((u_char*)&ip->ip_src.s_addr, + bcopy((caddr_t)&ip->ip_src.s_addr, data + off, 4); - bcopy((u_char*)&ipn->nat_outport, + bcopy((caddr_t)&nat2->nat_outport, data + off + 4, 2); } } } return 0; } - - -int ippr_h245_in(fin, ip, aps, nat) -fr_info_t *fin; -ip_t *ip; -ap_session_t *aps; -nat_t *nat; -{ - return 0; -} diff --git a/contrib/ipfilter/ip_htable.c b/contrib/ipfilter/ip_htable.c new file mode 100644 index 0000000..50aa926 --- /dev/null +++ b/contrib/ipfilter/ip_htable.c @@ -0,0 +1,455 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001, 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/file.h> +#if !defined(_KERNEL) +# include <stdlib.h> +# include <string.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL +#endif +#include <sys/socket.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +#endif +#if defined(__FreeBSD__) +# include <sys/cdefs.h> +# include <sys/proc.h> +#endif +#if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \ + !defined(linux) +# include <sys/mbuf.h> +#endif +#if defined(_KERNEL) +# include <sys/systm.h> +#else +# include <stdio.h> +#endif +#include <netinet/in.h> +#include <net/if.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" +/* END OF INCLUDES */ + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: ip_htable.c,v 2.34.2.2 2004/10/17 15:49:15 darrenr Exp"; +#endif + +#ifdef IPFILTER_LOOKUP +static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *)); +static u_long ipht_nomem[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static u_long ipf_nhtables[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static u_long ipf_nhtnodes[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; + + +void fr_htable_unload() +{ + iplookupflush_t fop; + + fop.iplf_unit = IPL_LOGALL; + (void)fr_flushhtable(&fop); +} + + +int fr_gethtablestat(op) +iplookupop_t *op; +{ + iphtstat_t stats; + + if (op->iplo_size != sizeof(stats)) + return EINVAL; + + stats.iphs_tables = ipf_htables[op->iplo_unit]; + stats.iphs_numtables = ipf_nhtables[op->iplo_unit]; + stats.iphs_numnodes = ipf_nhtnodes[op->iplo_unit]; + stats.iphs_nomem = ipht_nomem[op->iplo_unit]; + + return COPYOUT(&stats, op->iplo_struct, sizeof(stats)); + +} + + +/* + * Create a new hash table using the template passed. + */ +int fr_newhtable(op) +iplookupop_t *op; +{ + iphtable_t *iph, *oiph; + char name[FR_GROUPLEN]; + int err, i, unit; + + KMALLOC(iph, iphtable_t *); + if (iph == NULL) + return ENOMEM; + + err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); + if (err != 0) { + KFREE(iph); + return EFAULT; + } + + unit = op->iplo_unit; + if (iph->iph_unit != unit) { + KFREE(iph); + return EINVAL; + } + + if ((op->iplo_arg & IPHASH_ANON) == 0) { + if (fr_findhtable(op->iplo_unit, op->iplo_name) != NULL) { + KFREE(iph); + return EEXIST; + } + } else { + i = IPHASH_ANON; + do { + i++; +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%u", i); +#else + (void)sprintf(name, "%u", i); +#endif + for (oiph = ipf_htables[unit]; oiph != NULL; + oiph = oiph->iph_next) + if (strncmp(oiph->iph_name, name, + sizeof(oiph->iph_name)) == 0) + break; + } while (oiph != NULL); + (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); + err = COPYOUT(iph, op->iplo_struct, sizeof(*iph)); + if (err != 0) { + KFREE(iph); + return EFAULT; + } + iph->iph_type |= IPHASH_ANON; + } + + KMALLOCS(iph->iph_table, iphtent_t **, + iph->iph_size * sizeof(*iph->iph_table)); + if (iph->iph_table == NULL) { + KFREE(iph); + ipht_nomem[unit]++; + return ENOMEM; + } + + bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); + iph->iph_masks = 0; + + iph->iph_next = ipf_htables[unit]; + iph->iph_pnext = &ipf_htables[unit]; + if (ipf_htables[unit] != NULL) + ipf_htables[unit]->iph_pnext = &iph->iph_next; + ipf_htables[unit] = iph; + + ipf_nhtables[unit]++; + + return 0; +} + + +/* + */ +int fr_removehtable(op) +iplookupop_t *op; +{ + iphtable_t *iph; + + + iph = fr_findhtable(op->iplo_unit, op->iplo_name); + if (iph == NULL) + return ESRCH; + + if (iph->iph_unit != op->iplo_unit) { + return EINVAL; + } + + if (iph->iph_ref != 0) { + return EBUSY; + } + + fr_delhtable(iph); + + return 0; +} + + +void fr_delhtable(iph) +iphtable_t *iph; +{ + iphtent_t *ipe; + int i; + + for (i = 0; i < iph->iph_size; i++) + while ((ipe = iph->iph_table[i]) != NULL) + if (fr_delhtent(iph, ipe) != 0) + return; + + *iph->iph_pnext = iph->iph_next; + if (iph->iph_next != NULL) + iph->iph_next->iph_pnext = iph->iph_pnext; + + ipf_nhtables[iph->iph_unit]--; + + if (iph->iph_ref == 0) { + KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); + KFREE(iph); + } +} + + +void fr_derefhtable(iph) +iphtable_t *iph; +{ + iph->iph_ref--; + if (iph->iph_ref == 0) + fr_delhtable(iph); +} + + +iphtable_t *fr_findhtable(unit, name) +int unit; +char *name; +{ + iphtable_t *iph; + + for (iph = ipf_htables[unit]; iph != NULL; iph = iph->iph_next) + if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0) + break; + return iph; +} + + +size_t fr_flushhtable(op) +iplookupflush_t *op; +{ + iphtable_t *iph; + size_t freed; + int i; + + freed = 0; + + for (i = 0; i <= IPL_LOGMAX; i++) { + if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { + while ((iph = ipf_htables[i]) != NULL) { + fr_delhtable(iph); + freed++; + } + } + } + + return freed; +} + + +/* + * Add an entry to a hash table. + */ +int fr_addhtent(iph, ipeo) +iphtable_t *iph; +iphtent_t *ipeo; +{ + iphtent_t *ipe; + u_int hv; + int bits; + + KMALLOC(ipe, iphtent_t *); + if (ipe == NULL) + return -1; + + bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe)); + ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr; + ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr); + bits = count4bits(ipe->ipe_mask.in4_addr); + ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr); + + hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, + iph->iph_size); + ipe->ipe_ref = 0; + ipe->ipe_next = iph->iph_table[hv]; + ipe->ipe_pnext = iph->iph_table + hv; + + if (iph->iph_table[hv] != NULL) + iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next; + iph->iph_table[hv] = ipe; + if ((bits >= 0) && (bits != 32)) + iph->iph_masks |= 1 << bits; + + switch (iph->iph_type & ~IPHASH_ANON) + { + case IPHASH_GROUPMAP : + ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL, + iph->iph_flags, IPL_LOGIPF, + fr_active); + break; + + default : + ipe->ipe_ptr = NULL; + ipe->ipe_value = 0; + break; + } + + ipf_nhtnodes[iph->iph_unit]++; + + return 0; +} + + +/* + * Delete an entry from a hash table. + */ +int fr_delhtent(iph, ipe) +iphtable_t *iph; +iphtent_t *ipe; +{ + + if (ipe->ipe_ref != 0) + return EBUSY; + + + *ipe->ipe_pnext = ipe->ipe_next; + if (ipe->ipe_next != NULL) + ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; + + switch (iph->iph_type & ~IPHASH_ANON) + { + case IPHASH_GROUPMAP : + if (ipe->ipe_group != NULL) + fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active); + break; + + default : + ipe->ipe_ptr = NULL; + ipe->ipe_value = 0; + break; + } + + KFREE(ipe); + + ipf_nhtnodes[iph->iph_unit]--; + + return 0; +} + + +void *fr_iphmfindgroup(tptr, aptr) +void *tptr, *aptr; +{ + struct in_addr *addr; + iphtable_t *iph; + iphtent_t *ipe; + void *rval; + + READ_ENTER(&ip_poolrw); + iph = tptr; + addr = aptr; + + ipe = fr_iphmfind(iph, addr); + if (ipe != NULL) + rval = ipe->ipe_ptr; + else + rval = NULL; + RWLOCK_EXIT(&ip_poolrw); + return rval; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_iphmfindip */ +/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ +/* Parameters: tptr(I) - pointer to the pool to search */ +/* version(I) - IP protocol version (4 or 6) */ +/* aptr(I) - pointer to address information */ +/* */ +/* Search the hash table for a given address and return a search result. */ +/* ------------------------------------------------------------------------ */ +int fr_iphmfindip(tptr, version, aptr) +void *tptr, *aptr; +int version; +{ + struct in_addr *addr; + iphtable_t *iph; + iphtent_t *ipe; + int rval; + + if (version != 4) + return -1; + + if (tptr == NULL || aptr == NULL) + return -1; + + iph = tptr; + addr = aptr; + + READ_ENTER(&ip_poolrw); + ipe = fr_iphmfind(iph, addr); + if (ipe != NULL) + rval = 0; + else + rval = 1; + RWLOCK_EXIT(&ip_poolrw); + return rval; +} + + +/* Locks: ip_poolrw */ +static iphtent_t *fr_iphmfind(iph, addr) +iphtable_t *iph; +struct in_addr *addr; +{ + u_32_t hmsk, msk, ips; + iphtent_t *ipe; + u_int hv; + + hmsk = iph->iph_masks; + msk = 0xffffffff; +maskloop: + ips = ntohl(addr->s_addr) & msk; + hv = IPE_HASH_FN(ips, msk, iph->iph_size); + for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { + if (ipe->ipe_mask.in4_addr != msk || + ipe->ipe_addr.in4_addr != ips) { + continue; + } + break; + } + + if ((ipe == NULL) && (hmsk != 0)) { + while (hmsk != 0) { + msk <<= 1; + if (hmsk & 0x80000000) + break; + hmsk <<= 1; + } + if (hmsk != 0) { + hmsk <<= 1; + goto maskloop; + } + } + return ipe; +} + +#endif /* IPFILTER_LOOKUP */ diff --git a/contrib/ipfilter/ip_htable.h b/contrib/ipfilter/ip_htable.h new file mode 100644 index 0000000..e138459 --- /dev/null +++ b/contrib/ipfilter/ip_htable.h @@ -0,0 +1,71 @@ +/* $NetBSD$ */ + +#ifndef __IP_HTABLE_H__ +#define __IP_HTABLE_H__ + +#include "netinet/ip_lookup.h" + +typedef struct iphtent_s { + struct iphtent_s *ipe_next, **ipe_pnext; + void *ipe_ptr; + i6addr_t ipe_addr; + i6addr_t ipe_mask; + int ipe_ref; + union { + char ipeu_char[16]; + u_long ipeu_long; + u_int ipeu_int; + }ipe_un; +} iphtent_t; + +#define ipe_value ipe_un.ipeu_int +#define ipe_group ipe_un.ipeu_char + +#define IPE_HASH_FN(a, m, s) (((a) * (m)) % (s)) + + +typedef struct iphtable_s { + ipfrwlock_t iph_rwlock; + struct iphtable_s *iph_next, **iph_pnext; + struct iphtent_s **iph_table; + size_t iph_size; /* size of hash table */ + u_long iph_seed; /* hashing seed */ + u_32_t iph_flags; + u_int iph_unit; /* IPL_LOG* */ + u_int iph_ref; + u_int iph_type; /* lookup or group map - IPHASH_* */ + u_int iph_masks; /* IPv4 netmasks in use */ + char iph_name[FR_GROUPLEN]; /* hash table number */ +} iphtable_t; + +/* iph_type */ +#define IPHASH_LOOKUP 0 +#define IPHASH_GROUPMAP 1 +#define IPHASH_ANON 0x80000000 + + +typedef struct iphtstat_s { + iphtable_t *iphs_tables; + u_long iphs_numtables; + u_long iphs_numnodes; + u_long iphs_nomem; + u_long iphs_pad[16]; +} iphtstat_t; + + +extern iphtable_t *ipf_htables[IPL_LOGSIZE]; + +extern void fr_htable_unload __P((void)); +extern int fr_newhtable __P((iplookupop_t *)); +extern iphtable_t *fr_findhtable __P((int, char *)); +extern int fr_removehtable __P((iplookupop_t *)); +extern size_t fr_flushhtable __P((iplookupflush_t *)); +extern int fr_addhtent __P((iphtable_t *, iphtent_t *)); +extern int fr_delhtent __P((iphtable_t *, iphtent_t *)); +extern void fr_derefhtable __P((iphtable_t *)); +extern void fr_delhtable __P((iphtable_t *)); +extern void *fr_iphmfindgroup __P((void *, void *)); +extern int fr_iphmfindip __P((void *, int, void *)); +extern int fr_gethtablestat __P((iplookupop_t *)); + +#endif /* __IP_HTABLE_H__ */ diff --git a/contrib/ipfilter/ip_ipsec_pxy.c b/contrib/ipfilter/ip_ipsec_pxy.c index 40ce131..2159ecb 100644 --- a/contrib/ipfilter/ip_ipsec_pxy.c +++ b/contrib/ipfilter/ip_ipsec_pxy.c @@ -1,42 +1,90 @@ +/* $NetBSD$ */ + /* + * Copyright (C) 2001-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * * Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ipsec_pxy.c,v 1.1.2.10 2002/01/13 04:58:29 darrenr Exp $ + * Id: ip_ipsec_pxy.c,v 2.20.2.6 2005/03/28 10:47:53 darrenr Exp * */ #define IPF_IPSEC_PROXY int ippr_ipsec_init __P((void)); -int ippr_ipsec_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_ipsec_fini __P((void)); +int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *)); void ippr_ipsec_del __P((ap_session_t *)); -int ippr_ipsec_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *)); int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t ipsecfr; - - +static ipftq_t *ipsecnattqe; +static ipftq_t *ipsecstatetqe; static char ipsec_buffer[1500]; +int ipsec_proxy_init = 0; +int ipsec_proxy_ttl = 60; + /* - * RCMD application proxy initialization. + * IPSec application proxy initialization. */ int ippr_ipsec_init() { bzero((char *)&ipsecfr, sizeof(ipsecfr)); ipsecfr.fr_ref = 1; ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock"); + ipsec_proxy_init = 1; + + ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, ipsec_proxy_ttl); + if (ipsecnattqe == NULL) + return -1; + ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, ipsec_proxy_ttl); + if (ipsecstatetqe == NULL) { + if (fr_deletetimeoutqueue(ipsecnattqe) == 0) + fr_freetimeoutqueue(ipsecnattqe); + ipsecnattqe = NULL; + return -1; + } + + ipsecnattqe->ifq_flags |= IFQF_PROXY; + ipsecstatetqe->ifq_flags |= IFQF_PROXY; + + ipsecfr.fr_age[0] = ipsec_proxy_ttl; + ipsecfr.fr_age[1] = ipsec_proxy_ttl; return 0; } +void ippr_ipsec_fini() +{ + if (ipsecnattqe != NULL) { + if (fr_deletetimeoutqueue(ipsecnattqe) == 0) + fr_freetimeoutqueue(ipsecnattqe); + } + ipsecnattqe = NULL; + if (ipsecstatetqe != NULL) { + if (fr_deletetimeoutqueue(ipsecstatetqe) == 0) + fr_freetimeoutqueue(ipsecstatetqe); + } + ipsecstatetqe = NULL; + + if (ipsec_proxy_init == 1) { + MUTEX_DESTROY(&ipsecfr.fr_lock); + ipsec_proxy_init = 0; + } +} + + /* * Setup for a new IPSEC proxy. */ -int ippr_ipsec_new(fin, ip, aps, nat) +int ippr_ipsec_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { @@ -44,40 +92,22 @@ nat_t *nat; fr_info_t fi; ipnat_t *ipn; char *ptr; - int p, off, dlen; + int p, off, dlen, ttl; mb_t *m; + ip_t *ip; bzero(ipsec_buffer, sizeof(ipsec_buffer)); off = fin->fin_hlen + sizeof(udphdr_t); -#ifdef _KERNEL -# if SOLARIS - m = fin->fin_qfm; + ip = fin->fin_ip; + m = fin->fin_m; - dlen = msgdsize(m) - off; + dlen = M_LEN(m) - off; if (dlen < 16) return -1; - copyout_mblk(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); -# else - m = *(mb_t **)fin->fin_mp; - dlen = mbufchainlen(m) - off; - if (dlen < 16) - return -1; - m_copydata(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); -# endif -#else - m = *(mb_t **)fin->fin_mp; - dlen = ip->ip_len - off; - ptr = (char *)m; - ptr += off; - bcopy(ptr, ipsec_buffer, MIN(sizeof(ipsec_buffer), dlen)); -#endif + COPYDATA(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); - /* - * Because _new() gets called from nat_new(), ipf_nat is held with a - * write lock so pass rw=1 to nat_outlookup(). - */ if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip, - ip->ip_dst, 1) != NULL) + ip->ip_dst) != NULL) return -1; aps->aps_psiz = sizeof(*ipsec); @@ -94,7 +124,10 @@ nat_t *nat; * describe ESP but UDP instead. */ ipn = &ipsec->ipsc_rule; - ipn->in_ifp = fin->fin_ifp; + ttl = IPF_TTLVAL(ipsecnattqe->ifq_ttl); + ipn->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, ttl); + ipn->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, ttl); + ipn->in_ifps[0] = fin->fin_ifp; ipn->in_apr = NULL; ipn->in_use = 1; ipn->in_hits = 1; @@ -102,27 +135,31 @@ nat_t *nat; ipn->in_ippip = 1; ipn->in_inip = nat->nat_inip.s_addr; ipn->in_inmsk = 0xffffffff; - ipn->in_outip = nat->nat_outip.s_addr; - ipn->in_outmsk = 0xffffffff; + ipn->in_outip = fin->fin_saddr; + ipn->in_outmsk = nat->nat_outip.s_addr; ipn->in_srcip = fin->fin_saddr; ipn->in_srcmsk = 0xffffffff; ipn->in_redir = NAT_MAP; - bcopy(nat->nat_ptr->in_ifname, ipn->in_ifname, sizeof(ipn->in_ifname)); + bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0], + sizeof(ipn->in_ifnames[0])); ipn->in_p = IPPROTO_ESP; bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_state = NULL; + fi.fin_nat = NULL; fi.fin_fi.fi_p = IPPROTO_ESP; fi.fin_fr = &ipsecfr; fi.fin_data[0] = 0; fi.fin_data[1] = 0; p = ip->ip_p; ip->ip_p = IPPROTO_ESP; - fi.fin_fl &= ~FI_TCPUDP; + fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); + fi.fin_flx |= FI_IGNORE; ptr = ipsec_buffer; - bcopy(ptr, ipsec->ipsc_icookie, sizeof(ipsec_cookie_t)); + bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t)); ptr += sizeof(ipsec_cookie_t); - bcopy(ptr, ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t)); + bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t)); /* * The responder cookie should only be non-zero if the initiator * cookie is non-zero. Therefore, it is safe to assume(!) that the @@ -130,76 +167,101 @@ nat_t *nat; */ if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0) ipsec->ipsc_rckset = 1; - else - nat->nat_age = 60; /* 30 seconds */ - ipsec->ipsc_nat = nat_new(&fi, ip, ipn, &ipsec->ipsc_nat, FI_IGNOREPKT, - NAT_OUTBOUND); + ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat, + NAT_SLAVE|SI_WILDP, NAT_OUTBOUND); if (ipsec->ipsc_nat != NULL) { + (void) nat_proto(&fi, ipsec->ipsc_nat, 0); + nat_update(&fi, ipsec->ipsc_nat, ipn); + fi.fin_data[0] = 0; fi.fin_data[1] = 0; - ipsec->ipsc_state = fr_addstate(ip, &fi, &ipsec->ipsc_state, - FI_IGNOREPKT|FI_NORULE); + ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state, + SI_WILDP); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); } - ip->ip_p = p; + ip->ip_p = p & 0xff; return 0; } /* - * For outgoing IKE packets. refresh timeouts for NAT & stat entries, if + * For outgoing IKE packets. refresh timeouts for NAT & state entries, if * we can. If they have disappeared, recreate them. */ -int ippr_ipsec_out(fin, ip, aps, nat) +int ippr_ipsec_inout(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { ipsec_pxy_t *ipsec; fr_info_t fi; + ip_t *ip; int p; - bcopy((char *)fin, (char *)&fi, sizeof(fi)); - fi.fin_fi.fi_p = IPPROTO_ESP; - fi.fin_fr = &ipsecfr; - fi.fin_data[0] = 0; - fi.fin_data[1] = 0; - p = ip->ip_p; - ip->ip_p = IPPROTO_ESP; - fi.fin_fl &= ~FI_TCPUDP; + if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) + return 0; + + if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) + return 0; ipsec = aps->aps_data; + if (ipsec != NULL) { + ip = fin->fin_ip; + p = ip->ip_p; + + if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) { + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_fi.fi_p = IPPROTO_ESP; + fi.fin_fr = &ipsecfr; + fi.fin_data[0] = 0; + fi.fin_data[1] = 0; + ip->ip_p = IPPROTO_ESP; + fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); + fi.fin_flx |= FI_IGNORE; + } + /* * Update NAT timeout/create NAT if missing. */ - if (ipsec->ipsc_rckset == 0) - nat->nat_age = 60; /* 30 seconds */ if (ipsec->ipsc_nat != NULL) - ipsec->ipsc_nat->nat_age = nat->nat_age; - else - ipsec->ipsc_nat = nat_new(&fi, ip, &ipsec->ipsc_rule, + fr_queueback(&ipsec->ipsc_nat->nat_tqe); + else { + ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule, &ipsec->ipsc_nat, - FI_IGNOREPKT, NAT_OUTBOUND); + NAT_SLAVE|SI_WILDP, + nat->nat_dir); + if (ipsec->ipsc_nat != NULL) { + (void) nat_proto(&fi, ipsec->ipsc_nat, 0); + nat_update(&fi, ipsec->ipsc_nat, + &ipsec->ipsc_rule); + } + } /* * Update state timeout/create state if missing. */ READ_ENTER(&ipf_state); if (ipsec->ipsc_state != NULL) { - ipsec->ipsc_state->is_age = nat->nat_age; + fr_queueback(&ipsec->ipsc_state->is_sti); + ipsec->ipsc_state->is_die = nat->nat_age; RWLOCK_EXIT(&ipf_state); } else { RWLOCK_EXIT(&ipf_state); fi.fin_data[0] = 0; fi.fin_data[1] = 0; - ipsec->ipsc_state = fr_addstate(ip, &fi, + ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state, - FI_IGNOREPKT|FI_NORULE); + SI_WILDP); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); } + ip->ip_p = p; } - ip->ip_p = p; return 0; } @@ -220,24 +282,15 @@ nat_t *nat; mb_t *m; int off; - if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_fl & FI_FRAG)) + nat = nat; /* LINT */ + + if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG)) return -1; ipsec = aps->aps_data; off = fin->fin_hlen + sizeof(udphdr_t); -#ifdef _KERNEL -# if SOLARIS - m = fin->fin_qfm; - - copyout_mblk(m, off, sizeof(cookies), (char *)cookies); -# else - m = *(mb_t **)fin->fin_mp; - m_copydata(m, off, sizeof(cookies), (char *)cookies); -# endif -#else - m = *(mb_t **)fin->fin_mp; - bcopy((char *)m + off, cookies, sizeof(cookies)); -#endif + m = fin->fin_m; + COPYDATA(m, off, sizeof(cookies), (char *)cookies); if ((cookies[0] != ipsec->ipsc_icookie[0]) || (cookies[1] != ipsec->ipsc_icookie[1])) @@ -245,7 +298,6 @@ nat_t *nat; if (ipsec->ipsc_rckset == 0) { if ((cookies[2]|cookies[3]) == 0) { - nat->nat_age = 60; /* 30 seconds */ return 0; } ipsec->ipsc_rckset = 1; @@ -273,17 +325,16 @@ ap_session_t *aps; if (ipsec != NULL) { /* - * Don't delete it from here, just schedule it to be - * deleted ASAP. + * Don't bother changing any of the NAT structure details, + * *_del() is on a callback from aps_free(), from nat_delete() */ - if (ipsec->ipsc_nat != NULL) { - ipsec->ipsc_nat->nat_age = 1; - ipsec->ipsc_nat->nat_ptr = NULL; - } READ_ENTER(&ipf_state); - if (ipsec->ipsc_state != NULL) - ipsec->ipsc_state->is_age = 1; + if (ipsec->ipsc_state != NULL) { + ipsec->ipsc_state->is_die = fr_ticks + 1; + ipsec->ipsc_state->is_me = NULL; + fr_queuefront(&ipsec->ipsc_state->is_sti); + } RWLOCK_EXIT(&ipf_state); ipsec->ipsc_state = NULL; diff --git a/contrib/ipfilter/ip_irc_pxy.c b/contrib/ipfilter/ip_irc_pxy.c new file mode 100644 index 0000000..45a120f --- /dev/null +++ b/contrib/ipfilter/ip_irc_pxy.c @@ -0,0 +1,435 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2000-2003 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ip_irc_pxy.c,v 2.39.2.4 2005/02/04 10:22:55 darrenr Exp + */ + +#define IPF_IRC_PROXY + +#define IPF_IRCBUFSZ 96 /* This *MUST* be >= 64! */ + + +int ippr_irc_init __P((void)); +void ippr_irc_fini __P((void)); +int ippr_irc_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_irc_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_irc_send __P((fr_info_t *, nat_t *)); +int ippr_irc_complete __P((ircinfo_t *, char *, size_t)); +u_short ipf_irc_atoi __P((char **)); + +static frentry_t ircnatfr; + +int irc_proxy_init = 0; + + +/* + * Initialize local structures. + */ +int ippr_irc_init() +{ + bzero((char *)&ircnatfr, sizeof(ircnatfr)); + ircnatfr.fr_ref = 1; + ircnatfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&ircnatfr.fr_lock, "IRC proxy rule lock"); + irc_proxy_init = 1; + + return 0; +} + + +void ippr_irc_fini() +{ + if (irc_proxy_init == 1) { + MUTEX_DESTROY(&ircnatfr.fr_lock); + irc_proxy_init = 0; + } +} + + +char *ippr_irc_dcctypes[] = { + "CHAT ", /* CHAT chat ipnumber portnumber */ + "SEND ", /* SEND filename ipnumber portnumber */ + "MOVE ", + "TSEND ", + "SCHAT ", + NULL, +}; + + +/* + * :A PRIVMSG B :^ADCC CHAT chat 0 0^A\r\n + * PRIVMSG B ^ADCC CHAT chat 0 0^A\r\n + */ + + +int ippr_irc_complete(ircp, buf, len) +ircinfo_t *ircp; +char *buf; +size_t len; +{ + register char *s, c; + register size_t i; + u_32_t l; + int j, k; + + ircp->irc_ipnum = 0; + ircp->irc_port = 0; + + if (len < 31) + return 0; + s = buf; + c = *s++; + i = len - 1; + + if ((c != ':') && (c != 'P')) + return 0; + + if (c == ':') { + /* + * Loosely check that the source is a nickname of some sort + */ + s++; + c = *s; + ircp->irc_snick = s; + if (!ISALPHA(c)) + return 0; + i--; + for (c = *s; !ISSPACE(c) && (i > 0); i--) + c = *s++; + if (i < 31) + return 0; + if (c != 'P') + return 0; + } else + ircp->irc_snick = NULL; + + /* + * Check command string + */ + if (strncmp(s, "PRIVMSG ", 8)) + return 0; + i -= 8; + s += 8; + c = *s; + ircp->irc_dnick = s; + + /* + * Loosely check that the destination is a nickname of some sort + */ + if (!ISALPHA(c)) + return 0; + for (; !ISSPACE(c) && (i > 0); i--) + c = *s++; + if (i < 20) + return 0; + s++, + i--; + + /* + * Look for a ^A to start the DCC + */ + c = *s; + if (c == ':') { + s++; + c = *s; + } + + if (strncmp(s, "\001DCC ", 4)) + return 0; + + i -= 4; + s += 4; + + /* + * Check for a recognised DCC command + */ + for (j = 0, k = 0; ippr_irc_dcctypes[j]; j++) { + k = MIN(strlen(ippr_irc_dcctypes[j]), i); + if (!strncmp(ippr_irc_dcctypes[j], s, k)) + break; + } + if (!ippr_irc_dcctypes[j]) + return 0; + + ircp->irc_type = s; + i -= k; + s += k; + + if (i < 11) + return 0; + + /* + * Check for the arg + */ + c = *s; + if (ISSPACE(c)) + return 0; + ircp->irc_arg = s; + for (; (c != ' ') && (c != '\001') && (i > 0); i--) + c = *s++; + + if (c == '\001') /* In reality a ^A can quote another ^A...*/ + return 0; + + if (i < 5) + return 0; + + s++; + i--; + c = *s; + if (!ISDIGIT(c)) + return 0; + ircp->irc_addr = s; + /* + * Get the IP# + */ + for (l = 0; ISDIGIT(c) && (i > 0); i--) { + l *= 10; + l += c - '0'; + c = *s++; + } + + if (i < 4) + return 0; + + if (c != ' ') + return 0; + + ircp->irc_ipnum = l; + s++; + i--; + c = *s; + if (!ISDIGIT(c)) + return 0; + /* + * Get the port# + */ + for (l = 0; ISDIGIT(c) && (i > 0); i--) { + l *= 10; + l += c - '0'; + c = *s++; + } + if (i < 3) + return 0; + if (strncmp(s, "\001\r\n", 3)) + return 0; + s += 3; + ircp->irc_len = s - buf; + ircp->irc_port = l; + return 1; +} + + +int ippr_irc_new(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + ircinfo_t *irc; + + KMALLOC(irc, ircinfo_t *); + if (irc == NULL) + return -1; + + fin = fin; /* LINT */ + nat = nat; /* LINT */ + + aps->aps_data = irc; + aps->aps_psiz = sizeof(ircinfo_t); + + bzero((char *)irc, sizeof(*irc)); + return 0; +} + + +int ippr_irc_send(fin, nat) +fr_info_t *fin; +nat_t *nat; +{ + char ctcpbuf[IPF_IRCBUFSZ], newbuf[IPF_IRCBUFSZ]; + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + int off, inc = 0, i, dlen; + size_t nlen = 0, olen; + struct in_addr swip; + u_short a5, sp; + ircinfo_t *irc; + fr_info_t fi; + nat_t *nat2; + u_int a1; + ip_t *ip; + mb_t *m; +#ifdef MENTAT + mb_t *m1; +#endif + + m = fin->fin_m; + ip = fin->fin_ip; + tcp = (tcphdr_t *)fin->fin_dp; + bzero(ctcpbuf, sizeof(ctcpbuf)); + off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; + +#ifdef __sgi + dlen = fin->fin_plen - off; +#else + dlen = MSGDSIZE(m) - off; +#endif + if (dlen <= 0) + return 0; + COPYDATA(m, off, MIN(sizeof(ctcpbuf), dlen), ctcpbuf); + + if (dlen <= 0) + return 0; + ctcpbuf[sizeof(ctcpbuf) - 1] = '\0'; + *newbuf = '\0'; + + irc = nat->nat_aps->aps_data; + if (ippr_irc_complete(irc, ctcpbuf, dlen) == 0) + 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. + */ + if (irc->irc_ipnum != ntohl(nat->nat_inip.s_addr)) + return 0; + + a5 = irc->irc_port; + + /* + * Calculate new address parts for the DCC command + */ + a1 = ntohl(ip->ip_src.s_addr); + olen = irc->irc_len; + i = irc->irc_addr - ctcpbuf; + i++; + (void) strncpy(newbuf, ctcpbuf, i); + /* DO NOT change these! */ +#if defined(SNPRINTF) && defined(KERNEL) + SNPRINTF(newbuf, sizeof(newbuf) - i, "%u %u\001\r\n", a1, a5); +#else + (void) sprintf(newbuf, "%u %u\001\r\n", a1, a5); +#endif + + nlen = strlen(newbuf); + inc = nlen - olen; + + if ((inc + ip->ip_len) > 65535) + return 0; + +#ifdef MENTAT + for (m1 = m; m1->b_cont; m1 = m1->b_cont) + ; + if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { + mblk_t *nm; + + /* alloc enough to keep same trailer space for lower driver */ + nm = allocb(nlen, BPRI_MED); + PANIC((!nm),("ippr_irc_out: allocb failed")); + + nm->b_band = m1->b_band; + nm->b_wptr += nlen; + + m1->b_wptr -= olen; + PANIC((m1->b_wptr < m1->b_rptr), + ("ippr_irc_out: cannot handle fragmented data block")); + + linkb(m1, nm); + } else { +# if SOLARIS && defined(ICK_VALID) + if (m1->b_datap->db_struiolim == m1->b_wptr) + m1->b_datap->db_struiolim += inc; + m1->b_datap->db_struioflag &= ~STRUIO_IP; +# endif + m1->b_wptr += inc; + } +#else + if (inc < 0) + m_adj(m, inc); + /* the mbuf chain will be extended if necessary by m_copyback() */ +#endif + COPYBACK(m, off, nlen, newbuf); + + if (inc != 0) { +#if defined(MENTAT) || defined(__sgi) + register u_32_t sum1, sum2; + + sum1 = ip->ip_len; + sum2 = ip->ip_len + inc; + + /* Because ~1 == -2, We really need ~1 == -1 */ + if (sum1 > sum2) + sum2--; + sum2 -= sum1; + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + + fix_outcksum(fin, &ip->ip_sum, sum2); +#endif + ip->ip_len += inc; + } + + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + sp = htons(a5); + /* + * 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. + */ + bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi)); + fi.fin_data[0] = sp; + fi.fin_data[1] = fin->fin_data[1]; + nat2 = nat_outlookup(fin, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst); + if (nat2 == NULL) { + bcopy((caddr_t)fin, (caddr_t)&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 */ + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_data[0] = ntohs(sp); + fi.fin_data[1] = 0; + fi.fin_dp = (char *)tcp2; + fi.fin_fr = &ircnatfr; + fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); + swip = ip->ip_src; + ip->ip_src = nat->nat_inip; + nat2 = nat_new(&fi, nat->nat_ptr, NULL, + NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, 0); + nat_update(&fi, nat2, nat2->nat_ptr); + + (void) fr_addstate(&fi, NULL, SI_W_DPORT); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + } + ip->ip_src = swip; + } + return inc; +} + + +int ippr_irc_out(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + aps = aps; /* LINT */ + return ippr_irc_send(fin, nat); +} diff --git a/contrib/ipfilter/ip_log.c b/contrib/ipfilter/ip_log.c index 3628a58..1243081 100644 --- a/contrib/ipfilter/ip_log.c +++ b/contrib/ipfilter/ip_log.c @@ -1,144 +1,177 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1997-2001 by Darren Reed. + * Copyright (C) 1997-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_log.c,v 2.5.2.26 2004/06/20 01:59:01 darrenr Exp $ + * Id: ip_log.c,v 2.75.2.6 2004/10/16 07:59:27 darrenr Exp */ #include <sys/param.h> -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ defined(_KERNEL) # include "opt_ipfilter_log.h" #endif -#ifdef __FreeBSD__ -# if defined(_KERNEL) && !defined(IPFILTER_LKM) +#if defined(__FreeBSD__) && !defined(IPFILTER_LKM) +# if defined(_KERNEL) # if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) # include "opt_ipfilter.h" # endif # else -# ifdef KLD_MODULE -# ifndef __FreeBSD_cc_version -# include <osreldate.h> -# else -# if __FreeBSD_cc_version < 430000 -# include <osreldate.h> -# endif -# endif -# endif +# include <osreldate.h> # endif #endif -#ifdef IPFILTER_LOG -# ifndef SOLARIS -# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#ifndef SOLARIS +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/file.h> +#ifndef _KERNEL +# include <stdio.h> +# include <string.h> +# include <stdlib.h> +# include <ctype.h> +# define _KERNEL +# define KERNEL +# ifdef __OpenBSD__ +struct file; # endif -# ifndef _KERNEL -# include <stdio.h> -# include <string.h> -# include <stdlib.h> -# include <ctype.h> +# include <sys/uio.h> +# undef _KERNEL +# undef KERNEL +#endif +#if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include <sys/fcntl.h> +# include <sys/filio.h> +#else +# include <sys/ioctl.h> +#endif +#include <sys/time.h> +#if defined(_KERNEL) +# include <sys/systm.h> +# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) +# include <sys/proc.h> # endif -# include <sys/errno.h> -# include <sys/types.h> -# include <sys/file.h> -# if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include <sys/fcntl.h> -# include <sys/filio.h> +#endif /* _KERNEL */ +#if !SOLARIS && !defined(__hpux) && !defined(linux) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) +# include <sys/dirent.h> # else -# include <sys/ioctl.h> -# endif -# include <sys/time.h> -# if defined(_KERNEL) -# include <sys/systm.h> +# include <sys/dir.h> # endif -# if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) -# include <sys/dirent.h> -# else -# include <sys/dir.h> -# endif -# include <sys/mbuf.h> -# else +# include <sys/mbuf.h> +#else +# if !defined(__hpux) && defined(_KERNEL) # include <sys/filio.h> # include <sys/cred.h> +# include <sys/ddi.h> +# include <sys/sunddi.h> +# include <sys/ksynch.h> # include <sys/kmem.h> -# ifdef _KERNEL -# include <sys/ddi.h> -# include <sys/sunddi.h> -# include <sys/ksynch.h> -# include <sys/dditypes.h> -# include <sys/cmn_err.h> -# endif -# endif +# include <sys/mkdev.h> +# include <sys/dditypes.h> +# include <sys/cmn_err.h> +# endif /* !__hpux */ +#endif /* !SOLARIS && !__hpux */ +#if !defined(linux) # include <sys/protosw.h> -# include <sys/socket.h> +#endif +#include <sys/socket.h> -# include <net/if.h> -# ifdef sun -# include <net/af.h> -# endif -# if __FreeBSD_version >= 300000 -# include <net/if_var.h> -# endif -# include <net/route.h> -# include <netinet/in.h> -# ifdef __sgi -# define _KMEMUSER -# include <sys/ddi.h> -# ifdef IFF_DRVRLOCK /* IRIX6 */ -# include <sys/hashing.h> -# endif -# endif -# if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ -# include <netinet/in_var.h> -# endif -# include <netinet/in_systm.h> -# include <netinet/ip.h> -# include <netinet/tcp.h> -# include <netinet/udp.h> -# include <netinet/ip_icmp.h> -# ifdef USE_INET6 -# include <netinet/icmp6.h> +#include <net/if.h> +#ifdef sun +# include <net/af.h> +#endif +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#include <net/route.h> +#include <netinet/in.h> +#ifdef __sgi +# include <sys/ddi.h> +# ifdef IFF_DRVRLOCK /* IRIX6 */ +# include <sys/hashing.h> # endif +#endif +#if !defined(__hpux) && !defined(linux) && \ + !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ +# include <netinet/in_var.h> +#endif +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/ip_icmp.h> +#ifdef USE_INET6 +# include <netinet/icmp6.h> +#endif +#if !defined(linux) # include <netinet/ip_var.h> -# ifndef _KERNEL -# include <syslog.h> -# endif -# include "netinet/ip_compat.h" -# include <netinet/tcpip.h> -# include "netinet/ip_fil.h" -# if (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -# endif +#endif +#ifndef _KERNEL +# include <syslog.h> +#endif +#include "netinet/ip_compat.h" +#include <netinet/tcpip.h> +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_auth.h" +#if (__FreeBSD_version >= 300000) || defined(__NetBSD__) +# include <sys/malloc.h> +#endif +/* END OF INCLUDES */ -# ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -# endif -# ifdef IPFILTER_LOGSIZE -# undef IPLLOGSIZE -# define IPLLOGSIZE IPFILTER_LOGSIZE -# endif +#ifdef IPFILTER_LOG +# if defined(IPL_SELECT) +# include <machine/sys/user.h> +# include <sys/kthread_iface.h> +# define READ_COLLISION 0x001 -# if SOLARIS || defined(__sgi) -extern kmutex_t ipl_mutex; -# if SOLARIS +iplog_select_t iplog_ss[IPL_LOGMAX+1]; + +extern int selwait; +# endif /* IPL_SELECT */ + +# if defined(linux) && defined(_KERNEL) +wait_queue_head_t iplh_linux[IPL_LOGSIZE]; +# endif +# if SOLARIS extern kcondvar_t iplwait; -# endif # endif -iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; -size_t iplused[IPL_LOGMAX+1]; -static fr_info_t iplcrc[IPL_LOGMAX+1]; +iplog_t **iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE]; +int iplused[IPL_LOGSIZE]; +static fr_info_t iplcrc[IPL_LOGSIZE]; +int ipl_suppress = 1; +int ipl_buffer_sz; +int ipl_logmax = IPL_LOGMAX; +int ipl_logall = 0; +int ipl_log_init = 0; +int ipl_logsize = IPFILTER_LOGSIZE; +int ipl_magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE, + IPL_MAGIC, IPL_MAGIC, IPL_MAGIC, + IPL_MAGIC, IPL_MAGIC }; -/* - * Initialise log buffers & pointers. Also iniialised the CRC to a local - * secret for use in calculating the "last log checksum". - */ -void ipflog_init() +/* ------------------------------------------------------------------------ */ +/* Function: fr_loginit */ +/* Returns: int - 0 == success (always returned) */ +/* Parameters: Nil */ +/* */ +/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ +/* secret for use in calculating the "last log checksum". */ +/* ------------------------------------------------------------------------ */ +int fr_loginit() { int i; @@ -148,40 +181,88 @@ void ipflog_init() iplh[i] = &iplt[i]; iplused[i] = 0; bzero((char *)&iplcrc[i], sizeof(iplcrc[i])); +# ifdef IPL_SELECT + iplog_ss[i].read_waiter = 0; + iplog_ss[i].state = 0; +# endif +# if defined(linux) && defined(_KERNEL) + init_waitqueue_head(iplh_linux + i); +# endif } + +# if SOLARIS && defined(_KERNEL) + cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL); +# endif + MUTEX_INIT(&ipl_mutex, "ipf log mutex"); + + ipl_log_init = 1; + + return 0; } -/* - * ipflog - * Create a log record for a packet given that it has been triggered by a - * rule (or the default setting). Calculate the transport protocol header - * size using predetermined size of a couple of popular protocols and thus - * how much data to copy into the log, including part of the data body if - * requested. - */ -int ipflog(flags, ip, fin, m) -u_int flags; -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_logunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Clean up any log data that has accumulated without being read. */ +/* ------------------------------------------------------------------------ */ +void fr_logunload() +{ + int i; + + if (ipl_log_init == 0) + return; + + for (i = IPL_LOGMAX; i >= 0; i--) + (void) ipflog_clear(i); + +# if SOLARIS && defined(_KERNEL) + cv_destroy(&iplwait); +# endif + MUTEX_DESTROY(&ipl_mutex); + + ipl_log_init = 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipflog */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: fin(I) - pointer to packet information */ +/* flags(I) - flags from filter rules */ +/* */ +/* Create a log record for a packet given that it has been triggered by a */ +/* rule (or the default setting). Calculate the transport protocol header */ +/* size using predetermined size of a couple of popular protocols and thus */ +/* how much data to copy into the log, including part of the data body if */ +/* requested. */ +/* ------------------------------------------------------------------------ */ +int ipflog(fin, flags) fr_info_t *fin; -mb_t *m; +u_int flags; { - ipflog_t ipfl; - register size_t mlen, hlen; + register size_t hlen; + int types[2], mlen; size_t sizes[2]; void *ptrs[2]; - int types[2]; + ipflog_t ipfl; u_char p; -# if SOLARIS && defined(_KERNEL) - ill_t *ifp = fin->fin_ifp; + mb_t *m; +# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) + qif_t *ifp; # else - struct ifnet *ifp = fin->fin_ifp; -# endif + struct ifnet *ifp; +# endif /* SOLARIS || __hpux */ + ipfl.fl_nattag.ipt_num[0] = 0; + m = fin->fin_m; + ifp = fin->fin_ifp; + hlen = fin->fin_hlen; /* * calculate header size. */ - hlen = fin->fin_hlen; if (fin->fin_off == 0) { p = fin->fin_fi.fi_p; if (p == IPPROTO_TCP) @@ -192,7 +273,7 @@ mb_t *m; struct icmp *icmp; icmp = (struct icmp *)fin->fin_dp; - + /* * For ICMP, if the packet is an error packet, also * include the information about the packet which @@ -214,12 +295,12 @@ mb_t *m; break; } } -#ifdef USE_INET6 +# ifdef USE_INET6 else if (p == IPPROTO_ICMPV6) { struct icmp6_hdr *icmp; icmp = (struct icmp6_hdr *)fin->fin_dp; - + /* * For ICMPV6, if the packet is an error packet, also * include the information about the packet which @@ -233,53 +314,71 @@ mb_t *m; fin->fin_dlen); } } -#endif +# endif } /* * Get the interface number and name to which this packet is * currently associated. */ - bzero((char *)ipfl.fl_ifname, sizeof(ipfl.fl_ifname)); -# if SOLARIS && defined(_KERNEL) - ipfl.fl_unit = (u_int)ifp->ill_ppa; - bcopy(ifp->ill_name, ipfl.fl_ifname, - MIN(ifp->ill_name_length, sizeof(ipfl.fl_ifname))); - mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0; +# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) + ipfl.fl_unit = (u_int)ifp->qf_ppa; + COPYIFNAME(ifp, ipfl.fl_ifname); # else # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) - strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ); + COPYIFNAME(ifp, ipfl.fl_ifname); # else ipfl.fl_unit = (u_int)ifp->if_unit; - strncpy(ipfl.fl_ifname, ifp->if_name, MIN(sizeof(ipfl.fl_ifname), - sizeof(ifp->if_name))); +# if defined(_KERNEL) + if ((ipfl.fl_ifname[0] = ifp->if_name[0])) + if ((ipfl.fl_ifname[1] = ifp->if_name[1])) + if ((ipfl.fl_ifname[2] = ifp->if_name[2])) + ipfl.fl_ifname[3] = ifp->if_name[3]; +# else + (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); + ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; +# endif # endif - mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0; -# endif +# endif /* __hpux || SOLARIS */ + mlen = fin->fin_plen - hlen; + if (!ipl_logall) { + mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; + } else if ((flags & FR_LOGBODY) == 0) { + mlen = 0; + } + if (mlen < 0) + mlen = 0; ipfl.fl_plen = (u_char)mlen; ipfl.fl_hlen = (u_char)hlen; ipfl.fl_rule = fin->fin_rule; - ipfl.fl_group = fin->fin_group; - if (fin->fin_fr != NULL) + (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); + if (fin->fin_fr != NULL) { ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; - else + ipfl.fl_logtag = fin->fin_fr->fr_logtag; + } else { ipfl.fl_loglevel = 0xffff; + ipfl.fl_logtag = FR_NOLOGTAG; + } + if (fin->fin_nattag != NULL) + bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, + sizeof(ipfl.fl_nattag)); ipfl.fl_flags = flags; ipfl.fl_dir = fin->fin_out; + ipfl.fl_lflags = fin->fin_flx; ptrs[0] = (void *)&ipfl; sizes[0] = sizeof(ipfl); types[0] = 0; -# if SOLARIS && defined(_KERNEL) +# if defined(MENTAT) && defined(_KERNEL) /* * Are we copied from the mblk or an aligned array ? */ - if (ip == (ip_t *)m->b_rptr) { + if (fin->fin_ip == (ip_t *)m->b_rptr) { ptrs[1] = m; sizes[1] = hlen + mlen; types[1] = 1; } else { - ptrs[1] = ip; + ptrs[1] = fin->fin_ip; sizes[1] = hlen + mlen; types[1] = 0; } @@ -287,14 +386,25 @@ mb_t *m; ptrs[1] = m; sizes[1] = hlen + mlen; types[1] = 1; -# endif +# endif /* MENTAT */ return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); } -/* - * ipllog - */ +/* ------------------------------------------------------------------------ */ +/* Function: ipllog */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: dev(I) - device that owns this log record */ +/* fin(I) - pointer to packet information */ +/* items(I) - array of pointers to log data */ +/* itemsz(I) - array of size of valid memory pointed to */ +/* types(I) - type of data pointed to by items pointers */ +/* cnt(I) - number of elements in arrays items/itemsz/types */ +/* */ +/* Takes an array of parameters and constructs one record to include the */ +/* miscellaneous packet information, as well as packet data, for reading */ +/* from the log device. */ +/* ------------------------------------------------------------------------ */ int ipllog(dev, fin, items, itemsz, types, cnt) int dev; fr_info_t *fin; @@ -302,33 +412,39 @@ void **items; size_t *itemsz; int *types, cnt; { - caddr_t buf, s; + caddr_t buf, ptr; iplog_t *ipl; size_t len; int i; - +# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) + int s; +# endif + /* * Check to see if this log record has a CRC which matches the last * record logged. If it does, just up the count on the previous one * rather than create a new one. */ - MUTEX_ENTER(&ipl_mutex); - if ((fin != NULL) && (fin->fin_off == 0)) { - if ((ipll[dev] != NULL) && - bcmp((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE) == 0) { - ipll[dev]->ipl_count++; - MUTEX_EXIT(&ipl_mutex); - return 1; - } - bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE); - } else - bzero((char *)&iplcrc[dev], FI_LCSIZE); - MUTEX_EXIT(&ipl_mutex); + if (ipl_suppress) { + MUTEX_ENTER(&ipl_mutex); + if ((fin != NULL) && (fin->fin_off == 0)) { + if ((ipll[dev] != NULL) && + bcmp((char *)fin, (char *)&iplcrc[dev], + FI_LCSIZE) == 0) { + ipll[dev]->ipl_count++; + MUTEX_EXIT(&ipl_mutex); + return 0; + } + bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE); + } else + bzero((char *)&iplcrc[dev], FI_CSIZE); + MUTEX_EXIT(&ipl_mutex); + } /* * Get the total amount of data to be logged. */ - for (i = 0, len = IPLOG_SIZE; i < cnt; i++) + for (i = 0, len = sizeof(iplog_t); i < cnt; i++) len += itemsz[i]; /* @@ -336,70 +452,85 @@ int *types, cnt; * allocate that much. */ KMALLOCS(buf, caddr_t, len); - if (!buf) - return 0; + if (buf == NULL) + return -1; + SPL_NET(s); MUTEX_ENTER(&ipl_mutex); - if ((iplused[dev] + len) > IPLLOGSIZE) { + if ((iplused[dev] + len) > ipl_logsize) { MUTEX_EXIT(&ipl_mutex); + SPL_X(s); KFREES(buf, len); - return 0; + return -1; } iplused[dev] += len; MUTEX_EXIT(&ipl_mutex); + SPL_X(s); /* * advance the log pointer to the next empty record and deduct the * amount of space we're going to use. */ ipl = (iplog_t *)buf; - ipl->ipl_magic = IPL_MAGIC; + ipl->ipl_magic = ipl_magic[dev]; ipl->ipl_count = 1; ipl->ipl_next = NULL; ipl->ipl_dsize = len; -# ifdef _KERNEL -# if SOLARIS || defined(sun) - uniqtime(&ipl->ipl_tv); -# else -# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) - microtime(&ipl->ipl_tv); -# endif -# endif -# else +#ifdef _KERNEL + GETKTIME(&ipl->ipl_sec); +#else ipl->ipl_sec = 0; ipl->ipl_usec = 0; -# endif +#endif /* * Loop through all the items to be logged, copying each one to the * buffer. Use bcopy for normal data or the mb_t copyout routine. */ - for (i = 0, s = buf + IPLOG_SIZE; i < cnt; i++) { - if (types[i] == 0) - bcopy(items[i], s, itemsz[i]); - else if (types[i] == 1) { -# if SOLARIS && defined(_KERNEL) - copyout_mblk(items[i], 0, itemsz[i], s); -# else - m_copydata(items[i], 0, itemsz[i], s); -# endif + for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { + if (types[i] == 0) { + bcopy(items[i], ptr, itemsz[i]); + } else if (types[i] == 1) { + COPYDATA(items[i], 0, itemsz[i], ptr); } - s += itemsz[i]; + ptr += itemsz[i]; } + SPL_NET(s); MUTEX_ENTER(&ipl_mutex); ipll[dev] = ipl; *iplh[dev] = ipl; iplh[dev] = &ipl->ipl_next; + + /* + * Now that the log record has been completed and added to the queue, + * wake up any listeners who may want to read it. + */ # if SOLARIS && defined(_KERNEL) cv_signal(&iplwait); - mutex_exit(&ipl_mutex); + MUTEX_EXIT(&ipl_mutex); # else MUTEX_EXIT(&ipl_mutex); - WAKEUP(&iplh[dev]); + WAKEUP(iplh,dev); +# endif + SPL_X(s); +# ifdef IPL_SELECT + iplog_input_ready(dev); # endif - return 1; + return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: ipflog_read */ +/* Returns: int - 0 == success, else error value. */ +/* Parameters: unit(I) - device we are reading from */ +/* uio(O) - pointer to information about where to store data */ +/* */ +/* Called to handle a read on an IPFilter device. Returns only complete */ +/* log messages - will not partially copy a log record out to userland. */ +/* */ +/* NOTE: This function will block and wait for a signal to return data if */ +/* there is none present. Asynchronous I/O is not implemented. */ +/* ------------------------------------------------------------------------ */ int ipflog_read(unit, uio) minor_t unit; struct uio *uio; @@ -407,7 +538,7 @@ struct uio *uio; size_t dlen, copied; int error = 0; iplog_t *ipl; -# if defined(_KERNEL) && !SOLARIS +# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) int s; # endif @@ -417,11 +548,12 @@ struct uio *uio; */ if (IPL_LOGMAX < unit) return ENXIO; - if (!uio->uio_resid) + if (uio->uio_resid == 0) return 0; - if (uio->uio_resid < IPLOG_SIZE) + if ((uio->uio_resid < sizeof(iplog_t)) || + (uio->uio_resid > ipl_logsize)) return EINVAL; - + /* * Lock the log so we can snapshot the variables. Wait for a signal * if the log is empty. @@ -431,26 +563,48 @@ struct uio *uio; while (iplt[unit] == NULL) { # if SOLARIS && defined(_KERNEL) - if (!cv_wait_sig(&iplwait, &ipl_mutex)) { + if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) { MUTEX_EXIT(&ipl_mutex); return EINTR; } # else +# if defined(__hpux) && defined(_KERNEL) + lock_t *l; + +# ifdef IPL_SELECT + if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { + /* this is no blocking system call */ + MUTEX_EXIT(&ipl_mutex); + return 0; + } +# endif + MUTEX_EXIT(&ipl_mutex); - error = SLEEP(&iplh[unit], "ipl sleep"); - if (error) { - SPL_X(s); + l = get_sleep_lock(&iplh[unit]); + error = sleep(&iplh[unit], PZERO+1); + spinunlock(l); +# else +# if defined(__osf__) && defined(_KERNEL) + error = mpsleep(&iplh[unit], PSUSP|PCATCH, "iplread", 0, + &ipl_mutex, MS_LOCK_SIMPLE); +# else + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); + error = SLEEP(unit + iplh, "ipl sleep"); +# endif /* __osf__ */ +# endif /* __hpux */ + if (error) return error; - } + SPL_NET(s); MUTEX_ENTER(&ipl_mutex); # endif /* SOLARIS */ } -# if BSD >= 199306 || defined(__FreeBSD__) +# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__) uio->uio_rw = UIO_READ; # endif - for (copied = 0; (ipl = iplt[unit]); copied += dlen) { + for (copied = 0; (ipl = iplt[unit]) != NULL; copied += dlen) { dlen = ipl->ipl_dsize; if (dlen > uio->uio_resid) break; @@ -460,15 +614,19 @@ struct uio *uio; iplt[unit] = ipl->ipl_next; iplused[unit] -= dlen; MUTEX_EXIT(&ipl_mutex); + SPL_X(s); error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); - MUTEX_ENTER(&ipl_mutex); if (error) { + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); ipl->ipl_next = iplt[unit]; iplt[unit] = ipl; iplused[unit] += dlen; break; } + MUTEX_ENTER(&ipl_mutex); KFREES((caddr_t)ipl, dlen); + SPL_NET(s); } if (!iplt[unit]) { iplused[unit] = 0; @@ -482,14 +640,25 @@ struct uio *uio; } +/* ------------------------------------------------------------------------ */ +/* Function: ipflog_clear */ +/* Returns: int - number of log bytes cleared. */ +/* Parameters: unit(I) - device we are reading from */ +/* */ +/* Deletes all queued up log records for a given output device. */ +/* ------------------------------------------------------------------------ */ int ipflog_clear(unit) minor_t unit; { iplog_t *ipl; int used; +# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) + int s; +# endif + SPL_NET(s); MUTEX_ENTER(&ipl_mutex); - while ((ipl = iplt[unit])) { + while ((ipl = iplt[unit]) != NULL) { iplt[unit] = ipl->ipl_next; KFREES((caddr_t)ipl, ipl->ipl_dsize); } @@ -497,8 +666,9 @@ minor_t unit; ipll[unit] = NULL; used = iplused[unit]; iplused[unit] = 0; - bzero((char *)&iplcrc[unit], FI_LCSIZE); + bzero((char *)&iplcrc[unit], FI_CSIZE); MUTEX_EXIT(&ipl_mutex); + SPL_X(s); return used; } #endif /* IPFILTER_LOG */ diff --git a/contrib/ipfilter/ip_lookup.c b/contrib/ipfilter/ip_lookup.c new file mode 100644 index 0000000..b832373 --- /dev/null +++ b/contrib/ipfilter/ip_lookup.c @@ -0,0 +1,530 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002-2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#if defined(__osf__) +# define _PROTO_NET_H_ +#endif +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/file.h> +#if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include <sys/fcntl.h> +# include <sys/filio.h> +#else +# include <sys/ioctl.h> +#endif +#if !defined(_KERNEL) +# include <string.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL +#endif +#include <sys/socket.h> +#if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL) +# ifdef __osf__ +# include <net/radix.h> +# endif +# include "radix_ipf_local.h" +# define _RADIX_H_ +#endif +#include <net/if.h> +#if defined(__FreeBSD__) +# include <sys/cdefs.h> +# include <sys/proc.h> +#endif +#if defined(_KERNEL) +# include <sys/systm.h> +# if !defined(__SVR4) && !defined(__svr4__) +# include <sys/mbuf.h> +# endif +#endif +#include <netinet/in.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "netinet/ip_lookup.h" +/* END OF INCLUDES */ + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: ip_lookup.c,v 2.35.2.5 2004/07/06 11:16:25 darrenr Exp"; +#endif + +#ifdef IPFILTER_LOOKUP +int ip_lookup_inited = 0; + +static int iplookup_addnode __P((caddr_t)); +static int iplookup_delnode __P((caddr_t data)); +static int iplookup_addtable __P((caddr_t)); +static int iplookup_deltable __P((caddr_t)); +static int iplookup_stats __P((caddr_t)); +static int iplookup_flush __P((caddr_t)); + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_init */ +/* Returns: int - 0 = success, else error */ +/* Parameters: Nil */ +/* */ +/* Initialise all of the subcomponents of the lookup infrstructure. */ +/* ------------------------------------------------------------------------ */ +int ip_lookup_init() +{ + + if (ip_pool_init() == -1) + return -1; + + RWLOCK_INIT(&ip_poolrw, "ip pool rwlock"); + + ip_lookup_inited = 1; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_unload */ +/* Returns: int - 0 = success, else error */ +/* Parameters: Nil */ +/* */ +/* Free up all pool related memory that has been allocated whilst IPFilter */ +/* has been running. Also, do any other deinitialisation required such */ +/* ip_lookup_init() can be called again, safely. */ +/* ------------------------------------------------------------------------ */ +void ip_lookup_unload() +{ + ip_pool_fini(); + fr_htable_unload(); + + if (ip_lookup_inited == 1) { + RW_DESTROY(&ip_poolrw); + ip_lookup_inited = 0; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_ioctl */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */ +/* space. */ +/* cmd(I) - ioctl command number */ +/* mode(I) - file mode bits used with open */ +/* */ +/* Handle ioctl commands sent to the ioctl device. For the most part, this */ +/* involves just calling another function to handle the specifics of each */ +/* command. */ +/* ------------------------------------------------------------------------ */ +int ip_lookup_ioctl(data, cmd, mode) +caddr_t data; +ioctlcmd_t cmd; +int mode; +{ + int err; +# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) + int s; +# endif + + mode = mode; /* LINT */ + + SPL_NET(s); + + switch (cmd) + { + case SIOCLOOKUPADDNODE : + case SIOCLOOKUPADDNODEW : + WRITE_ENTER(&ip_poolrw); + err = iplookup_addnode(data); + RWLOCK_EXIT(&ip_poolrw); + break; + + case SIOCLOOKUPDELNODE : + case SIOCLOOKUPDELNODEW : + WRITE_ENTER(&ip_poolrw); + err = iplookup_delnode(data); + RWLOCK_EXIT(&ip_poolrw); + break; + + case SIOCLOOKUPADDTABLE : + WRITE_ENTER(&ip_poolrw); + err = iplookup_addtable(data); + RWLOCK_EXIT(&ip_poolrw); + break; + + case SIOCLOOKUPDELTABLE : + WRITE_ENTER(&ip_poolrw); + err = iplookup_deltable(data); + RWLOCK_EXIT(&ip_poolrw); + break; + + case SIOCLOOKUPSTAT : + case SIOCLOOKUPSTATW : + WRITE_ENTER(&ip_poolrw); + err = iplookup_stats(data); + RWLOCK_EXIT(&ip_poolrw); + break; + + case SIOCLOOKUPFLUSH : + WRITE_ENTER(&ip_poolrw); + err = iplookup_flush(data); + RWLOCK_EXIT(&ip_poolrw); + break; + + default : + err = EINVAL; + break; + } + SPL_X(s); + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_addnode */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* Add a new data node to a lookup structure. First, check to see if the */ +/* parent structure refered to by name exists and if it does, then go on to */ +/* add a node to it. */ +/* ------------------------------------------------------------------------ */ +static int iplookup_addnode(data) +caddr_t data; +{ + ip_pool_node_t node, *m; + iplookupop_t op; + iphtable_t *iph; + iphtent_t hte; + ip_pool_t *p; + int err; + + err = 0; + BCOPYIN(data, &op, sizeof(op)); + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; + + switch (op.iplo_type) + { + case IPLT_POOL : + if (op.iplo_size != sizeof(node)) + return EINVAL; + + err = COPYIN(op.iplo_struct, &node, sizeof(node)); + if (err != 0) + return EFAULT; + + p = ip_pool_find(op.iplo_unit, op.iplo_name); + if (p == NULL) + return ESRCH; + + /* + * add an entry to a pool - return an error if it already + * exists remove an entry from a pool - if it exists + * - in both cases, the pool *must* exist! + */ + m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask); + if (m) + return EEXIST; + err = ip_pool_insert(p, &node.ipn_addr.adf_addr, + &node.ipn_mask.adf_addr, node.ipn_info); + break; + + case IPLT_HASH : + if (op.iplo_size != sizeof(hte)) + return EINVAL; + + err = COPYIN(op.iplo_struct, &hte, sizeof(hte)); + if (err != 0) + return EFAULT; + + iph = fr_findhtable(op.iplo_unit, op.iplo_name); + if (iph == NULL) + return ESRCH; + err = fr_addhtent(iph, &hte); + break; + + default : + err = EINVAL; + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_delnode */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* Delete a node from a lookup table by first looking for the table it is */ +/* in and then deleting the entry that gets found. */ +/* ------------------------------------------------------------------------ */ +static int iplookup_delnode(data) +caddr_t data; +{ + ip_pool_node_t node, *m; + iplookupop_t op; + iphtable_t *iph; + iphtent_t hte; + ip_pool_t *p; + int err; + + err = 0; + BCOPYIN(data, &op, sizeof(op)); + + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; + + switch (op.iplo_type) + { + case IPLT_POOL : + if (op.iplo_size != sizeof(node)) + return EINVAL; + + err = COPYIN(op.iplo_struct, &node, sizeof(node)); + if (err != 0) + return EFAULT; + + p = ip_pool_find(op.iplo_unit, op.iplo_name); + if (!p) + return ESRCH; + + m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask); + if (m == NULL) + return ENOENT; + err = ip_pool_remove(p, m); + break; + + case IPLT_HASH : + if (op.iplo_size != sizeof(hte)) + return EINVAL; + + err = COPYIN(op.iplo_struct, &hte, sizeof(hte)); + if (err != 0) + return EFAULT; + + iph = fr_findhtable(op.iplo_unit, op.iplo_name); + if (iph == NULL) + return ESRCH; + err = fr_delhtent(iph, &hte); + break; + + default : + err = EINVAL; + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_addtable */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* Create a new lookup table, if one doesn't already exist using the name */ +/* for this one. */ +/* ------------------------------------------------------------------------ */ +static int iplookup_addtable(data) +caddr_t data; +{ + iplookupop_t op; + int err; + + err = 0; + BCOPYIN(data, &op, sizeof(op)); + + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; + + switch (op.iplo_type) + { + case IPLT_POOL : + if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL) + err = EEXIST; + else + err = ip_pool_create(&op); + break; + + case IPLT_HASH : + if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL) + err = EEXIST; + else + err = fr_newhtable(&op); + break; + + default : + err = EINVAL; + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_deltable */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* Decodes ioctl request to remove a particular hash table or pool and */ +/* calls the relevant function to do the cleanup. */ +/* ------------------------------------------------------------------------ */ +static int iplookup_deltable(data) +caddr_t data; +{ + iplookupop_t op; + int err; + + BCOPYIN(data, &op, sizeof(op)); + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; + + if (op.iplo_arg & IPLT_ANON) + op.iplo_arg &= IPLT_ANON; + + /* + * create a new pool - fail if one already exists with + * the same # + */ + switch (op.iplo_type) + { + case IPLT_POOL : + err = ip_pool_destroy(&op); + break; + + case IPLT_HASH : + err = fr_removehtable(&op); + break; + + default : + err = EINVAL; + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_stats */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* Copy statistical information from inside the kernel back to user space. */ +/* ------------------------------------------------------------------------ */ +static int iplookup_stats(data) +caddr_t data; +{ + iplookupop_t op; + int err; + + err = 0; + BCOPYIN(data, &op, sizeof(op)); + + switch (op.iplo_type) + { + case IPLT_POOL : + err = ip_pool_statistics(&op); + break; + + case IPLT_HASH : + err = fr_gethtablestat(&op); + break; + + default : + err = EINVAL; + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_flush */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* A flush is called when we want to flush all the nodes from a particular */ +/* entry in the hash table/pool or want to remove all groups from those. */ +/* ------------------------------------------------------------------------ */ +static int iplookup_flush(data) +caddr_t data; +{ + int err, unit, num, type; + iplookupflush_t flush; + + err = 0; + BCOPYIN(data, &flush, sizeof(flush)); + + flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; + + unit = flush.iplf_unit; + if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) + return EINVAL; + + type = flush.iplf_type; + err = EINVAL; + num = 0; + + if (type == IPLT_POOL || type == IPLT_ALL) { + err = 0; + num = ip_pool_flush(&flush); + } + + if (type == IPLT_HASH || type == IPLT_ALL) { + err = 0; + num += fr_flushhtable(&flush); + } + + if (err == 0) { + flush.iplf_count = num; + err = COPYOUT(&flush, data, sizeof(flush)); + } + return err; +} + + +void ip_lookup_deref(type, ptr) +int type; +void *ptr; +{ + if (ptr == NULL) + return; + + WRITE_ENTER(&ip_poolrw); + switch (type) + { + case IPLT_POOL : + ip_pool_deref(ptr); + break; + + case IPLT_HASH : + fr_derefhtable(ptr); + break; + } + RWLOCK_EXIT(&ip_poolrw); +} + + +#else /* IPFILTER_LOOKUP */ + +/*ARGSUSED*/ +int ip_lookup_ioctl(data, cmd, mode) +caddr_t data; +ioctlcmd_t cmd; +int mode; +{ + return EIO; +} +#endif /* IPFILTER_LOOKUP */ diff --git a/contrib/ipfilter/ip_lookup.h b/contrib/ipfilter/ip_lookup.h new file mode 100644 index 0000000..e9f8cb8 --- /dev/null +++ b/contrib/ipfilter/ip_lookup.h @@ -0,0 +1,65 @@ +/* $NetBSD$ */ + + +#ifndef __IP_LOOKUP_H__ +#define __IP_LOOKUP_H__ + +#if defined(__STDC__) || defined(__GNUC__) +# define SIOCLOOKUPADDTABLE _IOWR('r', 60, struct iplookupop) +# define SIOCLOOKUPDELTABLE _IOWR('r', 61, struct iplookupop) +# define SIOCLOOKUPSTAT _IOWR('r', 64, struct iplookupop) +# define SIOCLOOKUPSTATW _IOW('r', 64, struct iplookupop) +# define SIOCLOOKUPFLUSH _IOWR('r', 65, struct iplookupflush) +# define SIOCLOOKUPADDNODE _IOWR('r', 67, struct iplookupop) +# define SIOCLOOKUPADDNODEW _IOW('r', 67, struct iplookupop) +# define SIOCLOOKUPDELNODE _IOWR('r', 68, struct iplookupop) +# define SIOCLOOKUPDELNODEW _IOW('r', 68, struct iplookupop) +#else +# define SIOCLOOKUPADDTABLE _IOWR(r, 60, struct iplookupop) +# define SIOCLOOKUPDELTABLE _IOWR(r, 61, struct iplookupop) +# define SIOCLOOKUPSTAT _IOWR(r, 64, struct iplookupop) +# define SIOCLOOKUPSTATW _IOW(r, 64, struct iplookupop) +# define SIOCLOOKUPFLUSH _IOWR(r, 65, struct iplookupflush) +# define SIOCLOOKUPADDNODE _IOWR(r, 67, struct iplookupop) +# define SIOCLOOKUPADDNODEW _IOW(r, 67, struct iplookupop) +# define SIOCLOOKUPDELNODE _IOWR(r, 68, struct iplookupop) +# define SIOCLOOKUPDELNODEW _IOW(r, 68, struct iplookupop) +#endif + +typedef struct iplookupop { + int iplo_type; /* IPLT_* */ + int iplo_unit; /* IPL_LOG* */ + u_int iplo_arg; + char iplo_name[FR_GROUPLEN]; + size_t iplo_size; /* sizeof struct at iplo_struct */ + void *iplo_struct; +} iplookupop_t; + +typedef struct iplookupflush { + int iplf_type; /* IPLT_* */ + int iplf_unit; /* IPL_LOG* */ + u_int iplf_arg; + size_t iplf_count; + char iplf_name[FR_GROUPLEN]; +} iplookupflush_t; + +typedef struct iplookuplink { + int ipll_type; /* IPLT_* */ + int ipll_unit; /* IPL_LOG* */ + u_int ipll_num; + char ipll_group[FR_GROUPLEN]; +} iplookuplink_t; + +#define IPLT_ALL -1 +#define IPLT_NONE 0 +#define IPLT_POOL 1 +#define IPLT_HASH 2 + +#define IPLT_ANON 0x80000000 + +extern int ip_lookup_init __P((void)); +extern int ip_lookup_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern void ip_lookup_unload __P((void)); +extern void ip_lookup_deref __P((int, void *)); + +#endif /* __IP_LOOKUP_H__ */ diff --git a/contrib/ipfilter/ip_msnrpc_pxy.c b/contrib/ipfilter/ip_msnrpc_pxy.c new file mode 100644 index 0000000..187a964 --- /dev/null +++ b/contrib/ipfilter/ip_msnrpc_pxy.c @@ -0,0 +1,328 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2000-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Simple DCE transparent proxy for MSN RPC. + * + * ******* NOTE: THIS PROXY DOES NOT DO ADDRESS TRANSLATION ******** + * + * Id: ip_msnrpc_pxy.c,v 2.17.2.1 2005/02/04 10:22:55 darrenr Exp + */ + +#define IPF_MSNRPC_PROXY + +#define IPF_MINMSNRPCLEN 24 +#define IPF_MSNRPCSKIP (2 + 19 + 2 + 2 + 2 + 19 + 2 + 2) + + +typedef struct msnrpchdr { + u_char mrh_major; /* major # == 5 */ + u_char mrh_minor; /* minor # == 0 */ + u_char mrh_type; + u_char mrh_flags; + u_32_t mrh_endian; + u_short mrh_dlen; /* data size */ + u_short mrh_alen; /* authentication length */ + u_32_t mrh_cid; /* call identifier */ + u_32_t mrh_hint; /* allocation hint */ + u_short mrh_ctxt; /* presentation context hint */ + u_char mrh_ccnt; /* cancel count */ + u_char mrh_ans; +} msnrpchdr_t; + +int ippr_msnrpc_init __P((void)); +void ippr_msnrpc_fini __P((void)); +int ippr_msnrpc_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_msnrpc_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_msnrpc_in __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_msnrpc_check __P((ip_t *, msnrpchdr_t *)); + +static frentry_t msnfr; + +int msn_proxy_init = 0; + +/* + * Initialize local structures. + */ +int ippr_msnrpc_init() +{ + bzero((char *)&msnfr, sizeof(msnfr)); + msnfr.fr_ref = 1; + msnfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&msnfr.fr_lock, "MSN RPC proxy rule lock"); + msn_proxy_init = 1; + + return 0; +} + + +void ippr_msnrpc_fini() +{ + if (msn_proxy_init == 1) { + MUTEX_DESTROY(&msnfr.fr_lock); + msn_proxy_init = 0; + } +} + + +int ippr_msnrpc_new(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + msnrpcinfo_t *mri; + + KMALLOC(mri, msnrpcinfo_t *); + if (mri == NULL) + return -1; + aps->aps_data = mri; + aps->aps_psiz = sizeof(msnrpcinfo_t); + + bzero((char *)mri, sizeof(*mri)); + mri->mri_cmd[0] = 0xff; + mri->mri_cmd[1] = 0xff; + return 0; +} + + +int ippr_msnrpc_check(ip, mrh) +ip_t *ip; +msnrpchdr_t *mrh; +{ + if (mrh->mrh_major != 5) + return -1; + if (mrh->mrh_minor != 0) + return -1; + if (mrh->mrh_alen != 0) + return -1; + if (mrh->mrh_endian == 0x10) { + /* Both gateway and packet match endian */ + if (mrh->mrh_dlen > ip->ip_len) + return -1; + if (mrh->mrh_type == 0 || mrh->mrh_type == 2) + if (mrh->mrh_hint > ip->ip_len) + return -1; + } else if (mrh->mrh_endian == 0x10000000) { + /* XXX - Endian mismatch - should be swapping! */ + return -1; + } else { + return -1; + } + return 0; +} + + +int ippr_msnrpc_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + msnrpcinfo_t *mri; + msnrpchdr_t *mrh; + tcphdr_t *tcp; + int dlen; + + mri = aps->aps_data; + if (mri == NULL) + return 0; + + tcp = (tcphdr_t *)fin->fin_dp; + dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); + if (dlen < IPF_MINMSNRPCLEN) + return 0; + + mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); + if (ippr_msnrpc_check(ip, mrh)) + return 0; + + mri->mri_valid++; + + switch (mrh->mrh_type) + { + case 0x0b : /* BIND */ + case 0x00 : /* REQUEST */ + break; + case 0x0c : /* BIND ACK */ + case 0x02 : /* RESPONSE */ + default: + return 0; + } + mri->mri_cmd[1] = mrh->mrh_type; + return 0; +} + + +int ippr_msnrpc_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + int dlen, sz, sz2, i; + msnrpcinfo_t *mri; + msnrpchdr_t *mrh; + fr_info_t fi; + u_short len; + char *s; + + mri = aps->aps_data; + if (mri == NULL) + return 0; + tcp = (tcphdr_t *)fin->fin_dp; + dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); + if (dlen < IPF_MINMSNRPCLEN) + return 0; + + mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); + if (ippr_msnrpc_check(ip, mrh)) + return 0; + + mri->mri_valid++; + + switch (mrh->mrh_type) + { + case 0x0c : /* BIND ACK */ + if (mri->mri_cmd[1] != 0x0b) + return 0; + break; + case 0x02 : /* RESPONSE */ + if (mri->mri_cmd[1] != 0x00) + return 0; + break; + case 0x0b : /* BIND */ + case 0x00 : /* REQUEST */ + default: + return 0; + } + mri->mri_cmd[0] = mrh->mrh_type; + dlen -= sizeof(*mrh); + + /* + * Only processes RESPONSE's + */ + if (mrh->mrh_type != 0x02) + return 0; + + /* + * Skip over some bytes...what are these really ? + */ + if (dlen <= 44) + return 0; + s = (char *)(mrh + 1) + 20; + dlen -= 20; + bcopy(s, (char *)&len, sizeof(len)); + if (len == 1) { + s += 20; + dlen -= 20; + } else if (len == 2) { + s += 24; + dlen -= 24; + } else + return 0; + + if (dlen <= 10) + return 0; + dlen -= 10; + bcopy(s, (char *)&sz, sizeof(sz)); + s += sizeof(sz); + bcopy(s, (char *)&sz2, sizeof(sz2)); + s += sizeof(sz2); + if (sz2 != sz) + return 0; + if (sz > dlen) + return 0; + if (*s++ != 5) + return 0; + if (*s++ != 0) + return 0; + sz -= IPF_MSNRPCSKIP; + s += IPF_MSNRPCSKIP; + dlen -= IPF_MSNRPCSKIP; + + do { + if (sz < 7 || dlen < 7) + break; + bcopy(s, (char *)&len, sizeof(len)); + if (dlen < len) + break; + if (sz < len) + break; + + if (len != 1) + break; + sz -= 3; + i = *(s + 2); + s += 3; + dlen -= 3; + + bcopy(s, (char *)&len, sizeof(len)); + if (dlen < len) + break; + if (sz < len) + break; + s += sizeof(len); + + switch (i) + { + case 7 : + if (len == 2) { + bcopy(s, (char *)&mri->mri_rport, 2); + mri->mri_flags |= 1; + } + break; + case 9 : + if (len == 4) { + bcopy(s, (char *)&mri->mri_raddr, 4); + mri->mri_flags |= 2; + } + break; + default : + break; + } + sz -= len; + s += len; + dlen -= len; + } while (sz > 0); + + if (mri->mri_flags == 3) { + int slen; + + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + + 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); + TCP_OFF_A(tcp2, 5); + fi.fin_data[0] = htons(mri->mri_rport); + tcp2->th_sport = mri->mri_rport; + fi.fin_data[1] = 0; + tcp2->th_dport = 0; + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); + fi.fin_dp = (char *)tcp2; + fi.fin_fi.fi_daddr = ip->ip_dst.s_addr; + fi.fin_fi.fi_saddr = mri->mri_raddr.s_addr; + if (!fi.fin_fr) + fi.fin_fr = &msnfr; + if (fr_stlookup(&fi, NULL, NULL)) { + RWLOCK_EXIT(&ipf_state); + } else { + (void) fr_addstate(&fi, NULL, SI_W_DPORT|SI_CLONE); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + } + ip->ip_len = slen; + } + mri->mri_flags = 0; + return 0; +} diff --git a/contrib/ipfilter/ip_nat.c b/contrib/ipfilter/ip_nat.c index 4193933..5529502 100644 --- a/contrib/ipfilter/ip_nat.c +++ b/contrib/ipfilter/ip_nat.c @@ -1,16 +1,15 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1995-2001 by Darren Reed. + * Copyright (C) 1995-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. - * - * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com) */ -#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) -#define _KERNEL -#endif - -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include <sys/errno.h> #include <sys/types.h> @@ -21,30 +20,35 @@ defined(_KERNEL) # include "opt_ipfilter_log.h" #endif -#if !defined(_KERNEL) && !defined(KERNEL) +#if !defined(_KERNEL) # include <stdio.h> # include <string.h> # include <stdlib.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> #else # include <sys/ioctl.h> #endif #include <sys/fcntl.h> -#ifndef linux +#if !defined(linux) # include <sys/protosw.h> #endif #include <sys/socket.h> -#if defined(_KERNEL) && !defined(linux) +#if defined(_KERNEL) # include <sys/systm.h> -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# if !defined(__SVR4) && !defined(__svr4__) # include <sys/mbuf.h> # endif -#else +#endif +#if defined(__SVR4) || defined(__svr4__) # include <sys/filio.h> # include <sys/byteorder.h> # ifdef _KERNEL @@ -71,22 +75,14 @@ #include <netinet/in_systm.h> #include <netinet/ip.h> -#ifdef __sgi -# ifdef IFF_DRVRLOCK /* IRIX6 */ -#include <sys/hashing.h> -#include <netinet/in_var.h> -# endif -#endif - #ifdef RFC1825 # include <vpn/md5.h> # include <vpn/ipsec.h> extern struct ifnet vpnif; #endif -#ifndef linux +#if !defined(linux) # include <netinet/ip_var.h> -# include <netinet/tcp_fsm.h> #endif #include <netinet/tcp.h> #include <netinet/udp.h> @@ -98,20 +94,45 @@ extern struct ifnet vpnif; #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" +#ifdef IPFILTER_SYNC +#include "netinet/ip_sync.h" +#endif #if (__FreeBSD_version >= 300000) # include <sys/malloc.h> #endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif +/* END OF INCLUDES */ + #undef SOCKADDR_IN #define SOCKADDR_IN struct sockaddr_in #if !defined(lint) static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.82 2004/05/30 17:56:52 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: ip_nat.c,v 2.195.2.38 2005/03/28 11:09:54 darrenr Exp"; #endif + +/* ======================================================================== */ +/* How the NAT is organised and works. */ +/* */ +/* Inside (interface y) NAT Outside (interface x) */ +/* -------------------- -+- ------------------------------------- */ +/* Packet going | out, processsed by fr_checknatout() for x */ +/* ------------> | ------------> */ +/* src=10.1.1.1 | src=192.1.1.1 */ +/* | */ +/* | in, processed by fr_checknatin() for x */ +/* <------------ | <------------ */ +/* dst=10.1.1.1 | dst=192.1.1.1 */ +/* -------------------- -+- ------------------------------------- */ +/* fr_checknatout() - changes ip_src and if required, sport */ +/* - creates a new mapping, if required. */ +/* fr_checknatin() - changes ip_dst and if required, dport */ +/* */ +/* In the NAT table, internal source is recorded as "in" and externally */ +/* seen as "out". */ +/* ======================================================================== */ + + nat_t **nat_table[2] = { NULL, NULL }, *nat_instances = NULL; ipnat_t *nat_list = NULL; @@ -120,40 +141,73 @@ 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_int fr_nat_maxbucket = 0, + fr_nat_maxbucket_reset = 1; 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; +ipftq_t nat_tqb[IPF_TCP_NSTATES]; +ipftq_t nat_udptq; +ipftq_t nat_icmptq; +ipftq_t nat_iptq; +ipftq_t *nat_utqe = NULL; +#ifdef IPFILTER_LOG +int nat_logging = 1; +#else +int nat_logging = 0; +#endif u_long fr_defnatage = DEF_NAT_AGE, + fr_defnatipage = 120, /* 60 seconds */ fr_defnaticmpage = 6; /* 3 seconds */ natstat_t nat_stats; int fr_nat_lock = 0; -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_t ipf_rw; -extern KRWLOCK_T ipf_nat; +int fr_nat_init = 0; +#if SOLARIS +extern int pfil_delayed_copy; #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_delete __P((struct nat *, int)); 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 void nat_tabmove __P((fr_info_t *, nat_t *)); -static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); +static int fr_natputent __P((caddr_t, int)); +static void nat_tabmove __P((nat_t *)); +static int nat_match __P((fr_info_t *, ipnat_t *)); +static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); +static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, - struct in_addr)); + struct in_addr, struct in_addr, u_32_t)); static void nat_hostmapdel __P((struct hostmap *)); +static INLINE int nat_icmpquerytype4 __P((int)); +static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int)); +static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int)); +static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, + tcphdr_t *, nat_t **, int)); +static void nat_resolverule __P((ipnat_t *)); +static nat_t *fr_natclone __P((fr_info_t *, nat_t *)); static void nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *, u_short *)); +static INLINE int nat_wildok __P((nat_t *, int, int, int, int)); -int nat_init() +/* ------------------------------------------------------------------------ */ +/* Function: fr_natinit */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: Nil */ +/* */ +/* Initialise all of the NAT locks, tables and other structures. */ +/* ------------------------------------------------------------------------ */ +int fr_natinit() { + int i; + KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); if (nat_table[0] != NULL) bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *)); @@ -164,29 +218,109 @@ int nat_init() if (nat_table[1] != NULL) bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *)); else - return -1; + return -2; KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz); if (nat_rules != NULL) bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *)); else - return -1; + return -3; KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz); if (rdr_rules != NULL) bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *)); else - return -1; + return -4; 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 -5; + + KMALLOCS(nat_stats.ns_bucketlen[0], u_long *, + ipf_nattable_sz * sizeof(u_long)); + if (nat_stats.ns_bucketlen[0] == NULL) + return -6; + bzero((char *)nat_stats.ns_bucketlen[0], + ipf_nattable_sz * sizeof(u_long)); + + KMALLOCS(nat_stats.ns_bucketlen[1], u_long *, + ipf_nattable_sz * sizeof(u_long)); + if (nat_stats.ns_bucketlen[1] == NULL) + return -7; + + bzero((char *)nat_stats.ns_bucketlen[1], + ipf_nattable_sz * sizeof(u_long)); + + if (fr_nat_maxbucket == 0) { + for (i = ipf_nattable_sz; i > 0; i >>= 1) + fr_nat_maxbucket++; + fr_nat_maxbucket *= 2; + } + + fr_sttab_init(nat_tqb); + /* + * Increase this because we may have "keep state" following this too + * and packet storms can occur if this is removed too quickly. + */ + nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = fr_tcplastack; + nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &nat_udptq; + nat_udptq.ifq_ttl = fr_defnatage; + nat_udptq.ifq_ref = 1; + nat_udptq.ifq_head = NULL; + nat_udptq.ifq_tail = &nat_udptq.ifq_head; + MUTEX_INIT(&nat_udptq.ifq_lock, "nat ipftq udp tab"); + nat_udptq.ifq_next = &nat_icmptq; + nat_icmptq.ifq_ttl = fr_defnaticmpage; + nat_icmptq.ifq_ref = 1; + nat_icmptq.ifq_head = NULL; + nat_icmptq.ifq_tail = &nat_icmptq.ifq_head; + MUTEX_INIT(&nat_icmptq.ifq_lock, "nat icmp ipftq tab"); + nat_icmptq.ifq_next = &nat_iptq; + nat_iptq.ifq_ttl = fr_defnatipage; + nat_iptq.ifq_ref = 1; + nat_iptq.ifq_head = NULL; + nat_iptq.ifq_tail = &nat_iptq.ifq_head; + MUTEX_INIT(&nat_iptq.ifq_lock, "nat ip ipftq tab"); + nat_iptq.ifq_next = NULL; + + for (i = 0; i < IPF_TCP_NSTATES; i++) { + if (nat_tqb[i].ifq_ttl < fr_defnaticmpage) + nat_tqb[i].ifq_ttl = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat_tqb[i].ifq_ttl > fr_defnatage) + nat_tqb[i].ifq_ttl = fr_defnatage; +#endif + } + + /* + * Increase this because we may have "keep state" following + * this too and packet storms can occur if this is removed + * too quickly. + */ + nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl; + + RWLOCK_INIT(&ipf_nat, "ipf IP NAT rwlock"); + RWLOCK_INIT(&ipf_natfrag, "ipf IP NAT-Frag rwlock"); + MUTEX_INIT(&ipf_nat_new, "ipf nat new mutex"); + MUTEX_INIT(&ipf_natio, "ipf nat io mutex"); + + fr_nat_init = 1; + return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_addrdr */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to add */ +/* */ +/* Adds a redirect rule to the hash table of redirect rules and the list of */ +/* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ +/* use by redirect rules. */ +/* ------------------------------------------------------------------------ */ static void nat_addrdr(n) ipnat_t *n; { @@ -195,7 +329,7 @@ ipnat_t *n; u_int hv; int k; - k = countbits(n->in_outmsk); + k = count4bits(n->in_outmsk); if ((k >= 0) && (k != 32)) rdr_masks |= 1 << k; j = (n->in_outip & n->in_outmsk); @@ -205,10 +339,20 @@ ipnat_t *n; np = &(*np)->in_rnext; n->in_rnext = NULL; n->in_prnext = np; + n->in_hv = hv; *np = n; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_addnat */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to add */ +/* */ +/* Adds a NAT map rule to the hash table of rules and the list of loaded */ +/* NAT rules. Updates the bitmask indicating which netmasks are in use by */ +/* redirect rules. */ +/* ------------------------------------------------------------------------ */ static void nat_addnat(n) ipnat_t *n; { @@ -217,7 +361,7 @@ ipnat_t *n; u_int hv; int k; - k = countbits(n->in_inmsk); + k = count4bits(n->in_inmsk); if ((k >= 0) && (k != 32)) nat_masks |= 1 << k; j = (n->in_inip & n->in_inmsk); @@ -227,10 +371,18 @@ ipnat_t *n; np = &(*np)->in_mnext; n->in_mnext = NULL; n->in_pmnext = np; + n->in_hv = hv; *np = n; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_delrdr */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to delete */ +/* */ +/* Removes a redirect rule from the hash table of redirect rules. */ +/* ------------------------------------------------------------------------ */ static void nat_delrdr(n) ipnat_t *n; { @@ -240,60 +392,93 @@ ipnat_t *n; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_delnat */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to delete */ +/* */ +/* Removes a NAT map rule from the hash table of NAT map rules. */ +/* ------------------------------------------------------------------------ */ static void nat_delnat(n) ipnat_t *n; { - if (n->in_mnext) + if (n->in_mnext != NULL) 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. - * - * Must be called with ipf_nat held as a write lock. - */ -static struct hostmap *nat_hostmap(np, real, map) +/* ------------------------------------------------------------------------ */ +/* Function: nat_hostmap */ +/* Returns: struct hostmap* - NULL if no hostmap could be created, */ +/* else a pointer to the hostmapping to use */ +/* Parameters: np(I) - pointer to NAT rule */ +/* real(I) - real IP address */ +/* map(I) - mapped IP address */ +/* port(I) - destination port number */ +/* Write Locks: ipf_nat */ +/* */ +/* Check if an ip address has already been allocated for a given mapping */ +/* that is not doing port based translation. If is not yet allocated, then */ +/* create a new entry if a non-NULL NAT rule pointer has been supplied. */ +/* ------------------------------------------------------------------------ */ +static struct hostmap *nat_hostmap(np, src, dst, map, port) ipnat_t *np; -struct in_addr real; +struct in_addr src; +struct in_addr dst; struct in_addr map; +u_32_t port; { hostmap_t *hm; u_int hv; - hv = real.s_addr % HOSTMAP_SIZE; + hv = (src.s_addr ^ dst.s_addr); + hv += src.s_addr; + hv += dst.s_addr; + hv %= HOSTMAP_SIZE; for (hm = maptable[hv]; hm; hm = hm->hm_next) - if ((hm->hm_realip.s_addr == real.s_addr) && - (np == hm->hm_ipnat)) { + if ((hm->hm_srcip.s_addr == src.s_addr) && + (hm->hm_dstip.s_addr == dst.s_addr) && + ((np == NULL) || (np == hm->hm_ipnat)) && + ((port == 0) || (port == hm->hm_port))) { hm->hm_ref++; return hm; } + if (np == NULL) + return NULL; + KMALLOC(hm, hostmap_t *); if (hm) { hm->hm_next = maptable[hv]; hm->hm_pnext = maptable + hv; - if (maptable[hv]) + if (maptable[hv] != NULL) maptable[hv]->hm_pnext = &hm->hm_next; maptable[hv] = hm; hm->hm_ipnat = np; - hm->hm_realip = real; + hm->hm_srcip = src; + hm->hm_dstip = dst; hm->hm_mapip = map; hm->hm_ref = 1; + hm->hm_port = port; } return hm; } -/* - * Must be called with ipf_nat held as a write lock. - */ +/* ------------------------------------------------------------------------ */ +/* Function: nat_hostmapdel */ +/* Returns: Nil */ +/* Parameters: hm(I) - pointer to hostmap structure */ +/* Write Locks: ipf_nat */ +/* */ +/* Decrement the references to this hostmap structure by one. If this */ +/* reaches zero then remove it and free it. */ +/* ------------------------------------------------------------------------ */ static void nat_hostmapdel(hm) struct hostmap *hm; { - ATOMIC_DEC32(hm->hm_ref); + hm->hm_ref--; if (hm->hm_ref == 0) { if (hm->hm_next) hm->hm_next->hm_pnext = hm->hm_pnext; @@ -303,17 +488,27 @@ struct hostmap *hm; } +/* ------------------------------------------------------------------------ */ +/* Function: fix_outcksum */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* sp(I) - location of 16bit checksum to update */ +/* n((I) - amount to adjust checksum by */ +/* */ +/* Adjusts the 16bit checksum by "n" for packets going out. */ +/* ------------------------------------------------------------------------ */ void fix_outcksum(fin, sp, n) fr_info_t *fin; u_short *sp; u_32_t n; { - register u_short sumshort; - register u_32_t sum1; + u_short sumshort; + u_32_t sum1; - if (!n) + if (n == 0) return; - else if (n & NAT_HW_CKSUM) { + + if (n & NAT_HW_CKSUM) { n &= 0xffff; n += fin->fin_dlen; n = (n & 0xffff) + (n >> 16); @@ -330,28 +525,34 @@ u_32_t n; } +/* ------------------------------------------------------------------------ */ +/* Function: fix_incksum */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* sp(I) - location of 16bit checksum to update */ +/* n((I) - amount to adjust checksum by */ +/* */ +/* Adjusts the 16bit checksum by "n" for packets going in. */ +/* ------------------------------------------------------------------------ */ void fix_incksum(fin, sp, n) fr_info_t *fin; u_short *sp; u_32_t n; { - register u_short sumshort; - register u_32_t sum1; + u_short sumshort; + u_32_t sum1; - if (!n) + if (n == 0) return; - else if (n & NAT_HW_CKSUM) { + + if (n & NAT_HW_CKSUM) { n &= 0xffff; n += fin->fin_dlen; n = (n & 0xffff) + (n >> 16); *sp = n & 0xffff; return; } -#ifdef sparc - sum1 = (~(*sp)) & 0xffff; -#else sum1 = (~ntohs(*sp)) & 0xffff; -#endif sum1 += ~(n) & 0xffff; sum1 = (sum1 >> 16) + (sum1 & 0xffff); /* Again */ @@ -361,27 +562,32 @@ u_32_t n; } -/* - * fix_datacksum is used *only* for the adjustments of checksums in the data - * section of an IP packet. - * - * The only situation in which you need to do this is when NAT'ing an - * ICMP error message. Such a message, contains in its body the IP header - * of the original IP packet, that causes the error. - * - * You can't use fix_incksum or fix_outcksum in that case, because for the - * kernel the data section of the ICMP error is just data, and no special - * processing like hardware cksum or ntohs processing have been done by the - * kernel on the data section. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fix_datacksum */ +/* Returns: Nil */ +/* Parameters: sp(I) - location of 16bit checksum to update */ +/* n((I) - amount to adjust checksum by */ +/* */ +/* Fix_datacksum is used *only* for the adjustments of checksums in the */ +/* data section of an IP packet. */ +/* */ +/* The only situation in which you need to do this is when NAT'ing an */ +/* ICMP error message. Such a message, contains in its body the IP header */ +/* of the original IP packet, that causes the error. */ +/* */ +/* You can't use fix_incksum or fix_outcksum in that case, because for the */ +/* kernel the data section of the ICMP error is just data, and no special */ +/* processing like hardware cksum or ntohs processing have been done by the */ +/* kernel on the data section. */ +/* ------------------------------------------------------------------------ */ void fix_datacksum(sp, n) u_short *sp; u_32_t n; { - register u_short sumshort; - register u_32_t sum1; + u_short sumshort; + u_32_t sum1; - if (!n) + if (n == 0) return; sum1 = (~ntohs(*sp)) & 0xffff; @@ -393,76 +599,65 @@ u_32_t n; *(sp) = htons(sumshort); } -/* - * How the NAT is organised and works. - * - * Inside (interface y) NAT Outside (interface x) - * -------------------- -+- ------------------------------------- - * Packet going | out, processsed by ip_natout() for x - * ------------> | ------------> - * src=10.1.1.1 | src=192.1.1.1 - * | - * | in, processed by ip_natin() for x - * <------------ | <------------ - * dst=10.1.1.1 | dst=192.1.1.1 - * -------------------- -+- ------------------------------------- - * ip_natout() - changes ip_src and if required, sport - * - creates a new mapping, if required. - * ip_natin() - changes ip_dst and if required, dport - * - * In the NAT table, internal source is recorded as "in" and externally - * seen as "out". - */ -/* - * Handle ioctls which manipulate the NAT. - */ -int nat_ioctl(data, cmd, mode) -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -u_long cmd; -#else -int cmd; -#endif +/* ------------------------------------------------------------------------ */ +/* Function: fr_nat_ioctl */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* cmd(I) - ioctl command integer */ +/* mode(I) - file mode bits used with open */ +/* */ +/* Processes an ioctl call made to operate on the IP Filter NAT device. */ +/* ------------------------------------------------------------------------ */ +int fr_nat_ioctl(data, cmd, mode) +ioctlcmd_t cmd; caddr_t data; int mode; { - register ipnat_t *nat, *nt, *n = NULL, **np = NULL; + ipnat_t *nat, *nt, *n = NULL, **np = NULL; int error = 0, ret, arg, getlock; ipnat_t natd; - u_32_t i, j; #if (BSD >= 199306) && defined(_KERNEL) if ((securelevel >= 2) && (mode & FWRITE)) return EPERM; #endif - nat = NULL; /* XXX gcc -Wuninitialized */ - KMALLOC(nt, ipnat_t *); +#if defined(__osf__) && defined(_KERNEL) + getlock = 0; +#else getlock = (mode & NAT_LOCKHELD) ? 0 : 1; - if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { +#endif + + nat = NULL; /* XXX gcc -Wuninitialized */ + if (cmd == (ioctlcmd_t)SIOCADNAT) { + KMALLOC(nt, ipnat_t *); + } else { + nt = NULL; + } + + if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { if (mode & NAT_SYSSPACE) { bcopy(data, (char *)&natd, sizeof(natd)); error = 0; } else { - error = IRCOPYPTR(data, (char *)&natd, sizeof(natd)); + error = fr_inobj(data, &natd, IPFOBJ_IPNAT); } - } else if (cmd == SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ - error = IRCOPY(data, (char *)&arg, sizeof(arg)); - if (error) - error = EFAULT; + + } else if (cmd == (ioctlcmd_t)SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ + BCOPYIN(data, &arg, sizeof(arg)); } - if (error) + if (error != 0) goto done; /* * For add/delete, look to see if the NAT entry is already present */ - if (getlock == 1) { - WRITE_ENTER(&ipf_nat); - } - if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { + if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { nat = &natd; + if (nat->in_v == 0) /* For backward compat. */ + nat->in_v = 4; nat->in_flags &= IPN_USERFLAGS; if ((nat->in_redir & NAT_MAPBLK) == 0) { if ((nat->in_flags & IPN_SPLIT) == 0) @@ -470,14 +665,11 @@ int mode; if ((nat->in_flags & IPN_IPRANGE) == 0) nat->in_outip &= nat->in_outmsk; } - for (np = &nat_list; (n = *np); np = &n->in_next) + MUTEX_ENTER(&ipf_natio); + for (np = &nat_list; ((n = *np) != NULL); np = &n->in_next) if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, - IPN_CMPSIZ)) { - if (n->in_redir == NAT_REDIRECT && - n->in_pnext != nat->in_pnext) - continue; + IPN_CMPSIZ)) break; - } } switch (cmd) @@ -491,182 +683,94 @@ int mode; error = EPERM; else { tmp = ipflog_clear(IPL_LOGNAT); - IWCOPY((char *)&tmp, (char *)data, sizeof(tmp)); + BCOPYOUT((char *)&tmp, (char *)data, sizeof(tmp)); } break; } + case SIOCSETLG : + if (!(mode & FWRITE)) + error = EPERM; + else { + BCOPYIN((char *)data, (char *)&nat_logging, + sizeof(nat_logging)); + } + break; + case SIOCGETLG : + BCOPYOUT((char *)&nat_logging, (char *)data, + sizeof(nat_logging)); + break; + case FIONREAD : + arg = iplused[IPL_LOGNAT]; + BCOPYOUT(&arg, data, sizeof(arg)); + break; #endif case SIOCADNAT : if (!(mode & FWRITE)) { error = EPERM; - break; - } - if (n) { + } else if (n != NULL) { error = EEXIST; - break; - } - if (nt == NULL) { + } else if (nt == NULL) { error = ENOMEM; - break; } - n = nt; - nt = NULL; - bcopy((char *)nat, (char *)n, sizeof(*n)); - n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); - if (!n->in_ifp) - n->in_ifp = (void *)-1; - if (n->in_plabel[0] != '\0') { - n->in_apr = appr_lookup(n->in_p, n->in_plabel); - if (!n->in_apr) { - error = ENOENT; - break; - } - } - n->in_next = NULL; - *np = n; - - if (n->in_redir & NAT_REDIRECT) { - n->in_flags &= ~IPN_NOTDST; - nat_addrdr(n); - } - if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { - n->in_flags &= ~IPN_NOTSRC; - 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_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); - /* - * Calculate the number of valid IP addresses in the output - * mapping range. In all cases, the range is inclusive of - * the start and ending IP addresses. - * If to a CIDR address, lose 2: broadcast + network address - * (so subtract 1) - * If to a range, add one. - * If to a single IP address, set to 1. - */ - if (n->in_space) { - 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_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) { - n->in_pnext = ntohs(n->in_pmin); - /* - * Multiply by the number of ports made available. - */ - if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { - n->in_space *= (ntohs(n->in_pmax) - - ntohs(n->in_pmin) + 1); - /* - * Because two different sources can map to - * different destinations but use the same - * local IP#/port #. - * If the result is smaller than in_space, then - * we may have wrapped around 32bits. - */ - i = n->in_inmsk; - if ((i != 0) && (i != 0xffffffff)) { - j = n->in_space * (~ntohl(i) + 1); - if (j >= n->in_space) - n->in_space = j; - else - n->in_space = 0xffffffff; - } - } - /* - * If no protocol is specified, multiple by 256. - */ - if ((n->in_flags & IPN_TCPUDP) == 0) { - j = n->in_space * 256; - if (j >= n->in_space) - n->in_space = j; - else - n->in_space = 0xffffffff; - } + if (error != 0) { + MUTEX_EXIT(&ipf_natio); + break; } - /* Otherwise, these fields are preset */ - n = NULL; - nat_stats.ns_rules++; + bcopy((char *)nat, (char *)nt, sizeof(*n)); + error = nat_siocaddnat(nt, np, getlock); + MUTEX_EXIT(&ipf_natio); + if (error == 0) + nt = NULL; break; case SIOCRMNAT : if (!(mode & FWRITE)) { error = EPERM; n = NULL; - break; - } - if (!n) { + } else if (n == NULL) { error = ESRCH; - break; } - if (n->in_redir & NAT_REDIRECT) - nat_delrdr(n); - if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) - nat_delnat(n); - if (nat_list == NULL) { - nat_masks = 0; - rdr_masks = 0; - } - *np = n->in_next; - if (!n->in_use) { - if (n->in_apr) - appr_free(n->in_apr); - KFREE(n); - nat_stats.ns_rules--; - } else { - n->in_flags |= IPN_DELETE; - n->in_next = NULL; + + if (error != 0) { + MUTEX_EXIT(&ipf_natio); + break; } + nat_siocdelnat(n, np, getlock); + + MUTEX_EXIT(&ipf_natio); n = NULL; break; case SIOCGNATS : - MUTEX_DOWNGRADE(&ipf_nat); nat_stats.ns_table[0] = nat_table[0]; nat_stats.ns_table[1] = nat_table[1]; nat_stats.ns_list = nat_list; nat_stats.ns_maptable = maptable; nat_stats.ns_nattab_sz = ipf_nattable_sz; + nat_stats.ns_nattab_max = ipf_nattable_max; nat_stats.ns_rultab_sz = ipf_natrules_sz; nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; nat_stats.ns_hostmap_sz = ipf_hostmap_sz; nat_stats.ns_instances = nat_instances; nat_stats.ns_apslist = ap_sess_list; - error = IWCOPYPTR((char *)&nat_stats, (char *)data, - sizeof(nat_stats)); + error = fr_outobj(data, &nat_stats, IPFOBJ_NATSTAT); break; case SIOCGNATL : { natlookup_t nl; - MUTEX_DOWNGRADE(&ipf_nat); - error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl)); - if (error) - break; - - if (nat_lookupredir(&nl)) { - error = IWCOPYPTR((char *)&nl, (char *)data, - sizeof(nl)); - } else - error = ESRCH; + if (getlock) { + READ_ENTER(&ipf_nat); + } + error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP); + if (error == 0) { + if (nat_lookupredir(&nl) != NULL) { + error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP); + } else { + error = ESRCH; + } + } + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } break; } case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ @@ -674,6 +778,9 @@ int mode; error = EPERM; break; } + if (getlock) { + WRITE_ENTER(&ipf_nat); + } error = 0; if (arg == 0) ret = nat_flushtable(); @@ -681,57 +788,54 @@ int mode; ret = nat_clearlist(); else error = EINVAL; - MUTEX_DOWNGRADE(&ipf_nat); - if (!error) { - error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); - if (error) - error = EFAULT; + if (getlock) { + RWLOCK_EXIT(&ipf_nat); } + if (error == 0) { + BCOPYOUT(&ret, data, sizeof(ret)); + } + break; + case SIOCPROXY : + error = appr_ioctl(data, cmd, mode); 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; - } else - error = EFAULT; + fr_lock(data, &fr_nat_lock); break; case SIOCSTPUT : - if (fr_nat_lock) - error = fr_natputent(data); - else + if (fr_nat_lock) { + error = fr_natputent(data, getlock); + } else { error = EACCES; + } break; case SIOCSTGSZ : - if (fr_nat_lock) + if (fr_nat_lock) { + if (getlock) { + READ_ENTER(&ipf_nat); + } error = fr_natgetsz(data); - else + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + } else error = EACCES; break; case SIOCSTGET : - if (fr_nat_lock) + if (fr_nat_lock) { + if (getlock) { + READ_ENTER(&ipf_nat); + } error = fr_natgetent(data); - else + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + } else error = EACCES; break; - case FIONREAD : -#ifdef IPFILTER_LOG - arg = (int)iplused[IPL_LOGNAT]; - MUTEX_DOWNGRADE(&ipf_nat); - error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); - if (error) - error = EFAULT; -#endif - break; default : error = EINVAL; break; } - if (getlock == 1) { - RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ - } done: if (nt) KFREE(nt); @@ -739,27 +843,264 @@ done: } +/* ------------------------------------------------------------------------ */ +/* Function: nat_siocaddnat */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: n(I) - pointer to new NAT rule */ +/* np(I) - pointer to where to insert new NAT rule */ +/* getlock(I) - flag indicating if lock on ipf_nat is held */ +/* Mutex Locks: ipf_natio */ +/* */ +/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ +/* from information passed to the kernel, then add it to the appropriate */ +/* NAT rule table(s). */ +/* ------------------------------------------------------------------------ */ +static int nat_siocaddnat(n, np, getlock) +ipnat_t *n, **np; +int getlock; +{ + int error = 0, i, j; + + nat_resolverule(n); + if (n->in_plabel[0] != '\0') { + if (n->in_apr == NULL) + return ENOENT; + } + + if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) + return EINVAL; + + 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_IPRANGE) + n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); + else if (n->in_flags & IPN_SPLIT) + n->in_space = 2; + else if (n->in_outmsk != 0) + n->in_space = ~ntohl(n->in_outmsk); + else + n->in_space = 1; + + /* + * Calculate the number of valid IP addresses in the output + * mapping range. In all cases, the range is inclusive of + * the start and ending IP addresses. + * If to a CIDR address, lose 2: broadcast + network address + * (so subtract 1) + * If to a range, add one. + * If to a single IP address, set to 1. + */ + if (n->in_space) { + 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_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) { + n->in_pnext = ntohs(n->in_pmin); + /* + * Multiply by the number of ports made available. + */ + if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { + n->in_space *= (ntohs(n->in_pmax) - + ntohs(n->in_pmin) + 1); + /* + * Because two different sources can map to + * different destinations but use the same + * local IP#/port #. + * If the result is smaller than in_space, then + * we may have wrapped around 32bits. + */ + i = n->in_inmsk; + if ((i != 0) && (i != 0xffffffff)) { + j = n->in_space * (~ntohl(i) + 1); + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } + } + /* + * If no protocol is specified, multiple by 256 to allow for + * at least one IP:IP mapping per protocol. + */ + if ((n->in_flags & IPN_TCPUDPICMP) == 0) { + j = n->in_space * 256; + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } + } + + /* Otherwise, these fields are preset */ + + if (getlock) { + WRITE_ENTER(&ipf_nat); + } + n->in_next = NULL; + *np = n; + + if (n->in_age[0] != 0) + n->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, n->in_age[0]); + + if (n->in_age[1] != 0) + n->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, n->in_age[1]); + + if (n->in_redir & NAT_REDIRECT) { + n->in_flags &= ~IPN_NOTDST; + nat_addrdr(n); + } + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { + n->in_flags &= ~IPN_NOTSRC; + nat_addnat(n); + } + n = NULL; + nat_stats.ns_rules++; +#if SOLARIS + pfil_delayed_copy = 0; +#endif + if (getlock) { + RWLOCK_EXIT(&ipf_nat); /* WRITE */ + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_resolvrule */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule */ +/* */ +/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ +/* from information passed to the kernel, then add it to the appropriate */ +/* NAT rule table(s). */ +/* ------------------------------------------------------------------------ */ +static void nat_resolverule(n) +ipnat_t *n; +{ + n->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; + n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4); + + n->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; + if (n->in_ifnames[1][0] == '\0') { + (void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ); + n->in_ifps[1] = n->in_ifps[0]; + } else { + n->in_ifps[1] = fr_resolvenic(n->in_ifnames[0], 4); + } + + if (n->in_plabel[0] != '\0') { + n->in_apr = appr_lookup(n->in_p, n->in_plabel); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_siocdelnat */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: n(I) - pointer to new NAT rule */ +/* np(I) - pointer to where to insert new NAT rule */ +/* getlock(I) - flag indicating if lock on ipf_nat is held */ +/* Mutex Locks: ipf_natio */ +/* */ +/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ +/* from information passed to the kernel, then add it to the appropriate */ +/* NAT rule table(s). */ +/* ------------------------------------------------------------------------ */ +static void nat_siocdelnat(n, np, getlock) +ipnat_t *n, **np; +int getlock; +{ + if (getlock) { + WRITE_ENTER(&ipf_nat); + } + if (n->in_redir & NAT_REDIRECT) + nat_delrdr(n); + if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) + nat_delnat(n); + if (nat_list == NULL) { + nat_masks = 0; + rdr_masks = 0; + } + + if (n->in_tqehead[0] != NULL) { + if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) { + fr_freetimeoutqueue(n->in_tqehead[1]); + } + } + + if (n->in_tqehead[1] != NULL) { + if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) { + fr_freetimeoutqueue(n->in_tqehead[1]); + } + } + + *np = n->in_next; + + if (n->in_use == 0) { + if (n->in_apr) + appr_free(n->in_apr); + KFREE(n); + nat_stats.ns_rules--; +#if SOLARIS + if (nat_stats.ns_rules == 0) + pfil_delayed_copy = 1; +#endif + } else { + n->in_flags |= IPN_DELETE; + n->in_next = NULL; + } + if (getlock) { + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natgetsz */ +/* Returns: int - 0 == success, != 0 is the error value. */ +/* Parameters: data(I) - pointer to natget structure with kernel pointer */ +/* get the size of. */ +/* */ +/* Handle SIOCSTGSZ. */ +/* Return the size of the nat list entry to be copied back to user space. */ +/* The size of the entry is stored in the ng_sz field and the enture natget */ +/* structure is copied back to the user. */ +/* ------------------------------------------------------------------------ */ 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; + BCOPYIN(data, &ng, sizeof(ng)); nat = ng.ng_ptr; if (!nat) { nat = nat_instances; ng.ng_sz = 0; + /* + * Empty list so the size returned is 0. Simple. + */ if (nat == NULL) { - error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); - if (error) - error = EFAULT; - return error; + BCOPYOUT(&ng, data, sizeof(ng)); + return 0; } } else { /* @@ -774,45 +1115,59 @@ caddr_t data; return ESRCH; } + /* + * Incluse any space required for proxy data structures. + */ 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; - if (aps->aps_psiz > 4) /* XXX - sizeof(ipn_data) */ - ng.ng_sz -= 4; + if (aps != NULL) { + ng.ng_sz += sizeof(ap_session_t) - 4; + if (aps->aps_data != 0) + ng.ng_sz += aps->aps_psiz; } - error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); - if (error) - error = EFAULT; - return error; + BCOPYOUT(&ng, data, sizeof(ng)); + return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_natgetent */ +/* Returns: int - 0 == success, != 0 is the error value. */ +/* Parameters: data(I) - pointer to natget structure with kernel pointer */ +/* to NAT structure to copy out. */ +/* */ +/* Handle SIOCSTGET. */ +/* Copies out NAT entry to user space. Any additional data held for a */ +/* proxy is also copied, as to is the NAT rule which was responsible for it */ +/* ------------------------------------------------------------------------ */ static int fr_natgetent(data) caddr_t data; { - nat_save_t ipn, *ipnp, *ipnn = NULL; - register nat_t *n, *nat; + int error, outsize; ap_session_t *aps; - size_t dsz; - int error; + nat_save_t *ipn, ipns; + nat_t *n, *nat; - 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; + error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE); + if (error != 0) + return error; - nat = ipn.ipn_next; - if (!nat) { + if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) + return EINVAL; + + KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); + if (ipn == NULL) + return ENOMEM; + + ipn->ipn_dsize = ipns.ipn_dsize; + nat = ipns.ipn_next; + if (nat == NULL) { nat = nat_instances; if (nat == NULL) { if (nat_instances == NULL) - return ENOENT; - return 0; + error = ENOENT; + goto finished; } } else { /* @@ -823,150 +1178,215 @@ caddr_t data; for (n = nat_instances; n; n = n->nat_next) if (n == nat) break; - if (!n) - return ESRCH; + if (n == NULL) { + error = ESRCH; + goto finished; + } } + ipn->ipn_next = nat->nat_next; - ipn.ipn_next = nat->nat_next; - bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat)); - ipn.ipn_nat.nat_data = NULL; + /* + * Copy the NAT structure. + */ + bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); - if (nat->nat_ptr) { - bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat, - sizeof(ipn.ipn_ipnat)); - } + /* + * If we have a pointer to the NAT rule it belongs to, save that too. + */ + if (nat->nat_ptr != NULL) + 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 we also know the NAT entry has an associated filter rule, + * save that too. + */ + if (nat->nat_fr != NULL) + bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, + sizeof(ipn->ipn_fr)); - if ((aps = nat->nat_aps)) { - dsz = sizeof(*aps); - if (aps->aps_data) - dsz += aps->aps_psiz; - ipn.ipn_dsize = dsz; - if (dsz > sizeof(ipn.ipn_data)) - dsz -= sizeof(ipn.ipn_data); - KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + dsz); - if (ipnn == NULL) - return ENOMEM; - bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + /* + * Last but not least, if there is an application proxy session set + * up for this NAT entry, then copy that out too, including any + * private data saved along side it by the proxy. + */ + aps = nat->nat_aps; + outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); + if (aps != NULL) { + char *s; - bcopy((char *)aps, (char *)ipnn->ipn_data, sizeof(*aps)); - if (aps->aps_data) { - bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps), - aps->aps_psiz); + if (outsize < sizeof(*aps)) { + error = ENOBUFS; + goto finished; } - error = IWCOPY((caddr_t)ipnn, ipnp, - sizeof(ipn) + dsz); - if (error) - error = EFAULT; - KFREES(ipnn, sizeof(*ipnn) + dsz); - } else { - ipn.ipn_dsize = 0; - error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); - if (error) - error = EFAULT; + + s = ipn->ipn_data; + bcopy((char *)aps, s, sizeof(*aps)); + s += sizeof(*aps); + outsize -= sizeof(*aps); + if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) + bcopy(aps->aps_data, s, aps->aps_psiz); + else + error = ENOBUFS; + } + if (error == 0) { + error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize); + } + +finished: + if (ipn != NULL) { + KFREES(ipn, ipns.ipn_dsize); } return error; } -static int fr_natputent(data) +/* ------------------------------------------------------------------------ */ +/* Function: fr_natputent */ +/* Returns: int - 0 == success, != 0 is the error value. */ +/* Parameters: data(I) - pointer to natget structure with NAT */ +/* structure information to load into the kernel */ +/* getlock(I) - flag indicating whether or not a write lock */ +/* on ipf_nat is already held. */ +/* */ +/* Handle SIOCSTPUT. */ +/* Loads a NAT table entry from user space, including a NAT rule, proxy and */ +/* firewall rule data structures, if pointers to them indicate so. */ +/* ------------------------------------------------------------------------ */ +static int fr_natputent(data, getlock) caddr_t data; +int getlock; { - nat_save_t ipn, *ipnp, *ipnn = NULL; - register nat_t *n, *nat; + nat_save_t ipn, *ipnn; ap_session_t *aps; + nat_t *n, *nat; frentry_t *fr; + fr_info_t fin; 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; + error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); + if (error != 0) + return error; + + /* + * Initialise early because of code at junkput label. + */ + in = NULL; + aps = NULL; nat = NULL; - if (ipn.ipn_dsize) { - KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); + ipnn = NULL; + + /* + * New entry, copy in the rest of the NAT entry if it's size is more + * than just the nat_t structure. + */ + fr = NULL; + if (ipn.ipn_dsize > sizeof(ipn)) { + if (ipn.ipn_dsize > 81920) { + error = ENOMEM; + goto junkput; + } + + KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize); if (ipnn == NULL) return ENOMEM; - bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); - error = IRCOPY((caddr_t)ipnp + offsetof(nat_save_t, ipn_data), - (caddr_t)ipnn->ipn_data, ipn.ipn_dsize); - if (error) { + + error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize); + if (error != 0) { error = EFAULT; goto junkput; } } else - ipnn = NULL; + ipnn = &ipn; KMALLOC(nat, nat_t *); if (nat == NULL) { - error = EFAULT; + error = ENOMEM; goto junkput; } - bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat)); + bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); /* * Initialize all these so that nat_delete() doesn't cause a crash. */ - nat->nat_phnext[0] = NULL; - nat->nat_phnext[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_hm = NULL; - nat->nat_data = NULL; - nat->nat_ifp = GETUNIT(nat->nat_ifname, 4); + bzero((char *)nat, offsetof(struct nat, nat_tqe)); + nat->nat_tqe.tqe_pnext = NULL; + nat->nat_tqe.tqe_next = NULL; + nat->nat_tqe.tqe_ifq = NULL; + nat->nat_tqe.tqe_parent = nat; /* * Restore the rule associated with this nat session */ - if (in) { + in = ipnn->ipn_nat.nat_ptr; + if (in != NULL) { KMALLOC(in, ipnat_t *); + nat->nat_ptr = in; if (in == NULL) { error = ENOMEM; goto junkput; } - nat->nat_ptr = in; - bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in)); + bzero((char *)in, offsetof(struct ipnat, in_next6)); + bcopy((char *)&ipnn->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_lookup(in->in_p, in->in_plabel); + + ATOMIC_INC(nat_stats.ns_rules); + + nat_resolverule(in); + } + + /* + * Check that the NAT entry doesn't already exist in the kernel. + */ + bzero((char *)&fin, sizeof(fin)); + fin.fin_p = nat->nat_p; + if (nat->nat_dir == NAT_OUTBOUND) { + fin.fin_data[0] = ntohs(nat->nat_oport); + fin.fin_data[1] = ntohs(nat->nat_outport); + fin.fin_ifp = nat->nat_ifps[1]; + if (nat_inlookup(&fin, 0, fin.fin_p, nat->nat_oip, + nat->nat_inip) != NULL) { + error = EEXIST; + goto junkput; } + } else if (nat->nat_dir == NAT_INBOUND) { + fin.fin_data[0] = ntohs(nat->nat_outport); + fin.fin_data[1] = ntohs(nat->nat_oport); + fin.fin_ifp = nat->nat_ifps[0]; + if (nat_outlookup(&fin, 0, fin.fin_p, nat->nat_outip, + nat->nat_oip) != NULL) { + error = EEXIST; + goto junkput; + } + } else { + error = EINVAL; + goto junkput; } /* * Restore ap_session_t structure. Include the private data allocated * if it was there. */ - if (aps) { + aps = nat->nat_aps; + if (aps != NULL) { KMALLOC(aps, ap_session_t *); + nat->nat_aps = aps; 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) + if (in != NULL) aps->aps_apr = in->in_apr; - if (aps->aps_psiz) { + else + aps->aps_apr = NULL; + if (aps->aps_psiz != 0) { + if (aps->aps_psiz > 81920) { + error = ENOMEM; + goto junkput; + } KMALLOCS(aps->aps_data, void *, aps->aps_psiz); if (aps->aps_data == NULL) { error = ENOMEM; @@ -984,25 +1404,34 @@ caddr_t data; * If there was a filtering rule associated with this entry then * build up a new one. */ + fr = nat->nat_fr; if (fr != NULL) { - if (nat->nat_flags & FI_NEWFR) { + if ((nat->nat_flags & SI_NEWFR) != 0) { 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; - } + ipnn->ipn_nat.nat_fr = fr; + fr->fr_ref = 1; + (void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE); + bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); + MUTEX_NUKE(&fr->fr_lock); + MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); } else { + READ_ENTER(&ipf_nat); for (n = nat_instances; n; n = n->nat_next) if (n->nat_fr == fr) break; + + if (n != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + MUTEX_EXIT(&fr->fr_lock); + } + RWLOCK_EXIT(&ipf_nat); + if (!n) { error = ESRCH; goto junkput; @@ -1010,82 +1439,184 @@ caddr_t data; } } - if (ipnn) - KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); - nat_insert(nat); - return 0; + if (ipnn != &ipn) { + KFREES(ipnn, ipn.ipn_dsize); + ipnn = NULL; + } + + if (getlock) { + WRITE_ENTER(&ipf_nat); + } + error = nat_insert(nat, nat->nat_rev); + if ((error == 0) && (aps != NULL)) { + aps->aps_next = ap_sess_list; + ap_sess_list = aps; + } + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + + if (error == 0) + return 0; + + error = ENOMEM; + junkput: - if (ipnn) - KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); - if (nat) - nat_delete(nat); + if (fr != NULL) + fr_derefrule(&fr); + + if ((ipnn != NULL) && (ipnn != &ipn)) { + KFREES(ipnn, ipn.ipn_dsize); + } + if (nat != NULL) { + if (aps != NULL) { + if (aps->aps_data != NULL) { + KFREES(aps->aps_data, aps->aps_psiz); + } + KFREE(aps); + } + if (in != NULL) { + if (in->in_apr) + appr_free(in->in_apr); + KFREE(in); + } + KFREE(nat); + } return error; } -/* - * Delete a nat entry from the various lists and table. - */ -static void nat_delete(natd) -struct nat *natd; +/* ------------------------------------------------------------------------ */ +/* Function: nat_delete */ +/* Returns: Nil */ +/* Parameters: natd(I) - pointer to NAT structure to delete */ +/* logtype(I) - type of LOG record to create before deleting */ +/* Write Lock: ipf_nat */ +/* */ +/* Delete a nat entry from the various lists and table. If NAT logging is */ +/* enabled then generate a NAT log record for this event. */ +/* ------------------------------------------------------------------------ */ +static void nat_delete(nat, logtype) +struct nat *nat; +int logtype; { struct ipnat *ipn; - if (natd->nat_flags & FI_WILDP) - nat_stats.ns_wilds--; - if (natd->nat_hnext[0]) - natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; - *natd->nat_phnext[0] = natd->nat_hnext[0]; - if (natd->nat_hnext[1]) - natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; - *natd->nat_phnext[1] = natd->nat_hnext[1]; - if (natd->nat_me != NULL) - *natd->nat_me = NULL; + if (logtype != 0 && nat_logging != 0) + nat_log(nat, logtype); + + MUTEX_ENTER(&ipf_nat_new); + + /* + * Take it as a general indication that all the pointers are set if + * nat_pnext is set. + */ + if (nat->nat_pnext != NULL) { + nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; + nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; + + *nat->nat_pnext = nat->nat_next; + if (nat->nat_next != NULL) { + nat->nat_next->nat_pnext = nat->nat_pnext; + nat->nat_next = NULL; + } + nat->nat_pnext = NULL; + + *nat->nat_phnext[0] = nat->nat_hnext[0]; + if (nat->nat_hnext[0] != NULL) { + nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; + nat->nat_hnext[0] = NULL; + } + nat->nat_phnext[0] = NULL; - if (natd->nat_fr != NULL) { - ATOMIC_DEC32(natd->nat_fr->fr_ref); + *nat->nat_phnext[1] = nat->nat_hnext[1]; + if (nat->nat_hnext[1] != NULL) { + nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; + nat->nat_hnext[1] = NULL; + } + nat->nat_phnext[1] = NULL; + + if ((nat->nat_flags & SI_WILDP) != 0) + nat_stats.ns_wilds--; + } + + if (nat->nat_me != NULL) { + *nat->nat_me = NULL; + nat->nat_me = NULL; + } + + fr_deletequeueentry(&nat->nat_tqe); + + nat->nat_ref--; + if (nat->nat_ref > 0) { + MUTEX_EXIT(&ipf_nat_new); + return; } - if (natd->nat_hm != NULL) - nat_hostmapdel(natd->nat_hm); +#ifdef IPFILTER_SYNC + if (nat->nat_sync) + ipfsync_del(nat->nat_sync); +#endif + + if (nat->nat_fr != NULL) + (void)fr_derefrule(&nat->nat_fr); + + if (nat->nat_hm != NULL) + nat_hostmapdel(nat->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 * longer being used. */ - ipn = natd->nat_ptr; + ipn = nat->nat_ptr; if (ipn != NULL) { ipn->in_space++; ipn->in_use--; - if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) { + if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) { if (ipn->in_apr) appr_free(ipn->in_apr); KFREE(ipn); nat_stats.ns_rules--; +#if SOLARIS + if (nat_stats.ns_rules == 0) + pfil_delayed_copy = 1; +#endif } } - MUTEX_DESTROY(&natd->nat_lock); + MUTEX_DESTROY(&nat->nat_lock); + + aps_free(nat->nat_aps); + nat_stats.ns_inuse--; + MUTEX_EXIT(&ipf_nat_new); + /* * If there's a fragment table entry too for this nat entry, then - * dereference that as well. + * dereference that as well. This is after nat_lock is released + * because of Tru64. */ - ipfr_forgetnat((void *)natd); - aps_free(natd->nat_aps); - nat_stats.ns_inuse--; - KFREE(natd); + fr_forgetnat((void *)nat); + + KFREE(nat); } +/* ------------------------------------------------------------------------ */ +/* Function: nat_flushtable */ +/* Returns: int - number of NAT rules deleted */ +/* Parameters: Nil */ +/* */ +/* Deletes all currently active NAT sessions. In deleting each NAT entry a */ +/* log record should be emitted in nat_delete() if NAT logging is enabled. */ +/* ------------------------------------------------------------------------ */ /* * nat_flushtable - clear the NAT table of all mapping entries. - * (this is for the dynamic mappings) */ static int nat_flushtable() { - register nat_t *nat, **natp; - register int j = 0; + nat_t *nat; + int j = 0; /* * ALL NAT mappings deleted, so lets just make the deletions @@ -1098,26 +1629,28 @@ static int nat_flushtable() bzero((char *)nat_table[1], sizeof(nat_table[1]) * ipf_nattable_sz); - for (natp = &nat_instances; (nat = *natp); ) { - *natp = nat->nat_next; -#ifdef IPFILTER_LOG - nat_log(nat, NL_FLUSH); -#endif - nat_delete(nat); + while ((nat = nat_instances) != NULL) { + nat_delete(nat, NL_FLUSH); j++; } + nat_stats.ns_inuse = 0; return j; } -/* - * nat_clearlist - delete all rules in the active NAT mapping list. - * (this is for NAT/RDR rules) - */ -int nat_clearlist() +/* ------------------------------------------------------------------------ */ +/* Function: nat_clearlist */ +/* Returns: int - number of NAT/RDR rules deleted */ +/* Parameters: Nil */ +/* */ +/* Delete all rules in the current list of rules. There is nothing elegant */ +/* about this cleanup: simply free all entries on the list of rules and */ +/* clear out the tables used for hashed NAT rule lookups. */ +/* ------------------------------------------------------------------------ */ +static int nat_clearlist() { - register ipnat_t *n, **np = &nat_list; + ipnat_t *n, **np = &nat_list; int i = 0; if (nat_rules != NULL) @@ -1125,10 +1658,10 @@ int nat_clearlist() if (rdr_rules != NULL) bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz); - while ((n = *np)) { + while ((n = *np) != NULL) { *np = n->in_next; - if (!n->in_use) { - if (n->in_apr) + if (n->in_use == 0) { + if (n->in_apr != NULL) appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; @@ -1138,35 +1671,481 @@ int nat_clearlist() } i++; } +#if SOLARIS + pfil_delayed_copy = 1; +#endif nat_masks = 0; rdr_masks = 0; return i; } -/* - * Create a new NAT table entry. - * NOTE: Assumes write lock on ipf_nat has been obtained already. - * If you intend on changing this, beware: appr_new() may call nat_new() - * recursively! - */ -nat_t *nat_new(fin, ip, np, natsave, flags, direction) +/* ------------------------------------------------------------------------ */ +/* Function: nat_newmap */ +/* Returns: int - -1 == error, 0 == success */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT entry */ +/* ni(I) - pointer to structure with misc. information needed */ +/* to create new NAT entry. */ +/* */ +/* Given an empty NAT structure, populate it with new information about a */ +/* new NAT session, as defined by the matching NAT rule. */ +/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ +/* to the new IP address for the translation. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_newmap(fin, nat, ni) +fr_info_t *fin; +nat_t *nat; +natinfo_t *ni; +{ + u_short st_port, dport, sport, port, sp, dp; + struct in_addr in, inb; + hostmap_t *hm; + u_32_t flags; + u_32_t st_ip; + ipnat_t *np; + nat_t *natl; + int l; + + /* + * If it's an outbound packet which doesn't match any existing + * record, then create a new port + */ + l = 0; + hm = NULL; + np = ni->nai_np; + st_ip = np->in_nip; + st_port = np->in_pnext; + flags = ni->nai_flags; + sport = ni->nai_sport; + dport = ni->nai_dport; + + /* + * Do a loop until we either run out of entries to try or we find + * a NAT mapping that isn't currently being used. This is done + * because the change to the source is not (usually) being fixed. + */ + do { + port = 0; + 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. + */ + hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, + in, 0); + 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) + return -1; + } + + if (np->in_redir == NAT_BIMAP && + np->in_inmsk == np->in_outmsk) { + /* + * map the address block in a 1:1 fashion + */ + in.s_addr = np->in_outip; + in.s_addr |= fin->fin_saddr & ~np->in_inmsk; + in.s_addr = ntohl(in.s_addr); + + } else if (np->in_redir & NAT_MAPBLK) { + if ((l >= np->in_ppip) || ((l > 0) && + !(flags & IPN_TCPUDP))) + return -1; + /* + * map-block - Calculate destination address. + */ + in.s_addr = ntohl(fin->fin_saddr); + in.s_addr &= ntohl(~np->in_inmsk); + inb.s_addr = in.s_addr; + in.s_addr /= np->in_ippip; + in.s_addr &= ntohl(~np->in_outmsk); + in.s_addr += ntohl(np->in_outip); + /* + * Calculate destination port. + */ + if ((flags & IPN_TCPUDP) && + (np->in_ppip != 0)) { + port = ntohs(sport) + l; + port %= np->in_ppip; + port += np->in_ppip * + (inb.s_addr % np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + + } else if ((np->in_outip == 0) && + (np->in_outmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if ((l > 0) || + fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, + &in, NULL) == -1) + return -1; + in.s_addr = ntohl(in.s_addr); + + } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) { + /* + * 0/0 - use the original source address/port. + */ + if (l > 0) + return -1; + in.s_addr = ntohl(fin->fin_saddr); + + } else if ((np->in_outmsk != 0xffffffff) && + (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) + np->in_nip++; + + natl = NULL; + + if ((flags & IPN_TCPUDP) && + ((np->in_redir & NAT_MAPBLK) == 0) && + (np->in_flags & IPN_AUTOPORTMAP)) { + /* + * "ports auto" (without map-block) + */ + if ((l > 0) && (l % np->in_ppip == 0)) { + if (l > np->in_space) { + return -1; + } else if ((l > np->in_ppip) && + np->in_outmsk != 0xffffffff) + np->in_nip++; + } + if (np->in_ppip != 0) { + port = ntohs(sport); + port += (l % np->in_ppip); + port %= np->in_ppip; + port += np->in_ppip * + (ntohl(fin->fin_saddr) % + np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + + } else if (((np->in_redir & NAT_MAPBLK) == 0) && + (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { + /* + * Standard port translation. Select next port. + */ + port = htons(np->in_pnext++); + + if (np->in_pnext > ntohs(np->in_pmax)) { + np->in_pnext = ntohs(np->in_pmin); + if (np->in_outmsk != 0xffffffff) + np->in_nip++; + } + } + + 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) && + ((np->in_nip + 1) & ntohl(np->in_outmsk)) > + ntohl(np->in_outip)) + np->in_nip = ntohl(np->in_outip) + 1; + } + + if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) + port = sport; + + /* + * Here we do a lookup of the connection as seen from + * the outside. If an IP# pair already exists, try + * again. So if you have A->B becomes C->B, you can + * also have D->E become C->E but not D->B causing + * another C->B. Also take protocol and ports into + * account when determining whether a pre-existing + * NAT setup will cause an external conflict where + * this is appropriate. + */ + inb.s_addr = htonl(in.s_addr); + sp = fin->fin_data[0]; + dp = fin->fin_data[1]; + fin->fin_data[0] = fin->fin_data[1]; + fin->fin_data[1] = htons(port); + natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), + (u_int)fin->fin_p, fin->fin_dst, inb); + fin->fin_data[0] = sp; + fin->fin_data[1] = dp; + + /* + * Has the search wrapped around and come back to the + * start ? + */ + if ((natl != NULL) && + (np->in_pnext != 0) && (st_port == np->in_pnext) && + (np->in_nip != 0) && (st_ip == np->in_nip)) + return -1; + l++; + } while (natl != NULL); + + if (np->in_space > 0) + np->in_space--; + + /* Setup the NAT table */ + nat->nat_inip = fin->fin_src; + nat->nat_outip.s_addr = htonl(in.s_addr); + nat->nat_oip = fin->fin_dst; + if (nat->nat_hm == NULL) + nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, + nat->nat_outip, 0); + + /* + * The ICMP checksum does not have a pseudo header containing + * the IP addresses + */ + ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); + ni->nai_sum2 = LONG_SUM(in.s_addr); + if ((flags & IPN_TCPUDP)) { + ni->nai_sum1 += ntohs(sport); + ni->nai_sum2 += ntohs(port); + } + + if (flags & IPN_TCPUDP) { + nat->nat_inport = sport; + nat->nat_outport = port; /* sport */ + nat->nat_oport = dport; + ((tcphdr_t *)fin->fin_dp)->th_sport = port; + } else if (flags & IPN_ICMPQUERY) { + ((icmphdr_t *)fin->fin_dp)->icmp_id = port; + nat->nat_inport = port; + nat->nat_outport = port; + } else if (fin->fin_p == IPPROTO_GRE) { +#if 0 + nat->nat_gre.gs_flags = ((grehdr_t *)fin->fin_dp)->gr_flags; + if (GRE_REV(nat->nat_gre.gs_flags) == 1) { + nat->nat_oport = 0;/*fin->fin_data[1];*/ + nat->nat_inport = 0;/*fin->fin_data[0];*/ + nat->nat_outport = 0;/*fin->fin_data[0];*/ + nat->nat_call[0] = fin->fin_data[0]; + nat->nat_call[1] = fin->fin_data[0]; + } +#endif + } + ni->nai_ip.s_addr = in.s_addr; + ni->nai_port = port; + ni->nai_nport = dport; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_newrdr */ +/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ +/* allow rule to be moved if IPN_ROUNDR is set. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT entry */ +/* ni(I) - pointer to structure with misc. information needed */ +/* to create new NAT entry. */ +/* */ +/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/ +/* to the new IP address for the translation. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_newrdr(fin, nat, ni) +fr_info_t *fin; +nat_t *nat; +natinfo_t *ni; +{ + u_short nport, dport, sport; + struct in_addr in; + hostmap_t *hm; + u_32_t flags; + ipnat_t *np; + int move; + + move = 1; + hm = NULL; + in.s_addr = 0; + np = ni->nai_np; + flags = ni->nai_flags; + sport = ni->nai_sport; + dport = ni->nai_dport; + + /* + * If the matching rule has IPN_STICKY set, then we want to have the + * same rule kick in as before. Why would this happen? If you have + * a collection of rdr rules with "round-robin sticky", the current + * packet might match a different one to the previous connection but + * we want the same destination to be used. + */ + if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == + (IPN_ROUNDR|IPN_STICKY)) { + hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, + (u_32_t)dport); + if (hm != NULL) { + in.s_addr = ntohl(hm->hm_mapip.s_addr); + np = hm->hm_ipnat; + ni->nai_np = np; + move = 0; + } + } + + /* + * Otherwise, it's an inbound packet. Most likely, we don't + * want to rewrite source ports and source addresses. Instead, + * we want to rewrite to a fixed internal address and fixed + * internal port. + */ + if (np->in_flags & IPN_SPLIT) { + in.s_addr = np->in_nip; + + if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { + hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, + in, (u_32_t)dport); + if (hm != NULL) { + in.s_addr = hm->hm_mapip.s_addr; + move = 0; + } + } + + if (hm == NULL || hm->hm_ref == 1) { + if (np->in_inip == htonl(in.s_addr)) { + np->in_nip = ntohl(np->in_inmsk); + move = 0; + } else { + np->in_nip = ntohl(np->in_inip); + } + } + + } else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL) == -1) + return -1; + in.s_addr = ntohl(in.s_addr); + + } else if ((np->in_inip == 0) && (np->in_inmsk== 0)) { + /* + * 0/0 - use the original destination address/port. + */ + in.s_addr = ntohl(fin->fin_daddr); + + } else if (np->in_redir == NAT_BIMAP && + np->in_inmsk == np->in_outmsk) { + /* + * map the address block in a 1:1 fashion + */ + in.s_addr = np->in_inip; + in.s_addr |= fin->fin_daddr & ~np->in_inmsk; + in.s_addr = ntohl(in.s_addr); + } else { + in.s_addr = ntohl(np->in_inip); + } + + if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) + nport = dport; + else { + /* + * Whilst not optimized for the case where + * pmin == pmax, the gain is not significant. + */ + if (((np->in_flags & IPN_FIXEDDPORT) == 0) && + (np->in_pmin != np->in_pmax)) { + nport = ntohs(dport) - ntohs(np->in_pmin) + + ntohs(np->in_pnext); + nport = htons(nport); + } else + nport = np->in_pnext; + } + + /* + * 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) { + if (nport == dport) + return -1; + in.s_addr = ntohl(fin->fin_daddr); + } + + nat->nat_inip.s_addr = htonl(in.s_addr); + nat->nat_outip = fin->fin_dst; + nat->nat_oip = fin->fin_src; + + ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport); + ni->nai_sum2 = LONG_SUM(in.s_addr) + ntohs(nport); + + ni->nai_ip.s_addr = in.s_addr; + ni->nai_nport = nport; + ni->nai_port = sport; + + if (flags & IPN_TCPUDP) { + nat->nat_inport = nport; + nat->nat_outport = dport; + nat->nat_oport = sport; + ((tcphdr_t *)fin->fin_dp)->th_dport = nport; + } else if (flags & IPN_ICMPQUERY) { + ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; + nat->nat_inport = nport; + nat->nat_outport = nport; + } else if (fin->fin_p == IPPROTO_GRE) { +#if 0 + nat->nat_gre.gs_flags = ((grehdr_t *)fin->fin_dp)->gr_flags; + if (GRE_REV(nat->nat_gre.gs_flags) == 1) { + nat->nat_call[0] = fin->fin_data[0]; + nat->nat_call[1] = fin->fin_data[1]; + nat->nat_oport = 0; /*fin->fin_data[0];*/ + nat->nat_inport = 0; /*fin->fin_data[1];*/ + nat->nat_outport = 0; /*fin->fin_data[1];*/ + } +#endif + } + + return move; +} + +/* ------------------------------------------------------------------------ */ +/* Function: nat_new */ +/* Returns: nat_t* - NULL == failure to create new NAT structure, */ +/* else pointer to new NAT structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* np(I) - pointer to NAT rule */ +/* natsave(I) - pointer to where to store NAT struct pointer */ +/* flags(I) - flags describing the current packet */ +/* direction(I) - direction of packet (in/out) */ +/* Write Lock: ipf_nat */ +/* */ +/* Attempts to create a new NAT entry. Does not actually change the packet */ +/* in any way. */ +/* */ +/* This fucntion is in three main parts: (1) deal with creating a new NAT */ +/* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ +/* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ +/* and (3) building that structure and putting it into the NAT table(s). */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_new(fin, np, natsave, flags, direction) fr_info_t *fin; -ip_t *ip; ipnat_t *np; nat_t **natsave; u_int flags; int direction; { - register u_32_t sum1, sum2, sumd, l; u_short port = 0, sport = 0, dport = 0, nport = 0; - struct in_addr in, inb; - u_short nflags, sp, dp; tcphdr_t *tcp = NULL; hostmap_t *hm = NULL; + struct in_addr in; nat_t *nat, *natl; -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - qif_t *qf = fin->fin_qif; + u_int nflags; + natinfo_t ni; + u_32_t sumd; + int move; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) + qpktinfo_t *qpi = fin->fin_qpi; #endif if (nat_stats.ns_inuse >= ipf_nattable_max) { @@ -1174,12 +2153,13 @@ int direction; return NULL; } - nflags = flags & np->in_flags; - if (flags & IPN_TCPUDP) { - tcp = (tcphdr_t *)fin->fin_dp; - sport = htons(fin->fin_data[0]); - dport = htons(fin->fin_data[1]); - } + move = 1; + nflags = np->in_flags & flags; + nflags &= NAT_FROMRULE; + + ni.nai_np = np; + ni.nai_nflags = nflags; + ni.nai_flags = flags; /* Give me a new nat */ KMALLOC(nat, nat_t *); @@ -1199,352 +2179,237 @@ int direction; return NULL; } + if (flags & IPN_TCPUDP) { + tcp = fin->fin_dp; + ni.nai_sport = htons(fin->fin_sport); + ni.nai_dport = htons(fin->fin_dport); + } else if (flags & IPN_ICMPQUERY) { + /* + * In the ICMP query NAT code, we translate the ICMP id fields + * to make them unique. This is indepedent of the ICMP type + * (e.g. in the unlikely event that a host sends an echo and + * an tstamp request with the same id, both packets will have + * their ip address/id field changed in the same way). + */ + /* The icmp_id field is used by the sender to identify the + * process making the icmp request. (the receiver justs + * copies it back in its response). So, it closely matches + * the concept of source port. We overlay sport, so we can + * maximally reuse the existing code. + */ + ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id; + ni.nai_dport = ni.nai_sport; + } + bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; - if (flags & FI_WILDP) - nat_stats.ns_wilds++; + + if ((flags & NAT_SLAVE) == 0) { + MUTEX_ENTER(&ipf_nat_new); + } + /* * Search the current table for a match. */ if (direction == NAT_OUTBOUND) { /* - * Values at which the search for a free resouce starts. + * We can now arrange to call this for the same connection + * because ipf_nat_new doesn't protect the code path into + * this function. */ - u_32_t st_ip; - u_short st_port; - - /* - * If it's an outbound packet which doesn't match any existing - * record, then create a new port - */ - l = 0; - st_ip = np->in_nip; - st_port = np->in_pnext; - - do { - port = 0; - 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. - */ - hm = nat_hostmap(np, fin->fin_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) - goto badnat; - } - - if (np->in_redir & NAT_MAPBLK) { - if ((l >= np->in_ppip) || ((l > 0) && - !(flags & IPN_TCPUDP))) - goto badnat; - /* - * map-block - Calculate destination address. - */ - in.s_addr = ntohl(fin->fin_saddr); - in.s_addr &= ntohl(~np->in_inmsk); - inb.s_addr = in.s_addr; - in.s_addr /= np->in_ippip; - in.s_addr &= ntohl(~np->in_outmsk); - in.s_addr += ntohl(np->in_outip); - /* - * Calculate destination port. - */ - if ((flags & IPN_TCPUDP) && - (np->in_ppip != 0)) { - port = ntohs(sport) + l; - port %= np->in_ppip; - port += np->in_ppip * - (inb.s_addr % np->in_ippip); - port += MAPBLK_MINPORT; - port = htons(port); - } - } else if (!np->in_outip && - (np->in_outmsk == 0xffffffff)) { - /* - * 0/32 - use the interface's IP address. - */ - if ((l > 0) || - fr_ifpaddr(4, fin->fin_ifp, &in) == -1) - goto badnat; - in.s_addr = ntohl(in.s_addr); - } else if (!np->in_outip && !np->in_outmsk) { - /* - * 0/0 - use the original source address/port. - */ - if (l > 0) - goto badnat; - in.s_addr = ntohl(fin->fin_saddr); - } else if ((np->in_outmsk != 0xffffffff) && - (np->in_pnext == 0) && - ((l > 0) || (hm == NULL))) - np->in_nip++; - natl = NULL; - - if ((nflags & IPN_TCPUDP) && - ((np->in_redir & NAT_MAPBLK) == 0) && - (np->in_flags & IPN_AUTOPORTMAP)) { - if ((l > 0) && (l % np->in_ppip == 0)) { - if (l > np->in_space) { - goto badnat; - } else if ((l > np->in_ppip) && - np->in_outmsk != 0xffffffff) - np->in_nip++; - } - if (np->in_ppip != 0) { - port = ntohs(sport); - port += (l % np->in_ppip); - port %= np->in_ppip; - port += np->in_ppip * - (ntohl(fin->fin_saddr) % - np->in_ippip); - port += MAPBLK_MINPORT; - port = htons(port); - } - } else if (((np->in_redir & NAT_MAPBLK) == 0) && - (nflags & IPN_TCPUDP) && - (np->in_pnext != 0)) { - port = htons(np->in_pnext++); - if (np->in_pnext > ntohs(np->in_pmax)) { - np->in_pnext = ntohs(np->in_pmin); - if (np->in_outmsk != 0xffffffff) - np->in_nip++; - } - } - - 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) && - ((np->in_nip + 1) & ntohl(np->in_outmsk)) > - ntohl(np->in_outip)) - np->in_nip = ntohl(np->in_outip) + 1; - } - - if (!port && (flags & IPN_TCPUDP)) - port = sport; + natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p, + fin->fin_src, fin->fin_dst); + if (natl != NULL) { + nat = natl; + goto done; + } - /* - * Here we do a lookup of the connection as seen from - * the outside. If an IP# pair already exists, try - * again. So if you have A->B becomes C->B, you can - * also have D->E become C->E but not D->B causing - * another C->B. Also take protocol and ports into - * account when determining whether a pre-existing - * NAT setup will cause an external conflict where - * this is appropriate. - */ - inb.s_addr = htonl(in.s_addr); - sp = fin->fin_data[0]; - dp = fin->fin_data[1]; - fin->fin_data[0] = fin->fin_data[1]; - fin->fin_data[1] = htons(port); - natl = nat_inlookup(fin, flags & ~FI_WILDP, - (u_int)fin->fin_p, fin->fin_dst, - inb, 1); - fin->fin_data[0] = sp; - fin->fin_data[1] = dp; + move = nat_newmap(fin, nat, &ni); + if (move == -1) + goto badnat; - /* - * Has the search wrapped around and come back to the - * start ? - */ - if ((natl != NULL) && - (np->in_pnext != 0) && (st_port == np->in_pnext) && - (np->in_nip != 0) && (st_ip == np->in_nip)) - goto badnat; - l++; - } while (natl != NULL); - - if (np->in_space > 0) - np->in_space--; - - /* Setup the NAT table */ - nat->nat_inip = fin->fin_src; - nat->nat_outip.s_addr = htonl(in.s_addr); - nat->nat_oip = fin->fin_dst; - if (nat->nat_hm == NULL) - nat->nat_hm = nat_hostmap(np, fin->fin_src, - nat->nat_outip); - - sum1 = LONG_SUM(ntohl(fin->fin_saddr)) + ntohs(sport); - sum2 = LONG_SUM(in.s_addr) + ntohs(port); - - if (flags & IPN_TCPUDP) { - nat->nat_inport = sport; - nat->nat_outport = port; /* sport */ - nat->nat_oport = dport; - } + np = ni.nai_np; + in = ni.nai_ip; } else { /* - * Otherwise, it's an inbound packet. Most likely, we don't - * want to rewrite source ports and source addresses. Instead, - * we want to rewrite to a fixed internal address and fixed - * internal port. + * NAT_INBOUND is used only for redirects rules */ - 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. - */ - if (np->in_pmin != np->in_pmax) { - nport = ntohs(dport) - ntohs(np->in_pmin) + - ntohs(np->in_pnext); - nport = ntohs(nport); - } else - nport = np->in_pnext; + natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p, + fin->fin_src, fin->fin_dst); + if (natl != NULL) { + nat = natl; + goto done; } - /* - * When the redirect-to address is set to 0.0.0.0, just - * assume a blank `forwarding' of the packet. - */ - if (in.s_addr == 0) - in.s_addr = ntohl(fin->fin_daddr); - - nat->nat_inip.s_addr = htonl(in.s_addr); - nat->nat_outip = fin->fin_dst; - nat->nat_oip = fin->fin_src; - - sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport); - sum2 = LONG_SUM(in.s_addr) + ntohs(nport); + move = nat_newrdr(fin, nat, &ni); + if (move == -1) + goto badnat; - if (flags & IPN_TCPUDP) { - nat->nat_inport = nport; - nat->nat_outport = dport; - nat->nat_oport = sport; + np = ni.nai_np; + in = ni.nai_ip; + } + port = ni.nai_port; + nport = ni.nai_nport; + + if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { + if (np->in_redir == NAT_REDIRECT) { + nat_delrdr(np); + nat_addrdr(np); + } else if (np->in_redir == NAT_MAP) { + nat_delnat(np); + nat_addnat(np); } } - CALC_SUMD(sum1, sum2, sumd); + if (flags & IPN_TCPUDP) { + sport = ni.nai_sport; + dport = ni.nai_dport; + } else if (flags & IPN_ICMPQUERY) { + sport = ni.nai_sport; + dport = 0; + } + + CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) if ((flags & IPN_TCP) && dohwcksum && - (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { + (((ill_t *)qpi->qpi_ill)->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { if (direction == NAT_OUTBOUND) - sum1 = LONG_SUM(ntohl(in.s_addr)); + ni.nai_sum1 = LONG_SUM(in.s_addr); else - sum1 = LONG_SUM(ntohl(fin->fin_saddr)); - sum1 += LONG_SUM(ntohl(fin->fin_daddr)); - sum1 += IPPROTO_TCP; - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff); + ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); + ni.nai_sum1 += LONG_SUM(ntohl(fin->fin_daddr)); + ni.nai_sum1 += 30; + ni.nai_sum1 = (ni.nai_sum1 & 0xffff) + (ni.nai_sum1 >> 16); + nat->nat_sumd[1] = NAT_HW_CKSUM|(ni.nai_sum1 & 0xffff); } else #endif nat->nat_sumd[1] = nat->nat_sumd[0]; - if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) { + if ((flags & IPN_TCPUDPICMP) && ((sport != port) || (dport != nport))) { if (direction == NAT_OUTBOUND) - sum1 = LONG_SUM(ntohl(fin->fin_saddr)); + ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); else - sum1 = LONG_SUM(ntohl(fin->fin_daddr)); + ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)); - sum2 = LONG_SUM(in.s_addr); + ni.nai_sum2 = LONG_SUM(in.s_addr); - CALC_SUMD(sum1, sum2, sumd); + CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); - } else + } else { nat->nat_ipsumd = nat->nat_sumd[0]; + if (!(flags & IPN_TCPUDPICMP)) { + nat->nat_sumd[0] = 0; + nat->nat_sumd[1] = 0; + } + } - in.s_addr = htonl(in.s_addr); + if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) { + goto badnat; + } + if (flags & SI_WILDP) + nat_stats.ns_wilds++; + goto done; +badnat: + nat_stats.ns_badnat++; + if ((hm = nat->nat_hm) != NULL) + nat_hostmapdel(hm); + KFREE(nat); + nat = NULL; +done: + if ((flags & NAT_SLAVE) == 0) { + MUTEX_EXIT(&ipf_nat_new); + } + return nat; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_finalise */ +/* Returns: int - 0 == sucess, -1 == failure */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT entry */ +/* ni(I) - pointer to structure with misc. information needed */ +/* to create new NAT entry. */ +/* Write Lock: ipf_nat */ +/* */ +/* This is the tail end of constructing a new NAT entry and is the same */ +/* for both IPv4 and IPv6. */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction) +fr_info_t *fin; +nat_t *nat; +natinfo_t *ni; +tcphdr_t *tcp; +nat_t **natsave; +int direction; +{ + frentry_t *fr; + ipnat_t *np; - strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ); + np = ni->nai_np; + + COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0]); +#ifdef IPFILTER_SYNC + if ((nat->nat_flags & SI_CLONE) == 0) + nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); +#endif nat->nat_me = natsave; nat->nat_dir = direction; - nat->nat_ifp = fin->fin_ifp; + nat->nat_ifps[0] = fin->fin_ifp; nat->nat_ptr = np; nat->nat_p = fin->fin_p; - nat->nat_bytes = 0; - nat->nat_pkts = 0; nat->nat_mssclamp = np->in_mssclamp; - nat->nat_fr = fin->fin_fr; - if (nat->nat_fr != NULL) { - ATOMIC_INC32(nat->nat_fr->fr_ref); - } - if (direction == NAT_OUTBOUND) { - if (flags & IPN_TCPUDP) - tcp->th_sport = port; - } else { - if (flags & IPN_TCPUDP) - tcp->th_dport = nport; + fr = fin->fin_fr; + nat->nat_fr = fr; + + if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) + if (appr_new(fin, nat) == -1) + return -1; + + if (nat_insert(nat, fin->fin_rev) == 0) { + if (nat_logging) + nat_log(nat, (u_int)np->in_redir); + np->in_use++; + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + MUTEX_EXIT(&fr->fr_lock); + } + return 0; } - nat_insert(nat); - - if ((np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && dport == np->in_dport))) - (void) appr_new(fin, ip, nat); - - np->in_use++; -#ifdef IPFILTER_LOG - nat_log(nat, (u_int)np->in_redir); -#endif - return nat; -badnat: - nat_stats.ns_badnat++; - if ((hm = nat->nat_hm) != NULL) - nat_hostmapdel(hm); - KFREE(nat); - return NULL; + /* + * nat_insert failed, so cleanup time... + */ + return -1; } -/* - * Insert a NAT entry into the hash tables for searching and add it to the - * list of active NAT entries. Adjust global counters when complete. - */ -void nat_insert(nat) +/* ------------------------------------------------------------------------ */ +/* Function: nat_insert */ +/* Returns: int - 0 == sucess, -1 == failure */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* rev(I) - flag indicating forward/reverse direction of packet */ +/* Write Lock: ipf_nat */ +/* */ +/* Insert a NAT entry into the hash tables for searching and add it to the */ +/* list of active NAT entries. Adjust global counters when complete. */ +/* ------------------------------------------------------------------------ */ +int nat_insert(nat, rev) nat_t *nat; +int rev; { u_int hv1, hv2; nat_t **natp; - 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; - - if (!(nat->nat_flags & (FI_W_SPORT|FI_W_DPORT))) { + /* + * Try and return an error as early as possible, so calculate the hash + * entry numbers first and then proceed. + */ + if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, @@ -1552,20 +2417,57 @@ nat_t *nat; hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, - ipf_nattable_sz); - } else { - hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, nat->nat_inip.s_addr, - ipf_nattable_sz); - hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, nat->nat_outip.s_addr, ipf_nattable_sz); + } else { + hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); + hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz); + hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); + hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz); + } + + if (nat_stats.ns_bucketlen[0][hv1] >= fr_nat_maxbucket || + nat_stats.ns_bucketlen[1][hv2] >= fr_nat_maxbucket) { + return -1; + } + + nat->nat_hv[0] = hv1; + nat->nat_hv[1] = hv2; + + MUTEX_INIT(&nat->nat_lock, "nat entry lock"); + + nat->nat_rev = rev; + nat->nat_ref = 1; + nat->nat_bytes[0] = 0; + nat->nat_pkts[0] = 0; + nat->nat_bytes[1] = 0; + nat->nat_pkts[1] = 0; + + nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; + nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4); + + if (nat->nat_ifnames[1][0] !='\0') { + nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; + nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4); + } else { + (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0], + LIFNAMSIZ); + nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; + nat->nat_ifps[1] = nat->nat_ifps[0]; } + nat->nat_next = nat_instances; + nat->nat_pnext = &nat_instances; + if (nat_instances) + nat_instances->nat_pnext = &nat->nat_next; + nat_instances = nat; + natp = &nat_table[0][hv1]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + nat_stats.ns_bucketlen[0][hv1]++; natp = &nat_table[1][hv2]; if (*natp) @@ -1573,44 +2475,56 @@ nat_t *nat; nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; + nat_stats.ns_bucketlen[1][hv2]++; + + fr_setnatqueue(nat, rev); nat_stats.ns_added++; nat_stats.ns_inuse++; + return 0; } -nat_t *nat_icmplookup(ip, fin, dir) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: nat_icmperrorlookup */ +/* Returns: nat_t* - point to matching NAT structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* dir(I) - direction of packet (in/out) */ +/* */ +/* Check if the ICMP error message is related to an existing TCP, UDP or */ +/* ICMP query nat entry. It is assumed that the packet is already of the */ +/* the required length. */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_icmperrorlookup(fin, dir) fr_info_t *fin; int dir; { - icmphdr_t *icmp; + int flags = 0, type, minlen; + icmphdr_t *icmp, *orgicmp; tcphdr_t *tcp = NULL; + u_short data[2]; + nat_t *nat; ip_t *oip; - int flags = 0, type, minlen; + u_int p; - icmp = (icmphdr_t *)fin->fin_dp; + icmp = fin->fin_dp; + type = icmp->icmp_type; /* * Does it at least have the return (basic) IP header ? * Only a basic IP header (no options) should be with an ICMP error - * header. + * header. Also, if it's not an error type, then return. */ - if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN)) + if ((fin->fin_hlen != sizeof(ip_t)) || + !fr_icmp4errortype(type)) return NULL; - type = icmp->icmp_type; + /* - * If it's not an error type, then return. + * Check packet size */ - if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && - (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && - (type != ICMP_PARAMPROB)) - return NULL; - oip = (ip_t *)((char *)fin->fin_dp + 8); - minlen = (oip->ip_hl << 2); - if (minlen < sizeof(ip_t)) - return NULL; - if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) + minlen = IP_HL(oip) << 2; + if ((minlen < sizeof(ip_t)) || + (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) return NULL; /* * Is the buffer big enough for all of it ? It's the size of the IP @@ -1625,105 +2539,146 @@ int dir; { mb_t *m; -# if SOLARIS - m = fin->fin_qfm; + m = fin->fin_m; +# if defined(MENTAT) if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) return NULL; # else - m = *(mb_t **)fin->fin_mp; if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > - (char *)ip + m->m_len) + (char *)fin->fin_ip + M_LEN(m)) return NULL; # endif } #endif - if (oip->ip_p == IPPROTO_TCP) + if (fin->fin_daddr != oip->ip_src.s_addr) + return NULL; + + p = oip->ip_p; + if (p == IPPROTO_TCP) flags = IPN_TCP; - else if (oip->ip_p == IPPROTO_UDP) + else if (p == IPPROTO_UDP) flags = IPN_UDP; - if (flags & IPN_TCPUDP) { - u_short data[2]; - nat_t *nat; + else if (p == IPPROTO_ICMP) { + orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); + + /* see if this is related to an ICMP query */ + if (nat_icmpquerytype4(orgicmp->icmp_type)) { + data[0] = fin->fin_data[0]; + data[1] = fin->fin_data[1]; + fin->fin_data[0] = 0; + fin->fin_data[1] = orgicmp->icmp_id; + flags = IPN_ICMPERR|IPN_ICMPQUERY; + /* + * NOTE : dir refers to the direction of the original + * ip packet. By definition the icmp error + * message flows in the opposite direction. + */ + if (dir == NAT_INBOUND) + nat = nat_inlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); + else + nat = nat_outlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); + fin->fin_data[0] = data[0]; + fin->fin_data[1] = data[1]; + return nat; + } + } + + if (flags & IPN_TCPUDP) { minlen += 8; /* + 64bits of data to get ports */ - if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) + if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) return NULL; data[0] = fin->fin_data[0]; data[1] = fin->fin_data[1]; - tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); + tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); fin->fin_data[0] = ntohs(tcp->th_dport); fin->fin_data[1] = ntohs(tcp->th_sport); if (dir == NAT_INBOUND) { - nat = nat_inlookup(fin, flags, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + nat = nat_inlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); } else { - nat = nat_outlookup(fin, flags, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + nat = nat_outlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); } fin->fin_data[0] = data[0]; fin->fin_data[1] = data[1]; return nat; } if (dir == NAT_INBOUND) - return nat_inlookup(fin, 0, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); else - return nat_outlookup(fin, 0, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); } -/* - * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP - * packet gets correctly recognised. - */ -nat_t *nat_icmp(ip, fin, nflags, dir) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: nat_icmperror */ +/* Returns: nat_t* - point to matching NAT structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* nflags(I) - NAT flags for this packet */ +/* dir(I) - direction of packet (in/out) */ +/* */ +/* Fix up an ICMP packet which is an error message for an existing NAT */ +/* session. This will correct both packet header data and checksums. */ +/* */ +/* This should *ONLY* be used for incoming ICMP error packets to make sure */ +/* a NAT'd ICMP packet gets correctly recognised. */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_icmperror(fin, nflags, dir) fr_info_t *fin; u_int *nflags; int dir; { - u_32_t sum1, sum2, sumd, sumd2 = 0; + u_32_t sum1, sum2, sumd, sumd2; struct in_addr in; - int flags, dlen; icmphdr_t *icmp; - udphdr_t *udp; + int flags, dlen; + u_short *csump; tcphdr_t *tcp; nat_t *nat; ip_t *oip; + void *dp; - if ((fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) + if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) return NULL; /* - * nat_icmplookup() will return NULL for `defective' packets. + * nat_icmperrorlookup() will return NULL for `defective' packets. */ - if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) + if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir))) return NULL; + tcp = NULL; + csump = NULL; flags = 0; sumd2 = 0; *nflags = IPN_ICMPERR; - icmp = (icmphdr_t *)fin->fin_dp; + icmp = fin->fin_dp; oip = (ip_t *)&icmp->icmp_ip; - if (oip->ip_p == IPPROTO_TCP) + dp = (((char *)oip) + (IP_HL(oip) << 2)); + if (oip->ip_p == IPPROTO_TCP) { + tcp = (tcphdr_t *)dp; + csump = (u_short *)&tcp->th_sum; flags = IPN_TCP; - else if (oip->ip_p == IPPROTO_UDP) + } else if (oip->ip_p == IPPROTO_UDP) { + udphdr_t *udp; + + udp = (udphdr_t *)dp; + tcp = (tcphdr_t *)dp; + csump = (u_short *)&udp->uh_sum; flags = IPN_UDP; - udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); - dlen = ip->ip_len - ((char *)udp - (char *)ip); - /* - * XXX - what if this is bogus hl and we go off the end ? - * In this case, nat_icmplookup() will have returned NULL. - */ - tcp = (tcphdr_t *)udp; + } else if (oip->ip_p == IPPROTO_ICMP) + flags = IPN_ICMPQUERY; + dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip); /* * Need to adjust ICMP header to include the real IP#'s and * port #'s. Only apply a checksum change relative to the - * IP address change as it will be modified again in ip_natout + * IP address change as it will be modified again in fr_checknatout * for both address and port. Two checksum changes are * necessary for the two header address changes. Be careful * to only modify the checksum once for the port # and twice @@ -1741,7 +2696,6 @@ int dir; * checksum. So, we must compensate that as well. Even worse, the * change in the UDP and TCP checksums require yet another * adjustment of the ICMP checksum of the ICMP error message. - * */ if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { @@ -1762,14 +2716,14 @@ int dir; * Fix IP checksum of the offending IP packet to adjust for * the change in the IP address. * - * Normally, you would expect that the ICMP checksum of the + * Normally, you would expect that the ICMP checksum of the * ICMP error message needs to be adjusted as well for the * IP address change in oip. - * However, this is a NOP, because the ICMP checksum is + * However, this is a NOP, because the ICMP checksum is * calculated over the complete ICMP packet, which includes the - * changed oip IP addresses and oip->ip_sum. However, these + * changed oip IP addresses and oip->ip_sum. However, these * two changes cancel each other out (if the delta for - * the IP address is x, then the delta for ip_sum is minus x), + * the IP address is x, then the delta for ip_sum is minus x), * so no change in the icmp_cksum is necessary. * * Be careful that nat_dir refers to the direction of the @@ -1777,22 +2731,23 @@ int dir; */ fix_datacksum(&oip->ip_sum, sumd); /* Fix icmp cksum : IP Addr + Cksum */ + sumd2 = (sumd >> 16); /* * Fix UDP pseudo header checksum to compensate for the * IP address change. */ - if ((oip->ip_p == IPPROTO_UDP) && (dlen >= 8) && udp->uh_sum) { + if ((oip->ip_p == IPPROTO_UDP) && (dlen >= 8) && (*csump != 0)) { /* - * The UDP checksum is optional, only adjust it + * The UDP checksum is optional, only adjust it * if it has been set. */ - sum1 = ntohs(udp->uh_sum); - fix_datacksum(&udp->uh_sum, sumd); - sum2 = ntohs(udp->uh_sum); + sum1 = ntohs(*csump); + fix_datacksum(csump, sumd); + sum2 = ntohs(*csump); /* - * Fix ICMP checksum to compensate the UDP + * Fix ICMP checksum to compensate the UDP * checksum adjustment. */ sumd2 = sumd << 1; @@ -1801,25 +2756,25 @@ int dir; } /* - * Fix TCP pseudo header checksum to compensate for the + * Fix TCP pseudo header checksum to compensate for the * IP address change. Before we can do the change, we * must make sure that oip is sufficient large to hold * the TCP checksum (normally it does not!). + * 18 = offsetof(tcphdr_t, th_sum) + 2 */ - else if ((oip->ip_p == IPPROTO_TCP) && (dlen >= 18)) { - sum1 = ntohs(tcp->th_sum); - fix_datacksum(&tcp->th_sum, sumd); - sum2 = ntohs(tcp->th_sum); + else if (oip->ip_p == IPPROTO_TCP && dlen >= 18) { + sum1 = ntohs(*csump); + fix_datacksum(csump, sumd); + sum2 = ntohs(*csump); /* - * Fix ICMP checksum to compensate the TCP + * Fix ICMP checksum to compensate the TCP * checksum adjustment. */ sumd2 = sumd << 1; CALC_SUMD(sum1, sum2, sumd); sumd2 += sumd; } else { - sumd2 = (sumd >> 16); if (nat->nat_dir == NAT_OUTBOUND) sumd2 = ~sumd2; else @@ -1827,6 +2782,8 @@ int dir; } if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) { + int mode = 0; + /* * Step 2 : * For offending TCP/UDP IP packets, translate the ports as @@ -1846,166 +2803,215 @@ int dir; * include the TCP checksum. So we have to check if the * ip->ip_len actually holds the TCP checksum of the oip! */ - if (nat->nat_oport == tcp->th_dport) { + + if (nat->nat_oport == tcp->th_dport) { if (tcp->th_sport != nat->nat_inport) { - /* - * Fix ICMP checksum to compensate port - * adjustment. - */ + mode = 1; sum1 = ntohs(nat->nat_inport); sum2 = ntohs(tcp->th_sport); - tcp->th_sport = nat->nat_inport; + } + } else if (tcp->th_sport == nat->nat_oport) { + mode = 2; + sum1 = ntohs(nat->nat_outport); + sum2 = ntohs(tcp->th_dport); + } + + if (mode == 1) { + /* + * Fix ICMP checksum to compensate port adjustment. + */ + tcp->th_sport = htons(sum1); + + /* + * Fix udp checksum to compensate port adjustment. + * NOTE : the offending IP packet flows the other + * direction compared to the ICMP message. + * + * The UDP checksum is optional, only adjust it if + * it has been set. + */ + if ((oip->ip_p == IPPROTO_UDP) && + (dlen >= 8) && (*csump != 0)) { + sumd = sum1 - sum2; + sumd2 += sumd; + + sum1 = ntohs(*csump); + fix_datacksum(csump, sumd); + sum2 = ntohs(*csump); /* - * Fix udp checksum to compensate port - * adjustment. NOTE : the offending IP packet - * flows the other direction compared to the - * ICMP message. - * - * The UDP checksum is optional, only adjust - * it if it has been set. + * Fix ICMP checksum to compenstate + * UDP checksum adjustment. */ - if ((oip->ip_p == IPPROTO_UDP) && - (dlen >= 8) && udp->uh_sum) { + CALC_SUMD(sum1, sum2, sumd); + sumd2 += sumd; + } + + /* + * Fix TCP checksum (if present) to compensate port + * adjustment. NOTE : the offending IP packet flows + * the other direction compared to the ICMP message. + */ + if (oip->ip_p == IPPROTO_TCP) { + if (dlen >= 18) { sumd = sum1 - sum2; sumd2 += sumd; - sum1 = ntohs(udp->uh_sum); - fix_datacksum(&udp->uh_sum, sumd); - sum2 = ntohs(udp->uh_sum); + sum1 = ntohs(*csump); + fix_datacksum(csump, sumd); + sum2 = ntohs(*csump); /* * Fix ICMP checksum to compensate - * UDP checksum adjustment. + * TCP checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); sumd2 += sumd; - } - - /* - * Fix tcp checksum (if present) to compensate - * port adjustment. NOTE : the offending IP - * packet flows the other direction compared to - * the ICMP message. - */ - if (oip->ip_p == IPPROTO_TCP) { - if (dlen >= 18) { - sumd = sum1 - sum2; - sumd2 += sumd; - - sum1 = ntohs(tcp->th_sum); - fix_datacksum(&tcp->th_sum, - sumd); - sum2 = ntohs(tcp->th_sum); - - /* - * Fix ICMP checksum to - * compensate TCP checksum - * adjustment. - */ - CALC_SUMD(sum1, sum2, sumd); - sumd2 += sumd; - } else { - sumd = sum2 - sum1 + 1; - sumd2 += sumd; - } + } else { + sumd = sum2 - sum1 + 1; + sumd2 += sumd; } } - } else if (tcp->th_dport != nat->nat_outport) { + } else if (mode == 2) { /* - * Fix ICMP checksum to compensate port - * adjustment. + * Fix ICMP checksum to compensate port adjustment. */ - sum1 = ntohs(nat->nat_outport); - sum2 = ntohs(tcp->th_dport); - tcp->th_dport = nat->nat_outport; + tcp->th_dport = htons(sum1); /* - * Fix udp checksum to compensate port - * adjustment. NOTE : the offending IP - * packet flows the other direction compared - * to the ICMP message. + * Fix UDP checksum to compensate port adjustment. + * NOTE : the offending IP packet flows the other + * direction compared to the ICMP message. * * The UDP checksum is optional, only adjust * it if it has been set. */ if ((oip->ip_p == IPPROTO_UDP) && - (dlen >= 8) && udp->uh_sum) { + (dlen >= 8) && (*csump != 0)) { sumd = sum1 - sum2; sumd2 += sumd; - sum1 = ntohs(udp->uh_sum); - fix_datacksum(&udp->uh_sum, sumd); - sum2 = ntohs(udp->uh_sum); + sum1 = ntohs(*csump); + fix_datacksum(csump, sumd); + sum2 = ntohs(*csump); /* * Fix ICMP checksum to compensate * UDP checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); + sumd2 += sumd; } /* - * Fix tcp checksum (if present) to compensate - * port adjustment. NOTE : the offending IP - * packet flows the other direction compared to - * the ICMP message. + * Fix TCP checksum (if present) to compensate port + * adjustment. NOTE : the offending IP packet flows + * the other direction compared to the ICMP message. */ if (oip->ip_p == IPPROTO_TCP) { if (dlen >= 18) { sumd = sum1 - sum2; sumd2 += sumd; - sum1 = ntohs(tcp->th_sum); - fix_datacksum(&tcp->th_sum, sumd); - sum2 = ntohs(tcp->th_sum); + sum1 = ntohs(*csump); + fix_datacksum(csump, sumd); + sum2 = ntohs(*csump); /* * Fix ICMP checksum to compensate - * UDP checksum adjustment. + * TCP checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); + sumd2 += sumd; } else { - sumd = sum2 - sum1; - if (nat->nat_dir == NAT_OUTBOUND) - sumd++; + if (nat->nat_dir == NAT_INBOUND) + sumd = sum2 - sum1; + else + sumd = sum2 - sum1 + 1; + sumd2 += sumd; } } - sumd2 += sumd; } - if (sumd2) { + if (sumd2 != 0) { sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); fix_incksum(fin, &icmp->icmp_cksum, sumd2); } + } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) { + icmphdr_t *orgicmp; + + /* + * XXX - what if this is bogus hl and we go off the end ? + * In this case, nat_icmperrorlookup() will have returned NULL. + */ + orgicmp = (icmphdr_t *)dp; + + if (nat->nat_dir == NAT_OUTBOUND) { + if (orgicmp->icmp_id != nat->nat_inport) { + + /* + * Fix ICMP checksum (of the offening ICMP + * query packet) to compensate the change + * in the ICMP id of the offending ICMP + * packet. + * + * Since you modify orgicmp->icmp_id with + * a delta (say x) and you compensate that + * in origicmp->icmp_cksum with a delta + * minus x, you don't have to adjust the + * overall icmp->icmp_cksum + */ + sum1 = ntohs(orgicmp->icmp_id); + sum2 = ntohs(nat->nat_inport); + CALC_SUMD(sum1, sum2, sumd); + orgicmp->icmp_id = nat->nat_inport; + fix_datacksum(&orgicmp->icmp_cksum, sumd); + } + } /* nat_dir == NAT_INBOUND is impossible for icmp queries */ } - if (oip->ip_p == IPPROTO_ICMP) - nat->nat_age = fr_defnaticmpage; return nat; } /* - * NB: these lookups don't lock access to the list, it assume it has already - * been done! + * NB: these lookups don't lock access to the list, it assumed that it has + * already been done! */ -/* - * Lookup a nat entry based on the mapped destination ip address/port and - * real source address/port. We use this lookup when receiving a packet, - * we're looking for a table entry, based on the destination address. - * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. - */ -nat_t *nat_inlookup(fin, flags, p, src, mapdst, rw) + +/* ------------------------------------------------------------------------ */ +/* Function: nat_inlookup */ +/* Returns: nat_t* - NULL == no match, */ +/* else pointer to matching NAT entry */ +/* Parameters: fin(I) - pointer to packet information */ +/* flags(I) - NAT flags for this packet */ +/* p(I) - protocol for this packet */ +/* src(I) - source IP address */ +/* mapdst(I) - destination IP address */ +/* */ +/* Lookup a nat entry based on the mapped destination ip address/port and */ +/* real source address/port. We use this lookup when receiving a packet, */ +/* we're looking for a table entry, based on the destination address. */ +/* */ +/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ +/* */ +/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ +/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ +/* */ +/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ +/* the packet is of said protocol */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_inlookup(fin, flags, p, src, mapdst) fr_info_t *fin; -register u_int flags, p; +u_int flags, p; struct in_addr src , mapdst; -int rw; { - register u_short sport, dport; - register nat_t *nat; - register int nflags; - register u_32_t dst; + u_short sport, dport; + grehdr_t *gre; ipnat_t *ipn; + u_int sflags; + nat_t *nat; + int nflags; + u_32_t dst; void *ifp; u_int hv; @@ -2013,26 +3019,71 @@ int rw; ifp = fin->fin_ifp; else ifp = NULL; + sport = 0; + dport = 0; + gre = NULL; dst = mapdst.s_addr; - if (flags & IPN_TCPUDP) { + sflags = flags & NAT_TCPUDPICMP; + + switch (p) + { + case IPPROTO_TCP : + case IPPROTO_UDP : sport = htons(fin->fin_data[0]); dport = htons(fin->fin_data[1]); - } else { - sport = 0; - dport = 0; + break; + case IPPROTO_ICMP : + if (flags & IPN_ICMPERR) + sport = fin->fin_data[1]; + else + dport = fin->fin_data[1]; + break; + default : + break; } + + if ((flags & SI_WILDP) != 0) + goto find_in_wild_ports; + hv = NAT_HASH_FN(dst, dport, 0xffffffff); hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz); nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; - if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_oip.s_addr == src.s_addr && + + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[0]) + continue; + } else { + if (ifp != nat->nat_ifps[1]) + continue; + } + } + + if (nat->nat_oip.s_addr == src.s_addr && nat->nat_outip.s_addr == dst && - ((p == 0) || (p == nat->nat_p))) { + (((p == 0) && + (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) + || (p == nat->nat_p))) { switch (p) { +#if 0 + case IPPROTO_GRE : + if (nat->nat_call[1] != fin->fin_data[0]) + continue; + break; +#endif + case IPPROTO_ICMP : + if ((flags & IPN_ICMPERR) != 0) { + if (nat->nat_outport != sport) + continue; + } else { + if (nat->nat_outport != dport) + continue; + } + break; case IPPROTO_TCP : case IPPROTO_UDP : if (nat->nat_oport != sport) @@ -2051,56 +3102,94 @@ int rw; return nat; } } - if (!nat_stats.ns_wilds || !(flags & FI_WILDP)) + + /* + * So if we didn't find it but there are wildcard members in the hash + * table, go back and look for them. We do this search and update here + * because it is modifying the NAT table and we want to do this only + * for the first packet that matches. The exception, of course, is + * for "dummy" (FI_IGNORE) lookups. + */ +find_in_wild_ports: + if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) return NULL; - if (!rw) { - RWLOCK_EXIT(&ipf_nat); - } + if (nat_stats.ns_wilds == 0) + return NULL; + + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(dst, 0, 0xffffffff); - hv = NAT_HASH_FN(src.s_addr, dst, ipf_nattable_sz); - if (!rw) { - WRITE_ENTER(&ipf_nat); - } + hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz); + + WRITE_ENTER(&ipf_nat); + nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { - nflags = nat->nat_flags; - if (ifp && ifp != nat->nat_ifp) - continue; - if (!(nflags & FI_WILDP)) + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[0]) + continue; + } else { + if (ifp != nat->nat_ifps[1]) + continue; + } + } + + if (nat->nat_p != fin->fin_p) continue; if (nat->nat_oip.s_addr != src.s_addr || nat->nat_outip.s_addr != dst) continue; - if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && - ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { - nat_tabmove(fin, nat); + + nflags = nat->nat_flags; + if (!(nflags & (NAT_TCPUDP|SI_WILDP))) + continue; + + if (nat_wildok(nat, (int)sport, (int)dport, nflags, + NAT_INBOUND) == 1) { + if ((fin->fin_flx & FI_IGNORE) != 0) + break; + if ((nflags & SI_CLONE) != 0) { + nat = fr_natclone(fin, nat); + if (nat == NULL) + break; + } else { + MUTEX_ENTER(&ipf_nat_new); + nat_stats.ns_wilds--; + MUTEX_EXIT(&ipf_nat_new); + } + nat->nat_oport = sport; + nat->nat_outport = dport; + nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); + nat_tabmove(nat); break; } } - if (!rw) { - MUTEX_DOWNGRADE(&ipf_nat); - } + + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } -/* - * This function is only called for TCP/UDP NAT table entries where the - * original was placed in the table without hashing on the ports and we now - * want to include hashing on port numbers. - */ -static void nat_tabmove(fin, nat) -fr_info_t *fin; +/* ------------------------------------------------------------------------ */ +/* Function: nat_tabmove */ +/* Returns: Nil */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* Write Lock: ipf_nat */ +/* */ +/* This function is only called for TCP/UDP NAT table entries where the */ +/* original was placed in the table without hashing on the ports and we now */ +/* want to include hashing on port numbers. */ +/* ------------------------------------------------------------------------ */ +static void nat_tabmove(nat) nat_t *nat; { - register u_short sport, dport; - u_int hv, nflags; nat_t **natp; + u_int hv; - nflags = nat->nat_flags; - - sport = ntohs(fin->fin_data[0]); - dport = ntohs(fin->fin_data[1]); + if (nat->nat_flags & SI_CLONE) + return; /* * Remove the NAT entry from the old location @@ -2108,76 +3197,133 @@ nat_t *nat; if (nat->nat_hnext[0]) nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; *nat->nat_phnext[0] = nat->nat_hnext[0]; + nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; if (nat->nat_hnext[1]) nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; *nat->nat_phnext[1] = nat->nat_hnext[1]; + nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; /* * Add into the NAT table in the new position */ - hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, 0xffffffff); - hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); + hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, + ipf_nattable_sz); + nat->nat_hv[0] = hv; natp = &nat_table[0][hv]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + nat_stats.ns_bucketlen[0][hv]++; - hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, 0xffffffff); - hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); + hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, + ipf_nattable_sz); + nat->nat_hv[1] = hv; natp = &nat_table[1][hv]; if (*natp) (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; + nat_stats.ns_bucketlen[1][hv]++; } -/* - * Lookup a nat entry based on the source 'real' ip address/port and - * destination address/port. We use this lookup when sending a packet out, - * we're looking for a table entry, based on the source address. - * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. - */ -nat_t *nat_outlookup(fin, flags, p, src, dst, rw) +/* ------------------------------------------------------------------------ */ +/* Function: nat_outlookup */ +/* Returns: nat_t* - NULL == no match, */ +/* else pointer to matching NAT entry */ +/* Parameters: fin(I) - pointer to packet information */ +/* flags(I) - NAT flags for this packet */ +/* p(I) - protocol for this packet */ +/* src(I) - source IP address */ +/* dst(I) - destination IP address */ +/* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */ +/* */ +/* Lookup a nat entry based on the source 'real' ip address/port and */ +/* destination address/port. We use this lookup when sending a packet out, */ +/* we're looking for a table entry, based on the source address. */ +/* */ +/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ +/* */ +/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ +/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ +/* */ +/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ +/* the packet is of said protocol */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_outlookup(fin, flags, p, src, dst) fr_info_t *fin; -register u_int flags, p; +u_int flags, p; struct in_addr src , dst; -int rw; { - register u_short sport, dport; - register nat_t *nat; - register int nflags; + u_short sport, dport; + u_int sflags; ipnat_t *ipn; u_32_t srcip; + nat_t *nat; + int nflags; void *ifp; u_int hv; ifp = fin->fin_ifp; srcip = src.s_addr; - if (flags & IPN_TCPUDP) { - sport = ntohs(fin->fin_data[0]); - dport = ntohs(fin->fin_data[1]); - } else { - sport = 0; - dport = 0; + sflags = flags & IPN_TCPUDPICMP; + sport = 0; + dport = 0; + + switch (p) + { + case IPPROTO_TCP : + case IPPROTO_UDP : + sport = htons(fin->fin_data[0]); + dport = htons(fin->fin_data[1]); + break; + case IPPROTO_ICMP : + if (flags & IPN_ICMPERR) + sport = fin->fin_data[1]; + else + dport = fin->fin_data[1]; + break; + default : + break; } + if ((flags & SI_WILDP) != 0) + goto find_out_wild_ports; + hv = NAT_HASH_FN(srcip, sport, 0xffffffff); hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz); nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; - if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_inip.s_addr == srcip && + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[1]) + continue; + } else { + if (ifp != nat->nat_ifps[0]) + continue; + } + } + + if (nat->nat_inip.s_addr == srcip && nat->nat_oip.s_addr == dst.s_addr && - ((p == 0) || (p == nat->nat_p))) { + (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) + || (p == nat->nat_p))) { switch (p) { +#if 0 + case IPPROTO_GRE : + if (nat->nat_call[1] != fin->fin_data[0]) + continue; + break; +#endif case IPPROTO_TCP : case IPPROTO_UDP : if (nat->nat_oport != dport) @@ -2196,77 +3342,170 @@ int rw; return nat; } } - if (!nat_stats.ns_wilds || !(flags & FI_WILDP)) + + /* + * So if we didn't find it but there are wildcard members in the hash + * table, go back and look for them. We do this search and update here + * because it is modifying the NAT table and we want to do this only + * for the first packet that matches. The exception, of course, is + * for "dummy" (FI_IGNORE) lookups. + */ +find_out_wild_ports: + if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) + return NULL; + if (nat_stats.ns_wilds == 0) return NULL; - if (!rw) { - RWLOCK_EXIT(&ipf_nat); - } - hv = NAT_HASH_FN(dst.s_addr, srcip, ipf_nattable_sz); - if (!rw) { - WRITE_ENTER(&ipf_nat); - } + RWLOCK_EXIT(&ipf_nat); + + hv = NAT_HASH_FN(srcip, 0, 0xffffffff); + hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz); + + WRITE_ENTER(&ipf_nat); + nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { - nflags = nat->nat_flags; - if (ifp && ifp != nat->nat_ifp) - continue; - if (!(nflags & FI_WILDP)) + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[1]) + continue; + } else { + if (ifp != nat->nat_ifps[0]) + continue; + } + } + + if (nat->nat_p != fin->fin_p) continue; if ((nat->nat_inip.s_addr != srcip) || (nat->nat_oip.s_addr != dst.s_addr)) continue; - if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) && - ((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) { - nat_tabmove(fin, nat); + + nflags = nat->nat_flags; + if (!(nflags & (NAT_TCPUDP|SI_WILDP))) + continue; + + if (nat_wildok(nat, (int)sport, (int)dport, nflags, + NAT_OUTBOUND) == 1) { + if ((fin->fin_flx & FI_IGNORE) != 0) + break; + if ((nflags & SI_CLONE) != 0) { + nat = fr_natclone(fin, nat); + if (nat == NULL) + break; + } else { + MUTEX_ENTER(&ipf_nat_new); + nat_stats.ns_wilds--; + MUTEX_EXIT(&ipf_nat_new); + } + nat->nat_inport = sport; + nat->nat_oport = dport; + if (nat->nat_outport == 0) + nat->nat_outport = sport; + nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); + nat_tabmove(nat); break; } } - if (!rw) { - MUTEX_DOWNGRADE(&ipf_nat); - } + + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } -/* - * Lookup the NAT tables to search for a matching redirect - */ +/* ------------------------------------------------------------------------ */ +/* Function: nat_lookupredir */ +/* Returns: nat_t* - NULL == no match, */ +/* else pointer to matching NAT entry */ +/* Parameters: np(I) - pointer to description of packet to find NAT table */ +/* entry for. */ +/* */ +/* Lookup the NAT tables to search for a matching redirect */ +/* ------------------------------------------------------------------------ */ nat_t *nat_lookupredir(np) -register natlookup_t *np; +natlookup_t *np; { - nat_t *nat; fr_info_t fi; + nat_t *nat; bzero((char *)&fi, sizeof(fi)); - fi.fin_data[0] = ntohs(np->nl_inport); - fi.fin_data[1] = ntohs(np->nl_outport); + if (np->nl_flags & IPN_IN) { + fi.fin_data[0] = ntohs(np->nl_realport); + fi.fin_data[1] = ntohs(np->nl_outport); + } else { + fi.fin_data[0] = ntohs(np->nl_inport); + fi.fin_data[1] = ntohs(np->nl_outport); + } + if (np->nl_flags & IPN_TCP) + fi.fin_p = IPPROTO_TCP; + else if (np->nl_flags & IPN_UDP) + fi.fin_p = IPPROTO_UDP; + else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY)) + fi.fin_p = IPPROTO_ICMP; /* - * If nl_inip is non null, this is a lookup based on the real - * ip address. Else, we use the fake. + * We can do two sorts of lookups: + * - IPN_IN: we have the `real' and `out' address, look for `in'. + * - default: we have the `in' and `out' address, look for `real'. */ - if ((nat = nat_outlookup(&fi, np->nl_flags, 0, np->nl_inip, - np->nl_outip, 0))) { - np->nl_realip = nat->nat_outip; - np->nl_realport = nat->nat_outport; - } + if (np->nl_flags & IPN_IN) { + if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p, + np->nl_realip, np->nl_outip))) { + np->nl_inip = nat->nat_inip; + np->nl_inport = nat->nat_inport; + } + } else { + /* + * If nl_inip is non null, this is a lookup based on the real + * ip address. Else, we use the fake. + */ + if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p, + np->nl_inip, np->nl_outip))) { + + if ((np->nl_flags & IPN_FINDFORWARD) != 0) { + fr_info_t fin; + bzero((char *)&fin, sizeof(fin)); + fin.fin_p = nat->nat_p; + fin.fin_data[0] = ntohs(nat->nat_outport); + fin.fin_data[1] = ntohs(nat->nat_oport); + if (nat_inlookup(&fin, np->nl_flags, fin.fin_p, + nat->nat_outip, + nat->nat_oip) != NULL) { + np->nl_flags &= ~IPN_FINDFORWARD; + } + } + + np->nl_realip = nat->nat_outip; + np->nl_realport = nat->nat_outport; + } + } + return nat; } -static int nat_match(fin, np, ip) +/* ------------------------------------------------------------------------ */ +/* Function: nat_match */ +/* Returns: int - 0 == no match, 1 == match */ +/* Parameters: fin(I) - pointer to packet information */ +/* np(I) - pointer to NAT rule */ +/* */ +/* Pull the matching of a packet against a NAT rule out of that complex */ +/* loop inside fr_checknatin() and lay it out properly in its own function. */ +/* ------------------------------------------------------------------------ */ +static int nat_match(fin, np) fr_info_t *fin; ipnat_t *np; -ip_t *ip; { frtuc_t *ft; - if (ip->ip_v != 4) + if (fin->fin_v != 4) return 0; if (np->in_p && fin->fin_p != np->in_p) return 0; + if (fin->fin_out) { if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) return 0; @@ -2288,319 +3527,439 @@ ip_t *ip; } ft = &np->in_tuc; - if (!(fin->fin_fl & FI_TCPUDP) || - (fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) { + if (!(fin->fin_flx & FI_TCPUDP) || + (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) { if (ft->ftu_scmp || ft->ftu_dcmp) return 0; return 1; } - return fr_tcpudpchk(ft, fin); + return fr_tcpudpchk(fin, ft); } -/* - * Packets going out on the external interface go through this. - * Here, the source address requires alteration, if anything. - */ -int ip_natout(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: nat_update */ +/* Returns: Nil */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* np(I) - pointer to NAT rule */ +/* */ +/* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ +/* called with fin_rev updated - i.e. after calling nat_proto(). */ +/* ------------------------------------------------------------------------ */ +void nat_update(fin, nat, np) fr_info_t *fin; +nat_t *nat; +ipnat_t *np; { - register ipnat_t *np = NULL; - register u_32_t ipa; + ipftq_t *ifq, *ifq2; + ipftqent_t *tqe; + + MUTEX_ENTER(&nat->nat_lock); + tqe = &nat->nat_tqe; + ifq = tqe->tqe_ifq; + + /* + * We allow over-riding of NAT timeouts from NAT rules, even for + * TCP, however, if it is TCP and there is no rule timeout set, + * then do not update the timeout here. + */ + if (np != NULL) + ifq2 = np->in_tqehead[fin->fin_rev]; + else + ifq2 = NULL; + + if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) { + (void) fr_tcp_age(&nat->nat_tqe, fin, nat_tqb, 0); + } else { + if (ifq2 == NULL) { + if (nat->nat_p == IPPROTO_UDP) + ifq2 = &nat_udptq; + else if (nat->nat_p == IPPROTO_ICMP) + ifq2 = &nat_icmptq; + else + ifq2 = &nat_iptq; + } + + fr_movequeue(tqe, ifq, ifq2); + } + MUTEX_EXIT(&nat->nat_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checknatout */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 0 == no packet translation occurred, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(I) - pointer to filtering result flags */ +/* */ +/* Check to see if an outcoming packet should be changed. ICMP packets are */ +/* first checked to see if they match an existing entry (if an error), */ +/* otherwise a search of the current NAT table is made. If neither results */ +/* in a match then a search for a matching NAT rule is made. Create a new */ +/* NAT entry if a we matched a NAT rule. Lastly, actually change the */ +/* packet header(s) as required. */ +/* ------------------------------------------------------------------------ */ +int fr_checknatout(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + struct ifnet *ifp, *sifp; + icmphdr_t *icmp = NULL; tcphdr_t *tcp = NULL; - u_short sport = 0, dport = 0, *csump = NULL; - int natadd = 1, i, icmpset = 1; - u_int nflags = 0, hv, msk; - struct ifnet *ifp; + int rval, natfailed; + ipnat_t *np = NULL; + u_int nflags = 0; + u_32_t ipa, iph; + int natadd = 1; frentry_t *fr; - void *sifp; - u_32_t iph; nat_t *nat; - if (nat_list == NULL || (fr_nat_lock)) + if (nat_stats.ns_rules == 0 || fr_nat_lock != 0) return 0; - if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && - fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) { - sifp = fin->fin_ifp; + natfailed = 0; + fr = fin->fin_fr; + sifp = fin->fin_ifp; + if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && + fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) fin->fin_ifp = fr->fr_tif.fd_ifp; - } else - sifp = fin->fin_ifp; ifp = fin->fin_ifp; - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { - if (fin->fin_p == IPPROTO_TCP) + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + switch (fin->fin_p) + { + case IPPROTO_TCP : nflags = IPN_TCP; - else if (fin->fin_p == IPPROTO_UDP) + break; + case IPPROTO_UDP : nflags = IPN_UDP; - if ((nflags & IPN_TCPUDP)) { - tcp = (tcphdr_t *)fin->fin_dp; - sport = tcp->th_sport; - dport = tcp->th_dport; + break; + case IPPROTO_ICMP : + icmp = fin->fin_dp; + + /* + * This is an incoming packet, so the destination is + * the icmp_id and the source port equals 0 + */ + if (nat_icmpquerytype4(icmp->icmp_type)) + nflags = IPN_ICMPQUERY; + break; + default : + break; } + + if ((nflags & IPN_TCPUDP)) + tcp = fin->fin_dp; } ipa = fin->fin_saddr; READ_ENTER(&ipf_nat); - if ((fin->fin_p == IPPROTO_ICMP) && - (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) - icmpset = 1; - else if ((fin->fin_fl & FI_FRAG) && - (nat = ipfr_nat_knownfrag(ip, fin))) + if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && + (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) + /*EMPTY*/; + else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) natadd = 0; - else if ((nat = nat_outlookup(fin, nflags|FI_WILDP|FI_WILDA, - (u_int)fin->fin_p, fin->fin_src, - fin->fin_dst, 0))) { + else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, + fin->fin_src, fin->fin_dst))) { nflags = nat->nat_flags; - if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { - if ((nflags & FI_W_SPORT) && - (nat->nat_inport != sport)) - nat->nat_inport = sport; - if ((nflags & FI_W_DPORT) && - (nat->nat_oport != dport)) - nat->nat_oport = dport; - - if (nat->nat_outport == 0) - nat->nat_outport = sport; - nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); - nflags = nat->nat_flags; - nat_stats.ns_wilds--; - } } else { - RWLOCK_EXIT(&ipf_nat); - - msk = 0xffffffff; - i = 32; + u_32_t hv, msk, nmsk; - WRITE_ENTER(&ipf_nat); /* * If there is no current entry in the nat table for this IP#, * create one for it (if there is a matching rule). */ + RWLOCK_EXIT(&ipf_nat); + msk = 0xffffffff; + nmsk = nat_masks; + WRITE_ENTER(&ipf_nat); maskloop: iph = ipa & htonl(msk); hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); for (np = nat_rules[hv]; np; np = np->in_mnext) { - if (np->in_ifp && (np->in_ifp != ifp)) + if ((np->in_ifps[0] && (np->in_ifps[0] != ifp))) + continue; + if (np->in_v != fin->fin_v) continue; - if ((np->in_flags & IPN_RF) && - !(np->in_flags & nflags)) + if (np->in_p && (np->in_p != fin->fin_p)) + continue; + if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) continue; if (np->in_flags & IPN_FILTER) { - if (!nat_match(fin, np, ip)) + if (!nat_match(fin, np)) continue; } else if ((ipa & np->in_inmsk) != np->in_inip) continue; - if (*np->in_plabel && !appr_ok(ip, tcp, np)) + + if ((fr != NULL) && + !fr_matchtag(&np->in_tag, &fr->fr_nattag)) continue; - nat = nat_new(fin, ip, np, NULL, - (u_int)nflags, NAT_OUTBOUND); - if (nat != NULL) { + + if (*np->in_plabel != '\0') { + if (((np->in_flags & IPN_FILTER) == 0) && + (np->in_dport != tcp->th_dport)) + continue; + if (appr_ok(fin, tcp, np) == 0) + continue; + } + + if ((nat = nat_new(fin, np, NULL, nflags, + NAT_OUTBOUND))) { np->in_hits++; break; - } + } else + natfailed = -1; } - if ((np == NULL) && (i > 0)) { - do { - i--; + if ((np == NULL) && (nmsk != 0)) { + while (nmsk) { msk <<= 1; - } while ((i >= 0) && ((nat_masks & (1 << i)) == 0)); - if (i >= 0) + if (nmsk & 0x80000000) + break; + nmsk <<= 1; + } + if (nmsk != 0) { + nmsk <<= 1; goto maskloop; + } } MUTEX_DOWNGRADE(&ipf_nat); } - /* - * NOTE: ipf_nat must now only be held as a read lock - */ - if (nat) { - np = nat->nat_ptr; - if (natadd && (fin->fin_fl & FI_FRAG) && np) - ipfr_nat_newfrag(ip, fin, nat); - MUTEX_ENTER(&nat->nat_lock); - if (fin->fin_p != IPPROTO_TCP) { - if (np && np->in_age[1]) - nat->nat_age = np->in_age[1]; - else if (!icmpset && (fin->fin_p == IPPROTO_ICMP)) - nat->nat_age = fr_defnaticmpage; - else - nat->nat_age = fr_defnatage; + if (nat != NULL) { + rval = fr_natout(fin, nat, natadd, nflags); + if (rval == 1) { + MUTEX_ENTER(&nat->nat_lock); + nat->nat_ref++; + MUTEX_EXIT(&nat->nat_lock); + fin->fin_nat = nat; } - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&nat->nat_lock); + } else + rval = natfailed; + RWLOCK_EXIT(&ipf_nat); - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ + if (rval == -1) { + if (passp != NULL) + *passp = FR_BLOCK; + fin->fin_flx |= FI_BADNAT; + } + fin->fin_ifp = sifp; + return rval; +} + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natout */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* natadd(I) - flag indicating if it is safe to add frag cache */ +/* nflags(I) - NAT flags set for this packet */ +/* */ +/* Translate a packet coming "out" on an interface. */ +/* ------------------------------------------------------------------------ */ +int fr_natout(fin, nat, natadd, nflags) +fr_info_t *fin; +nat_t *nat; +int natadd; +u_32_t nflags; +{ + icmphdr_t *icmp; + u_short *csump; + tcphdr_t *tcp; + ipnat_t *np; + int i; + + tcp = NULL; + icmp = NULL; + csump = NULL; + np = nat->nat_ptr; + + if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL)) + (void) fr_nat_newfrag(fin, 0, nat); + + MUTEX_ENTER(&nat->nat_lock); + nat->nat_bytes[1] += fin->fin_plen; + nat->nat_pkts[1]++; + MUTEX_EXIT(&nat->nat_lock); + + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + * This is only done for STREAMS based IP implementations where the + * checksum has already been calculated by IP. In all other cases, + * IPFilter is called before the checksum needs calculating so there + * is no call to modify whatever is in the header now. + */ + if (fin->fin_v == 4) { if (nflags == IPN_ICMPERR) { u_32_t s1, s2, sumd; s1 = LONG_SUM(ntohl(fin->fin_saddr)); s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); CALC_SUMD(s1, s2, sumd); - fix_outcksum(fin, &ip->ip_sum, sumd); + fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd); } -#if (SOLARIS || defined(__sgi)) || !defined(_KERNEL) +#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || defined(linux) else { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); + fix_outcksum(fin, &fin->fin_ip->ip_sum, + nat->nat_ipsumd); else - fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); + fix_incksum(fin, &fin->fin_ip->ip_sum, + nat->nat_ipsumd); } #endif - /* - * Only change the packet contents, not what is filtered upon. - */ - ip->ip_src = nat->nat_outip; - - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { + } - if ((nat->nat_outport != 0) && (tcp != NULL)) { - tcp->th_sport = nat->nat_outport; - fin->fin_data[0] = ntohs(tcp->th_sport); - } + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { + tcp = fin->fin_dp; - if (fin->fin_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - MUTEX_ENTER(&nat->nat_lock); - fr_tcp_age(&nat->nat_age, - nat->nat_tcpstate, fin, 1, 0); - if (nat->nat_age < fr_defnaticmpage) - nat->nat_age = fr_defnaticmpage; -#ifdef LARGE_NAT - else if ((!np || !np->in_age[1]) && - (nat->nat_age > fr_defnatage)) - nat->nat_age = fr_defnatage; -#endif - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - - /* - * Do a MSS CLAMPING on a SYN packet, - * only deal IPv4 for now. - */ - if (nat->nat_mssclamp && - (tcp->th_flags & TH_SYN) != 0) - nat_mssclamp(tcp, nat->nat_mssclamp, - fin, csump); - - MUTEX_EXIT(&nat->nat_lock); - } else if (fin->fin_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } + tcp->th_sport = nat->nat_outport; + fin->fin_data[0] = ntohs(nat->nat_outport); + } - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(fin, csump, - nat->nat_sumd[1]); - else - fix_incksum(fin, csump, - nat->nat_sumd[1]); - } + if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { + icmp = fin->fin_dp; + icmp->icmp_id = nat->nat_outport; } - if (np && (np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && dport == np->in_dport))) { - i = appr_check(ip, fin, nat); - if (i == 0) - i = 1; - else if (i == -1) - nat->nat_drop[1]++; - } else - i = 1; - ATOMIC_INCL(nat_stats.ns_mapped[1]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - fin->fin_ifp = sifp; - return i; + csump = nat_proto(fin, nat, nflags); } - RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ - fin->fin_ifp = sifp; - return 0; + + fin->fin_ip->ip_src = nat->nat_outip; + + nat_update(fin, nat, np); + + /* + * The above comments do not hold for layer 4 (or higher) checksums... + */ + if (csump != NULL) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(fin, csump, nat->nat_sumd[1]); + else + fix_incksum(fin, csump, nat->nat_sumd[1]); + } +#ifdef IPFILTER_SYNC + ipfsync_update(SMC_NAT, fin, nat->nat_sync); +#endif + /* ------------------------------------------------------------- */ + /* A few quick notes: */ + /* Following are test conditions prior to calling the */ + /* appr_check routine. */ + /* */ + /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ + /* with a redirect rule, we attempt to match the packet's */ + /* source port against in_dport, otherwise we'd compare the */ + /* packet's destination. */ + /* ------------------------------------------------------------- */ + if ((np != NULL) && (np->in_apr != NULL)) { + i = appr_check(fin, nat); + if (i == 0) + i = 1; + } else + i = 1; + ATOMIC_INCL(nat_stats.ns_mapped[1]); + fin->fin_flx |= FI_NATED; + return i; } -/* - * Packets coming in from the external interface go through this. - * Here, the destination address requires alteration, if anything. - */ -int ip_natin(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_checknatin */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 0 == no packet translation occurred, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(I) - pointer to filtering result flags */ +/* */ +/* Check to see if an incoming packet should be changed. ICMP packets are */ +/* first checked to see if they match an existing entry (if an error), */ +/* otherwise a search of the current NAT table is made. If neither results */ +/* in a match then a search for a matching NAT rule is made. Create a new */ +/* NAT entry if a we matched a NAT rule. Lastly, actually change the */ +/* packet header(s) as required. */ +/* ------------------------------------------------------------------------ */ +int fr_checknatin(fin, passp) fr_info_t *fin; +u_32_t *passp; { - register struct in_addr src; - register struct in_addr in; - register ipnat_t *np; - u_short sport = 0, dport = 0, *csump = NULL; - u_int nflags = 0, natadd = 1, hv, msk; - struct ifnet *ifp = fin->fin_ifp; - tcphdr_t *tcp = NULL; - int i, icmpset = 0; + u_int nflags, natadd; + int rval, natfailed; + struct ifnet *ifp; + struct in_addr in; + icmphdr_t *icmp; + tcphdr_t *tcp; + u_short dport; + ipnat_t *np; nat_t *nat; u_32_t iph; - if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock)) + if (nat_stats.ns_rules == 0 || fr_nat_lock != 0) return 0; - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { - if (fin->fin_p == IPPROTO_TCP) + tcp = NULL; + icmp = NULL; + dport = 0; + natadd = 1; + nflags = 0; + natfailed = 0; + ifp = fin->fin_ifp; + + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + switch (fin->fin_p) + { + case IPPROTO_TCP : nflags = IPN_TCP; - else if (fin->fin_p == IPPROTO_UDP) + break; + case IPPROTO_UDP : nflags = IPN_UDP; + break; + case IPPROTO_ICMP : + icmp = fin->fin_dp; + + /* + * This is an incoming packet, so the destination is + * the icmp_id and the source port equals 0 + */ + if (nat_icmpquerytype4(icmp->icmp_type)) { + nflags = IPN_ICMPQUERY; + dport = icmp->icmp_id; + } break; + default : + break; + } + if ((nflags & IPN_TCPUDP)) { - tcp = (tcphdr_t *)fin->fin_dp; - sport = tcp->th_sport; + tcp = fin->fin_dp; dport = tcp->th_dport; } } in = fin->fin_dst; - /* make sure the source address is to be redirected */ - src = fin->fin_src; READ_ENTER(&ipf_nat); - if ((fin->fin_p == IPPROTO_ICMP) && - (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) - icmpset = 1; - else if ((fin->fin_fl & FI_FRAG) && - (nat = ipfr_nat_knownfrag(ip, fin))) + if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && + (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) + /*EMPTY*/; + else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) natadd = 0; - else if ((nat = nat_inlookup(fin, nflags|FI_WILDP|FI_WILDA, - (u_int)fin->fin_p, fin->fin_src, in, 0))) { + else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, + fin->fin_src, in))) { nflags = nat->nat_flags; - if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { - if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT)) - nat->nat_oport = sport; - if ((nat->nat_outport != dport) && - (nflags & FI_W_SPORT)) - nat->nat_outport = dport; - nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); - nflags = nat->nat_flags; - nat_stats.ns_wilds--; - } } else { - RWLOCK_EXIT(&ipf_nat); + u_32_t hv, msk, rmsk; + RWLOCK_EXIT(&ipf_nat); + rmsk = rdr_masks; msk = 0xffffffff; - i = 32; - WRITE_ENTER(&ipf_nat); /* * If there is no current entry in the nat table for this IP#, @@ -2610,150 +3969,288 @@ maskloop: iph = in.s_addr & htonl(msk); 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 != fin->fin_p)) || - (np->in_flags && !(nflags & np->in_flags))) + if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) + continue; + if (np->in_v != fin->fin_v) + continue; + if (np->in_p && (np->in_p != fin->fin_p)) + continue; + if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) continue; if (np->in_flags & IPN_FILTER) { - if (!nat_match(fin, np, ip)) + if (!nat_match(fin, np)) + continue; + } else { + if ((in.s_addr & np->in_outmsk) != np->in_outip) + continue; + if (np->in_pmin && + ((ntohs(np->in_pmax) < ntohs(dport)) || + (ntohs(dport) < ntohs(np->in_pmin)))) + continue; + } + + if (*np->in_plabel != '\0') { + if (!appr_ok(fin, tcp, np)) { continue; - } else if ((in.s_addr & np->in_outmsk) != np->in_outip) - continue; - if ((!np->in_pmin || (np->in_flags & IPN_FILTER) || - ((ntohs(np->in_pmax) >= ntohs(dport)) && - (ntohs(dport) >= ntohs(np->in_pmin))))) - if ((nat = nat_new(fin, ip, np, NULL, nflags, - NAT_INBOUND))) { - np->in_hits++; - break; } + } + + nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); + if (nat != NULL) { + np->in_hits++; + break; + } else + natfailed = -1; } - if ((np == NULL) && (i > 0)) { - do { - i--; + if ((np == NULL) && (rmsk != 0)) { + while (rmsk) { msk <<= 1; - } while ((i >= 0) && ((rdr_masks & (1 << i)) == 0)); - if (i >= 0) + if (rmsk & 0x80000000) + break; + rmsk <<= 1; + } + if (rmsk != 0) { + rmsk <<= 1; goto maskloop; + } } MUTEX_DOWNGRADE(&ipf_nat); } + if (nat != NULL) { + rval = fr_natin(fin, nat, natadd, nflags); + if (rval == 1) { + MUTEX_ENTER(&nat->nat_lock); + nat->nat_ref++; + MUTEX_EXIT(&nat->nat_lock); + fin->fin_nat = nat; + fin->fin_state = nat->nat_state; + } + } else + rval = natfailed; + RWLOCK_EXIT(&ipf_nat); + + if (rval == -1) { + if (passp != NULL) + *passp = FR_BLOCK; + fin->fin_flx |= FI_BADNAT; + } + return rval; +} - /* - * NOTE: ipf_nat must now only be held as a read lock - */ - if (nat) { - np = nat->nat_ptr; - fin->fin_fr = nat->nat_fr; - if (natadd && (fin->fin_fl & FI_FRAG) && np) - ipfr_nat_newfrag(ip, fin, nat); - if (np && (np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && sport == np->in_dport))) { - i = appr_check(ip, fin, nat); + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natin */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* natadd(I) - flag indicating if it is safe to add frag cache */ +/* nflags(I) - NAT flags set for this packet */ +/* Locks Held: ipf_nat (READ) */ +/* */ +/* Translate a packet coming "in" on an interface. */ +/* ------------------------------------------------------------------------ */ +int fr_natin(fin, nat, natadd, nflags) +fr_info_t *fin; +nat_t *nat; +int natadd; +u_32_t nflags; +{ + icmphdr_t *icmp; + u_short *csump; + tcphdr_t *tcp; + ipnat_t *np; + int i; + + tcp = NULL; + csump = NULL; + np = nat->nat_ptr; + fin->fin_fr = nat->nat_fr; + + if (np != NULL) { + if ((natadd != 0) && (fin->fin_flx & FI_FRAG)) + (void) fr_nat_newfrag(fin, 0, nat); + + /* ------------------------------------------------------------- */ + /* A few quick notes: */ + /* Following are test conditions prior to calling the */ + /* appr_check routine. */ + /* */ + /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ + /* with a map rule, we attempt to match the packet's */ + /* source port against in_dport, otherwise we'd compare the */ + /* packet's destination. */ + /* ------------------------------------------------------------- */ + if (np->in_apr != NULL) { + i = appr_check(fin, nat); if (i == -1) { - nat->nat_drop[0]++; - RWLOCK_EXIT(&ipf_nat); - return i; + return -1; } } + } - MUTEX_ENTER(&nat->nat_lock); - if (fin->fin_p != IPPROTO_TCP) { - if (np && np->in_age[0]) - nat->nat_age = np->in_age[0]; - else if (!icmpset && (fin->fin_p == IPPROTO_ICMP)) - nat->nat_age = fr_defnaticmpage; - else - nat->nat_age = fr_defnatage; +#ifdef IPFILTER_SYNC + ipfsync_update(SMC_NAT, fin, nat->nat_sync); +#endif + + MUTEX_ENTER(&nat->nat_lock); + nat->nat_bytes[0] += fin->fin_plen; + nat->nat_pkts[0]++; + MUTEX_EXIT(&nat->nat_lock); + + fin->fin_ip->ip_dst = nat->nat_inip; + fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; + if (nflags & IPN_TCPUDP) + tcp = fin->fin_dp; + + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + * Why only do this for some platforms on inbound packets ? + * Because for those that it is done, IP processing is yet to happen + * and so the IPv4 header checksum has not yet been evaluated. + * Perhaps it should always be done for the benefit of things like + * fast forwarding (so that it doesn't need to be recomputed) but with + * header checksum offloading, perhaps it is a moot point. + */ +#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ + defined(__osf__) || defined(linux) + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); + else + fix_outcksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); +#endif + + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_dport = nat->nat_inport; + fin->fin_data[1] = ntohs(nat->nat_inport); } - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&nat->nat_lock); - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ + + if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { + icmp = fin->fin_dp; + + icmp->icmp_id = nat->nat_inport; + } + + csump = nat_proto(fin, nat, nflags); + } + + nat_update(fin, nat, np); + + /* + * The above comments do not hold for layer 4 (or higher) checksums... + */ + if (csump != NULL) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); + fix_incksum(fin, csump, nat->nat_sumd[0]); else - fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); + fix_outcksum(fin, csump, nat->nat_sumd[0]); + } + ATOMIC_INCL(nat_stats.ns_mapped[0]); + fin->fin_flx |= FI_NATED; + if (np != NULL && np->in_tag.ipt_num[0] != 0) + fin->fin_nattag = &np->in_tag; + return 1; +} - ip->ip_dst = nat->nat_inip; - fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { +/* ------------------------------------------------------------------------ */ +/* Function: nat_proto */ +/* Returns: u_short* - pointer to transport header checksum to update, */ +/* NULL if the transport protocol is not recognised */ +/* as needing a checksum update. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* nflags(I) - NAT flags set for this packet */ +/* */ +/* Return the pointer to the checksum field for each protocol so understood.*/ +/* If support for making other changes to a protocol header is required, */ +/* that is not strictly 'address' translation, such as clamping the MSS in */ +/* TCP down to a specific value, then do it from here. */ +/* ------------------------------------------------------------------------ */ +u_short *nat_proto(fin, nat, nflags) +fr_info_t *fin; +nat_t *nat; +u_int nflags; +{ + icmphdr_t *icmp; + u_short *csump; + tcphdr_t *tcp; + udphdr_t *udp; - if ((nat->nat_inport != 0) && (tcp != NULL)) { - tcp->th_dport = nat->nat_inport; - fin->fin_data[1] = ntohs(tcp->th_dport); - } + csump = NULL; + if (fin->fin_out == 0) { + fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); + } else { + fin->fin_rev = (nat->nat_dir == NAT_INBOUND); + } - if (fin->fin_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - MUTEX_ENTER(&nat->nat_lock); - fr_tcp_age(&nat->nat_age, - nat->nat_tcpstate, fin, 0, 0); - if (nat->nat_age < fr_defnaticmpage) - nat->nat_age = fr_defnaticmpage; -#ifdef LARGE_NAT - else if ((!np || !np->in_age[0]) && - (nat->nat_age > fr_defnatage)) - nat->nat_age = fr_defnatage; -#endif - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - /* - * Do a MSS CLAMPING on a SYN packet, - * only deal IPv4 for now. - */ - if (nat->nat_mssclamp && - (tcp->th_flags & TH_SYN) != 0) - nat_mssclamp(tcp, nat->nat_mssclamp, - fin, csump); - - MUTEX_EXIT(&nat->nat_lock); - } else if (fin->fin_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } + switch (fin->fin_p) + { + case IPPROTO_TCP : + tcp = fin->fin_dp; - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(fin, csump, - nat->nat_sumd[0]); - else - fix_outcksum(fin, csump, - nat->nat_sumd[0]); - } + csump = &tcp->th_sum; + + /* + * Do a MSS CLAMPING on a SYN packet, + * only deal IPv4 for now. + */ + if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) + nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); + + break; + + case IPPROTO_UDP : + udp = fin->fin_dp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + break; + + case IPPROTO_ICMP : + icmp = fin->fin_dp; + + if ((nflags & IPN_ICMPQUERY) != 0) { + if (icmp->icmp_cksum != 0) + csump = &icmp->icmp_cksum; } - ATOMIC_INCL(nat_stats.ns_mapped[0]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - return 1; + break; } - RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ - return 0; + return csump; } -/* - * Free all memory used by NAT structures allocated at runtime. - */ -void ip_natunload() +/* ------------------------------------------------------------------------ */ +/* Function: fr_natunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Free all memory used by NAT structures allocated at runtime. */ +/* ------------------------------------------------------------------------ */ +void fr_natunload() { - WRITE_ENTER(&ipf_nat); + ipftq_t *ifq, *ifqnext; + (void) nat_clearlist(); (void) nat_flushtable(); - RWLOCK_EXIT(&ipf_nat); + + /* + * Proxy timeout queues are not cleaned here because although they + * exist on the NAT list, appr_unload is called after fr_natunload + * and the proxies actually are responsible for them being created. + * Should the proxy timeouts have their own list? There's no real + * justification as this is the only complication. + */ + for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + if (((ifq->ifq_flags & IFQF_PROXY) == 0) && + (fr_deletetimeoutqueue(ifq) == 0)) + fr_freetimeoutqueue(ifq); + } if (nat_table[0] != NULL) { KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz); @@ -2775,72 +4272,152 @@ void ip_natunload() KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); maptable = NULL; } + if (nat_stats.ns_bucketlen[0] != NULL) { + KFREES(nat_stats.ns_bucketlen[0], + sizeof(u_long *) * ipf_nattable_sz); + nat_stats.ns_bucketlen[0] = NULL; + } + if (nat_stats.ns_bucketlen[1] != NULL) { + KFREES(nat_stats.ns_bucketlen[1], + sizeof(u_long *) * ipf_nattable_sz); + nat_stats.ns_bucketlen[1] = NULL; + } + + if (fr_nat_maxbucket_reset == 1) + fr_nat_maxbucket = 0; + + if (fr_nat_init == 1) { + fr_nat_init = 0; + fr_sttab_destroy(nat_tqb); + + RW_DESTROY(&ipf_natfrag); + RW_DESTROY(&ipf_nat); + + MUTEX_DESTROY(&ipf_nat_new); + MUTEX_DESTROY(&ipf_natio); + + MUTEX_DESTROY(&nat_udptq.ifq_lock); + MUTEX_DESTROY(&nat_icmptq.ifq_lock); + MUTEX_DESTROY(&nat_iptq.ifq_lock); + } } -/* - * Slowly expire held state for NAT entries. Timeouts are set in - * expectation of this being called twice per second. - */ -void ip_natexpire() +/* ------------------------------------------------------------------------ */ +/* Function: fr_natexpire */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Check all of the timeout queues for entries at the top which need to be */ +/* expired. */ +/* ------------------------------------------------------------------------ */ +void fr_natexpire() { - register struct nat *nat, **natp; -#if defined(_KERNEL) && !SOLARIS + ipftq_t *ifq, *ifqnext; + ipftqent_t *tqe, *tqn; +#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) int s; #endif + int i; SPL_NET(s); WRITE_ENTER(&ipf_nat); - for (natp = &nat_instances; (nat = *natp); ) { - nat->nat_age--; - if (nat->nat_age) { - natp = &nat->nat_next; - continue; + for (ifq = nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) { + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + nat_delete(tqe->tqe_parent, NL_EXPIRE); + } + } + + for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + nat_delete(tqe->tqe_parent, NL_EXPIRE); } - *natp = nat->nat_next; -#ifdef IPFILTER_LOG - nat_log(nat, NL_EXPIRE); -#endif - nat_delete(nat); - nat_stats.ns_expire++; } + + for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + if (((ifq->ifq_flags & IFQF_DELETE) != 0) && + (ifq->ifq_ref == 0)) { + fr_freetimeoutqueue(ifq); + } + } + RWLOCK_EXIT(&ipf_nat); SPL_X(s); } -/* - */ -void ip_natsync(ifp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_natsync */ +/* Returns: Nil */ +/* Parameters: ifp(I) - pointer to network interface */ +/* */ +/* Walk through all of the currently active NAT sessions, looking for those */ +/* which need to have their translated address updated. */ +/* ------------------------------------------------------------------------ */ +void fr_natsync(ifp) void *ifp; { - register ipnat_t *n; - register nat_t *nat; - register u_32_t sum1, sum2, sumd; + u_32_t sum1, sum2, sumd; struct in_addr in; - ipnat_t *np; + ipnat_t *n; + nat_t *nat; void *ifp2; -#if defined(_KERNEL) && !SOLARIS +#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) int s; #endif + if (fr_running <= 0) + return; + /* * Change IP addresses for NAT sessions for any protocol except TCP - * since it will break the TCP connection anyway. + * since it will break the TCP connection anyway. The only rules + * which will get changed are those which are "map ... -> 0/32", + * where the rule specifies the address is taken from the interface. */ SPL_NET(s); WRITE_ENTER(&ipf_nat); - for (nat = nat_instances; nat; nat = nat->nat_next) - if (((ifp == NULL) || (ifp == nat->nat_ifp)) && - !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && - (np->in_outmsk == 0xffffffff) && !np->in_nip) { - ifp2 = nat->nat_ifp; + + if (fr_running <= 0) { + RWLOCK_EXIT(&ipf_nat); + return; + } + + for (nat = nat_instances; nat; nat = nat->nat_next) { + if ((nat->nat_flags & IPN_TCP) != 0) + continue; + n = nat->nat_ptr; + if ((n == NULL) || + (n->in_outip != 0) || (n->in_outmsk != 0xffffffff)) + continue; + if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || + (ifp == nat->nat_ifps[1]))) { + nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4); + if (nat->nat_ifnames[1][0] != '\0') { + nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], + 4); + } else + nat->nat_ifps[1] = nat->nat_ifps[0]; + ifp2 = nat->nat_ifps[0]; + if (ifp2 == NULL) + continue; + /* * Change the map-to address to be the same as the * new one. */ sum1 = nat->nat_outip.s_addr; - if (fr_ifpaddr(4, ifp2, &in) != -1) + if (fr_ifpaddr(4, FRI_NORMAL, ifp2, &in, NULL) != -1) nat->nat_outip = in; sum2 = nat->nat_outip.s_addr; @@ -2858,41 +4435,97 @@ void *ifp; nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); nat->nat_sumd[1] = nat->nat_sumd[0]; } + } - for (n = nat_list; (n != NULL); n = n->in_next) - if (n->in_ifp == ifp) { - n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); - if (!n->in_ifp) - n->in_ifp = (void *)-1; - } + for (n = nat_list; (n != NULL); n = n->in_next) { + if ((ifp == NULL) || (n->in_ifps[0] == ifp)) + n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4); + if ((ifp == NULL) || (n->in_ifps[1] == ifp)) + n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4); + } RWLOCK_EXIT(&ipf_nat); SPL_X(s); } -#ifdef IPFILTER_LOG +/* ------------------------------------------------------------------------ */ +/* Function: nat_icmpquerytype4 */ +/* Returns: int - 1 == success, 0 == failure */ +/* Parameters: icmptype(I) - ICMP type number */ +/* */ +/* Tests to see if the ICMP type number passed is a query/response type or */ +/* not. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_icmpquerytype4(icmptype) +int icmptype; +{ + + /* + * For the ICMP query NAT code, it is essential that both the query + * and the reply match on the NAT rule. Because the NAT structure + * does not keep track of the icmptype, and a single NAT structure + * is used for all icmp types with the same src, dest and id, we + * simply define the replies as queries as well. The funny thing is, + * altough it seems silly to call a reply a query, this is exactly + * as it is defined in the IPv4 specification + */ + + switch (icmptype) + { + + case ICMP_ECHOREPLY: + case ICMP_ECHO: + /* route aedvertisement/solliciation is currently unsupported: */ + /* it would require rewriting the ICMP data section */ + case ICMP_TSTAMP: + case ICMP_TSTAMPREPLY: + case ICMP_IREQ: + case ICMP_IREQREPLY: + case ICMP_MASKREQ: + case ICMP_MASKREPLY: + return 1; + default: + return 0; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_log */ +/* Returns: Nil */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* type(I) - type of log entry to create */ +/* */ +/* Creates a NAT log entry. */ +/* ------------------------------------------------------------------------ */ void nat_log(nat, type) struct nat *nat; u_int type; { +#ifdef IPFILTER_LOG +# ifndef LARGE_NAT struct ipnat *np; + int rulen; +# endif struct natlog natl; void *items[1]; size_t sizes[1]; - int rulen, types[1]; + int types[1]; natl.nl_inip = nat->nat_inip; natl.nl_outip = nat->nat_outip; natl.nl_origip = nat->nat_oip; - natl.nl_bytes = nat->nat_bytes; - natl.nl_pkts = nat->nat_pkts; + natl.nl_bytes[0] = nat->nat_bytes[0]; + natl.nl_bytes[1] = nat->nat_bytes[1]; + natl.nl_pkts[0] = nat->nat_pkts[0]; + natl.nl_pkts[1] = nat->nat_pkts[1]; natl.nl_origport = nat->nat_oport; natl.nl_inport = nat->nat_inport; natl.nl_outport = nat->nat_outport; natl.nl_p = nat->nat_p; natl.nl_type = type; natl.nl_rule = -1; -#ifndef LARGE_NAT +# ifndef LARGE_NAT if (nat->nat_ptr != NULL) { for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) if (np == nat->nat_ptr) { @@ -2900,29 +4533,202 @@ u_int type; break; } } -#endif +# endif items[0] = &natl; sizes[0] = sizeof(natl); types[0] = 0; (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); -} #endif +} #if defined(__OpenBSD__) +/* ------------------------------------------------------------------------ */ +/* Function: nat_ifdetach */ +/* Returns: Nil */ +/* Parameters: ifp(I) - pointer to network interface */ +/* */ +/* Compatibility interface for OpenBSD to trigger the correct updating of */ +/* interface references within IPFilter. */ +/* ------------------------------------------------------------------------ */ void nat_ifdetach(ifp) void *ifp; { - frsync(); + frsync(ifp); return; } #endif -/* - * Check for MSS option and clamp it if necessary. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_natderef */ +/* Returns: Nil */ +/* Parameters: isp(I) - pointer to pointer to NAT table entry */ +/* */ +/* Decrement the reference counter for this NAT table entry and free it if */ +/* there are no more things using it. */ +/* ------------------------------------------------------------------------ */ +void fr_natderef(natp) +nat_t **natp; +{ + nat_t *nat; + + nat = *natp; + *natp = NULL; + WRITE_ENTER(&ipf_nat); + nat->nat_ref--; + if (nat->nat_ref == 0) + nat_delete(nat, NL_EXPIRE); + RWLOCK_EXIT(&ipf_nat); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natclone */ +/* Returns: ipstate_t* - NULL == cloning failed, */ +/* else pointer to new state structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* Write Lock: ipf_nat */ +/* */ +/* Create a "duplcate" state table entry from the master. */ +/* ------------------------------------------------------------------------ */ +static nat_t *fr_natclone(fin, nat) +fr_info_t *fin; +nat_t *nat; +{ + frentry_t *fr; + nat_t *clone; + ipnat_t *np; + + KMALLOC(clone, nat_t *); + if (clone == NULL) + return NULL; + bcopy((char *)nat, (char *)clone, sizeof(*clone)); + + MUTEX_NUKE(&clone->nat_lock); + + clone->nat_flags &= ~SI_CLONE; + clone->nat_flags |= SI_CLONED; + + + if (nat_insert(clone, fin->fin_rev) == -1) { + KFREE(clone); + return NULL; + } + np = clone->nat_ptr; + if (np != NULL) { + if (nat_logging) + nat_log(clone, (u_int)np->in_redir); + np->in_use++; + } + fr = clone->nat_fr; + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + MUTEX_EXIT(&fr->fr_lock); + } + + + /* + * Because the clone is created outside the normal loop of things and + * TCP has special needs in terms of state, initialise the timeout + * state of the new NAT from here. + */ + if (clone->nat_p == IPPROTO_TCP) { + (void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb, \ + clone->nat_flags); + } +#ifdef IPFILTER_SYNC + clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); +#endif + if (nat_logging) + nat_log(clone, NL_CLONE); + return clone; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_wildok */ +/* Returns: int - 1 == packet's ports match wildcards */ +/* 0 == packet's ports don't match wildcards */ +/* Parameters: nat(I) - NAT entry */ +/* sport(I) - source port */ +/* dport(I) - destination port */ +/* flags(I) - wildcard flags */ +/* dir(I) - packet direction */ +/* */ +/* Use NAT entry and packet direction to determine which combination of */ +/* wildcard flags should be used. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_wildok(nat, sport, dport, flags, dir) +nat_t *nat; +int sport; +int dport; +int flags; +int dir; +{ + /* + * When called by dir is set to + * nat_inlookup NAT_INBOUND (0) + * nat_outlookup NAT_OUTBOUND (1) + * + * We simply combine the packet's direction in dir with the original + * "intended" direction of that NAT entry in nat->nat_dir to decide + * which combination of wildcard flags to allow. + */ + + switch ((dir << 1) | nat->nat_dir) + { + case 3: /* outbound packet / outbound entry */ + if (((nat->nat_inport == sport) || + (flags & SI_W_SPORT)) && + ((nat->nat_oport == dport) || + (flags & SI_W_DPORT))) + return 1; + break; + case 2: /* outbound packet / inbound entry */ + if (((nat->nat_outport == sport) || + (flags & SI_W_DPORT)) && + ((nat->nat_oport == dport) || + (flags & SI_W_SPORT))) + return 1; + break; + case 1: /* inbound packet / outbound entry */ + if (((nat->nat_oport == sport) || + (flags & SI_W_DPORT)) && + ((nat->nat_outport == dport) || + (flags & SI_W_SPORT))) + return 1; + break; + case 0: /* inbound packet / inbound entry */ + if (((nat->nat_oport == sport) || + (flags & SI_W_SPORT)) && + ((nat->nat_outport == dport) || + (flags & SI_W_DPORT))) + return 1; + break; + default: + break; + } + + return(0); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_mssclamp */ +/* Returns: Nil */ +/* Parameters: tcp(I) - pointer to TCP header */ +/* maxmss(I) - value to clamp the TCP MSS to */ +/* fin(I) - pointer to packet information */ +/* csump(I) - pointer to TCP checksum */ +/* */ +/* Check for MSS option and clamp it if necessary. If found and changed, */ +/* then the TCP header checksum will be updated to reflect the change in */ +/* the MSS. */ +/* ------------------------------------------------------------------------ */ static void nat_mssclamp(tcp, maxmss, fin, csump) tcphdr_t *tcp; u_32_t maxmss; @@ -2932,9 +4738,8 @@ u_short *csump; u_char *cp, *ep, opt; int hlen, advance; u_32_t mss, sumd; - u_short v; - hlen = tcp->th_off << 2; + hlen = TCP_OFF(tcp) << 2; if (hlen > sizeof(*tcp)) { cp = (u_char *)tcp + sizeof(*tcp); ep = (u_char *)tcp + hlen; @@ -2947,21 +4752,21 @@ u_short *csump; cp++; continue; } - - if (&cp[1] >= ep) + + if (cp + 1 >= ep) break; advance = cp[1]; - if (&cp[advance] > ep) + if ((cp + advance > ep) || (advance <= 0)) break; - switch (opt) { + switch (opt) + { case TCPOPT_MAXSEG: if (advance != 4) break; - bcopy(&cp[2], &v, sizeof(v)); - mss = ntohs(v); + mss = cp[2] * 256 + cp[3]; if (mss > maxmss) { - v = htons(maxmss); - bcopy(&v, &cp[2], sizeof(v)); + cp[2] = maxmss / 256; + cp[3] = maxmss & 0xff; CALC_SUMD(mss, maxmss, sumd); fix_outcksum(fin, csump, sumd); } @@ -2970,8 +4775,60 @@ u_short *csump; /* ignore unknown options */ break; } - - cp += advance; - } - } -} + + cp += advance; + } + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_setnatqueue */ +/* Returns: Nil */ +/* Parameters: nat(I)- pointer to NAT structure */ +/* rev(I) - forward(0) or reverse(1) direction */ +/* Locks: ipf_nat (read or write) */ +/* */ +/* Put the NAT entry on its default queue entry, using rev as a helped in */ +/* determining which queue it should be placed on. */ +/* ------------------------------------------------------------------------ */ +void fr_setnatqueue(nat, rev) +nat_t *nat; +int rev; +{ + ipftq_t *oifq, *nifq; + + if (nat->nat_ptr != NULL) + nifq = nat->nat_ptr->in_tqehead[rev]; + else + nifq = NULL; + + if (nifq == NULL) { + switch (nat->nat_p) + { + case IPPROTO_UDP : + nifq = &nat_udptq; + break; + case IPPROTO_ICMP : + nifq = &nat_icmptq; + break; + case IPPROTO_TCP : + nifq = nat_tqb + nat->nat_tqe.tqe_state[rev]; + break; + default : + nifq = &nat_iptq; + break; + } + } + + oifq = nat->nat_tqe.tqe_ifq; + /* + * If it's currently on a timeout queue, move it from one queue to + * another, else put it on the end of the newly determined queue. + */ + if (oifq != NULL) + fr_movequeue(&nat->nat_tqe, oifq, nifq); + else + fr_queueappend(&nat->nat_tqe, nifq, nat); + return; +} diff --git a/contrib/ipfilter/ip_nat.h b/contrib/ipfilter/ip_nat.h index 14e9d25..09cc119 100644 --- a/contrib/ipfilter/ip_nat.h +++ b/contrib/ipfilter/ip_nat.h @@ -1,68 +1,76 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1995-2001 by Darren Reed. + * Copyright (C) 1995-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.17.2.32 2004/02/11 15:16:37 darrenr Exp $ + * Id: ip_nat.h,v 2.90.2.9 2005/03/28 11:09:55 darrenr Exp */ #ifndef __IP_NAT_H__ #define __IP_NAT_H__ #ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif #if defined(__STDC__) || defined(__GNUC__) -#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 *) +#define SIOCADNAT _IOW('r', 60, struct ipfobj) +#define SIOCRMNAT _IOW('r', 61, struct ipfobj) +#define SIOCGNATS _IOWR('r', 62, struct ipfobj) +#define SIOCGNATL _IOWR('r', 63, struct ipfobj) +#define SIOCPROXY _IOWR('r', 64, struct ap_control) #else -#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 *) +#define SIOCADNAT _IOW(r, 60, struct ipfobj) +#define SIOCRMNAT _IOW(r, 61, struct ipfobj) +#define SIOCGNATS _IOWR(r, 62, struct ipfobj) +#define SIOCGNATL _IOWR(r, 63, struct ipfobj) +#define SIOCPROXY _IOWR(r, 64, struct ap_control) #endif -#undef LARGE_NAT /* define this if you're setting up a system to NAT +#undef LARGE_NAT /* define this if you're setting up a system to NAT * LARGE numbers of networks/hosts - i.e. in the * hundreds or thousands. In such a case, you should * also change the RDR_SIZE and NAT_SIZE below to more * appropriate sizes. The figures below were used for * a setup with 1000-2000 networks to NAT. */ -#ifndef NAT_SIZE -# ifdef LARGE_NAT +#ifndef NAT_SIZE +# ifdef LARGE_NAT # define NAT_SIZE 2047 # else # define NAT_SIZE 127 # endif #endif -#ifndef RDR_SIZE -# ifdef LARGE_NAT +#ifndef RDR_SIZE +# ifdef LARGE_NAT # define RDR_SIZE 2047 # else # define RDR_SIZE 127 # endif #endif -#ifndef HOSTMAP_SIZE -# ifdef LARGE_NAT +#ifndef HOSTMAP_SIZE +# ifdef LARGE_NAT # define HOSTMAP_SIZE 8191 # else # define HOSTMAP_SIZE 2047 # endif #endif #ifndef NAT_TABLE_MAX +/* + * This is newly introduced and for the sake of "least surprise", the numbers + * present aren't what we'd normally use for creating a proper hash table. + */ # ifdef LARGE_NAT # define NAT_TABLE_MAX 180000 # else # define NAT_TABLE_MAX 30000 # endif #endif -#ifndef NAT_TABLE_SZ -# ifdef LARGE_NAT +#ifndef NAT_TABLE_SZ +# ifdef LARGE_NAT # define NAT_TABLE_SZ 16383 # else # define NAT_TABLE_SZ 2047 @@ -75,82 +83,141 @@ #define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ +struct ipstate; 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; - 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 */ - U_QUAD_T nat_pkts; - U_QUAD_T nat_bytes; - u_int nat_drop[2]; - u_short nat_oport; /* other port */ - u_short nat_inport; - u_short nat_outport; - u_short nat_use; - u_char nat_tcpstate[2]; - u_char nat_p; /* protocol for NAT */ - u_32_t nat_mssclamp; /* if != zero clamp MSS to this */ - struct ipnat *nat_ptr; /* pointer back to the rule */ - struct hostmap *nat_hm; + ipfmutex_t nat_lock; struct nat *nat_next; + struct nat **nat_pnext; struct nat *nat_hnext[2]; struct nat **nat_phnext[2]; + struct hostmap *nat_hm; + void *nat_data; struct nat **nat_me; - void *nat_ifp; - int nat_dir; - char nat_ifname[IFNAMSIZ]; -#if SOLARIS || defined(__sgi) - kmutex_t nat_lock; -#endif + struct ipstate *nat_state; + struct ap_session *nat_aps; /* proxy session */ + frentry_t *nat_fr; /* filter rule ptr if appropriate */ + struct ipnat *nat_ptr; /* pointer back to the rule */ + void *nat_ifps[2]; + void *nat_sync; + ipftqent_t nat_tqe; + u_32_t nat_flags; + u_32_t nat_sumd[2]; /* ip checksum delta for data segment*/ + u_32_t nat_ipsumd; /* ip checksum delta for ip header */ + u_32_t nat_mssclamp; /* if != zero clamp MSS to this */ + i6addr_t nat_inip6; + i6addr_t nat_outip6; + i6addr_t nat_oip6; /* other ip */ + U_QUAD_T nat_pkts[2]; + U_QUAD_T nat_bytes[2]; + union { + udpinfo_t nat_unu; + tcpinfo_t nat_unt; + icmpinfo_t nat_uni; + greinfo_t nat_ugre; + } nat_un; + u_short nat_oport; /* other port */ + u_short nat_use; + u_char nat_p; /* protocol for NAT */ + int nat_dir; + int nat_ref; /* reference count */ + int nat_hv[2]; + char nat_ifnames[2][LIFNAMSIZ]; + int nat_rev; /* 0 = forward, 1 = reverse */ } nat_t; +#define nat_inip nat_inip6.in4 +#define nat_outip nat_outip6.in4 +#define nat_oip nat_oip6.in4 +#define nat_age nat_tqe.tqe_die +#define nat_inport nat_un.nat_unt.ts_sport +#define nat_outport nat_un.nat_unt.ts_dport +#define nat_type nat_un.nat_uni.ici_type +#define nat_seq nat_un.nat_uni.ici_seq +#define nat_id nat_un.nat_uni.ici_id +#define nat_tcpstate nat_tqe.tqe_state + +/* + * Values for nat_dir + */ +#define NAT_INBOUND 0 +#define NAT_OUTBOUND 1 + +/* + * Definitions for nat_flags + */ +#define NAT_TCP 0x0001 /* IPN_TCP */ +#define NAT_UDP 0x0002 /* IPN_UDP */ +#define NAT_ICMPERR 0x0004 /* IPN_ICMPERR */ +#define NAT_ICMPQUERY 0x0008 /* IPN_ICMPQUERY */ +#define NAT_SEARCH 0x0010 +#define NAT_SLAVE 0x0020 /* Slave connection for a proxy */ +#define NAT_NOTRULEPORT 0x0040 + +#define NAT_TCPUDP (NAT_TCP|NAT_UDP) +#define NAT_TCPUDPICMP (NAT_TCP|NAT_UDP|NAT_ICMPERR) +#define NAT_TCPUDPICMPQ (NAT_TCP|NAT_UDP|NAT_ICMPQUERY) +#define NAT_FROMRULE (NAT_TCP|NAT_UDP) + +/* 0x0100 reserved for FI_W_SPORT */ +/* 0x0200 reserved for FI_W_DPORT */ +/* 0x0400 reserved for FI_W_SADDR */ +/* 0x0800 reserved for FI_W_DADDR */ +/* 0x1000 reserved for FI_W_NEWFR */ +/* 0x2000 reserved for SI_CLONE */ +/* 0x4000 reserved for SI_CLONED */ +/* 0x8000 reserved for SI_IGNOREPKT */ + +#define NAT_DEBUG 0x800000 + 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; - u_int in_use; - u_int in_hits; - struct in_addr in_nextip; - u_short in_pnext; - u_short in_ippip; /* IP #'s per IP# */ - u_32_t in_flags; /* From here to in_dport must be reflected */ - u_32_t in_mssclamp; /* if != zero clamp MSS to this */ - u_short in_spare; - u_short in_ppip; /* ports per IP */ - u_short in_port[2]; /* correctly in IPN_CMPSIZ */ - struct in_addr in_in[2]; - struct in_addr in_out[2]; - struct in_addr in_src[2]; - struct frtuc in_tuc; - u_int in_age[2]; /* Aging for NAT entries. Not for TCP */ - 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 */ + struct ipnat *in_next; /* NAT rule list next */ + struct ipnat *in_rnext; /* rdr rule hash next */ + struct ipnat **in_prnext; /* prior rdr next ptr */ + struct ipnat *in_mnext; /* map rule hash next */ + struct ipnat **in_pmnext; /* prior map next ptr */ + struct ipftq *in_tqehead[2]; + void *in_ifps[2]; + void *in_apr; + char *in_comment; + i6addr_t in_next6; + u_long in_space; + u_long in_hits; + u_int in_use; + u_int in_hv; + int in_flineno; /* conf. file line number */ + u_short in_pnext; + u_char in_v; + u_char in_xxx; + /* From here to the end is covered by IPN_CMPSIZ */ + u_32_t in_flags; + u_32_t in_mssclamp; /* if != 0 clamp MSS to this */ + u_int in_age[2]; + int in_redir; /* see below for values */ + int in_p; /* protocol. */ + i6addr_t in_in[2]; + i6addr_t in_out[2]; + i6addr_t in_src[2]; + frtuc_t in_tuc; + u_short in_port[2]; + u_short in_ppip; /* ports per IP. */ + u_short in_ippip; /* IP #'s per IP# */ + char in_ifnames[2][LIFNAMSIZ]; + char in_plabel[APR_LABELLEN]; /* proxy label. */ + ipftag_t in_tag; } ipnat_t; #define in_pmin in_port[0] /* Also holds static redir port */ #define in_pmax in_port[1] -#define in_nip in_nextip.s_addr -#define in_inip in_in[0].s_addr -#define in_inmsk in_in[1].s_addr -#define in_outip in_out[0].s_addr -#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_nextip in_next6.in4 +#define in_nip in_next6.in4.s_addr +#define in_inip in_in[0].in4.s_addr +#define in_inmsk in_in[1].in4.s_addr +#define in_outip in_out[0].in4.s_addr +#define in_outmsk in_out[1].in4.s_addr +#define in_srcip in_src[0].in4.s_addr +#define in_srcmsk in_src[1].in4.s_addr #define in_scmp in_tuc.ftu_scmp #define in_dcmp in_tuc.ftu_dcmp #define in_stop in_tuc.ftu_stop @@ -158,18 +225,44 @@ typedef struct ipnat { #define in_sport in_tuc.ftu_sport #define in_dport in_tuc.ftu_dport -#define NAT_OUTBOUND 0 -#define NAT_INBOUND 1 +/* + * Bit definitions for in_flags + */ +#define IPN_ANY 0x00000 +#define IPN_TCP 0x00001 +#define IPN_UDP 0x00002 +#define IPN_TCPUDP (IPN_TCP|IPN_UDP) +#define IPN_ICMPERR 0x00004 +#define IPN_TCPUDPICMP (IPN_TCP|IPN_UDP|IPN_ICMPERR) +#define IPN_ICMPQUERY 0x00008 +#define IPN_TCPUDPICMPQ (IPN_TCP|IPN_UDP|IPN_ICMPQUERY) +#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) +#define IPN_AUTOPORTMAP 0x00010 +#define IPN_IPRANGE 0x00020 +#define IPN_FILTER 0x00040 +#define IPN_SPLIT 0x00080 +#define IPN_ROUNDR 0x00100 +#define IPN_NOTSRC 0x04000 +#define IPN_NOTDST 0x08000 +#define IPN_DYNSRCIP 0x10000 /* dynamic src IP# */ +#define IPN_DYNDSTIP 0x20000 /* dynamic dst IP# */ +#define IPN_DELETE 0x40000 +#define IPN_STICKY 0x80000 +#define IPN_FRAG 0x100000 +#define IPN_FIXEDDPORT 0x200000 +#define IPN_FINDFORWARD 0x400000 +#define IPN_IN 0x800000 +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ + IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|\ + IPN_FRAG|IPN_STICKY|IPN_FIXEDDPORT|IPN_ICMPQUERY) +/* + * Values for in_redir + */ #define NAT_MAP 0x01 #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) #define NAT_MAPBLK 0x04 -/* 0x100 reserved for FI_W_SPORT */ -/* 0x200 reserved for FI_W_DPORT */ -/* 0x400 reserved for FI_W_SADDR */ -/* 0x800 reserved for FI_W_DADDR */ -/* 0x1000 reserved for FI_W_NEWFR */ #define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ #define USABLE_PORTS (65536 - MAPBLK_MINPORT) @@ -204,16 +297,59 @@ typedef struct natget { } natget_t; +typedef struct nattrpnt { + struct in_addr tr_dstip; /* real destination IP# */ + struct in_addr tr_srcip; /* real source IP# */ + struct in_addr tr_locip; /* local source IP# */ + u_int tr_flags; + int tr_expire; + u_short tr_dstport; /* real destination port# */ + u_short tr_srcport; /* real source port# */ + u_short tr_locport; /* local source port# */ + struct nattrpnt *tr_hnext; + struct nattrpnt **tr_phnext; + struct nattrpnt *tr_next; + struct nattrpnt **tr_pnext; /* previous next */ +} nattrpnt_t; + +#define TN_CMPSIZ offsetof(nattrpnt_t, tr_hnext) + + +/* + * This structure gets used to help NAT sessions keep the same NAT rule (and + * thus translation for IP address) when: + * (a) round-robin redirects are in use + * (b) different IP add + */ typedef struct hostmap { struct hostmap *hm_next; struct hostmap **hm_pnext; struct ipnat *hm_ipnat; - struct in_addr hm_realip; + struct in_addr hm_srcip; + struct in_addr hm_dstip; struct in_addr hm_mapip; - int hm_ref; + u_32_t hm_port; + int hm_ref; } hostmap_t; +/* + * Structure used to pass information in to nat_newmap and nat_newrdr. + */ +typedef struct natinfo { + ipnat_t *nai_np; + u_32_t nai_sum1; + u_32_t nai_sum2; + u_32_t nai_nflags; + u_32_t nai_flags; + struct in_addr nai_ip; + u_short nai_port; + u_short nai_nport; + u_short nai_sport; + u_short nai_dport; +} natinfo_t; + + typedef struct natstat { u_long ns_mapped[2]; u_long ns_rules; @@ -224,37 +360,23 @@ typedef struct natstat { u_long ns_logfail; u_long ns_memfail; u_long ns_badnat; + u_long ns_addtrpnt; nat_t **ns_table[2]; hostmap_t **ns_maptable; ipnat_t *ns_list; void *ns_apslist; + u_int ns_wilds; u_int ns_nattab_sz; + u_int ns_nattab_max; u_int ns_rultab_sz; u_int ns_rdrtab_sz; + u_int ns_trpntab_sz; u_int ns_hostmap_sz; nat_t *ns_instances; - u_int ns_wilds; + nattrpnt_t *ns_trpntlist; + u_long *ns_bucketlen[2]; } natstat_t; -#define IPN_ANY 0x000 -#define IPN_TCP 0x001 -#define IPN_UDP 0x002 -#define IPN_TCPUDP (IPN_TCP|IPN_UDP) -#define IPN_DELETE 0x004 -#define IPN_ICMPERR 0x008 -#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) -#define IPN_AUTOPORTMAP 0x010 -#define IPN_IPRANGE 0x020 -#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ - IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|IPN_FRAG) -#define IPN_FILTER 0x040 -#define IPN_SPLIT 0x080 -#define IPN_ROUNDR 0x100 -#define IPN_NOTSRC 0x080000 -#define IPN_NOTDST 0x100000 -#define IPN_FRAG 0x200000 - - typedef struct natlog { struct in_addr nl_origip; struct in_addr nl_outip; @@ -264,8 +386,8 @@ typedef struct natlog { u_short nl_inport; u_short nl_type; int nl_rule; - U_QUAD_T nl_pkts; - U_QUAD_T nl_bytes; + U_QUAD_T nl_pkts[2]; + U_QUAD_T nl_bytes[2]; u_char nl_p; } natlog_t; @@ -274,6 +396,7 @@ typedef struct natlog { #define NL_NEWRDR NAT_REDIRECT #define NL_NEWBIMAP NAT_BIMAP #define NL_NEWBLOCK NAT_MAPBLK +#define NL_CLONE 0xfffd #define NL_FLUSH 0xfffe #define NL_EXPIRE 0xffff @@ -295,46 +418,60 @@ typedef struct natlog { #define NAT_SYSSPACE 0x80000000 #define NAT_LOCKHELD 0x40000000 + extern u_int ipf_nattable_sz; +extern u_int ipf_nattable_max; extern u_int ipf_natrules_sz; extern u_int ipf_rdrrules_sz; +extern u_int ipf_hostmap_sz; +extern u_int fr_nat_maxbucket; +extern u_int fr_nat_maxbucket_reset; extern int fr_nat_lock; -extern void ip_natsync __P((void *)); +extern void fr_natsync __P((void *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; +extern u_long fr_defnatipage; + /* nat_table[0] -> hashed list sorted by inside (ip, port) */ + /* nat_table[1] -> hashed list sorted by outside (ip, port) */ extern nat_t **nat_table[2]; extern nat_t *nat_instances; +extern ipnat_t *nat_list; extern ipnat_t **nat_rules; extern ipnat_t **rdr_rules; -extern ipnat_t *nat_list; +extern ipftq_t *nat_utqe; extern natstat_t nat_stats; + #if defined(__OpenBSD__) extern void nat_ifdetach __P((void *)); #endif -#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)); -#endif -extern int nat_init __P((void)); -extern nat_t *nat_new __P((fr_info_t *, ip_t *, ipnat_t *, nat_t **, - u_int, int)); +extern int fr_nat_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int fr_natinit __P((void)); +extern nat_t *nat_new __P((fr_info_t *, ipnat_t *, nat_t **, u_int, int)); extern nat_t *nat_outlookup __P((fr_info_t *, u_int, u_int, struct in_addr, - struct in_addr, int)); + struct in_addr)); +extern void fix_datacksum __P((u_short *, u_32_t)); extern nat_t *nat_inlookup __P((fr_info_t *, u_int, u_int, struct in_addr, - struct in_addr, int)); + struct in_addr)); +extern nat_t *nat_tnlookup __P((fr_info_t *, int)); +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_icmplookup __P((ip_t *, fr_info_t *, int)); -extern nat_t *nat_icmp __P((ip_t *, fr_info_t *, u_int *, int)); -extern int nat_clearlist __P((void)); -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 *)); -extern void ip_natunload __P((void)), ip_natexpire __P((void)); +extern nat_t *nat_icmperrorlookup __P((fr_info_t *, int)); +extern nat_t *nat_icmperror __P((fr_info_t *, u_int *, int)); +extern int nat_insert __P((nat_t *, int)); + +extern int fr_checknatout __P((fr_info_t *, u_32_t *)); +extern int fr_natout __P((fr_info_t *, nat_t *, int, u_32_t)); +extern int fr_checknatin __P((fr_info_t *, u_32_t *)); +extern int fr_natin __P((fr_info_t *, nat_t *, int, u_32_t)); +extern void fr_natunload __P((void)); +extern void fr_natexpire __P((void)); extern void nat_log __P((struct nat *, u_int)); extern void fix_incksum __P((fr_info_t *, u_short *, u_32_t)); extern void fix_outcksum __P((fr_info_t *, u_short *, u_32_t)); -extern void fix_datacksum __P((u_short *, u_32_t)); +extern void fr_natderef __P((nat_t **)); +extern u_short *nat_proto __P((fr_info_t *, nat_t *, u_int)); +extern void nat_update __P((fr_info_t *, nat_t *, ipnat_t *)); +extern void fr_setnatqueue __P((nat_t *, int)); #endif /* __IP_NAT_H__ */ diff --git a/contrib/ipfilter/ip_netbios_pxy.c b/contrib/ipfilter/ip_netbios_pxy.c index ee9b0c4..0ff6d25 100644 --- a/contrib/ipfilter/ip_netbios_pxy.c +++ b/contrib/ipfilter/ip_netbios_pxy.c @@ -1,11 +1,13 @@ +/* $NetBSD$ */ + /* * Simple netbios-dgm transparent proxy for in-kernel use. * For use with the NAT code. - * $Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp $ + * Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp */ /*- - * Copyright (c) 2002 Paul J. Ledbetter III + * Copyright (c) 2002-2003 Paul J. Ledbetter III * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,16 +31,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp $ + * Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp */ #define IPF_NETBIOS_PROXY int ippr_netbios_init __P((void)); -int ippr_netbios_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_netbios_fini __P((void)); +int ippr_netbios_out __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t netbiosfr; +int netbios_proxy_init = 0; + /* * Initialize local structures. */ @@ -47,43 +52,55 @@ int ippr_netbios_init() bzero((char *)&netbiosfr, sizeof(netbiosfr)); netbiosfr.fr_ref = 1; netbiosfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&netbiosfr.fr_lock, "NETBIOS proxy rule lock"); + netbios_proxy_init = 1; + return 0; } -int ippr_netbios_out(fin, ip, aps, nat) + +void ippr_netbios_fini() +{ + if (netbios_proxy_init == 1) { + MUTEX_DESTROY(&netbiosfr.fr_lock); + netbios_proxy_init = 0; + } +} + + +int ippr_netbios_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { char dgmbuf[6]; - int off, dlen; udphdr_t *udp; + ip_t *ip; mb_t *m; + aps = aps; /* LINT */ + nat = nat; /* LINT */ + + ip = fin->fin_ip; m = *(mb_t **)fin->fin_mp; off = fin->fin_hlen + sizeof(udphdr_t); -#if SOLARIS - dlen = msgdsize(m); -#else - dlen = mbufchainlen(m); -#endif + dlen = M_LEN(m); dlen -= off; /* * no net bios datagram could possibly be shorter than this */ - if (dlen < 11) + if (dlen < 11) return 0; udp = (udphdr_t *)fin->fin_dp; - /* + /* * move past the * ip header; * udp header; - * 4 bytes into the net bios dgm header. + * 4 bytes into the net bios dgm header. * According to rfc1002, this should be the exact location of * the source address/port */ @@ -99,11 +116,7 @@ nat_t *nat; dgmbuf[5] = (char)((udp->uh_sport >> 8)&0xFF); /* replace data in packet */ -#if SOLARIS - copyin_mblk(m, off, sizeof(dgmbuf), dgmbuf); -#else - m_copyback(m, off, sizeof(dgmbuf), dgmbuf); -#endif + COPYBACK(m, off, sizeof(dgmbuf), dgmbuf); return 0; } diff --git a/contrib/ipfilter/ip_pool.c b/contrib/ipfilter/ip_pool.c new file mode 100644 index 0000000..b6e111b --- /dev/null +++ b/contrib/ipfilter/ip_pool.c @@ -0,0 +1,786 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001, 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#if defined(__osf__) +# define _PROTO_NET_H_ +#endif +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#if !defined(_KERNEL) && !defined(__KERNEL__) +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL +#else +# include <sys/systm.h> +# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) +# include <sys/proc.h> +# endif +#endif +#include <sys/time.h> +#if !defined(linux) +# include <sys/protosw.h> +#endif +#include <sys/socket.h> +#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__)) +# include <sys/mbuf.h> +#endif +#if defined(__SVR4) || defined(__svr4__) +# include <sys/filio.h> +# include <sys/byteorder.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif +# include <sys/stream.h> +# include <sys/kmem.h> +#endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +#endif + +#if (defined(__osf__) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL) +# ifdef __osf__ +# include <net/radix.h> +# endif +# include "radix_ipf_local.h" +# define _RADIX_H_ +#endif +#include <net/if.h> +#include <netinet/in.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_pool.h" + +#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \ + ((BSD >= 198911) && !defined(__osf__) && \ + !defined(__hpux) && !defined(__sgi)) +static int rn_freenode __P((struct radix_node *, void *)); +#endif + +/* END OF INCLUDES */ + +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ip_pool.c,v 2.55.2.12 2005/02/01 04:04:46 darrenr Exp"; +#endif + +#ifdef IPFILTER_LOOKUP + +# ifndef RADIX_NODE_HEAD_LOCK +# define RADIX_NODE_HEAD_LOCK(x) ; +# endif +# ifndef RADIX_NODE_HEAD_UNLOCK +# define RADIX_NODE_HEAD_UNLOCK(x) ; +# endif + +ip_pool_stat_t ipoolstat; +ipfrwlock_t ip_poolrw; + +/* + * Binary tree routines from Sedgewick and enhanced to do ranges of addresses. + * NOTE: Insertion *MUST* be from greatest range to least for it to work! + * These should be replaced, eventually, by something else - most notably a + * interval searching method. The important feature is to be able to find + * the best match. + * + * So why not use a radix tree for this? As the first line implies, it + * has been written to work with a _range_ of addresses. A range is not + * necessarily a match with any given netmask so what we end up dealing + * with is an interval tree. Implementations of these are hard to find + * and the one herein is far from bug free. + * + * Sigh, in the end I became convinced that the bugs the code contained did + * not make it worthwhile not using radix trees. For now the radix tree from + * 4.4 BSD is used, but this is not viewed as a long term solution. + */ +ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; + + +#ifdef TEST_POOL +void treeprint __P((ip_pool_t *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + addrfamily_t a, b; + iplookupop_t op; + ip_pool_t *ipo; + i6addr_t ip; + + RWLOCK_INIT(&ip_poolrw, "poolrw"); + ip_pool_init(); + + bzero((char *)&a, sizeof(a)); + bzero((char *)&b, sizeof(b)); + bzero((char *)&ip, sizeof(ip)); + bzero((char *)&op, sizeof(op)); + strcpy(op.iplo_name, "0"); + + if (ip_pool_create(&op) == 0) + ipo = ip_pool_find(0, "0"); + + a.adf_addr.in4.s_addr = 0x0a010203; + b.adf_addr.in4.s_addr = 0xffffffff; + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + + a.adf_addr.in4.s_addr = 0x0a000000; + b.adf_addr.in4.s_addr = 0xff000000; + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); + + a.adf_addr.in4.s_addr = 0x0a010100; + b.adf_addr.in4.s_addr = 0xffffff00; + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + + a.adf_addr.in4.s_addr = 0x0a010200; + b.adf_addr.in4.s_addr = 0xffffff00; + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0); + + a.adf_addr.in4.s_addr = 0x0a010000; + b.adf_addr.in4.s_addr = 0xffff0000; + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + + a.adf_addr.in4.s_addr = 0x0a01020f; + b.adf_addr.in4.s_addr = 0xffffffff; + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); + ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1); +#ifdef DEBUG_POOL +treeprint(ipo); +#endif + ip.in4.s_addr = 0x0a00aabb; + printf("search(%#x) = %d (0)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0a000001; + printf("search(%#x) = %d (0)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0a000101; + printf("search(%#x) = %d (0)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0a010001; + printf("search(%#x) = %d (1)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0a010101; + printf("search(%#x) = %d (1)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0a010201; + printf("search(%#x) = %d (0)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0a010203; + printf("search(%#x) = %d (1)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0a01020f; + printf("search(%#x) = %d (1)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + + ip.in4.s_addr = 0x0b00aabb; + printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, + ip_pool_search(ipo, 4, &ip)); + +#ifdef DEBUG_POOL +treeprint(ipo); +#endif + + ip_pool_fini(); + + return 0; +} + + +void +treeprint(ipo) +ip_pool_t *ipo; +{ + ip_pool_node_t *c; + + for (c = ipo->ipo_list; c != NULL; c = c->ipn_next) + printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n", + c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr, + c->ipn_mask.adf_addr.in4.s_addr, + c->ipn_info, c->ipn_hits); +} +#endif /* TEST_POOL */ + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_init */ +/* Returns: int - 0 = success, else error */ +/* */ +/* Initialise the routing table data structures where required. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_init() +{ + + bzero((char *)&ipoolstat, sizeof(ipoolstat)); + +#if (!defined(_KERNEL) || (BSD < 199306)) + rn_init(); +#endif + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_fini */ +/* Returns: int - 0 = success, else error */ +/* Locks: WRITE(ipf_global) */ +/* */ +/* Clean up all the pool data structures allocated and call the cleanup */ +/* function for the radix tree that supports the pools. ip_pool_destroy() is*/ +/* used to delete the pools one by one to ensure they're properly freed up. */ +/* ------------------------------------------------------------------------ */ +void ip_pool_fini() +{ + ip_pool_t *p, *q; + iplookupop_t op; + int i; + + ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); + + for (i = 0; i <= IPL_LOGMAX; i++) { + for (q = ip_pool_list[i]; (p = q) != NULL; ) { + op.iplo_unit = i; + (void)strncpy(op.iplo_name, p->ipo_name, + sizeof(op.iplo_name)); + q = p->ipo_next; + (void) ip_pool_destroy(&op); + } + } + +#if (!defined(_KERNEL) || (BSD < 199306)) + rn_fini(); +#endif +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_statistics */ +/* Returns: int - 0 = success, else error */ +/* Parameters: op(I) - pointer to lookup operation arguments */ +/* */ +/* Copy the current statistics out into user space, collecting pool list */ +/* pointers as appropriate for later use. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_statistics(op) +iplookupop_t *op; +{ + ip_pool_stat_t stats; + int unit, i, err = 0; + + if (op->iplo_size != sizeof(ipoolstat)) + return EINVAL; + + bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats)); + unit = op->iplo_unit; + if (unit == IPL_LOGALL) { + for (i = 0; i < IPL_LOGSIZE; i++) + stats.ipls_list[i] = ip_pool_list[i]; + } else if (unit >= 0 && unit < IPL_LOGSIZE) { + if (op->iplo_name[0] != '\0') + stats.ipls_list[unit] = ip_pool_find(unit, + op->iplo_name); + else + stats.ipls_list[unit] = ip_pool_list[unit]; + } else + err = EINVAL; + if (err == 0) + err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); + return err; +} + + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_find */ +/* Returns: int - 0 = success, else error */ +/* Parameters: ipo(I) - pointer to the pool getting the new node. */ +/* */ +/* Find a matching pool inside the collection of pools for a particular */ +/* device, indicated by the unit number. */ +/* ------------------------------------------------------------------------ */ +void *ip_pool_find(unit, name) +int unit; +char *name; +{ + ip_pool_t *p; + + for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next) + if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0) + break; + return p; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_findeq */ +/* Returns: int - 0 = success, else error */ +/* Parameters: ipo(I) - pointer to the pool getting the new node. */ +/* addr(I) - pointer to address information to delete */ +/* mask(I) - */ +/* */ +/* Searches for an exact match of an entry in the pool. */ +/* ------------------------------------------------------------------------ */ +ip_pool_node_t *ip_pool_findeq(ipo, addr, mask) +ip_pool_t *ipo; +addrfamily_t *addr, *mask; +{ + struct radix_node *n; +#ifdef USE_SPL + int s; + + SPL_NET(s); +#endif + RADIX_NODE_HEAD_LOCK(ipo->ipo_head); + n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head); + RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + SPL_X(s); + return (ip_pool_node_t *)n; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_search */ +/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ +/* Parameters: tptr(I) - pointer to the pool to search */ +/* version(I) - IP protocol version (4 or 6) */ +/* dptr(I) - pointer to address information */ +/* */ +/* Search the pool for a given address and return a search result. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_search(tptr, version, dptr) +void *tptr; +int version; +void *dptr; +{ + struct radix_node *rn; + ip_pool_node_t *m; + i6addr_t *addr; + addrfamily_t v; + ip_pool_t *ipo; + int rv; + + ipo = tptr; + if (ipo == NULL) + return -1; + + rv = 1; + m = NULL; + addr = (i6addr_t *)dptr; + bzero(&v, sizeof(v)); + v.adf_len = offsetof(addrfamily_t, adf_addr); + + if (version == 4) { + v.adf_len += sizeof(addr->in4); + v.adf_addr.in4 = addr->in4; +#ifdef USE_INET6 + } else if (version == 6) { + v.adf_len += sizeof(addr->in6); + v.adf_addr.in6 = addr->in6; +#endif + } else + return -1; + + READ_ENTER(&ip_poolrw); + + RADIX_NODE_HEAD_LOCK(ipo->ipo_head); + rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head); + RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + + if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) { + m = (ip_pool_node_t *)rn; + ipo->ipo_hits++; + m->ipn_hits++; + rv = m->ipn_info; + } + RWLOCK_EXIT(&ip_poolrw); + return rv; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_insert */ +/* Returns: int - 0 = success, else error */ +/* Parameters: ipo(I) - pointer to the pool getting the new node. */ +/* addr(I) - address being added as a node */ +/* mask(I) - netmask to with the node being added */ +/* info(I) - extra information to store in this node. */ +/* Locks: WRITE(ip_poolrw) */ +/* */ +/* Add another node to the pool given by ipo. The three parameters passed */ +/* in (addr, mask, info) shold all be stored in the node. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_insert(ipo, addr, mask, info) +ip_pool_t *ipo; +i6addr_t *addr, *mask; +int info; +{ + struct radix_node *rn; + ip_pool_node_t *x; + + ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); + + KMALLOC(x, ip_pool_node_t *); + if (x == NULL) { + return ENOMEM; + } + + bzero(x, sizeof(*x)); + + x->ipn_info = info; + (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name)); + + bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr)); + x->ipn_addr.adf_len = sizeof(x->ipn_addr); + bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask)); + x->ipn_mask.adf_len = sizeof(x->ipn_mask); + + RADIX_NODE_HEAD_LOCK(ipo->ipo_head); + rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask, + ipo->ipo_head, x->ipn_nodes); + RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); +#ifdef DEBUG_POOL + printf("Added %p at %p\n", x, rn); +#endif + + if (rn == NULL) { + KFREE(x); + return ENOMEM; + } + + x->ipn_next = ipo->ipo_list; + x->ipn_pnext = &ipo->ipo_list; + if (ipo->ipo_list != NULL) + ipo->ipo_list->ipn_pnext = &x->ipn_next; + ipo->ipo_list = x; + + ipoolstat.ipls_nodes++; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_create */ +/* Returns: int - 0 = success, else error */ +/* Parameters: op(I) - pointer to iplookup struct with call details */ +/* Locks: WRITE(ip_poolrw) */ +/* */ +/* Creates a new group according to the paramters passed in via the */ +/* iplookupop structure. Does not check to see if the group already exists */ +/* when being inserted - assume this has already been done. If the pool is */ +/* marked as being anonymous, give it a new, unique, identifier. Call any */ +/* other functions required to initialise the structure. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_create(op) +iplookupop_t *op; +{ + char name[FR_GROUPLEN]; + int poolnum, unit; + ip_pool_t *h; + + ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); + + KMALLOC(h, ip_pool_t *); + if (h == NULL) + return ENOMEM; + bzero(h, sizeof(*h)); + + if (rn_inithead((void **)&h->ipo_head, + offsetof(addrfamily_t, adf_addr) << 3) == 0) { + KFREE(h); + return ENOMEM; + } + + unit = op->iplo_unit; + + if ((op->iplo_arg & IPOOL_ANON) != 0) { + ip_pool_t *p; + + poolnum = IPOOL_ANON; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%x", poolnum); +#else + (void)sprintf(name, "%x", poolnum); +#endif + + for (p = ip_pool_list[unit]; p != NULL; ) { + if (strncmp(name, p->ipo_name, + sizeof(p->ipo_name)) == 0) { + poolnum++; +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%x", poolnum); +#else + (void)sprintf(name, "%x", poolnum); +#endif + p = ip_pool_list[unit]; + } else + p = p->ipo_next; + } + + (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); + } else { + (void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); + } + + h->ipo_ref = 1; + h->ipo_list = NULL; + h->ipo_unit = unit; + h->ipo_next = ip_pool_list[unit]; + if (ip_pool_list[unit] != NULL) + ip_pool_list[unit]->ipo_pnext = &h->ipo_next; + h->ipo_pnext = &ip_pool_list[unit]; + ip_pool_list[unit] = h; + + ipoolstat.ipls_pools++; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_remove */ +/* Returns: int - 0 = success, else error */ +/* Parameters: ipo(I) - pointer to the pool to remove the node from. */ +/* ipe(I) - address being deleted as a node */ +/* Locks: WRITE(ip_poolrw) */ +/* */ +/* Add another node to the pool given by ipo. The three parameters passed */ +/* in (addr, mask, info) shold all be stored in the node. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_remove(ipo, ipe) +ip_pool_t *ipo; +ip_pool_node_t *ipe; +{ + ip_pool_node_t **ipp, *n; + + ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); + + for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) { + if (ipe == n) { + *n->ipn_pnext = n->ipn_next; + if (n->ipn_next) + n->ipn_next->ipn_pnext = n->ipn_pnext; + break; + } + } + + if (n == NULL) + return ENOENT; + + RADIX_NODE_HEAD_LOCK(ipo->ipo_head); + ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, + ipo->ipo_head); + RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + KFREE(n); + + ipoolstat.ipls_nodes--; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_destroy */ +/* Returns: int - 0 = success, else error */ +/* Parameters: op(I) - information about the pool to remove */ +/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* */ +/* Search for a pool using paramters passed in and if it's not otherwise */ +/* busy, free it. */ +/* */ +/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ +/* may not be initialised, we can't use an ASSERT to enforce the locking */ +/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_destroy(op) +iplookupop_t *op; +{ + ip_pool_t *ipo; + + ipo = ip_pool_find(op->iplo_unit, op->iplo_name); + if (ipo == NULL) + return ESRCH; + + if (ipo->ipo_ref != 1) + return EBUSY; + + ip_pool_free(ipo); + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_flush */ +/* Returns: int - number of pools deleted */ +/* Parameters: fp(I) - which pool(s) to flush */ +/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* */ +/* Free all pools associated with the device that matches the unit number */ +/* passed in with operation. */ +/* */ +/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ +/* may not be initialised, we can't use an ASSERT to enforce the locking */ +/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ +/* ------------------------------------------------------------------------ */ +int ip_pool_flush(fp) +iplookupflush_t *fp; +{ + int i, num = 0, unit, err; + ip_pool_t *p, *q; + iplookupop_t op; + + unit = fp->iplf_unit; + + for (i = 0; i <= IPL_LOGMAX; i++) { + if (unit != IPLT_ALL && i != unit) + continue; + for (q = ip_pool_list[i]; (p = q) != NULL; ) { + op.iplo_unit = i; + (void)strncpy(op.iplo_name, p->ipo_name, + sizeof(op.iplo_name)); + q = p->ipo_next; + err = ip_pool_destroy(&op); + if (err == 0) + num++; + else + break; + } + } + return num; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_free */ +/* Returns: void */ +/* Parameters: ipo(I) - pointer to pool structure */ +/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* */ +/* Deletes the pool strucutre passed in from the list of pools and deletes */ +/* all of the address information stored in it, including any tree data */ +/* structures also allocated. */ +/* */ +/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ +/* may not be initialised, we can't use an ASSERT to enforce the locking */ +/* assertion that one of the two (ip_poolrw,ipf_global) is held. */ +/* ------------------------------------------------------------------------ */ +void ip_pool_free(ipo) +ip_pool_t *ipo; +{ + ip_pool_node_t *n; + + RADIX_NODE_HEAD_LOCK(ipo->ipo_head); + while ((n = ipo->ipo_list) != NULL) { + ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, + ipo->ipo_head); + + *n->ipn_pnext = n->ipn_next; + if (n->ipn_next) + n->ipn_next->ipn_pnext = n->ipn_pnext; + + KFREE(n); + + ipoolstat.ipls_nodes--; + } + RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); + + ipo->ipo_list = NULL; + if (ipo->ipo_next != NULL) + ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; + *ipo->ipo_pnext = ipo->ipo_next; + rn_freehead(ipo->ipo_head); + KFREE(ipo); + + ipoolstat.ipls_pools--; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_deref */ +/* Returns: void */ +/* Parameters: ipo(I) - pointer to pool structure */ +/* Locks: WRITE(ip_poolrw) */ +/* */ +/* Drop the number of known references to this pool structure by one and if */ +/* we arrive at zero known references, free it. */ +/* ------------------------------------------------------------------------ */ +void ip_pool_deref(ipo) +ip_pool_t *ipo; +{ + + ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); + + ipo->ipo_ref--; + if (ipo->ipo_ref == 0) + ip_pool_free(ipo); +} + + +# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \ + !defined(__hpux) && !defined(__sgi)) +static int +rn_freenode(struct radix_node *n, void *p) +{ + struct radix_node_head *rnh = p; + struct radix_node *d; + + d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); + if (d != NULL) { + FreeS(d, max_keylen + 2 * sizeof (*d)); + } + return 0; +} + + +void +rn_freehead(rnh) + struct radix_node_head *rnh; +{ + + RADIX_NODE_HEAD_LOCK(rnh); + (*rnh->rnh_walktree)(rnh, rn_freenode, rnh); + + rnh->rnh_addaddr = NULL; + rnh->rnh_deladdr = NULL; + rnh->rnh_matchaddr = NULL; + rnh->rnh_lookup = NULL; + rnh->rnh_walktree = NULL; + RADIX_NODE_HEAD_UNLOCK(rnh); + + Free(rnh); +} +# endif + +#endif /* IPFILTER_LOOKUP */ diff --git a/contrib/ipfilter/ip_pool.h b/contrib/ipfilter/ip_pool.h new file mode 100644 index 0000000..3e3c073 --- /dev/null +++ b/contrib/ipfilter/ip_pool.h @@ -0,0 +1,87 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001, 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ip_pool.h,v 2.26.2.2 2004/03/23 12:44:34 darrenr Exp + */ + +#ifndef __IP_POOL_H__ +#define __IP_POOL_H__ + +#if defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) && \ + !defined(linux) && !defined(sun) +# include <net/radix.h> +extern void rn_freehead __P((struct radix_node_head *)); +# define FreeS(p, z) KFREES(p, z) +extern int max_keylen; +#else +# if defined(__osf__) || defined(__hpux) +# include "radix_ipf_local.h" +# define radix_mask ipf_radix_mask +# define radix_node ipf_radix_node +# define radix_node_head ipf_radix_node_head +# else +# include "radix_ipf.h" +# endif +#endif +#include "netinet/ip_lookup.h" + +#define IP_POOL_NOMATCH 0 +#define IP_POOL_POSITIVE 1 + +typedef struct ip_pool_node { + struct radix_node ipn_nodes[2]; + addrfamily_t ipn_addr; + addrfamily_t ipn_mask; + int ipn_info; + char ipn_name[FR_GROUPLEN]; + u_long ipn_hits; + struct ip_pool_node *ipn_next, **ipn_pnext; +} ip_pool_node_t; + + +typedef struct ip_pool_s { + struct ip_pool_s *ipo_next; + struct ip_pool_s **ipo_pnext; + struct radix_node_head *ipo_head; + ip_pool_node_t *ipo_list; + u_long ipo_hits; + int ipo_unit; + int ipo_flags; + int ipo_ref; + char ipo_name[FR_GROUPLEN]; +} ip_pool_t; + +#define IPOOL_ANON 0x80000000 + + +typedef struct ip_pool_stat { + u_long ipls_pools; + u_long ipls_tables; + u_long ipls_nodes; + ip_pool_t *ipls_list[IPL_LOGSIZE]; +} ip_pool_stat_t; + + +extern ip_pool_stat_t ipoolstat; +extern ip_pool_t *ip_pool_list[IPL_LOGSIZE]; + +extern int ip_pool_search __P((void *, int, void *)); +extern int ip_pool_init __P((void)); +extern void ip_pool_fini __P((void)); +extern int ip_pool_create __P((iplookupop_t *)); +extern int ip_pool_insert __P((ip_pool_t *, i6addr_t *, i6addr_t *, int)); +extern int ip_pool_remove __P((ip_pool_t *, ip_pool_node_t *)); +extern int ip_pool_destroy __P((iplookupop_t *)); +extern void ip_pool_free __P((ip_pool_t *)); +extern void ip_pool_deref __P((ip_pool_t *)); +extern void *ip_pool_find __P((int, char *)); +extern ip_pool_node_t *ip_pool_findeq __P((ip_pool_t *, + addrfamily_t *, addrfamily_t *)); +extern int ip_pool_flush __P((iplookupflush_t *)); +extern int ip_pool_statistics __P((iplookupop_t *)); + +#endif /* __IP_POOL_H__ */ diff --git a/contrib/ipfilter/ip_pptp_pxy.c b/contrib/ipfilter/ip_pptp_pxy.c new file mode 100644 index 0000000..2511a17 --- /dev/null +++ b/contrib/ipfilter/ip_pptp_pxy.c @@ -0,0 +1,527 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002-2003 by Darren Reed + * + * Simple PPTP transparent proxy for in-kernel use. For use with the NAT + * code. + * + * Id: ip_pptp_pxy.c,v 2.10.2.9 2005/03/16 18:17:34 darrenr Exp + * + */ +#define IPF_PPTP_PROXY + +typedef struct pptp_hdr { + u_short pptph_len; + u_short pptph_type; + u_32_t pptph_cookie; +} pptp_hdr_t; + +#define PPTP_MSGTYPE_CTL 1 +#define PPTP_MTCTL_STARTREQ 1 +#define PPTP_MTCTL_STARTREP 2 +#define PPTP_MTCTL_STOPREQ 3 +#define PPTP_MTCTL_STOPREP 4 +#define PPTP_MTCTL_ECHOREQ 5 +#define PPTP_MTCTL_ECHOREP 6 +#define PPTP_MTCTL_OUTREQ 7 +#define PPTP_MTCTL_OUTREP 8 +#define PPTP_MTCTL_INREQ 9 +#define PPTP_MTCTL_INREP 10 +#define PPTP_MTCTL_INCONNECT 11 +#define PPTP_MTCTL_CLEAR 12 +#define PPTP_MTCTL_DISCONNECT 13 +#define PPTP_MTCTL_WANERROR 14 +#define PPTP_MTCTL_LINKINFO 15 + + +int ippr_pptp_init __P((void)); +void ippr_pptp_fini __P((void)); +int ippr_pptp_new __P((fr_info_t *, ap_session_t *, nat_t *)); +void ippr_pptp_del __P((ap_session_t *)); +int ippr_pptp_inout __P((fr_info_t *, ap_session_t *, nat_t *)); +void ippr_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *)); +int ippr_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); +int ippr_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int)); +int ippr_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *)); + +static frentry_t pptpfr; + +int pptp_proxy_init = 0; +int ippr_pptp_debug = 0; +int ippr_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */ + + +/* + * PPTP application proxy initialization. + */ +int ippr_pptp_init() +{ + bzero((char *)&pptpfr, sizeof(pptpfr)); + pptpfr.fr_ref = 1; + pptpfr.fr_age[0] = ippr_pptp_gretimeout; + pptpfr.fr_age[1] = ippr_pptp_gretimeout; + pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock"); + pptp_proxy_init = 1; + + return 0; +} + + +void ippr_pptp_fini() +{ + if (pptp_proxy_init == 1) { + MUTEX_DESTROY(&pptpfr.fr_lock); + pptp_proxy_init = 0; + } +} + + +/* + * Setup for a new PPTP proxy. + */ +int ippr_pptp_new(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + pptp_pxy_t *pptp; + ipnat_t *ipn; + ip_t *ip; + int off; + + ip = fin->fin_ip; + off = fin->fin_hlen + sizeof(udphdr_t); + + if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip, + ip->ip_dst) != NULL) { + if (ippr_pptp_debug > 0) + printf("ippr_pptp_new: GRE session already exists\n"); + return -1; + } + + aps->aps_psiz = sizeof(*pptp); + KMALLOCS(aps->aps_data, pptp_pxy_t *, sizeof(*pptp)); + if (aps->aps_data == NULL) { + if (ippr_pptp_debug > 0) + printf("ippr_pptp_new: malloc for aps_data failed\n"); + return -1; + } + + /* + * Create NAT rule against which the tunnel/transport mapping is + * created. This is required because the current NAT rule does not + * describe GRE but TCP instead. + */ + pptp = aps->aps_data; + bzero((char *)pptp, sizeof(*pptp)); + ipn = &pptp->pptp_rule; + ipn->in_ifps[0] = fin->fin_ifp; + ipn->in_apr = NULL; + ipn->in_use = 1; + ipn->in_hits = 1; + ipn->in_ippip = 1; + if (nat->nat_dir == NAT_OUTBOUND) { + ipn->in_nip = ntohl(nat->nat_outip.s_addr); + ipn->in_outip = fin->fin_saddr; + ipn->in_redir = NAT_MAP; + } else if (nat->nat_dir == NAT_INBOUND) { + ipn->in_nip = 0; + ipn->in_outip = nat->nat_outip.s_addr; + ipn->in_redir = NAT_REDIRECT; + } + ipn->in_inip = nat->nat_inip.s_addr; + ipn->in_inmsk = 0xffffffff; + ipn->in_outmsk = 0xffffffff; + ipn->in_srcip = fin->fin_saddr; + ipn->in_srcmsk = 0xffffffff; + bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0], + sizeof(ipn->in_ifnames[0])); + ipn->in_p = IPPROTO_GRE; + + pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer; + pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer; + return 0; +} + + +void ippr_pptp_donatstate(fin, nat, pptp) +fr_info_t *fin; +nat_t *nat; +pptp_pxy_t *pptp; +{ + fr_info_t fi; + grehdr_t gre; + nat_t *nat2; + u_char p; + ip_t *ip; + + ip = fin->fin_ip; + p = ip->ip_p; + + nat2 = pptp->pptp_nat; + if ((nat2 == NULL) || (pptp->pptp_state == NULL)) { + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)&gre, sizeof(gre)); + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_fi.fi_p = IPPROTO_GRE; + fi.fin_fr = &pptpfr; + if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) || + (nat->nat_dir == NAT_INBOUND && !fin->fin_out)) { + fi.fin_data[0] = pptp->pptp_call[0]; + fi.fin_data[1] = pptp->pptp_call[1]; + } else { + fi.fin_data[0] = pptp->pptp_call[1]; + fi.fin_data[1] = pptp->pptp_call[0]; + } + ip = fin->fin_ip; + ip->ip_p = IPPROTO_GRE; + fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); + fi.fin_flx |= FI_IGNORE; + fi.fin_dp = &gre; + gre.gr_flags = htons(1 << 13); + if (fin->fin_out && nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_saddr = fin->fin_fi.fi_daddr; + fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; + } else if (!fin->fin_out && nat->nat_dir == NAT_OUTBOUND) { + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; + fi.fin_fi.fi_daddr = fin->fin_fi.fi_saddr; + } + } + + /* + * Update NAT timeout/create NAT if missing. + */ + if (nat2 != NULL) + fr_queueback(&nat2->nat_tqe); + else { + nat2 = nat_new(&fi, &pptp->pptp_rule, &pptp->pptp_nat, + NAT_SLAVE, nat->nat_dir); + pptp->pptp_nat = nat2; + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, 0); + nat_update(&fi, nat2, nat2->nat_ptr); + } + } + + READ_ENTER(&ipf_state); + if (pptp->pptp_state != NULL) { + fr_queueback(&pptp->pptp_state->is_sti); + RWLOCK_EXIT(&ipf_state); + } else { + RWLOCK_EXIT(&ipf_state); + if (nat->nat_dir == NAT_INBOUND) + fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr; + else + fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr; + fi.fin_ifp = NULL; + pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state, + 0); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + } + ip->ip_p = p; + return; +} + + +/* + * Try and build up the next PPTP message in the TCP stream and if we can + * build it up completely (fits in our buffer) then pass it off to the message + * parsing function. + */ +int ippr_pptp_nextmessage(fin, nat, pptp, rev) +fr_info_t *fin; +nat_t *nat; +pptp_pxy_t *pptp; +int rev; +{ + static char *funcname = "ippr_pptp_nextmessage"; + pptp_side_t *pptps; + u_32_t start, end; + pptp_hdr_t *hdr; + tcphdr_t *tcp; + int dlen, off; + u_short len; + char *msg; + + tcp = fin->fin_dp; + dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); + start = ntohl(tcp->th_seq); + pptps = &pptp->pptp_side[rev]; + off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) + + fin->fin_ipoff; + + if (dlen <= 0) + return 0; + /* + * If the complete data packet is before what we expect to see + * "next", just ignore it as the chances are we've already seen it. + * The next if statement following this one really just causes packets + * ahead of what we've seen to be dropped, implying that something in + * the middle went missing and we want to see that first. + */ + end = start + dlen; + if (pptps->pptps_next > end && pptps->pptps_next > start) + return 0; + + if (pptps->pptps_next != start) { + if (ippr_pptp_debug > 5) + printf("%s: next (%x) != start (%x)\n", funcname, + pptps->pptps_next, start); + return -1; + } + + msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2); + + while (dlen > 0) { + off += pptps->pptps_bytes; + if (pptps->pptps_gothdr == 0) { + /* + * PPTP has an 8 byte header that inclues the cookie. + * The start of every message should include one and + * it should match 1a2b3c4d. Byte order is ignored, + * deliberately, when printing out the error. + */ + len = MIN(8 - pptps->pptps_bytes, dlen); + COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); + pptps->pptps_bytes += len; + pptps->pptps_wptr += len; + hdr = (pptp_hdr_t *)pptps->pptps_buffer; + if (pptps->pptps_bytes == 8) { + pptps->pptps_next += 8; + if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) { + if (ippr_pptp_debug > 1) + printf("%s: bad cookie (%x)\n", + funcname, + hdr->pptph_cookie); + return -1; + } + } + dlen -= len; + msg += len; + off += len; + + pptps->pptps_gothdr = 1; + len = ntohs(hdr->pptph_len); + pptps->pptps_len = len; + pptps->pptps_nexthdr += len; + + /* + * If a message is too big for the buffer, just set + * the fields for the next message to come along. + * The messages defined in RFC 2637 will not exceed + * 512 bytes (in total length) so this is likely a + * bad data packet, anyway. + */ + if (len > sizeof(pptps->pptps_buffer)) { + if (ippr_pptp_debug > 3) + printf("%s: message too big (%d)\n", + funcname, len); + pptps->pptps_next = pptps->pptps_nexthdr; + pptps->pptps_wptr = pptps->pptps_buffer; + pptps->pptps_gothdr = 0; + pptps->pptps_bytes = 0; + pptps->pptps_len = 0; + break; + } + } + + len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen); + COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); + pptps->pptps_bytes += len; + pptps->pptps_wptr += len; + pptps->pptps_next += len; + + if (pptps->pptps_len > pptps->pptps_bytes) + break; + + ippr_pptp_message(fin, nat, pptp, pptps); + pptps->pptps_wptr = pptps->pptps_buffer; + pptps->pptps_gothdr = 0; + pptps->pptps_bytes = 0; + pptps->pptps_len = 0; + + start += len; + msg += len; + dlen -= len; + } + + return 0; +} + + +/* + * handle a complete PPTP message + */ +int ippr_pptp_message(fin, nat, pptp, pptps) +fr_info_t *fin; +nat_t *nat; +pptp_pxy_t *pptp; +pptp_side_t *pptps; +{ + pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer; + + switch (ntohs(hdr->pptph_type)) + { + case PPTP_MSGTYPE_CTL : + ippr_pptp_mctl(fin, nat, pptp, pptps); + break; + + default : + break; + } + return 0; +} + + +/* + * handle a complete PPTP control message + */ +int ippr_pptp_mctl(fin, nat, pptp, pptps) +fr_info_t *fin; +nat_t *nat; +pptp_pxy_t *pptp; +pptp_side_t *pptps; +{ + u_short *buffer = (u_short *)(pptps->pptps_buffer); + pptp_side_t *pptpo; + + if (pptps == &pptp->pptp_side[0]) + pptpo = &pptp->pptp_side[1]; + else + pptpo = &pptp->pptp_side[0]; + + /* + * Breakout to handle all the various messages. Most are just state + * transition. + */ + switch (ntohs(buffer[4])) + { + case PPTP_MTCTL_STARTREQ : + pptps->pptps_state = PPTP_MTCTL_STARTREQ; + break; + case PPTP_MTCTL_STARTREP : + if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ) + pptps->pptps_state = PPTP_MTCTL_STARTREP; + break; + case PPTP_MTCTL_STOPREQ : + pptps->pptps_state = PPTP_MTCTL_STOPREQ; + break; + case PPTP_MTCTL_STOPREP : + if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ) + pptps->pptps_state = PPTP_MTCTL_STOPREP; + break; + case PPTP_MTCTL_ECHOREQ : + pptps->pptps_state = PPTP_MTCTL_ECHOREQ; + break; + case PPTP_MTCTL_ECHOREP : + if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ) + pptps->pptps_state = PPTP_MTCTL_ECHOREP; + break; + case PPTP_MTCTL_OUTREQ : + pptps->pptps_state = PPTP_MTCTL_OUTREQ; + break; + case PPTP_MTCTL_OUTREP : + if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) { + pptps->pptps_state = PPTP_MTCTL_OUTREP; + pptp->pptp_call[0] = buffer[7]; + pptp->pptp_call[1] = buffer[6]; + ippr_pptp_donatstate(fin, nat, pptp); + } + break; + case PPTP_MTCTL_INREQ : + pptps->pptps_state = PPTP_MTCTL_INREQ; + break; + case PPTP_MTCTL_INREP : + if (pptpo->pptps_state == PPTP_MTCTL_INREQ) { + pptps->pptps_state = PPTP_MTCTL_INREP; + pptp->pptp_call[0] = buffer[7]; + pptp->pptp_call[1] = buffer[6]; + ippr_pptp_donatstate(fin, nat, pptp); + } + break; + case PPTP_MTCTL_INCONNECT : + pptps->pptps_state = PPTP_MTCTL_INCONNECT; + break; + case PPTP_MTCTL_CLEAR : + pptps->pptps_state = PPTP_MTCTL_CLEAR; + break; + case PPTP_MTCTL_DISCONNECT : + pptps->pptps_state = PPTP_MTCTL_DISCONNECT; + break; + case PPTP_MTCTL_WANERROR : + pptps->pptps_state = PPTP_MTCTL_WANERROR; + break; + case PPTP_MTCTL_LINKINFO : + pptps->pptps_state = PPTP_MTCTL_LINKINFO; + break; + } + + return 0; +} + + +/* + * For outgoing PPTP packets. refresh timeouts for NAT & state entries, if + * we can. If they have disappeared, recreate them. + */ +int ippr_pptp_inout(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + pptp_pxy_t *pptp; + tcphdr_t *tcp; + int rev; + + if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) + rev = 1; + else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) + rev = 1; + else + rev = 0; + + tcp = (tcphdr_t *)fin->fin_dp; + if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { + pptp = (pptp_pxy_t *)aps->aps_data; + pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack); + pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack); + pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1; + pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1; + } + return ippr_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data, + rev); +} + + +/* + * clean up after ourselves. + */ +void ippr_pptp_del(aps) +ap_session_t *aps; +{ + pptp_pxy_t *pptp; + + pptp = aps->aps_data; + + if (pptp != NULL) { + /* + * Don't bother changing any of the NAT structure details, + * *_del() is on a callback from aps_free(), from nat_delete() + */ + + READ_ENTER(&ipf_state); + if (pptp->pptp_state != NULL) { + pptp->pptp_state->is_die = fr_ticks + 1; + pptp->pptp_state->is_me = NULL; + fr_queuefront(&pptp->pptp_state->is_sti); + } + RWLOCK_EXIT(&ipf_state); + + pptp->pptp_state = NULL; + pptp->pptp_nat = NULL; + } +} diff --git a/contrib/ipfilter/ip_proxy.c b/contrib/ipfilter/ip_proxy.c index f3b2cd5..18bc4e1 100644 --- a/contrib/ipfilter/ip_proxy.c +++ b/contrib/ipfilter/ip_proxy.c @@ -1,45 +1,58 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1997-2002 by Darren Reed. + * Copyright (C) 1997-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif - -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include <sys/errno.h> #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> #include <sys/file.h> -#if !defined(__FreeBSD_version) -# include <sys/ioctl.h> -#endif #include <sys/fcntl.h> -#if !defined(_KERNEL) && !defined(KERNEL) +#if !defined(_KERNEL) && !defined(__KERNEL__) # include <stdio.h> # include <string.h> # include <stdlib.h> +# include <ctype.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL #endif -#ifndef linux +#if !defined(linux) # include <sys/protosw.h> #endif #include <sys/socket.h> #if defined(_KERNEL) -# if !defined(linux) -# include <sys/systm.h> -# else -# include <linux/string.h> +# if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \ + !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) +# include <sys/ctype.h> # endif -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# include <sys/systm.h> +# if !defined(__SVR4) && !defined(__svr4__) # include <sys/mbuf.h> # endif +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) +# include <sys/filio.h> +# include <sys/fcntl.h> +# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #else +# include <sys/ioctl.h> +#endif +#if defined(__SVR4) || defined(__svr4__) # include <sys/byteorder.h> # ifdef _KERNEL # include <sys/dditypes.h> @@ -74,69 +87,93 @@ # include <sys/malloc.h> #endif -#if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.26 2002/12/06 11:40:23 darrenr Exp $"; +#include "netinet/ip_ftp_pxy.c" +#include "netinet/ip_rcmd_pxy.c" +# include "netinet/ip_pptp_pxy.c" +#if defined(_KERNEL) +# include "netinet/ip_irc_pxy.c" +# include "netinet/ip_raudio_pxy.c" +# include "netinet/ip_h323_pxy.c" +# ifdef IPFILTER_PRO +# include "netinet/ip_msnrpc_pxy.c" +# endif +# include "netinet/ip_netbios_pxy.c" #endif +#include "netinet/ip_ipsec_pxy.c" +#include "netinet/ip_rpcb_pxy.c" -#if defined(_KERNEL) && (SOLARIS || defined(__sgi)) -extern KRWLOCK_T ipf_nat, ipf_state; -#endif +/* END OF INCLUDES */ -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +#if !defined(lint) +static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.62.2.12 2005/03/03 14:28:24 darrenr Exp"; #endif static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); - -#define PROXY_DEBUG 0 - #define AP_SESS_SIZE 53 -#include "netinet/ip_ftp_pxy.c" #if defined(_KERNEL) -#include "netinet/ip_rcmd_pxy.c" -#include "netinet/ip_raudio_pxy.c" -#include "netinet/ip_netbios_pxy.c" -#include "netinet/ip_h323_pxy.c" +int ipf_proxy_debug = 0; +#else +int ipf_proxy_debug = 2; #endif -#include "netinet/ip_ipsec_pxy.c" - 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 - { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_fini, ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL }, #endif +#ifdef IPF_IRC_PROXY + { NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini, + ippr_irc_new, NULL, NULL, ippr_irc_out, NULL, NULL }, +#endif #ifdef IPF_RCMD_PROXY - { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, - ippr_rcmd_new, NULL, NULL, ippr_rcmd_out, NULL }, + { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_fini, + ippr_rcmd_new, NULL, ippr_rcmd_in, ippr_rcmd_out, NULL, NULL }, #endif #ifdef IPF_RAUDIO_PROXY - { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL, - ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL }, + { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, ippr_raudio_fini, + ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL, NULL }, #endif -#ifdef IPF_IPSEC_PROXY - { NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, ippr_ipsec_init, NULL, - ippr_ipsec_new, ippr_ipsec_del, NULL, ippr_ipsec_out, - ippr_ipsec_match }, +#ifdef IPF_MSNRPC_PROXY + { NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, ippr_msnrpc_init, ippr_msnrpc_fini, + ippr_msnrpc_new, NULL, ippr_msnrpc_in, ippr_msnrpc_out, NULL, NULL }, #endif #ifdef IPF_NETBIOS_PROXY - { NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, NULL, - NULL, NULL, NULL, ippr_netbios_out, NULL }, + { NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, ippr_netbios_fini, + NULL, NULL, NULL, ippr_netbios_out, NULL, NULL }, +#endif +#ifdef IPF_IPSEC_PROXY + { NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, + ippr_ipsec_init, ippr_ipsec_fini, ippr_ipsec_new, ippr_ipsec_del, + ippr_ipsec_inout, ippr_ipsec_inout, ippr_ipsec_match, NULL }, +#endif +#ifdef IPF_PPTP_PROXY + { NULL, "pptp", (char)IPPROTO_TCP, 0, 0, + ippr_pptp_init, ippr_pptp_fini, ippr_pptp_new, ippr_pptp_del, + ippr_pptp_inout, ippr_pptp_inout, NULL, NULL }, #endif #ifdef IPF_H323_PROXY - { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, NULL, - ippr_h323_new, ippr_h323_del, ippr_h323_in, ippr_h323_out, NULL }, - { NULL, "h245", (char)IPPROTO_TCP, 0, 0, ippr_h245_init, NULL, - ippr_h245_new, NULL, NULL, ippr_h245_out, NULL }, -#endif - { NULL, "", '\0', 0, 0, NULL, NULL, NULL } + { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, ippr_h323_fini, + ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL }, + { NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL, + ippr_h245_new, NULL, NULL, ippr_h245_out, NULL }, +#endif +#ifdef IPF_RPCB_PROXY +# if 0 + { NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, + ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, + ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, +# endif + { NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, + ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, + ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, +#endif + { NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL } }; - /* * Dynamically add a new kernel proxy. Ensure that it is unique in the * collection compiled in and dynamically added. @@ -149,17 +186,59 @@ aproxy_t *ap; 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))) + sizeof(ap->apr_label))) { + if (ipf_proxy_debug > 1) + printf("appr_add: %s/%d already present (B)\n", + a->apr_label, a->apr_p); return -1; + } - for (a = ap_proxylist; a && a->apr_p; a = a->apr_next) + 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))) + sizeof(ap->apr_label))) { + if (ipf_proxy_debug > 1) + printf("appr_add: %s/%d already present (D)\n", + a->apr_label, a->apr_p); return -1; + } ap->apr_next = ap_proxylist; ap_proxylist = ap; - return (*ap->apr_init)(); + if (ap->apr_init != NULL) + return (*ap->apr_init)(); + return 0; +} + + +/* + * Check to see if the proxy this control request has come through for + * exists, and if it does and it has a control function then invoke that + * control function. + */ +int appr_ctl(ctl) +ap_ctl_t *ctl; +{ + aproxy_t *a; + int error; + + a = appr_lookup(ctl->apc_p, ctl->apc_label); + if (a == NULL) { + if (ipf_proxy_debug > 1) + printf("appr_ctl: can't find %s/%d\n", + ctl->apc_label, ctl->apc_p); + error = ESRCH; + } else if (a->apr_ctl == NULL) { + if (ipf_proxy_debug > 1) + printf("appr_ctl: no ctl function for %s/%d\n", + ctl->apc_label, ctl->apc_p); + error = ENXIO; + } else { + error = (*a->apr_ctl)(a, ctl); + if ((error != 0) && (ipf_proxy_debug > 1)) + printf("appr_ctl: %s/%d ctl error %d\n", + a->apr_label, a->apr_p, error); + } + return error; } @@ -173,14 +252,20 @@ aproxy_t *ap; { aproxy_t *a, **app; - for (app = &ap_proxylist; (a = *app); app = &a->apr_next) + for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) if (a == ap) { a->apr_flags |= APR_DELETE; *app = a->apr_next; - if (ap->apr_ref != 0) + if (ap->apr_ref != 0) { + if (ipf_proxy_debug > 2) + printf("appr_del: orphaning %s/%d\n", + ap->apr_label, ap->apr_p); return 1; + } return 0; } + if (ipf_proxy_debug > 1) + printf("appr_del: proxy %lx not found\n", (u_long)ap); return -1; } @@ -188,8 +273,8 @@ aproxy_t *ap; /* * Return 1 if the packet is a good match against a proxy, else 0. */ -int appr_ok(ip, tcp, nat) -ip_t *ip; +int appr_ok(fin, tcp, nat) +fr_info_t *fin; tcphdr_t *tcp; ipnat_t *nat; { @@ -197,14 +282,62 @@ ipnat_t *nat; u_short dport = nat->in_dport; if ((apr == NULL) || (apr->apr_flags & APR_DELETE) || - (ip->ip_p != apr->apr_p)) + (fin->fin_p != apr->apr_p)) return 0; - if (((tcp != NULL) && (tcp->th_dport != dport)) || (!tcp && dport)) + if ((tcp == NULL) && dport) return 0; return 1; } +int appr_ioctl(data, cmd, mode) +caddr_t data; +ioctlcmd_t cmd; +int mode; +{ + ap_ctl_t ctl; + caddr_t ptr; + int error; + + mode = mode; /* LINT */ + + switch (cmd) + { + case SIOCPROXY : + BCOPYIN(data, &ctl, sizeof(ctl)); + ptr = NULL; + + if (ctl.apc_dsize > 0) { + KMALLOCS(ptr, caddr_t, ctl.apc_dsize); + if (ptr == NULL) + error = ENOMEM; + else { + error = copyinptr(ctl.apc_data, ptr, + ctl.apc_dsize); + if (error == 0) + ctl.apc_data = ptr; + } + } else { + ctl.apc_data = NULL; + error = 0; + } + + if (error == 0) + error = appr_ctl(&ctl); + + if ((ctl.apc_dsize > 0) && (ptr != NULL) && + (ctl.apc_data == ptr)) { + KFREES(ptr, ctl.apc_dsize); + } + break; + + default : + error = EINVAL; + } + return error; +} + + /* * If a proxy has a match function, call that to do extended packet * matching. @@ -215,17 +348,37 @@ nat_t *nat; { aproxy_t *apr; ipnat_t *ipn; + int result; ipn = nat->nat_ptr; - if (ipn == NULL) + if (ipf_proxy_debug > 8) + printf("appr_match(%lx,%lx) aps %lx ptr %lx\n", + (u_long)fin, (u_long)nat, (u_long)nat->nat_aps, + (u_long)ipn); + + if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) { + if (ipf_proxy_debug > 0) + printf("appr_match: flx 0x%x (BAD|SHORT)\n", + fin->fin_flx); return -1; + } + apr = ipn->in_apr; - if ((apr == NULL) || (apr->apr_flags & APR_DELETE) || - (nat->nat_aps == NULL)) + if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) { + if (ipf_proxy_debug > 0) + printf("appr_match:apr %lx apr_flags 0x%x\n", + (u_long)apr, apr ? apr->apr_flags : 0); return -1; - if (apr->apr_match != NULL) - if ((*apr->apr_match)(fin, nat->nat_aps, nat) != 0) + } + + if (apr->apr_match != NULL) { + result = (*apr->apr_match)(fin, nat->nat_aps, nat); + if (result != 0) { + if (ipf_proxy_debug > 4) + printf("appr_match: result %d\n", result); return -1; + } + } return 0; } @@ -235,36 +388,55 @@ nat_t *nat; * relevant details. call the init function once complete, prior to * returning. */ -int appr_new(fin, ip, nat) +int appr_new(fin, nat) fr_info_t *fin; -ip_t *ip; nat_t *nat; { register ap_session_t *aps; aproxy_t *apr; - if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) + if (ipf_proxy_debug > 8) + printf("appr_new(%lx,%lx) \n", (u_long)fin, (u_long)nat); + + if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) { + if (ipf_proxy_debug > 0) + printf("appr_new: nat_ptr %lx nat_aps %lx\n", + (u_long)nat->nat_ptr, (u_long)nat->nat_aps); return -1; + } apr = nat->nat_ptr->in_apr; - if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) + if ((apr->apr_flags & APR_DELETE) || + (fin->fin_p != apr->apr_p)) { + if (ipf_proxy_debug > 2) + printf("appr_new: apr_flags 0x%x p %d/%d\n", + apr->apr_flags, fin->fin_p, apr->apr_p); return -1; + } KMALLOC(aps, ap_session_t *); - if (!aps) + if (!aps) { + if (ipf_proxy_debug > 0) + printf("appr_new: malloc failed (%lu)\n", + (u_long)sizeof(ap_session_t)); return -1; + } + bzero((char *)aps, sizeof(*aps)); - aps->aps_p = ip->ip_p; + aps->aps_p = fin->fin_p; aps->aps_data = NULL; aps->aps_apr = apr; aps->aps_psiz = 0; if (apr->apr_new != NULL) - if ((*apr->apr_new)(fin, ip, aps, nat) == -1) { + if ((*apr->apr_new)(fin, aps, nat) == -1) { if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) { KFREES(aps->aps_data, aps->aps_psiz); } KFREE(aps); + if (ipf_proxy_debug > 2) + printf("appr_new: new(%lx) failed\n", + (u_long)apr->apr_new); return -1; } aps->aps_nat = nat; @@ -277,95 +449,159 @@ nat_t *nat; /* - * check to see if a packet should be passed through an active proxy routine - * if one has been setup for it. + * Check to see if a packet should be passed through an active proxy routine + * if one has been setup for it. We don't need to check the checksum here if + * IPFILTER_CKSUM is defined because if it is, a failed check causes FI_BAD + * to be set. */ -int appr_check(ip, fin, nat) -ip_t *ip; +int appr_check(fin, nat) fr_info_t *fin; nat_t *nat; { #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - mb_t *m = fin->fin_qfm; +# if defined(ICK_VALID) + mb_t *m; +# endif int dosum = 1; #endif tcphdr_t *tcp = NULL; + udphdr_t *udp = NULL; ap_session_t *aps; aproxy_t *apr; - u_32_t sum; + ip_t *ip; short rv; int err; - - aps = nat->nat_aps; - if ((aps != NULL) && (aps->aps_p == ip->ip_p)) { - if (ip->ip_p == IPPROTO_TCP) { - tcp = (tcphdr_t *)fin->fin_dp; - /* - * verify that the checksum is correct. If not, then - * don't do anything with this packet. - */ -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - if (dohwcksum && (m->b_ick_flag == ICK_VALID)) { - sum = tcp->th_sum; - dosum = 0; - } - if (dosum) - sum = fr_tcpsum(fin->fin_qfm, ip, tcp); -#else - sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); +#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) + u_32_t s1, s2, sd; #endif - if (sum != tcp->th_sum) { -#if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL)) - printf("proxy tcp checksum failure\n"); + + if (fin->fin_flx & FI_BAD) { + if (ipf_proxy_debug > 0) + printf("appr_check: flx 0x%x (BAD)\n", fin->fin_flx); + return -1; + } + +#ifndef IPFILTER_CKSUM + if ((fin->fin_out == 0) && (fr_checkl4sum(fin) == -1)) { + if (ipf_proxy_debug > 0) + printf("appr_check: l4 checksum failure %d\n", + fin->fin_p); + if (fin->fin_p == IPPROTO_TCP) + frstats[fin->fin_out].fr_tcpbad++; + return -1; + } #endif - frstats[fin->fin_out].fr_tcpbad++; + + aps = nat->nat_aps; + if ((aps != NULL) && (aps->aps_p == fin->fin_p)) { + /* + * If there is data in this packet to be proxied then try and + * get it all into the one buffer, else drop it. + */ +#if defined(MENTAT) || defined(HAVE_M_PULLDOWN) + if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE)) + if (fr_coalesce(fin) == -1) { + if (ipf_proxy_debug > 0) + printf("appr_check: fr_coalesce failed %x\n", fin->fin_flx); return -1; } +#endif + ip = fin->fin_ip; + switch (fin->fin_p) + { + case IPPROTO_TCP : + tcp = (tcphdr_t *)fin->fin_dp; + +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) + m = fin->fin_qfm; + if (dohwcksum && (m->b_ick_flag == ICK_VALID)) + dosum = 0; +#endif /* * Don't bother the proxy with these...or in fact, * should we free up proxy stuff when seen? */ - if ((tcp->th_flags & TH_RST) != 0) - return 0; + if ((fin->fin_tcpf & TH_RST) != 0) + break; + /*FALLTHROUGH*/ + case IPPROTO_UDP : + udp = (udphdr_t *)fin->fin_dp; + break; + default : + break; } apr = aps->aps_apr; err = 0; if (fin->fin_out != 0) { if (apr->apr_outpkt != NULL) - err = (*apr->apr_outpkt)(fin, ip, aps, nat); + err = (*apr->apr_outpkt)(fin, aps, nat); } else { if (apr->apr_inpkt != NULL) - err = (*apr->apr_inpkt)(fin, ip, aps, nat); + err = (*apr->apr_inpkt)(fin, aps, nat); } rv = APR_EXIT(err); - if (rv == 1) { -#if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL)) - printf("proxy says bad packet received\n"); -#endif + if (((ipf_proxy_debug > 0) && (rv != 0)) || + (ipf_proxy_debug > 8)) + printf("appr_check: out %d err %x rv %d\n", + fin->fin_out, err, rv); + if (rv == 1) return -1; - } + if (rv == 2) { -#if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL)) - printf("proxy says free app proxy data\n"); -#endif appr_free(apr); nat->nat_aps = NULL; return -1; } + /* + * If err != 0 then the data size of the packet has changed + * so we need to recalculate the header checksums for the + * packet. + */ +#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) + if (err != 0) { + short adjlen = err & 0xffff; + + s1 = LONG_SUM(ip->ip_len - adjlen); + s2 = LONG_SUM(ip->ip_len); + CALC_SUMD(s1, s2, sd); + fix_outcksum(fin, &ip->ip_sum, sd); + } +#endif + + /* + * For TCP packets, we may need to adjust the sequence and + * acknowledgement numbers to reflect changes in size of the + * data stream. + * + * For both TCP and UDP, recalculate the layer 4 checksum, + * regardless, as we can't tell (here) if data has been + * changed or not. + */ if (tcp != NULL) { err = appr_fixseqack(fin, ip, aps, APR_INC(err)); #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) if (dosum) - tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); + tcp->th_sum = fr_cksum(fin->fin_qfm, ip, + IPPROTO_TCP, tcp); +#else + tcp->th_sum = fr_cksum(fin->fin_m, ip, + IPPROTO_TCP, tcp); +#endif + } else if ((udp != NULL) && (udp->uh_sum != 0)) { +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + if (dosum) + udp->uh_sum = fr_cksum(fin->fin_qfm, ip, + IPPROTO_UDP, udp); #else - tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); + udp->uh_sum = fr_cksum(fin->fin_m, ip, + IPPROTO_UDP, udp); #endif } - aps->aps_bytes += ip->ip_len; + aps->aps_bytes += fin->fin_plen; aps->aps_pkts++; return 1; } @@ -382,6 +618,9 @@ char *name; { aproxy_t *ap; + if (ipf_proxy_debug > 8) + printf("appr_lookup(%d,%s)\n", pr, name); + for (ap = ap_proxies; ap->apr_p; ap++) if ((ap->apr_p == pr) && !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { @@ -395,6 +634,8 @@ char *name; ap->apr_ref++; return ap; } + if (ipf_proxy_debug > 2) + printf("appr_lookup: failed for %d/%s\n", pr, name); return NULL; } @@ -415,7 +656,7 @@ ap_session_t *aps; if (!aps) return; - for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next) + for (ap = &ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next) if (a == aps) { *ap = a->aps_next; break; @@ -451,7 +692,7 @@ int inc; * ip_len has already been adjusted by 'inc'. */ nlen = ip->ip_len; - nlen -= (ip->ip_hl << 2) + (tcp->th_off << 2); + nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2); inc2 = inc; inc = (int)inc2; @@ -463,10 +704,10 @@ int inc; /* switch to other set ? */ if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && (seq1 > aps->aps_seqmin[!sel])) { -#if PROXY_DEBUG - printf("proxy out switch set seq %d -> %d %x > %x\n", - sel, !sel, seq1, aps->aps_seqmin[!sel]); -#endif + if (ipf_proxy_debug > 7) + printf("proxy out switch set seq %d -> %d %x > %x\n", + sel, !sel, seq1, + aps->aps_seqmin[!sel]); sel = aps->aps_sel[out] = !sel; } @@ -483,11 +724,10 @@ int inc; if (inc && (seq1 > aps->aps_seqmin[!sel])) { aps->aps_seqmin[sel] = seq1 + nlen - 1; aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc; -#if PROXY_DEBUG - printf("proxy seq set %d at %x to %d + %d\n", sel, - aps->aps_seqmin[sel], aps->aps_seqoff[sel], - inc); -#endif + if (ipf_proxy_debug > 7) + printf("proxy seq set %d at %x to %d + %d\n", + sel, aps->aps_seqmin[sel], + aps->aps_seqoff[sel], inc); } /***/ @@ -498,10 +738,10 @@ int inc; /* switch to other set ? */ if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && (seq1 > aps->aps_ackmin[!sel])) { -#if PROXY_DEBUG - printf("proxy out switch set ack %d -> %d %x > %x\n", - sel, !sel, seq1, aps->aps_ackmin[!sel]); -#endif + if (ipf_proxy_debug > 7) + printf("proxy out switch set ack %d -> %d %x > %x\n", + sel, !sel, seq1, + aps->aps_ackmin[!sel]); sel = aps->aps_sel[1 - out] = !sel; } @@ -517,10 +757,9 @@ int inc; /* switch to other set ? */ if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && (seq1 > aps->aps_ackmin[!sel])) { -#if PROXY_DEBUG - printf("proxy in switch set ack %d -> %d %x > %x\n", - sel, !sel, seq1, aps->aps_ackmin[!sel]); -#endif + if (ipf_proxy_debug > 7) + printf("proxy in switch set ack %d -> %d %x > %x\n", + sel, !sel, seq1, aps->aps_ackmin[!sel]); sel = aps->aps_sel[out] = !sel; } @@ -537,11 +776,11 @@ int inc; if (inc && (seq1 > aps->aps_ackmin[!sel])) { aps->aps_ackmin[!sel] = seq1 + nlen - 1; aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; -#if PROXY_DEBUG - printf("proxy ack set %d at %x to %d + %d\n", !sel, - aps->aps_seqmin[!sel], aps->aps_seqoff[sel], - inc); -#endif + + if (ipf_proxy_debug > 7) + printf("proxy ack set %d at %x to %d + %d\n", + !sel, aps->aps_seqmin[!sel], + aps->aps_seqoff[sel], inc); } /***/ @@ -552,19 +791,17 @@ int inc; /* switch to other set ? */ if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && (seq1 > aps->aps_seqmin[!sel])) { -#if PROXY_DEBUG - printf("proxy in switch set seq %d -> %d %x > %x\n", - sel, !sel, seq1, aps->aps_seqmin[!sel]); -#endif + if (ipf_proxy_debug > 7) + printf("proxy in switch set seq %d -> %d %x > %x\n", + sel, !sel, seq1, aps->aps_seqmin[!sel]); sel = aps->aps_sel[1 - out] = !sel; } if (aps->aps_seqoff[sel] != 0) { -#if PROXY_DEBUG - printf("sel %d seqoff %d seq1 %x seqmin %x\n", sel, - aps->aps_seqoff[sel], seq1, - aps->aps_seqmin[sel]); -#endif + if (ipf_proxy_debug > 7) + printf("sel %d seqoff %d seq1 %x seqmin %x\n", + sel, aps->aps_seqoff[sel], seq1, + aps->aps_seqmin[sel]); if (seq1 > aps->aps_seqmin[sel]) { seq2 = aps->aps_seqoff[sel]; tcp->th_ack = htonl(seq1 - seq2); @@ -572,10 +809,10 @@ int inc; } } } -#if PROXY_DEBUG - printf("appr_fixseqack: seq %x ack %x\n", ntohl(tcp->th_seq), - ntohl(tcp->th_ack)); -#endif + + if (ipf_proxy_debug > 8) + printf("appr_fixseqack: seq %x ack %x\n", + ntohl(tcp->th_seq), ntohl(tcp->th_ack)); return ch ? 2 : 0; } @@ -590,9 +827,11 @@ int appr_init() int err = 0; for (ap = ap_proxies; ap->apr_p; ap++) { - err = (*ap->apr_init)(); - if (err != 0) - break; + if (ap->apr_init != NULL) { + err = (*ap->apr_init)(); + if (err != 0) + break; + } } return err; } @@ -607,9 +846,9 @@ void appr_unload() aproxy_t *ap; for (ap = ap_proxies; ap->apr_p; ap++) - if (ap->apr_fini) + if (ap->apr_fini != NULL) (*ap->apr_fini)(); for (ap = ap_proxylist; ap; ap = ap->apr_next) - if (ap->apr_fini) + if (ap->apr_fini != NULL) (*ap->apr_fini)(); } diff --git a/contrib/ipfilter/ip_proxy.h b/contrib/ipfilter/ip_proxy.h index 50b0559..8e53c98 100644 --- a/contrib/ipfilter/ip_proxy.h +++ b/contrib/ipfilter/ip_proxy.h @@ -1,9 +1,11 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1997-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_proxy.h,v 2.8.2.14 2002/09/02 12:19:26 darrenr Exp $ + * Id: ip_proxy.h,v 2.31.2.2 2005/03/12 19:33:48 darrenr Exp */ #ifndef __IP_PROXY_H__ @@ -64,6 +66,26 @@ typedef struct ap_session { #define aps_ackmin aps_un.apu_tcp.apt_ackmin +typedef struct ap_control { + char apc_label[APR_LABELLEN]; + u_char apc_p; + /* + * The following fields are upto the proxy's apr_ctl routine to deal + * with. When the proxy gets this in kernel space, apc_data will + * point to a malloc'd region of memory of apc_dsize bytes. If the + * proxy wants to keep that memory, it must set apc_data to NULL + * before it returns. It is expected if this happens that it will + * take care to free it in apr_fini or otherwise as appropriate. + * apc_cmd is provided as a standard place to put simple commands, + * with apc_arg being available to put a simple arg. + */ + u_long apc_cmd; + u_long apc_arg; + void *apc_data; + size_t apc_dsize; +} ap_ctl_t; + + typedef struct aproxy { struct aproxy *apr_next; char apr_label[APR_LABELLEN]; /* Proxy label # */ @@ -72,34 +94,65 @@ typedef struct aproxy { 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_new) __P((fr_info_t *, ap_session_t *, struct nat *)); void (* apr_del) __P((ap_session_t *)); - int (* apr_inpkt) __P((fr_info_t *, ip_t *, - ap_session_t *, struct nat *)); - int (* apr_outpkt) __P((fr_info_t *, ip_t *, - ap_session_t *, struct nat *)); + int (* apr_inpkt) __P((fr_info_t *, ap_session_t *, struct nat *)); + int (* apr_outpkt) __P((fr_info_t *, ap_session_t *, struct nat *)); int (* apr_match) __P((fr_info_t *, ap_session_t *, struct nat *)); + int (* apr_ctl) __P((struct aproxy *, struct ap_control *)); } aproxy_t; #define APR_DELETE 1 -#define APR_ERR(x) (((x) & 0xffff) << 16) +#define APR_ERR(x) ((x) << 16) #define APR_EXIT(x) (((x) >> 16) & 0xffff) #define APR_INC(x) ((x) & 0xffff) -#define FTP_BUFSZ 160 /* - * For the ftp proxy. + * Generic #define's to cover missing things in the kernel */ +#ifndef isdigit +#define isdigit(x) ((x) >= '0' && (x) <= '9') +#endif +#ifndef isupper +#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z')) +#endif +#ifndef islower +#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) +#endif +#ifndef isalpha +#define isalpha(x) (isupper(x) || islower(x)) +#endif +#ifndef toupper +#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') +#endif +#ifndef isspace +#define isspace(x) (((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \ + ((x) == '\t') || ((x) == '\b')) +#endif + +/* + * This is the scratch buffer size used to hold strings from the TCP stream + * that we may want to parse. It's an arbitrary size, really, but it must + * be at least as large as IPF_FTPBUFSZ. + */ +#define FTP_BUFSZ 120 + +/* + * This buffer, however, doesn't need to be nearly so big. It just needs to + * be able to squeeze in the largest command it needs to rewrite, Which ones + * does it rewrite? EPRT, PORT, 227 replies. + */ +#define IPF_FTPBUFSZ 80 /* This *MUST* be >= 53! */ + typedef struct ftpside { char *ftps_rptr; char *ftps_wptr; + void *ftps_ifp; u_32_t ftps_seq[2]; u_32_t ftps_len; - int ftps_junk; + int ftps_junk; /* 2 = no cr/lf yet, 1 = cannot parse */ int ftps_cmds; - int ftps_cmd; char ftps_buf[FTP_BUFSZ]; } ftpside_t; @@ -109,6 +162,22 @@ typedef struct ftpinfo { ftpside_t ftp_side[2]; } ftpinfo_t; + +/* + * For the irc proxy. + */ +typedef struct ircinfo { + size_t irc_len; + char *irc_snick; + char *irc_dnick; + char *irc_type; + char *irc_arg; + char *irc_addr; + u_32_t irc_ipnum; + u_short irc_port; +} ircinfo_t; + + /* * Real audio proxy structure and #defines */ @@ -140,6 +209,19 @@ typedef struct raudio_s { #define RAP_M_TCP 4 #define RAP_M_UDP_ROBUST (RAP_M_UDP|RAP_M_ROBUST) + +/* + * MSN RPC proxy + */ +typedef struct msnrpcinfo { + u_int mri_flags; + int mri_cmd[2]; + u_int mri_valid; + struct in_addr mri_raddr; + u_short mri_rport; +} msnrpcinfo_t; + + /* * IPSec proxy */ @@ -154,21 +236,218 @@ typedef struct ipsec_pxy { ipstate_t *ipsc_state; } ipsec_pxy_t; +/* + * PPTP proxy + */ +typedef struct pptp_side { + u_32_t pptps_nexthdr; + u_32_t pptps_next; + int pptps_state; + int pptps_gothdr; + int pptps_len; + int pptps_bytes; + char *pptps_wptr; + char pptps_buffer[512]; +} pptp_side_t; + +typedef struct pptp_pxy { + ipnat_t pptp_rule; + nat_t *pptp_nat; + ipstate_t *pptp_state; + u_short pptp_call[2]; + pptp_side_t pptp_side[2]; +} pptp_pxy_t; + + +/* + * Sun RPCBIND proxy + */ +#define RPCB_MAXMSG 888 +#define RPCB_RES_PMAP 0 /* Response contains a v2 port. */ +#define RPCB_RES_STRING 1 /* " " " v3 (GETADDR) string. */ +#define RPCB_RES_LIST 2 /* " " " v4 (GETADDRLIST) list. */ +#define RPCB_MAXREQS 32 /* Arbitrary limit on tracked transactions */ + +#define RPCB_REQMIN 40 +#define RPCB_REQMAX 888 +#define RPCB_REPMIN 20 +#define RPCB_REPMAX 604 /* XXX double check this! */ + +/* + * These macros determine the number of bytes between p and the end of + * r->rs_buf relative to l. + */ +#define RPCB_BUF_END(r) (char *)((r)->rm_msgbuf + (r)->rm_buflen) +#define RPCB_BUF_GEQ(r, p, l) \ + ((RPCB_BUF_END((r)) > (char *)(p)) && \ + ((RPCB_BUF_END((r)) - (char *)(p)) >= (l))) +#define RPCB_BUF_EQ(r, p, l) \ + (RPCB_BUF_END((r)) == ((char *)(p) + (l))) + +/* + * The following correspond to RPC(B) detailed in RFC183[13]. + */ +#define RPCB_CALL 0 +#define RPCB_REPLY 1 +#define RPCB_MSG_VERSION 2 +#define RPCB_PROG 100000 +#define RPCB_GETPORT 3 +#define RPCB_GETADDR 3 +#define RPCB_GETADDRLIST 11 +#define RPCB_MSG_ACCEPTED 0 +#define RPCB_MSG_DENIED 1 + +/* BEGIN (Generic XDR structures) */ +typedef struct xdr_string { + u_32_t *xs_len; + char *xs_str; +} xdr_string_t; + +typedef struct xdr_auth { + /* u_32_t xa_flavor; */ + xdr_string_t xa_string; +} xdr_auth_t; + +typedef struct xdr_uaddr { + u_32_t xu_ip; + u_short xu_port; + xdr_string_t xu_str; +} xdr_uaddr_t; + +typedef struct xdr_proto { + u_int xp_proto; + xdr_string_t xp_str; +} xdr_proto_t; + +#define xu_xslen xu_str.xs_len +#define xu_xsstr xu_str.xs_str +#define xp_xslen xp_str.xs_len +#define xp_xsstr xp_str.xs_str +/* END (Generic XDR structures) */ + +/* BEGIN (RPC call structures) */ +typedef struct pmap_args { + /* u_32_t pa_prog; */ + /* u_32_t pa_vers; */ + u_32_t *pa_prot; + /* u_32_t pa_port; */ +} pmap_args_t; + +typedef struct rpcb_args { + /* u_32_t *ra_prog; */ + /* u_32_t *ra_vers; */ + xdr_proto_t ra_netid; + xdr_uaddr_t ra_maddr; + /* xdr_string_t ra_owner; */ +} rpcb_args_t; + +typedef struct rpc_call { + /* u_32_t rc_rpcvers; */ + /* u_32_t rc_prog; */ + u_32_t *rc_vers; + u_32_t *rc_proc; + xdr_auth_t rc_authcred; + xdr_auth_t rc_authverf; + union { + pmap_args_t ra_pmapargs; + rpcb_args_t ra_rpcbargs; + } rpcb_args; +} rpc_call_t; + +#define rc_pmapargs rpcb_args.ra_pmapargs +#define rc_rpcbargs rpcb_args.ra_rpcbargs +/* END (RPC call structures) */ + +/* BEGIN (RPC reply structures) */ +typedef struct rpcb_entry { + xdr_uaddr_t re_maddr; + xdr_proto_t re_netid; + /* u_32_t re_semantics; */ + xdr_string_t re_family; + xdr_proto_t re_proto; + u_32_t *re_more; /* 1 == another entry follows */ +} rpcb_entry_t; + +typedef struct rpcb_listp { + u_32_t *rl_list; /* 1 == list follows */ + int rl_cnt; + rpcb_entry_t rl_entries[2]; /* TCP / UDP only */ +} rpcb_listp_t; + +typedef struct rpc_resp { + /* u_32_t rr_acceptdeny; */ + /* Omitted 'message denied' fork; we don't care about rejects. */ + xdr_auth_t rr_authverf; + /* u_32_t *rr_astat; */ + union { + u_32_t *resp_pmap; + xdr_uaddr_t resp_getaddr; + rpcb_listp_t resp_getaddrlist; + } rpcb_reply; +} rpc_resp_t; + +#define rr_v2 rpcb_reply.resp_pmap +#define rr_v3 rpcb_reply.resp_getaddr +#define rr_v4 rpcb_reply.resp_getaddrlist +/* END (RPC reply structures) */ + +/* BEGIN (RPC message structure & macros) */ +typedef struct rpc_msg { + char rm_msgbuf[RPCB_MAXMSG]; /* RPCB data buffer */ + u_int rm_buflen; + u_32_t *rm_xid; + /* u_32_t Call vs Reply */ + union { + rpc_call_t rb_call; + rpc_resp_t rb_resp; + } rm_body; +} rpc_msg_t; + +#define rm_call rm_body.rb_call +#define rm_resp rm_body.rb_resp +/* END (RPC message structure & macros) */ + +/* + * These code paths aren't hot enough to warrant per transaction + * mutexes. + */ +typedef struct rpcb_xact { + struct rpcb_xact *rx_next; + struct rpcb_xact **rx_pnext; + u_32_t rx_xid; /* RPC transmission ID */ + u_int rx_type; /* RPCB response type */ + u_int rx_ref; /* reference count */ + u_int rx_proto; /* transport protocol (v2 only) */ +} rpcb_xact_t; + +typedef struct rpcb_session { + ipfmutex_t rs_rxlock; + rpcb_xact_t *rs_rxlist; +} rpcb_session_t; + +/* + * For an explanation, please see the following: + * RFC1832 - Sections 3.11, 4.4, and 4.5. + */ +#define XDRALIGN(x) ((((x) % 4) != 0) ? ((((x) + 3) / 4) * 4) : (x)) + 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_ctl __P((ap_ctl_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 int appr_ok __P((fr_info_t *, tcphdr_t *, struct ipnat *)); extern int appr_match __P((fr_info_t *, struct nat *)); extern void appr_free __P((aproxy_t *)); extern void aps_free __P((ap_session_t *)); -extern int appr_check __P((ip_t *, fr_info_t *, struct nat *)); +extern int appr_check __P((fr_info_t *, struct nat *)); extern aproxy_t *appr_lookup __P((u_int, char *)); -extern int appr_new __P((fr_info_t *, ip_t *, struct nat *)); +extern int appr_new __P((fr_info_t *, struct nat *)); +extern int appr_ioctl __P((caddr_t, ioctlcmd_t, int)); #endif /* __IP_PROXY_H__ */ diff --git a/contrib/ipfilter/ip_raudio_pxy.c b/contrib/ipfilter/ip_raudio_pxy.c index 12d3981..260fcd4 100644 --- a/contrib/ipfilter/ip_raudio_pxy.c +++ b/contrib/ipfilter/ip_raudio_pxy.c @@ -1,20 +1,26 @@ +/* $NetBSD$ */ + /* - * $Id: ip_raudio_pxy.c,v 1.7.2.9 2003/04/26 05:59:39 darrenr Exp $ + * Copyright (C) 1998-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ip_raudio_pxy.c,v 1.40.2.3 2005/02/04 10:22:55 darrenr Exp */ -#if SOLARIS && defined(_KERNEL) -extern kmutex_t ipf_rw; -#endif #define IPF_RAUDIO_PROXY int ippr_raudio_init __P((void)); -int ippr_raudio_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_raudio_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_raudio_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_raudio_fini __P((void)); +int ippr_raudio_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_raudio_in __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_raudio_out __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t raudiofr; +int raudio_proxy_init = 0; + /* * Real Audio application proxy initialization. @@ -24,26 +30,39 @@ int ippr_raudio_init() bzero((char *)&raudiofr, sizeof(raudiofr)); raudiofr.fr_ref = 1; raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&raudiofr.fr_lock, "Real Audio proxy rule lock"); + raudio_proxy_init = 1; + return 0; } +void ippr_raudio_fini() +{ + if (raudio_proxy_init == 1) { + MUTEX_DESTROY(&raudiofr.fr_lock); + raudio_proxy_init = 0; + } +} + + /* * Setup for a new proxy to handle Real Audio. */ -int ippr_raudio_new(fin, ip, aps, nat) +int ippr_raudio_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { raudio_t *rap; - KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); if (aps->aps_data == NULL) return -1; + fin = fin; /* LINT */ + nat = nat; /* LINT */ + bzero(aps->aps_data, sizeof(raudio_t)); rap = aps->aps_data; aps->aps_psiz = sizeof(raudio_t); @@ -53,20 +72,21 @@ nat_t *nat; -int ippr_raudio_out(fin, ip, aps, nat) +int ippr_raudio_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { raudio_t *rap = aps->aps_data; unsigned char membuf[512 + 1], *s; u_short id = 0; - int off, dlen; tcphdr_t *tcp; + int off, dlen; int len = 0; mb_t *m; + nat = nat; /* LINT */ + /* * If we've already processed the start messages, then nothing left * for the proxy to do. @@ -74,26 +94,24 @@ nat_t *nat; if (rap->rap_eos == 1) return 0; + m = fin->fin_m; tcp = (tcphdr_t *)fin->fin_dp; - off = fin->fin_hlen + (tcp->th_off << 2); - bzero(membuf, sizeof(membuf)); -#if SOLARIS - m = fin->fin_qfm; + off = (char *)tcp - (char *)fin->fin_ip; + off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff; - dlen = msgdsize(m) - off; - if (dlen <= 0) - return 0; - dlen = MIN(sizeof(membuf), dlen); - copyout_mblk(m, off, dlen, (char *)membuf); +#ifdef __sgi + dlen = fin->fin_plen - off; #else - m = *(mb_t **)fin->fin_mp; - - dlen = mbufchainlen(m) - off; + dlen = MSGDSIZE(m) - off; +#endif if (dlen <= 0) return 0; - dlen = MIN(sizeof(membuf), dlen); - m_copydata(m, off, dlen, (char *)membuf); -#endif + + if (dlen > sizeof(membuf)) + dlen = sizeof(membuf); + + bzero((char *)membuf, sizeof(membuf)); + COPYDATA(m, off, dlen, (char *)membuf); /* * In all the startup parsing, ensure that we don't go outside * the packet buffer boundary. @@ -160,23 +178,23 @@ nat_t *nat; } -int ippr_raudio_in(fin, ip, aps, nat) +int ippr_raudio_in(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { unsigned char membuf[IPF_MAXPORTLEN + 1], *s; tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; - int off, dlen, slen, clen; struct in_addr swa, swb; + int off, dlen, slen; int a1, a2, a3, a4; u_short sp, dp; fr_info_t fi; tcp_seq seq; - nat_t *ipn; + nat_t *nat2; u_char swp; + ip_t *ip; mb_t *m; /* @@ -187,27 +205,24 @@ nat_t *nat; if (rap->rap_sdone != 0) return 0; + m = fin->fin_m; tcp = (tcphdr_t *)fin->fin_dp; - off = fin->fin_hlen + (tcp->th_off << 2); - m = *(mb_t **)fin->fin_mp; - -#if SOLARIS - m = fin->fin_qfm; + off = (char *)tcp - (char *)fin->fin_ip; + off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff; - dlen = msgdsize(m) - off; - if (dlen <= 0) - return 0; - bzero(membuf, sizeof(membuf)); - clen = MIN(sizeof(membuf), dlen); - copyout_mblk(m, off, clen, (char *)membuf); +#ifdef __sgi + dlen = fin->fin_plen - off; #else - dlen = mbufchainlen(m) - off; + dlen = MSGDSIZE(m) - off; +#endif if (dlen <= 0) return 0; - bzero(membuf, sizeof(membuf)); - clen = MIN(sizeof(membuf), dlen); - m_copydata(m, off, clen, (char *)membuf); -#endif + + if (dlen > sizeof(membuf)) + dlen = sizeof(membuf); + + bzero((char *)membuf, sizeof(membuf)); + COPYDATA(m, off, dlen, (char *)membuf); seq = ntohl(tcp->th_seq); /* @@ -215,7 +230,7 @@ nat_t *nat; * We only care for the first 19 bytes coming back from the server. */ if (rap->rap_sseq == 0) { - s = (u_char *)memstr("PNA", (char *)membuf, 3, clen); + s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); if (s == NULL) return 0; a1 = s - membuf; @@ -250,6 +265,7 @@ nat_t *nat; rap->rap_srport = (*s << 8) | *(s + 1); } + ip = fin->fin_ip; swp = ip->ip_p; swa = ip->ip_src; swb = ip->ip_dst; @@ -260,10 +276,14 @@ nat_t *nat; bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); - tcp2->th_off = 5; + TCP_OFF_A(tcp2, 5); + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_flx |= FI_IGNORE; fi.fin_dp = (char *)tcp2; fi.fin_fr = &raudiofr; fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); tcp2->th_win = htons(8192); slen = ip->ip_len; ip->ip_len = fin->fin_hlen + sizeof(*tcp); @@ -277,13 +297,16 @@ nat_t *nat; fi.fin_data[0] = dp; fi.fin_data[1] = sp; fi.fin_out = 0; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, - IPN_UDP | (sp ? 0 : FI_W_SPORT), NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_IGNOREPKT|FI_NORULE| - (sp ? 0 : FI_W_SPORT)); + nat2 = nat_new(&fi, nat->nat_ptr, NULL, + NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT), + NAT_OUTBOUND); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_UDP); + nat_update(&fi, nat2, nat2->nat_ptr); + + (void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT)); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); } } @@ -294,12 +317,16 @@ nat_t *nat; fi.fin_data[0] = sp; fi.fin_data[1] = 0; fi.fin_out = 1; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_UDP|FI_W_DPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_W_DPORT|FI_IGNOREPKT|FI_NORULE); + nat2 = nat_new(&fi, nat->nat_ptr, NULL, + NAT_SLAVE|IPN_UDP|SI_W_DPORT, + NAT_OUTBOUND); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_UDP); + nat_update(&fi, nat2, nat2->nat_ptr); + + (void) fr_addstate(&fi, NULL, SI_W_DPORT); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); } } diff --git a/contrib/ipfilter/ip_rcmd_pxy.c b/contrib/ipfilter/ip_rcmd_pxy.c index 93cd32b..b7904c8 100644 --- a/contrib/ipfilter/ip_rcmd_pxy.c +++ b/contrib/ipfilter/ip_rcmd_pxy.c @@ -1,27 +1,31 @@ +/* $NetBSD$ */ + /* - * $Id: ip_rcmd_pxy.c,v 1.4.2.7 2003/04/26 05:59:39 darrenr Exp $ - */ -/* + * Copyright (C) 1998-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ip_rcmd_pxy.c,v 1.41.2.4 2005/02/04 10:22:55 darrenr Exp + * * Simple RCMD transparent proxy for in-kernel use. For use with the NAT * code. */ -#if SOLARIS && defined(_KERNEL) -extern kmutex_t ipf_rw; -#endif - -#define isdigit(x) ((x) >= '0' && (x) <= '9') #define IPF_RCMD_PROXY int ippr_rcmd_init __P((void)); -int ippr_rcmd_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_rcmd_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_rcmd_fini __P((void)); +int ippr_rcmd_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_in __P((fr_info_t *, ap_session_t *, nat_t *)); u_short ipf_rcmd_atoi __P((char *)); -int ippr_rcmd_portmsg __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t rcmdfr; +int rcmd_proxy_init = 0; + /* * RCMD application proxy initialization. @@ -31,25 +35,43 @@ int ippr_rcmd_init() bzero((char *)&rcmdfr, sizeof(rcmdfr)); rcmdfr.fr_ref = 1; rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock"); + rcmd_proxy_init = 1; + return 0; } +void ippr_rcmd_fini() +{ + if (rcmd_proxy_init == 1) { + MUTEX_DESTROY(&rcmdfr.fr_lock); + rcmd_proxy_init = 0; + } +} + + /* * Setup for a new RCMD proxy. */ -int ippr_rcmd_new(fin, ip, aps, nat) +int ippr_rcmd_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_psiz = sizeof(u_32_t); KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t)); - if (aps->aps_data == NULL) + if (aps->aps_data == NULL) { +#ifdef IP_RCMD_PROXY_DEBUG + printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t)); +#endif return -1; + } *(u_32_t *)aps->aps_data = 0; aps->aps_sport = tcp->th_sport; aps->aps_dport = tcp->th_dport; @@ -66,7 +88,7 @@ char *ptr; register char *s = ptr, c; register u_short i = 0; - while ((c = *s++) && isdigit(c)) { + while (((c = *s++) != '\0') && ISDIGIT(c)) { i *= 10; i += c - '0'; } @@ -74,19 +96,19 @@ char *ptr; } -int ippr_rcmd_portmsg(fin, ip, aps, nat) +int ippr_rcmd_portmsg(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { - char portbuf[8], *s; - struct in_addr swip; - int off, dlen; tcphdr_t *tcp, tcph, *tcp2 = &tcph; + struct in_addr swip, swip2; + int off, dlen, nflags; + char portbuf[8], *s; fr_info_t fi; u_short sp; - nat_t *ipn; + nat_t *nat2; + ip_t *ip; mb_t *m; tcp = (tcphdr_t *)fin->fin_dp; @@ -100,37 +122,47 @@ nat_t *nat; (tcp->th_seq != *(u_32_t *)aps->aps_data)) return 0; - off = fin->fin_hlen + (tcp->th_off << 2); + m = fin->fin_m; + ip = fin->fin_ip; + off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; -#if SOLARIS - m = fin->fin_qfm; - - dlen = msgdsize(m) - off; - bzero(portbuf, sizeof(portbuf)); - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); +#ifdef __sgi + dlen = fin->fin_plen - off; #else - m = *(mb_t **)fin->fin_mp; - dlen = mbufchainlen(m) - off; - bzero(portbuf, sizeof(portbuf)); - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); + dlen = MSGDSIZE(m) - off; #endif + if (dlen <= 0) + return 0; + + bzero(portbuf, sizeof(portbuf)); + COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf); portbuf[sizeof(portbuf) - 1] = '\0'; s = portbuf; sp = ipf_rcmd_atoi(s); - if (!sp) + if (sp == 0) { +#ifdef IP_RCMD_PROXY_DEBUG + printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n", + dlen, portbuf); +#endif return 0; + } /* * Add skeleton NAT entry for connection which will come back the * other way. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_flx |= FI_IGNORE; fi.fin_data[0] = sp; - fi.fin_data[1] = fin->fin_data[1]; - ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, 0); - if (ipn == NULL) { + fi.fin_data[1] = 0; + if (nat->nat_dir == NAT_OUTBOUND) + nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + else + nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + if (nat2 == NULL) { int slen; slen = ip->ip_len; @@ -139,33 +171,66 @@ nat_t *nat; tcp2->th_win = htons(8192); tcp2->th_sport = htons(sp); tcp2->th_dport = 0; /* XXX - don't specify remote port */ - tcp2->th_off = 5; + TCP_OFF_A(tcp2, 5); tcp2->th_flags = TH_SYN; - fi.fin_data[1] = 0; fi.fin_dp = (char *)tcp2; + fi.fin_fr = &rcmdfr; fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); + fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; + nflags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; + swip = ip->ip_src; - ip->ip_src = nat->nat_inip; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - fi.fin_fr = &rcmdfr; - (void) fr_addstate(ip, &fi, NULL, - FI_W_DPORT|FI_IGNOREPKT); + swip2 = ip->ip_dst; + + if (nat->nat_dir == NAT_OUTBOUND) { + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; + ip->ip_src = nat->nat_inip; + } else { + fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; + ip->ip_src = nat->nat_oip; + nflags |= NAT_NOTRULEPORT; + } + + nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); + + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_TCP); + nat_update(&fi, nat2, nat2->nat_ptr); + fi.fin_ifp = NULL; + if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; + ip->ip_dst = nat->nat_inip; + } + (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); } ip->ip_len = slen; ip->ip_src = swip; + ip->ip_dst = swip2; } return 0; } -int ippr_rcmd_out(fin, ip, aps, nat) +int ippr_rcmd_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { - return ippr_rcmd_portmsg(fin, ip, aps, nat); + if (nat->nat_dir == NAT_OUTBOUND) + return ippr_rcmd_portmsg(fin, aps, nat); + return 0; +} + + +int ippr_rcmd_in(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + if (nat->nat_dir == NAT_INBOUND) + return ippr_rcmd_portmsg(fin, aps, nat); + return 0; } diff --git a/contrib/ipfilter/ip_rpcb_pxy.c b/contrib/ipfilter/ip_rpcb_pxy.c new file mode 100644 index 0000000..5d0a1ee --- /dev/null +++ b/contrib/ipfilter/ip_rpcb_pxy.c @@ -0,0 +1,1460 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002-2003 by Ryan Beasley <ryanb@goddamnbastard.org> + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * Overview: + * This is an in-kernel application proxy for Sun's RPCBIND (nee portmap) + * protocol as defined in RFC1833. It is far from complete, mostly + * lacking in less-likely corner cases, but it's definitely functional. + * + * Invocation: + * rdr <int> <e_ip>/32 port <e_p> -> <i_ip> port <i_p> udp proxy rpcbu + * + * If the host running IP Filter is the same as the RPC server, it's + * perfectly legal for both the internal and external addresses and ports + * to match. + * + * When triggered by appropriate IP NAT rules, this proxy works by + * examining data contained in received packets. Requests and replies are + * modified, NAT and state table entries created, etc., as necessary. + */ +/* + * TODO / NOTES + * + * o Must implement locking to protect proxy session data. + * o Fragmentation isn't supported. + * o Only supports UDP. + * o Doesn't support multiple RPC records in a single request. + * o Errors should be more fine-grained. (e.g., malloc failure vs. + * illegal RPCB request / reply) + * o Even with the limit on the total amount of recorded transactions, + * should there be a timeout on transaction removal? + * o There is a potential collision between cloning, wildcard NAT and + * state entries. There should be an appr_getport routine for + * to avoid this. + * o The enclosed hack of STREAMS support is pretty sick and most likely + * broken. + * + * Id: ip_rpcb_pxy.c,v 2.25.2.3 2005/02/04 10:22:56 darrenr Exp + */ + +#define IPF_RPCB_PROXY + +/* + * Function prototypes + */ +int ippr_rpcb_init __P((void)); +void ippr_rpcb_fini __P((void)); +int ippr_rpcb_new __P((fr_info_t *, ap_session_t *, nat_t *)); +void ippr_rpcb_del __P((ap_session_t *)); +int ippr_rpcb_in __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_rpcb_out __P((fr_info_t *, ap_session_t *, nat_t *)); + +static void ippr_rpcb_flush __P((rpcb_session_t *)); +static int ippr_rpcb_decodereq __P((fr_info_t *, nat_t *, + rpcb_session_t *, rpc_msg_t *)); +static int ippr_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **)); +static int ippr_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *)); +static int ippr_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *)); +static int ippr_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *, + u_32_t **)); +static u_int ippr_rpcb_atoi __P((char *)); +static int ippr_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *, + mb_t *, u_int)); +static int ippr_rpcb_decoderep __P((fr_info_t *, nat_t *, + rpcb_session_t *, rpc_msg_t *, rpcb_xact_t **)); +static rpcb_xact_t * ippr_rpcb_lookup __P((rpcb_session_t *, u_32_t)); +static void ippr_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *)); +static int ippr_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *, + u_32_t **)); +static int ippr_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int)); +static int ippr_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *, + mb_t *, u_int)); +static int ippr_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *, + mb_t *, u_int)); +static void ippr_rpcb_fixlen __P((fr_info_t *, int)); + +/* + * Global variables + */ +static frentry_t rpcbfr; /* Skeleton rule for reference by entities + this proxy creates. */ +static int rpcbcnt; /* Upper bound of allocated RPCB sessions. */ + /* XXX rpcbcnt still requires locking. */ + +int rpcb_proxy_init = 0; + + +/* + * Since rpc_msg contains only pointers, one should use this macro as a + * handy way to get to the goods. (In case you're wondering about the name, + * this started as BYTEREF -> BREF -> B.) + */ +#define B(r) (u_32_t)ntohl(*(r)) + +/* + * Public subroutines + */ + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_init */ +/* Returns: int - 0 == success */ +/* Parameters: (void) */ +/* */ +/* Initialize the filter rule entry and session limiter. */ +/* -------------------------------------------------------------------- */ +int +ippr_rpcb_init() +{ + rpcbcnt = 0; + + bzero((char *)&rpcbfr, sizeof(rpcbfr)); + rpcbfr.fr_ref = 1; + rpcbfr.fr_flags = FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&rpcbfr.fr_lock, "ipf Sun RPCB proxy rule lock"); + rpcb_proxy_init = 1; + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_fini */ +/* Returns: void */ +/* Parameters: (void) */ +/* */ +/* Destroy rpcbfr's mutex to avoid a lock leak. */ +/* -------------------------------------------------------------------- */ +void +ippr_rpcb_fini() +{ + if (rpcb_proxy_init == 1) { + MUTEX_DESTROY(&rpcbfr.fr_lock); + rpcb_proxy_init = 0; + } +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_new */ +/* Returns: int - -1 == failure, 0 == success */ +/* Parameters: fin(I) - pointer to packet information */ +/* aps(I) - pointer to proxy session structure */ +/* nat(I) - pointer to NAT session structure */ +/* */ +/* Allocate resources for per-session proxy structures. */ +/* -------------------------------------------------------------------- */ +int +ippr_rpcb_new(fin, aps, nat) + fr_info_t *fin; + ap_session_t *aps; + nat_t *nat; +{ + rpcb_session_t *rs; + + fin = fin; /* LINT */ + nat = nat; /* LINT */ + + KMALLOC(rs, rpcb_session_t *); + if (rs == NULL) + return(-1); + + bzero((char *)rs, sizeof(*rs)); + MUTEX_INIT(&rs->rs_rxlock, "ipf Sun RPCB proxy session lock"); + + aps->aps_data = rs; + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_del */ +/* Returns: void */ +/* Parameters: aps(I) - pointer to proxy session structure */ +/* */ +/* Free up a session's list of RPCB requests. */ +/* -------------------------------------------------------------------- */ +void +ippr_rpcb_del(aps) + ap_session_t *aps; +{ + rpcb_session_t *rs; + rs = (rpcb_session_t *)aps->aps_data; + + MUTEX_ENTER(&rs->rs_rxlock); + ippr_rpcb_flush(rs); + MUTEX_EXIT(&rs->rs_rxlock); + MUTEX_DESTROY(&rs->rs_rxlock); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_in */ +/* Returns: int - APR_ERR(1) == drop the packet, */ +/* APR_ERR(2) == kill the proxy session, */ +/* else change in packet length (in bytes) */ +/* Parameters: fin(I) - pointer to packet information */ +/* ip(I) - pointer to packet header */ +/* aps(I) - pointer to proxy session structure */ +/* nat(I) - pointer to NAT session structure */ +/* */ +/* Given a presumed RPCB request, perform some minor tests and pass off */ +/* for decoding. Also pass packet off for a rewrite if necessary. */ +/* -------------------------------------------------------------------- */ +int +ippr_rpcb_in(fin, aps, nat) + fr_info_t *fin; + ap_session_t *aps; + nat_t *nat; +{ + rpc_msg_t rpcmsg, *rm; + rpcb_session_t *rs; + u_int off, dlen; + mb_t *m; + int rv; + + /* Disallow fragmented or illegally short packets. */ + if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) + return(APR_ERR(1)); + + /* Perform basic variable initialization. */ + rs = (rpcb_session_t *)aps->aps_data; + + m = fin->fin_m; + off = (char *)fin->fin_dp - (char *)fin->fin_ip; + off += sizeof(udphdr_t) + fin->fin_ipoff; + dlen = fin->fin_dlen - sizeof(udphdr_t); + + /* Disallow packets outside legal range for supported requests. */ + if ((dlen < RPCB_REQMIN) || (dlen > RPCB_REQMAX)) + return(APR_ERR(1)); + + /* Copy packet over to convenience buffer. */ + rm = &rpcmsg; + bzero((char *)rm, sizeof(*rm)); + COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); + rm->rm_buflen = dlen; + + /* Send off to decode request. */ + rv = ippr_rpcb_decodereq(fin, nat, rs, rm); + + switch(rv) + { + case -1: + return(APR_ERR(1)); + /*NOTREACHED*/ + break; + case 0: + break; + case 1: + rv = ippr_rpcb_modreq(fin, nat, rm, m, off); + break; + default: + /*CONSTANTCONDITION*/ + IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_req)", rv)); + } + + return(rv); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_out */ +/* Returns: int - APR_ERR(1) == drop the packet, */ +/* APR_ERR(2) == kill the proxy session, */ +/* else change in packet length (in bytes) */ +/* Parameters: fin(I) - pointer to packet information */ +/* ip(I) - pointer to packet header */ +/* aps(I) - pointer to proxy session structure */ +/* nat(I) - pointer to NAT session structure */ +/* */ +/* Given a presumed RPCB reply, perform some minor tests and pass off */ +/* for decoding. If the message indicates a successful request with */ +/* valid addressing information, create NAT and state structures to */ +/* allow direct communication between RPC client and server. */ +/* -------------------------------------------------------------------- */ +int +ippr_rpcb_out(fin, aps, nat) + fr_info_t *fin; + ap_session_t *aps; + nat_t *nat; +{ + rpc_msg_t rpcmsg, *rm; + rpcb_session_t *rs; + rpcb_xact_t *rx; + u_int off, dlen; + int rv, diff; + mb_t *m; + + /* Disallow fragmented or illegally short packets. */ + if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) + return(APR_ERR(1)); + + /* Perform basic variable initialization. */ + rs = (rpcb_session_t *)aps->aps_data; + + m = fin->fin_m; + off = (char *)fin->fin_dp - (char *)fin->fin_ip; + off += sizeof(udphdr_t) + fin->fin_ipoff; + dlen = fin->fin_dlen - sizeof(udphdr_t); + diff = 0; + + /* Disallow packets outside legal range for supported requests. */ + if ((dlen < RPCB_REPMIN) || (dlen > RPCB_REPMAX)) + return(APR_ERR(1)); + + /* Copy packet over to convenience buffer. */ + rm = &rpcmsg; + bzero((char *)rm, sizeof(*rm)); + COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); + rm->rm_buflen = dlen; + + /* Send off to decode reply. */ + rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx); + + switch(rv) + { + case -1: /* Bad packet */ + if (rx != NULL) { + MUTEX_ENTER(&rs->rs_rxlock); + ippr_rpcb_deref(rs, rx); + MUTEX_EXIT(&rs->rs_rxlock); + } + return(APR_ERR(1)); + /*NOTREACHED*/ + break; + case 0: /* Negative reply / request rejected */ + break; + case 1: /* Positive reply */ + /* + * With the IP address embedded in a GETADDR(LIST) reply, + * we'll need to rewrite the packet in the very possible + * event that the internal & external addresses aren't the + * same. (i.e., this box is either a router or rpcbind + * only listens on loopback.) + */ + if (nat->nat_inip.s_addr != nat->nat_outip.s_addr) { + if (rx->rx_type == RPCB_RES_STRING) + diff = ippr_rpcb_modv3(fin, nat, rm, m, off); + else if (rx->rx_type == RPCB_RES_LIST) + diff = ippr_rpcb_modv4(fin, nat, rm, m, off); + } + break; + default: + /*CONSTANTCONDITION*/ + IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_decoderep)", rv)); + } + + if (rx != NULL) { + MUTEX_ENTER(&rs->rs_rxlock); + /* XXX Gross hack - I'm overloading the reference + * counter to deal with both threads and retransmitted + * requests. One deref signals that this thread is + * finished with rx, and the other signals that we've + * processed its reply. + */ + ippr_rpcb_deref(rs, rx); + ippr_rpcb_deref(rs, rx); + MUTEX_EXIT(&rs->rs_rxlock); + } + + return(diff); +} + +/* + * Private support subroutines + */ + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_flush */ +/* Returns: void */ +/* Parameters: rs(I) - pointer to RPCB session structure */ +/* */ +/* Simply flushes the list of outstanding transactions, if any. */ +/* -------------------------------------------------------------------- */ +static void +ippr_rpcb_flush(rs) + rpcb_session_t *rs; +{ + rpcb_xact_t *r1, *r2; + + r1 = rs->rs_rxlist; + if (r1 == NULL) + return; + + while (r1 != NULL) { + r2 = r1; + r1 = r1->rx_next; + KFREE(r2); + } +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_decodereq */ +/* Returns: int - -1 == bad request or critical failure, */ +/* 0 == request successfully decoded, */ +/* 1 == request successfully decoded; requires */ +/* address rewrite/modification */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT session structure */ +/* rs(I) - pointer to RPCB session structure */ +/* rm(I) - pointer to RPC message structure */ +/* */ +/* Take a presumed RPCB request, decode it, and store the results in */ +/* the transaction list. If the internal target address needs to be */ +/* modified, store its location in ptr. */ +/* WARNING: It's the responsibility of the caller to make sure there */ +/* is enough room in rs_buf for the basic RPC message "preamble". */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_decodereq(fin, nat, rs, rm) + fr_info_t *fin; + nat_t *nat; + rpcb_session_t *rs; + rpc_msg_t *rm; +{ + rpcb_args_t *ra; + u_32_t xdr, *p; + rpc_call_t *rc; + rpcb_xact_t rx; + int mod; + + p = (u_32_t *)rm->rm_msgbuf; + mod = 0; + + bzero((char *)&rx, sizeof(rx)); + rc = &rm->rm_call; + + rm->rm_xid = p; + rx.rx_xid = B(p++); /* Record this message's XID. */ + + /* Parse out and test the RPC header. */ + if ((B(p++) != RPCB_CALL) || + (B(p++) != RPCB_MSG_VERSION) || + (B(p++) != RPCB_PROG)) + return(-1); + + /* Record the RPCB version and procedure. */ + rc->rc_vers = p++; + rc->rc_proc = p++; + + /* Bypass RPC authentication stuff. */ + if (ippr_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0) + return(-1); + if (ippr_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0) + return(-1); + + /* Compare RPCB version and procedure numbers. */ + switch(B(rc->rc_vers)) + { + case 2: + /* This proxy only supports PMAP_GETPORT. */ + if (B(rc->rc_proc) != RPCB_GETPORT) + return(-1); + + /* Portmap requests contain four 4 byte parameters. */ + if (RPCB_BUF_EQ(rm, p, 16) == 0) + return(-1); + + p += 2; /* Skip requested program and version numbers. */ + + /* Sanity check the requested protocol. */ + xdr = B(p); + if (!(xdr == IPPROTO_UDP || xdr == IPPROTO_TCP)) + return(-1); + + rx.rx_type = RPCB_RES_PMAP; + rx.rx_proto = xdr; + break; + case 3: + case 4: + /* GETADDRLIST is exclusive to v4; GETADDR for v3 & v4 */ + switch(B(rc->rc_proc)) + { + case RPCB_GETADDR: + rx.rx_type = RPCB_RES_STRING; + rx.rx_proto = (u_int)fin->fin_p; + break; + case RPCB_GETADDRLIST: + if (B(rc->rc_vers) != 4) + return(-1); + rx.rx_type = RPCB_RES_LIST; + break; + default: + return(-1); + } + + ra = &rc->rc_rpcbargs; + + /* Decode the 'struct rpcb' request. */ + if (ippr_rpcb_xdrrpcb(rm, p, ra) != 0) + return(-1); + + /* Are the target address & port valid? */ + if ((ra->ra_maddr.xu_ip != nat->nat_outip.s_addr) || + (ra->ra_maddr.xu_port != nat->nat_outport)) + return(-1); + + /* Do we need to rewrite this packet? */ + if ((nat->nat_outip.s_addr != nat->nat_inip.s_addr) || + (nat->nat_outport != nat->nat_inport)) + mod = 1; + break; + default: + return(-1); + } + + MUTEX_ENTER(&rs->rs_rxlock); + if (ippr_rpcb_insert(rs, &rx) != 0) { + MUTEX_EXIT(&rs->rs_rxlock); + return(-1); + } + MUTEX_EXIT(&rs->rs_rxlock); + + return(mod); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_skipauth */ +/* Returns: int -- -1 == illegal auth parameters (lengths) */ +/* 0 == valid parameters, pointer advanced */ +/* Parameters: rm(I) - pointer to RPC message structure */ +/* auth(I) - pointer to RPC auth structure */ +/* buf(IO) - pointer to location within convenience buffer */ +/* */ +/* Record auth data length & location of auth data, then advance past */ +/* it. */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_skipauth(rm, auth, buf) + rpc_msg_t *rm; + xdr_auth_t *auth; + u_32_t **buf; +{ + u_32_t *p, xdr; + + p = *buf; + + /* Make sure we have enough space for expected fixed auth parms. */ + if (RPCB_BUF_GEQ(rm, p, 8) == 0) + return(-1); + + p++; /* We don't care about auth_flavor. */ + + auth->xa_string.xs_len = p; + xdr = B(p++); /* Length of auth_data */ + + /* Test for absurdity / illegality of auth_data length. */ + if ((XDRALIGN(xdr) < xdr) || (RPCB_BUF_GEQ(rm, p, XDRALIGN(xdr)) == 0)) + return(-1); + + auth->xa_string.xs_str = (char *)p; + + p += XDRALIGN(xdr); /* Advance our location. */ + + *buf = (u_32_t *)p; + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_insert */ +/* Returns: int -- -1 == list insertion failed, */ +/* 0 == item successfully added */ +/* Parameters: rs(I) - pointer to RPCB session structure */ +/* rx(I) - pointer to RPCB transaction structure */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_insert(rs, rx) + rpcb_session_t *rs; + rpcb_xact_t *rx; +{ + rpcb_xact_t *rxp; + + rxp = ippr_rpcb_lookup(rs, rx->rx_xid); + if (rxp != NULL) { + ++rxp->rx_ref; + return(0); + } + + if (rpcbcnt == RPCB_MAXREQS) + return(-1); + + KMALLOC(rxp, rpcb_xact_t *); + if (rxp == NULL) + return(-1); + + bcopy((char *)rx, (char *)rxp, sizeof(*rx)); + + if (rs->rs_rxlist != NULL) + rs->rs_rxlist->rx_pnext = &rxp->rx_next; + + rxp->rx_pnext = &rs->rs_rxlist; + rxp->rx_next = rs->rs_rxlist; + rs->rs_rxlist = rxp; + + rxp->rx_ref = 1; + + ++rpcbcnt; + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_xdrrpcb */ +/* Returns: int -- -1 == failure to properly decode the request */ +/* 0 == rpcb successfully decoded */ +/* Parameters: rs(I) - pointer to RPCB session structure */ +/* p(I) - pointer to location within session buffer */ +/* rpcb(O) - pointer to rpcb (xdr type) structure */ +/* */ +/* Decode a XDR encoded rpcb structure and record its contents in rpcb */ +/* within only the context of TCP/UDP over IP networks. */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_xdrrpcb(rm, p, ra) + rpc_msg_t *rm; + u_32_t *p; + rpcb_args_t *ra; +{ + if (!RPCB_BUF_GEQ(rm, p, 20)) + return(-1); + + /* Bypass target program & version. */ + p += 2; + + /* Decode r_netid. Must be "tcp" or "udp". */ + if (ippr_rpcb_getproto(rm, &ra->ra_netid, &p) != 0) + return(-1); + + /* Decode r_maddr. */ + if (ippr_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0) + return(-1); + + /* Advance to r_owner and make sure it's empty. */ + if (!RPCB_BUF_EQ(rm, p, 4) || (B(p) != 0)) + return(-1); + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_getuaddr */ +/* Returns: int -- -1 == illegal string, */ +/* 0 == string parsed; contents recorded */ +/* Parameters: rm(I) - pointer to RPC message structure */ +/* xu(I) - pointer to universal address structure */ +/* p(IO) - pointer to location within message buffer */ +/* */ +/* Decode the IP address / port at p and record them in xu. */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_getuaddr(rm, xu, p) + rpc_msg_t *rm; + xdr_uaddr_t *xu; + u_32_t **p; +{ + char *c, *i, *b, *pp; + u_int d, dd, l, t; + char uastr[24]; + + /* Test for string length. */ + if (!RPCB_BUF_GEQ(rm, *p, 4)) + return(-1); + + xu->xu_xslen = (*p)++; + xu->xu_xsstr = (char *)*p; + + /* Length check */ + l = B(xu->xu_xslen); + if (l < 11 || l > 23 || !RPCB_BUF_GEQ(rm, *p, XDRALIGN(l))) + return(-1); + + /* Advance p */ + *(char **)p += XDRALIGN(l); + + /* Copy string to local buffer & terminate C style */ + bcopy(xu->xu_xsstr, uastr, l); + uastr[l] = '\0'; + + i = (char *)&xu->xu_ip; + pp = (char *)&xu->xu_port; + + /* + * Expected format: a.b.c.d.e.f where [a-d] correspond to bytes of + * an IP address and [ef] are the bytes of a L4 port. + */ + if (!(ISDIGIT(uastr[0]) && ISDIGIT(uastr[l-1]))) + return(-1); + b = uastr; + for (c = &uastr[1], d = 0, dd = 0; c < &uastr[l-1]; c++) { + if (ISDIGIT(*c)) { + dd = 0; + continue; + } + if (*c == '.') { + if (dd != 0) + return(-1); + + /* Check for ASCII byte. */ + *c = '\0'; + t = ippr_rpcb_atoi(b); + if (t > 255) + return(-1); + + /* Aim b at beginning of the next byte. */ + b = c + 1; + + /* Switch off IP addr vs port parsing. */ + if (d < 4) + i[d++] = t & 0xff; + else + pp[d++ - 4] = t & 0xff; + + dd = 1; + continue; + } + return(-1); + } + if (d != 5) /* String must contain exactly 5 periods. */ + return(-1); + + /* Handle the last byte (port low byte) */ + t = ippr_rpcb_atoi(b); + if (t > 255) + return(-1); + pp[d - 4] = t & 0xff; + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_atoi (XXX should be generic for all proxies) */ +/* Returns: int -- integer representation of supplied string */ +/* Parameters: ptr(I) - input string */ +/* */ +/* Simple version of atoi(3) ripped from ip_rcmd_pxy.c. */ +/* -------------------------------------------------------------------- */ +static u_int +ippr_rpcb_atoi(ptr) + char *ptr; +{ + register char *s = ptr, c; + register u_int i = 0; + + while (((c = *s++) != '\0') && ISDIGIT(c)) { + i *= 10; + i += c - '0'; + } + return i; +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_modreq */ +/* Returns: int -- change in datagram length */ +/* APR_ERR(2) - critical failure */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT session */ +/* rm(I) - pointer to RPC message structure */ +/* m(I) - pointer to mbuf chain */ +/* off(I) - current offset within mbuf chain */ +/* */ +/* When external and internal addresses differ, we rewrite the former */ +/* with the latter. (This is exclusive to protocol versions 3 & 4). */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_modreq(fin, nat, rm, m, off) + fr_info_t *fin; + nat_t *nat; + rpc_msg_t *rm; + mb_t *m; + u_int off; +{ + u_int len, xlen, pos, bogo; + rpcb_args_t *ra; + char uaddr[24]; + udphdr_t *udp; + char *i, *p; + int diff; + + ra = &rm->rm_call.rc_rpcbargs; + i = (char *)&nat->nat_inip.s_addr; + p = (char *)&nat->nat_inport; + + /* Form new string. */ + bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(uaddr, sizeof(uaddr), +#else + (void) sprintf(uaddr, +#endif + "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, + i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); + len = strlen(uaddr); + xlen = XDRALIGN(len); + + /* Determine mbuf offset to start writing to. */ + pos = (char *)ra->ra_maddr.xu_xslen - rm->rm_msgbuf; + off += pos; + + /* Write new string length. */ + bogo = htonl(len); + COPYBACK(m, off, 4, (caddr_t)&bogo); + off += 4; + + /* Write new string. */ + COPYBACK(m, off, xlen, uaddr); + off += xlen; + + /* Write in zero r_owner. */ + bogo = 0; + COPYBACK(m, off, 4, (caddr_t)&bogo); + + /* Determine difference in data lengths. */ + diff = xlen - XDRALIGN(B(ra->ra_maddr.xu_xslen)); + + /* + * If our new string has a different length, make necessary + * adjustments. + */ + if (diff != 0) { + udp = fin->fin_dp; + udp->uh_ulen = htons(ntohs(udp->uh_ulen) + diff); + fin->fin_ip->ip_len += diff; + fin->fin_dlen += diff; + fin->fin_plen += diff; + /* XXX Storage lengths. */ + } + + return(diff); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_decoderep */ +/* Returns: int - -1 == bad request or critical failure, */ +/* 0 == valid, negative reply */ +/* 1 == vaddlid, positive reply; needs no changes */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT session structure */ +/* rs(I) - pointer to RPCB session structure */ +/* rm(I) - pointer to RPC message structure */ +/* rxp(O) - pointer to RPCB transaction structure */ +/* */ +/* Take a presumed RPCB reply, extract the XID, search for the original */ +/* request information, and determine whether the request was accepted */ +/* or rejected. With a valid accepted reply, go ahead and create NAT */ +/* and state entries, and finish up by rewriting the packet as */ +/* required. */ +/* */ +/* WARNING: It's the responsibility of the caller to make sure there */ +/* is enough room in rs_buf for the basic RPC message "preamble". */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_decoderep(fin, nat, rs, rm, rxp) + fr_info_t *fin; + nat_t *nat; + rpcb_session_t *rs; + rpc_msg_t *rm; + rpcb_xact_t **rxp; +{ + rpcb_listp_t *rl; + rpcb_entry_t *re; + rpcb_xact_t *rx; + u_32_t xdr, *p; + rpc_resp_t *rr; + int rv, cnt; + + p = (u_32_t *)rm->rm_msgbuf; + + bzero((char *)&rx, sizeof(rx)); + rr = &rm->rm_resp; + + rm->rm_xid = p; + xdr = B(p++); /* Record this message's XID. */ + + /* Lookup XID */ + MUTEX_ENTER(&rs->rs_rxlock); + if ((rx = ippr_rpcb_lookup(rs, xdr)) == NULL) { + MUTEX_EXIT(&rs->rs_rxlock); + return(-1); + } + ++rx->rx_ref; /* per thread reference */ + MUTEX_EXIT(&rs->rs_rxlock); + + *rxp = rx; + + /* Test call vs reply */ + if (B(p++) != RPCB_REPLY) + return(-1); + + /* Test reply_stat */ + switch(B(p++)) + { + case RPCB_MSG_DENIED: + return(0); + case RPCB_MSG_ACCEPTED: + break; + default: + return(-1); + } + + /* Bypass RPC authentication stuff. */ + if (ippr_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0) + return(-1); + + /* Test accept status */ + if (!RPCB_BUF_GEQ(rm, p, 4)) + return(-1); + if (B(p++) != 0) + return(0); + + /* Parse out the expected reply */ + switch(rx->rx_type) + { + case RPCB_RES_PMAP: + /* There must be only one 4 byte argument. */ + if (!RPCB_BUF_EQ(rm, p, 4)) + return(-1); + + rr->rr_v2 = p; + xdr = B(rr->rr_v2); + + /* Reply w/ a 0 port indicates service isn't registered */ + if (xdr == 0) + return(0); + + /* Is the value sane? */ + if (xdr > 65535) + return(-1); + + /* Create NAT & state table entries. */ + if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0) + return(-1); + break; + case RPCB_RES_STRING: + /* Expecting a XDR string; need 4 bytes for length */ + if (!RPCB_BUF_GEQ(rm, p, 4)) + return(-1); + + rr->rr_v3.xu_str.xs_len = p++; + rr->rr_v3.xu_str.xs_str = (char *)p; + + xdr = B(rr->rr_v3.xu_xslen); + + /* A null string indicates an unregistered service */ + if ((xdr == 0) && RPCB_BUF_EQ(rm, p, 0)) + return(0); + + /* Decode the target IP address / port. */ + if (ippr_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0) + return(-1); + + /* Validate the IP address and port contained. */ + if (nat->nat_inip.s_addr != rr->rr_v3.xu_ip) + return(-1); + + /* Create NAT & state table entries. */ + if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, + (u_int)rr->rr_v3.xu_port) != 0) + return(-1); + break; + case RPCB_RES_LIST: + if (!RPCB_BUF_GEQ(rm, p, 4)) + return(-1); + /* rpcb_entry_list_ptr */ + switch(B(p)) + { + case 0: + return(0); + /*NOTREACHED*/ + break; + case 1: + break; + default: + return(-1); + } + rl = &rr->rr_v4; + rl->rl_list = p++; + cnt = 0; + + for(;;) { + re = &rl->rl_entries[rl->rl_cnt]; + if (ippr_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0) + return(-1); + if (ippr_rpcb_getproto(rm, &re->re_netid, &p) != 0) + return(-1); + /* re_semantics & re_pfamily length */ + if (!RPCB_BUF_GEQ(rm, p, 12)) + return(-1); + p++; /* Skipping re_semantics. */ + xdr = B(p++); + if ((xdr != 4) || strncmp((char *)p, "inet", 4)) + return(-1); + p++; + if (ippr_rpcb_getproto(rm, &re->re_proto, &p) != 0) + return(-1); + if (!RPCB_BUF_GEQ(rm, p, 4)) + return(-1); + re->re_more = p; + if (B(re->re_more) > 1) /* 0,1 only legal values */ + return(-1); + ++rl->rl_cnt; + ++cnt; + if (B(re->re_more) == 0) + break; + /* Replies in max out at 2; TCP and/or UDP */ + if (cnt > 2) + return(-1); + p++; + } + + for(rl->rl_cnt = 0; rl->rl_cnt < cnt; rl->rl_cnt++) { + re = &rl->rl_entries[rl->rl_cnt]; + rv = ippr_rpcb_getnat(fin, nat, + re->re_proto.xp_proto, + (u_int)re->re_maddr.xu_port); + if (rv != 0) + return(-1); + } + break; + default: + /*CONSTANTCONDITION*/ + IPF_PANIC(1, ("illegal rx_type %d", rx->rx_type)); + } + + return(1); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_lookup */ +/* Returns: rpcb_xact_t * - NULL == no matching record, */ +/* else pointer to relevant entry */ +/* Parameters: rs(I) - pointer to RPCB session */ +/* xid(I) - XID to look for */ +/* -------------------------------------------------------------------- */ +static rpcb_xact_t * +ippr_rpcb_lookup(rs, xid) + rpcb_session_t *rs; + u_32_t xid; +{ + rpcb_xact_t *rx; + + if (rs->rs_rxlist == NULL) + return(NULL); + + for (rx = rs->rs_rxlist; rx != NULL; rx = rx->rx_next) + if (rx->rx_xid == xid) + break; + + return(rx); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_deref */ +/* Returns: (void) */ +/* Parameters: rs(I) - pointer to RPCB session */ +/* rx(I) - pointer to RPC transaction struct to remove */ +/* force(I) - indicates to delete entry regardless of */ +/* reference count */ +/* Locking: rs->rs_rxlock must be held write only */ +/* */ +/* Free the RPCB transaction record rx from the chain of entries. */ +/* -------------------------------------------------------------------- */ +static void +ippr_rpcb_deref(rs, rx) + rpcb_session_t *rs; + rpcb_xact_t *rx; +{ + rs = rs; /* LINT */ + + if (rx == NULL) + return; + + if (--rx->rx_ref != 0) + return; + + if (rx->rx_next != NULL) + rx->rx_next->rx_pnext = rx->rx_pnext; + + *rx->rx_pnext = rx->rx_next; + + KFREE(rx); + + --rpcbcnt; +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_getproto */ +/* Returns: int - -1 == illegal protocol/netid, */ +/* 0 == legal protocol/netid */ +/* Parameters: rm(I) - pointer to RPC message structure */ +/* xp(I) - pointer to netid structure */ +/* p(IO) - pointer to location within packet buffer */ +/* */ +/* Decode netid/proto stored at p and record its numeric value. */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_getproto(rm, xp, p) + rpc_msg_t *rm; + xdr_proto_t *xp; + u_32_t **p; +{ + u_int len; + + /* Must have 4 bytes for length & 4 bytes for "tcp" or "udp". */ + if (!RPCB_BUF_GEQ(rm, p, 8)) + return(-1); + + xp->xp_xslen = (*p)++; + xp->xp_xsstr = (char *)*p; + + /* Test the string length. */ + len = B(xp->xp_xslen); + if (len != 3) + return(-1); + + /* Test the actual string & record the protocol accordingly. */ + if (!strncmp((char *)xp->xp_xsstr, "tcp\0", 4)) + xp->xp_proto = IPPROTO_TCP; + else if (!strncmp((char *)xp->xp_xsstr, "udp\0", 4)) + xp->xp_proto = IPPROTO_UDP; + else { + return(-1); + } + + /* Advance past the string. */ + (*p)++; + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_getnat */ +/* Returns: int -- -1 == failed to create table entries, */ +/* 0 == success */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT table entry */ +/* proto(I) - transport protocol for new entries */ +/* port(I) - new port to use w/ wildcard table entries */ +/* */ +/* Create state and NAT entries to handle an anticipated connection */ +/* attempt between RPC client and server. */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_getnat(fin, nat, proto, port) + fr_info_t *fin; + nat_t *nat; + u_int proto; + u_int port; +{ + ipnat_t *ipn, ipnat; + tcphdr_t tcp; + ipstate_t *is; + fr_info_t fi; + nat_t *natl; + int nflags; + + ipn = nat->nat_ptr; + + /* Generate dummy fr_info */ + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_out = 0; + fi.fin_src = fin->fin_dst; + fi.fin_dst = nat->nat_outip; + fi.fin_p = proto; + fi.fin_sport = 0; + fi.fin_dport = port & 0xffff; + fi.fin_flx |= FI_IGNORE; + + bzero((char *)&tcp, sizeof(tcp)); + tcp.th_dport = htons(port); + + if (proto == IPPROTO_TCP) { + tcp.th_win = htons(8192); + TCP_OFF_A(&tcp, sizeof(tcphdr_t) >> 2); + fi.fin_dlen = sizeof(tcphdr_t); + tcp.th_flags = TH_SYN; + nflags = NAT_TCP; + } else { + fi.fin_dlen = sizeof(udphdr_t); + nflags = NAT_UDP; + } + + nflags |= SI_W_SPORT|NAT_SEARCH; + fi.fin_dp = &tcp; + fi.fin_plen = fi.fin_hlen + fi.fin_dlen; + + /* + * Search for existing NAT & state entries. Pay close attention to + * mutexes / locks grabbed from lookup routines, as not doing so could + * lead to bad things. + * + * If successful, fr_stlookup returns with ipf_state locked. We have + * no use for this lock, so simply unlock it if necessary. + */ + is = fr_stlookup(&fi, &tcp, NULL); + if (is != NULL) + RWLOCK_EXIT(&ipf_state); + + RWLOCK_EXIT(&ipf_nat); + + WRITE_ENTER(&ipf_nat); + natl = nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst); + + if ((natl != NULL) && (is != NULL)) { + MUTEX_DOWNGRADE(&ipf_nat); + return(0); + } + + /* Slightly modify the following structures for actual use in creating + * NAT and/or state entries. We're primarily concerned with stripping + * flags that may be detrimental to the creation process or simply + * shouldn't be associated with a table entry. + */ + fi.fin_fr = &rpcbfr; + fi.fin_flx &= ~FI_IGNORE; + nflags &= ~NAT_SEARCH; + + if (natl == NULL) { + /* XXX Since we're just copying the original ipn contents + * back, would we be better off just sending a pointer to + * the 'temp' copy off to nat_new instead? + */ + /* Generate template/bogus NAT rule. */ + bcopy((char *)ipn, (char *)&ipnat, sizeof(ipnat)); + ipn->in_flags = nflags & IPN_TCPUDP; + ipn->in_apr = NULL; + ipn->in_p = proto; + ipn->in_pmin = htons(fi.fin_dport); + ipn->in_pmax = htons(fi.fin_dport); + ipn->in_pnext = htons(fi.fin_dport); + ipn->in_space = 1; + ipn->in_ippip = 1; + if (ipn->in_flags & IPN_FILTER) { + ipn->in_scmp = 0; + ipn->in_dcmp = 0; + } + *ipn->in_plabel = '\0'; + + /* Create NAT entry. return NULL if this fails. */ + natl = nat_new(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE, + NAT_INBOUND); + + bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat)); + + if (natl == NULL) { + MUTEX_DOWNGRADE(&ipf_nat); + return(-1); + } + + ipn->in_use++; + (void) nat_proto(&fi, natl, nflags); + nat_update(&fi, natl, natl->nat_ptr); + } + MUTEX_DOWNGRADE(&ipf_nat); + + if (is == NULL) { + /* Create state entry. Return NULL if this fails. */ + fi.fin_dst = nat->nat_inip; + fi.fin_nat = (void *)natl; + fi.fin_flx |= FI_NATED; + fi.fin_flx &= ~FI_STATE; + nflags &= NAT_TCPUDP; + nflags |= SI_W_SPORT|SI_CLONE; + + is = fr_addstate(&fi, NULL, nflags); + if (is == NULL) { + /* + * XXX nat_delete is private to ip_nat.c. Should + * check w/ Darren about this one. + * + * nat_delete(natl, NL_EXPIRE); + */ + return(-1); + } + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + } + + return(0); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_modv3 */ +/* Returns: int -- change in packet length */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT session */ +/* rm(I) - pointer to RPC message structure */ +/* m(I) - pointer to mbuf chain */ +/* off(I) - offset within mbuf chain */ +/* */ +/* Write a new universal address string to this packet, adjusting */ +/* lengths as necessary. */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_modv3(fin, nat, rm, m, off) + fr_info_t *fin; + nat_t *nat; + rpc_msg_t *rm; + mb_t *m; + u_int off; +{ + u_int len, xlen, pos, bogo; + rpc_resp_t *rr; + char uaddr[24]; + char *i, *p; + int diff; + + rr = &rm->rm_resp; + i = (char *)&nat->nat_outip.s_addr; + p = (char *)&rr->rr_v3.xu_port; + + /* Form new string. */ + bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(uaddr, sizeof(uaddr), +#else + (void) sprintf(uaddr, +#endif + "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, + i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); + len = strlen(uaddr); + xlen = XDRALIGN(len); + + /* Determine mbuf offset to write to. */ + pos = (char *)rr->rr_v3.xu_xslen - rm->rm_msgbuf; + off += pos; + + /* Write new string length. */ + bogo = htonl(len); + COPYBACK(m, off, 4, (caddr_t)&bogo); + off += 4; + + /* Write new string. */ + COPYBACK(m, off, xlen, uaddr); + + /* Determine difference in data lengths. */ + diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen)); + + /* + * If our new string has a different length, make necessary + * adjustments. + */ + if (diff != 0) + ippr_rpcb_fixlen(fin, diff); + + return(diff); +} + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_modv4 */ +/* Returns: int -- change in packet length */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT session */ +/* rm(I) - pointer to RPC message structure */ +/* m(I) - pointer to mbuf chain */ +/* off(I) - offset within mbuf chain */ +/* */ +/* Write new rpcb_entry list, adjusting lengths as necessary. */ +/* -------------------------------------------------------------------- */ +static int +ippr_rpcb_modv4(fin, nat, rm, m, off) + fr_info_t *fin; + nat_t *nat; + rpc_msg_t *rm; + mb_t *m; + u_int off; +{ + u_int len, xlen, pos, bogo; + rpcb_listp_t *rl; + rpcb_entry_t *re; + rpc_resp_t *rr; + char uaddr[24]; + int diff, cnt; + char *i, *p; + + diff = 0; + rr = &rm->rm_resp; + rl = &rr->rr_v4; + + i = (char *)&nat->nat_outip.s_addr; + + /* Determine mbuf offset to write to. */ + re = &rl->rl_entries[0]; + pos = (char *)re->re_maddr.xu_xslen - rm->rm_msgbuf; + off += pos; + + for (cnt = 0; cnt < rl->rl_cnt; cnt++) { + re = &rl->rl_entries[cnt]; + p = (char *)&re->re_maddr.xu_port; + + /* Form new string. */ + bzero(uaddr, sizeof(uaddr)); /* Just in case we need + padding. */ +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(uaddr, sizeof(uaddr), +#else + (void) sprintf(uaddr, +#endif + "%u.%u.%u.%u.%u.%u", i[0] & 0xff, + i[1] & 0xff, i[2] & 0xff, i[3] & 0xff, + p[0] & 0xff, p[1] & 0xff); + len = strlen(uaddr); + xlen = XDRALIGN(len); + + /* Write new string length. */ + bogo = htonl(len); + COPYBACK(m, off, 4, (caddr_t)&bogo); + off += 4; + + /* Write new string. */ + COPYBACK(m, off, xlen, uaddr); + off += xlen; + + /* Record any change in length. */ + diff += xlen - XDRALIGN(B(re->re_maddr.xu_xslen)); + + /* If the length changed, copy back the rest of this entry. */ + len = ((char *)re->re_more + 4) - + (char *)re->re_netid.xp_xslen; + if (diff != 0) { + COPYBACK(m, off, len, (caddr_t)re->re_netid.xp_xslen); + } + off += len; + } + + /* + * If our new string has a different length, make necessary + * adjustments. + */ + if (diff != 0) + ippr_rpcb_fixlen(fin, diff); + + return(diff); +} + + +/* -------------------------------------------------------------------- */ +/* Function: ippr_rpcb_fixlen */ +/* Returns: (void) */ +/* Parameters: fin(I) - pointer to packet information */ +/* len(I) - change in packet length */ +/* */ +/* Adjust various packet related lengths held in structure and packet */ +/* header fields. */ +/* -------------------------------------------------------------------- */ +static void +ippr_rpcb_fixlen(fin, len) + fr_info_t *fin; + int len; +{ + udphdr_t *udp; + + udp = fin->fin_dp; + udp->uh_ulen = htons(ntohs(udp->uh_ulen) + len); + fin->fin_ip->ip_len += len; + fin->fin_dlen += len; + fin->fin_plen += len; +} + +#undef B diff --git a/contrib/ipfilter/ip_scan.c b/contrib/ipfilter/ip_scan.c new file mode 100644 index 0000000..37f6d58 --- /dev/null +++ b/contrib/ipfilter/ip_scan.c @@ -0,0 +1,594 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1995-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#include <sys/param.h> +#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL) +# include <sys/kern_svcs.h> +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/errno.h> +#if !defined(_KERNEL) +# include <stdlib.h> +# include <string.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL +#else +# include <sys/systm.h> +# if !defined(__svr4__) && !defined(__SVR4) +# include <sys/mbuf.h> +# endif +#endif +#include <sys/socket.h> +#if !defined(__hpux) && !defined(__osf__) && !defined(linux) +# include <sys/ioccom.h> +#endif +#ifdef __FreeBSD__ +# include <sys/filio.h> +# include <sys/malloc.h> +#else +# include <sys/ioctl.h> +#endif + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#include <net/if.h> + + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_state.h" +#include "netinet/ip_scan.h" +/* END OF INCLUDES */ + +#if !defined(lint) +static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ip_scan.c,v 2.40.2.2 2005/01/18 10:13:16 darrenr Exp"; +#endif + +#ifdef IPFILTER_SCAN /* endif at bottom of file */ + + +ipscan_t *ipsc_list = NULL, + *ipsc_tail = NULL; +ipscanstat_t ipsc_stat; +# ifdef USE_MUTEXES +ipfrwlock_t ipsc_rwlock; +# endif + +# ifndef isalpha +# define isalpha(x) (((x) >= 'A' && 'Z' >= (x)) || \ + ((x) >= 'a' && 'z' >= (x))) +# endif + + +int ipsc_add __P((caddr_t)); +int ipsc_delete __P((caddr_t)); +struct ipscan *ipsc_lookup __P((char *)); +int ipsc_matchstr __P((sinfo_t *, char *, int)); +int ipsc_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *)); +int ipsc_match __P((ipstate_t *)); + + + +int ipsc_init() +{ + RWLOCK_INIT(&ipsc_rwlock, "ip scan rwlock"); + return 0; +} + + +void fr_scanunload() +{ + RW_DESTROY(&ipsc_rwlock); +} + + +int ipsc_add(data) +caddr_t data; +{ + ipscan_t *i, *isc; + int err; + + KMALLOC(isc, ipscan_t *); + if (!isc) + return ENOMEM; + + err = copyinptr(data, isc, sizeof(*isc)); + if (err) + return err; + + WRITE_ENTER(&ipsc_rwlock); + + i = ipsc_lookup(isc->ipsc_tag); + if (i) { + RWLOCK_EXIT(&ipsc_rwlock); + KFREE(isc); + return EEXIST; + } + + if (ipsc_tail) { + ipsc_tail->ipsc_next = isc; + isc->ipsc_pnext = &ipsc_tail->ipsc_next; + ipsc_tail = isc; + } else { + ipsc_list = isc; + ipsc_tail = isc; + isc->ipsc_pnext = &ipsc_list; + } + isc->ipsc_next = NULL; + + isc->ipsc_hits = 0; + isc->ipsc_fref = 0; + isc->ipsc_sref = 0; + isc->ipsc_active = 0; + + ipsc_stat.iscs_entries++; + RWLOCK_EXIT(&ipsc_rwlock); + return 0; +} + + +int ipsc_delete(data) +caddr_t data; +{ + ipscan_t isc, *i; + int err; + + err = copyinptr(data, &isc, sizeof(isc)); + if (err) + return err; + + WRITE_ENTER(&ipsc_rwlock); + + i = ipsc_lookup(isc.ipsc_tag); + if (i == NULL) + err = ENOENT; + else { + if (i->ipsc_fref) { + RWLOCK_EXIT(&ipsc_rwlock); + return EBUSY; + } + + *i->ipsc_pnext = i->ipsc_next; + if (i->ipsc_next) + i->ipsc_next->ipsc_pnext = i->ipsc_pnext; + else { + if (i->ipsc_pnext == &ipsc_list) + ipsc_tail = NULL; + else + ipsc_tail = *(*i->ipsc_pnext)->ipsc_pnext; + } + + ipsc_stat.iscs_entries--; + KFREE(i); + } + RWLOCK_EXIT(&ipsc_rwlock); + return err; +} + + +struct ipscan *ipsc_lookup(tag) +char *tag; +{ + ipscan_t *i; + + for (i = ipsc_list; i; i = i->ipsc_next) + if (!strcmp(i->ipsc_tag, tag)) + return i; + return NULL; +} + + +int ipsc_attachfr(fr) +struct frentry *fr; +{ + ipscan_t *i; + + if (fr->fr_isctag[0]) { + READ_ENTER(&ipsc_rwlock); + i = ipsc_lookup(fr->fr_isctag); + if (i != NULL) { + ATOMIC_INC32(i->ipsc_fref); + } + RWLOCK_EXIT(&ipsc_rwlock); + if (i == NULL) + return ENOENT; + fr->fr_isc = i; + } + return 0; +} + + +int ipsc_attachis(is) +struct ipstate *is; +{ + frentry_t *fr; + ipscan_t *i; + + READ_ENTER(&ipsc_rwlock); + fr = is->is_rule; + if (fr) { + i = fr->fr_isc; + if (!i || (i != (ipscan_t *)-1)) { + is->is_isc = i; + if (i) { + ATOMIC_INC32(i->ipsc_sref); + if (i->ipsc_clen) + is->is_flags |= IS_SC_CLIENT; + else + is->is_flags |= IS_SC_MATCHC; + if (i->ipsc_slen) + is->is_flags |= IS_SC_SERVER; + else + is->is_flags |= IS_SC_MATCHS; + } else + is->is_flags |= (IS_SC_CLIENT|IS_SC_SERVER); + } + } + RWLOCK_EXIT(&ipsc_rwlock); + return 0; +} + + +int ipsc_detachfr(fr) +struct frentry *fr; +{ + ipscan_t *i; + + i = fr->fr_isc; + if (i != NULL) { + ATOMIC_DEC32(i->ipsc_fref); + } + return 0; +} + + +int ipsc_detachis(is) +struct ipstate *is; +{ + ipscan_t *i; + + READ_ENTER(&ipsc_rwlock); + if ((i = is->is_isc) && (i != (ipscan_t *)-1)) { + ATOMIC_DEC32(i->ipsc_sref); + is->is_isc = NULL; + is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER); + } + RWLOCK_EXIT(&ipsc_rwlock); + return 0; +} + + +/* + * 'string' compare for scanning + */ +int ipsc_matchstr(sp, str, n) +sinfo_t *sp; +char *str; +int n; +{ + char *s, *t, *up; + int i = n; + + if (i > sp->s_len) + i = sp->s_len; + up = str; + + for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++) + switch ((int)*t) + { + case '.' : + if (*s != *up) + return 1; + break; + case '?' : + if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f))) + return 1; + break; + case '*' : + break; + } + return 0; +} + + +/* + * Returns 3 if both server and client match, 2 if just server, + * 1 if just client + */ +int ipsc_matchisc(isc, is, cl, sl, maxm) +ipscan_t *isc; +ipstate_t *is; +int cl, sl, maxm[2]; +{ + int i, j, k, n, ret = 0, flags; + + flags = is->is_flags; + + /* + * If we've already matched more than what is on offer, then + * assume we have a better match already and forget this one. + */ + if (maxm != NULL) { + if (isc->ipsc_clen < maxm[0]) + return 0; + if (isc->ipsc_slen < maxm[1]) + return 0; + j = maxm[0]; + k = maxm[1]; + } else { + j = 0; + k = 0; + } + + if (!isc->ipsc_clen) + ret = 1; + else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) && + cl && isc->ipsc_clen) { + i = 0; + n = MIN(cl, isc->ipsc_clen); + if ((n > 0) && (!maxm || (n >= maxm[1]))) { + if (!ipsc_matchstr(&isc->ipsc_cl, is->is_sbuf[0], n)) { + i++; + ret |= 1; + if (n > j) + j = n; + } + } + } + + if (!isc->ipsc_slen) + ret |= 2; + else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) && + sl && isc->ipsc_slen) { + i = 0; + n = MIN(cl, isc->ipsc_slen); + if ((n > 0) && (!maxm || (n >= maxm[1]))) { + if (!ipsc_matchstr(&isc->ipsc_sl, is->is_sbuf[1], n)) { + i++; + ret |= 2; + if (n > k) + k = n; + } + } + } + + if (maxm && (ret == 3)) { + maxm[0] = j; + maxm[1] = k; + } + return ret; +} + + +int ipsc_match(is) +ipstate_t *is; +{ + int i, j, k, n, cl, sl, maxm[2]; + ipscan_t *isc, *lm; + tcpdata_t *t; + + for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1) + cl++; + for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1) + sl++; + + j = 0; + isc = is->is_isc; + if (isc != NULL) { + /* + * Known object to scan for. + */ + i = ipsc_matchisc(isc, is, cl, sl, NULL); + if (i & 1) { + is->is_flags |= IS_SC_MATCHC; + is->is_flags &= ~IS_SC_CLIENT; + } else if (cl >= isc->ipsc_clen) + is->is_flags &= ~IS_SC_CLIENT; + if (i & 2) { + is->is_flags |= IS_SC_MATCHS; + is->is_flags &= ~IS_SC_SERVER; + } else if (sl >= isc->ipsc_slen) + is->is_flags &= ~IS_SC_SERVER; + } else { + i = 0; + lm = NULL; + maxm[0] = 0; + maxm[1] = 0; + for (k = 0, isc = ipsc_list; isc; isc = isc->ipsc_next) { + i = ipsc_matchisc(isc, is, cl, sl, maxm); + if (i) { + /* + * We only want to remember the best match + * and the number of times we get a best + * match. + */ + if ((j == 3) && (i < 3)) + continue; + if ((i == 3) && (j != 3)) + k = 1; + else + k++; + j = i; + lm = isc; + } + } + if (k == 1) + isc = lm; + + /* + * No matches or partial matches, so reset the respective + * search flag. + */ + if (!(j & 1)) + is->is_flags &= ~IS_SC_CLIENT; + + if (!(j & 2)) + is->is_flags &= ~IS_SC_SERVER; + + /* + * If we found the best match, then set flags appropriately. + */ + if ((j == 3) && (k == 1)) { + is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT); + is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC); + } + } + + /* + * If the acknowledged side of a connection has moved past the data in + * which we are interested, then reset respective flag. + */ + t = &is->is_tcp.ts_data[0]; + if (t->td_end > is->is_s0[0] + 15) + is->is_flags &= ~IS_SC_CLIENT; + + t = &is->is_tcp.ts_data[1]; + if (t->td_end > is->is_s0[1] + 15) + is->is_flags &= ~IS_SC_SERVER; + + /* + * Matching complete ? + */ + j = ISC_A_NONE; + if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) { + j = isc->ipsc_action; + ipsc_stat.iscs_acted++; + } else if ((is->is_isc != NULL) && + ((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) && + !(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) { + /* + * Matching failed... + */ + j = isc->ipsc_else; + ipsc_stat.iscs_else++; + } + + switch (j) + { + case ISC_A_CLOSE : + /* + * If as a result of a successful match we are to + * close a connection, change the "keep state" info. + * to block packets and generate TCP RST's. + */ + is->is_pass &= ~FR_RETICMP; + is->is_pass |= FR_RETRST; + break; + default : + break; + } + + return i; +} + + +/* + * check if a packet matches what we're scanning for + */ +int ipsc_packet(fin, is) +fr_info_t *fin; +ipstate_t *is; +{ + int i, j, rv, dlen, off, thoff; + u_32_t seq, s0; + tcphdr_t *tcp; + + rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src); + tcp = fin->fin_dp; + seq = ntohl(tcp->th_seq); + + if (!is->is_s0[rv]) + return 1; + + /* + * check if this packet has more data that falls within the first + * 16 bytes sent in either direction. + */ + s0 = is->is_s0[rv]; + off = seq - s0; + if ((off > 15) || (off < 0)) + return 1; + thoff = TCP_OFF(tcp) << 2; + dlen = fin->fin_dlen - thoff; + if (dlen <= 0) + return 1; + if (dlen > 16) + dlen = 16; + if (off + dlen > 16) + dlen = 16 - off; + + j = 0xffff >> (16 - dlen); + i = (0xffff & j) << off; +#ifdef _KERNEL + COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_hlen + thoff, dlen, + (caddr_t)is->is_sbuf[rv] + off); +#endif + is->is_smsk[rv] |= i; + for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1) + j++; + if (j == 0) + return 1; + + (void) ipsc_match(is); +#if 0 + /* + * There is the potential here for plain text passwords to get + * buffered and stored for some time... + */ + if (!(is->is_flags & IS_SC_CLIENT)) + bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0])); + if (!(is->is_flags & IS_SC_SERVER)) + bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1])); +#endif + return 0; +} + + +int fr_scan_ioctl(data, cmd, mode) +caddr_t data; +ioctlcmd_t cmd; +int mode; +{ + ipscanstat_t ipscs; + int err = 0; + + switch (cmd) + { + case SIOCADSCA : + err = ipsc_add(data); + break; + case SIOCRMSCA : + err = ipsc_delete(data); + break; + case SIOCGSCST : + bcopy((char *)&ipsc_stat, (char *)&ipscs, sizeof(ipscs)); + ipscs.iscs_list = ipsc_list; + BCOPYOUT(&ipscs, data, sizeof(ipscs)); + break; + default : + err = EINVAL; + break; + } + + return err; +} +#endif /* IPFILTER_SCAN */ diff --git a/contrib/ipfilter/ip_scan.h b/contrib/ipfilter/ip_scan.h new file mode 100644 index 0000000..de98f9c --- /dev/null +++ b/contrib/ipfilter/ip_scan.h @@ -0,0 +1,108 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * @(#)ip_fil.h 1.35 6/5/96 + * Id: ip_scan.h,v 2.9 2003/07/25 22:05:01 darrenr Exp + */ + +#ifndef __IP_SCAN_H__ +#define __IP_SCAN_H__ 1 + +#ifdef sun +# include <sys/ioccom.h> +#endif + +#define IPSCAN_NAME "/dev/ipscan" +#define IPL_SCAN IPSCAN_NAME +#define ISC_TLEN 16 + + +struct fr_info; +struct frentry; +struct ip; +struct ipstate; + + +#if defined(__STDC__) || defined(__GNUC__) +# define SIOCADSCA _IOWR('r', 60, struct ipscan *) +# define SIOCRMSCA _IOWR('r', 61, struct ipscan *) +# define SIOCGSCST _IOWR('r', 62, struct ipscan *) +#else +# define SIOCADSCA _IOWR(r, 60, struct ipscan *) +# define SIOCRMSCA _IOWR(r, 61, struct ipscan *) +# define SIOCGSCST _IOWR(r, 62, struct ipscan *) +#endif + +struct action { + int act_val; /* what to do */ + struct in_addr act_ip; /* redirect IP# */ + u_short act_port; /* redirect port number */ + int act_else; /* what to do */ + struct in_addr act_eip; /* redirect IP# */ + u_short act_eport; /* redirect port number */ +}; + + +typedef struct sinfo { + char s_txt[ISC_TLEN]; /* text to match */ + char s_msk[ISC_TLEN]; /* mask of the above to check */ + int s_len; /* length of server text */ +} sinfo_t; + + +typedef struct ipscan { + struct ipscan *ipsc_next; + struct ipscan **ipsc_pnext; + char ipsc_tag[ISC_TLEN]; /* table entry protocol tag */ + sinfo_t ipsc_si[2]; /* client/server side information */ + int ipsc_hits; /* times this has been matched */ + int ipsc_active; /* # of active matches */ + int ipsc_fref; /* # of references from filter rules */ + int ipsc_sref; /* # of references from state entries */ + struct action ipsc_act; +} ipscan_t; + + +#define ipsc_cl ipsc_si[0] +#define ipsc_sl ipsc_si[1] +#define ipsc_ctxt ipsc_cl.s_txt +#define ipsc_cmsk ipsc_cl.s_msk +#define ipsc_clen ipsc_cl.s_len +#define ipsc_stxt ipsc_sl.s_txt +#define ipsc_smsk ipsc_sl.s_msk +#define ipsc_slen ipsc_sl.s_len +#define ipsc_action ipsc_act.act_val +#define ipsc_ip ipsc_act.act_ip +#define ipsc_port ipsc_act.act_port +#define ipsc_else ipsc_act.act_else +#define ipsc_eip ipsc_act.act_eip +#define ipsc_eport ipsc_act.act_eport + +#define ISC_A_NONE 0 +#define ISC_A_TRACK 1 +#define ISC_A_CLOSE 2 +#define ISC_A_REDIRECT 3 + + +typedef struct ipscanstat { + struct ipscan *iscs_list; + u_long iscs_acted; + u_long iscs_else; + int iscs_entries; +} ipscanstat_t; + + +extern int fr_scan_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int ipsc_init __P((void)); +extern int ipsc_attachis __P((struct ipstate *)); +extern int ipsc_attachfr __P((struct frentry *)); +extern int ipsc_detachis __P((struct ipstate *)); +extern int ipsc_detachfr __P((struct frentry *)); +extern int ipsc_packet __P((struct fr_info *, struct ipstate *)); +extern void fr_scanunload __P((void)); + +#endif /* __IP_SCAN_H__ */ diff --git a/contrib/ipfilter/ip_state.c b/contrib/ipfilter/ip_state.c index 4934279..4ced16d 100644 --- a/contrib/ipfilter/ip_state.c +++ b/contrib/ipfilter/ip_state.c @@ -1,10 +1,15 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1995-2002 by Darren Reed. + * Copyright (C) 1995-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include <sys/errno.h> #include <sys/types.h> @@ -18,17 +23,18 @@ (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) #include "opt_inet6.h" #endif -#if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) +#if !defined(_KERNEL) && !defined(__KERNEL__) # include <stdio.h> # include <stdlib.h> # include <string.h> -#else -# ifdef linux -# include <linux/kernel.h> -# include <linux/module.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; # endif +# include <sys/uio.h> +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> # if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) @@ -38,18 +44,17 @@ # include <sys/ioctl.h> #endif #include <sys/time.h> -#ifndef linux +#if !defined(linux) # include <sys/protosw.h> #endif #include <sys/socket.h> -#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +#if defined(_KERNEL) # include <sys/systm.h> -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# if !defined(__SVR4) && !defined(__svr4__) # include <sys/mbuf.h> # endif -#else +#endif +#if defined(__SVR4) || defined(__svr4__) # include <sys/filio.h> # include <sys/byteorder.h> # ifdef _KERNEL @@ -68,8 +73,10 @@ #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/tcp.h> -#ifndef linux +#if !defined(linux) # include <netinet/ip_var.h> +#endif +#if !defined(__hpux) && !defined(linux) # include <netinet/tcp_fsm.h> #endif #include <netinet/udp.h> @@ -80,88 +87,129 @@ #include "netinet/ip_nat.h" #include "netinet/ip_frag.h" #include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#ifdef IPFILTER_SYNC +#include "netinet/ip_sync.h" +#endif +#ifdef IPFILTER_SCAN +#include "netinet/ip_scan.h" +#endif #ifdef USE_INET6 #include <netinet/icmp6.h> #endif #if (__FreeBSD_version >= 300000) # include <sys/malloc.h> -# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# if defined(_KERNEL) && !defined(IPFILTER_LKM) # include <sys/libkern.h> # include <sys/systm.h> # endif #endif +/* END OF INCLUDES */ + #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.88 2004/01/05 12:46:05 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: ip_state.c,v 2.186.2.29 2005/03/28 10:47:54 darrenr Exp"; #endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#define TCP_CLOSE (TH_FIN|TH_RST) - -static ipstate_t **ips_table = NULL; -static int ips_num = 0; -static int ips_wild = 0; -static ips_stat_t ips_stats; -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_state, ipf_mutex; -extern kmutex_t ipf_rw; -#endif +static ipstate_t **ips_table = NULL; +static u_long *ips_seed = NULL; +static int ips_num = 0; +static u_long ips_last_force_flush = 0; +ips_stat_t ips_stats; #ifdef USE_INET6 -static frentry_t *fr_checkicmp6matchingstate __P((ip6_t *, fr_info_t *)); +static ipstate_t *fr_checkicmp6matchingstate __P((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 *, int)); +static ipstate_t *fr_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *, + i6addr_t *, tcphdr_t *, u_32_t)); +static ipstate_t *fr_checkicmpmatchingstate __P((fr_info_t *)); static int fr_state_flush __P((int, int)); static ips_stat_t *fr_statetstats __P((void)); -static void fr_delstate __P((ipstate_t *)); +static void fr_delstate __P((ipstate_t *, int)); static int fr_state_remove __P((caddr_t)); -static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int)); -static int fr_tcpoptions __P((tcphdr_t *)); +static void fr_ipsmove __P((ipstate_t *, u_int)); +static int fr_tcpstate __P((fr_info_t *, tcphdr_t *, ipstate_t *)); +static int fr_tcpoptions __P((fr_info_t *, tcphdr_t *, tcpdata_t *)); +static ipstate_t *fr_stclone __P((fr_info_t *, tcphdr_t *, ipstate_t *)); +static void fr_fixinisn __P((fr_info_t *, ipstate_t *)); +static void fr_fixoutisn __P((fr_info_t *, ipstate_t *)); +static void fr_checknewisn __P((fr_info_t *, ipstate_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 */ +#define ONE_DAY IPF_TTLVAL(1 * 86400) /* 1 day */ +#define FIVE_DAYS (5 * ONE_DAY) +#define DOUBLE_HASH(x) (((x) + ips_seed[(x) % fr_statesize]) % fr_statesize) -#define TCP_MSL 240 /* 2 minutes */ u_long fr_tcpidletimeout = FIVE_DAYS, - fr_tcpclosewait = 2 * TCP_MSL, - fr_tcplastack = 2 * TCP_MSL, - fr_tcptimeout = 2 * TCP_MSL, - fr_tcpclosed = 120, - fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */ - fr_udptimeout = 240, - fr_udpacktimeout = 24, - fr_icmptimeout = 120, - fr_icmpacktimeout = 12; + fr_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL), + fr_tcplastack = IPF_TTLVAL(2 * TCP_MSL), + fr_tcptimeout = IPF_TTLVAL(2 * TCP_MSL), + fr_tcpclosed = IPF_TTLVAL(60), + fr_tcphalfclosed = IPF_TTLVAL(2 * 3600), /* 2 hours */ + fr_udptimeout = IPF_TTLVAL(120), + fr_udpacktimeout = IPF_TTLVAL(12), + fr_icmptimeout = IPF_TTLVAL(60), + fr_icmpacktimeout = IPF_TTLVAL(6), + fr_iptimeout = IPF_TTLVAL(60); int fr_statemax = IPSTATE_MAX, fr_statesize = IPSTATE_SIZE; int fr_state_doflush = 0, - fr_state_lock = 0; + fr_state_lock = 0, + fr_state_maxbucket = 0, + fr_state_maxbucket_reset = 1, + fr_state_init = 0; +ipftq_t ips_tqtqb[IPF_TCP_NSTATES], + ips_udptq, + ips_udpacktq, + ips_iptq, + ips_icmptq, + ips_icmpacktq, + *ips_utqe = NULL; +#ifdef IPFILTER_LOG +int ipstate_logging = 1; +#else +int ipstate_logging = 0; +#endif ipstate_t *ips_list = NULL; -static int icmpreplytype4[ICMP_MAXTYPE + 1]; -#ifdef USE_INET6 -static int icmpreplytype6[ICMP6_MAXTYPE + 1]; -#endif +/* ------------------------------------------------------------------------ */ +/* Function: fr_stateinit */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: Nil */ +/* */ +/* Initialise all the global variables used within the state code. */ +/* This action also includes initiailising locks. */ +/* ------------------------------------------------------------------------ */ 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 + if (ips_table == NULL) return -1; + bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *)); + + KMALLOCS(ips_seed, u_long *, fr_statesize * sizeof(*ips_seed)); + if (ips_seed == NULL) + return -2; + for (i = 0; i < fr_statesize; i++) { + /* + * XXX - ips_seed[X] should be a random number of sorts. + */ +#if (__FreeBSD_version >= 400000) + ips_seed[i] = arc4random(); +#else + ips_seed[i] = ((u_long)ips_seed + i) * fr_statesize; + ips_seed[i] ^= 0xa5a55a5a; + ips_seed[i] *= (u_long)ips_seed; + ips_seed[i] ^= 0x5a5aa5a5; + ips_seed[i] *= fr_statemax; +#endif + } /* fill icmp reply type table */ for (i = 0; i <= ICMP_MAXTYPE; i++) @@ -181,111 +229,155 @@ int fr_stateinit() icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; #endif + KMALLOCS(ips_stats.iss_bucketlen, u_long *, + fr_statesize * sizeof(u_long)); + if (ips_stats.iss_bucketlen == NULL) + return -1; + bzero((char *)ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long)); + + if (fr_state_maxbucket == 0) { + for (i = fr_statesize; i > 0; i >>= 1) + fr_state_maxbucket++; + fr_state_maxbucket *= 2; + } + + fr_sttab_init(ips_tqtqb); + ips_tqtqb[IPF_TCP_NSTATES - 1].ifq_next = &ips_udptq; + ips_udptq.ifq_ttl = (u_long)fr_udptimeout; + ips_udptq.ifq_ref = 1; + ips_udptq.ifq_head = NULL; + ips_udptq.ifq_tail = &ips_udptq.ifq_head; + MUTEX_INIT(&ips_udptq.ifq_lock, "ipftq udp tab"); + ips_udptq.ifq_next = &ips_udpacktq; + ips_udpacktq.ifq_ttl = (u_long)fr_udpacktimeout; + ips_udpacktq.ifq_ref = 1; + ips_udpacktq.ifq_head = NULL; + ips_udpacktq.ifq_tail = &ips_udpacktq.ifq_head; + MUTEX_INIT(&ips_udpacktq.ifq_lock, "ipftq udpack tab"); + ips_udpacktq.ifq_next = &ips_icmptq; + ips_icmptq.ifq_ttl = (u_long)fr_icmptimeout; + ips_icmptq.ifq_ref = 1; + ips_icmptq.ifq_head = NULL; + ips_icmptq.ifq_tail = &ips_icmptq.ifq_head; + MUTEX_INIT(&ips_icmptq.ifq_lock, "ipftq icmp tab"); + ips_icmptq.ifq_next = &ips_icmpacktq; + ips_icmpacktq.ifq_ttl = (u_long)fr_icmpacktimeout; + ips_icmpacktq.ifq_ref = 1; + ips_icmpacktq.ifq_head = NULL; + ips_icmpacktq.ifq_tail = &ips_icmpacktq.ifq_head; + MUTEX_INIT(&ips_icmpacktq.ifq_lock, "ipftq icmpack tab"); + ips_icmpacktq.ifq_next = &ips_iptq; + ips_iptq.ifq_ttl = (u_long)fr_iptimeout; + ips_iptq.ifq_ref = 1; + ips_iptq.ifq_head = NULL; + ips_iptq.ifq_tail = &ips_iptq.ifq_head; + MUTEX_INIT(&ips_iptq.ifq_lock, "ipftq ip tab"); + ips_iptq.ifq_next = NULL; + + RWLOCK_INIT(&ipf_state, "ipf IP state rwlock"); + MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex"); + fr_state_init = 1; + + ips_last_force_flush = fr_ticks; return 0; } -static ips_stat_t *fr_statetstats() +/* ------------------------------------------------------------------------ */ +/* Function: fr_stateunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Release and destroy any resources acquired or initialised so that */ +/* IPFilter can be unloaded or re-initialised. */ +/* ------------------------------------------------------------------------ */ +void fr_stateunload() { - ips_stats.iss_active = ips_num; - ips_stats.iss_table = ips_table; - ips_stats.iss_list = ips_list; - return &ips_stats; -} + ipftq_t *ifq, *ifqnext; + ipstate_t *is; + while ((is = ips_list) != NULL) + fr_delstate(is, 0); -/* - * flush state tables. two actions currently defined: - * which == 0 : flush all state table entries - * which == 1 : flush TCP connections which have started to close but are - * stuck for some reason. - * which == 2 : flush TCP connections which have been idle for a long time, - * starting at > 4 days idle and working back in successive half- - * days to at most 12 hours old. - */ -static int fr_state_flush(which, proto) -int which, proto; -{ - ipstate_t *is, **isp; -#if defined(_KERNEL) && !SOLARIS - int s; -#endif - int delete, removed = 0, try; + /* + * Proxy timeout queues are not cleaned here because although they + * exist on the state list, appr_unload is called after fr_stateunload + * and the proxies actually are responsible for them being created. + * Should the proxy timeouts have their own list? There's no real + * justification as this is the only complicationA + */ + for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + if (((ifq->ifq_flags & IFQF_PROXY) == 0) && + (fr_deletetimeoutqueue(ifq) == 0)) + fr_freetimeoutqueue(ifq); + } - SPL_NET(s); - for (isp = &ips_list; (is = *isp); ) { - delete = 0; + ips_stats.iss_inuse = 0; + ips_num = 0; - if ((proto != 0) && (is->is_v != proto)) - continue; + if (fr_state_init == 1) { + fr_sttab_destroy(ips_tqtqb); + MUTEX_DESTROY(&ips_udptq.ifq_lock); + MUTEX_DESTROY(&ips_icmptq.ifq_lock); + MUTEX_DESTROY(&ips_udpacktq.ifq_lock); + MUTEX_DESTROY(&ips_icmpacktq.ifq_lock); + MUTEX_DESTROY(&ips_iptq.ifq_lock); + } - switch (which) - { - case 0 : - delete = 1; - break; - case 1 : - case 2 : - if (is->is_p != IPPROTO_TCP) - break; - if ((is->is_state[0] != TCPS_ESTABLISHED) || - (is->is_state[1] != TCPS_ESTABLISHED)) - delete = 1; - break; - } + if (ips_table != NULL) { + KFREES(ips_table, fr_statesize * sizeof(*ips_table)); + ips_table = NULL; + } - 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); -#endif - fr_delstate(is); - removed++; - } else - isp = &is->is_next; + if (ips_seed != NULL) { + KFREES(ips_seed, fr_statesize * sizeof(*ips_seed)); + ips_seed = NULL; } - /* - * Asked to remove inactive entries, try again if first attempt - * failed. In this case, 86400 is half a day because the counter is - * activated every half second. - */ - if ((which == 2) && (removed == 0)) { - try = 86400; /* half a day */ - for (; (try < FIVE_DAYS) && (removed == 0); try += 86400) { - for (isp = &ips_list; (is = *isp); ) { - delete = 0; - if ((is->is_p == IPPROTO_TCP) && - ((is->is_state[0] == TCPS_ESTABLISHED) || - (is->is_state[1] == TCPS_ESTABLISHED)) && - (is->is_age < try)) { - ips_stats.iss_fin++; - delete = 1; - } else if ((is->is_p != IPPROTO_TCP) && - (is->is_pkts > 1)) { - ips_stats.iss_expire++; - delete = 1; - } - if (delete) { -#ifdef IPFILTER_LOG - ipstate_log(is, ISL_FLUSH); -#endif - fr_delstate(is); - removed++; - } else - isp = &is->is_next; - } - } + if (ips_stats.iss_bucketlen != NULL) { + KFREES(ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long)); + ips_stats.iss_bucketlen = NULL; } - SPL_X(s); - return removed; + if (fr_state_maxbucket_reset == 1) + fr_state_maxbucket = 0; + + if (fr_state_init == 1) { + fr_state_init = 0; + RW_DESTROY(&ipf_state); + MUTEX_DESTROY(&ipf_stinsert); + } } +/* ------------------------------------------------------------------------ */ +/* Function: fr_statetstats */ +/* Returns: ips_state_t* - pointer to state stats structure */ +/* Parameters: Nil */ +/* */ +/* Put all the current numbers and pointers into a single struct and return */ +/* a pointer to it. */ +/* ------------------------------------------------------------------------ */ +static ips_stat_t *fr_statetstats() +{ + ips_stats.iss_active = ips_num; + ips_stats.iss_statesize = fr_statesize; + ips_stats.iss_statemax = fr_statemax; + ips_stats.iss_table = ips_table; + ips_stats.iss_list = ips_list; + ips_stats.iss_ticks = fr_ticks; + return &ips_stats; +} + +/* ------------------------------------------------------------------------ */ +/* Function: fr_state_remove */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to state structure to delete from table */ +/* */ +/* Search for a state structure that matches the one passed, according to */ +/* the IP addresses and other protocol specific information. */ +/* ------------------------------------------------------------------------ */ static int fr_state_remove(data) caddr_t data; { @@ -293,23 +385,20 @@ caddr_t data; int error; sp = &st; - error = IRCOPYPTR(data, (caddr_t)&st, sizeof(st)); + error = fr_inobj(data, &st, IPFOBJ_IPSTATE); if (error) return EFAULT; WRITE_ENTER(&ipf_state); for (sp = ips_list; sp; sp = sp->is_next) if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && - !bcmp((char *)&sp->is_src, (char *)&st.is_src, + !bcmp((caddr_t)&sp->is_src, (caddr_t)&st.is_src, sizeof(st.is_src)) && - !bcmp((char *)&sp->is_dst, (char *)&st.is_dst, + !bcmp((caddr_t)&sp->is_dst, (caddr_t)&st.is_src, sizeof(st.is_dst)) && - !bcmp((char *)&sp->is_ps, (char *)&st.is_ps, + !bcmp((caddr_t)&sp->is_ps, (caddr_t)&st.is_ps, sizeof(st.is_ps))) { -#ifdef IPFILTER_LOG - ipstate_log(sp, ISL_REMOVE); -#endif - fr_delstate(sp); + fr_delstate(sp, ISL_REMOVE); RWLOCK_EXIT(&ipf_state); return 0; } @@ -318,49 +407,59 @@ caddr_t data; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_state_ioctl */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* cmd(I) - ioctl command integer */ +/* mode(I) - file mode bits used with open */ +/* */ +/* Processes an ioctl call made to operate on the IP Filter state device. */ +/* ------------------------------------------------------------------------ */ int fr_state_ioctl(data, cmd, mode) caddr_t data; -#if defined(__NetBSD__) || defined(__OpenBSD__) -u_long cmd; -#else -int cmd; -#endif +ioctlcmd_t cmd; int mode; { int arg, ret, error = 0; switch (cmd) { + /* + * Delete an entry from the state table. + */ case SIOCDELST : error = fr_state_remove(data); break; + /* + * Flush the state table + */ case SIOCIPFFL : - error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); - if (error) - break; + BCOPYIN(data, (char *)&arg, sizeof(arg)); if (arg == 0 || arg == 1) { WRITE_ENTER(&ipf_state); ret = fr_state_flush(arg, 4); RWLOCK_EXIT(&ipf_state); - error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); + BCOPYOUT((char *)&ret, data, sizeof(ret)); } else error = EINVAL; break; -#ifdef USE_INET6 +#ifdef USE_INET6 case SIOCIPFL6 : - error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); - if (error) - break; + BCOPYIN(data, (char *)&arg, sizeof(arg)); if (arg == 0 || arg == 1) { WRITE_ENTER(&ipf_state); ret = fr_state_flush(arg, 6); RWLOCK_EXIT(&ipf_state); - error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); + BCOPYOUT((char *)&ret, data, sizeof(ret)); } else error = EINVAL; break; #endif #ifdef IPFILTER_LOG + /* + * Flush the state log. + */ case SIOCIPFFB : if (!(mode & FWRITE)) error = EPERM; @@ -368,23 +467,51 @@ int mode; int tmp; tmp = ipflog_clear(IPL_LOGSTATE); - IWCOPY((char *)&tmp, data, sizeof(tmp)); + BCOPYOUT((char *)&tmp, data, sizeof(tmp)); } break; -#endif - case SIOCGETFS : - error = IWCOPYPTR((caddr_t)fr_statetstats(), data, - sizeof(ips_stat_t)); + /* + * Turn logging of state information on/off. + */ + case SIOCSETLG : + if (!(mode & FWRITE)) + error = EPERM; + else { + BCOPYIN((char *)data, (char *)&ipstate_logging, + sizeof(ipstate_logging)); + } + break; + /* + * Return the current state of logging. + */ + case SIOCGETLG : + BCOPYOUT((char *)&ipstate_logging, (char *)data, + sizeof(ipstate_logging)); break; + /* + * Return the number of bytes currently waiting to be read. + */ case FIONREAD : -#ifdef IPFILTER_LOG - arg = (int)iplused[IPL_LOGSTATE]; - error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); + arg = iplused[IPL_LOGSTATE]; /* returned in an int */ + BCOPYOUT((char *)&arg, data, sizeof(arg)); + break; #endif + /* + * Get the current state statistics. + */ + case SIOCGETFS : + error = fr_outobj(data, fr_statetstats(), IPFOBJ_STATESTAT); break; + /* + * Lock/Unlock the state table. (Locking prevents any changes, which + * means no packets match). + */ case SIOCSTLCK : - error = fr_lock(data, &fr_state_lock); + fr_lock(data, &fr_state_lock); break; + /* + * Add an entry to the current state table. + */ case SIOCSTPUT : if (!fr_state_lock) { error = EACCES; @@ -392,6 +519,9 @@ int mode; } error = fr_stputent(data); break; + /* + * Get a state table entry. + */ case SIOCSTGET : if (!fr_state_lock) { error = EACCES; @@ -407,22 +537,30 @@ int mode; } -/* - * Copy out state information from the kernel to a user space process. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_stgetent */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to state structure to retrieve from table */ +/* */ +/* Copy out state information from the kernel to a user space process. If */ +/* there is a filter rule associated with the state entry, copy that out */ +/* as well. The entry to copy out is taken from the value of "ips_next" in */ +/* the struct passed in and if not null and not found in the list of current*/ +/* state entries, the retrieval fails. */ +/* ------------------------------------------------------------------------ */ int fr_stgetent(data) caddr_t data; { - register ipstate_t *is, *isn; + ipstate_t *is, *isn; ipstate_save_t ips; int error; - error = IRCOPYPTR(data, (caddr_t)&ips, sizeof(ips)); + error = fr_inobj(data, &ips, IPFOBJ_STATESAVE); if (error) - return error; + return EFAULT; isn = ips.ips_next; - if (!isn) { + if (isn == NULL) { isn = ips_list; if (isn == NULL) { if (ips.ips_next == NULL) @@ -443,171 +581,272 @@ caddr_t data; } ips.ips_next = isn->is_next; bcopy((char *)isn, (char *)&ips.ips_is, sizeof(ips.ips_is)); - if (isn->is_rule) + ips.ips_rule = isn->is_rule; + if (isn->is_rule != NULL) bcopy((char *)isn->is_rule, (char *)&ips.ips_fr, sizeof(ips.ips_fr)); - error = IWCOPYPTR((caddr_t)&ips, data, sizeof(ips)); + error = fr_outobj(data, &ips, IPFOBJ_STATESAVE); if (error) - error = EFAULT; - return error; + return EFAULT; + return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_stputent */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to state information struct */ +/* */ +/* This function implements the SIOCSTPUT ioctl: insert a state entry into */ +/* the state table. If the state info. includes a pointer to a filter rule */ +/* then also add in an orphaned rule (will not show up in any "ipfstat -io" */ +/* output. */ +/* ------------------------------------------------------------------------ */ int fr_stputent(data) caddr_t data; { - register ipstate_t *is, *isn; + ipstate_t *is, *isn; ipstate_save_t ips; int error, out, i; frentry_t *fr; char *name; - error = IRCOPYPTR(data, (caddr_t)&ips, sizeof(ips)); + error = fr_inobj(data, &ips, IPFOBJ_STATESAVE); if (error) - return 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)); - out = fr->fr_flags & FR_OUTQUE ? 1 : 0; - isn->is_rule = fr; - ips.ips_is.is_rule = fr; + bzero((char *)isn, offsetof(struct ipstate, is_pkts)); + isn->is_sti.tqe_pnext = NULL; + isn->is_sti.tqe_next = NULL; + isn->is_sti.tqe_ifq = NULL; + isn->is_sti.tqe_parent = isn; + isn->is_ifp[0] = NULL; + isn->is_ifp[1] = NULL; + isn->is_ifp[2] = NULL; + isn->is_ifp[3] = NULL; + isn->is_sync = NULL; + fr = ips.ips_rule; + + if (fr == NULL) { + READ_ENTER(&ipf_state); + fr_stinsert(isn, 0); + RWLOCK_EXIT(&ipf_state); + return 0; + } - /* - * Look up all the interface names in the rule. - */ - for (i = 0; i < 4; i++) { - name = fr->fr_ifnames[i]; - if ((name[1] == '\0') && - ((name[0] == '-') || (name[0] == '*'))) { - fr->fr_ifas[i] = NULL; - } else if (*name != '\0') { - fr->fr_ifas[i] = GETUNIT(name, - fr->fr_v); - if (fr->fr_ifas[i] == NULL) - fr->fr_ifas[i] = (void *)-1; - else { - strncpy(isn->is_ifname[i], - IFNAME(fr->fr_ifas[i]), - IFNAMSIZ); - } - } - isn->is_ifp[out] = fr->fr_ifas[i]; - } + if (isn->is_flags & SI_NEWFR) { + KMALLOC(fr, frentry_t *); + if (fr == NULL) { + KFREE(isn); + return ENOMEM; + } + bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); + out = fr->fr_flags & FR_OUTQUE ? 1 : 0; + isn->is_rule = fr; + ips.ips_is.is_rule = fr; + MUTEX_NUKE(&fr->fr_lock); + MUTEX_INIT(&fr->fr_lock, "state filter rule lock"); - /* - * send a copy back to userland of what we ended up - * to allow for verification. - */ - error = IWCOPYPTR((caddr_t)&ips, data, 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; + /* + * Look up all the interface names in the rule. + */ + for (i = 0; i < 4; i++) { + name = fr->fr_ifnames[i]; + fr->fr_ifas[i] = fr_resolvenic(name, fr->fr_v); + name = isn->is_ifname[i]; + isn->is_ifp[i] = fr_resolvenic(name, isn->is_v); + } + + fr->fr_ref = 0; + fr->fr_dsize = 0; + fr->fr_data = NULL; + + fr_resolvedest(&fr->fr_tif, fr->fr_v); + fr_resolvedest(&fr->fr_dif, fr->fr_v); + + /* + * send a copy back to userland of what we ended up + * to allow for verification. + */ + error = fr_outobj(data, &ips, IPFOBJ_STATESAVE); + if (error) { + KFREE(isn); + MUTEX_DESTROY(&fr->fr_lock); + KFREE(fr); + return EFAULT; + } + READ_ENTER(&ipf_state); + fr_stinsert(isn, 0); + RWLOCK_EXIT(&ipf_state); + + } else { + READ_ENTER(&ipf_state); + for (is = ips_list; is; is = is->is_next) + if (is->is_rule == fr) { + fr_stinsert(isn, 0); + break; } + + if (is == NULL) { + KFREE(isn); + isn = NULL; } + RWLOCK_EXIT(&ipf_state); + + return (isn == NULL) ? ESRCH : 0; } - fr_stinsert(isn); + return 0; } -/* - * Insert a state table entry manually. - */ -void fr_stinsert(is) -register ipstate_t *is; +/* ------------------------------------------------------------------------ */ +/* Function: fr_stinsert */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure */ +/* rev(I) - flag indicating forward/reverse direction of packet */ +/* */ +/* Inserts a state structure into the hash table (for lookups) and the list */ +/* of state entries (for enumeration). Resolves all of the interface names */ +/* to pointers and adjusts running stats for the hash table as appropriate. */ +/* */ +/* Locking: it is assumed that some kind of lock on ipf_state is held. */ +/* ------------------------------------------------------------------------ */ +void fr_stinsert(is, rev) +ipstate_t *is; +int rev; { - register u_int hv = is->is_hv; - char *name; + frentry_t *fr; + u_int hv; int i; - MUTEX_INIT(&is->is_lock, "ipf state entry", NULL); + MUTEX_INIT(&is->is_lock, "ipf state entry"); + + fr = is->is_rule; + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + fr->fr_statecnt++; + MUTEX_EXIT(&fr->fr_lock); + } /* * Look up all the interface names in the state entry. */ for (i = 0; i < 4; i++) { - name = is->is_ifname[i]; - if ((name[1] == '\0') && - ((name[0] == '-') || (name[0] == '*'))) { - is->is_ifp[0] = NULL; - } else if (*name != '\0') { - is->is_ifp[i] = GETUNIT(name, is->is_v); - if (is->is_ifp[i] == NULL) - is->is_ifp[i] = (void *)-1; - } + if (is->is_ifp[i] != NULL) + continue; + is->is_ifp[i] = fr_resolvenic(is->is_ifname[i], is->is_v); } + /* + * If we could trust is_hv, then the modulous would not be needed, but + * when running with IPFILTER_SYNC, this stops bad values. + */ + hv = is->is_hv % fr_statesize; + is->is_hv = hv; + + /* + * We need to get both of these locks...the first because it is + * possible that once the insert is complete another packet might + * come along, match the entry and want to update it. + */ + MUTEX_ENTER(&is->is_lock); + MUTEX_ENTER(&ipf_stinsert); /* * add into list table. */ - if (ips_list) + if (ips_list != NULL) ips_list->is_pnext = &is->is_next; is->is_pnext = &ips_list; is->is_next = ips_list; ips_list = is; - if (ips_table[hv]) + + if (ips_table[hv] != NULL) 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; + ips_stats.iss_bucketlen[hv]++; ips_num++; + MUTEX_EXIT(&ipf_stinsert); + + fr_setstatequeue(is, rev); + MUTEX_EXIT(&is->is_lock); } -/* - * Create a new ipstate structure and hang it off the hash table. - */ -ipstate_t *fr_addstate(ip, fin, stsave, flags) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_addstate */ +/* Returns: ipstate_t* - NULL == failure, else pointer to new state */ +/* Parameters: fin(I) - pointer to packet information */ +/* stsave(O) - pointer to place to save pointer to created */ +/* state structure. */ +/* flags(I) - flags to use when creating the structure */ +/* */ +/* Creates a new IP state structure from the packet information collected. */ +/* Inserts it into the state table and appends to the bottom of the active */ +/* list. If the capacity of the table has reached the maximum allowed then */ +/* the call will fail and a flush is scheduled for the next timeout call. */ +/* ------------------------------------------------------------------------ */ +ipstate_t *fr_addstate(fin, stsave, flags) fr_info_t *fin; ipstate_t **stsave; u_int flags; { - register tcphdr_t *tcp = NULL; - register ipstate_t *is; - register u_int hv; + ipstate_t *is, ips; struct icmp *ic; - ipstate_t ips; - int out, ws; - u_int pass; + u_int pass, hv; + frentry_t *fr; + tcphdr_t *tcp; + grehdr_t *gre; void *ifp; + int out; - if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT) || - (fin->fin_misc & FM_BADSTATE)) + if (fr_state_lock || + (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD))) return NULL; - if (ips_num == fr_statemax) { - ips_stats.iss_max++; + + if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN)) + return NULL; + + fr = fin->fin_fr; + if ((fr->fr_statemax == 0) && (ips_num == fr_statemax)) { + ATOMIC_INCL(ips_stats.iss_max); + fr_state_doflush = 1; + return NULL; + } + + /* + * If a "keep state" rule has reached the maximum number of references + * to it, then schedule an automatic flush in case we can clear out + * some "dead old wood". + */ + if ((fr != NULL) && (fr->fr_statemax != 0) && + (fr->fr_statecnt >= fr->fr_statemax)) { + MUTEX_EXIT(&fr->fr_lock); + ATOMIC_INCL(ips_stats.iss_maxref); fr_state_doflush = 1; return NULL; } + + pass = (fr == NULL) ? 0 : fr->fr_flags; + + ic = NULL; + tcp = NULL; out = fin->fin_out; is = &ips; bzero((char *)is, sizeof(*is)); - ips.is_age = 1; + is->is_die = 1 + fr_ticks; + /* * Copy and calculate... */ @@ -618,12 +857,22 @@ u_int flags; hv += is->is_daddr; #ifdef USE_INET6 if (fin->fin_v == 6) { + /* + * For ICMPv6, we check to see if the destination address is + * a multicast address. If it is, do not include it in the + * calculation of the hash because the correct reply will come + * back from a real address, not a multicast address. + */ if ((is->is_p == IPPROTO_ICMPV6) && IN6_IS_ADDR_MULTICAST(&is->is_dst.in6)) { /* * So you can do keep state with neighbour discovery. + * + * Here we could use the address from the neighbour + * solicit message to put in the state structure and + * we could use that without a wildcard flag too... */ - flags |= FI_W_DADDR; + flags |= SI_W_DADDR; hv -= is->is_daddr; } else { hv += is->is_dst.i6[1]; @@ -638,36 +887,30 @@ u_int flags; switch (is->is_p) { - int off; - #ifdef USE_INET6 case IPPROTO_ICMPV6 : - ic = (struct icmp *)fin->fin_dp; - if ((ic->icmp_type & ICMP6_INFOMSG_MASK) == 0) - return NULL; + ic = fin->fin_dp; switch (ic->icmp_type) { case ICMP6_ECHO_REQUEST : - 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); + is->is_icmp.ici_type = ic->icmp_type; + hv += (is->is_icmp.ici_id = ic->icmp_id); break; case ICMP6_MEMBERSHIP_QUERY : case ND_ROUTER_SOLICIT : case ND_NEIGHBOR_SOLICIT : case ICMP6_NI_QUERY : - is->is_icmp.ics_type = ic->icmp_type; + is->is_icmp.ici_type = ic->icmp_type; break; default : return NULL; } ATOMIC_INCL(ips_stats.iss_icmp); - is->is_age = fr_icmptimeout; break; #endif case IPPROTO_ICMP : - ic = (struct icmp *)fin->fin_dp; + ic = fin->fin_dp; switch (ic->icmp_type) { @@ -675,18 +918,28 @@ u_int flags; case ICMP_TSTAMP : case ICMP_IREQ : case ICMP_MASKREQ : - 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); + is->is_icmp.ici_type = ic->icmp_type; + hv += (is->is_icmp.ici_id = ic->icmp_id); break; default : return NULL; } ATOMIC_INCL(ips_stats.iss_icmp); - is->is_age = fr_icmptimeout; break; + + case IPPROTO_GRE : + gre = fin->fin_dp; + + is->is_gre.gs_flags = gre->gr_flags; + is->is_gre.gs_ptype = gre->gr_ptype; + if (GRE_REV(is->is_gre.gs_flags) == 1) { + is->is_call[0] = fin->fin_data[0]; + is->is_call[1] = fin->fin_data[1]; + } + break; + case IPPROTO_TCP : - tcp = (tcphdr_t *)fin->fin_dp; + tcp = fin->fin_dp; if (tcp->th_flags & TH_RST) return NULL; @@ -696,32 +949,55 @@ u_int flags; */ is->is_sport = htons(fin->fin_data[0]); is->is_dport = htons(fin->fin_data[1]); - if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { + if ((flags & (SI_W_DPORT|SI_W_SPORT)) == 0) { hv += is->is_sport; hv += is->is_dport; } - if ((flags & FI_IGNOREPKT) == 0) { + + /* + * If this is a real packet then initialise fields in the + * state information structure from the TCP header information. + */ + + is->is_maxdwin = 1; + is->is_maxswin = ntohs(tcp->th_win); + if (is->is_maxswin == 0) + is->is_maxswin = 1; + + if ((fin->fin_flx & FI_IGNORE) == 0) { is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - - (off = (tcp->th_off << 2)) + + (TCP_OFF(tcp) << 2) + ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); is->is_maxsend = is->is_send; - if ((tcp->th_flags & TH_SYN) && - ((tcp->th_off << 2) >= (sizeof(*tcp) + 4))) { - ws = fr_tcpoptions(tcp); - if (ws >= 0) - is->is_swscale = ws; + /* + * Window scale option is only present in + * SYN/SYN-ACK packet. + */ + if ((tcp->th_flags & ~(TH_FIN|TH_ACK|TH_ECNALL)) == + TH_SYN && + (TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) { + if (fr_tcpoptions(fin, tcp, + &is->is_tcp.ts_data[0])) + is->is_swinflags = TCP_WSCALE_SEEN| + TCP_WSCALE_FIRST; } - } - is->is_maxdwin = 1; - is->is_maxswin = ntohs(tcp->th_win); - if (is->is_maxswin == 0) - is->is_maxswin = 1; + if ((fin->fin_out != 0) && (pass & FR_NEWISN) != 0) { + fr_checknewisn(fin, is); + fr_fixoutisn(fin, is); + } - if ((tcp->th_flags & TH_OPENING) == TH_SYN) - is->is_fsm = 1; + if ((tcp->th_flags & TH_OPENING) == TH_SYN) + flags |= IS_TCPFSM; + else { + is->is_maxdwin = is->is_maxswin * 2; + is->is_dend = ntohl(tcp->th_ack); + is->is_maxdend = ntohl(tcp->th_ack); + is->is_maxdwin *= 2; + } + } /* * If we're creating state for a starting connection, start the @@ -732,213 +1008,462 @@ u_int flags; break; case IPPROTO_UDP : - tcp = (tcphdr_t *)fin->fin_dp; + tcp = fin->fin_dp; is->is_sport = htons(fin->fin_data[0]); is->is_dport = htons(fin->fin_data[1]); - if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { - hv += is->is_sport; - hv += is->is_dport; + if ((flags & (SI_W_DPORT|SI_W_SPORT)) == 0) { + hv += tcp->th_dport; + hv += tcp->th_sport; } ATOMIC_INCL(ips_stats.iss_udp); - is->is_age = fr_udptimeout; break; + default : - is->is_age = fr_udptimeout; break; } + hv = DOUBLE_HASH(hv); + is->is_hv = hv; + is->is_rule = fr; + is->is_flags = flags & IS_INHERITED; + + /* + * Look for identical state. + */ + for (is = ips_table[is->is_hv % fr_statesize]; is != NULL; + is = is->is_hnext) { + if (bcmp(&ips.is_src, &is->is_src, + offsetof(struct ipstate, is_ps) - + offsetof(struct ipstate, is_src)) == 0) + break; + } + if (is != NULL) + return NULL; + if (ips_stats.iss_bucketlen[hv] >= fr_state_maxbucket) { + ATOMIC_INCL(ips_stats.iss_bucketfull); + return NULL; + } KMALLOC(is, ipstate_t *); if (is == NULL) { ATOMIC_INCL(ips_stats.iss_nomem); return NULL; } bcopy((char *)&ips, (char *)is, sizeof(*is)); - hv %= fr_statesize; - is->is_hv = hv; - is->is_rule = fin->fin_fr; - if (is->is_rule != NULL) { - is->is_group = is->is_rule->fr_group; - ATOMIC_INC32(is->is_rule->fr_ref); - pass = is->is_rule->fr_flags; - is->is_frage[0] = is->is_rule->fr_age[0]; - is->is_frage[1] = is->is_rule->fr_age[1]; - if (is->is_frage[0] != 0) - is->is_age = is->is_frage[0]; - - is->is_ifp[(out << 1) + 1] = is->is_rule->fr_ifas[1]; - is->is_ifp[(1 - out) << 1] = is->is_rule->fr_ifas[2]; - is->is_ifp[((1 - out) << 1) + 1] = is->is_rule->fr_ifas[3]; - - if (((ifp = is->is_rule->fr_ifas[1]) != NULL) && - (ifp != (void *)-1)) - strncpy(is->is_ifname[(out << 1) + 1], - IFNAME(ifp), IFNAMSIZ); - if (((ifp = is->is_rule->fr_ifas[2]) != NULL) && - (ifp != (void *)-1)) - strncpy(is->is_ifname[(1 - out) << 1], - IFNAME(ifp), IFNAMSIZ); - if (((ifp = is->is_rule->fr_ifas[3]) != NULL) && - (ifp != (void *)-1)) - strncpy(is->is_ifname[((1 - out) << 1) + 1], - IFNAME(ifp), IFNAMSIZ); - } else + /* + * Do not do the modulous here, it is done in fr_stinsert(). + */ + if (fr != NULL) { + (void) strncpy(is->is_group, fr->fr_group, FR_GROUPLEN); + if (fr->fr_age[0] != 0) { + is->is_tqehead[0] = fr_addtimeoutqueue(&ips_utqe, + fr->fr_age[0]); + is->is_sti.tqe_flags |= TQE_RULEBASED; + } + if (fr->fr_age[1] != 0) { + is->is_tqehead[1] = fr_addtimeoutqueue(&ips_utqe, + fr->fr_age[1]); + is->is_sti.tqe_flags |= TQE_RULEBASED; + } + + is->is_tag = fr->fr_logtag; + + is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1]; + is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2]; + is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3]; + + if (((ifp = fr->fr_ifas[1]) != NULL) && + (ifp != (void *)-1)) { + COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1]); + } + if (((ifp = fr->fr_ifas[2]) != NULL) && + (ifp != (void *)-1)) { + COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1]); + } + if (((ifp = fr->fr_ifas[3]) != NULL) && + (ifp != (void *)-1)) { + COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1]); + } + } else { pass = fr_flags; + is->is_tag = FR_NOLOGTAG; + } is->is_ifp[out << 1] = fin->fin_ifp; - strncpy(is->is_ifname[out << 1], IFNAME(fin->fin_ifp), IFNAMSIZ); - - WRITE_ENTER(&ipf_state); + if (fin->fin_ifp != NULL) { + COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]); + } + /* + * It may seem strange to set is_ref to 2, but fr_check() will call + * fr_statederef() after calling fr_addstate() and the idea is to + * have it exist at the end of fr_check() with is_ref == 1. + */ + is->is_ref = 2; is->is_pass = pass; - if ((flags & FI_IGNOREPKT) == 0) { - is->is_pkts = 1; - is->is_bytes = fin->fin_dlen + fin->fin_hlen; + is->is_pkts[0] = 0, is->is_bytes[0] = 0; + is->is_pkts[1] = 0, is->is_bytes[1] = 0; + is->is_pkts[2] = 0, is->is_bytes[2] = 0; + is->is_pkts[3] = 0, is->is_bytes[3] = 0; + if ((fin->fin_flx & FI_IGNORE) == 0) { + is->is_pkts[out] = 1; + is->is_bytes[out] = fin->fin_plen; + is->is_flx[out][0] = fin->fin_flx & FI_CMP; + is->is_flx[out][0] &= ~FI_OOW; } + + if (pass & FR_STSTRICT) + is->is_flags |= IS_STRICT; + + if (pass & FR_STATESYNC) + is->is_flags |= IS_STATESYNC; + /* * 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_v; - is->is_rulen = fin->fin_rule; - is->is_opt = fin->fin_fi.fi_optmsk; + is->is_opt = fin->fin_optmsk; is->is_optmsk = 0xffffffff; - is->is_sec = fin->fin_fi.fi_secmsk; + is->is_sec = fin->fin_secmsk; is->is_secmsk = 0xffff; - is->is_auth = fin->fin_fi.fi_auth; + is->is_auth = fin->fin_auth; is->is_authmsk = 0xffff; - is->is_flags = fin->fin_fl & FI_CMP; - is->is_flags |= FI_CMP << 4; - is->is_flags |= flags & (FI_WILDP|FI_WILDA); - if (flags & (FI_WILDP|FI_WILDA)) - ips_wild++; + if (flags & (SI_WILDP|SI_WILDA)) { + ATOMIC_INCL(ips_stats.iss_wild); + } + is->is_rulen = fin->fin_rule; + if (pass & FR_LOGFIRST) is->is_pass &= ~(FR_LOGFIRST|FR_LOG); - fr_stinsert(is); + + READ_ENTER(&ipf_state); is->is_me = stsave; - if (is->is_p == IPPROTO_TCP) { - fr_tcp_age(&is->is_age, is->is_state, fin, - 0, is->is_fsm); /* 0 = packet from the source */ + + fr_stinsert(is, fin->fin_rev); + + if (fin->fin_p == IPPROTO_TCP) { + /* + * If we're creating state for a starting connection, start the + * timer on it as we'll never see an error if it fails to + * connect. + */ + MUTEX_ENTER(&is->is_lock); + (void) fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags); + MUTEX_EXIT(&is->is_lock); +#ifdef IPFILTER_SCAN + if ((is->is_flags & SI_CLONE) == 0) + (void) ipsc_attachis(is); +#endif } -#ifdef IPFILTER_LOG - ipstate_log(is, ISL_NEW); +#ifdef IPFILTER_SYNC + if ((is->is_flags & IS_STATESYNC) && ((is->is_flags & SI_CLONE) == 0)) + is->is_sync = ipfsync_new(SMC_STATE, fin, is); #endif + if (ipstate_logging) + ipstate_log(is, ISL_NEW); + RWLOCK_EXIT(&ipf_state); - fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst); - if ((fin->fin_fl & FI_FRAG) && (pass & FR_KEEPFRAG)) - ipfr_newfrag(ip, fin); + fin->fin_state = is; + fin->fin_rev = IP6_NEQ(&is->is_dst, &fin->fin_daddr); + fin->fin_flx |= FI_STATE; + if (fin->fin_flx & FI_FRAG) + (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE); + return is; } -static int fr_tcpoptions(tcp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpoptions */ +/* Returns: int - 1 == packet matches state entry, 0 == it does not */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP packet header */ +/* td(I) - pointer to TCP data held as part of the state */ +/* */ +/* Look after the TCP header for any options and deal with those that are */ +/* present. Record details about those that we recogise. */ +/* ------------------------------------------------------------------------ */ +static int fr_tcpoptions(fin, tcp, td) +fr_info_t *fin; tcphdr_t *tcp; +tcpdata_t *td; { - u_char *opt, *last; - int wscale; + int off, mlen, ol, i, len, retval; + char buf[64], *s, opt; + mb_t *m = NULL; + + off = fin->fin_hlen + sizeof(*tcp); + len = (TCP_OFF(tcp) << 2) - sizeof(*tcp); + if (fin->fin_plen < off + len) + return 0; - opt = (u_char *) (tcp + 1); - last = ((u_char *)tcp) + (tcp->th_off << 2); + m = fin->fin_m; + off += fin->fin_ipoff; + mlen = MSGDSIZE(m) - off; + if (len > mlen) { + len = mlen; + retval = 0; + } else { + retval = 1; + } - /* If we don't find wscale here, we need to clear it */ - wscale = -2; + COPYDATA(m, off, len, buf); - /* Termination condition picked such that opt[0 .. 2] exist */ - while ((opt < last - 2) && (*opt != TCPOPT_EOL)) { - switch (*opt) { - case TCPOPT_NOP: - opt++; - continue; - case TCPOPT_WSCALE: - /* Proper length ? */ - if (opt[1] == 3) { - if (opt[2] > 14) - wscale = 14; - else - wscale = opt[2]; - } + for (s = buf; len > 0; ) { + opt = *s; + if (opt == TCPOPT_EOL) break; - default: - /* Unknown options must be two bytes+ */ - if (opt[1] < 2) + else if (opt == TCPOPT_NOP) + ol = 1; + else { + if (len < 2) break; - opt += opt[1]; - continue; + ol = (int)*(s + 1); + if (ol < 2 || ol > len) + break; + + /* + * Extract the TCP options we are interested in out of + * the header and store them in the the tcpdata struct. + */ + switch (opt) + { + case TCPOPT_WINDOW : + if (ol == TCPOLEN_WINDOW) { + i = (int)*(s + 2); + if (i > TCP_WSCALE_MAX) + i = TCP_WSCALE_MAX; + else if (i < 0) + i = 0; + td->td_winscale = i; + } + break; + case TCPOPT_MAXSEG : + /* + * So, if we wanted to set the TCP MAXSEG, + * it should be done here... + */ + if (ol == TCPOLEN_MAXSEG) { + i = (int)*(s + 2); + i <<= 8; + i += (int)*(s + 3); + td->td_maxseg = i; + } + break; + } } - break; + len -= ol; + s += ol; } - return wscale; + return retval; } - -/* - * check to see if a packet with TCP headers fits within the TCP window. - * change timeout depending on whether new packet is a SYN-ACK returning for a - * SYN or a RST or FIN which indicate time to close up shop. - */ -int fr_tcpstate(is, fin, ip, tcp) -register ipstate_t *is; +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpstate */ +/* Returns: int - 1 == packet matches state entry, 0 == it does not */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP packet header */ +/* is(I) - pointer to master state structure */ +/* */ +/* Check to see if a packet with TCP headers fits within the TCP window. */ +/* Change timeout depending on whether new packet is a SYN-ACK returning */ +/* for a SYN or a RST or FIN which indicate time to close up shop. */ +/* ------------------------------------------------------------------------ */ +static int fr_tcpstate(fin, tcp, is) fr_info_t *fin; -ip_t *ip; tcphdr_t *tcp; +ipstate_t *is; { - register tcp_seq seq, ack, end; - register int ackskew; + int source, ret = 0, flags; tcpdata_t *fdata, *tdata; - u_32_t win, maxwin; - int ret = 0, off; - int source; - int wscale; - /* - * Find difference between last checked packet and this packet. - */ - source = IP6EQ(fin->fin_fi.fi_src, is->is_src); - if (source && (ntohs(is->is_sport) != fin->fin_data[0])) + source = !fin->fin_rev; + if (((is->is_flags & IS_TCPFSM) != 0) && (source == 1) && + (ntohs(is->is_sport) != fin->fin_data[0])) source = 0; fdata = &is->is_tcp.ts_data[!source]; tdata = &is->is_tcp.ts_data[source]; - off = tcp->th_off << 2; - seq = ntohl(tcp->th_seq); - ack = ntohl(tcp->th_ack); - win = ntohs(tcp->th_win); - end = seq + fin->fin_dlen - off + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); + MUTEX_ENTER(&is->is_lock); + if (fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags)) { +#ifdef IPFILTER_SCAN + if (is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER)) { + ipsc_packet(fin, is); + if (FR_ISBLOCK(is->is_pass)) { + MUTEX_EXIT(&is->is_lock); + return 1; + } + } +#endif - if ((tcp->th_flags & TH_SYN) && (off >= sizeof(*tcp) + 4)) - wscale = fr_tcpoptions(tcp); + /* + * Nearing end of connection, start timeout. + */ + ret = fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags); + if (ret == 0) { + MUTEX_EXIT(&is->is_lock); + return 0; + } + + /* + * set s0's as appropriate. Use syn-ack packet as it + * contains both pieces of required information. + */ + /* + * Window scale option is only present in SYN/SYN-ACK packet. + * Compare with ~TH_FIN to mask out T/TCP setups. + */ + flags = tcp->th_flags & ~(TH_FIN|TH_ECNALL); + if (flags == (TH_SYN|TH_ACK)) { + is->is_s0[source] = ntohl(tcp->th_ack); + is->is_s0[!source] = ntohl(tcp->th_seq) + 1; + if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2)) && + tdata->td_winscale) { + if (fr_tcpoptions(fin, tcp, fdata)) { + fdata->td_winflags = TCP_WSCALE_SEEN| + TCP_WSCALE_FIRST; + } else { + if (!fdata->td_winscale) + tdata->td_winscale = 0; + } + } + if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) + fr_checknewisn(fin, is); + } else if (flags == TH_SYN) { + is->is_s0[source] = ntohl(tcp->th_seq) + 1; + if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) + if (fr_tcpoptions(fin, tcp, tdata)) { + tdata->td_winflags = TCP_WSCALE_SEEN| + TCP_WSCALE_FIRST; + } + + if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) + fr_checknewisn(fin, is); + + } + ret = 1; + } else + fin->fin_flx |= FI_OOW; + MUTEX_EXIT(&is->is_lock); + return ret; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checknewisn */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* */ +/* Check to see if this TCP connection is expecting and needs a new */ +/* sequence number for a particular direction of the connection. */ +/* */ +/* NOTE: This does not actually change the sequence numbers, only gets new */ +/* one ready. */ +/* ------------------------------------------------------------------------ */ +static void fr_checknewisn(fin, is) +fr_info_t *fin; +ipstate_t *is; +{ + u_32_t sumd, old, new; + tcphdr_t *tcp; + int i; + + i = fin->fin_rev; + tcp = fin->fin_dp; + + if (((i == 0) && !(is->is_flags & IS_ISNSYN)) || + ((i == 1) && !(is->is_flags & IS_ISNACK))) { + old = ntohl(tcp->th_seq); + new = fr_newisn(fin); + is->is_isninc[i] = new - old; + CALC_SUMD(old, new, sumd); + is->is_sumd[i] = (sumd & 0xffff) + (sumd >> 16); + + is->is_flags |= ((i == 0) ? IS_ISNSYN : IS_ISNACK); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpinwindow */ +/* Returns: int - 1 == packet inside TCP "window", 0 == not inside. */ +/* Parameters: fin(I) - pointer to packet information */ +/* fdata(I) - pointer to tcp state informatio (forward) */ +/* tdata(I) - pointer to tcp state informatio (reverse) */ +/* tcp(I) - pointer to TCP packet header */ +/* */ +/* Given a packet has matched addresses and ports, check to see if it is */ +/* within the TCP data window. In a show of generosity, allow packets that */ +/* are within the window space behind the current sequence # as well. */ +/* ------------------------------------------------------------------------ */ +int fr_tcpinwindow(fin, fdata, tdata, tcp, flags) +fr_info_t *fin; +tcpdata_t *fdata, *tdata; +tcphdr_t *tcp; +int flags; +{ + tcp_seq seq, ack, end; + int ackskew, tcpflags; + u_32_t win, maxwin; + + /* + * Find difference between last checked packet and this packet. + */ + tcpflags = tcp->th_flags; + seq = ntohl(tcp->th_seq); + ack = ntohl(tcp->th_ack); + if (tcpflags & TH_SYN) + win = ntohs(tcp->th_win); else - wscale = -1; + win = ntohs(tcp->th_win) << fdata->td_winscale; + if (win == 0) + win = 1; - MUTEX_ENTER(&is->is_lock); + /* + * if window scaling is present, the scaling is only allowed + * for windows not in the first SYN packet. In that packet the + * window is 65535 to specify the largest window possible + * for receivers not implementing the window scale option. + * Currently, we do not assume TTCP here. That means that + * if we see a second packet from a host (after the initial + * SYN), we can assume that the receiver of the SYN did + * already send back the SYN/ACK (and thus that we know if + * the receiver also does window scaling) + */ + if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) { + if (tdata->td_winflags & TCP_WSCALE_SEEN) { + fdata->td_winflags &= ~TCP_WSCALE_FIRST; + fdata->td_maxwin = win; + } else { + fdata->td_winscale = 0; + fdata->td_winflags = 0; + tdata->td_winscale = 0; + tdata->td_winflags = 0; + } + } - if (wscale >= 0) - fdata->td_wscale = wscale; - else if (wscale == -2) - fdata->td_wscale = tdata->td_wscale = 0; - if (!(tcp->th_flags & TH_SYN)) - win <<= fdata->td_wscale; + end = seq + fin->fin_dlen - (TCP_OFF(tcp) << 2) + + ((tcpflags & TH_SYN) ? 1 : 0) + ((tcpflags & TH_FIN) ? 1 : 0); if ((fdata->td_end == 0) && - (!is->is_fsm || ((tcp->th_flags & TH_OPENING) == TH_OPENING))) { + (!(flags & IS_TCPFSM) || + ((tcpflags & TH_OPENING) == TH_OPENING))) { /* * Must be a (outgoing) SYN-ACK in reply to a SYN. */ fdata->td_end = end; fdata->td_maxwin = 1; fdata->td_maxend = end + win; - if (win == 0) - fdata->td_maxend++; } - if (!(tcp->th_flags & TH_ACK)) { /* Pretend an ack was sent */ + if (!(tcpflags & TH_ACK)) { /* Pretend an ack was sent */ ack = tdata->td_end; - } else if (((tcp->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && + } else if (((tcpflags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && (ack == 0)) { /* gross hack to get around certain broken tcp stacks */ ack = tdata->td_end; @@ -950,14 +1475,26 @@ tcphdr_t *tcp; maxwin = tdata->td_maxwin; ackskew = tdata->td_end - ack; + /* + * Strict sequencing only allows in-order delivery. + */ + if ((flags & IS_STRICT) != 0) { + if (seq != fdata->td_end) { + return 0; + } + } + #define SEQ_GE(a,b) ((int)((a) - (b)) >= 0) #define SEQ_GT(a,b) ((int)((a) - (b)) > 0) - if ((SEQ_GE(fdata->td_maxend, end)) && + if ( +#if defined(_KERNEL) + (SEQ_GE(fdata->td_maxend, end)) && (SEQ_GE(seq, fdata->td_end - maxwin)) && +#endif /* XXX what about big packets */ #define MAXACKWINDOW 66000 - (-ackskew <= (MAXACKWINDOW << tdata->td_wscale)) && - ( ackskew <= (MAXACKWINDOW << tdata->td_wscale))) { + (-ackskew <= (MAXACKWINDOW << fdata->td_winscale)) && + ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) { /* if ackskew < 0 then this should be due to fragmented * packets. There is no way to know the length of the @@ -973,219 +1510,358 @@ tcphdr_t *tcp; * Thus, when ackskew is negative but still seems to belong * to this session, we bump up the destinations end value. */ - /* - * Nearing end of connection, start timeout. - */ - /* source ? 0 : 1 -> !source */ - if (fr_tcp_age(&is->is_age, is->is_state, fin, !source, - (int)is->is_fsm) == 0) { - if (ackskew < 0) - tdata->td_end = ack; - - /* update max window seen */ - if (fdata->td_maxwin < win) - fdata->td_maxwin = win; - if (SEQ_GT(end, fdata->td_end)) - fdata->td_end = end; - if (SEQ_GE(ack + win, tdata->td_maxend)) { - tdata->td_maxend = ack + win; - if (win == 0) - tdata->td_maxend++; - } - - ATOMIC_INCL(ips_stats.iss_hits); - ret = 1; - } + if (ackskew < 0) + tdata->td_end = ack; + + /* update max window seen */ + if (fdata->td_maxwin < win) + fdata->td_maxwin = win; + if (SEQ_GT(end, fdata->td_end)) + fdata->td_end = end; + if (SEQ_GE(ack + win, tdata->td_maxend)) + tdata->td_maxend = ack + win; + return 1; } - MUTEX_EXIT(&is->is_lock); - if ((ret == 0) && ((tcp->th_flags & TH_OPENING) != TH_SYN)) - fin->fin_misc |= FM_BADSTATE; - return ret; + return 0; } -/* - * Match a state table entry against an IP packet. - */ -static int fr_matchsrcdst(is, src, dst, fin, tcp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_stclone */ +/* Returns: ipstate_t* - NULL == cloning failed, */ +/* else pointer to new state structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP/UDP header */ +/* is(I) - pointer to master state structure */ +/* */ +/* Create a "duplcate" state table entry from the master. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_stclone(fin, tcp, is) +fr_info_t *fin; +tcphdr_t *tcp; ipstate_t *is; -union i6addr src, dst; +{ + ipstate_t *clone; + u_32_t send; + + if (ips_num == fr_statemax) { + ATOMIC_INCL(ips_stats.iss_max); + fr_state_doflush = 1; + return NULL; + } + KMALLOC(clone, ipstate_t *); + if (clone == NULL) + return NULL; + bcopy((char *)is, (char *)clone, sizeof(*clone)); + + MUTEX_NUKE(&clone->is_lock); + + clone->is_die = ONE_DAY + fr_ticks; + clone->is_state[0] = 0; + clone->is_state[1] = 0; + send = ntohl(tcp->th_seq) + fin->fin_dlen - (TCP_OFF(tcp) << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + + if (fin->fin_rev == 1) { + clone->is_dend = send; + clone->is_maxdend = send; + clone->is_send = 0; + clone->is_maxswin = 1; + clone->is_maxdwin = ntohs(tcp->th_win); + if (clone->is_maxdwin == 0) + clone->is_maxdwin = 1; + } else { + clone->is_send = send; + clone->is_maxsend = send; + clone->is_dend = 0; + clone->is_maxdwin = 1; + clone->is_maxswin = ntohs(tcp->th_win); + if (clone->is_maxswin == 0) + clone->is_maxswin = 1; + } + + clone->is_flags &= ~SI_CLONE; + clone->is_flags |= SI_CLONED; + fr_stinsert(clone, fin->fin_rev); + MUTEX_ENTER(&clone->is_lock); + clone->is_ref = 1; + if (clone->is_p == IPPROTO_TCP) { + (void) fr_tcp_age(&clone->is_sti, fin, ips_tqtqb, + clone->is_flags); + } + MUTEX_EXIT(&clone->is_lock); +#ifdef IPFILTER_SCAN + (void) ipsc_attachis(is); +#endif +#ifdef IPFILTER_SYNC + if (is->is_flags & IS_STATESYNC) + clone->is_sync = ipfsync_new(SMC_STATE, fin, clone); +#endif + return clone; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_matchsrcdst */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to state structure */ +/* src(I) - pointer to source address */ +/* dst(I) - pointer to destination address */ +/* tcp(I) - pointer to TCP/UDP header */ +/* */ +/* Match a state table entry against an IP packet. The logic below is that */ +/* ret gets set to one if the match succeeds, else remains 0. If it is */ +/* still 0 after the test. no match. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_matchsrcdst(fin, is, src, dst, tcp, cmask) fr_info_t *fin; +ipstate_t *is; +i6addr_t *src, *dst; tcphdr_t *tcp; +u_32_t cmask; { - int ret = 0, rev, out, flags, idx; + int ret = 0, rev, out, flags, flx = 0, idx; u_short sp, dp; + u_32_t cflx; void *ifp; - rev = IP6NEQ(is->is_dst, dst); + rev = IP6_NEQ(&is->is_dst, dst); ifp = fin->fin_ifp; out = fin->fin_out; - flags = is->is_flags & (FI_WILDA|FI_WILDP); + flags = is->is_flags; sp = 0; dp = 0; if (tcp != NULL) { - flags = is->is_flags; - sp = tcp->th_sport; - dp = tcp->th_dport; - if (!rev) { - if (!(flags & FI_W_SPORT) && (sp != is->is_sport)) + sp = htons(fin->fin_sport); + dp = ntohs(fin->fin_dport); + } + if (!rev) { + if (tcp != NULL) { + if (!(flags & SI_W_SPORT) && (sp != is->is_sport)) rev = 1; - else if (!(flags & FI_W_DPORT) && (dp != is->is_dport)) + else if (!(flags & SI_W_DPORT) && (dp != is->is_dport)) rev = 1; } } idx = (out << 1) + rev; - if ((is->is_ifp[idx] == NULL && - (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) || + /* + * If the interface for this 'direction' is set, make sure it matches. + * An interface name that is not set matches any, as does a name of *. + */ + if ((is->is_ifp[idx] == NULL && + (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) || is->is_ifp[idx] == ifp) ret = 1; if (ret == 0) - return 0; + return NULL; ret = 0; + /* + * Match addresses and ports. + */ if (rev == 0) { - 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; + if ((IP6_EQ(&is->is_dst, dst) || (flags & SI_W_DADDR)) && + (IP6_EQ(&is->is_src, src) || (flags & SI_W_SADDR))) { + if (tcp) { + if ((sp == is->is_sport || flags & SI_W_SPORT)&& + (dp == is->is_dport || flags & SI_W_DPORT)) + ret = 1; + } else { + ret = 1; + } } } else { - 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; + if ((IP6_EQ(&is->is_dst, src) || (flags & SI_W_DADDR)) && + (IP6_EQ(&is->is_src, dst) || (flags & SI_W_SADDR))) { + if (tcp) { + if ((dp == is->is_sport || flags & SI_W_SPORT)&& + (sp == is->is_dport || flags & SI_W_DPORT)) + ret = 1; + } else { + ret = 1; + } } } + if (ret == 0) - return 0; + return NULL; /* * Whether or not this should be here, is questionable, but the aim * is to get this out of the main line. */ if (tcp == NULL) - flags = is->is_flags & (FI_CMP|(FI_CMP<<4)); + flags = is->is_flags & ~(SI_WILDP|SI_NEWFR|SI_CLONE|SI_CLONED); - if (((fin->fin_fl & (flags >> 4)) != (flags & FI_CMP)) || - (fin->fin_fi.fi_optmsk != is->is_opt) || - (fin->fin_fi.fi_secmsk != is->is_sec) || - (fin->fin_fi.fi_auth != is->is_auth)) - return 0; + /* + * Only one of the source or destination address can be flaged as a + * wildcard. Fill in the missing address, if set. + * For IPv6, if the address being copied in is multicast, then + * don't reset the wild flag - multicast causes it to be set in the + * first place! + */ + if ((flags & (SI_W_SADDR|SI_W_DADDR))) { + fr_ip_t *fi = &fin->fin_fi; - flags = is->is_flags & (FI_WILDA|FI_WILDP); - if ((flags & (FI_W_SADDR|FI_W_DADDR))) { - if ((flags & FI_W_SADDR) != 0) { + if ((flags & SI_W_SADDR) != 0) { if (rev == 0) { - is->is_src = fin->fin_fi.fi_src; +#ifdef USE_INET6 + if (is->is_v == 6 && + IN6_IS_ADDR_MULTICAST(&fi->fi_src.in6)) + /*EMPTY*/; + else +#endif + { + is->is_src = fi->fi_src; + is->is_flags &= ~SI_W_SADDR; + } } else { - is->is_src = fin->fin_fi.fi_dst; +#ifdef USE_INET6 + if (is->is_v == 6 && + IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) + /*EMPTY*/; + else +#endif + { + is->is_src = fi->fi_dst; + is->is_flags &= ~SI_W_SADDR; + } } - } else if ((flags & FI_W_DADDR) != 0) { + } else if ((flags & SI_W_DADDR) != 0) { if (rev == 0) { - is->is_dst = fin->fin_fi.fi_dst; +#ifdef USE_INET6 + if (is->is_v == 6 && + IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) + /*EMPTY*/; + else +#endif + { + is->is_dst = fi->fi_dst; + is->is_flags &= ~SI_W_DADDR; + } } else { - is->is_dst = fin->fin_fi.fi_src; +#ifdef USE_INET6 + if (is->is_v == 6 && + IN6_IS_ADDR_MULTICAST(&fi->fi_src.in6)) + /*EMPTY*/; + else +#endif + { + is->is_dst = fi->fi_src; + is->is_flags &= ~SI_W_DADDR; + } } } - is->is_flags &= ~(FI_W_SADDR|FI_W_DADDR); - if ((is->is_flags & (FI_WILDA|FI_WILDP)) == 0) - ips_wild--; + if ((is->is_flags & (SI_WILDA|SI_WILDP)) == 0) { + ATOMIC_DECL(ips_stats.iss_wild); + } } - if ((flags & (FI_W_SPORT|FI_W_DPORT))) { - if ((flags & FI_W_SPORT) != 0) { + flx = fin->fin_flx & cmask; + cflx = is->is_flx[out][rev]; + + /* + * Match up any flags set from IP options. + */ + if ((cflx && (flx != (cflx & cmask))) || + ((fin->fin_optmsk & is->is_optmsk) != is->is_opt) || + ((fin->fin_secmsk & is->is_secmsk) != is->is_sec) || + ((fin->fin_auth & is->is_authmsk) != is->is_auth)) + return NULL; + + /* + * Only one of the source or destination port can be flagged as a + * wildcard. When filling it in, fill in a copy of the matched entry + * if it has the cloning flag set. + */ + if ((fin->fin_flx & FI_IGNORE) != 0) { + fin->fin_rev = rev; + return is; + } + + if ((flags & (SI_W_SPORT|SI_W_DPORT))) { + if ((flags & SI_CLONE) != 0) { + is = fr_stclone(fin, tcp, is); + if (is == NULL) + return NULL; + } else { + ATOMIC_DECL(ips_stats.iss_wild); + } + + if ((flags & SI_W_SPORT) != 0) { if (rev == 0) { is->is_sport = sp; - is->is_send = htonl(tcp->th_seq); + is->is_send = ntohl(tcp->th_seq); } else { is->is_sport = dp; - is->is_send = htonl(tcp->th_ack); + is->is_send = ntohl(tcp->th_ack); } is->is_maxsend = is->is_send + 1; - } else if ((flags & FI_W_DPORT) != 0) { + } else if ((flags & SI_W_DPORT) != 0) { if (rev == 0) { is->is_dport = dp; - is->is_dend = htonl(tcp->th_ack); + is->is_dend = ntohl(tcp->th_ack); } else { is->is_dport = sp; - is->is_dend = htonl(tcp->th_seq); + is->is_dend = ntohl(tcp->th_seq); } is->is_maxdend = is->is_dend + 1; } - is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); - ips_wild--; + is->is_flags &= ~(SI_W_SPORT|SI_W_DPORT); + if ((flags & SI_CLONED) && ipstate_logging) + ipstate_log(is, ISL_CLONE); } ret = -1; - if (is->is_ifp[idx] == NULL && - (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) - ret = idx; + if (is->is_flx[out][rev] == 0) + is->is_flx[out][rev] = flx; - if (ret >= 0) { - is->is_ifp[ret] = ifp; - strncpy(is->is_ifname[ret], IFNAME(ifp), - sizeof(is->is_ifname[ret])); + /* + * Check if the interface name for this "direction" is set and if not, + * fill it in. + */ + if (is->is_ifp[idx] == NULL && + (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) { + is->is_ifp[idx] = ifp; + COPYIFNAME(ifp, is->is_ifname[idx]); } fin->fin_rev = rev; - return 1; + return is; } -static int fr_matchicmpqueryreply(v, is, icmp, rev) -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 ((!rev && (icmp->icmp_type == is->is_type)) || - (rev && (icmpreplytype4[is->is_type] == icmp->icmp_type))) { - if (icmp->icmp_type != ICMP_ECHOREPLY) - return 1; - if ((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 ((!rev && (icmp->icmp_type == is->is_type)) || - (rev && (icmpreplytype6[is->is_type] == icmp->icmp_type))) { - if (icmp->icmp_type != ICMP6_ECHO_REPLY) - return 1; - if ((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; +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkicmpmatchingstate */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* If we've got an ICMP error message, using the information stored in the */ +/* ICMP packet, look for a matching state table entry. */ +/* */ +/* If we return NULL then no lock on ipf_state is held. */ +/* If we return non-null then a read-lock on ipf_state is held. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_checkicmpmatchingstate(fin) fr_info_t *fin; { - register ipstate_t *is, **isp; - register u_short sport, dport; - register u_char pr; - u_short savelen, ohlen; - union i6addr dst, src; + ipstate_t *is, **isp; + u_short sport, dport; + u_char pr; + int backward, i, oi; + i6addr_t dst, src; struct icmp *ic; + u_short savelen; icmphdr_t *icmp; fr_info_t ofin; - int type, len; tcphdr_t *tcp; - frentry_t *fr; + int type, len; ip_t *oip; u_int hv; @@ -1194,11 +1870,10 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with * an ICMP error header. */ - if (((ip->ip_v != 4) || (ip->ip_hl != 5)) || + if ((fin->fin_v != 4) || (fin->fin_hlen != sizeof(ip_t)) || (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; - - ic = (struct icmp *)fin->fin_dp; + ic = fin->fin_dp; type = ic->icmp_type; /* * If it's not an error type, then return @@ -1209,19 +1884,18 @@ fr_info_t *fin; return NULL; oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN); - ohlen = oip->ip_hl << 2; /* * Check if the at least the old IP header (with options) and * 8 bytes of payload is present. */ - if (fin->fin_plen < ICMPERR_MAXPKTLEN + ohlen - sizeof(*oip)) + if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((IP_HL(oip) - 5) << 2)) return NULL; /* - * Sanity checks. + * Sanity Checks. */ len = fin->fin_dlen - ICMPERR_ICMPHLEN; - if ((len <= 0) || (ohlen > len)) + if ((len <= 0) || ((IP_HL(oip) << 2) > len)) return NULL; /* @@ -1237,52 +1911,56 @@ fr_info_t *fin; { mb_t *m; -# if SOLARIS - m = fin->fin_qfm; + m = fin->fin_m; +# if defined(MENTAT) if ((char *)oip + len > (char *)m->b_wptr) return NULL; # else - m = *(mb_t **)fin->fin_mp; - if ((char *)oip + len > (char *)ip + m->m_len) + if ((char *)oip + len > (char *)fin->fin_ip + m->m_len) return NULL; # endif } #endif + bcopy((char *)fin, (char *)&ofin, sizeof(fin)); /* * in the IPv4 case we must zero the i6addr union otherwise - * the IP6EQ and IP6NEQ macros produce the wrong results because + * the IP6_EQ and IP6_NEQ macros produce the wrong results because * of the 'junk' in the unused part of the union */ bzero((char *)&src, sizeof(src)); bzero((char *)&dst, sizeof(dst)); - bzero((char *)&ofin, sizeof(ofin)); + /* - * 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 that we - * fill in fin_mp such that if someone uses it we'll get + * 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. - */ - ofin.fin_ifp = fin->fin_ifp; - ofin.fin_out = !fin->fin_out; - ofin.fin_mp = NULL; - ofin.fin_v = 4; - /* + * * watch out here, as ip is in host order and oip in network * order. Any change we make must be undone afterwards, like * oip->ip_off - it is still in network byte order so fix it. */ savelen = oip->ip_len; oip->ip_len = len; - oip->ip_off = ntohs(oip->ip_off); - (void) fr_makefrip(ohlen, oip, &ofin); + oip->ip_off = htons(oip->ip_off); + + ofin.fin_flx = FI_NOCKSUM; + ofin.fin_v = 4; + ofin.fin_ip = oip; + ofin.fin_m = NULL; /* if dereferenced, panic XXX */ + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + ofin.fin_plen = fin->fin_dlen - ICMPERR_ICMPHLEN; + (void) fr_makefrip(IP_HL(oip) << 2, oip, &ofin); + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; /* - * Reset the short flag here because in fr_matchsrcdst() the flags - * for the current packet (fin_fl) are compared against * those for - * the existing session. + * Reset the short and bad flag here because in fr_matchsrcdst() + * the flags for the current packet (fin_flx) are compared against + * those for the existing session. */ - ofin.fin_fl &= ~FI_SHORT; + ofin.fin_flx &= ~(FI_BAD|FI_SHORT); /* * Put old values of ip_len and ip_off back as we don't know @@ -1291,15 +1969,10 @@ fr_info_t *fin; oip->ip_len = savelen; oip->ip_off = htons(oip->ip_off); -#if SOLARIS - ofin.fin_qfm = NULL; -#endif - fr = NULL; - switch (oip->ip_p) { case IPPROTO_ICMP : - icmp = (icmphdr_t *)((char *)oip + ohlen); + icmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); /* * an ICMP error can only be generated as a result of an @@ -1308,10 +1981,10 @@ fr_info_t *fin; * XXX theoretically ICMP_ECHOREP and the other reply's are * ICMP query's as well, but adding them here seems strange XXX */ - if ((icmp->icmp_type != ICMP_ECHO) && - (icmp->icmp_type != ICMP_TSTAMP) && - (icmp->icmp_type != ICMP_IREQ) && - (icmp->icmp_type != ICMP_MASKREQ)) + if ((icmp->icmp_type != ICMP_ECHO) && + (icmp->icmp_type != ICMP_TSTAMP) && + (icmp->icmp_type != ICMP_IREQ) && + (icmp->icmp_type != ICMP_MASKREQ)) return NULL; /* @@ -1323,35 +1996,52 @@ fr_info_t *fin; dst.in4 = oip->ip_dst; hv += dst.in4.s_addr; hv += icmp->icmp_id; - hv += icmp->icmp_seq; - hv %= fr_statesize; + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == 4) && - (is->is_icmppkts < is->is_pkts) && - fr_matchsrcdst(is, src, dst, &ofin, NULL) && - fr_matchicmpqueryreply(is->is_v, is, icmp, - fin->fin_rev)) { + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != 4)) + continue; + if (is->is_pass & FR_NOICMPERR) + continue; + is = fr_matchsrcdst(&ofin, is, &src, &dst, + NULL, FI_ICMPCMP); + if (is != NULL) { + if ((is->is_pass & FR_NOICMPERR) != 0) { + RWLOCK_EXIT(&ipf_state); + return NULL; + } + /* + * i : the index of this packet (the icmp + * unreachable) + * oi : the index of the original packet found + * in the icmp header (i.e. the packet + * causing this icmp) + * backward : original packet was backward + * compared to the state + */ + backward = IP6_NEQ(&is->is_src, &src); + fin->fin_rev = !backward; + i = (!backward << 1) + fin->fin_out; + oi = (backward << 1) + ofin.fin_out; + if (is->is_icmppkts[i] > is->is_pkts[oi]) + continue; ips_stats.iss_hits++; - is->is_icmppkts++; - is->is_bytes += ip->ip_len; - fr = is->is_rule; - break; + is->is_icmppkts[i]++; + return is; } + } RWLOCK_EXIT(&ipf_state); - return fr; - + return NULL; case IPPROTO_TCP : case IPPROTO_UDP : - if (fin->fin_plen < ICMPERR_MAXPKTLEN) - return NULL; break; default : return NULL; } - tcp = (tcphdr_t *)((char *)oip + ohlen); + tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); dport = tcp->th_dport; sport = tcp->th_sport; @@ -1362,98 +2052,129 @@ fr_info_t *fin; hv += dst.in4.s_addr; hv += dport; hv += sport; - hv %= fr_statesize; + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + 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. Only the + * tcp internals such as seq and ack numbers. Only the * ports are known to be present and can be even if the * short flag is set. */ if ((is->is_p == pr) && (is->is_v == 4) && - (is->is_icmppkts < is->is_pkts) && - fr_matchsrcdst(is, src, dst, &ofin, tcp)) { - fr = is->is_rule; + (is = fr_matchsrcdst(&ofin, is, &src, &dst, + tcp, FI_ICMPCMP))) { + /* + * i : the index of this packet (the icmp unreachable) + * oi : the index of the original packet found in the + * icmp header (i.e. the packet causing this icmp) + * backward : original packet was backward compared to + * the state + */ + backward = IP6_NEQ(&is->is_src, &src); + fin->fin_rev = !backward; + i = (!backward << 1) + fin->fin_out; + oi = (backward << 1) + ofin.fin_out; + + if (((is->is_pass & FR_NOICMPERR) != 0) || + (is->is_icmppkts[i] > is->is_pkts[oi])) + break; ips_stats.iss_hits++; - is->is_icmppkts++; - is->is_bytes += fin->fin_plen; + is->is_icmppkts[i]++; /* * we deliberately do not touch the timeouts * for the accompanying state table entry. * It remains to be seen if that is correct. XXX */ - break; + return is; } } RWLOCK_EXIT(&ipf_state); - return fr; + return NULL; } -/* - * Move a state hash table entry from its old location at is->is_hv to - * its new location, indexed by hv % fr_statesize. - */ -static void fr_ipsmove(isp, is, hv) -ipstate_t **isp, *is; +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipsmove */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state table entry */ +/* hv(I) - new hash value for state table entry */ +/* Write Locks: ipf_state */ +/* */ +/* Move a state entry from one position in the hash table to another. */ +/* ------------------------------------------------------------------------ */ +static void fr_ipsmove(is, hv) +ipstate_t *is; u_int hv; { + ipstate_t **isp; u_int hvm; + ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0); + hvm = is->is_hv; /* * Remove the hash from the old location... */ + isp = is->is_phnext; if (is->is_hnext) is->is_hnext->is_phnext = isp; *isp = is->is_hnext; if (ips_table[hvm] == NULL) ips_stats.iss_inuse--; + ips_stats.iss_bucketlen[hvm]--; /* * ...and put the hash in the new one. */ - hvm = hv % fr_statesize; + hvm = DOUBLE_HASH(hv); is->is_hv = hvm; isp = &ips_table[hvm]; if (*isp) (*isp)->is_phnext = &is->is_hnext; else ips_stats.iss_inuse++; + ips_stats.iss_bucketlen[hvm]++; is->is_phnext = isp; is->is_hnext = *isp; *isp = is; } -/* - * Check if a packet has a registered state. - */ -frentry_t *fr_checkstate(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_stlookup */ +/* Returns: ipstate_t* - NULL == no matching state found, */ +/* else pointer to state information is returned */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP/UDP header. */ +/* */ +/* Search the state table for a matching entry to the packet described by */ +/* the contents of *fin. */ +/* */ +/* If we return NULL then no lock on ipf_state is held. */ +/* If we return non-null then a read-lock on ipf_state is held. */ +/* ------------------------------------------------------------------------ */ +ipstate_t *fr_stlookup(fin, tcp, ifqp) fr_info_t *fin; +tcphdr_t *tcp; +ipftq_t **ifqp; { - union i6addr dst, src; - register ipstate_t *is, **isp; - register u_char pr; - u_int hv, hvm, hlen, tryagain, pass, v; + u_int hv, hvm, pr, v, tryagain; + ipstate_t *is, **isp; + u_short dport, sport; + i6addr_t src, dst; struct icmp *ic; - frentry_t *fr; - tcphdr_t *tcp; - int rev; - - if ((ips_list == NULL) || (fin->fin_off != 0) || fr_state_lock || - (fin->fin_fl & FI_SHORT)) - return NULL; + ipftq_t *ifq; + int oow; is = NULL; - hlen = fin->fin_hlen; - tcp = (tcphdr_t *)((char *)ip + hlen); + ifq = NULL; + tcp = fin->fin_dp; ic = (struct icmp *)tcp; hv = (pr = fin->fin_fi.fi_p); src = fin->fin_fi.fi_src; @@ -1461,18 +2182,12 @@ fr_info_t *fin; hv += src.in4.s_addr; hv += dst.in4.s_addr; - /* - * Search the hash table for matching packet header info. - * At the bottom of this switch statement, the following is expected: - * is == NULL, no lock on ipf_state is held. - * is != NULL, a lock on ipf_state is held. - */ v = fin->fin_fi.fi_v; #ifdef USE_INET6 if (v == 6) { - hv += fin->fin_fi.fi_src.i6[1]; - hv += fin->fin_fi.fi_src.i6[2]; - hv += fin->fin_fi.fi_src.i6[3]; + hv += fin->fin_fi.fi_src.i6[1]; + hv += fin->fin_fi.fi_src.i6[2]; + hv += fin->fin_fi.fi_src.i6[3]; if ((fin->fin_p == IPPROTO_ICMPV6) && IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_dst.in6)) { @@ -1485,43 +2200,46 @@ fr_info_t *fin; } #endif - switch (fin->fin_p) + /* + * Search the hash table for matching packet header info. + */ + switch (pr) { #ifdef USE_INET6 case IPPROTO_ICMPV6 : - tcp = NULL; tryagain = 0; if (v == 6) { if ((ic->icmp_type == ICMP6_ECHO_REQUEST) || (ic->icmp_type == ICMP6_ECHO_REPLY)) { hv += ic->icmp_id; - hv += ic->icmp_seq; } } READ_ENTER(&ipf_state); icmp6again: - hvm = hv % fr_statesize; - for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, NULL) && - fr_matchicmpqueryreply(v, is, ic, fin->fin_rev)) { - rev = fin->fin_rev; - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else if (rev != 0) - is->is_age = fr_icmpacktimeout; + hvm = DOUBLE_HASH(hv); + for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP); + if (is != NULL && + fr_matchicmpqueryreply(v, &is->is_icmp, + ic, fin->fin_rev)) { + if (fin->fin_rev) + ifq = &ips_icmpacktq; else - is->is_age = fr_icmptimeout; + ifq = &ips_icmptq; break; } + } if (is != NULL) { - if (tryagain && !(is->is_flags & FI_W_DADDR)) { + if ((tryagain != 0) && !(is->is_flags & SI_W_DADDR)) { hv += fin->fin_fi.fi_src.i6[0]; hv += fin->fin_fi.fi_src.i6[1]; hv += fin->fin_fi.fi_src.i6[2]; hv += fin->fin_fi.fi_src.i6[3]; - fr_ipsmove(isp, is, hv); + fr_ipsmove(is, hv); MUTEX_DOWNGRADE(&ipf_state); } break; @@ -1531,8 +2249,14 @@ icmp6again: /* * No matching icmp state entry. Perhaps this is a * response to another state entry. + * + * XXX With some ICMP6 packets, the "other" address is already + * in the packet, after the ICMP6 header, and this could be + * used in place of the multicast address. However, taking + * advantage of this requires some significant code changes + * to handle the specific types where that is the case. */ - if ((ips_wild != 0) && (v == 6) && (tryagain == 0) && + if ((ips_stats.iss_wild != 0) && (v == 6) && (tryagain == 0) && !IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_src.in6)) { hv -= fin->fin_fi.fi_src.i6[0]; hv -= fin->fin_fi.fi_src.i6[1]; @@ -1543,113 +2267,107 @@ icmp6again: goto icmp6again; } - fr = fr_checkicmp6matchingstate((ip6_t *)ip, fin); - if (fr) - return fr; + is = fr_checkicmp6matchingstate(fin); + if (is != NULL) + return is; break; #endif + case IPPROTO_ICMP : - tcp = NULL; if (v == 4) { hv += ic->icmp_id; - hv += ic->icmp_seq; } - hvm = hv % fr_statesize; + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, NULL) && - fr_matchicmpqueryreply(v, is, ic, fin->fin_rev)) { - rev = fin->fin_rev; - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else if (fin->fin_rev) - is->is_age = fr_icmpacktimeout; + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP); + if (is != NULL && + fr_matchicmpqueryreply(v, &is->is_icmp, + ic, fin->fin_rev)) { + if (fin->fin_rev) + ifq = &ips_icmpacktq; else - is->is_age = fr_icmptimeout; + ifq = &ips_icmptq; break; } - - if (is != NULL) - break; - RWLOCK_EXIT(&ipf_state); - /* - * No matching icmp state entry. Perhaps this is a - * response to another state entry. - */ - fr = fr_checkicmpmatchingstate(ip, fin); - if (fr) - return fr; + } + if (is == NULL) { + RWLOCK_EXIT(&ipf_state); + } break; + case IPPROTO_TCP : - /* - * Just plain ignore RST flag set with either FIN or SYN. - */ - if ((tcp->th_flags & TH_RST) && - ((tcp->th_flags & (TH_FIN|TH_SYN|TH_RST)) != TH_RST)) - break; case IPPROTO_UDP : - { - register u_short dport, sport; - - dport = tcp->th_dport; - sport = tcp->th_sport; - tryagain = 0; - hv += dport; + ifqp = NULL; + sport = htons(fin->fin_data[0]); hv += sport; + dport = htons(fin->fin_data[1]); + hv += dport; + oow = 0; + tryagain = 0; READ_ENTER(&ipf_state); retry_tcpudp: - hvm = hv % fr_statesize; - for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, tcp)) { - rev = fin->fin_rev; - if ((pr == IPPROTO_TCP)) { - if (!fr_tcpstate(is, fin, ip, tcp)) - is = NULL; - } else if ((pr == IPPROTO_UDP)) { - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else if (fin->fin_rev) - is->is_age = fr_udpacktimeout; - else - is->is_age = fr_udptimeout; + hvm = DOUBLE_HASH(hv); + for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + fin->fin_flx &= ~FI_OOW; + is = fr_matchsrcdst(fin, is, &src, &dst, tcp, FI_CMP); + if (is != NULL) { + if (pr == IPPROTO_TCP) { + if (!fr_tcpstate(fin, tcp, is)) { + oow |= fin->fin_flx & FI_OOW; + continue; + } } break; } + } if (is != NULL) { if (tryagain && - !(is->is_flags & (FI_WILDP|FI_WILDA))) { + !(is->is_flags & (SI_CLONE|SI_WILDP|SI_WILDA))) { hv += dport; hv += sport; - fr_ipsmove(isp, is, hv); + fr_ipsmove(is, hv); MUTEX_DOWNGRADE(&ipf_state); } break; } - RWLOCK_EXIT(&ipf_state); - if (!tryagain && ips_wild) { + + if (!tryagain && ips_stats.iss_wild) { hv -= dport; hv -= sport; tryagain = 1; WRITE_ENTER(&ipf_state); goto retry_tcpudp; } + fin->fin_flx |= oow; break; - } + +#if 0 + case IPPROTO_GRE : + gre = fin->fin_dp; + if (GRE_REV(gre->gr_flags) == 1) { + hv += gre->gr_call; + } + /* FALLTHROUGH */ +#endif default : - tcp = NULL; - hv %= fr_statesize; + ifqp = NULL; + hvm = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - 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)) { - rev = fin->fin_rev; - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else - is->is_age = fr_udptimeout; + for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP); + if (is != NULL) { + ifq = &ips_iptq; break; } } @@ -1659,463 +2377,1013 @@ retry_tcpudp: break; } + if ((is != NULL) && ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) && + (is->is_tqehead[fin->fin_rev] != NULL)) + ifq = is->is_tqehead[fin->fin_rev]; + if (ifq != NULL && ifqp != NULL) + *ifqp = ifq; + return is; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_updatestate */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to state table entry */ +/* Read Locks: ipf_state */ +/* */ +/* Updates packet and byte counters for a newly received packet. Seeds the */ +/* fragment cache with a new entry as required. */ +/* ------------------------------------------------------------------------ */ +void fr_updatestate(fin, is, ifq) +fr_info_t *fin; +ipstate_t *is; +ipftq_t *ifq; +{ + ipftqent_t *tqe; + int i, pass; + + i = (fin->fin_rev << 1) + fin->fin_out; + + /* + * For TCP packets, ifq == NULL. For all others, check if this new + * queue is different to the last one it was on and move it if so. + */ + tqe = &is->is_sti; + MUTEX_ENTER(&is->is_lock); + if ((tqe->tqe_flags & TQE_RULEBASED) != 0) + ifq = is->is_tqehead[fin->fin_rev]; + + if (ifq != NULL) + fr_movequeue(tqe, tqe->tqe_ifq, ifq); + + is->is_pkts[i]++; + is->is_bytes[i] += fin->fin_plen; + MUTEX_EXIT(&is->is_lock); + +#ifdef IPFILTER_SYNC + if (is->is_flags & IS_STATESYNC) + ipfsync_update(SMC_STATE, fin, is->is_sync); +#endif + + ATOMIC_INCL(ips_stats.iss_hits); + + fin->fin_fr = is->is_rule; + + /* + * If this packet is a fragment and the rule says to track fragments, + * then create a new fragment cache entry. + */ + pass = is->is_pass; + if ((fin->fin_flx & FI_FRAG) && FR_ISPASS(pass)) + (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkstate */ +/* Returns: frentry_t* - NULL == search failed, */ +/* else pointer to rule for matching state */ +/* Parameters: ifp(I) - pointer to interface */ +/* passp(I) - pointer to filtering result flags */ +/* */ +/* Check if a packet is associated with an entry in the state table. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_checkstate(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + ipstate_t *is; + frentry_t *fr; + tcphdr_t *tcp; + ipftq_t *ifq; + u_int pass; + + if (fr_state_lock || (ips_list == NULL) || + (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD))) + return NULL; + + is = NULL; + if ((fin->fin_flx & FI_TCPUDP) || + (fin->fin_fi.fi_p == IPPROTO_ICMP) +#ifdef USE_INET6 + || (fin->fin_fi.fi_p == IPPROTO_ICMPV6) +#endif + ) + tcp = fin->fin_dp; + else + tcp = NULL; + + /* + * Search the hash table for matching packet header info. + */ + ifq = NULL; + is = fin->fin_state; + if (is == NULL) + is = fr_stlookup(fin, tcp, &ifq); + switch (fin->fin_p) + { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + if (is != NULL) + break; + if (fin->fin_v == 6) { + is = fr_checkicmp6matchingstate(fin); + if (is != NULL) + goto matched; + } + break; +#endif + case IPPROTO_ICMP : + if (is != NULL) + break; + /* + * No matching icmp state entry. Perhaps this is a + * response to another state entry. + */ + is = fr_checkicmpmatchingstate(fin); + if (is != NULL) + goto matched; + break; + case IPPROTO_TCP : + if (is == NULL) + break; + + if (is->is_pass & FR_NEWISN) { + if (fin->fin_out == 0) + fr_fixinisn(fin, is); + else if (fin->fin_out == 1) + fr_fixoutisn(fin, is); + } + break; + default : + if (fin->fin_rev) + ifq = &ips_udpacktq; + else + ifq = &ips_udptq; + break; + } if (is == NULL) { ATOMIC_INCL(ips_stats.iss_miss); return NULL; } - MUTEX_ENTER(&is->is_lock); - is->is_bytes += fin->fin_plen; - ips_stats.iss_hits++; - is->is_pkts++; - MUTEX_EXIT(&is->is_lock); +matched: fr = is->is_rule; - fin->fin_rule = is->is_rulen; if (fr != NULL) { - fin->fin_group = fr->fr_group; + if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { + if (fin->fin_nattag == NULL) + return NULL; + if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) != 0) + return NULL; + } + (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN); fin->fin_icode = fr->fr_icode; } - fin->fin_fr = fr; + + fin->fin_rule = is->is_rulen; pass = is->is_pass; + fr_updatestate(fin, is, ifq); + if (fin->fin_out == 1) + fin->fin_nat = is->is_nat[fin->fin_rev]; + + fin->fin_state = is; + is->is_touched = fr_ticks; + MUTEX_ENTER(&is->is_lock); + is->is_ref++; + MUTEX_EXIT(&is->is_lock); RWLOCK_EXIT(&ipf_state); - if ((fin->fin_fl & FI_FRAG) && (pass & FR_KEEPFRAG)) - ipfr_newfrag(ip, fin); -#ifndef _KERNEL - if ((tcp != NULL) && (tcp->th_flags & TCP_CLOSE)) - fr_delstate(is); -#endif + fin->fin_flx |= FI_STATE; + if ((pass & FR_LOGFIRST) != 0) + pass &= ~(FR_LOGFIRST|FR_LOG); + *passp = pass; return fr; } -/* - * Sync. state entries. If interfaces come or go or just change position, - * this is needed. - */ -void ip_statesync(ifp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_fixoutisn */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* */ +/* Called only for outbound packets, adjusts the sequence number and the */ +/* TCP checksum to match that change. */ +/* ------------------------------------------------------------------------ */ +static void fr_fixoutisn(fin, is) +fr_info_t *fin; +ipstate_t *is; +{ + tcphdr_t *tcp; + int rev; + u_32_t seq; + + tcp = fin->fin_dp; + rev = fin->fin_rev; + if ((is->is_flags & IS_ISNSYN) != 0) { + if (rev == 0) { + seq = ntohl(tcp->th_seq); + seq += is->is_isninc[0]; + tcp->th_seq = htonl(seq); + fix_outcksum(fin, &tcp->th_sum, is->is_sumd[0]); + } + } + if ((is->is_flags & IS_ISNACK) != 0) { + if (rev == 1) { + seq = ntohl(tcp->th_seq); + seq += is->is_isninc[1]; + tcp->th_seq = htonl(seq); + fix_outcksum(fin, &tcp->th_sum, is->is_sumd[1]); + } + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fixinisn */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* */ +/* Called only for inbound packets, adjusts the acknowledge number and the */ +/* TCP checksum to match that change. */ +/* ------------------------------------------------------------------------ */ +static void fr_fixinisn(fin, is) +fr_info_t *fin; +ipstate_t *is; +{ + tcphdr_t *tcp; + int rev; + u_32_t ack; + + tcp = fin->fin_dp; + rev = fin->fin_rev; + if ((is->is_flags & IS_ISNSYN) != 0) { + if (rev == 1) { + ack = ntohl(tcp->th_ack); + ack -= is->is_isninc[0]; + tcp->th_ack = htonl(ack); + fix_incksum(fin, &tcp->th_sum, is->is_sumd[0]); + } + } + if ((is->is_flags & IS_ISNACK) != 0) { + if (rev == 0) { + ack = ntohl(tcp->th_ack); + ack -= is->is_isninc[1]; + tcp->th_ack = htonl(ack); + fix_incksum(fin, &tcp->th_sum, is->is_sumd[1]); + } + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_statesync */ +/* Returns: Nil */ +/* Parameters: ifp(I) - pointer to interface */ +/* */ +/* Walk through all state entries and if an interface pointer match is */ +/* found then look it up again, based on its name in case the pointer has */ +/* changed since last time. */ +/* */ +/* If ifp is passed in as being non-null then we are only doing updates for */ +/* existing, matching, uses of it. */ +/* ------------------------------------------------------------------------ */ +void fr_statesync(ifp) void *ifp; { - register ipstate_t *is; + ipstate_t *is; int i; + if (fr_running <= 0) + return; + WRITE_ENTER(&ipf_state); + + if (fr_running <= 0) { + RWLOCK_EXIT(&ipf_state); + return; + } + for (is = ips_list; is; is = is->is_next) { + /* + * Look up all the interface names in the state entry. + */ for (i = 0; i < 4; i++) { - if (is->is_ifp[i] == ifp) { - is->is_ifp[i] = GETUNIT(is->is_ifname[i], - is->is_v); - if (!is->is_ifp[i]) - is->is_ifp[i] = (void *)-1; - } + if (ifp == NULL || ifp == is->is_ifp[i]) + is->is_ifp[i] = fr_resolvenic(is->is_ifname[i], + is->is_v); } } RWLOCK_EXIT(&ipf_state); } -/* - * Must always be called with fr_ipfstate held as a write lock. - */ -static void fr_delstate(is) +/* ------------------------------------------------------------------------ */ +/* Function: fr_delstate */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure to delete */ +/* why(I) - if not 0, log reason why it was deleted */ +/* Write Locks: ipf_state */ +/* */ +/* Deletes a state entry from the enumerated list as well as the hash table */ +/* and timeout queue lists. Make adjustments to hash table statistics and */ +/* global counters as required. */ +/* ------------------------------------------------------------------------ */ +static void fr_delstate(is, why) ipstate_t *is; +int why; { - frentry_t *fr; - if (is->is_flags & (FI_WILDP|FI_WILDA)) - ips_wild--; - if (is->is_next) - is->is_next->is_pnext = is->is_pnext; - *is->is_pnext = is->is_next; - 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--; - if (is->is_me) - *is->is_me = NULL; + ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0); - fr = is->is_rule; - if (fr != NULL) { - fr->fr_ref--; - if (fr->fr_ref == 0) { - KFREE(fr); + /* + * Since we want to delete this, remove it from the state table, + * where it can be found & used, first. + */ + if (is->is_pnext != NULL) { + *is->is_pnext = is->is_next; + + if (is->is_next != NULL) + is->is_next->is_pnext = is->is_pnext; + + is->is_pnext = NULL; + is->is_next = NULL; + } + + if (is->is_phnext != NULL) { + *is->is_phnext = is->is_hnext; + if (is->is_hnext != NULL) + is->is_hnext->is_phnext = is->is_phnext; + if (ips_table[is->is_hv] == NULL) + ips_stats.iss_inuse--; + ips_stats.iss_bucketlen[is->is_hv]--; + + is->is_phnext = NULL; + is->is_hnext = NULL; + } + + /* + * Because ips_stats.iss_wild is a count of entries in the state + * table that have wildcard flags set, only decerement it once + * and do it here. + */ + if (is->is_flags & (SI_WILDP|SI_WILDA)) { + if (!(is->is_flags & SI_CLONED)) { + ATOMIC_DECL(ips_stats.iss_wild); } + is->is_flags &= ~(SI_WILDP|SI_WILDA); } -#ifdef _KERNEL - MUTEX_DESTROY(&is->is_lock); + + /* + * Next, remove it from the timeout queue it is in. + */ + fr_deletequeueentry(&is->is_sti); + + if (is->is_me != NULL) { + *is->is_me = NULL; + is->is_me = NULL; + } + + /* + * If it is still in use by something else, do not go any further, + * but note that at this point it is now an orphan. + */ + is->is_ref--; + if (is->is_ref > 0) + return; + + if (is->is_tqehead[0] != NULL) { + if (fr_deletetimeoutqueue(is->is_tqehead[0]) == 0) + fr_freetimeoutqueue(is->is_tqehead[0]); + } + if (is->is_tqehead[1] != NULL) { + if (fr_deletetimeoutqueue(is->is_tqehead[1]) == 0) + fr_freetimeoutqueue(is->is_tqehead[1]); + } + +#ifdef IPFILTER_SYNC + if (is->is_sync) + ipfsync_del(is->is_sync); +#endif +#ifdef IPFILTER_SCAN + (void) ipsc_detachis(is); #endif - KFREE(is); - ips_num--; -} + if (ipstate_logging != 0 && why != 0) + ipstate_log(is, why); -/* - * Free memory in use by all state info. kept. - */ -void fr_stateunload() -{ - register ipstate_t *is; + if (is->is_rule != NULL) { + is->is_rule->fr_statecnt--; + (void)fr_derefrule(&is->is_rule); + } - WRITE_ENTER(&ipf_state); - while ((is = ips_list)) - fr_delstate(is); - ips_stats.iss_inuse = 0; - ips_num = 0; - RWLOCK_EXIT(&ipf_state); - if (ips_table) - KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); - ips_table = NULL; + MUTEX_DESTROY(&is->is_lock); + KFREE(is); + ips_num--; } -/* - * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set - * in expectation of this being called twice per second. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_timeoutstate */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Slowly expire held state for thingslike UDP and ICMP. The algorithm */ +/* used here is to keep the queue sorted with the oldest things at the top */ +/* and the youngest at the bottom. So if the top one doesn't need to be */ +/* expired then neither will any under it. */ +/* ------------------------------------------------------------------------ */ void fr_timeoutstate() { - register ipstate_t *is, **isp; -#if defined(_KERNEL) && !SOLARIS + ipftq_t *ifq, *ifqnext; + ipftqent_t *tqe, *tqn; + ipstate_t *is; +#if defined(USE_SPL) && defined(_KERNEL) int s; #endif SPL_NET(s); WRITE_ENTER(&ipf_state); - 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); -#endif - fr_delstate(is); - } else - isp = &is->is_next; + for (ifq = ips_tqtqb; ifq != NULL; ifq = ifq->ifq_next) + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + } + + for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + } + } + + for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + if (((ifq->ifq_flags & IFQF_DELETE) != 0) && + (ifq->ifq_ref == 0)) { + fr_freetimeoutqueue(ifq); + } + } + if (fr_state_doflush) { (void) fr_state_flush(2, 0); fr_state_doflush = 0; } + RWLOCK_EXIT(&ipf_state); SPL_X(s); } -/* - * Original idea freom Pradeep Krishnan for use primarily with NAT code. - * (pkrishna@netcom.com) - * - * Rewritten by Arjan de Vet <Arjan.deVet@adv.iae.nl>, 2000-07-29: - * - * - (try to) base state transitions on real evidence only, - * i.e. packets that are sent and have been received by ipfilter; - * diagram 18.12 of TCP/IP volume 1 by W. Richard Stevens was used. - * - * - deal with half-closed connections correctly; - * - * - store the state of the source in state[0] such that ipfstat - * displays the state as source/dest instead of dest/source; the calls - * to fr_tcp_age have been changed accordingly. - * - * Parameters: - * - * state[0] = state of source (host that initiated connection) - * state[1] = state of dest (host that accepted the connection) - * - * dir == 0 : a packet from source to dest - * dir == 1 : a packet from dest to source - * - */ -int fr_tcp_age(age, state, fin, dir, fsm) -u_long *age; -u_char *state; -fr_info_t *fin; -int dir, fsm; +/* ------------------------------------------------------------------------ */ +/* Function: fr_state_flush */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: Nil */ +/* Write Locks: ipf_state */ +/* */ +/* Flush state tables. Three actions currently defined: */ +/* which == 0 : flush all state table entries */ +/* which == 1 : flush TCP connections which have started to close but are */ +/* stuck for some reason. */ +/* which == 2 : flush TCP connections which have been idle for a long time, */ +/* starting at > 4 days idle and working back in successive half-*/ +/* days to at most 12 hours old. If this fails to free enough */ +/* slots then work backwards in half hour slots to 30 minutes. */ +/* If that too fails, then work backwards in 30 second intervals */ +/* for the last 30 minutes to at worst 30 seconds idle. */ +/* ------------------------------------------------------------------------ */ +static int fr_state_flush(which, proto) +int which, proto; { - tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; - u_char flags = tcp->th_flags; - int dlen, ostate; - u_long newage; + ipftq_t *ifq, *ifqnext; + ipftqent_t *tqe, *tqn; + ipstate_t *is, **isp; + int delete, removed; + long try, maxtick; + u_long interval; +#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) + int s; +#endif - ostate = state[1 - dir]; + removed = 0; - dlen = fin->fin_plen - fin->fin_hlen - (tcp->th_off << 2); + SPL_NET(s); + for (isp = &ips_list; ((is = *isp) != NULL); ) { + delete = 0; - if (flags & TH_RST) { - if (!(tcp->th_flags & TH_PUSH) && !dlen) { - *age = fr_tcpclosed; - state[dir] = TCPS_CLOSED; - } else { - *age = fr_tcpclosewait; - state[dir] = TCPS_CLOSE_WAIT; + if ((proto != 0) && (is->is_v != proto)) { + isp = &is->is_next; + continue; } - return 0; + + switch (which) + { + case 0 : + delete = 1; + break; + case 1 : + case 2 : + if (is->is_p != IPPROTO_TCP) + break; + if ((is->is_state[0] != IPF_TCPS_ESTABLISHED) || + (is->is_state[1] != IPF_TCPS_ESTABLISHED)) + delete = 1; + break; + } + + if (delete) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; + fr_delstate(is, ISL_FLUSH); + removed++; + } else + isp = &is->is_next; } - newage = 0; + if (which != 2) { + SPL_X(s); + return removed; + } - switch(state[dir]) - { - case TCPS_CLOSED: /* 0 */ - if ((flags & TH_OPENING) == TH_OPENING) { - /* - * 'dir' received an S and sends SA in response, - * CLOSED -> SYN_RECEIVED - */ - state[dir] = TCPS_SYN_RECEIVED; - newage = fr_tcptimeout; - } else if ((flags & TH_OPENING) == TH_SYN) { - /* 'dir' sent S, CLOSED -> SYN_SENT */ - state[dir] = TCPS_SYN_SENT; - newage = fr_tcptimeout; - } - - /* - * It is apparently possible that a hosts sends two syncs - * before the remote party is able to respond with a SA. In - * such a case the remote server sometimes ACK's the second - * sync, and then responds with a SA. The following code - * is used to prevent this ack from being blocked. - * - * We do not reset the timeout here to fr_tcptimeout because - * a connection connect timeout does not renew after every - * packet that is sent. We need to set newage to something - * to indicate the packet has passed the check for its flags - * being valid in the TCP FSM. - */ - else if ((ostate == TCPS_SYN_SENT) && - ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK)) { - newage = *age; + /* + * Asked to remove inactive entries because the table is full, try + * again, 3 times, if first attempt failed with a different criteria + * each time. The order tried in must be in decreasing age. + * Another alternative is to implement random drop and drop N entries + * at random until N have been freed up. + */ + if (fr_ticks - ips_last_force_flush < IPF_TTLVAL(5)) + goto force_flush_skipped; + ips_last_force_flush = fr_ticks; + + if (fr_ticks > IPF_TTLVAL(43200)) + interval = IPF_TTLVAL(43200); + else if (fr_ticks > IPF_TTLVAL(1800)) + interval = IPF_TTLVAL(1800); + else if (fr_ticks > IPF_TTLVAL(30)) + interval = IPF_TTLVAL(30); + else + interval = IPF_TTLVAL(10); + try = fr_ticks - (fr_ticks - interval); + if (try < 0) + goto force_flush_skipped; + + while (removed == 0) { + maxtick = fr_ticks - interval; + if (maxtick < 0) + break; + + while (try < maxtick) { + for (ifq = ips_tqtqb; ifq != NULL; + ifq = ifq->ifq_next) { + for (tqn = ifq->ifq_head; + ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > try) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + removed++; + } + } + + for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + for (tqn = ifq->ifq_head; + ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > try) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + removed++; + } + } + if (try + interval > maxtick) + break; + try += interval; } - /* - * The next piece of code makes it possible to get - * already established connections into the state table - * after a restart or reload of the filter rules; this - * does not work when a strict 'flags S keep state' is - * used for tcp connections of course, however, use a - * lower time-out so the state disappears quickly if - * the other side does not pick it up. - */ - else if (!fsm && - (flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) { - /* we saw an A, guess 'dir' is in ESTABLISHED mode */ - if (ostate == TCPS_CLOSED) { - state[dir] = TCPS_ESTABLISHED; - newage = fr_tcptimeout; - } else if (ostate == TCPS_ESTABLISHED) { - state[dir] = TCPS_ESTABLISHED; - newage = fr_tcpidletimeout; + if (removed == 0) { + if (interval == IPF_TTLVAL(43200)) { + interval = IPF_TTLVAL(1800); + } else if (interval == IPF_TTLVAL(1800)) { + interval = IPF_TTLVAL(30); + } else if (interval == IPF_TTLVAL(30)) { + interval = IPF_TTLVAL(10); + } else { + break; } } - /* - * TODO: besides regular ACK packets we can have other - * packets as well; it is yet to be determined how we - * should initialize the states in those cases - */ - break; + } +force_flush_skipped: + SPL_X(s); + return removed; +} - case TCPS_LISTEN: /* 1 */ - /* NOT USED */ - break; - case TCPS_SYN_SENT: /* 2 */ - if ((flags & ~(TH_ECN|TH_CWR)) == TH_SYN) { - /* - * A retransmitted SYN packet. We do not reset the - * timeout here to fr_tcptimeout because a connection - * connect timeout does not renew after every packet - * that is sent. We need to set newage to something - * to indicate the packet has passed the check for its - * flags being valid in the TCP FSM. - */ - newage = *age; - } else if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { - /* - * We see an A from 'dir' which is in SYN_SENT - * state: 'dir' sent an A in response to an SA - * which it received, SYN_SENT -> ESTABLISHED - */ - state[dir] = TCPS_ESTABLISHED; - newage = fr_tcpidletimeout; - } else if (flags & TH_FIN) { - /* - * We see an F from 'dir' which is in SYN_SENT - * state and wants to close its side of the - * connection; SYN_SENT -> FIN_WAIT_1 - */ - state[dir] = TCPS_FIN_WAIT_1; - newage = fr_tcpidletimeout; /* or fr_tcptimeout? */ - } else if ((flags & TH_OPENING) == TH_OPENING) { - /* - * We see an SA from 'dir' which is already in - * SYN_SENT state, this means we have a - * simultaneous open; SYN_SENT -> SYN_RECEIVED - */ - state[dir] = TCPS_SYN_RECEIVED; - newage = fr_tcptimeout; - } - break; - case TCPS_SYN_RECEIVED: /* 3 */ - if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { - /* - * We see an A from 'dir' which was in SYN_RECEIVED - * state so it must now be in established state, - * SYN_RECEIVED -> ESTABLISHED - */ - state[dir] = TCPS_ESTABLISHED; - newage = fr_tcpidletimeout; - } else if ((flags & ~(TH_ECN|TH_CWR)) == TH_OPENING) { +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcp_age */ +/* Returns: int - 1 == state transition made, 0 == no change (rejected) */ +/* Parameters: tq(I) - pointer to timeout queue information */ +/* fin(I) - pointer to packet information */ +/* tqtab(I) - TCP timeout queue table this is in */ +/* flags(I) - flags from state/NAT entry */ +/* */ +/* Rewritten by Arjan de Vet <Arjan.deVet@adv.iae.nl>, 2000-07-29: */ +/* */ +/* - (try to) base state transitions on real evidence only, */ +/* i.e. packets that are sent and have been received by ipfilter; */ +/* diagram 18.12 of TCP/IP volume 1 by W. Richard Stevens was used. */ +/* */ +/* - deal with half-closed connections correctly; */ +/* */ +/* - store the state of the source in state[0] such that ipfstat */ +/* displays the state as source/dest instead of dest/source; the calls */ +/* to fr_tcp_age have been changed accordingly. */ +/* */ +/* Internal Parameters: */ +/* */ +/* state[0] = state of source (host that initiated connection) */ +/* state[1] = state of dest (host that accepted the connection) */ +/* */ +/* dir == 0 : a packet from source to dest */ +/* dir == 1 : a packet from dest to source */ +/* */ +/* Locking: it is assumed that the parent of the tqe structure is locked. */ +/* ------------------------------------------------------------------------ */ +int fr_tcp_age(tqe, fin, tqtab, flags) +ipftqent_t *tqe; +fr_info_t *fin; +ipftq_t *tqtab; +int flags; +{ + int dlen, ostate, nstate, rval, dir; + u_char tcpflags; + tcphdr_t *tcp; + + tcp = fin->fin_dp; + + rval = 0; + dir = fin->fin_rev; + tcpflags = tcp->th_flags; + dlen = fin->fin_plen - fin->fin_hlen - (TCP_OFF(tcp) << 2); + + if (tcpflags & TH_RST) { + if (!(tcpflags & TH_PUSH) && !dlen) + nstate = IPF_TCPS_CLOSED; + else + nstate = IPF_TCPS_CLOSE_WAIT; + rval = 1; + } else { + ostate = tqe->tqe_state[1 - dir]; + nstate = tqe->tqe_state[dir]; + + switch (nstate) + { + case IPF_TCPS_CLOSED: /* 0 */ + if ((tcpflags & TH_OPENING) == TH_OPENING) { + /* + * 'dir' received an S and sends SA in + * response, CLOSED -> SYN_RECEIVED + */ + nstate = IPF_TCPS_SYN_RECEIVED; + rval = 1; + } else if ((tcpflags & TH_OPENING) == TH_SYN) { + /* 'dir' sent S, CLOSED -> SYN_SENT */ + nstate = IPF_TCPS_SYN_SENT; + rval = 1; + } /* - * We see an SA from 'dir' which is already in - * SYN_RECEIVED state. + * the next piece of code makes it possible to get + * already established connections into the state table + * after a restart or reload of the filter rules; this + * does not work when a strict 'flags S keep state' is + * used for tcp connections of course */ - newage = fr_tcptimeout; - } else if (flags & TH_FIN) { + if (((flags & IS_TCPFSM) == 0) && + ((tcpflags & TH_ACKMASK) == TH_ACK)) { + /* + * we saw an A, guess 'dir' is in ESTABLISHED + * mode + */ + switch (ostate) + { + case IPF_TCPS_CLOSED : + case IPF_TCPS_SYN_RECEIVED : + nstate = IPF_TCPS_HALF_ESTAB; + rval = 1; + break; + case IPF_TCPS_HALF_ESTAB : + case IPF_TCPS_ESTABLISHED : + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + break; + default : + break; + } + } /* - * We see an F from 'dir' which is in SYN_RECEIVED - * state and wants to close its side of the connection; - * SYN_RECEIVED -> FIN_WAIT_1 + * TODO: besides regular ACK packets we can have other + * packets as well; it is yet to be determined how we + * should initialize the states in those cases */ - state[dir] = TCPS_FIN_WAIT_1; - newage = fr_tcpidletimeout; - } - break; + break; - case TCPS_ESTABLISHED: /* 4 */ - if (flags & TH_FIN) { - /* - * 'dir' closed its side of the connection; this - * gives us a half-closed connection; - * ESTABLISHED -> FIN_WAIT_1 - */ - state[dir] = TCPS_FIN_WAIT_1; - newage = fr_tcphalfclosed; - } else if (flags & TH_ACK) { - /* an ACK, should we exclude other flags here? */ - if (ostate == TCPS_FIN_WAIT_1) { + case IPF_TCPS_LISTEN: /* 1 */ + /* NOT USED */ + break; + + case IPF_TCPS_SYN_SENT: /* 2 */ + if ((tcpflags & ~(TH_ECN|TH_CWR)) == TH_SYN) { /* - * We know the other side did an active close, - * so we are ACKing the recvd FIN packet (does - * the window matching code guarantee this?) - * and go into CLOSE_WAIT state; this gives us - * a half-closed connection + * A retransmitted SYN packet. We do not reset + * the timeout here to fr_tcptimeout because a + * connection connect timeout does not renew + * after every packet that is sent. We need to + * set rval so as to indicate the packet has + * passed the check for its flags being valid + * in the TCP FSM. Setting rval to 2 has the + * result of not resetting the timeout. */ - state[dir] = TCPS_CLOSE_WAIT; - newage = fr_tcphalfclosed; - } else if (ostate < TCPS_CLOSE_WAIT) + rval = 2; + } else if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == + TH_ACK) { /* - * Still a fully established connection, - * reset timeout + * we see an A from 'dir' which is in SYN_SENT + * state: 'dir' sent an A in response to an SA + * which it received, SYN_SENT -> ESTABLISHED */ - newage = fr_tcpidletimeout; - } - break; + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + } else if (tcpflags & TH_FIN) { + /* + * we see an F from 'dir' which is in SYN_SENT + * state and wants to close its side of the + * connection; SYN_SENT -> FIN_WAIT_1 + */ + nstate = IPF_TCPS_FIN_WAIT_1; + rval = 1; + } else if ((tcpflags & TH_OPENING) == TH_OPENING) { + /* + * we see an SA from 'dir' which is already in + * SYN_SENT state, this means we have a + * simultaneous open; SYN_SENT -> SYN_RECEIVED + */ + nstate = IPF_TCPS_SYN_RECEIVED; + rval = 1; + } + break; - case TCPS_CLOSE_WAIT: /* 5 */ - if (flags & TH_FIN) { - /* - * Application closed and 'dir' sent a FIN, we're now - * going into LAST_ACK state - */ - newage = fr_tcplastack; - state[dir] = TCPS_LAST_ACK; - } else { - /* - * We remain in CLOSE_WAIT because the other side has - * closed already and we did not close our side yet; - * reset timeout - */ - newage = fr_tcphalfclosed; - } - break; + case IPF_TCPS_SYN_RECEIVED: /* 3 */ + if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { + /* + * we see an A from 'dir' which was in + * SYN_RECEIVED state so it must now be in + * established state, SYN_RECEIVED -> + * ESTABLISHED + */ + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + } else if ((tcpflags & ~(TH_ECN|TH_CWR)) == + TH_OPENING) { + /* + * We see an SA from 'dir' which is already in + * SYN_RECEIVED state. + */ + rval = 2; + } else if (tcpflags & TH_FIN) { + /* + * we see an F from 'dir' which is in + * SYN_RECEIVED state and wants to close its + * side of the connection; SYN_RECEIVED -> + * FIN_WAIT_1 + */ + nstate = IPF_TCPS_FIN_WAIT_1; + rval = 1; + } + break; - case TCPS_FIN_WAIT_1: /* 6 */ - if ((flags & TH_ACK) && ostate > TCPS_CLOSE_WAIT) { - /* - * If the other side is not active anymore it has sent - * us a FIN packet that we are ack'ing now with an ACK; - * this means both sides have now closed the connection - * and we go into TIME_WAIT - */ - /* - * XXX: how do we know we really are ACKing the FIN - * packet here? does the window code guarantee that? - */ - state[dir] = TCPS_TIME_WAIT; - newage = fr_tcptimeout; - } else - /* - * We closed our side of the connection already but the - * other side is still active (ESTABLISHED/CLOSE_WAIT); - * continue with this half-closed connection - */ - newage = fr_tcphalfclosed; - break; + case IPF_TCPS_HALF_ESTAB: /* 4 */ + if (ostate >= IPF_TCPS_HALF_ESTAB) { + if ((tcpflags & TH_ACKMASK) == TH_ACK) { + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + } + } + + break; - case TCPS_CLOSING: /* 7 */ - /* NOT USED */ - break; + case IPF_TCPS_ESTABLISHED: /* 5 */ + rval = 1; + if (tcpflags & TH_FIN) { + /* + * 'dir' closed its side of the connection; + * this gives us a half-closed connection; + * ESTABLISHED -> FIN_WAIT_1 + */ + nstate = IPF_TCPS_FIN_WAIT_1; + } else if (tcpflags & TH_ACK) { + /* + * an ACK, should we exclude other flags here? + */ + if (ostate == IPF_TCPS_FIN_WAIT_1) { + /* + * We know the other side did an active + * close, so we are ACKing the recvd + * FIN packet (does the window matching + * code guarantee this?) and go into + * CLOSE_WAIT state; this gives us a + * half-closed connection + */ + nstate = IPF_TCPS_CLOSE_WAIT; + } else if (ostate < IPF_TCPS_CLOSE_WAIT) { + /* + * still a fully established + * connection reset timeout + */ + nstate = IPF_TCPS_ESTABLISHED; + } + } + break; - case TCPS_LAST_ACK: /* 8 */ - if (flags & TH_ACK) { - if ((flags & TH_PUSH) || dlen) + case IPF_TCPS_CLOSE_WAIT: /* 6 */ + rval = 1; + if (tcpflags & TH_FIN) { /* - * There is still data to be delivered, reset - * timeout + * application closed and 'dir' sent a FIN, + * we're now going into LAST_ACK state */ - newage = fr_tcplastack; - else - newage = *age; - } - /* - * We cannot detect when we go out of LAST_ACK state to CLOSED - * because that is based on the reception of ACK packets; - * ipfilter can only detect that a packet has been sent by a - * host - */ - break; + nstate = IPF_TCPS_LAST_ACK; + } else { + /* + * we remain in CLOSE_WAIT because the other + * side has closed already and we did not + * close our side yet; reset timeout + */ + nstate = IPF_TCPS_CLOSE_WAIT; + } + break; - case TCPS_FIN_WAIT_2: /* 9 */ - /* NOT USED */ - break; + case IPF_TCPS_FIN_WAIT_1: /* 7 */ + rval = 1; + if ((tcpflags & TH_ACK) && + ostate > IPF_TCPS_CLOSE_WAIT) { + /* + * if the other side is not active anymore + * it has sent us a FIN packet that we are + * ack'ing now with an ACK; this means both + * sides have now closed the connection and + * we go into TIME_WAIT + */ + /* + * XXX: how do we know we really are ACKing + * the FIN packet here? does the window code + * guarantee that? + */ + nstate = IPF_TCPS_TIME_WAIT; + } else { + /* + * we closed our side of the connection + * already but the other side is still active + * (ESTABLISHED/CLOSE_WAIT); continue with + * this half-closed connection + */ + nstate = IPF_TCPS_FIN_WAIT_1; + } + break; - case TCPS_TIME_WAIT: /* 10 */ - newage = fr_tcptimeout; /* default 4 mins */ - /* we're in 2MSL timeout now */ - break; + case IPF_TCPS_CLOSING: /* 8 */ + /* NOT USED */ + break; + + case IPF_TCPS_LAST_ACK: /* 9 */ + if (tcpflags & TH_ACK) { + if ((tcpflags & TH_PUSH) || dlen) + /* + * there is still data to be delivered, + * reset timeout + */ + rval = 1; + else + rval = 2; + } + /* + * we cannot detect when we go out of LAST_ACK state to + * CLOSED because that is based on the reception of ACK + * packets; ipfilter can only detect that a packet + * has been sent by a host + */ + break; + + case IPF_TCPS_FIN_WAIT_2: /* 10 */ + rval = 1; + if ((tcpflags & TH_OPENING) == TH_OPENING) + nstate = IPF_TCPS_SYN_RECEIVED; + else if (tcpflags & TH_SYN) + nstate = IPF_TCPS_SYN_SENT; + break; + + case IPF_TCPS_TIME_WAIT: /* 11 */ + /* we're in 2MSL timeout now */ + rval = 1; + break; + + default : +#if defined(_KERNEL) +# if SOLARIS + cmn_err(CE_NOTE, + "tcp %lx flags %x si %lx nstate %d ostate %d\n", + (u_long)tcp, tcpflags, (u_long)tqe, + nstate, ostate); +# else + printf("tcp %lx flags %x si %lx nstate %d ostate %d\n", + (u_long)tcp, tcpflags, (u_long)tqe, + nstate, ostate); +# endif +# ifdef DIAGNOSTIC + panic("invalid TCP state"); +# endif +#else + abort(); +#endif + break; + } } - if (newage != 0) { - *age = newage; - return 0; + /* + * If rval == 2 then do not update the queue position, but treat the + * packet as being ok. + */ + if (rval == 2) + rval = 1; + else if (rval == 1) { + tqe->tqe_state[dir] = nstate; + if ((tqe->tqe_flags & TQE_RULEBASED) == 0) + fr_movequeue(tqe, tqe->tqe_ifq, tqtab + nstate); } - return -1; + + return rval; } -#ifdef IPFILTER_LOG +/* ------------------------------------------------------------------------ */ +/* Function: ipstate_log */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure */ +/* type(I) - type of log entry to create */ +/* */ +/* Creates a state table log entry using the state structure and type info. */ +/* passed in. Log packet/byte counts, source/destination address and other */ +/* protocol specific information. */ +/* ------------------------------------------------------------------------ */ void ipstate_log(is, type) struct ipstate *is; u_int type; { +#ifdef IPFILTER_LOG struct ipslog ipsl; - void *items[1]; size_t sizes[1]; + void *items[1]; int types[1]; + /* + * Copy information out of the ipstate_t structure and into the + * structure used for logging. + */ ipsl.isl_type = type; - ipsl.isl_pkts = is->is_pkts + is->is_icmppkts; - ipsl.isl_bytes = is->is_bytes; + ipsl.isl_pkts[0] = is->is_pkts[0] + is->is_icmppkts[0]; + ipsl.isl_bytes[0] = is->is_bytes[0]; + ipsl.isl_pkts[1] = is->is_pkts[1] + is->is_icmppkts[1]; + ipsl.isl_bytes[1] = is->is_bytes[1]; + ipsl.isl_pkts[2] = is->is_pkts[2] + is->is_icmppkts[2]; + ipsl.isl_bytes[2] = is->is_bytes[2]; + ipsl.isl_pkts[3] = is->is_pkts[3] + is->is_icmppkts[3]; + ipsl.isl_bytes[3] = is->is_bytes[3]; 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; + ipsl.isl_tag = is->is_tag; ipsl.isl_rulen = is->is_rulen; - ipsl.isl_group = is->is_group; + (void) strncpy(ipsl.isl_group, is->is_group, FR_GROUPLEN); + if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) { ipsl.isl_sport = is->is_sport; ipsl.isl_dport = is->is_dport; @@ -2124,13 +3392,14 @@ u_int type; ipsl.isl_state[1] = is->is_state[1]; } } else if (ipsl.isl_p == IPPROTO_ICMP) { - ipsl.isl_itype = is->is_icmp.ics_type; + ipsl.isl_itype = is->is_icmp.ici_type; } else if (ipsl.isl_p == IPPROTO_ICMPV6) { - ipsl.isl_itype = is->is_icmp.ics_type; + ipsl.isl_itype = is->is_icmp.ici_type; } else { ipsl.isl_ps.isl_filler[0] = 0; ipsl.isl_ps.isl_filler[1] = 0; } + items[0] = &ipsl; sizes[0] = sizeof(ipsl); types[0] = 0; @@ -2140,26 +3409,35 @@ u_int type; } else { ATOMIC_INCL(ips_stats.iss_logfail); } -} #endif +} #ifdef USE_INET6 -frentry_t *fr_checkicmp6matchingstate(ip, fin) -ip6_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkicmp6matchingstate */ +/* Returns: ipstate_t* - NULL == no match found, */ +/* else pointer to matching state entry */ +/* Parameters: fin(I) - pointer to packet information */ +/* Locks: NULL == no locks, else Read Lock on ipf_state */ +/* */ +/* If we've got an ICMPv6 error message, using the information stored in */ +/* the ICMPv6 packet, look for a matching state table entry. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_checkicmp6matchingstate(fin) fr_info_t *fin; { - register ipstate_t *is, **isp; - register u_short sport, dport; - register u_char pr; - struct icmp6_hdr *ic, *oic; - union i6addr dst, src; + struct icmp6_hdr *ic6, *oic; + int type, backward, i; + ipstate_t *is, **isp; + u_short sport, dport; + i6addr_t dst, src; u_short savelen; + icmpinfo_t *ic; fr_info_t ofin; tcphdr_t *tcp; - frentry_t *fr; - ip6_t *oip; - int type; + ip6_t *oip6; + u_char pr; u_int hv; /* @@ -2169,8 +3447,9 @@ fr_info_t *fin; */ if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN)) return NULL; - ic = (struct icmp6_hdr *)fin->fin_dp; - type = ic->icmp6_type; + + ic6 = fin->fin_dp; + type = ic6->icmp6_type; /* * If it's not an error type, then return */ @@ -2178,22 +3457,17 @@ fr_info_t *fin; (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_TCP) && (oip->ip6_nxt != IPPROTO_UDP) && - (oip->ip6_nxt != IPPROTO_ICMPV6)) + oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN); + if (fin->fin_plen < sizeof(*oip6)) return NULL; - bzero((char *)&ofin, sizeof(ofin)); - ofin.fin_out = !fin->fin_out; - ofin.fin_ifp = fin->fin_ifp; - ofin.fin_mp = NULL; + bcopy((char *)fin, (char *)&ofin, sizeof(fin)); ofin.fin_v = 6; -#if SOLARIS - ofin.fin_qfm = NULL; -#endif + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_m = NULL; /* if dereferenced, panic XXX */ + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + /* * We make a fin entry to be able to feed it to * matchsrcdst. Note that not all fields are necessary @@ -2201,16 +3475,20 @@ fr_info_t *fin; * 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 + * watch out here, as ip is in host order and oip6 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; - fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); - oip->ip6_plen = savelen; - - if (oip->ip6_nxt == IPPROTO_ICMPV6) { - oic = (struct icmp6_hdr *)(oip + 1); + savelen = oip6->ip6_plen; + oip6->ip6_plen = fin->fin_dlen - ICMPERR_ICMPHLEN; + ofin.fin_flx = FI_NOCKSUM; + ofin.fin_ip = (ip_t *)oip6; + ofin.fin_plen = oip6->ip6_plen; + (void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin); + ofin.fin_flx &= ~(FI_BAD|FI_SHORT); + oip6->ip6_plen = savelen; + + if (oip6->ip6_nxt == IPPROTO_ICMPV6) { + oic = (struct icmp6_hdr *)(oip6 + 1); /* * an ICMP error can only be generated as a result of an * ICMP query, not as the response on an ICMP error @@ -2224,61 +3502,71 @@ fr_info_t *fin; /* * perform a lookup of the ICMP packet in the state table */ - hv = (pr = oip->ip6_nxt); - src.in6 = oip->ip6_src; + hv = (pr = oip6->ip6_nxt); + src.in6 = oip6->ip6_src; hv += src.in4.s_addr; - dst.in6 = oip->ip6_dst; + dst.in6 = oip6->ip6_dst; hv += dst.in4.s_addr; hv += oic->icmp6_id; hv += oic->icmp6_seq; - hv %= fr_statesize; + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + ic = &is->is_icmp; + 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)) { + !(is->is_pass & FR_NOICMPERR) && + (oic->icmp6_id == ic->ici_id) && + (oic->icmp6_seq == ic->ici_seq) && + (is = fr_matchsrcdst(&ofin, is, &src, + &dst, NULL, FI_ICMPCMP))) { /* * 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) && + if (((ic->ici_type == ICMP6_ECHO_REPLY) && (oic->icmp6_type == ICMP6_ECHO_REQUEST)) || - (is->is_type - 1 == oic->icmp6_type )) { + (ic->ici_type - 1 == oic->icmp6_type )) { ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += fin->fin_plen; - return is->is_rule; + backward = IP6_NEQ(&is->is_dst, &src); + fin->fin_rev = !backward; + i = (backward << 1) + fin->fin_out; + is->is_icmppkts[i]++; + return is; } } + } RWLOCK_EXIT(&ipf_state); - 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; + hv = (pr = oip6->ip6_nxt); + src.in6 = oip6->ip6_src; + hv += src.i6[0]; hv += src.i6[1]; hv += src.i6[2]; hv += src.i6[3]; - dst.in6 = oip->ip6_dst; - hv += dst.in4.s_addr; + dst.in6 = oip6->ip6_dst; + hv += dst.i6[0]; hv += dst.i6[1]; hv += dst.i6[2]; hv += dst.i6[3]; - hv += dport; - hv += sport; - hv %= fr_statesize; + + if ((oip6->ip6_nxt == IPPROTO_TCP) || (oip6->ip6_nxt == IPPROTO_UDP)) { + tcp = (tcphdr_t *)(oip6 + 1); + dport = tcp->th_dport; + sport = tcp->th_sport; + hv += dport; + hv += sport; + } else + tcp = NULL; + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; /* * Only allow this icmp though if the * encapsulated packet was allowed through the @@ -2286,22 +3574,229 @@ 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) && (is->is_v == 6) && - fr_matchsrcdst(is, src, dst, &ofin, tcp)) { - fr = is->is_rule; + if ((is->is_p != pr) || (is->is_v != 6) || + (is->is_pass & FR_NOICMPERR)) + continue; + is = fr_matchsrcdst(&ofin, is, &src, &dst, tcp, FI_ICMPCMP); + if (is != NULL) { ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += fin->fin_plen; + backward = IP6_NEQ(&is->is_dst, &src); + fin->fin_rev = !backward; + i = (backward << 1) + fin->fin_out; + is->is_icmppkts[i]++; /* * 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; + return is; } } RWLOCK_EXIT(&ipf_state); return NULL; } #endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_sttab_init */ +/* Returns: Nil */ +/* Parameters: tqp(I) - pointer to an array of timeout queues for TCP */ +/* */ +/* Initialise the array of timeout queues for TCP. */ +/* ------------------------------------------------------------------------ */ +void fr_sttab_init(tqp) +ipftq_t *tqp; +{ + int i; + + for (i = IPF_TCP_NSTATES - 1; i >= 0; i--) { + tqp[i].ifq_ttl = 0; + tqp[i].ifq_ref = 1; + tqp[i].ifq_head = NULL; + tqp[i].ifq_tail = &tqp[i].ifq_head; + tqp[i].ifq_next = tqp + i + 1; + MUTEX_INIT(&tqp[i].ifq_lock, "ipftq tcp tab"); + } + tqp[IPF_TCP_NSTATES - 1].ifq_next = NULL; + tqp[IPF_TCPS_CLOSED].ifq_ttl = fr_tcpclosed; + tqp[IPF_TCPS_LISTEN].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_SYN_SENT].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_SYN_RECEIVED].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_ESTABLISHED].ifq_ttl = fr_tcpidletimeout; + tqp[IPF_TCPS_CLOSE_WAIT].ifq_ttl = fr_tcphalfclosed; + tqp[IPF_TCPS_FIN_WAIT_1].ifq_ttl = fr_tcphalfclosed; + tqp[IPF_TCPS_CLOSING].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_LAST_ACK].ifq_ttl = fr_tcplastack; + tqp[IPF_TCPS_FIN_WAIT_2].ifq_ttl = fr_tcpclosewait; + tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = fr_tcptimeout; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_sttab_destroy */ +/* Returns: Nil */ +/* Parameters: tqp(I) - pointer to an array of timeout queues for TCP */ +/* */ +/* Do whatever is necessary to "destroy" each of the entries in the array */ +/* of timeout queues for TCP. */ +/* ------------------------------------------------------------------------ */ +void fr_sttab_destroy(tqp) +ipftq_t *tqp; +{ + int i; + + for (i = IPF_TCP_NSTATES - 1; i >= 0; i--) + MUTEX_DESTROY(&tqp[i].ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_statederef */ +/* Returns: Nil */ +/* Parameters: isp(I) - pointer to pointer to state table entry */ +/* */ +/* Decrement the reference counter for this state table entry and free it */ +/* if there are no more things using it. */ +/* */ +/* When operating in userland (ipftest), we have no timers to clear a state */ +/* entry. Therefore, we make a few simple tests before deleting an entry */ +/* outright. We compare states on each side looking for a combination of */ +/* TIME_WAIT (should really be FIN_WAIT_2?) and LAST_ACK. Then we factor */ +/* in packet direction with the interface list to make sure we don't */ +/* prematurely delete an entry on a final inbound packet that's we're also */ +/* supposed to route elsewhere. */ +/* */ +/* Internal parameters: */ +/* state[0] = state of source (host that initiated connection) */ +/* state[1] = state of dest (host that accepted the connection) */ +/* */ +/* dir == 0 : a packet from source to dest */ +/* dir == 1 : a packet from dest to source */ +/* ------------------------------------------------------------------------ */ +void fr_statederef(fin, isp) +fr_info_t *fin; +ipstate_t **isp; +{ + ipstate_t *is = *isp; +#if 0 + int nstate, ostate, dir, eol; + + eol = 0; /* End-of-the-line flag. */ + dir = fin->fin_rev; + ostate = is->is_state[1 - dir]; + nstate = is->is_state[dir]; + /* + * Determine whether this packet is local or routed. State entries + * with us as the destination will have an interface list of + * int1,-,-,int1. Entries with us as the origin run as -,int1,int1,-. + */ + if ((fin->fin_p == IPPROTO_TCP) && (fin->fin_out == 0)) { + if ((strcmp(is->is_ifname[0], is->is_ifname[3]) == 0) && + (strcmp(is->is_ifname[1], is->is_ifname[2]) == 0)) { + if ((dir == 0) && + (strcmp(is->is_ifname[1], "-") == 0) && + (strcmp(is->is_ifname[0], "-") != 0)) { + eol = 1; + } else if ((dir == 1) && + (strcmp(is->is_ifname[0], "-") == 0) && + (strcmp(is->is_ifname[1], "-") != 0)) { + eol = 1; + } + } + } +#endif + + fin = fin; /* LINT */ + is = *isp; + *isp = NULL; + WRITE_ENTER(&ipf_state); + is->is_ref--; + if (is->is_ref == 0) { + is->is_ref++; /* To counter ref-- in fr_delstate() */ + fr_delstate(is, ISL_EXPIRE); +#ifndef _KERNEL +#if 0 + } else if (((fin->fin_out == 1) || (eol == 1)) && + ((ostate == IPF_TCPS_LAST_ACK) && + (nstate == IPF_TCPS_TIME_WAIT))) { + ; +#else + } else if ((is->is_sti.tqe_state[0] > IPF_TCPS_ESTABLISHED) || + (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) { +#endif + fr_delstate(is, ISL_ORPHAN); +#endif + } + RWLOCK_EXIT(&ipf_state); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_setstatequeue */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure */ +/* rev(I) - forward(0) or reverse(1) direction */ +/* Locks: ipf_state (read or write) */ +/* */ +/* Put the state entry on its default queue entry, using rev as a helped in */ +/* determining which queue it should be placed on. */ +/* ------------------------------------------------------------------------ */ +void fr_setstatequeue(is, rev) +ipstate_t *is; +int rev; +{ + ipftq_t *oifq, *nifq; + + + if ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) + nifq = is->is_tqehead[rev]; + else + nifq = NULL; + + if (nifq == NULL) { + switch (is->is_p) + { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + if (rev == 1) + nifq = &ips_icmpacktq; + else + nifq = &ips_icmptq; + break; +#endif + case IPPROTO_ICMP : + if (rev == 1) + nifq = &ips_icmpacktq; + else + nifq = &ips_icmptq; + break; + case IPPROTO_TCP : + nifq = ips_tqtqb + is->is_state[rev]; + break; + + case IPPROTO_UDP : + if (rev == 1) + nifq = &ips_udpacktq; + else + nifq = &ips_udptq; + break; + + default : + nifq = &ips_iptq; + break; + } + } + + oifq = is->is_sti.tqe_ifq; + /* + * If it's currently on a timeout queue, move it from one queue to + * another, else put it on the end of the newly determined queue. + */ + if (oifq != NULL) + fr_movequeue(&is->is_sti, oifq, nifq); + else + fr_queueappend(&is->is_sti, nifq, is); + return; +} diff --git a/contrib/ipfilter/ip_state.h b/contrib/ipfilter/ip_state.h index d155302..2f5f7f1 100644 --- a/contrib/ipfilter/ip_state.h +++ b/contrib/ipfilter/ip_state.h @@ -1,20 +1,24 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1995-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 2.13.2.14 2003/11/15 11:47:46 darrenr Exp $ + * Id: ip_state.h,v 2.68.2.3 2005/03/03 14:24:11 darrenr Exp */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ #if defined(__STDC__) || defined(__GNUC__) -# define SIOCDELST _IOW('r', 61, struct ipstate *) +# define SIOCDELST _IOW('r', 61, struct ipfobj) #else -# define SIOCDELST _IOW(r, 61, struct ipstate *) +# define SIOCDELST _IOW(r, 61, struct ipfobj) #endif +struct ipscan; + #ifndef IPSTATE_SIZE # define IPSTATE_SIZE 5737 #endif @@ -28,54 +32,34 @@ (s2).s_addr, (d2).s_addr) -typedef struct udpstate { - u_short us_sport; - u_short us_dport; -} udpstate_t; - -typedef struct icmpstate { - u_short ics_id; - u_short ics_seq; - u_char ics_type; -} icmpstate_t; - -typedef struct tcpdata { - u_32_t td_end; - u_32_t td_maxend; - u_32_t td_maxwin; - u_char td_wscale; -} tcpdata_t; - -typedef struct tcpstate { - u_short ts_sport; - u_short ts_dport; - tcpdata_t ts_data[2]; - u_char ts_state[2]; -} tcpstate_t; - typedef struct ipstate { + ipfmutex_t is_lock; struct ipstate *is_next; struct ipstate **is_pnext; struct ipstate *is_hnext; struct ipstate **is_phnext; struct ipstate **is_me; + void *is_ifp[4]; + void *is_sync; + struct nat *is_nat[2]; frentry_t *is_rule; - U_QUAD_T is_pkts; - U_QUAD_T is_bytes; - U_QUAD_T is_icmppkts; - union i6addr is_src; - union i6addr is_dst; - void *is_ifp[4]; - u_long is_age; - u_int is_frage[2]; /* age from filter rule, forward & reverse */ + struct ipftq *is_tqehead[2]; + struct ipscan *is_isc; + U_QUAD_T is_pkts[4]; + U_QUAD_T is_bytes[4]; + U_QUAD_T is_icmppkts[4]; + struct ipftqent is_sti; + u_int is_frage[2]; + int is_ref; /* reference count */ + int is_isninc[2]; + u_short is_sumd[2]; + i6addr_t is_src; + i6addr_t is_dst; u_int is_pass; u_char is_p; /* Protocol */ - u_char is_v; /* IP version */ - u_char is_fsm; /* 1 = following FSM, 0 = not */ - u_char is_xxx; /* pad */ - u_int is_hv; /* hash value for this in the table */ - u_32_t is_rulen; /* rule number */ - u_32_t is_flags; /* flags for this structure */ + u_char is_v; + u_32_t is_hv; + u_32_t is_tag; u_32_t is_opt; /* packet options set */ u_32_t is_optmsk; /* " " mask */ u_short is_sec; /* security options set */ @@ -83,37 +67,74 @@ typedef struct ipstate { u_short is_auth; /* authentication options set */ u_short is_authmsk; /* " " mask */ union { - icmpstate_t is_ics; - tcpstate_t is_ts; - udpstate_t is_us; + icmpinfo_t is_ics; + tcpinfo_t is_ts; + udpinfo_t is_us; + greinfo_t is_ug; } is_ps; - u_32_t is_group; - char is_ifname[4][IFNAMSIZ]; -#if SOLARIS || defined(__sgi) - kmutex_t is_lock; -#endif + u_32_t is_flags; + int is_flx[2][2]; + u_32_t is_rulen; /* rule number when created */ + u_32_t is_s0[2]; + u_short is_smsk[2]; + char is_group[FR_GROUPLEN]; + char is_sbuf[2][16]; + char is_ifname[4][LIFNAMSIZ]; } ipstate_t; +#define is_die is_sti.tqe_die +#define is_state is_sti.tqe_state +#define is_touched is_sti.tqe_touched #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_type is_icmp.ici_type +#define is_code is_icmp.ici_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_swscale is_tcp.ts_data[0].td_wscale -#define is_dwscale is_tcp.ts_data[1].td_wscale #define is_maxsend is_tcp.ts_data[0].td_maxend #define is_maxdend is_tcp.ts_data[1].td_maxend +#define is_swinscale is_tcp.ts_data[0].td_winscale +#define is_dwinscale is_tcp.ts_data[1].td_winscale +#define is_swinflags is_tcp.ts_data[0].td_winflags +#define is_dwinflags is_tcp.ts_data[1].td_winflags #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[2] +#define is_gre is_ps.is_ug +#define is_call is_gre.gs_call + +#define IS_WSPORT SI_W_SPORT /* 0x00100 */ +#define IS_WDPORT SI_W_DPORT /* 0x00200 */ +#define IS_WSADDR SI_W_SADDR /* 0x00400 */ +#define IS_WDADDR SI_W_DADDR /* 0x00800 */ +#define IS_NEWFR SI_NEWFR /* 0x01000 */ +#define IS_CLONE SI_CLONE /* 0x02000 */ +#define IS_CLONED SI_CLONED /* 0x04000 */ +#define IS_TCPFSM 0x10000 +#define IS_STRICT 0x20000 +#define IS_ISNSYN 0x40000 +#define IS_ISNACK 0x80000 +#define IS_STATESYNC 0x100000 +/* + * IS_SC flags are for scan-operations that need to be recognised in state. + */ +#define IS_SC_CLIENT 0x10000000 +#define IS_SC_SERVER 0x20000000 +#define IS_SC_MATCHC 0x40000000 +#define IS_SC_MATCHS 0x80000000 +#define IS_SC_MATCHALL (IS_SC_MATCHC|IS_SC_MATCHC) +#define IS_SC_ALL (IS_SC_MATCHC|IS_SC_MATCHC|IS_SC_CLIENT|IS_SC_SERVER) + +/* + * Flags that can be passed into fr_addstate + */ +#define IS_INHERITED 0x0fffff00 #define TH_OPENING (TH_SYN|TH_ACK) /* @@ -123,6 +144,8 @@ typedef struct ipstate { * Bits 4 - 7 are set from the initial packet and contain what the packet * anded with bits 0-3 must match. * Bits 8,9 are used to indicate wildcard source/destination port matching. + * Bits 10,11 are reserved for other wildcard flag compatibility. + * Bits 12,13 are for scaning. */ typedef struct ipstate_save { @@ -135,10 +158,11 @@ typedef struct ipstate_save { typedef struct ipslog { - U_QUAD_T isl_pkts; - U_QUAD_T isl_bytes; - union i6addr isl_src; - union i6addr isl_dst; + U_QUAD_T isl_pkts[4]; + U_QUAD_T isl_bytes[4]; + i6addr_t isl_src; + i6addr_t isl_dst; + u_32_t isl_tag; u_short isl_type; union { u_short isl_filler[2]; @@ -150,23 +174,28 @@ typedef struct ipslog { u_char isl_flags; u_char isl_state[2]; u_32_t isl_rulen; - u_32_t isl_group; + char isl_group[FR_GROUPLEN]; } ipslog_t; #define isl_sport isl_ps.isl_ports[0] #define isl_dport isl_ps.isl_ports[1] #define isl_itype isl_ps.isl_icmp -#define ISL_NEW 0 -#define ISL_EXPIRE 0xffff -#define ISL_FLUSH 0xfffe -#define ISL_REMOVE 0xfffd +#define ISL_NEW 0 +#define ISL_CLONE 1 +#define ISL_EXPIRE 0xffff +#define ISL_FLUSH 0xfffe +#define ISL_REMOVE 0xfffd +#define ISL_INTERMEDIATE 0xfffc +#define ISL_KILLED 0xfffb +#define ISL_ORPHAN 0xfffa typedef struct ips_stat { u_long iss_hits; u_long iss_miss; u_long iss_max; + u_long iss_maxref; u_long iss_tcp; u_long iss_udp; u_long iss_icmp; @@ -177,8 +206,15 @@ typedef struct ips_stat { u_long iss_logged; u_long iss_logfail; u_long iss_inuse; + u_long iss_wild; + u_long iss_killed; + u_long iss_ticks; + u_long iss_bucketfull; + int iss_statesize; + int iss_statemax; ipstate_t **iss_table; ipstate_t *iss_list; + u_long *iss_bucketlen; } ips_stat_t; @@ -192,21 +228,34 @@ extern u_long fr_udptimeout; extern u_long fr_udpacktimeout; extern u_long fr_icmptimeout; extern u_long fr_icmpacktimeout; -extern ipstate_t *ips_list; +extern u_long fr_iptimeout; +extern int fr_statemax; +extern int fr_statesize; extern int fr_state_lock; +extern int fr_state_maxbucket; +extern int fr_state_maxbucket_reset; +extern ipstate_t *ips_list; +extern ipftq_t *ips_utqe; +extern ipftq_t ips_tqtqb[IPF_TCP_NSTATES]; + 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 *, ipstate_t **, u_int)); -extern frentry_t *fr_checkstate __P((ip_t *, fr_info_t *)); -extern void ip_statesync __P((void *)); +extern ipstate_t *fr_addstate __P((fr_info_t *, ipstate_t **, u_int)); +extern frentry_t *fr_checkstate __P((struct fr_info *, u_32_t *)); +extern ipstate_t *fr_stlookup __P((fr_info_t *, tcphdr_t *, ipftq_t **)); +extern void fr_statesync __P((void *)); extern void fr_timeoutstate __P((void)); -extern int fr_tcp_age __P((u_long *, u_char *, fr_info_t *, int, int)); +extern int fr_tcp_age __P((struct ipftqent *, struct fr_info *, + struct ipftq *, int)); +extern int fr_tcpinwindow __P((struct fr_info *, struct tcpdata *, + struct tcpdata *, tcphdr_t *, int)); extern void fr_stateunload __P((void)); extern void ipstate_log __P((struct ipstate *, u_int)); -#if defined(__NetBSD__) || defined(__OpenBSD__) -extern int fr_state_ioctl __P((caddr_t, u_long, int)); -#else -extern int fr_state_ioctl __P((caddr_t, int, int)); -#endif +extern int fr_state_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern void fr_stinsert __P((struct ipstate *, int)); +extern void fr_sttab_init __P((struct ipftq *)); +extern void fr_sttab_destroy __P((struct ipftq *)); +extern void fr_updatestate __P((fr_info_t *, ipstate_t *, ipftq_t *)); +extern void fr_statederef __P((fr_info_t *, ipstate_t **)); +extern void fr_setstatequeue __P((ipstate_t *, int)); #endif /* __IP_STATE_H__ */ diff --git a/contrib/ipfilter/ip_sync.c b/contrib/ipfilter/ip_sync.c new file mode 100644 index 0000000..396bae7 --- /dev/null +++ b/contrib/ipfilter/ip_sync.c @@ -0,0 +1,1001 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1995-1998 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#if !defined(_KERNEL) && !defined(__KERNEL__) +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# define _KERNEL +# define KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL +# undef KERNEL +#else +# include <sys/systm.h> +# if !defined(__SVR4) && !defined(__svr4__) +# include <sys/mbuf.h> +# endif +#endif +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) +# include <sys/proc.h> +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) +# include <sys/filio.h> +# include <sys/fcntl.h> +# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif +#else +# include <sys/ioctl.h> +#endif +#include <sys/time.h> +#if !defined(linux) +# include <sys/protosw.h> +#endif +#include <sys/socket.h> +#if defined(__SVR4) || defined(__svr4__) +# include <sys/filio.h> +# include <sys/byteorder.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif +# include <sys/stream.h> +# include <sys/kmem.h> +#endif + +#include <net/if.h> +#ifdef sun +# include <net/af.h> +#endif +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#if !defined(linux) +# include <netinet/ip_var.h> +#endif +#if !defined(__hpux) && !defined(linux) +# include <netinet/tcp_fsm.h> +#endif +#include <netinet/udp.h> +#include <netinet/ip_icmp.h> +#include "netinet/ip_compat.h" +#include <netinet/tcpip.h> +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_sync.h" +#ifdef USE_INET6 +#include <netinet/icmp6.h> +#endif +#if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include <sys/libkern.h> +# include <sys/systm.h> +# endif +#endif +/* END OF INCLUDES */ + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: ip_sync.c,v 2.40.2.3 2005/02/18 13:06:29 darrenr Exp"; +#endif + +#define SYNC_STATETABSZ 256 +#define SYNC_NATTABSZ 256 + +#ifdef IPFILTER_SYNC +ipfmutex_t ipf_syncadd, ipsl_mutex; +ipfrwlock_t ipf_syncstate, ipf_syncnat; +#if SOLARIS && defined(_KERNEL) +kcondvar_t ipslwait; +#endif +synclist_t *syncstatetab[SYNC_STATETABSZ]; +synclist_t *syncnattab[SYNC_NATTABSZ]; +synclogent_t synclog[SYNCLOG_SZ]; +syncupdent_t syncupd[SYNCLOG_SZ]; +u_int ipf_syncnum = 1; +u_int ipf_syncwrap = 0; +u_int sl_idx = 0, /* next available sync log entry */ + su_idx = 0, /* next available sync update entry */ + sl_tail = 0, /* next sync log entry to read */ + su_tail = 0; /* next sync update entry to read */ +int ipf_sync_debug = 0; + + +# if !defined(sparc) && !defined(__hppa) +void ipfsync_tcporder __P((int, struct tcpdata *)); +void ipfsync_natorder __P((int, struct nat *)); +void ipfsync_storder __P((int, struct ipstate *)); +# endif + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_init */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: Nil */ +/* */ +/* Initialise all of the locks required for the sync code and initialise */ +/* any data structures, as required. */ +/* ------------------------------------------------------------------------ */ +int ipfsync_init() +{ + RWLOCK_INIT(&ipf_syncstate, "add things to state sync table"); + RWLOCK_INIT(&ipf_syncnat, "add things to nat sync table"); + MUTEX_INIT(&ipf_syncadd, "add things to sync table"); + MUTEX_INIT(&ipsl_mutex, "add things to sync table"); +# if SOLARIS && defined(_KERNEL) + cv_init(&ipslwait, "ipsl condvar", CV_DRIVER, NULL); +# endif + + bzero((char *)syncnattab, sizeof(syncnattab)); + bzero((char *)syncstatetab, sizeof(syncstatetab)); + + return 0; +} + + +# if !defined(sparc) && !defined(__hppa) +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_tcporder */ +/* Returns: Nil */ +/* Parameters: way(I) - direction of byte order conversion. */ +/* td(IO) - pointer to data to be converted. */ +/* */ +/* Do byte swapping on values in the TCP state information structure that */ +/* need to be used at both ends by the host in their native byte order. */ +/* ------------------------------------------------------------------------ */ +void ipfsync_tcporder(way, td) +int way; +tcpdata_t *td; +{ + if (way) { + td->td_maxwin = htons(td->td_maxwin); + td->td_end = htonl(td->td_end); + td->td_maxend = htonl(td->td_maxend); + } else { + td->td_maxwin = ntohs(td->td_maxwin); + td->td_end = ntohl(td->td_end); + td->td_maxend = ntohl(td->td_maxend); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_natorder */ +/* Returns: Nil */ +/* Parameters: way(I) - direction of byte order conversion. */ +/* nat(IO) - pointer to data to be converted. */ +/* */ +/* Do byte swapping on values in the NAT data structure that need to be */ +/* used at both ends by the host in their native byte order. */ +/* ------------------------------------------------------------------------ */ +void ipfsync_natorder(way, n) +int way; +nat_t *n; +{ + if (way) { + n->nat_age = htonl(n->nat_age); + n->nat_flags = htonl(n->nat_flags); + n->nat_ipsumd = htonl(n->nat_ipsumd); + n->nat_use = htonl(n->nat_use); + n->nat_dir = htonl(n->nat_dir); + } else { + n->nat_age = ntohl(n->nat_age); + n->nat_flags = ntohl(n->nat_flags); + n->nat_ipsumd = ntohl(n->nat_ipsumd); + n->nat_use = ntohl(n->nat_use); + n->nat_dir = ntohl(n->nat_dir); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_storder */ +/* Returns: Nil */ +/* Parameters: way(I) - direction of byte order conversion. */ +/* ips(IO) - pointer to data to be converted. */ +/* */ +/* Do byte swapping on values in the IP state data structure that need to */ +/* be used at both ends by the host in their native byte order. */ +/* ------------------------------------------------------------------------ */ +void ipfsync_storder(way, ips) +int way; +ipstate_t *ips; +{ + ipfsync_tcporder(way, &ips->is_tcp.ts_data[0]); + ipfsync_tcporder(way, &ips->is_tcp.ts_data[1]); + + if (way) { + ips->is_hv = htonl(ips->is_hv); + ips->is_die = htonl(ips->is_die); + ips->is_pass = htonl(ips->is_pass); + ips->is_flags = htonl(ips->is_flags); + ips->is_opt = htonl(ips->is_opt); + ips->is_optmsk = htonl(ips->is_optmsk); + ips->is_sec = htons(ips->is_sec); + ips->is_secmsk = htons(ips->is_secmsk); + ips->is_auth = htons(ips->is_auth); + ips->is_authmsk = htons(ips->is_authmsk); + ips->is_s0[0] = htonl(ips->is_s0[0]); + ips->is_s0[1] = htonl(ips->is_s0[1]); + ips->is_smsk[0] = htons(ips->is_smsk[0]); + ips->is_smsk[1] = htons(ips->is_smsk[1]); + } else { + ips->is_hv = ntohl(ips->is_hv); + ips->is_die = ntohl(ips->is_die); + ips->is_pass = ntohl(ips->is_pass); + ips->is_flags = ntohl(ips->is_flags); + ips->is_opt = ntohl(ips->is_opt); + ips->is_optmsk = ntohl(ips->is_optmsk); + ips->is_sec = ntohs(ips->is_sec); + ips->is_secmsk = ntohs(ips->is_secmsk); + ips->is_auth = ntohs(ips->is_auth); + ips->is_authmsk = ntohs(ips->is_authmsk); + ips->is_s0[0] = ntohl(ips->is_s0[0]); + ips->is_s0[1] = ntohl(ips->is_s0[1]); + ips->is_smsk[0] = ntohl(ips->is_smsk[0]); + ips->is_smsk[1] = ntohl(ips->is_smsk[1]); + } +} +# else /* !defined(sparc) && !defined(__hppa) */ +# define ipfsync_tcporder(x,y) +# define ipfsync_natorder(x,y) +# define ipfsync_storder(x,y) +# endif /* !defined(sparc) && !defined(__hppa) */ + +/* enable this for debugging */ + +# ifdef _KERNEL +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_write */ +/* Returns: int - 0 == success, else error value. */ +/* Parameters: uio(I) - pointer to information about data to write */ +/* */ +/* Moves data from user space into the kernel and uses it for updating data */ +/* structures in the state/NAT tables. */ +/* ------------------------------------------------------------------------ */ +int ipfsync_write(uio) +struct uio *uio; +{ + synchdr_t sh; + + /* + * THIS MUST BE SUFFICIENT LARGE TO STORE + * ANY POSSIBLE DATA TYPE + */ + char data[2048]; + + int err = 0; + +# if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__) + uio->uio_rw = UIO_WRITE; +# endif + + /* Try to get bytes */ + while (uio->uio_resid > 0) { + + if (uio->uio_resid >= sizeof(sh)) { + + err = UIOMOVE((caddr_t)&sh, sizeof(sh), UIO_WRITE, uio); + + if (err) { + if (ipf_sync_debug > 2) + printf("uiomove(header) failed: %d\n", + err); + return err; + } + + /* convert to host order */ + sh.sm_magic = ntohl(sh.sm_magic); + sh.sm_len = ntohl(sh.sm_len); + sh.sm_num = ntohl(sh.sm_num); + + if (ipf_sync_debug > 8) + printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n", + sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd, + sh.sm_table, sh.sm_rev, sh.sm_len, + sh.sm_magic); + + if (sh.sm_magic != SYNHDRMAGIC) { + if (ipf_sync_debug > 2) + printf("uiomove(header) invalud %s\n", + "magic"); + return EINVAL; + } + + if (sh.sm_v != 4 && sh.sm_v != 6) { + if (ipf_sync_debug > 2) + printf("uiomove(header) invalid %s\n", + "protocol"); + return EINVAL; + } + + if (sh.sm_cmd > SMC_MAXCMD) { + if (ipf_sync_debug > 2) + printf("uiomove(header) invalid %s\n", + "command"); + return EINVAL; + } + + + if (sh.sm_table > SMC_MAXTBL) { + if (ipf_sync_debug > 2) + printf("uiomove(header) invalid %s\n", + "table"); + return EINVAL; + } + + } else { + /* unsufficient data, wait until next call */ + if (ipf_sync_debug > 2) + printf("uiomove(header) insufficient data"); + return EAGAIN; + } + + + /* + * We have a header, so try to read the amount of data + * needed for the request + */ + + /* not supported */ + if (sh.sm_len == 0) { + if (ipf_sync_debug > 2) + printf("uiomove(data zero length %s\n", + "not supported"); + return EINVAL; + } + + if (uio->uio_resid >= sh.sm_len) { + + err = UIOMOVE((caddr_t)data, sh.sm_len, UIO_WRITE, uio); + + if (err) { + if (ipf_sync_debug > 2) + printf("uiomove(data) failed: %d\n", + err); + return err; + } + + if (ipf_sync_debug > 7) + printf("uiomove(data) %d bytes read\n", + sh.sm_len); + + if (sh.sm_table == SMC_STATE) + err = ipfsync_state(&sh, data); + else if (sh.sm_table == SMC_NAT) + err = ipfsync_nat(&sh, data); + if (ipf_sync_debug > 7) + printf("[%d] Finished with error %d\n", + sh.sm_num, err); + + } else { + /* insufficient data, wait until next call */ + if (ipf_sync_debug > 2) + printf("uiomove(data) %s %d bytes, got %d\n", + "insufficient data, need", + sh.sm_len, uio->uio_resid); + return EAGAIN; + } + } + + /* no more data */ + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_read */ +/* Returns: int - 0 == success, else error value. */ +/* Parameters: uio(O) - pointer to information about where to store data */ +/* */ +/* This function is called when a user program wants to read some data */ +/* for pending state/NAT updates. If no data is available, the caller is */ +/* put to sleep, pending a wakeup from the "lower half" of this code. */ +/* ------------------------------------------------------------------------ */ +int ipfsync_read(uio) +struct uio *uio; +{ + syncupdent_t *su; + synclogent_t *sl; + int err = 0; + + if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) + return EINVAL; + +# if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__) + uio->uio_rw = UIO_READ; +# endif + + MUTEX_ENTER(&ipsl_mutex); + while ((sl_tail == sl_idx) && (su_tail == su_idx)) { +# if SOLARIS && defined(_KERNEL) + if (!cv_wait_sig(&ipslwait, &ipsl_mutex)) { + MUTEX_EXIT(&ipsl_mutex); + return EINTR; + } +# else +# ifdef __hpux + { + lock_t *l; + + l = get_sleep_lock(&sl_tail); + err = sleep(&sl_tail, PZERO+1); + spinunlock(l); + } +# else /* __hpux */ +# ifdef __osf__ + err = mpsleep(&sl_tail, PSUSP|PCATCH, "ipl sleep", 0, + &ipsl_mutex, MS_LOCK_SIMPLE); +# else + MUTEX_EXIT(&ipsl_mutex); + err = SLEEP(&sl_tail, "ipl sleep"); +# endif /* __osf__ */ +# endif /* __hpux */ + if (err) { + MUTEX_EXIT(&ipsl_mutex); + return err; + } +# endif /* SOLARIS */ + } + MUTEX_EXIT(&ipsl_mutex); + + READ_ENTER(&ipf_syncstate); + while ((sl_tail < sl_idx) && (uio->uio_resid > sizeof(*sl))) { + sl = synclog + sl_tail++; + err = UIOMOVE((caddr_t)sl, sizeof(*sl), UIO_READ, uio); + if (err != 0) + break; + } + + while ((su_tail < su_idx) && (uio->uio_resid > sizeof(*su))) { + su = syncupd + su_tail; + su_tail++; + err = UIOMOVE((caddr_t)su, sizeof(*su), UIO_READ, uio); + if (err != 0) + break; + if (su->sup_hdr.sm_sl != NULL) + su->sup_hdr.sm_sl->sl_idx = -1; + } + + MUTEX_ENTER(&ipf_syncadd); + if (su_tail == su_idx) + su_tail = su_idx = 0; + if (sl_tail == sl_idx) + sl_tail = sl_idx = 0; + MUTEX_EXIT(&ipf_syncadd); + RWLOCK_EXIT(&ipf_syncstate); + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_state */ +/* Returns: int - 0 == success, else error value. */ +/* Parameters: sp(I) - pointer to sync packet data header */ +/* uio(I) - pointer to user data for further information */ +/* */ +/* Updates the state table according to information passed in the sync */ +/* header. As required, more data is fetched from the uio structure but */ +/* varies depending on the contents of the sync header. This function can */ +/* create a new state entry or update one. Deletion is left to the state */ +/* structures being timed out correctly. */ +/* ------------------------------------------------------------------------ */ +int ipfsync_state(sp, data) +synchdr_t *sp; +void *data; +{ + synctcp_update_t su; + ipstate_t *is, sn; + synclist_t *sl; + frentry_t *fr; + u_int hv; + int err = 0; + + hv = sp->sm_num & (SYNC_STATETABSZ - 1); + + switch (sp->sm_cmd) + { + case SMC_CREATE : + + bcopy(data, &sn, sizeof(sn)); + KMALLOC(is, ipstate_t *); + if (is == NULL) { + err = ENOMEM; + break; + } + + KMALLOC(sl, synclist_t *); + if (sl == NULL) { + err = ENOMEM; + KFREE(is); + break; + } + + bzero((char *)is, offsetof(ipstate_t, is_die)); + bcopy((char *)&sn.is_die, (char *)&is->is_die, + sizeof(*is) - offsetof(ipstate_t, is_die)); + ipfsync_storder(0, is); + + /* + * We need to find the same rule on the slave as was used on + * the master to create this state entry. + */ + READ_ENTER(&ipf_mutex); + fr = fr_getrulen(IPL_LOGIPF, sn.is_group, sn.is_rulen); + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + fr->fr_statecnt++; + MUTEX_EXIT(&fr->fr_lock); + } + RWLOCK_EXIT(&ipf_mutex); + + if (ipf_sync_debug > 4) + printf("[%d] Filter rules = %p\n", sp->sm_num, fr); + + is->is_rule = fr; + is->is_sync = sl; + + sl->sl_idx = -1; + sl->sl_ips = is; + bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr)); + + WRITE_ENTER(&ipf_syncstate); + WRITE_ENTER(&ipf_state); + + sl->sl_pnext = syncstatetab + hv; + sl->sl_next = syncstatetab[hv]; + if (syncstatetab[hv] != NULL) + syncstatetab[hv]->sl_pnext = &sl->sl_next; + syncstatetab[hv] = sl; + MUTEX_DOWNGRADE(&ipf_syncstate); + fr_stinsert(is, sp->sm_rev); + /* + * Do not initialise the interface pointers for the state + * entry as the full complement of interface names may not + * be present. + * + * Put this state entry on its timeout queue. + */ + /*fr_setstatequeue(is, sp->sm_rev);*/ + break; + + case SMC_UPDATE : + bcopy(data, &su, sizeof(su)); + + if (ipf_sync_debug > 4) + printf("[%d] Update age %lu state %d/%d \n", + sp->sm_num, su.stu_age, su.stu_state[0], + su.stu_state[1]); + + READ_ENTER(&ipf_syncstate); + for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next) + if (sl->sl_hdr.sm_num == sp->sm_num) + break; + if (sl == NULL) { + if (ipf_sync_debug > 1) + printf("[%d] State not found - can't update\n", + sp->sm_num); + RWLOCK_EXIT(&ipf_syncstate); + err = ENOENT; + break; + } + + READ_ENTER(&ipf_state); + + if (ipf_sync_debug > 6) + printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n", + sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p, + sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table, + sl->sl_hdr.sm_rev); + + is = sl->sl_ips; + + MUTEX_ENTER(&is->is_lock); + switch (sp->sm_p) + { + case IPPROTO_TCP : + /* XXX FV --- shouldn't we do ntohl/htonl???? XXX */ + is->is_send = su.stu_data[0].td_end; + is->is_maxsend = su.stu_data[0].td_maxend; + is->is_maxswin = su.stu_data[0].td_maxwin; + is->is_state[0] = su.stu_state[0]; + is->is_dend = su.stu_data[1].td_end; + is->is_maxdend = su.stu_data[1].td_maxend; + is->is_maxdwin = su.stu_data[1].td_maxwin; + is->is_state[1] = su.stu_state[1]; + break; + default : + break; + } + + if (ipf_sync_debug > 6) + printf("[%d] Setting timers for state\n", sp->sm_num); + + fr_setstatequeue(is, sp->sm_rev); + + MUTEX_EXIT(&is->is_lock); + break; + + default : + err = EINVAL; + break; + } + + if (err == 0) { + RWLOCK_EXIT(&ipf_state); + RWLOCK_EXIT(&ipf_syncstate); + } + + if (ipf_sync_debug > 6) + printf("[%d] Update completed with error %d\n", + sp->sm_num, err); + + return err; +} +# endif /* _KERNEL */ + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_del */ +/* Returns: Nil */ +/* Parameters: sl(I) - pointer to synclist object to delete */ +/* */ +/* Deletes an object from the synclist table and free's its memory. */ +/* ------------------------------------------------------------------------ */ +void ipfsync_del(sl) +synclist_t *sl; +{ + WRITE_ENTER(&ipf_syncstate); + *sl->sl_pnext = sl->sl_next; + if (sl->sl_next != NULL) + sl->sl_next->sl_pnext = sl->sl_pnext; + if (sl->sl_idx != -1) + syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL; + RWLOCK_EXIT(&ipf_syncstate); + KFREE(sl); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_nat */ +/* Returns: int - 0 == success, else error value. */ +/* Parameters: sp(I) - pointer to sync packet data header */ +/* uio(I) - pointer to user data for further information */ +/* */ +/* Updates the NAT table according to information passed in the sync */ +/* header. As required, more data is fetched from the uio structure but */ +/* varies depending on the contents of the sync header. This function can */ +/* create a new NAT entry or update one. Deletion is left to the NAT */ +/* structures being timed out correctly. */ +/* ------------------------------------------------------------------------ */ +int ipfsync_nat(sp, data) +synchdr_t *sp; +void *data; +{ + synclogent_t sle; + syncupdent_t su; + nat_t *n, *nat; + synclist_t *sl; + u_int hv = 0; + int err; + + READ_ENTER(&ipf_syncstate); + + switch (sp->sm_cmd) + { + case SMC_CREATE : + bcopy(data, &sle, sizeof(sle)); + + KMALLOC(n, nat_t *); + if (n == NULL) { + err = ENOMEM; + break; + } + + KMALLOC(sl, synclist_t *); + if (sl == NULL) { + err = ENOMEM; + KFREE(n); + break; + } + + WRITE_ENTER(&ipf_nat); + + nat = &sle.sle_un.sleu_ipn; + bzero((char *)n, offsetof(nat_t, nat_age)); + bcopy((char *)&nat->nat_age, (char *)&n->nat_age, + sizeof(*n) - offsetof(nat_t, nat_age)); + ipfsync_natorder(0, n); + n->nat_sync = sl; + + sl->sl_idx = -1; + sl->sl_ipn = n; + sl->sl_num = ntohl(sp->sm_num); + sl->sl_pnext = syncstatetab + hv; + sl->sl_next = syncstatetab[hv]; + if (syncstatetab[hv] != NULL) + syncstatetab[hv]->sl_pnext = &sl->sl_next; + syncstatetab[hv] = sl; + nat_insert(n, sl->sl_rev); + RWLOCK_EXIT(&ipf_nat); + break; + + case SMC_UPDATE : + bcopy(data, &su, sizeof(su)); + + READ_ENTER(&ipf_syncstate); + for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next) + if (sl->sl_hdr.sm_num == sp->sm_num) + break; + if (sl == NULL) { + err = ENOENT; + break; + } + + READ_ENTER(&ipf_nat); + + nat = sl->sl_ipn; + + MUTEX_ENTER(&nat->nat_lock); + fr_setnatqueue(nat, sl->sl_rev); + MUTEX_EXIT(&nat->nat_lock); + + RWLOCK_EXIT(&ipf_nat); + + break; + + default : + err = EINVAL; + break; + } + + RWLOCK_EXIT(&ipf_syncstate); + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_new */ +/* Returns: synclist_t* - NULL == failure, else pointer to new synclist */ +/* data structure. */ +/* Parameters: tab(I) - type of synclist_t to create */ +/* fin(I) - pointer to packet information */ +/* ptr(I) - pointer to owning object */ +/* */ +/* Creates a new sync table entry and notifies any sleepers that it's there */ +/* waiting to be processed. */ +/* ------------------------------------------------------------------------ */ +synclist_t *ipfsync_new(tab, fin, ptr) +int tab; +fr_info_t *fin; +void *ptr; +{ + synclist_t *sl, *ss; + synclogent_t *sle; + u_int hv, sz; + + if (sl_idx == SYNCLOG_SZ) + return NULL; + KMALLOC(sl, synclist_t *); + if (sl == NULL) + return NULL; + + MUTEX_ENTER(&ipf_syncadd); + /* + * Get a unique number for this synclist_t. The number is only meant + * to be unique for the lifetime of the structure and may be reused + * later. + */ + ipf_syncnum++; + if (ipf_syncnum == 0) { + ipf_syncnum = 1; + ipf_syncwrap = 1; + } + + hv = ipf_syncnum & (SYNC_STATETABSZ - 1); + while (ipf_syncwrap != 0) { + for (ss = syncstatetab[hv]; ss; ss = ss->sl_next) + if (ss->sl_hdr.sm_num == ipf_syncnum) + break; + if (ss == NULL) + break; + ipf_syncnum++; + hv = ipf_syncnum & (SYNC_STATETABSZ - 1); + } + /* + * Use the synch number of the object as the hash key. Should end up + * with relatively even distribution over time. + * XXX - an attacker could lunch an DoS attack, of sorts, if they are + * the only one causing new table entries by only keeping open every + * nth connection they make, where n is a value in the interval + * [0, SYNC_STATETABSZ-1]. + */ + sl->sl_pnext = syncstatetab + hv; + sl->sl_next = syncstatetab[hv]; + syncstatetab[hv] = sl; + sl->sl_num = ipf_syncnum; + MUTEX_EXIT(&ipf_syncadd); + + sl->sl_magic = htonl(SYNHDRMAGIC); + sl->sl_v = fin->fin_v; + sl->sl_p = fin->fin_p; + sl->sl_cmd = SMC_CREATE; + sl->sl_idx = -1; + sl->sl_table = tab; + sl->sl_rev = fin->fin_rev; + if (tab == SMC_STATE) { + sl->sl_ips = ptr; + sz = sizeof(*sl->sl_ips); + } else if (tab == SMC_NAT) { + sl->sl_ipn = ptr; + sz = sizeof(*sl->sl_ipn); + } else { + ptr = NULL; + sz = 0; + } + sl->sl_len = sz; + + /* + * Create the log entry to be read by a user daemon. When it has been + * finished and put on the queue, send a signal to wakeup any waiters. + */ + MUTEX_ENTER(&ipf_syncadd); + sle = synclog + sl_idx++; + bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr, + sizeof(sle->sle_hdr)); + sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num); + sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len); + if (ptr != NULL) { + bcopy((char *)ptr, (char *)&sle->sle_un, sz); + if (tab == SMC_STATE) { + ipfsync_storder(1, &sle->sle_un.sleu_ips); + } else if (tab == SMC_NAT) { + ipfsync_natorder(1, &sle->sle_un.sleu_ipn); + } + } + MUTEX_EXIT(&ipf_syncadd); + + MUTEX_ENTER(&ipsl_mutex); +# if SOLARIS +# ifdef _KERNEL + cv_signal(&ipslwait); +# endif + MUTEX_EXIT(&ipsl_mutex); +# else + MUTEX_EXIT(&ipsl_mutex); +# ifdef _KERNEL + wakeup(&sl_tail); +# endif +# endif + return sl; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipfsync_update */ +/* Returns: Nil */ +/* Parameters: tab(I) - type of synclist_t to create */ +/* fin(I) - pointer to packet information */ +/* sl(I) - pointer to synchronisation object */ +/* */ +/* For outbound packets, only, create an sync update record for the user */ +/* process to read. */ +/* ------------------------------------------------------------------------ */ +void ipfsync_update(tab, fin, sl) +int tab; +fr_info_t *fin; +synclist_t *sl; +{ + synctcp_update_t *st; + syncupdent_t *slu; + ipstate_t *ips; + nat_t *nat; + + if (fin->fin_out == 0 || sl == NULL) + return; + + WRITE_ENTER(&ipf_syncstate); + MUTEX_ENTER(&ipf_syncadd); + if (sl->sl_idx == -1) { + slu = syncupd + su_idx; + sl->sl_idx = su_idx++; + bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr, + sizeof(slu->sup_hdr)); + slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC); + slu->sup_hdr.sm_sl = sl; + slu->sup_hdr.sm_cmd = SMC_UPDATE; + slu->sup_hdr.sm_table = tab; + slu->sup_hdr.sm_num = htonl(sl->sl_num); + slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update)); + slu->sup_hdr.sm_rev = fin->fin_rev; +# if 0 + if (fin->fin_p == IPPROTO_TCP) { + st->stu_len[0] = 0; + st->stu_len[1] = 0; + } +# endif + } else + slu = syncupd + sl->sl_idx; + MUTEX_EXIT(&ipf_syncadd); + MUTEX_DOWNGRADE(&ipf_syncstate); + + /* + * Only TCP has complex timeouts, others just use default timeouts. + * For TCP, we only need to track the connection state and window. + */ + if (fin->fin_p == IPPROTO_TCP) { + st = &slu->sup_tcp; + if (tab == SMC_STATE) { + ips = sl->sl_ips; + st->stu_age = htonl(ips->is_die); + st->stu_data[0].td_end = ips->is_send; + st->stu_data[0].td_maxend = ips->is_maxsend; + st->stu_data[0].td_maxwin = ips->is_maxswin; + st->stu_state[0] = ips->is_state[0]; + st->stu_data[1].td_end = ips->is_dend; + st->stu_data[1].td_maxend = ips->is_maxdend; + st->stu_data[1].td_maxwin = ips->is_maxdwin; + st->stu_state[1] = ips->is_state[1]; + } else if (tab == SMC_NAT) { + nat = sl->sl_ipn; + st->stu_age = htonl(nat->nat_age); + } + } + RWLOCK_EXIT(&ipf_syncstate); + + MUTEX_ENTER(&ipsl_mutex); +# if SOLARIS +# ifdef _KERNEL + cv_signal(&ipslwait); +# endif + MUTEX_EXIT(&ipsl_mutex); +# else + MUTEX_EXIT(&ipsl_mutex); +# ifdef _KERNEL + wakeup(&sl_tail); +# endif +# endif +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_sync_ioctl */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* cmd(I) - ioctl command integer */ +/* mode(I) - file mode bits used with open */ +/* */ +/* This function currently does not handle any ioctls and so just returns */ +/* EINVAL on all occasions. */ +/* ------------------------------------------------------------------------ */ +int fr_sync_ioctl(data, cmd, mode) +caddr_t data; +ioctlcmd_t cmd; +int mode; +{ + return EINVAL; +} +#endif /* IPFILTER_SYNC */ diff --git a/contrib/ipfilter/ip_sync.h b/contrib/ipfilter/ip_sync.h new file mode 100644 index 0000000..e319a95 --- /dev/null +++ b/contrib/ipfilter/ip_sync.h @@ -0,0 +1,117 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * @(#)ip_fil.h 1.35 6/5/96 + * Id: ip_sync.h,v 2.11.2.2 2004/11/04 19:29:07 darrenr Exp + */ + +#ifndef __IP_SYNC_H__ +#define __IP_SYNC_H__ + +typedef struct synchdr { + u_32_t sm_magic; /* magic */ + u_char sm_v; /* version: 4,6 */ + u_char sm_p; /* protocol */ + u_char sm_cmd; /* command */ + u_char sm_table; /* NAT, STATE, etc */ + u_int sm_num; /* table entry number */ + int sm_rev; /* forward/reverse */ + int sm_len; /* length of the data section */ + struct synclist *sm_sl; /* back pointer to parent */ +} synchdr_t; + + +#define SYNHDRMAGIC 0x0FF51DE5 + +/* + * Commands + * No delete required as expirey will take care of that! + */ +#define SMC_CREATE 0 /* pass ipstate_t after synchdr_t */ +#define SMC_UPDATE 1 +#define SMC_MAXCMD 1 + +/* + * Tables + */ +#define SMC_NAT 0 +#define SMC_STATE 1 +#define SMC_MAXTBL 1 + + +/* + * Only TCP requires "more" information than just a reference to the entry + * for which an update is being made. + */ +typedef struct synctcp_update { + u_long stu_age; + tcpdata_t stu_data[2]; + int stu_state[2]; +} synctcp_update_t; + + +typedef struct synclist { + struct synclist *sl_next; + struct synclist **sl_pnext; + int sl_idx; /* update index */ + struct synchdr sl_hdr; + union { + struct ipstate *slu_ips; + struct nat *slu_ipn; + void *slu_ptr; + } sl_un; +} synclist_t; + +#define sl_ptr sl_un.slu_ptr +#define sl_ips sl_un.slu_ips +#define sl_ipn sl_un.slu_ipn +#define sl_magic sl_hdr.sm_magic +#define sl_v sl_hdr.sm_v +#define sl_p sl_hdr.sm_p +#define sl_cmd sl_hdr.sm_cmd +#define sl_rev sl_hdr.sm_rev +#define sl_table sl_hdr.sm_table +#define sl_num sl_hdr.sm_num +#define sl_len sl_hdr.sm_len + +/* + * NOTE: SYNCLOG_SZ is defined *low*. It should be the next power of two + * up for whatever number of packets per second you expect to see. Be + * warned: this index's a table of large elements (upto 272 bytes in size + * each), and thus a size of 8192, for example, results in a 2MB table. + * The lesson here is not to use small machines for running fast firewalls + * (100BaseT) in sync, where you might have upwards of 10k pps. + */ +#define SYNCLOG_SZ 256 + +typedef struct synclogent { + struct synchdr sle_hdr; + union { + struct ipstate sleu_ips; + struct nat sleu_ipn; + } sle_un; +} synclogent_t; + +typedef struct syncupdent { /* 28 or 32 bytes */ + struct synchdr sup_hdr; + struct synctcp_update sup_tcp; +} syncupdent_t; + +extern synclogent_t synclog[SYNCLOG_SZ]; + + +extern int fr_sync_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern synclist_t *ipfsync_new __P((int, fr_info_t *, void *)); +extern void ipfsync_del __P((synclist_t *)); +extern void ipfsync_update __P((int, fr_info_t *, synclist_t *)); +extern int ipfsync_init __P((void)); +extern int ipfsync_nat __P((synchdr_t *sp, void *data)); +extern int ipfsync_state __P((synchdr_t *sp, void *data)); +extern int ipfsync_read __P((struct uio *uio)); +extern int ipfsync_write __P((struct uio *uio)); + +#endif /* IP_SYNC */ diff --git a/contrib/ipfilter/ipf.h b/contrib/ipfilter/ipf.h index 9260d03f..1398c05 100644 --- a/contrib/ipfilter/ipf.h +++ b/contrib/ipfilter/ipf.h @@ -1,72 +1,124 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ipf.h 1.12 6/5/96 - * $Id: ipf.h,v 2.9.2.7 2003/05/15 17:45:33 darrenr Exp $ + * Id: ipf.h,v 2.71.2.6 2005/02/21 05:05:29 darrenr Exp */ #ifndef __IPF_H__ #define __IPF_H__ -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#if defined(__osf__) +# define radix_mask ipf_radix_mask +# define radix_node ipf_radix_node +# define radix_node_head ipf_radix_node_head +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/file.h> +/* + * This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD. + * Needed here because on some systems <sys/uio.h> gets included by things + * like <sys/socket.h> + */ +#ifndef _KERNEL +# define ADD_KERNEL +# define _KERNEL +# define KERNEL +#endif +#ifdef __OpenBSD__ +struct file; +#endif +#include <sys/uio.h> +#ifdef ADD_KERNEL +# undef _KERNEL +# undef KERNEL +#endif +#include <sys/time.h> +#include <sys/socket.h> +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#ifndef TCP_PAWS_IDLE /* IRIX */ +# include <netinet/tcp.h> #endif -#define OPT_REMOVE 0x000001 -#define OPT_DEBUG 0x000002 -#define OPT_OUTQUE FR_OUTQUE /* 0x00004 */ -#define OPT_INQUE FR_INQUE /* 0x00008 */ -#define OPT_LOG FR_LOG /* 0x00010 */ -#define OPT_SHOWLIST 0x000020 -#define OPT_VERBOSE 0x000040 -#define OPT_DONOTHING 0x000080 -#define OPT_HITS 0x000100 -#define OPT_BRIEF 0x000200 -#define OPT_ACCNT FR_ACCOUNT /* 0x0400 */ -#define OPT_FRSTATES FR_KEEPFRAG /* 0x0800 */ -#define OPT_IPSTATES FR_KEEPSTATE /* 0x1000 */ -#define OPT_INACTIVE FR_INACTIVE /* 0x2000 */ -#define OPT_SHOWLINENO 0x004000 -#define OPT_PRINTFR 0x008000 -#define OPT_ZERORULEST 0x010000 -#define OPT_SAVEOUT 0x020000 -#define OPT_AUTHSTATS 0x040000 -#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_HEX 0x2000000 -#define OPT_NODO 0x80000000 - -#define OPT_STAT OPT_FRSTATES -#define OPT_LIST OPT_SHOWLIST +#include <netinet/udp.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#if !defined(__SVR4) && !defined(__svr4__) && defined(sun) +# include <strings.h> +#endif +#include <string.h> +#include <unistd.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_auth.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_scan.h" +#include "netinet/ip_htable.h" +#include "netinet/ip_sync.h" + +#include "opts.h" #ifndef __P -# ifdef __STDC__ +# ifdef __STDC__ # define __P(x) x # else # define __P(x) () # endif #endif +#ifndef __STDC__ +# undef const +# define const +#endif -struct ipstate; -struct frpcmp; -struct ipnat; -struct nat; +#ifndef U_32_T +# define U_32_T 1 +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ + defined(__sgi) +typedef u_int32_t u_32_t; +# else +# if defined(__alpha__) || defined(__alpha) || defined(_LP64) +typedef unsigned int u_32_t; +# else +# if SOLARIS2 >= 6 +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; +# endif +# endif +# endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */ +#endif /* U_32_T */ -#ifdef ultrix -extern char *strdup __P((char *)); +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 #endif -extern struct frentry *parse __P((char *, int, int *)); - -extern void printfr __P((struct frentry *)); -extern void binprint __P((struct frentry *)), initparse __P((void)); -extern int portnum __P((char *, u_short *, int)); +#define MAX_ICMPCODE 16 +#define MAX_ICMPTYPE 19 struct ipopt_names { @@ -77,47 +129,178 @@ struct ipopt_names { }; -extern char *proto; +typedef struct alist_s { + struct alist_s *al_next; + int al_not; + i6addr_t al_i6addr; + i6addr_t al_i6mask; +} alist_t; + +#define al_addr al_i6addr.in4_addr +#define al_mask al_i6mask.in4_addr +#define al_1 al_addr +#define al_2 al_mask + + +typedef struct { + u_short fb_c; + u_char fb_t; + u_char fb_f; + u_32_t fb_k; +} fakebpf_t; + + +#if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ + SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux) +# include <stdarg.h> +typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...)); +#else +typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *)); +#endif +typedef void (* addfunc_t) __P((int, ioctlfunc_t, void *)); +typedef int (* copyfunc_t) __P((void *, void *, size_t)); + + +/* + * SunOS4 + */ +#if defined(sun) && !defined(__SVR4) && !defined(__svr4__) +extern int ioctl __P((int, int, void *)); +#endif + +extern char thishost[]; extern char flagset[]; extern u_char flags[]; +extern struct ipopt_names ionames[]; +extern struct ipopt_names secclass[]; +extern char *icmpcodes[MAX_ICMPCODE + 1]; +extern char *icmptypes[MAX_ICMPTYPE + 1]; +extern int use_inet6; +extern int lineNum; +extern struct ipopt_names v6ionames[]; -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 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 printpacket6 __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)); -extern char *hostname __P((int, void *)); -extern struct ipstate *printstate __P((struct ipstate *, int)); -extern void printnat __P((struct ipnat *, int)); -extern void printactivenat __P((struct nat *, int)); -#if SOLARIS -extern int inet_aton __P((const char *, struct in_addr *)); -extern int gethostname __P((char *, int )); -extern void sync __P((void)); +extern int addicmp __P((char ***, struct frentry *, int)); +extern int addipopt __P((char *, struct ipopt_names *, int, char *)); +extern int addkeep __P((char ***, struct frentry *, int)); +extern int bcopywrap __P((void *, void *, size_t)); +extern void binprint __P((void *, size_t)); +extern void initparse __P((void)); +extern u_32_t buildopts __P((char *, char *, int)); +extern int checkrev __P((char *)); +extern int count6bits __P((u_32_t *)); +extern int count4bits __P((u_32_t)); +extern int extras __P((char ***, struct frentry *, int)); +extern char *fac_toname __P((int)); +extern int fac_findname __P((char *)); +extern void fill6bits __P((int, u_int *)); +extern int gethost __P((char *, u_32_t *)); +extern int getport __P((struct frentry *, char *, u_short *)); +extern int getportproto __P((char *, int)); +extern int getproto __P((char *)); +extern char *getline __P((char *, size_t, FILE *, int *)); +extern int genmask __P((char *, u_32_t *)); +extern char *getnattype __P((struct ipnat *)); +extern char *getsumd __P((u_32_t)); +extern u_32_t getoptbyname __P((char *)); +extern u_32_t getoptbyvalue __P((int)); +extern u_32_t getv6optbyname __P((char *)); +extern u_32_t getv6optbyvalue __P((int)); +extern void hexdump __P((FILE *, void *, int, int)); +extern int hostmask __P((char ***, char *, char *, u_32_t *, u_32_t *, int)); +extern int hostnum __P((u_32_t *, char *, int, char *)); +extern int icmpcode __P((char *)); +extern int icmpidnum __P((char *, u_short *, int)); +extern void initparse __P((void)); +extern void ipf_dotuning __P((int, char *, ioctlfunc_t)); +extern void ipf_addrule __P((int, ioctlfunc_t, void *)); +extern int ipf_parsefile __P((int, addfunc_t, ioctlfunc_t *, char *)); +extern int ipf_parsesome __P((int, addfunc_t, ioctlfunc_t *, FILE *)); +extern int ipmon_parsefile __P((char *)); +extern int ipmon_parsesome __P((FILE *)); +extern void ipnat_addrule __P((int, ioctlfunc_t, void *)); +extern int ipnat_parsefile __P((int, addfunc_t, ioctlfunc_t, char *)); +extern int ipnat_parsesome __P((int, addfunc_t, ioctlfunc_t, FILE *)); +extern int ippool_parsefile __P((int, char *, ioctlfunc_t)); +extern int ippool_parsesome __P((int, FILE *, ioctlfunc_t)); +extern int kmemcpywrap __P((void *, void *, size_t)); +extern char *kvatoname __P((ipfunc_t, ioctlfunc_t)); +extern int load_hash __P((struct iphtable_s *, struct iphtent_s *, + ioctlfunc_t)); +extern int load_hashnode __P((int, char *, struct iphtent_s *, ioctlfunc_t)); +extern int load_pool __P((struct ip_pool_s *list, ioctlfunc_t)); +extern int load_poolnode __P((int, char *, ip_pool_node_t *, ioctlfunc_t)); +extern int loglevel __P((char **, u_int *, int)); +extern alist_t *make_range __P((int, struct in_addr, struct in_addr)); +extern ipfunc_t nametokva __P((char *, ioctlfunc_t)); +extern ipnat_t *natparse __P((char *, int)); +extern void natparsefile __P((int, char *, int)); +extern void nat_setgroupmap __P((struct ipnat *)); +extern int ntomask __P((int, int, u_32_t *)); +extern u_32_t optname __P((char ***, u_short *, int)); +extern struct frentry *parse __P((char *, int)); +extern char *portname __P((int, int)); +extern int portnum __P((char *, char *, u_short *, int)); +extern int ports __P((char ***, char *, u_short *, int *, u_short *, int)); +extern int pri_findname __P((char *)); +extern char *pri_toname __P((int)); +extern void print_toif __P((char *, struct frdest *)); +extern void printaps __P((ap_session_t *, int)); +extern void printbuf __P((char *, int, int)); +extern void printfr __P((struct frentry *, ioctlfunc_t)); +extern void printtunable __P((ipftune_t *)); +extern struct iphtable_s *printhash __P((struct iphtable_s *, copyfunc_t, + char *, int)); +extern struct iphtent_s *printhashnode __P((struct iphtable_s *, + struct iphtent_s *, + copyfunc_t, int)); +extern void printhostmask __P((int, u_32_t *, u_32_t *)); +extern void printip __P((u_32_t *)); +extern void printlog __P((struct frentry *)); +extern void printlookup __P((i6addr_t *addr, i6addr_t *mask)); +extern void printmask __P((u_32_t *)); +extern void printpacket __P((struct ip *)); +extern void printpacket6 __P((struct ip *)); +extern struct ip_pool_s *printpool __P((struct ip_pool_s *, copyfunc_t, + char *, int)); +extern struct ip_pool_node *printpoolnode __P((struct ip_pool_node *, int)); +extern void printportcmp __P((int, struct frpcmp *)); +extern void optprint __P((u_short *, u_long, u_long)); +#ifdef USE_INET6 +extern void optprintv6 __P((u_short *, u_long, u_long)); #endif +extern int ratoi __P((char *, int *, int, int)); +extern int ratoui __P((char *, u_int *, u_int, u_int)); +extern int remove_hash __P((struct iphtable_s *, ioctlfunc_t)); +extern int remove_hashnode __P((int, char *, struct iphtent_s *, ioctlfunc_t)); +extern int remove_pool __P((ip_pool_t *, ioctlfunc_t)); +extern int remove_poolnode __P((int, char *, ip_pool_node_t *, ioctlfunc_t)); +extern u_char tcp_flags __P((char *, u_char *, int)); +extern u_char tcpflags __P((char *)); +extern int to_interface __P((struct frdest *, char *, int)); +extern void printc __P((struct frentry *)); +extern void printC __P((int)); +extern void emit __P((int, int, void *, struct frentry *)); +extern u_char secbit __P((int)); +extern u_char seclevel __P((char *)); +extern void printfraginfo __P((char *, struct ipfr *)); +extern void printifname __P((char *, char *, void *)); +extern char *hostname __P((int, void *)); +extern struct ipstate *printstate __P((struct ipstate *, int, u_long)); +extern void printsbuf __P((char *)); +extern void printnat __P((struct ipnat *, int)); +extern void printactivenat __P((struct nat *, int)); +extern void printhostmap __P((struct hostmap *, u_int)); +extern void printpacket __P((struct ip *)); -#if defined(sun) && !SOLARIS -# define STRERROR(x) sys_errlist[x] -extern char *sys_errlist[]; -#else -# define STRERROR(x) strerror(x) -#endif +extern void set_variable __P((char *, char *)); +extern char *get_variable __P((char *, char **, int)); +extern void resetlexer __P((void)); -#ifndef MIN -#define MIN(a,b) ((a) > (b) ? (b) : (a)) +#if SOLARIS +extern int gethostname __P((char *, int )); +extern void sync __P((void)); #endif #endif /* __IPF_H__ */ diff --git a/contrib/ipfilter/ipl.h b/contrib/ipfilter/ipl.h index b975ee9..7e90820 100644 --- a/contrib/ipfilter/ipl.h +++ b/contrib/ipfilter/ipl.h @@ -1,15 +1,19 @@ +/* $NetBSD$ */ + /* - * Copyright (C) 1993-2002 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.44 2004/06/03 17:28:20 darrenr Exp $ + * Id: ipl.h,v 2.52.2.9 2005/03/30 14:14:05 darrenr Exp */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.35" +#define IPL_VERSION "IP Filter: v4.1.8" + +#define IPFILTER_VERSION 4010800 #endif diff --git a/contrib/ipfilter/iplang/.cvsignore b/contrib/ipfilter/iplang/.cvsignore new file mode 100644 index 0000000..68b5b4e --- /dev/null +++ b/contrib/ipfilter/iplang/.cvsignore @@ -0,0 +1,9 @@ +y.tab.h +y.output +lex.yy.c +y.tab.c +y.tab.o +lex.yy.o +iplang_y.output +iplang_y.tab.c +iplang_y.tab.h diff --git a/contrib/ipfilter/iplang/Makefile b/contrib/ipfilter/iplang/Makefile index f97bf19..5b53e9a 100644 --- a/contrib/ipfilter/iplang/Makefile +++ b/contrib/ipfilter/iplang/Makefile @@ -1,36 +1,31 @@ # -# 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. +# See the IPFILTER.LICENCE file for details on licencing. # #CC=gcc -Wuninitialized -Wstrict-prototypes -Werror -O CFLAGS=-I.. -all: $(DESTDIR)/y.tab.o $(DESTDIR)/lex.yy.o +all: $(DESTDIR)/iplang_y.o $(DESTDIR)/iplang_l.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)/iplang_y.o: $(DESTDIR)/iplang_y.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_y.c -o $@ -$(DESTDIR)/$(OBJ)/y.tab.o: $(DESTDIR)/y.tab.c - $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/y.tab.c -o $@ +$(DESTDIR)/iplang_l.o: $(DESTDIR)/iplang_l.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_l.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 $@ +iplang_y.o: iplang_y.c + $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@ -y.tab.o: y.tab.c - $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c y.tab.c -o $@ +iplang_l.o: iplang_l.c + $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@ -lex.yy.o: lex.yy.c - $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c lex.yy.c -o $@ - -$(DESTDIR)/lex.yy.c: iplang_l.l $(DESTDIR)/y.tab.h +$(DESTDIR)/iplang_l.c: iplang_l.l $(DESTDIR)/iplang_y.h lex iplang_l.l - mv lex.yy.c $(DESTDIR) + mv lex.yy.c $(DESTDIR)/iplang_l.c -$(DESTDIR)/y.tab.c $(DESTDIR)/y.tab.h: iplang_y.y +$(DESTDIR)/iplang_y.c $(DESTDIR)/iplang_y.h: iplang_y.y yacc -d iplang_y.y - mv y.tab.c $(DESTDIR) - mv y.tab.h $(DESTDIR) + mv y.tab.c $(DESTDIR)/iplang_y.c + mv y.tab.h $(DESTDIR)/iplang_y.h clean: /bin/rm -f *.o lex.yy.c y.tab.c y.tab.h diff --git a/contrib/ipfilter/iplang/iplang.h b/contrib/ipfilter/iplang/iplang.h index f36a384..675897b 100644 --- a/contrib/ipfilter/iplang/iplang.h +++ b/contrib/ipfilter/iplang/iplang.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1997-1998 by Darren Reed. * diff --git a/contrib/ipfilter/iplang/iplang_l.l b/contrib/ipfilter/iplang/iplang_l.l index cc31781..0a97ec9 100644 --- a/contrib/ipfilter/iplang/iplang_l.l +++ b/contrib/ipfilter/iplang/iplang_l.l @@ -1,12 +1,12 @@ +/* $NetBSD$ */ + %{ /* * Copyright (C) 1997-1998 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. + * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: iplang_l.l,v 2.2.2.1 2003/07/28 01:15:59 darrenr Exp $ + * Id: iplang_l.l,v 2.8 2003/07/28 01:15:31 darrenr Exp */ #include <stdio.h> #include <string.h> @@ -17,8 +17,7 @@ #include <sys/types.h> #include <netinet/in_systm.h> #include <netinet/in.h> -#include "y.tab.h" -#include "ip_compat.h" +#include "iplang_y.h" #include "ipf.h" #ifndef __P @@ -43,13 +42,13 @@ int save_token __P((void)); void swallow __P((void)); int yylex __P((void)); -struct wordtab { +struct lwordtab { char *word; int state; int next; }; -struct wordtab words[] = { +struct lwordtab words[] = { { "interface", IL_INTERFACE, -1 }, { "iface", IL_INTERFACE, -1 }, { "name", IL_IFNAME, IL_TOKEN }, @@ -217,7 +216,7 @@ void pop_proto() int save_token() { - yylval.str = strdup(yytext); + yylval.str = strdup((char *)yytext); return IL_TOKEN; } @@ -225,7 +224,7 @@ int save_token() int next_item(nstate) int nstate; { - struct wordtab *wt; + struct lwordtab *wt; if (opts & OPT_DEBUG) printf("text=[%s] id=%d next=%d\n", yytext, nstate, next); @@ -236,13 +235,13 @@ int nstate; token++; for (wt = words; wt->word; wt++) - if (!strcasecmp(wt->word, yytext)) + if (!strcasecmp(wt->word, (char *)yytext)) return next_state(wt->state, wt->next); if (opts & OPT_DEBUG) printf("unknown keyword=[%s]\n", yytext); next = -1; if (nstate == IL_NUMBER) - yylval.num = atoi(yytext); + yylval.num = atoi((char *)yytext); token++; return nstate; } diff --git a/contrib/ipfilter/iplang/iplang_y.y b/contrib/ipfilter/iplang/iplang_y.y index f536f35..fa960df 100644 --- a/contrib/ipfilter/iplang/iplang_y.y +++ b/contrib/ipfilter/iplang/iplang_y.y @@ -1,17 +1,14 @@ +/* $NetBSD$ */ + %{ /* * Copyright (C) 1997-1998 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. + * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: iplang_y.y,v 2.2.2.3 2002/12/06 11:41:14 darrenr Exp $ + * Id: iplang_y.y,v 2.9.2.2 2004/12/09 19:41:10 darrenr Exp */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> -#endif #include <stdio.h> #include <string.h> #include <fcntl.h> @@ -31,12 +28,9 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#include <netinet/ip_icmp.h> #ifndef linux #include <netinet/ip_var.h> #endif -#include <netinet/tcp.h> -#include <netinet/udp.h> #include <net/if.h> #ifndef linux #include <netinet/if_ether.h> @@ -52,7 +46,7 @@ #include "iplang.h" #if !defined(__NetBSD__) && (!defined(__FreeBSD_version) && \ - __FreeBSD_version < 400020 ) && SOLARIS2 < 10 + __FreeBSD_version < 400020) && (!SOLARIS || SOLARIS2 < 10) extern struct ether_addr *ether_aton __P((char *)); #endif @@ -773,7 +767,7 @@ char **arg; while ((c = *s++)) { if (todo) { - if (isdigit(c)) { + if (ISDIGIT(c)) { todo--; if (c > '7') { fprintf(stderr, "octal with %c!\n", c); @@ -782,7 +776,7 @@ char **arg; val <<= 3; val |= (c - '0'); } - if (!isdigit(c) || !todo) { + if (!ISDIGIT(c) || !todo) { *t++ = (u_char)(val & 0xff); todo = 0; } @@ -790,7 +784,7 @@ char **arg; continue; } if (quote) { - if (isdigit(c)) { + if (ISDIGIT(c)) { todo = 2; if (c > '7') { fprintf(stderr, "octal with %c!\n", c); @@ -1294,7 +1288,7 @@ void prep_packet() return; } if (ifp->if_fd == -1) - ifp->if_fd = initdevice(ifp->if_name, 0, 5); + ifp->if_fd = initdevice(ifp->if_name, 5); gwip = sending.snd_gw; if (!gwip.s_addr) gwip = aniphead->ah_ip->ip_dst; @@ -1326,7 +1320,7 @@ void packet_done() sprintf((char *)t, " "); t += 8; for (k = 16; k; k--, s++) - *t++ = (isprint(*s) ? *s : '.'); + *t++ = (ISPRINT(*s) ? *s : '.'); s--; } @@ -1344,7 +1338,7 @@ void packet_done() t += 7; s -= j & 0xf; for (k = j & 0xf; k; k--, s++) - *t++ = (isprint(*s) ? *s : '.'); + *t++ = (ISPRINT(*s) ? *s : '.'); *t++ = '\n'; *t = '\0'; } @@ -1518,11 +1512,6 @@ int type; } -static char *icmpcodes[] = { - "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail", - "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib", - "net-tos", "host-tos", NULL }; - void set_icmpcodetok(code) char **code; { @@ -1541,13 +1530,6 @@ char **code; } -static char *icmptypes[] = { - "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", - "redir", (char *)NULL, (char *)NULL, "echo", (char *)NULL, - (char *)NULL, "timex", "paramprob", "timest", "timestrep", - "inforeq", "inforep", "maskreq", "maskrep", "END" -}; - void set_icmptypetok(type) char **type; { diff --git a/contrib/ipfilter/ipmon.h b/contrib/ipfilter/ipmon.h new file mode 100644 index 0000000..a240836 --- /dev/null +++ b/contrib/ipfilter/ipmon.h @@ -0,0 +1,96 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * @(#)ip_fil.h 1.35 6/5/96 + * Id: ipmon.h,v 2.8 2003/07/25 22:16:20 darrenr Exp + */ + + +typedef struct ipmon_action { + struct ipmon_action *ac_next; + int ac_mflag; /* collection of things to compare */ + int ac_dflag; /* flags to compliment the doing fields */ + int ac_syslog; /* = 1 to syslog rules. */ + char *ac_savefile; /* filename to save log records to */ + FILE *ac_savefp; + int ac_direction; + char ac_group[FR_GROUPLEN]; + char ac_nattag[16]; + u_32_t ac_logtag; + int ac_type; /* nat/state/ipf */ + int ac_proto; + int ac_rule; + int ac_packet; + int ac_second; + int ac_result; + u_32_t ac_sip; + u_32_t ac_smsk; + u_32_t ac_dip; + u_32_t ac_dmsk; + u_short ac_sport; + u_short ac_dport; + char *ac_exec; /* execute argument */ + char *ac_run; /* actual command that gets run */ + char *ac_iface; + /* + * used with ac_packet/ac_second + */ + struct timeval ac_last; + int ac_pktcnt; +} ipmon_action_t; + +#define ac_lastsec ac_last.tv_sec +#define ac_lastusec ac_last.tv_usec + +/* + * Flags indicating what fields to do matching upon (ac_mflag). + */ +#define IPMAC_DIRECTION 0x0001 +#define IPMAC_DSTIP 0x0002 +#define IPMAC_DSTPORT 0x0004 +#define IPMAC_EVERY 0x0008 +#define IPMAC_GROUP 0x0010 +#define IPMAC_INTERFACE 0x0020 +#define IPMAC_LOGTAG 0x0040 +#define IPMAC_NATTAG 0x0080 +#define IPMAC_PROTOCOL 0x0100 +#define IPMAC_RESULT 0x0200 +#define IPMAC_RULE 0x0400 +#define IPMAC_SRCIP 0x0800 +#define IPMAC_SRCPORT 0x1000 +#define IPMAC_TYPE 0x2000 +#define IPMAC_WITH 0x4000 + +#define IPMR_BLOCK 1 +#define IPMR_PASS 2 +#define IPMR_NOMATCH 3 +#define IPMR_LOG 4 + +#define IPMDO_SAVERAW 0x0001 + +#define OPT_SYSLOG 0x001 +#define OPT_RESOLVE 0x002 +#define OPT_HEXBODY 0x004 +#define OPT_VERBOSE 0x008 +#define OPT_HEXHDR 0x010 +#define OPT_TAIL 0x020 +#define OPT_NAT 0x080 +#define OPT_STATE 0x100 +#define OPT_FILTER 0x200 +#define OPT_PORTNUM 0x400 +#define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) + +#define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) + +#ifndef LOGFAC +#define LOGFAC LOG_LOCAL0 +#endif + +extern int load_config __P((char *)); +extern void dumphex __P((FILE *, int, char *, int)); +extern int check_action __P((char *, char *, int, int)); +extern char *getword __P((int)); diff --git a/contrib/ipfilter/ipsd/Celler/ip_compat.h b/contrib/ipfilter/ipsd/Celler/ip_compat.h index a911fd8..8b43cb9 100644 --- a/contrib/ipfilter/ipsd/Celler/ip_compat.h +++ b/contrib/ipfilter/ipsd/Celler/ip_compat.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * (C)opyright 1995 by Darren Reed. * diff --git a/contrib/ipfilter/ipsd/Makefile b/contrib/ipfilter/ipsd/Makefile index b9ad044..0f3ce08 100644 --- a/contrib/ipfilter/ipsd/Makefile +++ b/contrib/ipfilter/ipsd/Makefile @@ -1,9 +1,7 @@ # # Copyright (C) 1993-1998 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. +# See the IPFILTER.LICENCE file for details on licencing. # OBJS=ipsd.o BINDEST=/usr/local/bin diff --git a/contrib/ipfilter/ipsd/ipsd.c b/contrib/ipfilter/ipsd/ipsd.c index 261ad89..3d9ea4c 100644 --- a/contrib/ipfilter/ipsd/ipsd.c +++ b/contrib/ipfilter/ipsd/ipsd.c @@ -1,11 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1995-1998 Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include <stdio.h> #include <fcntl.h> @@ -35,7 +34,7 @@ #ifndef lint static const char sccsid[] = "@(#)ipsd.c 1.3 12/3/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipsd.c,v 2.1.4.1 2001/06/26 10:43:21 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: ipsd.c,v 2.2 2001/06/09 17:09:25 darrenr Exp"; #endif extern char *optarg; diff --git a/contrib/ipfilter/ipsd/ipsd.h b/contrib/ipfilter/ipsd/ipsd.h index a8f58c3..48f5911 100644 --- a/contrib/ipfilter/ipsd/ipsd.h +++ b/contrib/ipfilter/ipsd/ipsd.h @@ -1,11 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1995-1998 Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * * @(#)ipsd.h 1.3 12/3/95 */ diff --git a/contrib/ipfilter/ipsd/ipsdr.c b/contrib/ipfilter/ipsd/ipsdr.c index 298f655..4689cba 100644 --- a/contrib/ipfilter/ipsd/ipsdr.c +++ b/contrib/ipfilter/ipsd/ipsdr.c @@ -1,11 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1995-1998 Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include <stdio.h> #include <fcntl.h> @@ -36,7 +35,7 @@ #ifndef lint static const char sccsid[] = "@(#)ipsdr.c 1.3 12/3/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipsdr.c,v 2.1.4.1 2001/06/26 10:43:21 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: ipsdr.c,v 2.2 2001/06/09 17:09:25 darrenr Exp"; #endif extern char *optarg; diff --git a/contrib/ipfilter/ipsd/linux.h b/contrib/ipfilter/ipsd/linux.h index d9606cb..2fadfcf 100644 --- a/contrib/ipfilter/ipsd/linux.h +++ b/contrib/ipfilter/ipsd/linux.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1997-1998 by Darren Reed. * diff --git a/contrib/ipfilter/ipsd/sbpf.c b/contrib/ipfilter/ipsd/sbpf.c index 97bb4ce..29a7200 100644 --- a/contrib/ipfilter/ipsd/sbpf.c +++ b/contrib/ipfilter/ipsd/sbpf.c @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * (C)opyright 1995-1998 Darren Reed. (from tcplog) * diff --git a/contrib/ipfilter/ipsd/sdlpi.c b/contrib/ipfilter/ipsd/sdlpi.c index c08fe69..289ad2f 100644 --- a/contrib/ipfilter/ipsd/sdlpi.c +++ b/contrib/ipfilter/ipsd/sdlpi.c @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * @@ -158,7 +160,7 @@ int tout; (void) sprintf(devname, "/dev/%s", device); s = devname + 5; - while (*s && !isdigit(*s)) + while (*s && !ISDIGIT(*s)) s++; if (!*s) { diff --git a/contrib/ipfilter/ipsd/slinux.c b/contrib/ipfilter/ipsd/slinux.c index 2c5aa97d..3b786b0 100644 --- a/contrib/ipfilter/ipsd/slinux.c +++ b/contrib/ipfilter/ipsd/slinux.c @@ -1,11 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include <stdio.h> diff --git a/contrib/ipfilter/ipsd/snit.c b/contrib/ipfilter/ipsd/snit.c index ec7178f..8f25026 100644 --- a/contrib/ipfilter/ipsd/snit.c +++ b/contrib/ipfilter/ipsd/snit.c @@ -1,11 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include <stdio.h> diff --git a/contrib/ipfilter/ipsend/.OLD/ip_compat.h b/contrib/ipfilter/ipsend/.OLD/ip_compat.h index c38fa59..3b62be1 100644 --- a/contrib/ipfilter/ipsend/.OLD/ip_compat.h +++ b/contrib/ipfilter/ipsend/.OLD/ip_compat.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * (C)opyright 1995 by Darren Reed. * diff --git a/contrib/ipfilter/ipsend/.cvsignore b/contrib/ipfilter/ipsend/.cvsignore new file mode 100644 index 0000000..b7aea24 --- /dev/null +++ b/contrib/ipfilter/ipsend/.cvsignore @@ -0,0 +1,3 @@ +ipsend +ipresend +iptest diff --git a/contrib/ipfilter/ipsend/44arp.c b/contrib/ipfilter/ipsend/44arp.c index de9f4d9..4206355 100644 --- a/contrib/ipfilter/ipsend/44arp.c +++ b/contrib/ipfilter/ipsend/44arp.c @@ -1,33 +1,37 @@ +/* $NetBSD$ */ + /* * Based upon 4.4BSD's /usr/sbin/arp */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> -#endif -#include <unistd.h> -#include <string.h> -#include <stdlib.h> #include <sys/param.h> #include <sys/file.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif #include <net/if_dl.h> #include <net/if_types.h> +#if defined(__FreeBSD__) +# include "radix_ipf.h" +#endif #include <net/route.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> #include <netdb.h> #include <errno.h> #include <nlist.h> #include <stdio.h> -#include <netinet/in.h> -#include <netinet/ip_var.h> -#include <netinet/tcp.h> -#if __FreeBSD_version >= 300000 -# include <net/if_var.h> -#endif #include "ipsend.h" #include "iplang/iplang.h" @@ -37,7 +41,7 @@ * its IP address in address * (4 bytes) */ -int resolve(host, address) +int resolve(host, address) char *host, *address; { struct hostent *hp; @@ -74,6 +78,9 @@ char *addr, *eaddr; return 0; #endif + if (!addr) + return -1; + mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; @@ -101,8 +108,8 @@ char *addr, *eaddr; rtm = (struct rt_msghdr *)next; sin = (struct sockaddr_inarp *)(rtm + 1); sdl = (struct sockaddr_dl *)(sin + 1); - if (addr && !bcmp(addr, (char *)&sin->sin_addr, - sizeof(struct in_addr))) + if (!bcmp(addr, (char *)&sin->sin_addr, + sizeof(struct in_addr))) { bcopy(LLADDR(sdl), eaddr, sdl->sdl_alen); return 0; diff --git a/contrib/ipfilter/ipsend/Makefile b/contrib/ipfilter/ipsend/Makefile index bb8000f..ed3a51e 100644 --- a/contrib/ipfilter/ipsend/Makefile +++ b/contrib/ipfilter/ipsend/Makefile @@ -1,9 +1,7 @@ # # Copyright (C) 1993-1998 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. +# See the IPFILTER.LICENCE file for details on licencing. # IPFT=ipft_ef.o ipft_hx.o ipft_pc.o ipft_sn.o ipft_td.o ipft_tx.o opt.o OBJS=ipsend.o ip.o ipsopt.o y.tab.o lex.yy.o @@ -134,6 +132,14 @@ hpux9 : make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ CFLAGS="$(CFLAGS)" "LIBS=" +hpux11 : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -DIPSEND" "LIBS=" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + ipsend: ipf $(OBJS) $(UNIXOBJS) $(CC) $(OBJS) $(UNIXOBJS) -o $@ $(LIBS) $(LLIB) $(ELIB) diff --git a/contrib/ipfilter/ipsend/arp.c b/contrib/ipfilter/ipsend/arp.c index 8e5f7f4..0e8f556 100644 --- a/contrib/ipfilter/ipsend/arp.c +++ b/contrib/ipfilter/ipsend/arp.c @@ -1,20 +1,21 @@ +/* $NetBSD$ */ + /* * arp.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "@(#)arp.c 1.4 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: arp.c,v 2.8 2003/12/01 02:01:15 darrenr Exp"; #endif -#include <stdio.h> -#include <errno.h> #include <sys/types.h> #include <sys/socket.h> -#if !defined(ultrix) && !defined(hpux) +#if !defined(ultrix) && !defined(hpux) && !defined(__hpux) && !defined(__osf__) #include <sys/sockio.h> #endif #include <sys/ioctl.h> -#include <netdb.h> +#include <netinet/in_systm.h> #include <netinet/in.h> #include <net/if.h> #include <netinet/if_ether.h> @@ -22,23 +23,22 @@ #include <net/if_arp.h> #endif #include <netinet/in.h> +#include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/tcp.h> +#include <stdio.h> +#include <errno.h> +#include <netdb.h> #include "ipsend.h" #include "iplang/iplang.h" -#if !defined(lint) -static const char sccsid[] = "@(#)arp.c 1.4 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: arp.c,v 2.1.4.4 2002/12/06 11:40:35 darrenr Exp $"; -#endif - /* * lookup host and return * its IP address in address * (4 bytes) */ -int resolve(host, address) +int resolve(host, address) char *host, *address; { struct hostent *hp; @@ -90,7 +90,11 @@ char *ether; bcopy(ip, (char *)&sin->sin_addr.s_addr, 4); #ifndef hpux if ((hp = gethostbyaddr(ip, 4, AF_INET))) +# if SOLARIS && (SOLARIS2 >= 10) + if (!(ether_hostton(hp->h_name, (struct ether_addr *)ether))) +# else if (!(ether_hostton(hp->h_name, ether))) +# endif goto savearp; #endif @@ -122,6 +126,13 @@ tryagain: return -1; } + if ((ar.arp_ha.sa_data[0] == 0) && (ar.arp_ha.sa_data[1] == 0) && + (ar.arp_ha.sa_data[2] == 0) && (ar.arp_ha.sa_data[3] == 0) && + (ar.arp_ha.sa_data[4] == 0) && (ar.arp_ha.sa_data[5] == 0)) { + fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr)); + return -1; + } + bcopy(ar.arp_ha.sa_data, ether, 6); savearp: bcopy(ether, ethersave, 6); diff --git a/contrib/ipfilter/ipsend/dlcommon.c b/contrib/ipfilter/ipsend/dlcommon.c index 59b283d..6e351f0 100644 --- a/contrib/ipfilter/ipsend/dlcommon.c +++ b/contrib/ipfilter/ipsend/dlcommon.c @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Common (shared) DLPI test routines. * Mostly pretty boring boilerplate sorta stuff. @@ -18,7 +20,11 @@ typedef unsigned long ulong; #include <sys/types.h> #include <sys/stream.h> #include <sys/stropts.h> -#include <sys/dlpi.h> +#ifdef __osf__ +# include <sys/dlpihdr.h> +#else +# include <sys/dlpi.h> +#endif #include <sys/signal.h> #include <stdio.h> #include <string.h> @@ -35,6 +41,7 @@ char *dlstyle(); char *dlmactype(); +void dlinforeq(fd) int fd; { @@ -54,6 +61,7 @@ int fd; syserr("dlinforeq: putmsg"); } +void dlinfoack(fd, bufp) int fd; char *bufp; @@ -82,6 +90,7 @@ char *bufp; err("dlinfoack: short response ctl.len: %d", ctl.len); } +void dlattachreq(fd, ppa) int fd; u_long ppa; @@ -103,6 +112,7 @@ u_long ppa; syserr("dlattachreq: putmsg"); } +void dlenabmultireq(fd, addr, length) int fd; char *addr; @@ -131,6 +141,7 @@ int length; syserr("dlenabmultireq: putmsg"); } +void dldisabmultireq(fd, addr, length) int fd; char *addr; @@ -159,6 +170,7 @@ int length; syserr("dldisabmultireq: putmsg"); } +void dlpromisconreq(fd, level) int fd; u_long level; @@ -181,6 +193,7 @@ u_long level; } +void dlpromiscoff(fd, level) int fd; u_long level; @@ -202,6 +215,7 @@ u_long level; syserr("dlpromiscoff: putmsg"); } +void dlphysaddrreq(fd, addrtype) int fd; u_long addrtype; @@ -223,6 +237,7 @@ u_long addrtype; syserr("dlphysaddrreq: putmsg"); } +void dlsetphysaddrreq(fd, addr, length) int fd; char *addr; @@ -251,6 +266,7 @@ int length; syserr("dlsetphysaddrreq: putmsg"); } +void dldetachreq(fd) int fd; { @@ -270,6 +286,7 @@ int fd; syserr("dldetachreq: putmsg"); } +void dlbindreq(fd, sap, max_conind, service_mode, conn_mgmt, xidtest) int fd; u_long sap; @@ -299,6 +316,7 @@ u_long xidtest; syserr("dlbindreq: putmsg"); } +void dlunitdatareq(fd, addrp, addrlen, minpri, maxpri, datap, datalen) int fd; u_char *addrp; @@ -333,6 +351,7 @@ int datalen; syserr("dlunitdatareq: putmsg"); } +void dlunbindreq(fd) int fd; { @@ -352,6 +371,7 @@ int fd; syserr("dlunbindreq: putmsg"); } +void dlokack(fd, bufp) int fd; char *bufp; @@ -380,6 +400,7 @@ char *bufp; err("dlokack: short response ctl.len: %d", ctl.len); } +void dlerrorack(fd, bufp) int fd; char *bufp; @@ -408,6 +429,7 @@ char *bufp; err("dlerrorack: short response ctl.len: %d", ctl.len); } +void dlbindack(fd, bufp) int fd; char *bufp; @@ -433,6 +455,7 @@ char *bufp; err("dlbindack: short response ctl.len: %d", ctl.len); } +void dlphysaddrack(fd, bufp) int fd; char *bufp; @@ -695,10 +718,11 @@ union DL_primitives *dlp; printdlerrorack(dlp) union DL_primitives *dlp; { - (void) printf("DL_ERROR_ACK: error_primitive %s errno %s unix_errno %d\n", + (void) printf("DL_ERROR_ACK: error_primitive %s errno %s unix_errno %d: %s\n", dlprim(dlp->error_ack.dl_error_primitive), dlerrno(dlp->error_ack.dl_errno), - dlp->error_ack.dl_unix_errno); + dlp->error_ack.dl_unix_errno, + strerror(dlp->error_ack.dl_unix_errno)); } printdlenabmultireq(dlp) diff --git a/contrib/ipfilter/ipsend/dltest.h b/contrib/ipfilter/ipsend/dltest.h index 4c32c30..9fafd91 100644 --- a/contrib/ipfilter/ipsend/dltest.h +++ b/contrib/ipfilter/ipsend/dltest.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Common DLPI Test Suite header file * diff --git a/contrib/ipfilter/ipsend/hpux.c b/contrib/ipfilter/ipsend/hpux.c index 463fdbf..69f962c 100644 --- a/contrib/ipfilter/ipsend/hpux.c +++ b/contrib/ipfilter/ipsend/hpux.c @@ -1,7 +1,11 @@ +/* $NetBSD$ */ + /* * (C)opyright 1997-1998 Darren Reed. (from tcplog) * - * See the IPFILTER.LICENCE file for details on licencing. + * 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 <stdio.h> #include <strings.h> diff --git a/contrib/ipfilter/ipsend/in_var.h b/contrib/ipfilter/ipsend/in_var.h index b935259..f228bbb 100644 --- a/contrib/ipfilter/ipsend/in_var.h +++ b/contrib/ipfilter/ipsend/in_var.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* @(#)in_var.h 1.3 88/08/19 SMI; from UCB 7.1 6/5/86 */ /* @@ -173,5 +175,5 @@ struct in_multistep { } struct in_multi *in_addmulti(); -#endif KERNEL +#endif /* KERNEL */ #endif /*!_netinet_in_var_h*/ diff --git a/contrib/ipfilter/ipsend/ip.c b/contrib/ipfilter/ipsend/ip.c index 8d30bf5..8302806 100644 --- a/contrib/ipfilter/ipsend/ip.c +++ b/contrib/ipfilter/ipsend/ip.c @@ -1,25 +1,21 @@ +/* $NetBSD$ */ + /* * ip.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995"; +static const char rcsid[] = "@(#)Id: ip.c,v 2.8.2.1 2004/10/19 12:31:48 darrenr Exp"; #endif -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> +#include <sys/param.h> #include <sys/types.h> #include <netinet/in_systm.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> #include <sys/param.h> #ifndef linux # include <netinet/if_ether.h> @@ -28,12 +24,13 @@ # include <net/if_var.h> # endif #endif +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] = "%W% %G% (C)1995"; -static const char rcsid[] = "@(#)$Id: ip.c,v 2.1.4.5 2002/12/06 11:40:35 darrenr Exp $"; -#endif static char *ipbuf = NULL, *ethbuf = NULL; @@ -71,7 +68,9 @@ struct in_addr gwip; bcopy((char *)buf, s + sizeof(*eh), len); if (gwip.s_addr == last_gw.s_addr) + { bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); + } else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) { perror("arp"); @@ -92,7 +91,8 @@ ip_t *ip; struct in_addr gwip; int frag; { - static struct in_addr last_gw; + static struct in_addr last_gw, local_ip; + static char local_arp[6] = { 0, 0, 0, 0, 0, 0}; static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; static u_short id = 0; ether_header_t *eh; @@ -102,7 +102,7 @@ int frag; if (!ipbuf) { ipbuf = (char *)malloc(65536); - if(!ipbuf) + if (!ipbuf) { perror("malloc failed"); return -2; @@ -113,7 +113,9 @@ int frag; bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) + { bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); + } else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) { perror("arp"); @@ -127,18 +129,25 @@ int frag; iplen = ip->ip_len; ip->ip_len = htons(iplen); if (!(frag & 2)) { - if (!ip->ip_v) - ip->ip_v = IPVERSION; + if (!IP_V(ip)) + IP_V_A(ip, IPVERSION); if (!ip->ip_id) ip->ip_id = htons(id++); if (!ip->ip_ttl) ip->ip_ttl = 60; } + if (ip->ip_src.s_addr != local_ip.s_addr) { + (void) arp((char *)&ip->ip_src, (char *)A_A local_arp); + bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp)); + local_ip = ip->ip_src; + } else + bcopy(local_arp, (char *)A_A eh->ether_shost, 6); + if (!frag || (sizeof(*eh) + iplen < mtu)) { ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); @@ -155,14 +164,14 @@ int frag; char *s; int i, sent = 0, ts, hlen, olen; - hlen = ip->ip_hl << 2; + hlen = IP_HL(ip) << 2; if (mtu < (hlen + 8)) { fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", mtu, hlen); fprintf(stderr, "can't fragment data\n"); return -2; } - ol = (ip->ip_hl << 2) - sizeof(*ip); + ol = (IP_HL(ip) << 2) - sizeof(*ip); for (i = 0, s = (char*)(ip + 1); ol > 0; ) if (*s == IPOPT_EOL) { optcpy[i++] = *s; @@ -223,7 +232,7 @@ int frag; else if (!(ip->ip_off & htons(0x1fff))) { hlen = i + sizeof(*ip); - ip->ip_hl = (sizeof(*ip) + i) >> 2; + IP_HL_A(ip, (sizeof(*ip) + i) >> 2); bcopy(optcpy, (char *)(ip + 1), i); } } @@ -243,45 +252,46 @@ ip_t *ip; struct in_addr gwip; { static tcp_seq iss = 2; - struct tcpiphdr *ti; - tcphdr_t *t; + tcphdr_t *t, *t2; int thlen, i, iplen, hlen; u_32_t lbuf[20]; + ip_t *ip2; iplen = ip->ip_len; - hlen = ip->ip_hl << 2; + hlen = IP_HL(ip) << 2; t = (tcphdr_t *)((char *)ip + hlen); - ti = (struct tcpiphdr *)lbuf; - thlen = t->th_off << 2; + ip2 = (struct ip *)lbuf; + t2 = (tcphdr_t *)((char *)ip2 + hlen); + thlen = TCP_OFF(t) << 2; if (!thlen) thlen = sizeof(tcphdr_t); - bzero((char *)ti, sizeof(*ti)); + bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2)); ip->ip_p = IPPROTO_TCP; - ti->ti_pr = ip->ip_p; - ti->ti_src = ip->ip_src; - ti->ti_dst = ip->ip_dst; - bcopy((char *)ip + hlen, (char *)&ti->ti_sport, thlen); + ip2->ip_p = ip->ip_p; + ip2->ip_src = ip->ip_src; + ip2->ip_dst = ip->ip_dst; + bcopy((char *)ip + hlen, (char *)t2, thlen); - if (!ti->ti_win) - ti->ti_win = htons(4096); + if (!t2->th_win) + t2->th_win = htons(4096); iss += 63; i = sizeof(struct tcpiphdr) / sizeof(long); - if ((ti->ti_flags == TH_SYN) && !ntohs(ip->ip_off) && + if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) && (lbuf[i] != htonl(0x020405b4))) { lbuf[i] = htonl(0x020405b4); bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, iplen - thlen - hlen); thlen += 4; } - ti->ti_off = thlen >> 2; - ti->ti_len = htons(thlen); + TCP_OFF_A(t2, thlen >> 2); + ip2->ip_len = htons(thlen); ip->ip_len = hlen + thlen; - ti->ti_sum = 0; - ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); + t2->th_sum = 0; + t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t)); - bcopy((char *)&ti->ti_sport, (char *)ip + hlen, thlen); + bcopy((char *)t2, (char *)ip + hlen, thlen); return send_ip(nfd, mtu, ip, gwip, 1); } @@ -304,16 +314,16 @@ struct in_addr gwip; ti->ti_pr = ip->ip_p; ti->ti_src = ip->ip_src; ti->ti_dst = ip->ip_dst; - bcopy((char *)ip + (ip->ip_hl << 2), + bcopy((char *)ip + (IP_HL(ip) << 2), (char *)&ti->ti_sport, sizeof(udphdr_t)); ti->ti_len = htons(thlen); - ip->ip_len = (ip->ip_hl << 2) + thlen; + ip->ip_len = (IP_HL(ip) << 2) + thlen; ti->ti_sum = 0; ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); bcopy((char *)&ti->ti_sport, - (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); + (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t)); return send_ip(nfd, mtu, ip, gwip, 1); } @@ -328,7 +338,7 @@ struct in_addr gwip; { struct icmp *ic; - ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); + ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); ic->icmp_cksum = 0; ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); diff --git a/contrib/ipfilter/ipsend/ip_var.h b/contrib/ipfilter/ipsend/ip_var.h index ace9800..b08f4e7 100644 --- a/contrib/ipfilter/ipsend/ip_var.h +++ b/contrib/ipfilter/ipsend/ip_var.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* @(#)ip_var.h 1.11 88/08/19 SMI; from UCB 7.1 6/5/86 */ /* @@ -44,7 +46,7 @@ struct ipq { * Note: ipf_next must be at same offset as ipq_next above */ struct ipasfrag { -#if defined(vax) || defined(i386) || defined(__i386__) +#if defined(vax) || defined(i386) u_char ip_hl:4, ip_v:4; #endif diff --git a/contrib/ipfilter/ipsend/ipresend.1 b/contrib/ipfilter/ipsend/ipresend.1 index 6014313..cffc6f3 100644 --- a/contrib/ipfilter/ipsend/ipresend.1 +++ b/contrib/ipfilter/ipsend/ipresend.1 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPRESEND 1 .SH NAME ipresend \- resend IP packets out to network diff --git a/contrib/ipfilter/ipsend/ipresend.c b/contrib/ipfilter/ipsend/ipresend.c index 9252b4b..1db54e1 100644 --- a/contrib/ipfilter/ipsend/ipresend.c +++ b/contrib/ipfilter/ipsend/ipresend.c @@ -1,42 +1,33 @@ +/* $NetBSD$ */ + /* * ipresend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipresend.c,v 2.4 2004/01/08 13:34:31 darrenr Exp"; #endif -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <netdb.h> -#include <string.h> -#include <sys/types.h> #include <sys/param.h> +#include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> #ifndef linux #include <netinet/ip_var.h> #endif +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <string.h> #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipresend.c,v 2.1.4.4 2002/12/06 11:40:35 darrenr Exp $"; -#endif - extern char *optarg; extern int optind; diff --git a/contrib/ipfilter/ipsend/ipsend.1 b/contrib/ipfilter/ipsend/ipsend.1 index f2f8066..33320f3 100644 --- a/contrib/ipfilter/ipsend/ipsend.1 +++ b/contrib/ipfilter/ipsend/ipsend.1 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPSEND 1 .SH NAME ipsend \- sends IP packets diff --git a/contrib/ipfilter/ipsend/ipsend.5 b/contrib/ipfilter/ipsend/ipsend.5 index f713147..aac757a 100644 --- a/contrib/ipfilter/ipsend/ipsend.5 +++ b/contrib/ipfilter/ipsend/ipsend.5 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPSEND 5 .SH NAME ipsend \- IP packet description language @@ -358,7 +360,7 @@ should be routing packets via another route. The redirect code names are: Echo. .TP .B routerad -Router Advertisment. +Router Advertisement. .TP .B routersol Router solicitation. diff --git a/contrib/ipfilter/ipsend/ipsend.c b/contrib/ipfilter/ipsend/ipsend.c index cdf18a7..6c91d4d 100644 --- a/contrib/ipfilter/ipsend/ipsend.c +++ b/contrib/ipfilter/ipsend/ipsend.c @@ -1,21 +1,14 @@ +/* $NetBSD$ */ + /* * ipsend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipsend.c,v 2.8.2.2 2004/11/13 16:50:10 darrenr Exp"; #endif -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <netdb.h> -#include <string.h> #include <sys/param.h> #include <sys/types.h> #include <sys/time.h> @@ -23,20 +16,19 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/in_systm.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <string.h> #include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/udp_var.h> -#include <netinet/ip_icmp.h> #ifndef linux -#include <netinet/ip_var.h> +# include <netinet/ip_var.h> #endif #include "ipsend.h" - -#if !defined(lint) -static const char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipsend.c,v 2.2.2.7 2004/04/10 11:50:52 darrenr Exp $"; +#include "ipf.h" +#ifndef linux +# include <netinet/udp_var.h> #endif @@ -46,27 +38,27 @@ extern void iplang __P((FILE *)); char options[68]; int opts; -#ifdef linux +#ifdef linux char default_device[] = "eth0"; #else -# ifdef sun -char default_device[] = "le0"; -# else -# ifdef ultrix +# ifdef ultrix char default_device[] = "ln0"; -# else -# ifdef __bsdi__ +# else +# ifdef __bsdi__ char default_device[] = "ef0"; -# else -# ifdef __sgi +# else +# ifdef __sgi char default_device[] = "ec0"; -# else +# else +# ifdef __hpux char default_device[] = "lan0"; -# endif -# endif -# endif -# endif -#endif +# else +char default_device[] = "le0"; +# endif /* __hpux */ +# endif /* __sgi */ +# endif /* __bsdi__ */ +# endif /* ultrix */ +#endif /* linux */ static void usage __P((char *)); @@ -161,13 +153,9 @@ int mtu; ip_t *ip; struct in_addr gwip; { - u_short sport = 0; - int wfd; - - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) - sport = ((struct tcpiphdr *)ip)->ti_sport; - wfd = initdevice(dev, sport, 5); + int wfd; + wfd = initdevice(dev, 5); return send_packet(wfd, mtu, ip, gwip); } @@ -185,7 +173,7 @@ udpcksum(ip_t *ip, struct udphdr *udp, int len) u_short w[6]; } ph; u_32_t temp32; - u_short cksum, *opts; + u_short *opts; ph.h.len = htons(len); ph.h.ttl = 0; @@ -208,8 +196,6 @@ int argc; char **argv; { FILE *langfile = NULL; - struct tcpiphdr *ti; - struct udpiphdr *ui; struct in_addr gwip; tcphdr_t *tcp; udphdr_t *udp; @@ -223,15 +209,12 @@ char **argv; * 65535 is maximum packet size...you never know... */ ip = (ip_t *)calloc(1, 65536); - ti = (struct tcpiphdr *)ip; - ui = (struct udpiphdr *)ip; - tcp = (tcphdr_t *)&ti->ti_sport; - udp = (udphdr_t *)&ui->ui_sport; - ui->ui_ulen = htons(sizeof(*udp)); + tcp = (tcphdr_t *)(ip + 1); + udp = (udphdr_t *)tcp; ip->ip_len = sizeof(*ip); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); - while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) + while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) { switch (c) { case 'I' : @@ -325,7 +308,7 @@ char **argv; break; case 'o' : nonl++; - olen = buildopts(optarg, options, (ip->ip_hl - 5) << 2); + olen = buildopts(optarg, options, (IP_HL(ip) - 5) << 2); break; case 's' : nonl++; @@ -350,6 +333,7 @@ char **argv; fprintf(stderr, "Unknown option \"%c\"\n", c); usage(name); } + } if (argc - optind < 1) usage(name); @@ -381,11 +365,6 @@ char **argv; exit(2); } - if (ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP) { - fprintf(stderr,"Unsupported protocol %d\n", ip->ip_p); - exit(2); - } - if (olen) { int hlen; @@ -393,22 +372,24 @@ char **argv; printf("Options: %d\n", olen); hlen = sizeof(*ip) + olen; - ip->ip_hl = hlen >> 2; + IP_HL_A(ip, hlen >> 2); ip->ip_len += olen; p = (char *)malloc(65536); - if(!p) + if (p == NULL) { - fprintf(stderr,"malloc failed\n"); + fprintf(stderr, "malloc failed\n"); exit(2); - } + } + bcopy(ip, p, sizeof(*ip)); bcopy(options, p + sizeof(*ip), olen); bcopy(ip + 1, p + hlen, ip->ip_len - hlen); ip = (ip_t *)p; + if (ip->ip_p == IPPROTO_TCP) { - tcp = (tcphdr_t *)((char *)ip + hlen); - } else { - udp = (udphdr_t *)((char *)ip + hlen); + tcp = (tcphdr_t *)(p + hlen); + } else if (ip->ip_p == IPPROTO_UDP) { + udp = (udphdr_t *)(p + hlen); } } @@ -448,11 +429,11 @@ char **argv; if (ip->ip_p == IPPROTO_UDP) { udp->uh_sum = 0; - udpcksum(ip, udp, (ip->ip_len) - (ip->ip_hl << 2)); + udpcksum(ip, udp, ip->ip_len - (IP_HL(ip) << 2)); } #ifdef DOSOCKET if (ip->ip_p == IPPROTO_TCP && tcp->th_dport) - return do_socket(dev, mtu, (struct tcpiphdr *)ip, gwip); + return do_socket(dev, mtu, ip, gwip); #endif return send_packets(dev, mtu, ip, gwip); } diff --git a/contrib/ipfilter/ipsend/ipsend.h b/contrib/ipfilter/ipsend/ipsend.h index 71e5490..be98c1b 100644 --- a/contrib/ipfilter/ipsend/ipsend.h +++ b/contrib/ipfilter/ipsend/ipsend.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * ipsend.h (C) 1997-1998 Darren Reed * @@ -6,7 +8,11 @@ * conditions, enough of the TCP header is missing for unpredictable * results unless the filter is aware that this can happen. * - * See the IPFILTER.LICENCE file for details on licencing. + * The author provides this program as-is, with no gaurantee for its + * suitability for any specific purpose. The author takes no responsibility + * for the misuse/abuse of this program and provides it for the sole purpose + * of testing packet filter policies. This file maybe distributed freely + * providing it is not modified and that this notice remains in tact. * */ #ifndef __P @@ -17,13 +23,14 @@ # endif #endif -#include "ip_compat.h" +#include <net/if.h> + +#include "ipf.h" #ifdef linux #include <linux/sockios.h> #endif #include "tcpip.h" #include "ipt.h" -#include "ipf.h" extern int resolve __P((char *, char *)); extern int arp __P((char *, char *)); @@ -35,10 +42,10 @@ extern int send_udp __P((int, int, ip_t *, struct in_addr)); extern int send_icmp __P((int, int, ip_t *, struct in_addr)); extern int send_packet __P((int, int, ip_t *, struct in_addr)); extern int send_packets __P((char *, int, ip_t *, struct in_addr)); -extern u_short seclevel __P((char *)); +extern u_short ipseclevel __P((char *)); extern u_32_t buildopts __P((char *, char *, int)); extern int addipopt __P((char *, struct ipopt_names *, int, char *)); -extern int initdevice __P((char *, int, int)); +extern int initdevice __P((char *, int)); extern int sendip __P((int, char *, int)); #ifdef linux extern struct sock *find_tcp __P((int, struct tcpiphdr *)); @@ -55,7 +62,6 @@ extern void ip_test5 __P((char *, int, ip_t *, struct in_addr, int)); extern void ip_test6 __P((char *, int, ip_t *, struct in_addr, int)); extern void ip_test7 __P((char *, int, ip_t *, struct in_addr, int)); extern int do_socket __P((char *, int, struct tcpiphdr *, struct in_addr)); -extern int openkmem __P((void)); extern int kmemcpy __P((char *, void *, int)); #define KMCPY(a,b,c) kmemcpy((char *)(a), (void *)(b), (int)(c)) @@ -63,9 +69,3 @@ extern int kmemcpy __P((char *, void *, int)); #ifndef OPT_RAW #define OPT_RAW 0x80000 #endif - -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif diff --git a/contrib/ipfilter/ipsend/ipsopt.c b/contrib/ipfilter/ipsend/ipsopt.c index 144c86f..7f16705 100644 --- a/contrib/ipfilter/ipsend/ipsopt.c +++ b/contrib/ipfilter/ipsend/ipsopt.c @@ -1,21 +1,25 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipsopt.c,v 2.4.4.1 2004/03/23 12:58:05 darrenr Exp"; #endif #include <sys/param.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> #ifndef linux #include <netinet/ip_var.h> #endif @@ -23,9 +27,13 @@ #include <arpa/inet.h> #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipsopt.c,v 2.1.4.5 2004/04/10 11:50:52 darrenr Exp $"; + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif #endif @@ -53,7 +61,7 @@ struct ipopt_names secnames[] = { }; -u_short seclevel(slevel) +u_short ipseclevel(slevel) char *slevel; { struct ipopt_names *so; @@ -108,7 +116,7 @@ char *class; switch (io->on_value) { case IPOPT_SECURITY : - lvl = seclevel(class); + lvl = ipseclevel(class); *(op - 1) = lvl; break; case IPOPT_LSRR : diff --git a/contrib/ipfilter/ipsend/iptest.1 b/contrib/ipfilter/ipsend/iptest.1 index ca74094..0af5cc2 100644 --- a/contrib/ipfilter/ipsend/iptest.1 +++ b/contrib/ipfilter/ipsend/iptest.1 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPTEST 1 .SH NAME iptest \- automatically generate a packets to test IP functionality diff --git a/contrib/ipfilter/ipsend/iptest.c b/contrib/ipfilter/ipsend/iptest.c index 72d0d78..45f8f3a 100644 --- a/contrib/ipfilter/ipsend/iptest.c +++ b/contrib/ipfilter/ipsend/iptest.c @@ -1,21 +1,15 @@ +/* $NetBSD$ */ + /* * ipsend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: iptest.c,v 2.6 2004/01/08 13:34:31 darrenr Exp"; #endif -#include <stdio.h> -#include <netdb.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> #include <sys/param.h> #include <sys/types.h> #include <sys/time.h> @@ -24,22 +18,19 @@ #include <arpa/inet.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> #ifndef linux #include <netinet/ip_var.h> #endif #ifdef linux #include <linux/sockios.h> #endif +#include <stdio.h> +#include <netdb.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: iptest.c,v 2.2.2.4 2002/12/06 11:40:35 darrenr Exp $"; -#endif - extern char *optarg; extern int optind; @@ -111,7 +102,7 @@ char **argv; ip = (ip_t *)calloc(1, 65536); ti = (struct tcpiphdr *)ip; ip->ip_len = sizeof(*ip); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); while ((c = getopt(argc, argv, "1234567d:g:m:p:s:")) != -1) switch (c) diff --git a/contrib/ipfilter/ipsend/iptests.c b/contrib/ipfilter/ipsend/iptests.c index a2f8432..a6cb41a 100644 --- a/contrib/ipfilter/ipsend/iptests.c +++ b/contrib/ipfilter/ipsend/iptests.c @@ -1,35 +1,38 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1993-1998 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: iptests.c,v 2.8.2.3 2004/04/16 23:33:04 darrenr Exp"; #endif -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> +#include <sys/param.h> #include <sys/types.h> #include <sys/time.h> -#include <sys/param.h> -#define _KERNEL -#define KERNEL -#if !defined(solaris) && !defined(linux) && !defined(__sgi) -# include <sys/file.h> -#else -# ifdef solaris -# include <sys/dditypes.h> +#if !defined(__osf__) +# define _KERNEL +# define KERNEL +# if !defined(solaris) && !defined(linux) && !defined(__sgi) && !defined(hpux) +# include <sys/file.h> +# else +# ifdef solaris +# include <sys/dditypes.h> +# endif # endif +# undef _KERNEL +# undef KERNEL #endif -#undef _KERNEL -#undef KERNEL #if !defined(solaris) && !defined(linux) && !defined(__sgi) # include <nlist.h> # include <sys/user.h> # include <sys/proc.h> #endif -#if !defined(ultrix) && !defined(hpux) && !defined(linux) && !defined(__sgi) +#if !defined(ultrix) && !defined(hpux) && !defined(linux) && \ + !defined(__sgi) && !defined(__osf__) # include <kvm.h> #endif #ifndef ultrix @@ -50,11 +53,17 @@ #endif #include <netinet/in_systm.h> #include <sys/socket.h> +#ifdef __hpux +# define _NET_ROUTE_INCLUDED +#endif #include <net/if.h> #if defined(linux) && (LINUX >= 0200) # include <asm/atomic.h> #endif #if !defined(linux) +# if defined(__FreeBSD__) +# include "radix_ipf.h" +# endif # include <net/route.h> #else # define __KERNEL__ /* because there's a macro not wrapped by this */ @@ -63,35 +72,38 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> -#ifndef linux +#if !defined(linux) # include <netinet/ip_var.h> -# include <netinet/in_pcb.h> -# include <netinet/tcp_timer.h> -# include <netinet/tcp_var.h> +# if !defined(__hpux) +# include <netinet/in_pcb.h> +# endif #endif #if defined(__SVR4) || defined(__svr4__) || defined(__sgi) # include <sys/sysmacros.h> #endif -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000000) -# define USE_NANOSLEEP +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#ifdef __hpux +# undef _NET_ROUTE_INCLUDED #endif #include "ipsend.h" - -#if !defined(lint) -static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: iptests.c,v 2.1.4.8 2002/12/06 11:40:35 darrenr Exp $"; +#if !defined(linux) && !defined(__hpux) +# include <netinet/tcp_timer.h> +# include <netinet/tcp_var.h> +#endif +#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000000) +# define USE_NANOSLEEP #endif -#ifdef USE_NANOSLEEP -# define PAUSE() ts.tv_sec = 0; ts.tv_nsec = 10000000; \ +#ifdef USE_NANOSLEEP +# define PAUSE() ts.tv_sec = 0; ts.tv_nsec = 10000000; \ (void) nanosleep(&ts, NULL) #else # define PAUSE() tv.tv_sec = 0; tv.tv_usec = 10000; \ - (void) select(0, NULL, NULL, NULL, &tv) + (void) select(0, NULL, NULL, NULL, &tv) #endif @@ -102,7 +114,7 @@ ip_t *ip; struct in_addr gwip; int ptest; { -#ifdef USE_NANOSLEEP +#ifdef USE_NANOSLEEP struct timespec ts; #else struct timeval tv; @@ -110,8 +122,8 @@ int ptest; udphdr_t *u; int nfd, i = 0, len, id = getpid(); - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; @@ -124,7 +136,7 @@ int ptest; u->uh_ulen = htons(sizeof(*u) + 4); ip->ip_len = sizeof(*ip) + ntohs(u->uh_ulen); len = ip->ip_len; - nfd = initdevice(dev, u->uh_sport, 1); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* @@ -133,7 +145,7 @@ int ptest; ip->ip_id = 0; printf("1.1. sending packets with ip_hl < ip_len\n"); for (i = 0; i < ((sizeof(*ip) + ntohs(u->uh_ulen)) >> 2); i++) { - ip->ip_hl = i >> 2; + IP_HL_A(ip, i >> 2); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -149,7 +161,7 @@ int ptest; ip->ip_id = 0; printf("1.2. sending packets with ip_hl > ip_len\n"); for (; i < ((sizeof(*ip) * 2 + ntohs(u->uh_ulen)) >> 2); i++) { - ip->ip_hl = i >> 2; + IP_HL_A(ip, i >> 2); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -164,9 +176,9 @@ int ptest; */ ip->ip_id = 0; printf("1.3. ip_v < 4\n"); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); for (i = 0; i < 4; i++) { - ip->ip_v = i; + IP_V_A(ip, i); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -182,7 +194,7 @@ int ptest; ip->ip_id = 0; printf("1.4. ip_v > 4\n"); for (i = 5; i < 16; i++) { - ip->ip_v = i; + IP_V_A(ip, i); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -196,13 +208,13 @@ int ptest; * Part5: len < packet */ ip->ip_id = 0; - ip->ip_v = IPVERSION; + IP_V_A(ip, IPVERSION); i = ip->ip_len + 1; printf("1.5.0 ip_len < packet size (size++, long packets)\n"); for (; i < (ip->ip_len * 2); i++) { ip->ip_id = htons(id++); ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, i, gwip); printf("%d\r", i); fflush(stdout); @@ -214,7 +226,7 @@ int ptest; ip->ip_id = htons(id++); ip->ip_len = i; ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, len, gwip); printf("%d\r", i); fflush(stdout); @@ -233,7 +245,7 @@ int ptest; ip->ip_id = htons(id++); ip->ip_len = i; ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, len, gwip); printf("%d\r", i); fflush(stdout); @@ -245,7 +257,7 @@ int ptest; for (i = len; i > 0; i--) { ip->ip_id = htons(id++); ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, i, gwip); printf("%d\r", i); fflush(stdout); @@ -314,14 +326,14 @@ int ptest; ip->ip_len = MIN(768 + 20, mtu - 68); i = 512; for (; i < (63 * 1024 + 768); i += 768) { - ip->ip_off = htons(IP_MF | ((i >> 3) & 0x1fff)); + ip->ip_off = htons(IP_MF | (i >> 3)); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); fflush(stdout); PAUSE(); } ip->ip_len = 896 + 20; - ip->ip_off = htons((i >> 3) & 0x1fff); + ip->ip_off = htons(i >> 3); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); putchar('\n'); @@ -348,7 +360,7 @@ int ptest; ip->ip_len = MIN(768 + 20, mtu - 68); i = 512; for (; i < (63 * 1024 + 768); i += 768) { - ip->ip_off = htons(IP_MF | ((i >> 3) & 0x1fff)); + ip->ip_off = htons(IP_MF | (i >> 3)); if ((rand() & 0x1f) != 0) { (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); @@ -358,7 +370,7 @@ int ptest; PAUSE(); } ip->ip_len = 896 + 20; - ip->ip_off = htons((i >> 3) & 0x1fff); + ip->ip_off = htons(i >> 3); if ((rand() & 0x1f) != 0) { (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); @@ -385,14 +397,14 @@ int ptest; ip->ip_len = MIN(768 + 20, mtu - 68); i = 512; for (; i < (32 * 1024 + 768); i += 768) { - ip->ip_off = htons(IP_MF | ((i >> 3) & 0x1fff)); + ip->ip_off = htons(IP_MF | (i >> 3)); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); fflush(stdout); PAUSE(); } ip->ip_len = 896 + 20; - ip->ip_off = htons((i >> 3) & 0x1fff); + ip->ip_off = htons(i >> 3); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); putchar('\n'); @@ -450,7 +462,7 @@ ip_t *ip; struct in_addr gwip; int ptest; { -#ifdef USE_NANOSLEEP +#ifdef USE_NANOSLEEP struct timespec ts; #else struct timeval tv; @@ -459,10 +471,10 @@ int ptest; u_char *s; s = (u_char *)(ip + 1); - nfd = initdevice(dev, htons(1), 1); + nfd = initdevice(dev, 1); - ip->ip_hl = 6; - ip->ip_len = ip->ip_hl << 2; + IP_HL_A(ip, 6); + ip->ip_len = IP_HL(ip) << 2; s[IPOPT_OPTVAL] = IPOPT_NOP; s++; if (!ptest || (ptest == 1)) { @@ -480,8 +492,8 @@ int ptest; PAUSE(); } - ip->ip_hl = 7; - ip->ip_len = ip->ip_hl << 2; + IP_HL_A(ip, 7); + ip->ip_len = IP_HL(ip) << 2; if (!ptest || (ptest == 1)) { /* * Test 2: options have length = 0 @@ -545,7 +557,7 @@ int ptest; { static int ict1[10] = { 8, 9, 10, 13, 14, 15, 16, 17, 18, 0 }; static int ict2[8] = { 3, 9, 10, 13, 14, 17, 18, 0 }; -#ifdef USE_NANOSLEEP +#ifdef USE_NANOSLEEP struct timespec ts; #else struct timeval tv; @@ -553,16 +565,16 @@ int ptest; struct icmp *icp; int nfd, i; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; ip->ip_p = IPPROTO_ICMP; ip->ip_sum = 0; ip->ip_len = sizeof(*ip) + sizeof(*icp); - icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); - nfd = initdevice(dev, htons(1), 1); + icp = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* @@ -741,7 +753,7 @@ ip_t *ip; struct in_addr gwip; int ptest; { -#ifdef USE_NANOSLEEP +#ifdef USE_NANOSLEEP struct timespec ts; #else struct timeval tv; @@ -750,25 +762,25 @@ int ptest; int nfd, i; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; ip->ip_p = IPPROTO_UDP; ip->ip_sum = 0; - u = (udphdr_t *)((char *)ip + (ip->ip_hl << 2)); + u = (udphdr_t *)((char *)ip + (IP_HL(ip) << 2)); u->uh_sport = htons(1); u->uh_dport = htons(1); u->uh_ulen = htons(sizeof(*u) + 4); - nfd = initdevice(dev, u->uh_sport, 1); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* * Test 1. ulen > packet */ u->uh_ulen = htons(sizeof(*u) + 4); - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.1 UDP uh_ulen > packet size - short packets\n"); for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) { u->uh_ulen = htons(i); @@ -785,7 +797,7 @@ int ptest; * Test 2. ulen < packet */ u->uh_ulen = htons(sizeof(*u) + 4); - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.2 UDP uh_ulen < packet size - short packets\n"); for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) { ip->ip_len = i; @@ -803,7 +815,7 @@ int ptest; * sport = 32768, sport = 65535 */ u->uh_ulen = sizeof(*u) + 4; - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.3.1 UDP sport = 0\n"); u->uh_sport = 0; (void) send_udp(nfd, 1500, ip, gwip); @@ -844,7 +856,7 @@ int ptest; */ u->uh_ulen = ntohs(sizeof(*u) + 4); u->uh_sport = htons(1); - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.4.1 UDP dport = 0\n"); u->uh_dport = 0; (void) send_udp(nfd, 1500, ip, gwip); @@ -903,7 +915,7 @@ ip_t *ip; struct in_addr gwip; int ptest; { -#ifdef USE_NANOSLEEP +#ifdef USE_NANOSLEEP struct timespec ts; #else struct timeval tv; @@ -911,11 +923,11 @@ int ptest; tcphdr_t *t; int nfd, i; - t = (tcphdr_t *)((char *)ip + (ip->ip_hl << 2)); -#ifndef linux + t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); +#if !defined(linux) && !defined(__osf__) t->th_x2 = 0; #endif - t->th_off = 0; + TCP_OFF_A(t, 0); t->th_sport = htons(1); t->th_dport = htons(1); t->th_win = htons(4096); @@ -924,13 +936,13 @@ int ptest; t->th_seq = htonl(1); t->th_ack = 0; ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t); - nfd = initdevice(dev, t->th_sport, 1); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* * Test 1: flags variations, 0 - 3f */ - t->th_off = sizeof(*t) >> 2; + TCP_OFF_A(t, sizeof(*t) >> 2); printf("5.1 Test TCP flag combinations\n"); for (i = 0; i <= (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN); i++) { @@ -1054,14 +1066,13 @@ int ptest; } #if !defined(linux) && !defined(__SVR4) && !defined(__svr4__) && \ - !defined(__sgi) + !defined(__sgi) && !defined(__hpux) && !defined(__osf__) { struct tcpcb *tcbp, tcb; struct tcpiphdr ti; struct sockaddr_in sin; int fd, slen; - fd = -1; bzero((char *)&sin, sizeof(sin)); for (i = 1; i < 63; i++) { @@ -1130,7 +1141,7 @@ int ptest; t->th_flags = TH_ACK; printf("5.6.1 TCP off = 1-15, len = 40\n"); for (i = 1; i < 16; i++) { - ti.ti_off = ntohs(i); + TCP_OFF_A(t, ntohs(i)); (void) send_tcp(nfd, mtu, ip, gwip); printf("%d\r", i); fflush(stdout); @@ -1146,7 +1157,7 @@ skip_five_and_six: #endif t->th_seq = htonl(1); t->th_ack = htonl(1); - t->th_off = 0; + TCP_OFF_A(t, 0); if (!ptest || (ptest == 7)) { t->th_flags = TH_SYN; @@ -1250,7 +1261,7 @@ ip_t *ip; struct in_addr gwip; int ptest; { -#ifdef USE_NANOSLEEP +#ifdef USE_NANOSLEEP struct timespec ts; #else struct timeval tv; @@ -1258,7 +1269,7 @@ int ptest; udphdr_t *u; int nfd, i, j, k; - ip->ip_v = IPVERSION; + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; @@ -1269,7 +1280,7 @@ int ptest; u->uh_dport = htons(9); u->uh_sum = 0; - nfd = initdevice(dev, u->uh_sport, 1); + nfd = initdevice(dev, 1); u->uh_ulen = htons(7168); printf("6. Exhaustive mbuf test.\n"); @@ -1280,7 +1291,7 @@ int ptest; * First send the entire packet in 768 byte chunks. */ ip->ip_len = sizeof(*ip) + 768 + sizeof(*u); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); ip->ip_off = htons(IP_MF); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d %d\r", i, 0); @@ -1298,7 +1309,7 @@ int ptest; for (j = 768; j < 3584; j += 768) { ip->ip_len = sizeof(*ip) + 768; - ip->ip_off = htons(IP_MF|((j>>3) & 0x1fff)); + ip->ip_off = htons(IP_MF|(j>>3)); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d %d\r", i, j); fflush(stdout); @@ -1306,7 +1317,7 @@ int ptest; ip->ip_len = sizeof(*ip) + 128; for (k = j - 768; k < j; k += 128) { - ip->ip_off = htons(IP_MF|((k>>3) & 0x1fff)); + ip->ip_off = htons(IP_MF|(k>>3)); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d %d\r", i, k); fflush(stdout); @@ -1329,16 +1340,16 @@ ip_t *ip; struct in_addr gwip; int ptest; { -#ifdef USE_NANOSLEEP + ip_t *pip; +#ifdef USE_NANOSLEEP struct timespec ts; #else struct timeval tv; #endif - ip_t *pip; int nfd, i, j; u_char *s; - nfd = initdevice(dev, 0, 1); + nfd = initdevice(dev, 1); pip = (ip_t *)tbuf; srand(time(NULL) ^ (getpid() * getppid())); @@ -1348,7 +1359,7 @@ int ptest; for (i = 0; i < 512; i++) { for (s = (u_char *)pip, j = 0; j < sizeof(tbuf); j++, s++) *s = (rand() >> 13) & 0xff; - pip->ip_v = IPVERSION; + IP_V_A(pip, IPVERSION); bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst, sizeof(struct in_addr)); pip->ip_sum = 0; @@ -1363,7 +1374,7 @@ int ptest; for (i = 0; i < 512; i++) { for (s = (u_char *)pip, j = 0; j < sizeof(tbuf); j++, s++) *s = (rand() >> 13) & 0xff; - pip->ip_v = IPVERSION; + IP_V_A(pip, IPVERSION); pip->ip_off &= htons(0xc000); bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst, sizeof(struct in_addr)); diff --git a/contrib/ipfilter/ipsend/larp.c b/contrib/ipfilter/ipsend/larp.c index d178d64..a8e782e 100644 --- a/contrib/ipfilter/ipsend/larp.c +++ b/contrib/ipfilter/ipsend/larp.c @@ -1,21 +1,25 @@ +/* $NetBSD$ */ + /* * larp.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. + * */ #if !defined(lint) static const char sccsid[] = "@(#)larp.c 1.1 8/19/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: larp.c,v 2.1.4.1 2001/06/26 10:43:22 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: larp.c,v 2.4 2003/12/01 02:01:16 darrenr Exp"; #endif -#include <stdio.h> -#include <errno.h> +#include <sys/param.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> -#include <netdb.h> #include <netinet/in.h> #include <net/if.h> #include <net/if_arp.h> +#include <stdio.h> +#include <netdb.h> +#include <errno.h> #include "ip_compat.h" #include "iplang/iplang.h" @@ -25,7 +29,7 @@ static const char rcsid[] = "@(#)$Id: larp.c,v 2.1.4.1 2001/06/26 10:43:22 darre * its IP address in address * (4 bytes) */ -int resolve(host, address) +int resolve(host, address) char *host, *address; { struct hostent *hp; diff --git a/contrib/ipfilter/ipsend/linux.h b/contrib/ipfilter/ipsend/linux.h index 2d2a243..d8296ba 100644 --- a/contrib/ipfilter/ipsend/linux.h +++ b/contrib/ipfilter/ipsend/linux.h @@ -1,7 +1,11 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1995-1998 by Darren Reed. * - * See the IPFILTER.LICENCE file for details on licencing. + * This code may be freely distributed as long as it retains this notice + * and is not changed in any way. The author accepts no responsibility + * for the use of this software. I hate legaleese, don't you ? * * @(#)linux.h 1.1 8/19/95 */ diff --git a/contrib/ipfilter/ipsend/lsock.c b/contrib/ipfilter/ipsend/lsock.c index 23a7621..abe664e 100644 --- a/contrib/ipfilter/ipsend/lsock.c +++ b/contrib/ipfilter/ipsend/lsock.c @@ -1,14 +1,14 @@ +/* $NetBSD$ */ + /* * lsock.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. + * */ #if !defined(lint) static const char sccsid[] = "@(#)lsock.c 1.2 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: lsock.c,v 2.1.4.3 2002/12/06 11:40:36 darrenr Exp $"; -#endif -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +static const char rcsid[] = "@(#)Id: lsock.c,v 2.3 2001/06/09 17:09:26 darrenr Exp"; #endif #include <stdio.h> #include <unistd.h> @@ -226,7 +226,7 @@ struct in_addr gwip; (void) getsockname(fd, (struct sockaddr *)&lsin, &len); ti->ti_sport = lsin.sin_port; printf("sport %d\n", ntohs(lsin.sin_port)); - nfd = initdevice(dev, ntohs(lsin.sin_port), 0); + nfd = initdevice(dev, 0); if (!(s = find_tcp(fd, ti))) return -1; diff --git a/contrib/ipfilter/ipsend/resend.c b/contrib/ipfilter/ipsend/resend.c index 646da1a..07220df 100644 --- a/contrib/ipfilter/ipsend/resend.c +++ b/contrib/ipfilter/ipsend/resend.c @@ -1,21 +1,16 @@ +/* $NetBSD$ */ + /* * resend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: resend.c,v 2.8 2004/01/08 13:34:31 darrenr Exp"; #endif -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> +#include <sys/param.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> @@ -24,9 +19,6 @@ #include <arpa/inet.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> #ifndef linux # include <netinet/ip_var.h> # include <netinet/if_ether.h> @@ -34,14 +26,13 @@ # include <net/if_var.h> # endif #endif +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] = "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: resend.c,v 2.1.4.5 2002/12/06 11:40:36 darrenr Exp $"; -#endif - - extern int opts; static u_char pbuf[65536]; /* 1 big packet */ @@ -54,7 +45,7 @@ ip_t *ip; tcphdr_t *t; int i, j; - t = (tcphdr_t *)((char *)ip + (ip->ip_hl << 2)); + t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); if (ip->ip_tos) printf("tos %#x ", ip->ip_tos); if (ip->ip_off & 0x3fff) @@ -88,13 +79,13 @@ char *datain; ether_header_t *eh; char dhost[6]; ip_t *ip; - int fd, wfd = initdevice(dev, 0, 5), len, i; + int fd, wfd = initdevice(dev, 5), len, i; if (datain) fd = (*r->r_open)(datain); else fd = (*r->r_open)("-"); - + if (fd < 0) exit(-1); @@ -130,7 +121,7 @@ char *datain; sizeof(dhost)); if (!ip->ip_sum) ip->ip_sum = chksum((u_short *)ip, - ip->ip_hl << 2); + IP_HL(ip) << 2); bcopy(ip, (char *)(eh + 1), len); len += sizeof(*eh); printpacket(ip); diff --git a/contrib/ipfilter/ipsend/sbpf.c b/contrib/ipfilter/ipsend/sbpf.c index ec95b49..9147929 100644 --- a/contrib/ipfilter/ipsend/sbpf.c +++ b/contrib/ipfilter/ipsend/sbpf.c @@ -1,18 +1,13 @@ +/* $NetBSD$ */ + /* * (C)opyright 1995-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> -#include <ctype.h> -#include <signal.h> -#include <errno.h> -#include <sys/types.h> #include <sys/param.h> +#include <sys/types.h> #include <sys/mbuf.h> #include <sys/time.h> #include <sys/timeb.h> @@ -37,11 +32,21 @@ #include <netinet/udp.h> #include <netinet/udp_var.h> #include <netinet/tcp.h> + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> + #include "ipsend.h" #if !defined(lint) static const char sccsid[] = "@(#)sbpf.c 1.3 8/25/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: sbpf.c,v 2.1.4.2 2001/09/30 04:04:28 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: sbpf.c,v 2.5 2002/02/24 07:30:03 darrenr Exp"; #endif /* @@ -51,17 +56,15 @@ static u_char *buf = NULL; static int bufsize = 0, timeout = 1; -int initdevice(device, sport, tout) +int initdevice(device, tout) char *device; -int sport, tout; +int tout; { struct bpf_version bv; struct timeval to; struct ifreq ifr; char bpfname[16]; - int fd, i; - - fd = -1; + int fd = 0, i; for (i = 0; i < 16; i++) { diff --git a/contrib/ipfilter/ipsend/sdlpi.c b/contrib/ipfilter/ipsend/sdlpi.c index dcd8422..215223a 100644 --- a/contrib/ipfilter/ipsend/sdlpi.c +++ b/contrib/ipfilter/ipsend/sdlpi.c @@ -1,7 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ #include <stdio.h> @@ -19,10 +22,17 @@ #include <sys/stropts.h> #ifdef sun -#include <sys/pfmod.h> -#include <sys/bufmod.h> +# include <sys/pfmod.h> +# include <sys/bufmod.h> +#endif +#ifdef __osf__ +# include <sys/dlpihdr.h> +#else +# include <sys/dlpi.h> +#endif +#ifdef __hpux +# include <sys/dlpi_ext.h> #endif -#include <sys/dlpi.h> #include <net/if.h> #include <netinet/in.h> @@ -38,7 +48,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)sdlpi.c 1.3 10/30/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: sdlpi.c,v 2.1.4.2 2001/06/26 10:43:22 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: sdlpi.c,v 2.8.2.1 2004/12/09 19:41:13 darrenr Exp"; #endif #define CHUNKSIZE 8192 @@ -49,9 +59,9 @@ static const char rcsid[] = "@(#)$Id: sdlpi.c,v 2.1.4.2 2001/06/26 10:43:22 darr * Be careful to only include those defined in the flags option for the * interface are included in the header size. */ -int initdevice(device, sport, tout) +int initdevice(device, tout) char *device; -int sport, tout; +int tout; { char devname[16], *s, buf[256]; int i, fd; @@ -60,7 +70,7 @@ int sport, tout; (void) strncat(devname, device, sizeof(devname) - strlen(devname)); s = devname + 5; - while (*s && !isdigit(*s)) + while (*s && !ISDIGIT(*s)) s++; if (!*s) { @@ -79,24 +89,43 @@ int sport, tout; exit(-1); } - if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1) + if (dlattachreq(fd, i) == -1) + { + fprintf(stderr, "dlattachreq: DLPI error\n"); + exit(-1); + } + else if (dlokack(fd, buf) == -1) + { + fprintf(stderr, "dlokack(attach): DLPI error\n"); + exit(-1); + } +#ifdef DL_HP_RAWDLS + if (dlpromisconreq(fd, DL_PROMISC_SAP) < 0) { - fprintf(stderr, "DLPI error\n"); + fprintf(stderr, "dlpromisconreq: DL_PROMISC_PHYS error\n"); exit(-1); } + else if (dlokack(fd, buf) < 0) + { + fprintf(stderr, "dlokack(promisc): DLPI error\n"); + exit(-1); + } + /* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */ + + dlbindreq(fd, 22, 1, DL_HP_RAWDLS, 0, 0); +#else dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0); +#endif dlbindack(fd, buf); /* * write full headers */ -#ifdef sun /* we require RAW DLPI mode, which is a Sun extension */ +#ifdef DLIOCRAW /* we require RAW DLPI mode, which is a Sun extension */ if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1) { fprintf(stderr, "DLIOCRAW error\n"); exit(-1); } -#else -you lose #endif return fd; } @@ -109,8 +138,19 @@ int sendip(fd, pkt, len) int fd, len; char *pkt; { - struct strbuf dbuf, *dp = &dbuf; + struct strbuf dbuf, *dp = &dbuf, *cp = NULL; + int pri = 0; +#ifdef DL_HP_RAWDLS + struct strbuf cbuf; + dl_hp_rawdata_req_t raw; + cp = &cbuf; + raw.dl_primitive = DL_HP_RAWDATA_REQ; + cp->len = sizeof(raw); + cp->buf = (char *)&raw; + cp->maxlen = cp->len; + pri = MSG_HIPRI; +#endif /* * construct NIT STREAMS messages, first control then data. */ @@ -118,7 +158,7 @@ char *pkt; dp->len = len; dp->maxlen = dp->len; - if (putmsg(fd, NULL, dp, 0) == -1) + if (putmsg(fd, cp, dp, pri) == -1) { perror("putmsg"); return -1; @@ -130,3 +170,4 @@ char *pkt; } return len; } + diff --git a/contrib/ipfilter/ipsend/sirix.c b/contrib/ipfilter/ipsend/sirix.c index 8f491f7..39a0992 100644 --- a/contrib/ipfilter/ipsend/sirix.c +++ b/contrib/ipfilter/ipsend/sirix.c @@ -1,12 +1,12 @@ +/* $NetBSD$ */ + /* * (C)opyright 1992-1998 Darren Reed. * (C)opyright 1997 Marc Boucher. * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> -#endif #include <stdio.h> #include <sys/types.h> #include <string.h> @@ -23,17 +23,15 @@ #include <netinet/ip.h> #include <netinet/if_ether.h> #include <netinet/ip_var.h> -#include <netinet/udp.h> -#include <netinet/udp_var.h> -#include <netinet/tcp.h> #include "ipsend.h" +#include <netinet/udp_var.h> #if !defined(lint) && defined(LIBC_SCCS) static char sirix[] = "@(#)sirix.c 1.0 10/9/97 (C)1997 Marc Boucher"; #endif -int initdevice(char *device, int sport, int tout) +int initdevice(char *device, int tout) { int fd; struct sockaddr_raw sr; diff --git a/contrib/ipfilter/ipsend/slinux.c b/contrib/ipfilter/ipsend/slinux.c index 7438d1c..3bc7f09 100644 --- a/contrib/ipfilter/ipsend/slinux.c +++ b/contrib/ipfilter/ipsend/slinux.c @@ -1,7 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ #include <stdio.h> @@ -27,7 +30,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)slinux.c 1.2 8/25/95"; -static const char rcsid[] = "@(#)$Id: slinux.c,v 2.1.4.1 2001/06/26 10:43:22 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: slinux.c,v 2.3 2001/06/09 17:09:26 darrenr Exp"; #endif #define CHUNKSIZE 8192 @@ -42,9 +45,9 @@ static int timeout; static char *eth_dev = NULL; -int initdevice(dev, sport, spare) +int initdevice(dev, spare) char *dev; -int sport, spare; +int spare; { int fd; diff --git a/contrib/ipfilter/ipsend/snit.c b/contrib/ipfilter/ipsend/snit.c index 6f2c662..a4b19b9 100644 --- a/contrib/ipfilter/ipsend/snit.c +++ b/contrib/ipfilter/ipsend/snit.c @@ -1,7 +1,10 @@ +/* $NetBSD$ */ + /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ #include <stdio.h> @@ -38,7 +41,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)snit.c 1.5 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: snit.c,v 2.1.4.1 2001/06/26 10:43:22 darrenr Exp $"; +static const char rcsid[] = "@(#)Id: snit.c,v 2.3 2001/06/09 17:09:26 darrenr Exp"; #endif #define CHUNKSIZE 8192 @@ -54,9 +57,9 @@ static const char rcsid[] = "@(#)$Id: snit.c,v 2.1.4.1 2001/06/26 10:43:22 darre static int timeout; -int initdevice(device, sport, tout) +int initdevice(device, tout) char *device; -int sport, tout; +int tout; { struct strioctl si; struct timeval to; diff --git a/contrib/ipfilter/ipsend/sock.c b/contrib/ipfilter/ipsend/sock.c index 2e7a11c..ccc57f0 100644 --- a/contrib/ipfilter/ipsend/sock.c +++ b/contrib/ipfilter/ipsend/sock.c @@ -1,20 +1,18 @@ +/* $NetBSD$ */ + /* * sock.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#if defined(__sgi) && (IRIX > 602) -# include <sys/ptimers.h> +#if !defined(lint) +static const char sccsid[] = "@(#)sock.c 1.2 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: sock.c,v 2.8.4.1 2004/03/23 12:58:06 darrenr Exp"; #endif -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <stdlib.h> -#include <stddef.h> -#include <pwd.h> +#include <sys/param.h> #include <sys/types.h> #include <sys/time.h> -#include <sys/param.h> #include <sys/stat.h> #ifndef ultrix #include <fcntl.h> @@ -24,21 +22,23 @@ #else # include <sys/dir.h> #endif -#define _KERNEL -#define KERNEL -#ifdef ultrix -# undef LOCORE -# include <sys/smp_lock.h> +#if !defined(__osf__) +# define _KERNEL +# define KERNEL +# ifdef ultrix +# undef LOCORE +# include <sys/smp_lock.h> +# endif +# include <sys/file.h> +# undef _KERNEL +# undef KERNEL #endif -#include <sys/file.h> -#undef _KERNEL -#undef KERNEL #include <nlist.h> #include <sys/user.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/proc.h> -#if !defined(ultrix) && !defined(hpux) +#if !defined(ultrix) && !defined(hpux) && !defined(__osf__) # include <kvm.h> #endif #ifdef sun @@ -56,18 +56,22 @@ #include <netinet/ip.h> #include <netinet/tcp.h> #include <net/if.h> +#if defined(__FreeBSD__) +# include "radix_ipf.h" +#endif #include <net/route.h> #include <netinet/ip_var.h> #include <netinet/in_pcb.h> #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <pwd.h> #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] = "@(#)sock.c 1.2 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: sock.c,v 2.1.4.6 2002/12/06 11:40:36 darrenr Exp $"; -#endif - int nproc; struct proc *proc; @@ -379,7 +383,7 @@ struct in_addr gwip; (void) getsockname(fd, (struct sockaddr *)&lsin, &len); ti->ti_sport = lsin.sin_port; printf("sport %d\n", ntohs(lsin.sin_port)); - nfd = initdevice(dev, ntohs(lsin.sin_port), 1); + nfd = initdevice(dev, 1); if (!(t = find_tcp(fd, ti))) return -1; diff --git a/contrib/ipfilter/ipsend/sockraw.c b/contrib/ipfilter/ipsend/sockraw.c new file mode 100644 index 0000000..822c146 --- /dev/null +++ b/contrib/ipfilter/ipsend/sockraw.c @@ -0,0 +1,89 @@ +/* $NetBSD$ */ + +/* + * (C)opyright 2000 Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * WARNING: Attempting to use this .c file on HP-UX 11.00 will cause the + * system to crash. + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include "ipsend.h" + +#if !defined(lint) && defined(LIBC_SCCS) +static char sirix[] = "@(#)sirix.c 1.0 10/9/97 (C)1997 Marc Boucher"; +#endif + + +int initdevice(char *device, int tout) +{ + struct sockaddr s; + struct ifreq ifr; + int fd; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name); + + if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + { + perror("socket(AF_INET, SOCK_RAW, IPPROTO_RAW)"); + return -1; + } + + if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) + { + perror("ioctl SIOCGIFADDR"); + return -1; + } + + bzero((char *)&s, sizeof(s)); + s.sa_family = AF_INET; + bcopy(&ifr.ifr_addr, s.sa_data, 4); + if (bind(fd, &s, sizeof(s)) == -1) + perror("bind"); + return fd; +} + + +/* + * output an IP packet + */ +int sendip(int fd, char *pkt, int len) +{ + struct ether_header *eh; + struct sockaddr_in sin; + + eh = (struct ether_header *)pkt; + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + pkt += 14; + len -= 14; + bcopy(pkt + 12, (char *)&sin.sin_addr, 4); + + if (sendto(fd, pkt, len, 0, &sin, sizeof(sin)) == -1) + { + perror("send"); + return -1; + } + + return len; +} diff --git a/contrib/ipfilter/ipsend/tcpip.h b/contrib/ipfilter/ipsend/tcpip.h index c735593..0d3e040 100644 --- a/contrib/ipfilter/ipsend/tcpip.h +++ b/contrib/ipfilter/ipsend/tcpip.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -10,11 +12,7 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,7 +29,7 @@ * SUCH DAMAGE. * * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 - * $Id: tcpip.h,v 2.1 1999/08/04 17:31:16 darrenr Exp $ + * Id: tcpip.h,v 2.2.2.3 2004/05/26 15:45:48 darrenr Exp */ #ifndef _NETINET_TCPIP_H_ @@ -54,12 +52,9 @@ struct ipovly { */ struct tcpiphdr { struct ipovly ti_i; /* overlaid ip structure */ -#ifdef linux - tcphdr_t ti_t; -#else struct tcphdr ti_t; /* tcp header */ -#endif }; + #ifdef notyet /* * Tcp+ip header, after ip options removed but including TCP options. diff --git a/contrib/ipfilter/ipt.h b/contrib/ipfilter/ipt.h index 677c74a..6a14fe5 100644 --- a/contrib/ipfilter/ipt.h +++ b/contrib/ipfilter/ipt.h @@ -1,8 +1,11 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. - * $Id: ipt.h,v 2.2.2.1 2001/06/26 10:43:19 darrenr Exp $ + * + * Id: ipt.h,v 2.6 2003/02/16 02:33:09 darrenr Exp */ #ifndef __IPT_H__ @@ -24,8 +27,11 @@ struct ipread { int (*r_open) __P((char *)); int (*r_close) __P((void)); int (*r_readip) __P((char *, int, char **, int *)); + int r_flags; }; +#define R_DO_CKSUM 0x01 + extern void debug __P((char *, ...)); extern void verbose __P((char *, ...)); diff --git a/contrib/ipfilter/kmem.h b/contrib/ipfilter/kmem.h index f7056c2..7cb6635 100644 --- a/contrib/ipfilter/kmem.h +++ b/contrib/ipfilter/kmem.h @@ -1,8 +1,10 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. - * $Id: kmem.h,v 2.2.2.4 2002/01/01 13:43:48 darrenr Exp $ + * Id: kmem.h,v 2.5 2002/08/21 22:57:36 darrenr Exp */ #ifndef __KMEM_H__ @@ -18,7 +20,6 @@ extern int openkmem __P((char *, char *)); extern int kmemcpy __P((char *, long, int)); extern int kstrncpy __P((char *, long, int)); -extern char *getifname __P((void *)); #if defined(__NetBSD__) || defined(__OpenBSD) # include <paths.h> diff --git a/contrib/ipfilter/l4check/http.ok b/contrib/ipfilter/l4check/http.ok index 2b5d2c1..0e7dd90 100644 --- a/contrib/ipfilter/l4check/http.ok +++ b/contrib/ipfilter/l4check/http.ok @@ -1 +1 @@ -<HTML>
\ No newline at end of file +<HTML> diff --git a/contrib/ipfilter/l4check/l4check.c b/contrib/ipfilter/l4check/l4check.c index 23ac79a..68c41de 100644 --- a/contrib/ipfilter/l4check/l4check.c +++ b/contrib/ipfilter/l4check/l4check.c @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * (C)Copyright March, 2000 - Darren Reed. */ @@ -141,8 +143,7 @@ void closel4(l4, dead) l4cfg_t *l4; int dead; { - if (l4->l4_fd != -1) - close(l4->l4_fd); + close(l4->l4_fd); l4->l4_fd = -1; l4->l4_rw = -1; if (dead && l4->l4_alive) { @@ -308,7 +309,7 @@ int runconfig() if (opts & OPT_VERBOSE) fprintf(stderr, "failed\n"); perror("connect"); - closel4(l4, 1); + close(fd); fd = -1; } else { if (opts & OPT_VERBOSE) @@ -417,10 +418,10 @@ u_short *portp; *port++ = '\0'; #ifdef HAVE_INET_ATON - if (isdigit(*host) && inet_aton(host, &ip)) + if (ISDIGIT(*host) && inet_aton(host, &ip)) *ipp = ip.s_addr; #else - if (isdigit(*host)) + if (ISDIGIT(*host)) *ipp = inet_addr(host); #endif else { @@ -433,7 +434,7 @@ u_short *portp; } if (port) { - if (isdigit(*port)) + if (ISDIGIT(*port)) *portp = htons(atoi(port)); else { sp = getservbyname(port, "tcp"); @@ -526,7 +527,7 @@ char *filename; /* * Skip leading whitespace */ - for (line = buf; (c = *line) && isspace(c); line++) + for (line = buf; (c = *line) && ISSPACE(c); line++) ; if (!*line) continue; @@ -606,14 +607,14 @@ char *filename; } 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_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) { + if (!s || !t) { errtxt = line; err = -1; break; @@ -635,7 +636,7 @@ char *filename; } } else if (!strcasecmp(t, "probe")) { s = strtok(NULL, " \t"); - if (!s) { + if (!s) { errtxt = line; err = -1; break; @@ -683,13 +684,13 @@ char *filename; } } else if (!strcasecmp(t, "response")) { s = strtok(NULL, " \t"); - if (!s) { + if (!s) { errtxt = line; err = -1; break; } else if (!strcasecmp(s, "timeout")) { t = strtok(NULL, " \t"); - if (!t) { + if (!t) { errtxt = line; err = -1; break; diff --git a/contrib/ipfilter/lib/Makefile b/contrib/ipfilter/lib/Makefile new file mode 100644 index 0000000..d448ba0 --- /dev/null +++ b/contrib/ipfilter/lib/Makefile @@ -0,0 +1,309 @@ +INCDEP=$(TOP)/ip_compat.h $(TOP)/ip_fil.h $(TOP)/ipf.h + +LIBOBJS=$(DEST)/addicmp.o \ + $(DEST)/addipopt.o \ + $(DEST)/addkeep.o \ + $(DEST)/bcopywrap.o \ + $(DEST)/binprint.o \ + $(DEST)/buildopts.o \ + $(DEST)/checkrev.o \ + $(DEST)/count6bits.o \ + $(DEST)/count4bits.o \ + $(DEST)/debug.o \ + $(DEST)/extras.o \ + $(DEST)/facpri.o \ + $(DEST)/flags.o \ + $(DEST)/fill6bits.o \ + $(DEST)/genmask.o \ + $(DEST)/gethost.o \ + $(DEST)/getifname.o \ + $(DEST)/getline.o \ + $(DEST)/getnattype.o \ + $(DEST)/getport.o \ + $(DEST)/getportproto.o \ + $(DEST)/getproto.o \ + $(DEST)/getsumd.o \ + $(DEST)/hexdump.o \ + $(DEST)/hostmask.o \ + $(DEST)/hostname.o \ + $(DEST)/hostnum.o \ + $(DEST)/icmpcode.o \ + $(DEST)/inet_addr.o \ + $(DEST)/initparse.o \ + $(DEST)/ionames.o \ + $(DEST)/ipoptsec.o \ + $(DEST)/ipf_dotuning.o \ + $(DEST)/ipft_ef.o \ + $(DEST)/ipft_hx.o \ + $(DEST)/ipft_pc.o \ + $(DEST)/ipft_sn.o \ + $(DEST)/ipft_td.o \ + $(DEST)/ipft_tx.o \ + $(DEST)/kmem.o \ + $(DEST)/kmemcpywrap.o \ + $(DEST)/kvatoname.o \ + $(DEST)/load_hash.o \ + $(DEST)/load_hashnode.o \ + $(DEST)/load_pool.o \ + $(DEST)/load_poolnode.o \ + $(DEST)/loglevel.o \ + $(DEST)/make_range.o \ + $(DEST)/mutex_emul.o \ + $(DEST)/nametokva.o \ + $(DEST)/nat_setgroupmap.o \ + $(DEST)/ntomask.o \ + $(DEST)/optname.o \ + $(DEST)/optprint.o \ + $(DEST)/optprintv6.o \ + $(DEST)/optvalue.o \ + $(DEST)/portname.o \ + $(DEST)/portnum.o \ + $(DEST)/ports.o \ + $(DEST)/print_toif.o \ + $(DEST)/printactivenat.o \ + $(DEST)/printaps.o \ + $(DEST)/printbuf.o \ + $(DEST)/printhash.o \ + $(DEST)/printhashnode.o \ + $(DEST)/printip.o \ + $(DEST)/printpool.o \ + $(DEST)/printpoolnode.o \ + $(DEST)/printfr.o \ + $(DEST)/printfraginfo.o \ + $(DEST)/printhostmap.o \ + $(DEST)/printifname.o \ + $(DEST)/printhostmask.o \ + $(DEST)/printlog.o \ + $(DEST)/printmask.o \ + $(DEST)/printnat.o \ + $(DEST)/printportcmp.o \ + $(DEST)/printpacket.o \ + $(DEST)/printpacket6.o \ + $(DEST)/printsbuf.o \ + $(DEST)/printstate.o \ + $(DEST)/printtunable.o \ + $(DEST)/ratoi.o \ + $(DEST)/ratoui.o \ + $(DEST)/remove_hash.o \ + $(DEST)/remove_hashnode.o \ + $(DEST)/remove_pool.o \ + $(DEST)/remove_poolnode.o \ + $(DEST)/resetlexer.o \ + $(DEST)/rwlock_emul.o \ + $(DEST)/tcpflags.o \ + $(DEST)/tcp_flags.o \ + $(DEST)/to_interface.o \ + $(DEST)/var.o \ + $(DEST)/verbose.o \ + $(DEST)/v6ionames.o \ + $(DEST)/v6optvalue.o + +$(DEST)/libipf.a: $(LIBOBJS) + /bin/rm -f $@ + ar $(AROPTS) $@ $(LIBOBJS) + $(RANLIB) $@ + +$(DEST)/addicmp.o: $(LIBSRC)/addicmp.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/addicmp.c -o $@ +$(DEST)/addipopt.o: $(LIBSRC)/addipopt.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/addipopt.c -o $@ +$(DEST)/addkeep.o: $(LIBSRC)/addkeep.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/addkeep.c -o $@ +$(DEST)/bcopywrap.o: $(LIBSRC)/bcopywrap.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/bcopywrap.c -o $@ +$(DEST)/binprint.o: $(LIBSRC)/binprint.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/binprint.c -o $@ +$(DEST)/buildopts.o: $(LIBSRC)/buildopts.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/buildopts.c -o $@ +$(DEST)/count6bits.o: $(LIBSRC)/count6bits.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/count6bits.c -o $@ +$(DEST)/checkrev.o: $(LIBSRC)/checkrev.c $(INCDEP) $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/checkrev.c -o $@ +$(DEST)/count4bits.o: $(LIBSRC)/count4bits.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/count4bits.c -o $@ +$(DEST)/debug.o: $(LIBSRC)/debug.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/debug.c -o $@ +$(DEST)/extras.o: $(LIBSRC)/extras.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/extras.c -o $@ +$(DEST)/facpri.o: $(LIBSRC)/facpri.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/facpri.c -o $@ +$(DEST)/fill6bits.o: $(LIBSRC)/fill6bits.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/fill6bits.c -o $@ +$(DEST)/flags.o: $(LIBSRC)/flags.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/flags.c -o $@ +$(DEST)/genmask.o: $(LIBSRC)/genmask.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/genmask.c -o $@ +$(DEST)/getline.o: $(LIBSRC)/getline.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getline.c -o $@ +$(DEST)/gethost.o: $(LIBSRC)/gethost.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/gethost.c -o $@ +$(DEST)/getifname.o: $(LIBSRC)/getifname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getifname.c -o $@ +$(DEST)/getnattype.o: $(LIBSRC)/getnattype.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getnattype.c -o $@ +$(DEST)/getport.o: $(LIBSRC)/getport.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getport.c -o $@ +$(DEST)/getportproto.o: $(LIBSRC)/getportproto.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getportproto.c -o $@ +$(DEST)/getproto.o: $(LIBSRC)/getproto.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getproto.c -o $@ +$(DEST)/getsumd.o: $(LIBSRC)/getsumd.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getsumd.c -o $@ +$(DEST)/hexdump.o: $(LIBSRC)/hexdump.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/hexdump.c -o $@ +$(DEST)/hostmask.o: $(LIBSRC)/hostmask.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/hostmask.c -o $@ +$(DEST)/hostname.o: $(LIBSRC)/hostname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/hostname.c -o $@ +$(DEST)/hostnum.o: $(LIBSRC)/hostnum.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/hostnum.c -o $@ +$(DEST)/icmpcode.o: $(LIBSRC)/icmpcode.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/icmpcode.c -o $@ +$(DEST)/ipoptsec.o: $(LIBSRC)/ipoptsec.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipoptsec.c -o $@ +$(DEST)/inet_addr.o: $(LIBSRC)/inet_addr.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/inet_addr.c -o $@ +$(DEST)/initparse.o: $(LIBSRC)/initparse.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/initparse.c -o $@ +$(DEST)/ionames.o: $(LIBSRC)/ionames.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ionames.c -o $@ +$(DEST)/ipf_dotuning.o: $(LIBSRC)/ipf_dotuning.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipf_dotuning.c -o $@ +$(DEST)/ipft_ef.o: $(LIBSRC)/ipft_ef.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_ef.c -o $@ +$(DEST)/ipft_hx.o: $(LIBSRC)/ipft_hx.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_hx.c -o $@ +$(DEST)/ipft_pc.o: $(LIBSRC)/ipft_pc.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_pc.c -o $@ +$(DEST)/ipft_sn.o: $(LIBSRC)/ipft_sn.c $(TOP)/snoop.h + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_sn.c -o $@ +$(DEST)/ipft_td.o: $(LIBSRC)/ipft_td.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_td.c -o $@ +$(DEST)/ipft_tx.o: $(LIBSRC)/ipft_tx.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_tx.c -o $@ +$(DEST)/kmem.o: $(LIBSRC)/kmem.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/kmem.c -o $@ +$(DEST)/kmemcpywrap.o: $(LIBSRC)/kmemcpywrap.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/kmemcpywrap.c -o $@ +$(DEST)/kvatoname.o: $(LIBSRC)/kvatoname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/kvatoname.c -o $@ +$(DEST)/load_hash.o: $(LIBSRC)/load_hash.c $(INCDEP) $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_hash.c -o $@ +$(DEST)/load_hashnode.o: $(LIBSRC)/load_hashnode.c $(INCDEP) $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_hashnode.c -o $@ +$(DEST)/load_pool.o: $(LIBSRC)/load_pool.c $(INCDEP) $(TOP)/ip_pool.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_pool.c -o $@ +$(DEST)/load_poolnode.o: $(LIBSRC)/load_poolnode.c $(INCDEP) $(TOP)/ip_pool.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_poolnode.c -o $@ +$(DEST)/make_range.o: $(LIBSRC)/make_range.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/make_range.c -o $@ +$(DEST)/mutex_emul.o: $(LIBSRC)/mutex_emul.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/mutex_emul.c -o $@ +$(DEST)/nametokva.o: $(LIBSRC)/nametokva.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/nametokva.c -o $@ +$(DEST)/nat_setgroupmap.o: $(LIBSRC)/nat_setgroupmap.c $(TOP)/ip_compat.h \ + $(TOP)/ipf.h $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/nat_setgroupmap.c -o $@ +$(DEST)/ntomask.o: $(LIBSRC)/ntomask.c $(TOP)/ip_compat.h + $(CC) $(CCARGS) -c $(LIBSRC)/ntomask.c -o $@ +$(DEST)/loglevel.o: $(LIBSRC)/loglevel.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/loglevel.c -o $@ +$(DEST)/optname.o: $(LIBSRC)/optname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optname.c -o $@ +$(DEST)/optprint.o: $(LIBSRC)/optprint.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optprint.c -o $@ +$(DEST)/optprintv6.o: $(LIBSRC)/optprintv6.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optprintv6.c -o $@ +$(DEST)/optvalue.o: $(LIBSRC)/optvalue.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optvalue.c -o $@ +$(DEST)/portname.o: $(LIBSRC)/portname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/portname.c -o $@ +$(DEST)/portnum.o: $(LIBSRC)/portnum.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/portnum.c -o $@ +$(DEST)/ports.o: $(LIBSRC)/ports.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ports.c -o $@ +$(DEST)/print_toif.o: $(LIBSRC)/print_toif.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/print_toif.c -o $@ +$(DEST)/printactivenat.o: $(LIBSRC)/printactivenat.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printactivenat.c -o $@ +$(DEST)/printaps.o: $(LIBSRC)/printaps.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printaps.c -o $@ +$(DEST)/printbuf.o: $(LIBSRC)/printbuf.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printbuf.c -o $@ +$(DEST)/printfr.o: $(LIBSRC)/printfr.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printfr.c -o $@ +$(DEST)/printfraginfo.o: $(LIBSRC)/printfraginfo.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printfraginfo.c -o $@ +$(DEST)/printhash.o: $(LIBSRC)/printhash.c $(TOP)/ip_fil.h $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhash.c -o $@ +$(DEST)/printhashnode.o: $(LIBSRC)/printhashnode.c $(TOP)/ip_fil.h \ + $(TOP)/ip_htable.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhashnode.c -o $@ +$(DEST)/printip.o: $(LIBSRC)/printip.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printip.c -o $@ +$(DEST)/printpool.o: $(LIBSRC)/printpool.c $(TOP)/ip_fil.h $(TOP)/ip_pool.h + $(CC) $(CCARGS) -c $(LIBSRC)/printpool.c -o $@ +$(DEST)/printpoolnode.o: $(LIBSRC)/printpoolnode.c $(TOP)/ip_fil.h \ + $(TOP)/ip_pool.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) -c $(LIBSRC)/printpoolnode.c -o $@ +$(DEST)/printhostmap.o: $(LIBSRC)/printhostmap.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhostmap.c -o $@ +$(DEST)/printifname.o: $(LIBSRC)/printifname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printifname.c -o $@ +$(DEST)/printmask.o: $(LIBSRC)/printmask.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printmask.c -o $@ +$(DEST)/printnat.o: $(LIBSRC)/printnat.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printnat.c -o $@ +$(DEST)/printhostmask.o: $(LIBSRC)/printhostmask.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printhostmask.c -o $@ +$(DEST)/printlog.o: $(LIBSRC)/printlog.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printlog.c -o $@ +$(DEST)/printpacket.o: $(LIBSRC)/printpacket.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printpacket.c -o $@ +$(DEST)/printpacket6.o: $(LIBSRC)/printpacket6.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printpacket6.c -o $@ +$(DEST)/printportcmp.o: $(LIBSRC)/printportcmp.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printportcmp.c -o $@ +$(DEST)/printsbuf.o: $(LIBSRC)/printsbuf.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printsbuf.c -o $@ +$(DEST)/printstate.o: $(LIBSRC)/printstate.c $(INCDEP) $(TOP)/ip_state.h + $(CC) $(CCARGS) -c $(LIBSRC)/printstate.c -o $@ +$(DEST)/printtunable.o: $(LIBSRC)/printtunable.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printtunable.c -o $@ +$(DEST)/ratoi.o: $(LIBSRC)/ratoi.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ratoi.c -o $@ +$(DEST)/ratoui.o: $(LIBSRC)/ratoui.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ratoui.c -o $@ +$(DEST)/remove_hash.o: $(LIBSRC)/remove_hash.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_hash.c -o $@ +$(DEST)/remove_hashnode.o: $(LIBSRC)/remove_hashnode.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_hashnode.c -o $@ +$(DEST)/remove_pool.o: $(LIBSRC)/remove_pool.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_pool.c -o $@ +$(DEST)/remove_poolnode.o: $(LIBSRC)/remove_poolnode.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_poolnode.c -o $@ +$(DEST)/resetlexer.o: $(LIBSRC)/resetlexer.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/resetlexer.c -o $@ +$(DEST)/rwlock_emul.o: $(LIBSRC)/rwlock_emul.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/rwlock_emul.c -o $@ +$(DEST)/to_interface.o: $(LIBSRC)/to_interface.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/to_interface.c -o $@ +$(DEST)/tcpflags.o: $(LIBSRC)/tcpflags.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/tcpflags.c -o $@ +$(DEST)/tcp_flags.o: $(LIBSRC)/tcp_flags.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/tcp_flags.c -o $@ +$(DEST)/var.o: $(LIBSRC)/var.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/var.c -o $@ +$(DEST)/verbose.o: $(LIBSRC)/verbose.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/verbose.c -o $@ +$(DEST)/v6ionames.o: $(LIBSRC)/v6ionames.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/v6ionames.c -o $@ +$(DEST)/v6optvalue.o: $(LIBSRC)/v6optvalue.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/v6optvalue.c -o $@ + +clean-lib: + /bin/rm -f ${LIBOBJS} ${LIB} diff --git a/contrib/ipfilter/lib/addicmp.c b/contrib/ipfilter/lib/addicmp.c new file mode 100644 index 0000000..a8c1722 --- /dev/null +++ b/contrib/ipfilter/lib/addicmp.c @@ -0,0 +1,94 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: addicmp.c,v 1.10.2.1 2004/12/09 19:41:16 darrenr Exp + */ + +#include <ctype.h> + +#include "ipf.h" + + +char *icmptypes[MAX_ICMPTYPE + 1] = { + "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", + "redir", (char *)NULL, (char *)NULL, "echo", "routerad", + "routersol", "timex", "paramprob", "timest", "timestrep", + "inforeq", "inforep", "maskreq", "maskrep", "END" +}; + +/* + * set the icmp field to the correct type if "icmp" word is found + */ +int addicmp(cp, fp, linenum) +char ***cp; +struct frentry *fp; +int linenum; +{ + char **t; + int i; + + (*cp)++; + if (!**cp) + return -1; + if (!fp->fr_proto) /* to catch lusers */ + fp->fr_proto = IPPROTO_ICMP; + if (ISDIGIT(***cp)) { + if (!ratoi(**cp, &i, 0, 255)) { + fprintf(stderr, + "%d: Invalid icmp-type (%s) specified\n", + linenum, **cp); + return -1; + } + } else { + for (t = icmptypes, i = 0; ; t++, i++) { + if (!*t) + continue; + if (!strcasecmp("END", *t)) { + i = -1; + break; + } + if (!strcasecmp(*t, **cp)) + break; + } + if (i == -1) { + fprintf(stderr, + "%d: Unknown icmp-type (%s) specified\n", + linenum, **cp); + return -1; + } + } + fp->fr_icmp = (u_short)(i << 8); + fp->fr_icmpm = (u_short)0xff00; + (*cp)++; + if (!**cp) + return 0; + + if (**cp && strcasecmp("code", **cp)) + return 0; + (*cp)++; + if (ISDIGIT(***cp)) { + if (!ratoi(**cp, &i, 0, 255)) { + fprintf(stderr, + "%d: Invalid icmp code (%s) specified\n", + linenum, **cp); + return -1; + } + } else { + i = icmpcode(**cp); + if (i == -1) { + fprintf(stderr, + "%d: Unknown icmp code (%s) specified\n", + linenum, **cp); + return -1; + } + } + i &= 0xff; + fp->fr_icmp |= (u_short)i; + fp->fr_icmpm = (u_short)0xffff; + (*cp)++; + return 0; +} diff --git a/contrib/ipfilter/lib/addipopt.c b/contrib/ipfilter/lib/addipopt.c new file mode 100644 index 0000000..23f4427 --- /dev/null +++ b/contrib/ipfilter/lib/addipopt.c @@ -0,0 +1,67 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: addipopt.c,v 1.7 2002/01/28 06:50:45 darrenr Exp + */ + +#include "ipf.h" + + +int addipopt(op, io, len, class) +char *op; +struct ipopt_names *io; +int len; +char *class; +{ + int olen = len; + struct in_addr ipadr; + u_short val; + u_char lvl; + char *s; + + if ((len + io->on_siz) > 48) { + fprintf(stderr, "options too long\n"); + return 0; + } + len += io->on_siz; + *op++ = io->on_value; + if (io->on_siz > 1) { + s = op; + *op++ = io->on_siz; + *op++ = IPOPT_MINOFF; + + if (class) { + switch (io->on_value) + { + case IPOPT_SECURITY : + lvl = seclevel(class); + *(op - 1) = lvl; + break; + case IPOPT_LSRR : + case IPOPT_SSRR : + ipadr.s_addr = inet_addr(class); + s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4; + bcopy((char *)&ipadr, op, sizeof(ipadr)); + break; + case IPOPT_SATID : + val = atoi(class); + bcopy((char *)&val, op, 2); + break; + } + } + + op += io->on_siz - 3; + if (len & 3) { + *op++ = IPOPT_NOP; + len++; + } + } + if (opts & OPT_DEBUG) + fprintf(stderr, "bo: %s %d %#x: %d\n", + io->on_name, io->on_value, io->on_bit, len); + return len - olen; +} diff --git a/contrib/ipfilter/lib/addkeep.c b/contrib/ipfilter/lib/addkeep.c new file mode 100644 index 0000000..3f20fb4 --- /dev/null +++ b/contrib/ipfilter/lib/addkeep.c @@ -0,0 +1,86 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: addkeep.c,v 1.12 2003/12/01 01:59:42 darrenr Exp + */ + +#include "ipf.h" + + +/* + * Parses "keep state" and "keep frags" stuff on the end of a line. + */ +int addkeep(cp, fp, linenum) +char ***cp; +struct frentry *fp; +int linenum; +{ + char *s; + + (*cp)++; + if (!**cp) { + fprintf(stderr, "%d: Missing state/frag after keep\n", + linenum); + return -1; + } + + if (!strcasecmp(**cp, "state")) { + fp->fr_flags |= FR_KEEPSTATE; + (*cp)++; + if (**cp && !strcasecmp(**cp, "limit")) { + (*cp)++; + fp->fr_statemax = atoi(**cp); + (*cp)++; + } + if (**cp && !strcasecmp(**cp, "scan")) { + (*cp)++; + if (!strcmp(**cp, "*")) { + fp->fr_isc = NULL; + fp->fr_isctag[0] = '\0'; + } else { + strncpy(fp->fr_isctag, **cp, + sizeof(fp->fr_isctag)); + fp->fr_isctag[sizeof(fp->fr_isctag)-1] = '\0'; + fp->fr_isc = NULL; + } + (*cp)++; + } else + fp->fr_isc = (struct ipscan *)-1; + } else if (!strncasecmp(**cp, "frag", 4)) { + fp->fr_flags |= FR_KEEPFRAG; + (*cp)++; + } else if (!strcasecmp(**cp, "state-age")) { + if (fp->fr_ip.fi_p == IPPROTO_TCP) { + fprintf(stderr, "%d: cannot use state-age with tcp\n", + linenum); + return -1; + } + if ((fp->fr_flags & FR_KEEPSTATE) == 0) { + fprintf(stderr, "%d: state-age with no 'keep state'\n", + linenum); + return -1; + } + (*cp)++; + if (!**cp) { + fprintf(stderr, "%d: state-age with no arg\n", + linenum); + return -1; + } + fp->fr_age[0] = atoi(**cp); + s = strchr(**cp, '/'); + if (s != NULL) { + s++; + fp->fr_age[1] = atoi(s); + } else + fp->fr_age[1] = fp->fr_age[0]; + } else { + fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n", + linenum, **cp); + return -1; + } + return 0; +} diff --git a/contrib/ipfilter/lib/bcopywrap.c b/contrib/ipfilter/lib/bcopywrap.c new file mode 100644 index 0000000..939137b --- /dev/null +++ b/contrib/ipfilter/lib/bcopywrap.c @@ -0,0 +1,12 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +int bcopywrap(from, to, size) +void *from, *to; +size_t size; +{ + bcopy((caddr_t)from, (caddr_t)to, size); + return 0; +} + diff --git a/contrib/ipfilter/lib/binprint.c b/contrib/ipfilter/lib/binprint.c new file mode 100644 index 0000000..afa4910 --- /dev/null +++ b/contrib/ipfilter/lib/binprint.c @@ -0,0 +1,31 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: binprint.c,v 1.8 2002/05/14 15:18:56 darrenr Exp + */ + +#include "ipf.h" + + +void binprint(ptr, size) +void *ptr; +size_t size; +{ + u_char *s; + int i, j; + + for (i = size, j = 0, s = (u_char *)ptr; i; i--, s++) { + j++; + printf("%02x ", *s); + if (j == 16) { + printf("\n"); + j = 0; + } + } + putchar('\n'); + (void)fflush(stdout); +} diff --git a/contrib/ipfilter/lib/buildopts.c b/contrib/ipfilter/lib/buildopts.c new file mode 100644 index 0000000..a35649b --- /dev/null +++ b/contrib/ipfilter/lib/buildopts.c @@ -0,0 +1,44 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: buildopts.c,v 1.6 2002/01/28 06:50:45 darrenr Exp + */ + +#include "ipf.h" + + +u_32_t buildopts(cp, op, len) +char *cp, *op; +int len; +{ + struct ipopt_names *io; + u_32_t msk = 0; + char *s, *t; + int inc; + + for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { + if ((t = strchr(s, '='))) + *t++ = '\0'; + for (io = ionames; io->on_name; io++) { + if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) + continue; + if ((inc = addipopt(op, io, len, t))) { + op += inc; + len += inc; + } + msk |= io->on_bit; + break; + } + if (!io->on_name) { + fprintf(stderr, "unknown IP option name %s\n", s); + return 0; + } + } + *op++ = IPOPT_EOL; + len++; + return len; +} diff --git a/contrib/ipfilter/lib/checkrev.c b/contrib/ipfilter/lib/checkrev.c new file mode 100644 index 0000000..28032ce --- /dev/null +++ b/contrib/ipfilter/lib/checkrev.c @@ -0,0 +1,46 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: checkrev.c,v 1.12.2.1 2004/03/09 14:44:39 darrenr Exp + */ + +#include <sys/ioctl.h> +#include <fcntl.h> + +#include "ipf.h" +#include "netinet/ipl.h" + +int checkrev(ipfname) +char *ipfname; +{ + static int vfd = -1; + struct friostat fio, *fiop = &fio; + ipfobj_t ipfo; + + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(*fiop); + ipfo.ipfo_ptr = (void *)fiop; + ipfo.ipfo_type = IPFOBJ_IPFSTAT; + + if ((vfd == -1) && ((vfd = open(ipfname, O_RDONLY)) == -1)) { + perror("open device"); + return -1; + } + + if (ioctl(vfd, SIOCGETFS, &ipfo)) { + perror("ioctl(SIOCGETFS)"); + close(vfd); + vfd = -1; + return -1; + } + + if (strncmp(IPL_VERSION, fio.f_version, sizeof(fio.f_version))) { + return -1; + } + return 0; +} diff --git a/contrib/ipfilter/lib/count4bits.c b/contrib/ipfilter/lib/count4bits.c new file mode 100644 index 0000000..0f2187f --- /dev/null +++ b/contrib/ipfilter/lib/count4bits.c @@ -0,0 +1,40 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: count4bits.c,v 1.1 2002/06/15 04:46:39 darrenr Exp + */ + +#include "ipf.h" + + +/* + * 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 count4bits(ip) +u_int ip; +{ + int cnt = 0, i, j; + u_int ipn; + + 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; +} diff --git a/contrib/ipfilter/lib/count6bits.c b/contrib/ipfilter/lib/count6bits.c new file mode 100644 index 0000000..bd4e9f8 --- /dev/null +++ b/contrib/ipfilter/lib/count6bits.c @@ -0,0 +1,29 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: count6bits.c,v 1.4 2001/06/09 17:09:23 darrenr Exp + */ + +#include "ipf.h" + + +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; +} diff --git a/contrib/ipfilter/lib/debug.c b/contrib/ipfilter/lib/debug.c new file mode 100644 index 0000000..1510222 --- /dev/null +++ b/contrib/ipfilter/lib/debug.c @@ -0,0 +1,37 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: debug.c,v 1.6 2001/06/09 17:09:24 darrenr Exp + */ + +#if defined(__STDC__) +# include <stdarg.h> +#else +# include <varargs.h> +#endif +#include <stdio.h> + +#include "ipt.h" +#include "opts.h" + + +#ifdef __STDC__ +void debug(char *fmt, ...) +#else +void debug(fmt, va_alist) +char *fmt; +va_dcl +#endif +{ + va_list pvar; + + va_start(pvar, fmt); + + if (opts & OPT_DEBUG) + vprintf(fmt, pvar); + va_end(pvar); +} diff --git a/contrib/ipfilter/lib/extras.c b/contrib/ipfilter/lib/extras.c new file mode 100644 index 0000000..0f7f39f --- /dev/null +++ b/contrib/ipfilter/lib/extras.c @@ -0,0 +1,114 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: extras.c,v 1.12 2002/07/13 12:06:49 darrenr Exp + */ + +#include "ipf.h" + + +/* + * deal with extra bits on end of the line + */ +int extras(cp, fr, linenum) +char ***cp; +struct frentry *fr; +int linenum; +{ + u_short secmsk; + u_long opts; + int notopt; + + opts = 0; + secmsk = 0; + notopt = 0; + (*cp)++; + if (!**cp) + return -1; + + while (**cp) { + if (!strcasecmp(**cp, "not") || !strcasecmp(**cp, "no")) { + notopt = 1; + (*cp)++; + continue; + } else if (!strncasecmp(**cp, "ipopt", 5)) { + if (!notopt) + fr->fr_flx |= FI_OPTIONS; + fr->fr_mflx |= FI_OPTIONS; + goto nextopt; + } else if (!strcasecmp(**cp, "lowttl")) { + if (!notopt) + fr->fr_flx |= FI_LOWTTL; + fr->fr_mflx |= FI_LOWTTL; + goto nextopt; + } else if (!strcasecmp(**cp, "bad-src")) { + if (!notopt) + fr->fr_flx |= FI_BADSRC; + fr->fr_mflx |= FI_BADSRC; + goto nextopt; + } else if (!strncasecmp(**cp, "mbcast", 6)) { + if (!notopt) + fr->fr_flx |= FI_MBCAST; + fr->fr_mflx |= FI_MBCAST; + goto nextopt; + } else if (!strncasecmp(**cp, "nat", 3)) { + if (!notopt) + fr->fr_flx |= FI_NATED; + fr->fr_mflx |= FI_NATED; + goto nextopt; + } else if (!strncasecmp(**cp, "frag", 4)) { + if (!notopt) + fr->fr_flx |= FI_FRAG; + fr->fr_mflx |= FI_FRAG; + goto nextopt; + } else if (!strncasecmp(**cp, "opt", 3)) { + if (!*(*cp + 1)) { + fprintf(stderr, "%d: opt missing arguements\n", + linenum); + return -1; + } + (*cp)++; + if (!(opts = optname(cp, &secmsk, linenum))) + return -1; + + if (notopt) { + if (!secmsk) { + fr->fr_optmask |= opts; + } else { + fr->fr_optmask |= (opts & ~0x0100); + fr->fr_secmask |= secmsk; + } + fr->fr_secbits &= ~secmsk; + fr->fr_optbits &= ~opts; + } else { + fr->fr_optmask |= opts; + fr->fr_secmask |= secmsk; + fr->fr_optbits |= opts; + fr->fr_secbits |= secmsk; + } + } else if (!strncasecmp(**cp, "short", 5)) { + if (fr->fr_tcpf) { + fprintf(stderr, + "%d: short cannot be used with TCP flags\n", + linenum); + return -1; + } + + if (!notopt) + fr->fr_flx |= FI_SHORT; + fr->fr_mflx |= FI_SHORT; + goto nextopt; + } else + return -1; +nextopt: + notopt = 0; + opts = 0; + secmsk = 0; + (*cp)++; + } + return 0; +} diff --git a/contrib/ipfilter/lib/facpri.c b/contrib/ipfilter/lib/facpri.c new file mode 100644 index 0000000..1e35ea9 --- /dev/null +++ b/contrib/ipfilter/lib/facpri.c @@ -0,0 +1,153 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: facpri.c,v 1.6 2003/12/01 01:59:43 darrenr Exp + */ + +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#endif +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <syslog.h> +#include "facpri.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: facpri.c,v 1.6 2003/12/01 01:59:43 darrenr Exp"; +#endif + + +typedef struct table { + char *name; + int value; +} table_t; + +table_t facs[] = { + { "kern", LOG_KERN }, { "user", LOG_USER }, + { "mail", LOG_MAIL }, { "daemon", LOG_DAEMON }, + { "auth", LOG_AUTH }, { "syslog", LOG_SYSLOG }, + { "lpr", LOG_LPR }, { "news", LOG_NEWS }, + { "uucp", LOG_UUCP }, +#if LOG_CRON == LOG_CRON2 + { "cron2", LOG_CRON1 }, +#else + { "cron", LOG_CRON1 }, +#endif +#ifdef LOG_FTP + { "ftp", LOG_FTP }, +#endif +#ifdef LOG_AUTHPRIV + { "authpriv", LOG_AUTHPRIV }, +#endif +#ifdef LOG_AUDIT + { "audit", LOG_AUDIT }, +#endif +#ifdef LOG_LFMT + { "logalert", LOG_LFMT }, +#endif +#if LOG_CRON == LOG_CRON1 + { "cron", LOG_CRON2 }, +#else + { "cron2", LOG_CRON2 }, +#endif +#ifdef LOG_SECURITY + { "security", LOG_SECURITY }, +#endif + { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, + { NULL, 0 } +}; + + +/* + * map a facility number to its name + */ +char * +fac_toname(facpri) + int facpri; +{ + int i, j, fac; + + fac = facpri & LOG_FACMASK; + j = fac >> 3; + if (j < 24) { + if (facs[j].value == fac) + return facs[j].name; + for (i = 0; facs[i].name; i++) + if (fac == facs[i].value) + return facs[i].name; + } + + return NULL; +} + + +/* + * map a facility name to its number + */ +int +fac_findname(name) + char *name; +{ + int i; + + for (i = 0; facs[i].name; i++) + if (!strcmp(facs[i].name, name)) + return facs[i].value; + return -1; +} + + +table_t pris[] = { + { "emerg", LOG_EMERG }, { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, { "err", LOG_ERR }, + { "warn", LOG_WARNING }, { "notice", LOG_NOTICE }, + { "info", LOG_INFO }, { "debug", LOG_DEBUG }, + { NULL, 0 } +}; + + +/* + * map a priority name to its number + */ +int +pri_findname(name) + char *name; +{ + int i; + + for (i = 0; pris[i].name; i++) + if (!strcmp(pris[i].name, name)) + return pris[i].value; + return -1; +} + + +/* + * map a priority number to its name + */ +char * +pri_toname(facpri) + int facpri; +{ + int i, pri; + + pri = facpri & LOG_PRIMASK; + if (pris[pri].value == pri) + return pris[pri].name; + for (i = 0; pris[i].name; i++) + if (pri == pris[i].value) + return pris[i].name; + return NULL; +} diff --git a/contrib/ipfilter/lib/facpri.h b/contrib/ipfilter/lib/facpri.h new file mode 100644 index 0000000..e8eef2b --- /dev/null +++ b/contrib/ipfilter/lib/facpri.h @@ -0,0 +1,43 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1999-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: facpri.h,v 1.3 2001/06/09 17:19:50 darrenr Exp + */ + +#ifndef __FACPRI_H__ +#define __FACPRI_H__ + +#ifndef __P +# define P_DEF +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +extern char *fac_toname __P((int)); +extern int fac_findname __P((char *)); + +extern char *pri_toname __P((int)); +extern int pri_findname __P((char *)); + +#ifdef P_DEF +# undef __P +# undef P_DEF +#endif + +#if LOG_CRON == (9<<3) +# define LOG_CRON1 LOG_CRON +# define LOG_CRON2 (15<<3) +#endif +#if LOG_CRON == (15<<3) +# define LOG_CRON1 (9<<3) +# define LOG_CRON2 LOG_CRON +#endif + +#endif /* __FACPRI_H__ */ diff --git a/contrib/ipfilter/lib/fill6bits.c b/contrib/ipfilter/lib/fill6bits.c new file mode 100644 index 0000000..8f23a6f --- /dev/null +++ b/contrib/ipfilter/lib/fill6bits.c @@ -0,0 +1,48 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: fill6bits.c,v 1.5 2002/03/27 15:09:57 darrenr Exp + */ + +#include "ipf.h" + + +void fill6bits(bits, msk) +int bits; +u_int *msk; +{ + if (bits == 0) { + msk[0] = 0; + msk[1] = 0; + msk[2] = 0; + msk[3] = 0; + return; + } + + msk[0] = 0xffffffff; + msk[1] = 0xffffffff; + msk[2] = 0xffffffff; + msk[3] = 0xffffffff; + + if (bits == 128) + return; + if (bits > 96) { + msk[3] = htonl(msk[3] << (128 - bits)); + } else if (bits > 64) { + msk[3] = 0; + msk[2] = htonl(msk[2] << (96 - bits)); + } else if (bits > 32) { + msk[3] = 0; + msk[2] = 0; + msk[1] = htonl(msk[1] << (64 - bits)); + } else { + msk[3] = 0; + msk[2] = 0; + msk[1] = 0; + msk[0] = htonl(msk[0] << (32 - bits)); + } +} diff --git a/contrib/ipfilter/lib/flags.c b/contrib/ipfilter/lib/flags.c new file mode 100644 index 0000000..df6645d --- /dev/null +++ b/contrib/ipfilter/lib/flags.c @@ -0,0 +1,25 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: flags.c,v 1.4 2002/11/02 07:16:36 darrenr Exp + */ + +#include "ipf.h" + +/* + * ECN is a new addition to TCP - RFC 2481 + */ +#ifndef TH_ECN +# define TH_ECN 0x40 +#endif +#ifndef TH_CWR +# define TH_CWR 0x80 +#endif + +char flagset[] = "FSRPAUEC"; +u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG, + TH_ECN, TH_CWR }; diff --git a/contrib/ipfilter/lib/genmask.c b/contrib/ipfilter/lib/genmask.c new file mode 100644 index 0000000..06f6404 --- /dev/null +++ b/contrib/ipfilter/lib/genmask.c @@ -0,0 +1,56 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: genmask.c,v 1.7 2003/11/11 13:40:15 darrenr Exp + */ + +#include "ipf.h" + + +int genmask(msk, mskp) +char *msk; +u_32_t *mskp; +{ + char *endptr = 0L; + int bits; + + if (strchr(msk, '.') || strchr(msk, 'x') || strchr(msk, ':')) { + /* possibly of the form xxx.xxx.xxx.xxx + * or 0xYYYYYYYY */ +#ifdef USE_INET6 + if (use_inet6) { + if (inet_pton(AF_INET6, msk, mskp) != 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; +} diff --git a/contrib/ipfilter/lib/gethost.c b/contrib/ipfilter/lib/gethost.c new file mode 100644 index 0000000..a03168a --- /dev/null +++ b/contrib/ipfilter/lib/gethost.c @@ -0,0 +1,36 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +int gethost(name, hostp) +char *name; +u_32_t *hostp; +{ + struct hostent *h; + struct netent *n; + u_32_t addr; + + if (!strcmp(name, "test.host.dots")) { + *hostp = htonl(0xfedcba98); + return 0; + } + + if (!strcmp(name, "<thishost>")) + name = thishost; + + h = gethostbyname(name); + if (h != NULL) { + if ((h->h_addr != NULL) && (h->h_length == sizeof(addr))) { + bcopy(h->h_addr, (char *)&addr, sizeof(addr)); + *hostp = addr; + return 0; + } + } + + n = getnetbyname(name); + if (n != NULL) { + *hostp = (u_32_t)htonl(n->n_net & 0xffffffff); + return 0; + } + return -1; +} diff --git a/contrib/ipfilter/lib/getifname.c b/contrib/ipfilter/lib/getifname.c new file mode 100644 index 0000000..94c9c9c --- /dev/null +++ b/contrib/ipfilter/lib/getifname.c @@ -0,0 +1,76 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +#include "kmem.h" + +/* + * Given a pointer to an interface in the kernel, return a pointer to a + * string which is the interface name. + */ +char *getifname(ptr) +struct ifnet *ptr; +{ +#if SOLARIS || defined(__hpux) +# if SOLARIS +# include <sys/mutex.h> +# include <sys/condvar.h> +# endif +# ifdef __hpux +# include "compat.h" +# endif +# include "../pfil/qif.h" + char *ifname; + qif_t qif; + + if ((void *)ptr == (void *)-1) + return "!"; + if (ptr == NULL) + return "-"; + + if (kmemcpy((char *)&qif, (u_long)ptr, sizeof(qif)) == -1) + return "X"; + ifname = strdup(qif.qf_name); + if ((ifname != NULL) && (*ifname == '\0')) { + free(ifname); + return "!"; + } + return ifname; +#else +# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ + defined(__OpenBSD__) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) +#else + char buf[32]; + int len; +# endif + struct ifnet netif; + + if ((void *)ptr == (void *)-1) + return "!"; + if (ptr == NULL) + return "-"; + + if (kmemcpy((char *)&netif, (u_long)ptr, sizeof(netif)) == -1) + return "X"; +# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ + defined(__OpenBSD__) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + return strdup(netif.if_xname); +# else + if (kstrncpy(buf, (u_long)netif.if_name, sizeof(buf)) == -1) + return "X"; + if (netif.if_unit < 10) + len = 2; + else if (netif.if_unit < 1000) + len = 3; + else if (netif.if_unit < 10000) + len = 4; + else + len = 5; + buf[sizeof(buf) - len] = '\0'; + sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000); + return strdup(buf); +# endif +#endif +} diff --git a/contrib/ipfilter/lib/getline.c b/contrib/ipfilter/lib/getline.c new file mode 100644 index 0000000..61c00ba --- /dev/null +++ b/contrib/ipfilter/lib/getline.c @@ -0,0 +1,58 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: getline.c,v 1.3 2001/06/09 17:09:24 darrenr Exp + */ + +#include <stdio.h> +#if !defined(__SVR4) && !defined(__GNUC__) +#include <strings.h> +#endif +#include <string.h> +#include "ipf.h" + + +/* + * Similar to fgets(3) but can handle '\\' and NL is converted to NUL. + * Returns NULL if error occured, EOF encounterd or input line is too long. + */ +char *getline(str, size, file, linenum) +register char *str; +size_t size; +FILE *file; +int *linenum; +{ + char *p; + int s, len; + + do { + for (p = str, s = size;; p += (len - 1), s -= (len - 1)) { + /* + * if an error occured, EOF was encounterd, or there + * was no room to put NUL, return NULL. + */ + if (fgets(p, s, file) == NULL) + return (NULL); + len = strlen(p); + if (p[len - 1] != '\n') { + p[len] = '\0'; + break; + } + (*linenum)++; + p[len - 1] = '\0'; + if (len < 2 || p[len - 2] != '\\') + break; + else + /* + * Convert '\\' to a space so words don't + * run together + */ + p[len - 2] = ' '; + } + } while (*str == '\0'); + return (str); +} diff --git a/contrib/ipfilter/lib/getnattype.c b/contrib/ipfilter/lib/getnattype.c new file mode 100644 index 0000000..c783d6f --- /dev/null +++ b/contrib/ipfilter/lib/getnattype.c @@ -0,0 +1,54 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ +#include "ipf.h" +#include "kmem.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: getnattype.c,v 1.3 2004/01/17 17:26:07 darrenr Exp"; +#endif + + +/* + * Get a nat filter type given its kernel address. + */ +char *getnattype(ipnat) +ipnat_t *ipnat; +{ + static char unknownbuf[20]; + ipnat_t ipnatbuff; + char *which; + + if (!ipnat) + return "???"; + if (kmemcpy((char *)&ipnatbuff, (long)ipnat, sizeof(ipnatbuff))) + return "!!!"; + + switch (ipnatbuff.in_redir) + { + case NAT_MAP : + which = "MAP"; + break; + case NAT_MAPBLK : + which = "MAP-BLOCK"; + break; + case NAT_REDIRECT : + which = "RDR"; + break; + case NAT_BIMAP : + which = "BIMAP"; + break; + default : + sprintf(unknownbuf, "unknown(%04x)", + ipnatbuff.in_redir & 0xffffffff); + which = unknownbuf; + break; + } + return which; +} diff --git a/contrib/ipfilter/lib/getport.c b/contrib/ipfilter/lib/getport.c new file mode 100644 index 0000000..7cf903d --- /dev/null +++ b/contrib/ipfilter/lib/getport.c @@ -0,0 +1,46 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +int getport(fr, name, port) +frentry_t *fr; +char *name; +u_short *port; +{ + struct protoent *p; + struct servent *s; + u_short p1; + + if (fr == NULL || fr->fr_type != FR_T_IPF) { + s = getservbyname(name, NULL); + if (s != NULL) { + *port = s->s_port; + return 0; + } + return -1; + } + + if ((fr->fr_flx & FI_TCPUDP) != 0) { + /* + * If a rule is "tcp/udp" then check that both TCP and UDP + * mappings for this protocol name match ports. + */ + s = getservbyname(name, "tcp"); + if (s == NULL) + return -1; + p1 = s->s_port; + s = getservbyname(name, "udp"); + if (s == NULL || s->s_port != p1) + return -1; + *port = p1; + return 0; + } + + p = getprotobynumber(fr->fr_proto); + s = getservbyname(name, p ? p->p_name : NULL); + if (s != NULL) { + *port = s->s_port; + return 0; + } + return -1; +} diff --git a/contrib/ipfilter/lib/getportproto.c b/contrib/ipfilter/lib/getportproto.c new file mode 100644 index 0000000..17efa43 --- /dev/null +++ b/contrib/ipfilter/lib/getportproto.c @@ -0,0 +1,32 @@ +/* $NetBSD$ */ + +#include <ctype.h> +#include "ipf.h" + +int getportproto(name, proto) +char *name; +int proto; +{ + struct servent *s; + struct protoent *p; + + if (ISDIGIT(*name)) { + int number; + char *s; + + for (s = name; *s != '\0'; s++) + if (!ISDIGIT(*s)) + return -1; + + number = atoi(name); + if (number < 0 || number > 65535) + return -1; + return htons(number); + } + + p = getprotobynumber(proto); + s = getservbyname(name, p ? p->p_name : NULL); + if (s != NULL) + return s->s_port; + return -1; +} diff --git a/contrib/ipfilter/lib/getproto.c b/contrib/ipfilter/lib/getproto.c new file mode 100644 index 0000000..c75f137 --- /dev/null +++ b/contrib/ipfilter/lib/getproto.c @@ -0,0 +1,21 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +int getproto(name) +char *name; +{ + struct protoent *p; + char *s; + + for (s = name; *s != '\0'; s++) + if (!ISDIGIT(*s)) + break; + if (*s == '\0') + return atoi(name); + + p = getprotobyname(name); + if (p != NULL) + return p->p_proto; + return -1; +} diff --git a/contrib/ipfilter/lib/getsumd.c b/contrib/ipfilter/lib/getsumd.c new file mode 100644 index 0000000..11ecc57 --- /dev/null +++ b/contrib/ipfilter/lib/getsumd.c @@ -0,0 +1,15 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +char *getsumd(sum) +u_32_t sum; +{ + static char sumdbuf[17]; + + if (sum & NAT_HW_CKSUM) + sprintf(sumdbuf, "hw(%#0x)", sum & 0xffff); + else + sprintf(sumdbuf, "%#0x", sum); + return sumdbuf; +} diff --git a/contrib/ipfilter/lib/hexdump.c b/contrib/ipfilter/lib/hexdump.c new file mode 100644 index 0000000..4eb3b9ad --- /dev/null +++ b/contrib/ipfilter/lib/hexdump.c @@ -0,0 +1,30 @@ +/* $NetBSD$ */ + +#include <ctype.h> + +#include "ipf.h" + +void hexdump(out, addr, len, ascii) +FILE *out; +void *addr; +int len, ascii; +{ + FILE *fpout; + u_char *s, *t; + int i; + + fpout = out ? out : stdout; + for (i = 0, s = addr; i < len; i++, s++) { + fprintf(fpout, "%02x", *s); + if (i % 16 == 15) { + if (ascii != 0) { + fputc('\t', fpout); + for (t = s - 15; t<= s; t++) + fputc(ISPRINT(*t) ? *t : '.', fpout); + } + fputc('\n', fpout); + } else if (i % 4 == 3) { + fputc(' ', fpout); + } + } +} diff --git a/contrib/ipfilter/lib/hostmask.c b/contrib/ipfilter/lib/hostmask.c new file mode 100644 index 0000000..67755f8 --- /dev/null +++ b/contrib/ipfilter/lib/hostmask.c @@ -0,0 +1,95 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: hostmask.c,v 1.10 2002/01/28 06:50:46 darrenr Exp + */ + +#include "ipf.h" + + +/* + * 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, proto, ifname, sa, msk, linenum) +char ***seg, *proto, *ifname; +u_32_t *sa, *msk; +int linenum; +{ + struct in_addr maskaddr; + char *s; + + if ((s = strchr(**seg, '='))) { + *s++ = '\0'; + if (!strcmp(**seg, "pool")) { + *sa = atoi(s); + return 1; + } + } + + /* + * is it possibly hostname/num ? + */ + if ((s = strchr(**seg, '/')) || + ((s = strchr(**seg, ':')) && !strchr(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, ifname) == -1) { + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); + return -1; + } + *sa &= *msk; + (*seg)++; + return 0; + } + + /* + * look for extra segments if "mask" found in right spot + */ + if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) { + if (hostnum(sa, **seg, linenum, ifname) == -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 0; + } + + if (**seg) { + u_32_t k; + + if (hostnum(sa, **seg, linenum, ifname) == -1) { + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); + return -1; + } + (*seg)++; + k = *sa ? 0xffffffff : 0; +#ifdef USE_INET6 + if (use_inet6) { + msk[1] = k; + msk[2] = k; + msk[3] = k; + } +#endif + *msk = k; + return 0; + } + fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); + return -1; +} diff --git a/contrib/ipfilter/lib/hostname.c b/contrib/ipfilter/lib/hostname.c new file mode 100644 index 0000000..a0109da --- /dev/null +++ b/contrib/ipfilter/lib/hostname.c @@ -0,0 +1,51 @@ +/* $NetBSD$ */ + + +#include "ipf.h" + +char *hostname(v, ip) +int v; +void *ip; +{ + static char hostbuf[MAXHOSTNAMELEN+1]; + struct hostent *hp; + struct in_addr ipa; + struct netent *np; + + if (v == 4) { + ipa.s_addr = *(u_32_t *)ip; + if (ipa.s_addr == htonl(0xfedcba98)) + return "test.host.dots"; + } + + if ((opts & OPT_NORESOLVE) == 0) { + if (v == 4) { + hp = gethostbyaddr(ip, 4, AF_INET); + if (hp != NULL && hp->h_name != NULL && + *hp->h_name != '\0') { + strncpy(hostbuf, hp->h_name, sizeof(hostbuf)); + hostbuf[sizeof(hostbuf) - 1] = '\0'; + return hostbuf; + } + + np = getnetbyaddr(ipa.s_addr, AF_INET); + if (np != NULL && np->n_name != NULL && + *np->n_name != '\0') { + strncpy(hostbuf, np->n_name, sizeof(hostbuf)); + hostbuf[sizeof(hostbuf) - 1] = '\0'; + return hostbuf; + } + } + } + + if (v == 4) { + 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 +} diff --git a/contrib/ipfilter/lib/hostnum.c b/contrib/ipfilter/lib/hostnum.c new file mode 100644 index 0000000..c62e4a1 --- /dev/null +++ b/contrib/ipfilter/lib/hostnum.c @@ -0,0 +1,49 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: hostnum.c,v 1.10.2.1 2004/12/09 19:41:20 darrenr Exp + */ + +#include <ctype.h> + +#include "ipf.h" + + +/* + * 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, ifname) +u_32_t *ipa; +char *host; +int linenum; +char *ifname; +{ + struct in_addr ip; + + if (!strcasecmp("any", host) || + (ifname && *ifname && !strcasecmp(ifname, 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; + + return gethost(host, ipa); +} diff --git a/contrib/ipfilter/lib/icmpcode.c b/contrib/ipfilter/lib/icmpcode.c new file mode 100644 index 0000000..17e1ba4 --- /dev/null +++ b/contrib/ipfilter/lib/icmpcode.c @@ -0,0 +1,49 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: icmpcode.c,v 1.7.2.1 2004/12/09 19:41:20 darrenr Exp + */ + +#include <ctype.h> + +#include "ipf.h" + +#ifndef MIN +# define MIN(a,b) ((a) > (b) ? (b) : (a)) +#endif + + +char *icmpcodes[MAX_ICMPCODE + 1] = { + "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail", + "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib", + "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff", + NULL }; + +/* + * Return the number for the associated ICMP unreachable code. + */ +int icmpcode(str) +char *str; +{ + char *s; + int i, len; + + if ((s = strrchr(str, ')'))) + *s = '\0'; + if (ISDIGIT(*str)) { + if (!ratoi(str, &i, 0, 255)) + return -1; + else + return i; + } + len = strlen(str); + for (i = 0; icmpcodes[i]; i++) + if (!strncasecmp(str, icmpcodes[i], MIN(len, + strlen(icmpcodes[i])) )) + return i; + return -1; +} diff --git a/contrib/ipfilter/lib/inet_addr.c b/contrib/ipfilter/lib/inet_addr.c new file mode 100644 index 0000000..5ccf6a9 --- /dev/null +++ b/contrib/ipfilter/lib/inet_addr.c @@ -0,0 +1,210 @@ +/* $NetBSD$ */ + +/* + * ++Copyright++ 1983, 1990, 1993 + * - + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if !defined(lint) +static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static const char rcsid[] = "@(#)Id: inet_addr.c,v 1.8.2.3 2004/12/09 19:41:20 darrenr Exp"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +#ifndef linux +int inet_aton __P((const char *, struct in_addr *)); + +/* + * Because the ctype(3) posix definition, if used "safely" in code everywhere, + * would mean all normal code that walks through strings needed casts. Yuck. + */ +#define ISALNUM(x) isalnum((u_char)(x)) +#define ISALPHA(x) isalpha((u_char)(x)) +#define ISASCII(x) isascii((u_char)(x)) +#define ISDIGIT(x) isdigit((u_char)(x)) +#define ISPRINT(x) isprint((u_char)(x)) +#define ISSPACE(x) isspace((u_char)(x)) +#define ISUPPER(x) isupper((u_char)(x)) +#define ISXDIGIT(x) isxdigit((u_char)(x)) +#define ISLOWER(x) islower((u_char)(x)) + +/* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(cp, addr) + register const char *cp; + struct in_addr *addr; +{ + register u_long val; + register int base, n; + register char c; + u_int parts[4]; + register u_int *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!ISDIGIT(c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else + base = 8; + } + for (;;) { + if (ISASCII(c) && ISDIGIT(c)) { + val = (val * base) + (c - '0'); + c = *++cp; + } else if (base == 16 && ISASCII(c) && ISXDIGIT(c)) { + val = (val << 4) | + (c + 10 - (ISLOWER(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!ISASCII(c) || !ISSPACE(c))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} +#endif + +/* these are compatibility routines, not needed on recent BSD releases */ + +/* + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +#if 0 +inet_addr(cp) + const char *cp; +{ + struct in_addr val; + + if (inet_aton(cp, &val)) + return (val.s_addr); + return (0xffffffff); +} +#endif diff --git a/contrib/ipfilter/lib/initparse.c b/contrib/ipfilter/lib/initparse.c new file mode 100644 index 0000000..676774c --- /dev/null +++ b/contrib/ipfilter/lib/initparse.c @@ -0,0 +1,20 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: initparse.c,v 1.6 2002/01/28 06:50:46 darrenr Exp + */ +#include "ipf.h" + + +char thishost[MAXHOSTNAMELEN]; + + +void initparse __P((void)) +{ + gethostname(thishost, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; +} diff --git a/contrib/ipfilter/lib/ionames.c b/contrib/ipfilter/lib/ionames.c new file mode 100644 index 0000000..9e4602b --- /dev/null +++ b/contrib/ipfilter/lib/ionames.c @@ -0,0 +1,40 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ionames.c,v 1.7 2002/01/28 06:50:46 darrenr Exp + */ +#include "ipf.h" + + +struct ipopt_names ionames[] ={ + { IPOPT_NOP, 0x000001, 1, "nop" }, /* RFC791 */ + { IPOPT_RR, 0x000002, 7, "rr" }, /* 1 route */ + { IPOPT_ZSU, 0x000004, 3, "zsu" }, /* size ?? */ + { IPOPT_MTUP, 0x000008, 3, "mtup" }, /* RFC1191 */ + { IPOPT_MTUR, 0x000010, 3, "mtur" }, /* RFC1191 */ + { IPOPT_ENCODE, 0x000020, 3, "encode" }, /* size ?? */ + { IPOPT_TS, 0x000040, 8, "ts" }, /* 1 TS */ + { IPOPT_TR, 0x000080, 3, "tr" }, /* RFC1393 */ + { IPOPT_SECURITY,0x000100, 11, "sec" }, /* RFC1108 */ + { IPOPT_SECURITY,0x000100, 11, "sec-class" }, /* RFC1108 */ + { IPOPT_LSRR, 0x000200, 7, "lsrr" }, /* 1 route */ + { IPOPT_E_SEC, 0x000400, 3, "e-sec" }, /* RFC1108 */ + { IPOPT_CIPSO, 0x000800, 3, "cipso" }, /* size ?? */ + { IPOPT_SATID, 0x001000, 4, "satid" }, /* RFC791 */ + { IPOPT_SSRR, 0x002000, 7, "ssrr" }, /* 1 route */ + { IPOPT_ADDEXT, 0x004000, 3, "addext" }, /* IPv7 ?? */ + { IPOPT_VISA, 0x008000, 3, "visa" }, /* size ?? */ + { IPOPT_IMITD, 0x010000, 3, "imitd" }, /* size ?? */ + { IPOPT_EIP, 0x020000, 3, "eip" }, /* RFC1385 */ + { IPOPT_FINN, 0x040000, 3, "finn" }, /* size ?? */ + { IPOPT_DPS, 0x080000, 3, "dps" }, /* size ?? */ + { IPOPT_SDB, 0x100000, 3, "sdb" }, /* size ?? */ + { IPOPT_NSAPA, 0x200000, 3, "nsapa" }, /* size ?? */ + { IPOPT_RTRALRT,0x400000, 3, "rtralrt" }, /* RFC2113 */ + { IPOPT_UMP, 0x800000, 3, "ump" }, /* size ?? */ + { 0, 0, 0, (char *)NULL } /* must be last */ +}; diff --git a/contrib/ipfilter/lib/ipf_dotuning.c b/contrib/ipfilter/lib/ipf_dotuning.c new file mode 100644 index 0000000..c9416ff --- /dev/null +++ b/contrib/ipfilter/lib/ipf_dotuning.c @@ -0,0 +1,60 @@ +/* $NetBSD$ */ + +#include "ipf.h" +#include "ipl.h" +#include <sys/ioctl.h> + +void ipf_dotuning(fd, tuneargs, iocfn) +int fd; +char *tuneargs; +ioctlfunc_t iocfn; +{ + ipfobj_t obj; + ipftune_t tu; + char *s, *t; + + bzero((char *)&tu, sizeof(tu)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(tu);; + obj.ipfo_ptr = (void *)&tu; + obj.ipfo_type = IPFOBJ_TUNEABLE; + + for (s = strtok(tuneargs, ","); s != NULL; s = strtok(NULL, ",")) { + if (!strcmp(s, "list")) { + while (1) { + if ((*iocfn)(fd, SIOCIPFGETNEXT, &obj) == -1) { + perror("ioctl(SIOCIPFGETNEXT)"); + break; + } + if (tu.ipft_cookie == NULL) + break; + + tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; + printtunable(&tu); + } + } else if ((t = strchr(s, '=')) != NULL) { + *t++ = '\0'; + strncpy(tu.ipft_name, s, sizeof(tu.ipft_name)); + if (sscanf(t, "%lu", &tu.ipft_vlong) == 1) { + if ((*iocfn)(fd, SIOCIPFSET, &obj) == -1) { + perror("ioctl(SIOCIPFSET)"); + return; + } + } else { + fprintf(stderr, "invalid value '%s'\n", s); + return; + } + } else { + strncpy(tu.ipft_name, s, sizeof(tu.ipft_name)); + if ((*iocfn)(fd, SIOCIPFGET, &obj) == -1) { + perror("ioctl(SIOCIPFGET)"); + return; + } + if (tu.ipft_cookie == NULL) + return; + + tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; + printtunable(&tu); + } + } +} diff --git a/contrib/ipfilter/lib/ipft_ef.c b/contrib/ipfilter/lib/ipft_ef.c new file mode 100644 index 0000000..eebc417 --- /dev/null +++ b/contrib/ipfilter/lib/ipft_ef.c @@ -0,0 +1,130 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ipft_ef.c,v 1.14 2004/01/08 13:34:31 darrenr Exp + */ + +/* + icmp type + lnth proto source destination src port dst port + +etherfind -n + + 60 tcp 128.250.20.20 128.250.133.13 2419 telnet + +etherfind -n -t + + 0.32 91 04 131.170.1.10 128.250.133.13 + 0.33 566 udp 128.250.37.155 128.250.133.3 901 901 +*/ + +#include "ipf.h" +#include "ipt.h" + +#ifndef linux +#include <netinet/ip_var.h> +#endif +#include <netinet/tcpip.h> + + +#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 1.14 2004/01/08 13:34:31 darrenr Exp"; +#endif + +static int etherf_open __P((char *)); +static int etherf_close __P((void)); +static int etherf_readip __P((char *, int, char **, int *)); + +struct ipread etherf = { etherf_open, etherf_close, etherf_readip, 0 }; + +static FILE *efp = NULL; +static int efd = -1; + + +static int etherf_open(fname) +char *fname; +{ + if (efd != -1) + return efd; + + if (!strcmp(fname, "-")) { + efd = 0; + efp = stdin; + } else { + efd = open(fname, O_RDONLY); + efp = fdopen(efd, "r"); + } + return efd; +} + + +static int etherf_close() +{ + return close(efd); +} + + +static int etherf_readip(buf, cnt, ifn, dir) +char *buf, **ifn; +int cnt, *dir; +{ + struct tcpiphdr pkt; + ip_t *ip = (ip_t *)&pkt; + char src[16], dst[16], sprt[16], dprt[16]; + char lbuf[128], len[8], prot[8], time[8], *s; + int slen, extra = 0, i; + + if (!fgets(lbuf, sizeof(lbuf) - 1, efp)) + return 0; + + if ((s = strchr(lbuf, '\n'))) + *s = '\0'; + lbuf[sizeof(lbuf)-1] = '\0'; + + bzero(&pkt, sizeof(pkt)); + + if (sscanf(lbuf, "%7s %7s %15s %15s %15s %15s", len, prot, src, dst, + sprt, dprt) != 6) + if (sscanf(lbuf, "%7s %7s %7s %15s %15s %15s %15s", time, + len, prot, src, dst, sprt, dprt) != 7) + return -1; + + ip->ip_p = getproto(prot); + + switch (ip->ip_p) { + case IPPROTO_TCP : + case IPPROTO_UDP : + s = strtok(NULL, " :"); + ip->ip_len += atoi(s); + if (ip->ip_p == IPPROTO_TCP) + extra = sizeof(struct tcphdr); + else if (ip->ip_p == IPPROTO_UDP) + extra = sizeof(struct udphdr); + break; +#ifdef IGMP + case IPPROTO_IGMP : + extra = sizeof(struct igmp); + break; +#endif + case IPPROTO_ICMP : + extra = sizeof(struct icmp); + break; + default : + break; + } + + (void) inet_aton(src, &ip->ip_src); + (void) inet_aton(dst, &ip->ip_dst); + ip->ip_len = atoi(len); + IP_HL_A(ip, sizeof(ip_t)); + + slen = IP_HL(ip) + extra; + i = MIN(cnt, slen); + bcopy((char *)&pkt, buf, i); + return i; +} diff --git a/contrib/ipfilter/lib/ipft_hx.c b/contrib/ipfilter/lib/ipft_hx.c new file mode 100644 index 0000000..3cc8ec5 --- /dev/null +++ b/contrib/ipfilter/lib/ipft_hx.c @@ -0,0 +1,158 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1995-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#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 1.11.4.1 2004/12/09 19:41:20 darrenr Exp"; +#endif + +#include <ctype.h> + +#include "ipf.h" +#include "ipt.h" + + +extern int opts; + +static int hex_open __P((char *)); +static int hex_close __P((void)); +static int hex_readip __P((char *, int, char **, int *)); +static char *readhex __P((char *, char *)); + +struct ipread iphex = { hex_open, hex_close, hex_readip, 0 }; +static FILE *tfp = NULL; +static int tfd = -1; + +static int hex_open(fname) +char *fname; +{ + if (tfp && tfd != -1) { + rewind(tfp); + return tfd; + } + + if (!strcmp(fname, "-")) { + tfd = 0; + tfp = stdin; + } else { + tfd = open(fname, O_RDONLY); + if (tfd != -1) + tfp = fdopen(tfd, "r"); + } + return tfd; +} + + +static int hex_close() +{ + int cfd = tfd; + + tfd = -1; + return close(cfd); +} + + +static int hex_readip(buf, cnt, ifn, dir) +char *buf, **ifn; +int cnt, *dir; +{ + register char *s, *t, *u; + char line[513]; + ip_t *ip; + + /* + * interpret start of line as possibly "[ifname]" or + * "[in/out,ifname]". + */ + if (ifn) + *ifn = NULL; + if (dir) + *dir = 0; + ip = (ip_t *)buf; + while (fgets(line, sizeof(line)-1, tfp)) { + if ((s = strchr(line, '\n'))) { + if (s == line) + return (char *)ip - buf; + *s = '\0'; + } + if ((s = strchr(line, '#'))) + *s = '\0'; + if (!*line) + continue; + if (!(opts & OPT_BRIEF)) { + printf("input: %s", line); + } + + if ((*line == '[') && (s = strchr(line, ']'))) { + t = line + 1; + if (s - t > 0) { + *s++ = '\0'; + if ((u = strchr(t, ',')) && (u < s)) { + u++; + if (ifn) + *ifn = strdup(u); + if (dir) { + if (*t == 'i') + *dir = 0; + else if (*t == 'o') + *dir = 1; + } + } else if (ifn) + *ifn = t; + } + } else + s = line; + t = (char *)ip; + ip = (ip_t *)readhex(s, (char *)ip); + if (!(opts & OPT_BRIEF)) { + if (opts & OPT_ASCII) { + if (t < (char *)ip) + putchar('\t'); + while (t < (char *)ip) { + if (ISPRINT(*t) && ISASCII(*t)) + putchar(*t); + else + putchar('.'); + t++; + } + } + putchar('\n'); + fflush(stdout); + } + } + return -1; +} + + +static char *readhex(src, dst) +register char *src, *dst; +{ + int state = 0; + char c; + + while ((c = *src++)) { + if (ISSPACE(c)) { + if (state) { + dst++; + state = 0; + } + continue; + } else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')) { + c = ISDIGIT(c) ? (c - '0') : (TOUPPER(c) - 55); + if (state == 0) { + *dst = (c << 4); + state++; + } else { + *dst++ |= c; + state = 0; + } + } else + break; + } + return dst; +} diff --git a/contrib/ipfilter/lib/ipft_pc.c b/contrib/ipfilter/lib/ipft_pc.c new file mode 100644 index 0000000..3678d78 --- /dev/null +++ b/contrib/ipfilter/lib/ipft_pc.c @@ -0,0 +1,252 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ipft_pc.c,v 1.10 2004/02/07 18:17:40 darrenr Exp + */ +#include "ipf.h" +#include "pcap-ipf.h" +#include "bpf-ipf.h" +#include "ipt.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: ipft_pc.c,v 1.10 2004/02/07 18:17:40 darrenr Exp"; +#endif + +struct llc { + int lc_type; + int lc_sz; /* LLC header length */ + int lc_to; /* LLC Type offset */ + int lc_tl; /* LLC Type length */ +}; + +/* + * While many of these maybe the same, some do have different header formats + * which make this useful. + */ + +static struct llc llcs[] = { + { DLT_NULL, 0, 0, 0 }, + { DLT_EN10MB, 14, 12, 2 }, + { DLT_EN3MB, 0, 0, 0 }, + { DLT_AX25, 0, 0, 0 }, + { DLT_PRONET, 0, 0, 0 }, + { DLT_CHAOS, 0, 0, 0 }, + { DLT_IEEE802, 0, 0, 0 }, + { DLT_ARCNET, 0, 0, 0 }, + { DLT_SLIP, 0, 0, 0 }, + { DLT_PPP, 0, 0, 0 }, + { DLT_FDDI, 0, 0, 0 }, +#ifdef DLT_ATMRFC1483 + { DLT_ATMRFC1483, 0, 0, 0 }, +#endif + { DLT_RAW, 0, 0, 0 }, +#ifdef DLT_ENC + { DLT_ENC, 0, 0, 0 }, +#endif +#ifdef DLT_SLIP_BSDOS + { DLT_SLIP_BSDOS, 0, 0, 0 }, +#endif +#ifdef DLT_PPP_BSDOS + { DLT_PPP_BSDOS, 0, 0, 0 }, +#endif +#ifdef DLT_HIPPI + { DLT_HIPPI, 0, 0, 0 }, +#endif +#ifdef DLT_HDLC + { DLT_HDLC, 0, 0, 0 }, +#endif +#ifdef DLT_PPP_SERIAL + { DLT_PPP_SERIAL, 4, 4, 0 }, +#endif +#ifdef DLT_PPP_ETHER + { DLT_PPP_ETHER, 8, 8, 0 }, +#endif +#ifdef DLT_ECONET + { DLT_ECONET, 0, 0, 0 }, +#endif + { -1, -1, -1, -1 } +}; + +static int pcap_open __P((char *)); +static int pcap_close __P((void)); +static int pcap_readip __P((char *, int, char **, int *)); +static void swap_hdr __P((pcaphdr_t *)); +static int pcap_read_rec __P((struct pcap_pkthdr *)); + +static int pfd = -1, swapped = 0; +static struct llc *llcp = NULL; + +struct ipread pcap = { pcap_open, pcap_close, pcap_readip, 0 }; + +#define SWAPLONG(y) \ + ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) +#define SWAPSHORT(y) \ + ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) ) + +static void swap_hdr(p) +pcaphdr_t *p; +{ + p->pc_v_maj = SWAPSHORT(p->pc_v_maj); + p->pc_v_min = SWAPSHORT(p->pc_v_min); + p->pc_zone = SWAPLONG(p->pc_zone); + p->pc_sigfigs = SWAPLONG(p->pc_sigfigs); + p->pc_slen = SWAPLONG(p->pc_slen); + p->pc_type = SWAPLONG(p->pc_type); +} + +static int pcap_open(fname) +char *fname; +{ + pcaphdr_t ph; + int fd, i; + + if (pfd != -1) + return pfd; + + if (!strcmp(fname, "-")) + fd = 0; + else if ((fd = open(fname, O_RDONLY)) == -1) + return -1; + + if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph)) + return -2; + + if (ph.pc_id != TCPDUMP_MAGIC) { + if (SWAPLONG(ph.pc_id) != TCPDUMP_MAGIC) { + (void) close(fd); + return -2; + } + swapped = 1; + swap_hdr(&ph); + } + + if (ph.pc_v_maj != PCAP_VERSION_MAJ) { + (void) close(fd); + return -2; + } + + for (i = 0; llcs[i].lc_type != -1; i++) + if (llcs[i].lc_type == ph.pc_type) { + llcp = llcs + i; + break; + } + + if (llcp == NULL) { + (void) close(fd); + return -2; + } + + pfd = fd; + printf("opened pcap file %s:\n", fname); + printf("\tid: %08x version: %d.%d type: %d snap %d\n", + ph.pc_id, ph.pc_v_maj, ph.pc_v_min, ph.pc_type, ph.pc_slen); + + return fd; +} + + +static int pcap_close() +{ + return close(pfd); +} + + +/* + * read in the header (and validate) which should be the first record + * in a pcap file. + */ +static int pcap_read_rec(rec) +struct pcap_pkthdr *rec; +{ + int n, p; + + if (read(pfd, (char *)rec, sizeof(*rec)) != sizeof(*rec)) + return -2; + + if (swapped) { + rec->ph_clen = SWAPLONG(rec->ph_clen); + rec->ph_len = SWAPLONG(rec->ph_len); + rec->ph_ts.tv_sec = SWAPLONG(rec->ph_ts.tv_sec); + rec->ph_ts.tv_usec = SWAPLONG(rec->ph_ts.tv_usec); + } + p = rec->ph_clen; + n = MIN(p, rec->ph_len); + if (!n || n < 0) + return -3; + + return p; +} + + +#ifdef notyet +/* + * read an entire pcap packet record. only the data part is copied into + * the available buffer, with the number of bytes copied returned. + */ +static int pcap_read(buf, cnt) +char *buf; +int cnt; +{ + struct pcap_pkthdr rec; + static char *bufp = NULL; + int i, n; + + if ((i = pcap_read_rec(&rec)) <= 0) + return i; + + if (!bufp) + bufp = malloc(i); + else + bufp = realloc(bufp, i); + + if (read(pfd, bufp, i) != i) + return -2; + + n = MIN(i, cnt); + bcopy(bufp, buf, n); + return n; +} +#endif + + +/* + * return only an IP packet read into buf + */ +static int pcap_readip(buf, cnt, ifn, dir) +char *buf, **ifn; +int cnt, *dir; +{ + static char *bufp = NULL; + struct pcap_pkthdr rec; + struct llc *l; + char *s, ty[4]; + int i, n; + + l = llcp; + + /* do { */ + if ((i = pcap_read_rec(&rec)) <= 0) + return i; + + if (!bufp) + bufp = malloc(i); + else + bufp = realloc(bufp, i); + s = bufp; + + if (read(pfd, s, i) != i) + return -2; + + i -= l->lc_sz; + s += l->lc_to; + bcopy(s, ty, l->lc_tl); + s += l->lc_tl; + /* } while (ty[0] != 0x8 && ty[1] != 0); */ + n = MIN(i, cnt); + bcopy(s, buf, n); + return n; +} diff --git a/contrib/ipfilter/lib/ipft_sn.c b/contrib/ipfilter/lib/ipft_sn.c new file mode 100644 index 0000000..1458821 --- /dev/null +++ b/contrib/ipfilter/lib/ipft_sn.c @@ -0,0 +1,197 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ipft_sn.c,v 1.7 2003/02/16 02:32:36 darrenr Exp + */ + +/* + * Written to comply with the recent RFC 1761 from Sun. + */ +#include "ipf.h" +#include "snoop.h" +#include "ipt.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: ipft_sn.c,v 1.7 2003/02/16 02:32:36 darrenr Exp"; +#endif + +struct llc { + int lc_sz; /* LLC header length */ + int lc_to; /* LLC Type offset */ + int lc_tl; /* LLC Type length */ +}; + +/* + * While many of these maybe the same, some do have different header formats + * which make this useful. + */ +static struct llc llcs[SDL_MAX+1] = { + { 0, 0, 0 }, /* SDL_8023 */ + { 0, 0, 0 }, /* SDL_8024 */ + { 0, 0, 0 }, /* SDL_8025 */ + { 0, 0, 0 }, /* SDL_8026 */ + { 14, 12, 2 }, /* SDL_ETHER */ + { 0, 0, 0 }, /* SDL_HDLC */ + { 0, 0, 0 }, /* SDL_CHSYNC */ + { 0, 0, 0 }, /* SDL_IBMCC */ + { 0, 0, 0 }, /* SDL_FDDI */ + { 0, 0, 0 }, /* SDL_OTHER */ +}; + +static int snoop_open __P((char *)); +static int snoop_close __P((void)); +static int snoop_readip __P((char *, int, char **, int *)); + +static int sfd = -1, s_type = -1; +static int snoop_read_rec __P((struct snooppkt *)); + +struct ipread snoop = { snoop_open, snoop_close, snoop_readip, 0 }; + + +static int snoop_open(fname) +char *fname; +{ + struct snoophdr sh; + int fd; + int s_v; + + if (sfd != -1) + return sfd; + + if (!strcmp(fname, "-")) + fd = 0; + else if ((fd = open(fname, O_RDONLY)) == -1) + return -1; + + if (read(fd, (char *)&sh, sizeof(sh)) != sizeof(sh)) + return -2; + + s_v = (int)ntohl(sh.s_v); + s_type = (int)ntohl(sh.s_type); + + if (s_v != SNOOP_VERSION || + s_type < 0 || s_type > SDL_MAX) { + (void) close(fd); + return -2; + } + + sfd = fd; + printf("opened snoop file %s:\n", fname); + printf("\tid: %8.8s version: %d type: %d\n", sh.s_id, s_v, s_type); + + return fd; +} + + +static int snoop_close() +{ + return close(sfd); +} + + +/* + * read in the header (and validate) which should be the first record + * in a snoop file. + */ +static int snoop_read_rec(rec) +struct snooppkt *rec; +{ + int n, plen, ilen; + + if (read(sfd, (char *)rec, sizeof(*rec)) != sizeof(*rec)) + return -2; + + ilen = (int)ntohl(rec->sp_ilen); + plen = (int)ntohl(rec->sp_plen); + if (ilen > plen || plen < sizeof(*rec)) + return -2; + + plen -= sizeof(*rec); + n = MIN(plen, ilen); + if (!n || n < 0) + return -3; + + return plen; +} + + +#ifdef notyet +/* + * read an entire snoop packet record. only the data part is copied into + * the available buffer, with the number of bytes copied returned. + */ +static int snoop_read(buf, cnt) +char *buf; +int cnt; +{ + struct snooppkt rec; + static char *bufp = NULL; + int i, n; + + if ((i = snoop_read_rec(&rec)) <= 0) + return i; + + if (!bufp) + bufp = malloc(i); + else + bufp = realloc(bufp, i); + + if (read(sfd, bufp, i) != i) + return -2; + + n = MIN(i, cnt); + bcopy(bufp, buf, n); + return n; +} +#endif + + +/* + * return only an IP packet read into buf + */ +static int snoop_readip(buf, cnt, ifn, dir) +char *buf, **ifn; +int cnt, *dir; +{ + static char *bufp = NULL; + struct snooppkt rec; + struct llc *l; + char ty[4], *s; + int i, n; + + do { + if ((i = snoop_read_rec(&rec)) <= 0) + return i; + + if (!bufp) + bufp = malloc(i); + else + bufp = realloc(bufp, i); + s = bufp; + + if (read(sfd, s, i) != i) + return -2; + + l = &llcs[s_type]; + i -= l->lc_to; + s += l->lc_to; + /* + * XXX - bogus assumption here on the part of the time field + * that it won't be greater than 4 bytes and the 1st two will + * have the values 8 and 0 for IP. Should be a table of + * these too somewhere. Really only works for SDL_ETHER. + */ + bcopy(s, ty, l->lc_tl); + } while (ty[0] != 0x8 && ty[1] != 0); + + i -= l->lc_tl; + s += l->lc_tl; + n = MIN(i, cnt); + bcopy(s, buf, n); + + return n; +} diff --git a/contrib/ipfilter/lib/ipft_td.c b/contrib/ipfilter/lib/ipft_td.c new file mode 100644 index 0000000..b278c72 --- /dev/null +++ b/contrib/ipfilter/lib/ipft_td.c @@ -0,0 +1,174 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ipft_td.c,v 1.15 2004/01/08 13:34:31 darrenr Exp + */ + +/* +tcpdump -n + +00:05:47.816843 128.231.76.76.3291 > 224.2.252.231.36573: udp 36 (encap) + +tcpdump -nq + +00:33:48.410771 192.73.213.11.1463 > 224.2.248.153.59360: udp 31 (encap) + +tcpdump -nqt + +128.250.133.13.23 > 128.250.20.20.2419: tcp 27 + +tcpdump -nqtt + +123456789.1234567 128.250.133.13.23 > 128.250.20.20.2419: tcp 27 + +tcpdump -nqte + +8:0:20:f:65:f7 0:0:c:1:8a:c5 81: 128.250.133.13.23 > 128.250.20.20.2419: tcp 27 + +*/ + +#include "ipf.h" +#include "ipt.h" + +#ifndef linux +#include <netinet/ip_var.h> +#endif +#include <netinet/tcpip.h> + + +#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 1.15 2004/01/08 13:34:31 darrenr Exp"; +#endif + +static int tcpd_open __P((char *)); +static int tcpd_close __P((void)); +static int tcpd_readip __P((char *, int, char **, int *)); +static int count_dots __P((char *)); + +struct ipread tcpd = { tcpd_open, tcpd_close, tcpd_readip, 0 }; + +static FILE *tfp = NULL; +static int tfd = -1; + + +static int tcpd_open(fname) +char *fname; +{ + if (tfd != -1) + return tfd; + + if (!strcmp(fname, "-")) { + tfd = 0; + tfp = stdin; + } else { + tfd = open(fname, O_RDONLY); + tfp = fdopen(tfd, "r"); + } + return tfd; +} + + +static int tcpd_close() +{ + (void) fclose(tfp); + return close(tfd); +} + + +static int count_dots(str) +char *str; +{ + int i = 0; + + while (*str) + if (*str++ == '.') + i++; + return i; +} + + +static int tcpd_readip(buf, cnt, ifn, dir) +char *buf, **ifn; +int cnt, *dir; +{ + struct tcpiphdr pkt; + ip_t *ip = (ip_t *)&pkt; + char src[32], dst[32], misc[256], time[32], link1[32], link2[32]; + char lbuf[160], *s; + int n, slen, extra = 0; + + if (!fgets(lbuf, sizeof(lbuf) - 1, tfp)) + return 0; + + if ((s = strchr(lbuf, '\n'))) + *s = '\0'; + lbuf[sizeof(lbuf)-1] = '\0'; + + bzero(&pkt, sizeof(pkt)); + + if ((n = sscanf(lbuf, "%31s > %31s: %255s", src, dst, misc)) != 3) + if ((n = sscanf(lbuf, "%31s %31s > %31s: %255s", + time, src, dst, misc)) != 4) + if ((n = sscanf(lbuf, "%31s %31s: %31s > %31s: %255s", + link1, link2, src, dst, misc)) != 5) { + n = sscanf(lbuf, + "%31s %31s %31s: %31s > %31s: %255s", + time, link1, link2, src, dst, misc); + if (n != 6) + return -1; + } + + if (count_dots(dst) == 4) { + s = strrchr(src, '.'); + *s++ = '\0'; + (void) inet_aton(src, &ip->ip_src); + pkt.ti_sport = htons(atoi(s)); + *--s = '.'; + s = strrchr(dst, '.'); + + *s++ = '\0'; + (void) inet_aton(src, &ip->ip_dst); + pkt.ti_dport = htons(atoi(s)); + *--s = '.'; + + } else { + (void) inet_aton(src, &ip->ip_src); + (void) inet_aton(src, &ip->ip_dst); + } + ip->ip_len = sizeof(ip_t); + IP_HL_A(ip, sizeof(ip_t)); + + s = strtok(misc, " :"); + ip->ip_p = getproto(s); + + switch (ip->ip_p) + { + case IPPROTO_TCP : + case IPPROTO_UDP : + s = strtok(NULL, " :"); + ip->ip_len += atoi(s); + if (ip->ip_p == IPPROTO_TCP) + extra = sizeof(struct tcphdr); + else if (ip->ip_p == IPPROTO_UDP) + extra = sizeof(struct udphdr); + break; +#ifdef IGMP + case IPPROTO_IGMP : + extra = sizeof(struct igmp); + break; +#endif + case IPPROTO_ICMP : + extra = sizeof(struct icmp); + break; + default : + break; + } + + slen = IP_HL(ip) + extra + ip->ip_len; + return slen; +} diff --git a/contrib/ipfilter/lib/ipft_tx.c b/contrib/ipfilter/lib/ipft_tx.c new file mode 100644 index 0000000..c77fbc4 --- /dev/null +++ b/contrib/ipfilter/lib/ipft_tx.c @@ -0,0 +1,331 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1995-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ipft_tx.c,v 1.15.2.2 2004/12/09 19:41:21 darrenr Exp + */ +#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 1.15.2.2 2004/12/09 19:41:21 darrenr Exp"; +#endif + +#include <ctype.h> + +#include "ipf.h" +#include "ipt.h" + +#ifndef linux +#include <netinet/ip_var.h> +#endif +#include <netinet/tcpip.h> + + +extern int opts; + +static char *tx_proto = ""; + +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[] = "FSRPAUEC"; +static u_char _tcp_flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, + TH_ACK, TH_URG, TH_ECN, TH_CWR }; + +struct ipread iptext = { text_open, text_close, text_readip, R_DO_CKSUM }; +static FILE *tfp = NULL; +static int tfd = -1; + +static u_32_t tx_hostnum __P((char *, int *)); +static u_short tx_portnum __P((char *)); + + +/* + * returns an ip address as a long var as a result of either a DNS lookup or + * straight inet_addr() call + */ +static u_32_t tx_hostnum(host, resolved) +char *host; +int *resolved; +{ + u_32_t ipa; + + *resolved = 0; + if (!strcasecmp("any", host)) + return 0L; + if (ISDIGIT(*host)) + return inet_addr(host); + + if (gethost(host, &ipa) == -1) { + *resolved = -1; + fprintf(stderr, "can't resolve hostname: %s\n", host); + return 0; + } + return ipa; +} + + +/* + * find the port number given by the name, either from getservbyname() or + * straight atoi() + */ +static u_short tx_portnum(name) +char *name; +{ + struct servent *sp, *sp2; + u_short p1 = 0; + + if (ISDIGIT(*name)) + return (u_short)atoi(name); + if (!tx_proto) + tx_proto = "tcp/udp"; + if (strcasecmp(tx_proto, "tcp/udp")) { + sp = getservbyname(name, tx_proto); + if (sp) + return ntohs(sp->s_port); + (void) fprintf(stderr, "unknown service \"%s\".\n", name); + return 0; + } + sp = getservbyname(name, "tcp"); + if (sp) + p1 = sp->s_port; + sp2 = getservbyname(name, "udp"); + if (!sp || !sp2) { + (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n", + name); + return 0; + } + if (p1 != sp2->s_port) { + (void) fprintf(stderr, "%s %d/tcp is a different port to ", + name, p1); + (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port); + return 0; + } + return ntohs(p1); +} + + +char *tx_icmptypes[] = { + "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", + "redir", (char *)NULL, (char *)NULL, "echo", "routerad", + "routersol", "timex", "paramprob", "timest", "timestrep", + "inforeq", "inforep", "maskreq", "maskrep", "END" +}; + +static int text_open(fname) +char *fname; +{ + if (tfp && tfd != -1) { + rewind(tfp); + return tfd; + } + + if (!strcmp(fname, "-")) { + tfd = 0; + tfp = stdin; + } else { + tfd = open(fname, O_RDONLY); + if (tfd != -1) + tfp = fdopen(tfd, "r"); + } + return tfd; +} + + +static int text_close() +{ + int cfd = tfd; + + tfd = -1; + return close(cfd); +} + + +static int text_readip(buf, cnt, ifn, dir) +char *buf, **ifn; +int cnt, *dir; +{ + register char *s; + char line[513]; + + *ifn = NULL; + while (fgets(line, sizeof(line)-1, tfp)) { + if ((s = strchr(line, '\n'))) + *s = '\0'; + if ((s = strchr(line, '\r'))) + *s = '\0'; + if ((s = strchr(line, '#'))) + *s = '\0'; + if (!*line) + continue; + if (!(opts & OPT_BRIEF)) + printf("input: %s\n", line); + *ifn = NULL; + *dir = 0; + if (!parseline(line, (ip_t *)buf, ifn, dir)) +#if 0 + return sizeof(ip_t) + sizeof(tcphdr_t); +#else + return sizeof(ip_t); +#endif + } + return -1; +} + +static int parseline(line, ip, ifn, out) +char *line; +ip_t *ip; +char **ifn; +int *out; +{ + tcphdr_t th, *tcp = &th; + struct icmp icmp, *ic = &icmp; + char *cps[20], **cpp, c, ipopts[68]; + int i, r; + + if (*ifn) + free(*ifn); + bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip)); + bzero((char *)tcp, sizeof(*tcp)); + bzero((char *)ic, sizeof(*ic)); + bzero(ipopts, sizeof(ipopts)); + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); + for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; ) + cps[++i] = strtok(NULL, " \b\t\r\n"); + + cpp = cps; + if (!*cpp) + return 1; + + c = **cpp; + if (!ISALPHA(c) || (TOLOWER(c) != 'o' && TOLOWER(c) != 'i')) { + fprintf(stderr, "bad direction \"%s\"\n", *cpp); + return 1; + } + *out = (TOLOWER(c) == 'o') ? 1 : 0; + cpp++; + if (!*cpp) + return 1; + + if (!strcasecmp(*cpp, "on")) { + cpp++; + if (!*cpp) + return 1; + *ifn = strdup(*cpp++); + if (!*cpp) + return 1; + } + + c = **cpp; + ip->ip_len = sizeof(ip_t); + if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") || + !strcasecmp(*cpp, "icmp")) { + if (c == 't') { + ip->ip_p = IPPROTO_TCP; + ip->ip_len += sizeof(struct tcphdr); + tx_proto = "tcp"; + } else if (c == 'u') { + ip->ip_p = IPPROTO_UDP; + ip->ip_len += sizeof(struct udphdr); + tx_proto = "udp"; + } else { + ip->ip_p = IPPROTO_ICMP; + ip->ip_len += ICMPERR_IPICMPHLEN; + tx_proto = "icmp"; + } + cpp++; + } else if (ISDIGIT(**cpp) && !index(*cpp, '.')) { + ip->ip_p = atoi(*cpp); + cpp++; + } else + ip->ip_p = IPPROTO_IP; + + if (!*cpp) + return 1; + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { + char *last; + + last = strchr(*cpp, ','); + if (!last) { + fprintf(stderr, "tcp/udp with no source port\n"); + return 1; + } + *last++ = '\0'; + tcp->th_sport = htons(tx_portnum(last)); + if (ip->ip_p == IPPROTO_TCP) { + tcp->th_win = htons(4096); + TCP_OFF_A(tcp, sizeof(*tcp) >> 2); + } + } + ip->ip_src.s_addr = tx_hostnum(*cpp, &r); + cpp++; + if (!*cpp) + return 1; + + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { + char *last; + + last = strchr(*cpp, ','); + if (!last) { + fprintf(stderr, "tcp/udp with no destination port\n"); + return 1; + } + *last++ = '\0'; + tcp->th_dport = htons(tx_portnum(last)); + } + 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[]; + char *s, *t; + + tcp->th_flags = 0; + for (s = *cpp; *s; s++) + if ((t = strchr(_tcp_flagset, *s))) + tcp->th_flags |= _tcp_flags[t - _tcp_flagset]; + if (tcp->th_flags) + cpp++; + if (tcp->th_flags == 0) + abort(); + if (tcp->th_flags & TH_URG) + tcp->th_urp = htons(1); + } else if (*cpp && ip->ip_p == IPPROTO_ICMP) { + extern char *tx_icmptypes[]; + char **s, *t; + int i; + + for (s = tx_icmptypes, i = 0; !*s || strcmp(*s, "END"); + s++, i++) + if (*s && !strncasecmp(*cpp, *s, strlen(*s))) { + ic->icmp_type = i; + if ((t = strchr(*cpp, ','))) + ic->icmp_code = atoi(t+1); + cpp++; + break; + } + } + + if (*cpp && !strcasecmp(*cpp, "opt")) { + u_long olen; + + cpp++; + olen = buildopts(*cpp, ipopts, (IP_HL(ip) - 5) << 2); + if (olen) { + bcopy(ipopts, (char *)(ip + 1), olen); + IP_HL_A(ip, IP_HL(ip) + (olen >> 2)); + } + } + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + bcopy((char *)tcp, ((char *)ip) + (IP_HL(ip) << 2), + sizeof(*tcp)); + else if (ip->ip_p == IPPROTO_ICMP) + bcopy((char *)ic, ((char *)ip) + (IP_HL(ip) << 2), + sizeof(*ic)); + ip->ip_len = htons(ip->ip_len); + return 0; +} diff --git a/contrib/ipfilter/lib/ipoptsec.c b/contrib/ipfilter/lib/ipoptsec.c new file mode 100644 index 0000000..95bde9c --- /dev/null +++ b/contrib/ipfilter/lib/ipoptsec.c @@ -0,0 +1,58 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ipoptsec.c,v 1.2 2002/01/28 06:50:46 darrenr Exp + */ + +#include "ipf.h" + + +struct ipopt_names secclass[] = { + { IPSO_CLASS_RES4, 0x01, 0, "reserv-4" }, + { IPSO_CLASS_TOPS, 0x02, 0, "topsecret" }, + { IPSO_CLASS_SECR, 0x04, 0, "secret" }, + { IPSO_CLASS_RES3, 0x08, 0, "reserv-3" }, + { IPSO_CLASS_CONF, 0x10, 0, "confid" }, + { IPSO_CLASS_UNCL, 0x20, 0, "unclass" }, + { IPSO_CLASS_RES2, 0x40, 0, "reserv-2" }, + { IPSO_CLASS_RES1, 0x80, 0, "reserv-1" }, + { 0, 0, 0, NULL } /* must be last */ +}; + + +u_char seclevel(slevel) +char *slevel; +{ + struct ipopt_names *so; + + for (so = secclass; so->on_name; so++) + if (!strcasecmp(slevel, so->on_name)) + break; + + if (!so->on_name) { + fprintf(stderr, "no such security level: %s\n", slevel); + return 0; + } + return (u_char)so->on_value; +} + + +u_char secbit(class) +int class; +{ + struct ipopt_names *so; + + for (so = secclass; so->on_name; so++) + if (so->on_value == class) + break; + + if (!so->on_name) { + fprintf(stderr, "no such security class: %d\n", class); + return 0; + } + return (u_char)so->on_bit; +} diff --git a/contrib/ipfilter/lib/kmem.c b/contrib/ipfilter/lib/kmem.c new file mode 100644 index 0000000..3f044bb --- /dev/null +++ b/contrib/ipfilter/lib/kmem.c @@ -0,0 +1,203 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * kmemcpy() - copies n bytes from kernel memory into user buffer. + * returns 0 on success, -1 on error. + */ + +#include <stdio.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/file.h> +#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && !defined(linux) +#include <kvm.h> +#endif +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#if defined(linux) || defined(__osf__) || defined(__sgi) || defined(__hpux) +# include <stdlib.h> +#endif + +#include "kmem.h" + +#ifndef __STDC__ +# define const +#endif + +#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 1.16.2.1 2004/06/20 10:25:58 darrenr Exp"; +#endif + + + +#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && !defined(linux) +/* + * For all platforms where there is a libkvm and a kvm_t, we use that... + */ +static kvm_t *kvm_f = NULL; + +#else +/* + *...and for the others (HP-UX, IRIX, Tru64), we have to provide our own. + */ + +typedef int * kvm_t; + +static kvm_t kvm_f = NULL; +static char *kvm_errstr = NULL; + +kvm_t kvm_open __P((char *, char *, char *, int, char *)); +int kvm_read __P((kvm_t, u_long, char *, size_t)); + +kvm_t kvm_open(kernel, core, swap, mode, errstr) +char *kernel, *core, *swap; +int mode; +char *errstr; +{ + kvm_t k; + int fd; + + kvm_errstr = errstr; + + if (core == NULL) + core = "/dev/kmem"; + + fd = open(core, mode); + if (fd == -1) + return NULL; + k = malloc(sizeof(*k)); + if (k == NULL) + return NULL; + *k = fd; + return k; +} + +int kvm_read(kvm, pos, buffer, size) +kvm_t kvm; +u_long pos; +char *buffer; +size_t size; +{ + int r = 0, left; + char *bufp; + + if (lseek(*kvm, pos, 0) == -1) { + if (kvm_errstr != NULL) { + fprintf(stderr, "%s", kvm_errstr); + perror("lseek"); + } + return -1; + } + + for (bufp = buffer, left = size; left > 0; bufp += r, left -= r) { + r = read(*kvm, bufp, left); +#ifdef __osf__ + /* + * Tru64 returns "0" for successful operation, not the number + * of bytes read. + */ + if (r == 0) + r = left; +#endif + if (r <= 0) + return -1; + } + return r; +} +#endif /* !defined(__sgi) && !defined(__hpux) && !defined(__osf__) */ + +int openkmem(kern, core) +char *kern, *core; +{ + kvm_f = kvm_open(kern, core, NULL, O_RDONLY, NULL); + if (kvm_f == NULL) + { + perror("openkmem:open"); + return -1; + } + return kvm_f != NULL; +} + +int kmemcpy(buf, pos, n) +register char *buf; +long pos; +register int n; +{ + register int r; + + if (!n) + return 0; + + if (kvm_f == NULL) + if (openkmem(NULL, NULL) == -1) + return -1; + + while ((r = kvm_read(kvm_f, pos, buf, n)) < n) + if (r <= 0) + { + fprintf(stderr, "pos=0x%lx ", (u_long)pos); + perror("kmemcpy:read"); + return -1; + } + else + { + buf += r; + pos += r; + n -= r; + } + return 0; +} + +int kstrncpy(buf, pos, n) +register char *buf; +long pos; +register int n; +{ + register int r; + + if (!n) + return 0; + + if (kvm_f == NULL) + if (openkmem(NULL, NULL) == -1) + return -1; + + while (n > 0) + { + r = kvm_read(kvm_f, pos, buf, 1); + if (r <= 0) + { + fprintf(stderr, "pos=0x%lx ", (u_long)pos); + perror("kmemcpy:read"); + return -1; + } + else + { + if (*buf == '\0') + break; + buf++; + pos++; + n--; + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/kmem.h b/contrib/ipfilter/lib/kmem.h new file mode 100644 index 0000000..07a14f5 --- /dev/null +++ b/contrib/ipfilter/lib/kmem.h @@ -0,0 +1,34 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * Id: kmem.h,v 1.2 2002/08/21 22:57:36 darrenr Exp + */ + +#ifndef __KMEM_H__ +#define __KMEM_H__ + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +extern int openkmem __P((char *, char *)); +extern int kmemcpy __P((char *, long, int)); +extern int kstrncpy __P((char *, long, int)); + +#if defined(__NetBSD__) || defined(__OpenBSD) +# include <paths.h> +#endif + +#ifdef _PATH_KMEM +# define KMEM _PATH_KMEM +#else +# define KMEM "/dev/kmem" +#endif + +#endif /* __KMEM_H__ */ diff --git a/contrib/ipfilter/lib/kmemcpywrap.c b/contrib/ipfilter/lib/kmemcpywrap.c new file mode 100644 index 0000000..274bcb1 --- /dev/null +++ b/contrib/ipfilter/lib/kmemcpywrap.c @@ -0,0 +1,15 @@ +/* $NetBSD$ */ + +#include "ipf.h" +#include "kmem.h" + +int kmemcpywrap(from, to, size) +void *from, *to; +size_t size; +{ + int ret; + + ret = kmemcpy((caddr_t)to, (u_long)from, size); + return ret; +} + diff --git a/contrib/ipfilter/lib/kvatoname.c b/contrib/ipfilter/lib/kvatoname.c new file mode 100644 index 0000000..030c633 --- /dev/null +++ b/contrib/ipfilter/lib/kvatoname.c @@ -0,0 +1,31 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +#include <fcntl.h> +#include <sys/ioctl.h> + +char *kvatoname(func, iocfunc) +ipfunc_t func; +ioctlfunc_t iocfunc; +{ + static char funcname[40]; + ipfunc_resolve_t res; + int fd; + + res.ipfu_addr = func; + res.ipfu_name[0] = '\0'; + fd = -1; + + if ((opts & OPT_DONOTHING) == 0) { + fd = open(IPL_NAME, O_RDONLY); + if (fd == -1) + return NULL; + } + (void) (*iocfunc)(fd, SIOCFUNCL, &res); + if (fd >= 0) + close(fd); + strncpy(funcname, res.ipfu_name, sizeof(funcname)); + funcname[sizeof(funcname) - 1] = '\0'; + return funcname; +} diff --git a/contrib/ipfilter/lib/load_hash.c b/contrib/ipfilter/lib/load_hash.c new file mode 100644 index 0000000..4fc042b --- /dev/null +++ b/contrib/ipfilter/lib/load_hash.c @@ -0,0 +1,112 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: load_hash.c,v 1.11.2.2 2005/02/01 02:44:05 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + +static int hashfd = -1; + + +int load_hash(iphp, list, iocfunc) +iphtable_t *iphp; +iphtent_t *list; +ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtable_t iph; + iphtent_t *a; + size_t size; + int n; + + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + hashfd = open(IPLOOKUP_NAME, O_RDWR); + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + for (n = 0, a = list; a != NULL; a = a->ipe_next) + n++; + + op.iplo_arg = 0; + op.iplo_type = IPLT_HASH; + op.iplo_unit = iphp->iph_unit; + strncpy(op.iplo_name, iphp->iph_name, sizeof(op.iplo_name)); + if (*op.iplo_name == '\0') + op.iplo_arg = IPHASH_ANON; + op.iplo_size = sizeof(iph); + op.iplo_struct = &iph; + iph.iph_unit = iphp->iph_unit; + iph.iph_type = iphp->iph_type; + strncpy(iph.iph_name, iphp->iph_name, sizeof(iph.iph_name)); + iph.iph_flags = iphp->iph_flags; + if (n <= 0) + n = 1; + if (iphp->iph_size == 0) + size = n * 2 - 1; + else + size = iphp->iph_size; + if ((list == NULL) && (size == 1)) { + fprintf(stderr, + "WARNING: empty hash table %s, recommend setting %s\n", + iphp->iph_name, "size to match expected use"); + } + iph.iph_size = size; + iph.iph_seed = iphp->iph_seed; + iph.iph_table = NULL; + iph.iph_ref = 0; + + if ((opts & OPT_REMOVE) == 0) { + if ((*iocfunc)(hashfd, SIOCLOOKUPADDTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + perror("load_hash:SIOCLOOKUPADDTABLE"); + return -1; + } + } + + strncpy(op.iplo_name, iph.iph_name, sizeof(op.iplo_name)); + strncpy(iphp->iph_name, iph.iph_name, sizeof(op.iplo_name)); + + if (opts & OPT_VERBOSE) { + for (a = list; a != NULL; a = a->ipe_next) { + a->ipe_addr.in4_addr = ntohl(a->ipe_addr.in4_addr); + a->ipe_mask.in4_addr = ntohl(a->ipe_mask.in4_addr); + } + iph.iph_table = calloc(size, sizeof(*iph.iph_table)); + if (iph.iph_table == NULL) { + perror("calloc(size, sizeof(*iph.iph_table))"); + return -1; + } + iph.iph_table[0] = list; + printhash(&iph, bcopywrap, iph.iph_name, opts); + free(iph.iph_table); + + for (a = list; a != NULL; a = a->ipe_next) { + a->ipe_addr.in4_addr = htonl(a->ipe_addr.in4_addr); + a->ipe_mask.in4_addr = htonl(a->ipe_mask.in4_addr); + } + } + + if (opts & OPT_DEBUG) + printf("Hash %s:\n", iph.iph_name); + + for (a = list; a != NULL; a = a->ipe_next) + load_hashnode(iphp->iph_unit, iph.iph_name, a, iocfunc); + + if ((opts & OPT_REMOVE) != 0) { + if ((*iocfunc)(hashfd, SIOCLOOKUPDELTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + perror("load_hash:SIOCLOOKUPDELTABLE"); + return -1; + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/load_hashnode.c b/contrib/ipfilter/lib/load_hashnode.c new file mode 100644 index 0000000..186ba05 --- /dev/null +++ b/contrib/ipfilter/lib/load_hashnode.c @@ -0,0 +1,61 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: load_hashnode.c,v 1.2.4.1 2004/03/06 14:33:28 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + +static int hashfd = -1; + + +int load_hashnode(unit, name, node, iocfunc) +int unit; +char *name; +iphtent_t *node; +ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtent_t ipe; + int err; + + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + hashfd = open(IPLOOKUP_NAME, O_RDWR); + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + op.iplo_type = IPLT_HASH; + op.iplo_unit = unit; + op.iplo_arg = 0; + op.iplo_size = sizeof(ipe); + op.iplo_struct = &ipe; + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + + bzero((char *)&ipe, sizeof(ipe)); + bcopy((char *)&node->ipe_addr, (char *)&ipe.ipe_addr, + sizeof(ipe.ipe_addr)); + bcopy((char *)&node->ipe_mask, (char *)&ipe.ipe_mask, + sizeof(ipe.ipe_mask)); + bcopy((char *)&node->ipe_group, (char *)&ipe.ipe_group, + sizeof(ipe.ipe_group)); + + if ((opts & OPT_REMOVE) == 0) + err = (*iocfunc)(hashfd, SIOCLOOKUPADDNODE, &op); + else + err = (*iocfunc)(hashfd, SIOCLOOKUPDELNODE, &op); + + if (err != 0) + if (!(opts & OPT_DONOTHING)) { + perror("load_hash:SIOCLOOKUP*NODE"); + return -1; + } + return 0; +} diff --git a/contrib/ipfilter/lib/load_pool.c b/contrib/ipfilter/lib/load_pool.c new file mode 100644 index 0000000..5fab311 --- /dev/null +++ b/contrib/ipfilter/lib/load_pool.c @@ -0,0 +1,69 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: load_pool.c,v 1.14.2.2 2005/02/01 02:44:06 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + +static int poolfd = -1; + + +int load_pool(plp, iocfunc) +ip_pool_t *plp; +ioctlfunc_t iocfunc; +{ + iplookupop_t op; + ip_pool_node_t *a; + ip_pool_t pool; + + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + poolfd = open(IPLOOKUP_NAME, O_RDWR); + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + op.iplo_unit = plp->ipo_unit; + op.iplo_type = IPLT_POOL; + op.iplo_arg = 0; + strncpy(op.iplo_name, plp->ipo_name, sizeof(op.iplo_name)); + op.iplo_size = sizeof(pool); + op.iplo_struct = &pool; + bzero((char *)&pool, sizeof(pool)); + strncpy(pool.ipo_name, plp->ipo_name, sizeof(pool.ipo_name)); + if (*plp->ipo_name == '\0') + op.iplo_arg |= IPOOL_ANON; + + if ((opts & OPT_REMOVE) == 0) { + if ((*iocfunc)(poolfd, SIOCLOOKUPADDTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + perror("load_pool:SIOCLOOKUPADDTABLE"); + return -1; + } + } + + if ((opts & OPT_VERBOSE) != 0) { + pool.ipo_list = plp->ipo_list; + printpool(&pool, bcopywrap, pool.ipo_name, opts); + pool.ipo_list = NULL; + } + + for (a = plp->ipo_list; a != NULL; a = a->ipn_next) + load_poolnode(plp->ipo_unit, plp->ipo_name, a, iocfunc); + + if ((opts & OPT_REMOVE) != 0) { + if ((*iocfunc)(poolfd, SIOCLOOKUPDELTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + perror("load_pool:SIOCLOOKUPDELTABLE"); + return -1; + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/load_poolnode.c b/contrib/ipfilter/lib/load_poolnode.c new file mode 100644 index 0000000..e9d233f --- /dev/null +++ b/contrib/ipfilter/lib/load_poolnode.c @@ -0,0 +1,63 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: load_poolnode.c,v 1.3.2.1 2004/03/06 14:33:29 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + +static int poolfd = -1; + + +int load_poolnode(role, name, node, iocfunc) +int role; +char *name; +ip_pool_node_t *node; +ioctlfunc_t iocfunc; +{ + ip_pool_node_t pn; + iplookupop_t op; + int err; + + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + poolfd = open(IPLOOKUP_NAME, O_RDWR); + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + op.iplo_unit = role; + op.iplo_type = IPLT_POOL; + op.iplo_arg = 0; + op.iplo_struct = &pn; + op.iplo_size = sizeof(pn); + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + + bzero((char *)&pn, sizeof(pn)); + bcopy((char *)&node->ipn_addr, (char *)&pn.ipn_addr, + sizeof(pn.ipn_addr)); + bcopy((char *)&node->ipn_mask, (char *)&pn.ipn_mask, + sizeof(pn.ipn_mask)); + pn.ipn_info = node->ipn_info; + strncpy(pn.ipn_name, node->ipn_name, sizeof(pn.ipn_name)); + + if ((opts & OPT_REMOVE) == 0) + err = (*iocfunc)(poolfd, SIOCLOOKUPADDNODE, &op); + else + err = (*iocfunc)(poolfd, SIOCLOOKUPDELNODE, &op); + + if (err != 0) { + if ((opts & OPT_DONOTHING) == 0) { + perror("load_pool:SIOCLOOKUP*NODE"); + return -1; + } + } + + return 0; +} diff --git a/contrib/ipfilter/lib/loglevel.c b/contrib/ipfilter/lib/loglevel.c new file mode 100644 index 0000000..31b4f17 --- /dev/null +++ b/contrib/ipfilter/lib/loglevel.c @@ -0,0 +1,55 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: loglevel.c,v 1.5 2001/06/09 17:09:24 darrenr Exp + */ + +#include "ipf.h" + + +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 = strchr(*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; +} diff --git a/contrib/ipfilter/lib/make_range.c b/contrib/ipfilter/lib/make_range.c new file mode 100644 index 0000000..9ec3ca3 --- /dev/null +++ b/contrib/ipfilter/lib/make_range.c @@ -0,0 +1,26 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: make_range.c,v 1.2 2002/05/18 07:27:52 darrenr Exp + */ +#include "ipf.h" + + +alist_t *make_range(not, a1, a2) +int not; +struct in_addr a1, a2; +{ + alist_t *a; + + a = (alist_t *)calloc(1, sizeof(*a)); + if (a != NULL) { + a->al_1 = a1.s_addr; + a->al_2 = a2.s_addr; + a->al_not = not; + } + return a; +} diff --git a/contrib/ipfilter/lib/mutex_emul.c b/contrib/ipfilter/lib/mutex_emul.c new file mode 100644 index 0000000..43b7f76 --- /dev/null +++ b/contrib/ipfilter/lib/mutex_emul.c @@ -0,0 +1,80 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +#define EMM_MAGIC 0x9d7adba3 + +void eMmutex_enter(mtx, file, line) +eMmutex_t *mtx; +char *file; +int line; +{ + if (mtx->eMm_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMmutex_enter(%p): bad magic: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + if (mtx->eMm_held != 0) { + fprintf(stderr, "%s:eMmutex_enter(%p): already locked: %d\n", + mtx->eMm_owner, mtx, mtx->eMm_held); + abort(); + } + mtx->eMm_held++; + mtx->eMm_heldin = file; + mtx->eMm_heldat = line; +} + + +void eMmutex_exit(mtx) +eMmutex_t *mtx; +{ + if (mtx->eMm_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMmutex_exit(%p): bad magic: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + if (mtx->eMm_held != 1) { + fprintf(stderr, "%s:eMmutex_exit(%p): not locked: %d\n", + mtx->eMm_owner, mtx, mtx->eMm_held); + abort(); + } + mtx->eMm_held--; + mtx->eMm_heldin = NULL; + mtx->eMm_heldat = 0; +} + + +void eMmutex_init(mtx, who) +eMmutex_t *mtx; +char *who; +{ + if (mtx->eMm_magic == EMM_MAGIC) { /* safe bet ? */ + fprintf(stderr, + "%s:eMmutex_init(%p): already initialised?: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + mtx->eMm_magic = EMM_MAGIC; + mtx->eMm_held = 0; + if (who != NULL) + mtx->eMm_owner = strdup(who); + else + mtx->eMm_owner = NULL; +} + + +void eMmutex_destroy(mtx) +eMmutex_t *mtx; +{ + if (mtx->eMm_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMmutex_destroy(%p): bad magic: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + if (mtx->eMm_held != 0) { + fprintf(stderr, "%s:eMmutex_enter(%p): still locked: %d\n", + mtx->eMm_owner, mtx, mtx->eMm_held); + abort(); + } + memset(mtx, 0xa5, sizeof(*mtx)); +} diff --git a/contrib/ipfilter/lib/nametokva.c b/contrib/ipfilter/lib/nametokva.c new file mode 100644 index 0000000..50f3077 --- /dev/null +++ b/contrib/ipfilter/lib/nametokva.c @@ -0,0 +1,30 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +#include <sys/ioctl.h> +#include <fcntl.h> + +ipfunc_t nametokva(name, iocfunc) +char *name; +ioctlfunc_t iocfunc; +{ + ipfunc_resolve_t res; + int fd; + + strncpy(res.ipfu_name, name, sizeof(res.ipfu_name)); + res.ipfu_addr = NULL; + fd = -1; + + if ((opts & OPT_DONOTHING) == 0) { + fd = open(IPL_NAME, O_RDONLY); + if (fd == -1) + return NULL; + } + (void) (*iocfunc)(fd, SIOCFUNCL, &res); + if (fd >= 0) + close(fd); + if (res.ipfu_addr == NULL) + res.ipfu_addr = (ipfunc_t)-1; + return res.ipfu_addr; +} diff --git a/contrib/ipfilter/lib/nat_setgroupmap.c b/contrib/ipfilter/lib/nat_setgroupmap.c new file mode 100644 index 0000000..ce64abb --- /dev/null +++ b/contrib/ipfilter/lib/nat_setgroupmap.c @@ -0,0 +1,34 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char rcsid[] = "@(#)Id: nat_setgroupmap.c,v 1.1 2003/04/13 06:40:14 darrenr Exp"; +#endif + +#include "ipf.h" + +void nat_setgroupmap(n) +ipnat_t *n; +{ + if (n->in_outmsk == n->in_inmsk) + n->in_ippip = 1; + else if (n->in_flags & IPN_AUTOPORTMAP) { + n->in_ippip = ~ntohl(n->in_inmsk); + if (n->in_outmsk != 0xffffffff) + n->in_ippip /= (~ntohl(n->in_outmsk) + 1); + n->in_ippip++; + if (n->in_ippip == 0) + n->in_ippip = 1; + n->in_ppip = USABLE_PORTS / n->in_ippip; + } else { + n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); + n->in_nip = 0; + if (!(n->in_ppip = n->in_pmin)) + n->in_ppip = 1; + n->in_ippip = USABLE_PORTS / n->in_ppip; + } +} diff --git a/contrib/ipfilter/lib/natparse.c b/contrib/ipfilter/lib/natparse.c new file mode 100644 index 0000000..adbbeb9 --- /dev/null +++ b/contrib/ipfilter/lib/natparse.c @@ -0,0 +1,730 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#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.8.2.1 2004/12/09 19:41:21 darrenr Exp"; +#endif + +#include <sys/ioctl.h> +#include <errno.h> +#include <ctype.h> + +#include "ipf.h" +#include "opts.h" + + +void nat_setgroupmap(n) +ipnat_t *n; +{ + if (n->in_outmsk == n->in_inmsk) + n->in_ippip = 1; + else if (n->in_flags & IPN_AUTOPORTMAP) { + n->in_ippip = ~ntohl(n->in_inmsk); + if (n->in_outmsk != 0xffffffff) + n->in_ippip /= (~ntohl(n->in_outmsk) + 1); + n->in_ippip++; + if (n->in_ippip == 0) + n->in_ippip = 1; + n->in_ppip = USABLE_PORTS / n->in_ippip; + } else { + n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); + n->in_nip = 0; + if (!(n->in_ppip = n->in_pmin)) + n->in_ppip = 1; + n->in_ippip = USABLE_PORTS / n->in_ppip; + } +} + + + +ipnat_t *natparse(line, linenum) +char *line; +int linenum; +{ + static ipnat_t ipn; + struct protoent *pr; + char *dnetm = NULL, *dport = NULL, *proto = NULL; + char *s, *t, *cps[31], **cpp; + int i, cnt; + + + if ((s = strchr(line, '\n'))) + *s = '\0'; + if ((s = strchr(line, '#'))) + *s = '\0'; + while (*line && ISSPACE(*line)) + line++; + if (!*line) + return NULL; + + 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; + } + + cpp = cps; + + if (!strcasecmp(*cpp, "map")) + ipn.in_redir = NAT_MAP; + else if (!strcasecmp(*cpp, "map-block")) + ipn.in_redir = NAT_MAPBLK; + else if (!strcasecmp(*cpp, "rdr")) + ipn.in_redir = NAT_REDIRECT; + else if (!strcasecmp(*cpp, "bimap")) + ipn.in_redir = NAT_BIMAP; + else { + fprintf(stderr, "%d: unknown mapping: \"%s\"\n", + linenum, *cpp); + return NULL; + } + + cpp++; + + strncpy(ipn.in_ifnames[0], *cpp, sizeof(ipn.in_ifnames[0]) - 1); + ipn.in_ifnames[0][sizeof(ipn.in_ifnames[0]) - 1] = '\0'; + cpp++; + + if (!strcasecmp(*cpp, "from") || (**cpp == '!')) { + if (!strcmp(*cpp, "!")) { + cpp++; + if (strcasecmp(*cpp, "from")) { + fprintf(stderr, "Missing from after !\n"); + return NULL; + } + ipn.in_flags |= IPN_NOTSRC; + } else if (**cpp == '!') { + if (strcasecmp(*cpp + 1, "from")) { + fprintf(stderr, "Missing from after !\n"); + return NULL; + } + ipn.in_flags |= IPN_NOTSRC; + } + if ((ipn.in_flags & IPN_NOTSRC) && + (ipn.in_redir & (NAT_MAP|NAT_MAPBLK))) { + fprintf(stderr, "Cannot use '! from' with map\n"); + return NULL; + } + + ipn.in_flags |= IPN_FILTER; + cpp++; + if (ipn.in_redir == NAT_REDIRECT) { + if (hostmask(&cpp, proto, NULL, + (u_32_t *)&ipn.in_srcip, + (u_32_t *)&ipn.in_srcmsk, linenum) == -1) + return NULL; + + if (ports(&cpp, proto, &ipn.in_sport, + &ipn.in_scmp, &ipn.in_stop, linenum)) + return NULL; + } else { + if (hostmask(&cpp, proto, NULL, + (u_32_t *)&ipn.in_inip, + (u_32_t *)&ipn.in_inmsk, linenum) == -1) + return NULL; + + if (ports(&cpp, proto, &ipn.in_dport, + &ipn.in_dcmp, &ipn.in_dtop, linenum)) + return NULL; + } + + if (!strcmp(*cpp, "!")) { + cpp++; + ipn.in_flags |= IPN_NOTDST; + } else if (**cpp == '!') { + (*cpp)++; + ipn.in_flags |= IPN_NOTDST; + } + + if (strcasecmp(*cpp, "to")) { + fprintf(stderr, "%d: unexpected keyword (%s) - to\n", + linenum, *cpp); + return NULL; + } + if ((ipn.in_flags & IPN_NOTDST) && + (ipn.in_redir & (NAT_REDIRECT))) { + fprintf(stderr, "Cannot use '! to' with rdr\n"); + return NULL; + } + + if (!*++cpp) { + fprintf(stderr, "%d: missing host after to\n", linenum); + return NULL; + } + if (ipn.in_redir == NAT_REDIRECT) { + if (hostmask(&cpp, proto, NULL, + (u_32_t *)&ipn.in_outip, + (u_32_t *)&ipn.in_outmsk, linenum)) + return NULL; + + if (ports(&cpp, proto, &ipn.in_dport, + &ipn.in_dcmp, &ipn.in_dtop, linenum)) + return NULL; + ipn.in_pmin = htons(ipn.in_dport); + } else { + if (hostmask(&cpp, proto, NULL, + (u_32_t *)&ipn.in_srcip, + (u_32_t *)&ipn.in_srcmsk, linenum)) + return NULL; + + if (ports(&cpp, proto, &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, NULL)) + return NULL; + if (genmask(t, (u_32_t *)&ipn.in_outmsk) == -1) { + return NULL; + } + } else { + if (hostnum((u_32_t *)&ipn.in_inip, s, linenum, NULL)) + return NULL; + if (genmask(t, (u_32_t *)&ipn.in_inmsk) == -1) { + return NULL; + } + } + cpp++; + if (!*cpp) + return NULL; + } + + 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; + } + + cpp++; + + if (!*cpp) { + fprintf(stderr, + "%d: missing fields (destination port)\n", + linenum); + return NULL; + } + + if (ISDIGIT(**cpp) && (s = strchr(*cpp, '-'))) + *s++ = '\0'; + else + s = NULL; + + if (!portnum(*cpp, proto, &ipn.in_pmin, linenum)) + return NULL; + ipn.in_pmin = htons(ipn.in_pmin); + cpp++; + + if (!strcmp(*cpp, "-")) { + cpp++; + s = *cpp++; + } + + if (s) { + if (!portnum(s, proto, &ipn.in_pmax, linenum)) + return NULL; + ipn.in_pmax = htons(ipn.in_pmax); + } else + ipn.in_pmax = ipn.in_pmin; + } + + if (!*cpp) { + fprintf(stderr, "%d: missing fields (->)\n", linenum); + return NULL; + } + if (strcmp(*cpp, "->")) { + fprintf(stderr, "%d: missing ->\n", linenum); + return NULL; + } + cpp++; + + if (!*cpp) { + fprintf(stderr, "%d: missing fields (%s)\n", + linenum, ipn.in_redir ? "destination" : "target"); + return NULL; + } + + if (ipn.in_redir == NAT_MAP) { + 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"); + return NULL; + } + } + } + + 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; + } + 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, NULL)) + return NULL; + } else { + if (hostnum((u_32_t *)&ipn.in_outip, *cpp, linenum, NULL)) + return NULL; + } + cpp++; + + if (ipn.in_redir & NAT_MAPBLK) { + if (*cpp && strcasecmp(*cpp, "ports")) { + fprintf(stderr, + "%d: expected \"ports\" - got \"%s\"\n", + linenum, *cpp); + return NULL; + } + cpp++; + if (*cpp) { + ipn.in_pmin = atoi(*cpp); + cpp++; + } else + ipn.in_pmin = 0; + } else if ((ipn.in_redir & NAT_BIMAP) == NAT_REDIRECT) { + if (*cpp && 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 (!*cpp || strcasecmp(*cpp, "port")) { + fprintf(stderr, "%d: missing fields - 2nd port (%s)\n", + linenum, *cpp); + return NULL; + } + cpp++; + if (!*cpp) { + fprintf(stderr, + "%d: missing fields (destination port)\n", + linenum); + return NULL; + } + if (!portnum(*cpp, proto, &ipn.in_pnext, linenum)) + return NULL; + ipn.in_pnext = htons(ipn.in_pnext); + cpp++; + } + if (dnetm && *dnetm == '/') + *dnetm++ = '\0'; + + if (ipn.in_redir & (NAT_MAP|NAT_MAPBLK)) { + if (ipn.in_flags & IPN_IPRANGE) { + if (hostnum((u_32_t *)&ipn.in_outmsk, dnetm, + linenum, NULL) == -1) + return NULL; + } else if (genmask(dnetm, (u_32_t *)&ipn.in_outmsk)) + return NULL; + } else { + if (ipn.in_flags & IPN_SPLIT) { + if (hostnum((u_32_t *)&ipn.in_inmsk, dnetm, + linenum, NULL) == -1) + return NULL; + } else if (genmask("255.255.255.255", (u_32_t *)&ipn.in_inmsk)) + return NULL; + if (!*cpp) { + ipn.in_flags |= IPN_TCP; /* XXX- TCP only by default */ + proto = "tcp"; + } else { + 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; + ipn.in_p = getproto(*cpp); + } + proto = *cpp; + cpp++; + + if (*cpp && !strcasecmp(*cpp, "round-robin")) { + cpp++; + ipn.in_flags |= IPN_ROUNDR; + } + + if (*cpp && !strcasecmp(*cpp, "frag")) { + cpp++; + ipn.in_flags |= IPN_FRAG; + } + + if (*cpp && !strcasecmp(*cpp, "age")) { + cpp++; + if (!*cpp) { + fprintf(stderr, + "%d: age with no parameters\n", + linenum); + return NULL; + } + + ipn.in_age[0] = atoi(*cpp); + s = strchr(*cpp, '/'); + if (s != NULL) + ipn.in_age[1] = atoi(s + 1); + else + ipn.in_age[1] = ipn.in_age[0]; + cpp++; + } + + if (*cpp && !strcasecmp(*cpp, "mssclamp")) { + cpp++; + if (*cpp) { + ipn.in_mssclamp = atoi(*cpp); + cpp++; + } else { + fprintf(stderr, + "%d: mssclamp with no parameters\n", + linenum); + return NULL; + } + } + + if (*cpp) { + fprintf(stderr, + "%d: extra junk at the end of rdr: %s\n", + linenum, *cpp); + return NULL; + } + } + } + + 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 (*cpp && !strcasecmp(*cpp, "frag")) { + cpp++; + ipn.in_flags |= IPN_ROUNDR; + } + + if (!*cpp) + return &ipn; + + if (ipn.in_redir != NAT_BIMAP && !strcasecmp(*cpp, "proxy")) { + if (ipn.in_redir == NAT_BIMAP) { + fprintf(stderr, "%d: cannot use proxy with bimap\n", + linenum); + return NULL; + } + + cpp++; + if (!*cpp) { + fprintf(stderr, + "%d: missing parameter for \"proxy\"\n", + linenum); + return NULL; + } + dport = NULL; + + if (!strcasecmp(*cpp, "port")) { + cpp++; + if (!*cpp) { + fprintf(stderr, + "%d: missing parameter for \"port\"\n", + linenum); + return NULL; + } + + dport = *cpp; + cpp++; + + if (!*cpp) { + fprintf(stderr, + "%d: missing parameter for \"proxy\"\n", + linenum); + return NULL; + } + } else { + fprintf(stderr, + "%d: missing keyword \"port\"\n", linenum); + return NULL; + } + + if ((proto = strchr(*cpp, '/'))) { + *proto++ = '\0'; + ipn.in_p = getproto(proto); + } else + ipn.in_p = 0; + + if (dport && !portnum(dport, proto, &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(*cpp, "icmpidmap")) { + + cpp++; + if (!*cpp) { + fprintf(stderr, + "%d: icmpidmap misses protocol and range\n", + linenum); + return NULL; + }; + + if (!strcasecmp(*cpp, "icmp")) + ipn.in_flags = IPN_ICMPQUERY; + else { + fprintf(stderr, "%d: icmpidmap only valid for icmp\n", + linenum); + return NULL; + } + cpp++; + + if (!*cpp) { + fprintf(stderr, "%d: no icmp id argument found\n", + linenum); + return NULL; + } + + if (!(t = strchr(*cpp, ':'))) { + fprintf(stderr, + "%d: no icmp id range detected in \"%s\"\n", + linenum, *cpp); + return NULL; + } + *t++ = '\0'; + + if (!icmpidnum(*cpp, &ipn.in_pmin, linenum) || + !icmpidnum(t, &ipn.in_pmax, linenum)) + return NULL; + } else if (!strcasecmp(*cpp, "portmap")) { + if (ipn.in_redir == NAT_BIMAP) { + fprintf(stderr, "%d: cannot use proxy with bimap\n", + linenum); + return NULL; + } + cpp++; + if (!*cpp) { + fprintf(stderr, + "%d: missing expression following portmap\n", + linenum); + return NULL; + } + + 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, *cpp); + return NULL; + } + proto = *cpp; + cpp++; + + if (!*cpp) { + fprintf(stderr, "%d: no port range found\n", linenum); + return NULL; + } + + if (!strcasecmp(*cpp, "auto")) { + ipn.in_flags |= IPN_AUTOPORTMAP; + ipn.in_pmin = htons(1024); + ipn.in_pmax = htons(65535); + nat_setgroupmap(&ipn); + } else { + if (!(t = strchr(*cpp, ':'))) { + fprintf(stderr, + "%d: no port range in \"%s\"\n", + linenum, *cpp); + return NULL; + } + *t++ = '\0'; + if (!portnum(*cpp, proto, &ipn.in_pmin, linenum) || + !portnum(t, proto, &ipn.in_pmax, linenum)) + return NULL; + } + cpp++; + } + + if (*cpp && !strcasecmp(*cpp, "round-robin")) { + cpp++; + ipn.in_flags |= IPN_ROUNDR; + } + + if (*cpp && !strcasecmp(*cpp, "age")) { + cpp++; + if (!*cpp) { + fprintf(stderr, "%d: age with no parameters\n", + linenum); + return NULL; + } + s = strchr(*cpp, '/'); + if (s != NULL) + ipn.in_age[1] = atoi(s + 1); + else + ipn.in_age[1] = ipn.in_age[0]; + cpp++; + } + + if (*cpp && !strcasecmp(*cpp, "mssclamp")) { + cpp++; + if (*cpp) { + ipn.in_mssclamp = atoi(*cpp); + cpp++; + } else { + fprintf(stderr, "%d: mssclamp with no parameters\n", + linenum); + return NULL; + } + } + + if (*cpp) { + fprintf(stderr, "%d: extra junk at the end of the line: %s\n", + linenum, *cpp); + return NULL; + } + + ipn.in_pmin = htons(ipn.in_pmin); + ipn.in_pmax = htons(ipn.in_pmax); + return &ipn; +} + + +void natparsefile(fd, file, opts) +int fd; +char *file; +int opts; +{ + char line[512], *s; + ipnat_t *np; + FILE *fp; + int linenum = 0; + + if (strcmp(file, "-")) { + if (!(fp = fopen(file, "r"))) { + fprintf(stderr, "%s: open: %s\n", file, + STRERROR(errno)); + exit(1); + } + } else + fp = stdin; + + while (getline(line, sizeof(line) - 1, fp, &linenum)) { + line[sizeof(line) - 1] = '\0'; + if ((s = strchr(line, '\n'))) + *s = '\0'; + + if (!(np = natparse(line, linenum))) { + if (*line) + fprintf(stderr, "%d: syntax error in \"%s\"\n", + linenum, line); + } else { + if ((opts & OPT_VERBOSE) && np) + printnat(np, opts); + if (!(opts & OPT_DONOTHING)) { + if (!(opts & OPT_REMOVE)) { + if (ioctl(fd, SIOCADNAT, &np) == -1) + perror("ioctl(SIOCADNAT)"); + } else if (ioctl(fd, SIOCRMNAT, &np) == -1) + perror("ioctl(SIOCRMNAT)"); + } + } + } + if (fp != stdin) + fclose(fp); +} + + +int icmpidnum(str, id, linenum) +char *str; +u_short *id; +int linenum; +{ + int i; + + + i = atoi(str); + + if ((i<0) || (i>65535)) { + fprintf(stderr, "%d: invalid icmp id\"%s\".\n", linenum, str); + return 0; + } + + *id = (u_short)i; + + return 1; +} diff --git a/contrib/ipfilter/lib/ntomask.c b/contrib/ipfilter/lib/ntomask.c new file mode 100644 index 0000000..415a5e8 --- /dev/null +++ b/contrib/ipfilter/lib/ntomask.c @@ -0,0 +1,38 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +int ntomask(v, nbits, ap) +int v, nbits; +u_32_t *ap; +{ + u_32_t mask; + + if (nbits < 0) + return -1; + + switch (v) + { + case 4 : + if (nbits > 32 || use_inet6 != 0) + return -1; + if (nbits == 0) { + mask = 0; + } else { + mask = 0xffffffff; + mask <<= (32 - nbits); + } + *ap = htonl(mask); + break; + + case 6 : + if ((nbits > 128) || (use_inet6 == 0)) + return -1; + fill6bits(nbits, ap); + break; + + default : + return -1; + } + return 0; +} diff --git a/contrib/ipfilter/lib/optname.c b/contrib/ipfilter/lib/optname.c new file mode 100644 index 0000000..7fdcc57 --- /dev/null +++ b/contrib/ipfilter/lib/optname.c @@ -0,0 +1,65 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: optname.c,v 1.3 2001/06/09 17:09:24 darrenr Exp + */ + +#include "ipf.h" + + +u_32_t optname(cp, sp, linenum) +char ***cp; +u_short *sp; +int linenum; +{ + struct ipopt_names *io, *so; + u_long msk = 0; + u_short smsk = 0; + char *s; + int sec = 0; + + for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { + for (io = ionames; io->on_name; io++) + if (!strcasecmp(s, io->on_name)) { + msk |= io->on_bit; + break; + } + if (!io->on_name) { + fprintf(stderr, "%d: unknown IP option name %s\n", + linenum, s); + return 0; + } + if (!strcasecmp(s, "sec-class")) + sec = 1; + } + + if (sec && !*(*cp + 1)) { + fprintf(stderr, "%d: missing security level after sec-class\n", + linenum); + return 0; + } + + if (sec) { + (*cp)++; + for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { + for (so = secclass; so->on_name; so++) + if (!strcasecmp(s, so->on_name)) { + smsk |= so->on_bit; + break; + } + if (!so->on_name) { + fprintf(stderr, + "%d: no such security level: %s\n", + linenum, s); + return 0; + } + } + if (smsk) + *sp = smsk; + } + return msk; +} diff --git a/contrib/ipfilter/lib/optprint.c b/contrib/ipfilter/lib/optprint.c new file mode 100644 index 0000000..261a75c --- /dev/null +++ b/contrib/ipfilter/lib/optprint.c @@ -0,0 +1,79 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: optprint.c,v 1.6 2002/07/13 15:59:49 darrenr Exp + */ +#include "ipf.h" + + +void optprint(sec, optmsk, optbits) +u_short *sec; +u_long optmsk, optbits; +{ + u_short secmsk = sec[0], secbits = sec[1]; + struct ipopt_names *io, *so; + char *s; + + s = " opt "; + for (io = ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) == (io->on_bit & optbits))) { + if ((io->on_value != IPOPT_SECURITY) || + (!secmsk && !secbits)) { + printf("%s%s", s, io->on_name); + if (io->on_value == IPOPT_SECURITY) + io++; + s = ","; + } + } + + + if (secmsk & secbits) { + printf("%ssec-class", s); + s = " "; + for (so = secclass; so->on_name; so++) + if ((secmsk & so->on_bit) && + ((so->on_bit & secmsk) == (so->on_bit & secbits))) { + printf("%s%s", s, so->on_name); + s = ","; + } + } + + if ((optmsk && (optmsk != optbits)) || + (secmsk && (secmsk != secbits))) { + s = " "; + printf(" not opt"); + if (optmsk != optbits) { + for (io = ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) != + (io->on_bit & optbits))) { + if ((io->on_value != IPOPT_SECURITY) || + (!secmsk && !secbits)) { + printf("%s%s", s, io->on_name); + s = ","; + if (io->on_value == + IPOPT_SECURITY) + io++; + } else + io++; + } + } + + if (secmsk != secbits) { + printf("%ssec-class", s); + s = " "; + for (so = secclass; so->on_name; so++) + if ((so->on_bit & secmsk) && + ((so->on_bit & secmsk) != + (so->on_bit & secbits))) { + printf("%s%s", s, so->on_name); + s = ","; + } + } + } +} diff --git a/contrib/ipfilter/lib/optprintv6.c b/contrib/ipfilter/lib/optprintv6.c new file mode 100644 index 0000000..75e0fd0 --- /dev/null +++ b/contrib/ipfilter/lib/optprintv6.c @@ -0,0 +1,47 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: optprintv6.c,v 1.2 2003/04/30 00:39:39 darrenr Exp + */ +#include "ipf.h" + + +#ifdef USE_INET6 + +void optprintv6(sec, optmsk, optbits) +u_short *sec; +u_long optmsk, optbits; +{ + u_short secmsk = sec[0], secbits = sec[1]; + struct ipopt_names *io; + char *s; + + s = " v6hdrs "; + for (io = v6ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) == (io->on_bit & optbits))) { + printf("%s%s", s, io->on_name); + s = ","; + } + + if ((optmsk && (optmsk != optbits)) || + (secmsk && (secmsk != secbits))) { + s = " "; + printf(" not v6hdrs"); + if (optmsk != optbits) { + for (io = v6ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) != + (io->on_bit & optbits))) { + printf("%s%s", s, io->on_name); + s = ","; + } + } + + } +} +#endif diff --git a/contrib/ipfilter/lib/optvalue.c b/contrib/ipfilter/lib/optvalue.c new file mode 100644 index 0000000..dc9448d --- /dev/null +++ b/contrib/ipfilter/lib/optvalue.c @@ -0,0 +1,34 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: optvalue.c,v 1.2 2002/01/28 06:50:47 darrenr Exp + */ +#include "ipf.h" + + +u_32_t getoptbyname(optname) +char *optname; +{ + struct ipopt_names *io; + + for (io = ionames; io->on_name; io++) + if (!strcasecmp(optname, io->on_name)) + return io->on_bit; + return -1; +} + + +u_32_t getoptbyvalue(optval) +int optval; +{ + struct ipopt_names *io; + + for (io = ionames; io->on_name; io++) + if (io->on_value == optval) + return io->on_bit; + return -1; +} diff --git a/contrib/ipfilter/lib/parse.c b/contrib/ipfilter/lib/parse.c new file mode 100644 index 0000000..4cf69ab --- /dev/null +++ b/contrib/ipfilter/lib/parse.c @@ -0,0 +1,754 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: parse.c,v 1.34.2.1 2004/12/09 19:41:21 darrenr Exp + */ +#include <ctype.h> +#include "ipf.h" +#include "opts.h" + +static frentry_t *fp = NULL; + +/* parse() + * + * parse a line read from the input filter rule file + */ +struct frentry *parse(line, linenum) +char *line; +int linenum; +{ + static fripf_t fip; + char *cps[31], **cpp, *endptr, *proto = NULL, *s; + struct protoent *p = NULL; + int i, cnt = 1, j; + u_int k; + + if (fp == NULL) { + fp = malloc(sizeof(*fp)); + if (fp == NULL) + return NULL; + } + + while (*line && ISSPACE(*line)) + line++; + if (!*line) + return NULL; + + bzero((char *)fp, sizeof(*fp)); + bzero((char *)&fip, sizeof(fip)); + fp->fr_v = use_inet6 ? 6 : 4; + fp->fr_ipf = &fip; + fp->fr_dsize = sizeof(fip); + fp->fr_ip.fi_v = fp->fr_v; + fp->fr_mip.fi_v = 0xf; + fp->fr_type = FR_T_NONE; + fp->fr_loglevel = 0xffff; + fp->fr_isc = (void *)-1; + fp->fr_tag = FR_NOTAG; + + /* + * break line up into max of 20 segments + */ + if (opts & OPT_DEBUG) + fprintf(stderr, "parse [%s]\n", line); + 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; + } + + cpp = cps; + /* + * The presence of an '@' followed by a number gives the position in + * the current rule list to insert this one. + */ + if (**cpp == '@') + fp->fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1; + + /* + * Check the first keyword in the rule and any options that are + * expected to follow it. + */ + if (!strcasecmp("block", *cpp)) { + fp->fr_flags |= FR_BLOCK; + if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) && + (i = 19)) + fp->fr_flags |= FR_FAKEICMP; + else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11)) + fp->fr_flags |= FR_RETICMP; + if (fp->fr_flags & FR_RETICMP) { + cpp++; + if (strlen(*cpp) == i) { + if (*(cpp + 1) && **(cpp +1) == '(') { + cpp++; + i = 0; + } else + i = -1; + } + + /* + * The ICMP code is not required to follow in ()'s + */ + if ((i >= 0) && (*(*cpp + i) == '(')) { + i++; + j = icmpcode(*cpp + i); + if (j == -1) { + fprintf(stderr, + "%d: unrecognised icmp code %s\n", + linenum, *cpp + 20); + return NULL; + } + fp->fr_icode = j; + } + } else if (!strncasecmp(*(cpp+1), "return-rst", 10)) { + fp->fr_flags |= FR_RETRST; + cpp++; + } + } else if (!strcasecmp("count", *cpp)) { + fp->fr_flags |= FR_ACCOUNT; + } else if (!strcasecmp("pass", *cpp)) { + fp->fr_flags |= FR_PASS; + } else if (!strcasecmp("auth", *cpp)) { + fp->fr_flags |= FR_AUTH; + } else if (fp->fr_arg != 0) { + printf("skip %u", fp->fr_arg); + } else if (!strcasecmp("preauth", *cpp)) { + fp->fr_flags |= FR_PREAUTH; + } else if (!strcasecmp("nomatch", *cpp)) { + fp->fr_flags |= FR_NOMATCH; + } else if (!strcasecmp("skip", *cpp)) { + cpp++; + if (ratoui(*cpp, &k, 0, UINT_MAX)) + fp->fr_arg = k; + else { + fprintf(stderr, "%d: integer must follow skip\n", + linenum); + return NULL; + } + } else if (!strcasecmp("log", *cpp)) { + fp->fr_flags |= FR_LOG; + if (!strcasecmp(*(cpp+1), "body")) { + fp->fr_flags |= FR_LOGBODY; + cpp++; + } + if (!strcasecmp(*(cpp+1), "first")) { + fp->fr_flags |= FR_LOGFIRST; + cpp++; + } + if (*cpp && !strcasecmp(*(cpp+1), "or-block")) { + fp->fr_flags |= FR_LOGORBLOCK; + cpp++; + } + if (!strcasecmp(*(cpp+1), "level")) { + cpp++; + if (loglevel(cpp, &fp->fr_loglevel, linenum) == -1) + return NULL; + cpp++; + } + } else { + /* + * Doesn't start with one of the action words + */ + fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp); + return NULL; + } + if (!*++cpp) { + fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum); + return NULL; + } + + /* + * Get the direction for filtering. Impose restrictions on direction + * if blocking with returning ICMP or an RST has been requested. + */ + if (!strcasecmp("in", *cpp)) + fp->fr_flags |= FR_INQUE; + else if (!strcasecmp("out", *cpp)) { + fp->fr_flags |= FR_OUTQUE; + if (fp->fr_flags & FR_RETICMP) { + fprintf(stderr, + "%d: Can only use return-icmp with 'in'\n", + linenum); + return NULL; + } else if (fp->fr_flags & FR_RETRST) { + fprintf(stderr, + "%d: Can only use return-rst with 'in'\n", + linenum); + return NULL; + } + } + if (!*++cpp) { + fprintf(stderr, "%d: missing source specification\n", linenum); + return NULL; + } + + if (!strcasecmp("log", *cpp)) { + if (!*++cpp) { + fprintf(stderr, "%d: missing source specification\n", + linenum); + return NULL; + } + if (FR_ISPASS(fp->fr_flags)) + fp->fr_flags |= FR_LOGP; + else if (FR_ISBLOCK(fp->fr_flags)) + fp->fr_flags |= FR_LOGB; + if (*cpp && !strcasecmp(*cpp, "body")) { + fp->fr_flags |= FR_LOGBODY; + cpp++; + } + if (*cpp && !strcasecmp(*cpp, "first")) { + fp->fr_flags |= FR_LOGFIRST; + cpp++; + } + if (*cpp && !strcasecmp(*cpp, "or-block")) { + if (!FR_ISPASS(fp->fr_flags)) { + fprintf(stderr, + "%d: or-block must be used with pass\n", + linenum); + return NULL; + } + fp->fr_flags |= FR_LOGORBLOCK; + cpp++; + } + if (*cpp && !strcasecmp(*cpp, "level")) { + if (loglevel(cpp, &fp->fr_loglevel, linenum) == -1) + return NULL; + cpp++; + cpp++; + } + } + + if (*cpp && !strcasecmp("quick", *cpp)) { + if (fp->fr_arg != 0) { + fprintf(stderr, "%d: cannot use skip with quick\n", + linenum); + return NULL; + } + cpp++; + fp->fr_flags |= FR_QUICK; + } + + /* + * Parse rule options that are available if a rule is tied to an + * interface. + */ + *fp->fr_ifname = '\0'; + *fp->fr_oifname = '\0'; + if (*cpp && !strcasecmp(*cpp, "on")) { + if (!*++cpp) { + fprintf(stderr, "%d: interface name missing\n", + linenum); + return NULL; + } + (void)strncpy(fp->fr_ifname, *cpp, IFNAMSIZ-1); + fp->fr_ifname[IFNAMSIZ-1] = '\0'; + cpp++; + if (!*cpp) { + if ((fp->fr_flags & FR_RETMASK) == FR_RETRST) { + fprintf(stderr, + "%d: %s can only be used with TCP\n", + linenum, "return-rst"); + return NULL; + } + return fp; + } + + if (!strcasecmp(*cpp, "out-via")) { + if (fp->fr_flags & FR_OUTQUE) { + fprintf(stderr, + "out-via must be used with in\n"); + return NULL; + } + cpp++; + (void)strncpy(fp->fr_oifname, *cpp, IFNAMSIZ-1); + fp->fr_oifname[IFNAMSIZ-1] = '\0'; + cpp++; + } else if (!strcasecmp(*cpp, "in-via")) { + if (fp->fr_flags & FR_INQUE) { + fprintf(stderr, + "in-via must be used with out\n"); + return NULL; + } + cpp++; + (void)strncpy(fp->fr_oifname, *cpp, IFNAMSIZ-1); + fp->fr_oifname[IFNAMSIZ-1] = '\0'; + cpp++; + } + + if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) { + cpp++; + if (to_interface(&fp->fr_dif, *cpp, linenum)) + return NULL; + cpp++; + } + if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) { + cpp++; + if (to_interface(&fp->fr_tif, *cpp, linenum)) + return NULL; + cpp++; + } else if (*cpp && !strcasecmp(*cpp, "fastroute")) { + if (!(fp->fr_flags & FR_INQUE)) { + fprintf(stderr, + "can only use %s with 'in'\n", + "fastroute"); + return NULL; + } + fp->fr_flags |= FR_FASTROUTE; + cpp++; + } + + /* + * Set the "other" interface name. Lets you specify both + * inbound and outbound interfaces for state rules. Do not + * prevent both interfaces from being the same. + */ + strcpy(fp->fr_ifnames[3], "*"); + if ((*cpp != NULL) && (*(cpp + 1) != NULL) && + ((((fp->fr_flags & FR_INQUE) != 0) && + (strcasecmp(*cpp, "out-via") == 0)) || + (((fp->fr_flags & FR_OUTQUE) != 0) && + (strcasecmp(*cpp, "in-via") == 0)))) { + cpp++; + + s = strchr(*cpp, ','); + if (s != NULL) { + *s++ = '\0'; + (void)strncpy(fp->fr_ifnames[3], s, + IFNAMSIZ - 1); + fp->fr_ifnames[3][IFNAMSIZ - 1] = '\0'; + } + + (void)strncpy(fp->fr_ifnames[2], *cpp, IFNAMSIZ - 1); + fp->fr_ifnames[2][IFNAMSIZ - 1] = '\0'; + cpp++; + } else + strcpy(fp->fr_ifnames[2], "*"); + + } + + if (*cpp && !strcasecmp(*cpp, "tos")) { + if (!*++cpp) { + fprintf(stderr, "%d: tos missing value\n", linenum); + return NULL; + } + fp->fr_tos = strtol(*cpp, NULL, 0); + fp->fr_mip.fi_tos = 0xff; + cpp++; + } + + if (*cpp && !strcasecmp(*cpp, "ttl")) { + if (!*++cpp) { + fprintf(stderr, "%d: ttl missing hopcount value\n", + linenum); + return NULL; + } + if (ratoi(*cpp, &i, 0, 255)) + fp->fr_ttl = i; + else { + fprintf(stderr, "%d: invalid ttl (%s)\n", + linenum, *cpp); + return NULL; + } + fp->fr_mip.fi_ttl = 0xff; + cpp++; + } + + /* + * check for "proto <protoname>" only decode udp/tcp/icmp as protoname + */ + if (*cpp && !strcasecmp(*cpp, "proto")) { + if (!*++cpp) { + fprintf(stderr, "%d: protocol name missing\n", linenum); + return NULL; + } + fp->fr_type = FR_T_IPF; + proto = *cpp++; + if (!strcasecmp(proto, "tcp/udp")) { + fp->fr_flx |= FI_TCPUDP; + fp->fr_mflx |= FI_TCPUDP; + } else if (use_inet6 && !strcasecmp(proto, "icmp")) { + fprintf(stderr, +"%d: use proto ipv6-icmp with IPv6 (or use proto 1 if you really mean icmp)\n", + linenum); + return NULL; + } else { + fp->fr_proto = getproto(proto); + fp->fr_mip.fi_p = 0xff; + } + } + if ((fp->fr_proto != IPPROTO_TCP) && + ((fp->fr_flags & FR_RETMASK) == FR_RETRST)) { + fprintf(stderr, "%d: %s can only be used with TCP\n", + linenum, "return-rst"); + return NULL; + } + + /* + * get the from host and bit mask to use against packets + */ + + if (!*cpp) { + fprintf(stderr, "%d: missing source specification\n", linenum); + return NULL; + } + if (!strcasecmp(*cpp, "all")) { + cpp++; + if (!*cpp) { + if (fp->fr_type == FR_T_NONE) { + fp->fr_dsize = 0; + fp->fr_data = NULL; + } + return fp; + } + fp->fr_type = FR_T_IPF; +#ifdef IPFILTER_BPF + } else if (!strcmp(*cpp, "{")) { + struct bpf_program bpf; + struct pcap *p; + char **cp; + u_32_t l; + + if (fp->fr_type != FR_T_NONE) { + fprintf(stderr, + "%d: cannot mix BPF/ipf matching\n", linenum); + return NULL; + } + fp->fr_type = FR_T_BPFOPC; + cpp++; + if (!strncmp(*cpp, "0x", 2)) { + fp->fr_data = malloc(4); + for (cp = cpp, i = 0; *cp; cp++, i++) { + if (!strcmp(*cp, "}")) + break; + fp->fr_data = realloc(fp->fr_data, + (i + 1) * 4); + l = strtoul(*cp, NULL, 0); + ((u_32_t *)fp->fr_data)[i] = l; + } + if (!*cp) { + fprintf(stderr, "Missing closing '}'\n"); + return NULL; + } + fp->fr_dsize = i * sizeof(l); + bpf.bf_insns = fp->fr_data; + bpf.bf_len = fp->fr_dsize / sizeof(struct bpf_insn); + } else { + for (cp = cpp; *cp; cp++) { + if (!strcmp(*cp, "}")) + break; + (*cp)[-1] = ' '; + } + if (!*cp) { + fprintf(stderr, "Missing closing '}'\n"); + return NULL; + } + + bzero((char *)&bpf, sizeof(bpf)); + p = pcap_open_dead(DLT_RAW, 1); + if (!p) { + fprintf(stderr, "pcap_open_dead failed\n"); + return NULL; + } + + if (pcap_compile(p, &bpf, *cpp, 1, 0xffffffff)) { + pcap_perror(p, "ipf"); + pcap_close(p); + fprintf(stderr, "pcap parsing failed\n"); + return NULL; + } + pcap_close(p); + fp->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn); + fp->fr_data = bpf.bf_insns; + if (!bpf_validate(fp->fr_data, bpf.bf_len)) { + fprintf(stderr, "BPF validation failed\n"); + return NULL; + } + if (opts & OPT_DEBUG) + bpf_dump(&bpf, 0); + } + cpp = cp; + (*cpp)++; +#endif + } else { + fp->fr_type = FR_T_IPF; + + if (strcasecmp(*cpp, "from")) { + fprintf(stderr, "%d: unexpected keyword (%s) - from\n", + linenum, *cpp); + return NULL; + } + if (!*++cpp) { + fprintf(stderr, "%d: missing host after from\n", + linenum); + return NULL; + } + if (**cpp == '!') { + fp->fr_flags |= FR_NOTSRCIP; + (*cpp)++; + } else if (!strcmp(*cpp, "!")) { + fp->fr_flags |= FR_NOTSRCIP; + cpp++; + } + + s = *cpp; + i = hostmask(&cpp, proto, fp->fr_ifname, (u_32_t *)&fp->fr_src, + (u_32_t *)&fp->fr_smsk, linenum); + if (i == -1) + return NULL; + if (*fp->fr_ifname && !strcasecmp(s, fp->fr_ifname)) + fp->fr_satype = FRI_DYNAMIC; + if (i == 1) { + if (fp->fr_v == 6) { + fprintf(stderr, + "can only use pools with ipv4\n"); + return NULL; + } + fp->fr_satype = FRI_LOOKUP; + } + + if (ports(&cpp, proto, &fp->fr_sport, &fp->fr_scmp, + &fp->fr_stop, linenum)) + return NULL; + + if (!*cpp) { + fprintf(stderr, "%d: missing to fields\n", linenum); + return NULL; + } + + /* + * do the same for the to field (destination host) + */ + if (strcasecmp(*cpp, "to")) { + fprintf(stderr, "%d: unexpected keyword (%s) - to\n", + linenum, *cpp); + return NULL; + } + if (!*++cpp) { + fprintf(stderr, "%d: missing host after to\n", linenum); + return NULL; + } + + if (**cpp == '!') { + fp->fr_flags |= FR_NOTDSTIP; + (*cpp)++; + } else if (!strcmp(*cpp, "!")) { + fp->fr_flags |= FR_NOTDSTIP; + cpp++; + } + + s = *cpp; + i = hostmask(&cpp, proto, fp->fr_ifname, (u_32_t *)&fp->fr_dst, + (u_32_t *)&fp->fr_dmsk, linenum); + if (i == -1) + return NULL; + if (*fp->fr_ifname && !strcasecmp(s, fp->fr_ifname)) + fp->fr_datype = FRI_DYNAMIC; + if (i == 1) { + if (fp->fr_v == 6) { + fprintf(stderr, + "can only use pools with ipv4\n"); + return NULL; + } + fp->fr_datype = FRI_LOOKUP; + } + + if (ports(&cpp, proto, &fp->fr_dport, &fp->fr_dcmp, + &fp->fr_dtop, linenum)) + return NULL; + } + + if (fp->fr_type == FR_T_IPF) { + /* + * check some sanity, make sure we don't have icmp checks + * with tcp or udp or visa versa. + */ + if (fp->fr_proto && (fp->fr_dcmp || fp->fr_scmp) && + fp->fr_proto != IPPROTO_TCP && + fp->fr_proto != IPPROTO_UDP) { + fprintf(stderr, + "%d: port operation on non tcp/udp\n",linenum); + return NULL; + } + if (fp->fr_icmp && fp->fr_proto != IPPROTO_ICMP) { + fprintf(stderr, + "%d: icmp comparisons on wrong protocol\n", + linenum); + return NULL; + } + + if (!*cpp) + return fp; + + if (*cpp && (fp->fr_type == FR_T_IPF) && + !strcasecmp(*cpp, "flags")) { + if (!*++cpp) { + fprintf(stderr, "%d: no flags present\n", + linenum); + return NULL; + } + fp->fr_tcpf = tcp_flags(*cpp, &fp->fr_tcpfm, linenum); + cpp++; + } + + /* + * extras... + */ + if ((fp->fr_v == 4) && *cpp && (!strcasecmp(*cpp, "with") || + !strcasecmp(*cpp, "and"))) + if (extras(&cpp, fp, linenum)) + return NULL; + + /* + * icmp types for use with the icmp protocol + */ + if (*cpp && !strcasecmp(*cpp, "icmp-type")) { + if (fp->fr_proto != IPPROTO_ICMP && + fp->fr_proto != IPPROTO_ICMPV6) { + fprintf(stderr, + "%d: icmp with wrong protocol (%d)\n", + linenum, fp->fr_proto); + return NULL; + } + if (addicmp(&cpp, fp, linenum)) + return NULL; + fp->fr_icmp = htons(fp->fr_icmp); + fp->fr_icmpm = htons(fp->fr_icmpm); + } + } + + /* + * Keep something... + */ + while (*cpp && !strcasecmp(*cpp, "keep")) + if (addkeep(&cpp, fp, linenum)) + return NULL; + + /* + * This is here to enforce the old interface binding behaviour. + * That is, "on X" is equivalent to "<dir> on X <!dir>-via -,X" + */ + if (fp->fr_flags & FR_KEEPSTATE) { + if (*fp->fr_ifnames[0] && !*fp->fr_ifnames[3]) { + bcopy(fp->fr_ifnames[0], fp->fr_ifnames[3], + sizeof(fp->fr_ifnames[3])); + strncpy(fp->fr_ifnames[2], "*", + sizeof(fp->fr_ifnames[3])); + } + } + + /* + * head of a new group ? + */ + if (*cpp && !strcasecmp(*cpp, "head")) { + if (fp->fr_arg != 0) { + fprintf(stderr, "%d: cannot use skip with head\n", + linenum); + return NULL; + } + if (!*++cpp) { + fprintf(stderr, "%d: head without group #\n", linenum); + return NULL; + } + if (strlen(*cpp) > FR_GROUPLEN) { + fprintf(stderr, "%d: head name too long #\n", linenum); + return NULL; + } + strncpy(fp->fr_grhead, *cpp, FR_GROUPLEN); + cpp++; + } + + /* + * reference to an already existing group ? + */ + if (*cpp && !strcasecmp(*cpp, "group")) { + if (!*++cpp) { + fprintf(stderr, "%d: group without group #\n", + linenum); + return NULL; + } + if (strlen(*cpp) > FR_GROUPLEN) { + fprintf(stderr, "%d: group name too long #\n", linenum); + return NULL; + } + strncpy(fp->fr_group, *cpp, FR_GROUPLEN); + cpp++; + } + + if (*cpp && !strcasecmp(*cpp, "tag")) { + if (!*++cpp) { + fprintf(stderr, "%d: tag id missing value\n", linenum); + return NULL; + } + fp->fr_tag = strtol(*cpp, NULL, 0); + cpp++; + } + + /* + * pps counter + */ + if (*cpp && !strcasecmp(*cpp, "pps")) { + if (!*++cpp) { + fprintf(stderr, "%d: pps without rate\n", linenum); + return NULL; + } + if (ratoui(*cpp, &k, 0, INT_MAX)) + fp->fr_pps = k; + else { + fprintf(stderr, "%d: invalid pps rate (%s)\n", + linenum, *cpp); + return NULL; + } + cpp++; + } + + /* + * leftovers...yuck + */ + if (*cpp && **cpp) { + fprintf(stderr, "%d: unknown words at end: [", linenum); + for (; *cpp; cpp++) + fprintf(stderr, "%s ", *cpp); + fprintf(stderr, "]\n"); + return NULL; + } + + /* + * lazy users... + */ + if (fp->fr_type == FR_T_IPF) { + if ((fp->fr_tcpf || fp->fr_tcpfm) && + (fp->fr_proto != IPPROTO_TCP)) { + fprintf(stderr, + "%d: TCP protocol not specified\n", linenum); + return NULL; + } + if (!(fp->fr_flx & FI_TCPUDP) && + (fp->fr_proto != IPPROTO_TCP) && + (fp->fr_proto != IPPROTO_UDP) && + (fp->fr_dcmp || fp->fr_scmp)) { + if (!fp->fr_proto) { + fp->fr_flx |= FI_TCPUDP; + fp->fr_mflx |= FI_TCPUDP; + } else { + fprintf(stderr, + "%d: port check for non-TCP/UDP\n", + linenum); + return NULL; + } + } + } + if (*fp->fr_oifname && strcmp(fp->fr_oifname, "*") && + !(fp->fr_flags & FR_KEEPSTATE)) { + fprintf(stderr, "%d: *-via <if> must be used %s\n", + linenum, "with keep-state"); + return NULL; + } + return fp; +} diff --git a/contrib/ipfilter/lib/portname.c b/contrib/ipfilter/lib/portname.c new file mode 100644 index 0000000..7c0fc87 --- /dev/null +++ b/contrib/ipfilter/lib/portname.c @@ -0,0 +1,42 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: portname.c,v 1.7 2003/08/14 14:27:43 darrenr Exp + */ +#include "ipf.h" + + +char *portname(pr, port) +int pr, port; +{ + static char buf[32]; + struct protoent *p = NULL; + struct servent *sv = NULL, *sv1 = NULL; + + if ((opts & OPT_NORESOLVE) == 0) { + 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 != -2) && (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; +} diff --git a/contrib/ipfilter/lib/portnum.c b/contrib/ipfilter/lib/portnum.c new file mode 100644 index 0000000..284bbc9 --- /dev/null +++ b/contrib/ipfilter/lib/portnum.c @@ -0,0 +1,64 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * + * Id: portnum.c,v 1.6.4.1 2004/12/09 19:41:22 darrenr Exp + */ + +#include <ctype.h> + +#include "ipf.h" + + +/* + * find the port number given by the name, either from getservbyname() or + * straight atoi(). Return 1 on success, 0 on failure + */ +int portnum(name, proto, port, linenum) +char *name, *proto; +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; +} diff --git a/contrib/ipfilter/lib/ports.c b/contrib/ipfilter/lib/ports.c new file mode 100644 index 0000000..634dfeb --- /dev/null +++ b/contrib/ipfilter/lib/ports.c @@ -0,0 +1,81 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ports.c,v 1.9.4.1 2004/12/09 19:41:22 darrenr Exp + */ + +#include <ctype.h> + +#include "ipf.h" + + +/* + * check for possible presence of the port fields in the line + */ +int ports(seg, proto, pp, cp, tp, linenum) +char ***seg; +char *proto; +u_short *pp; +int *cp; +u_short *tp; +int linenum; +{ + int comp = -1; + + if (!*seg || !**seg || !***seg) + return 0; + if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) { + (*seg)++; + if (ISALNUM(***seg) && *(*seg + 2)) { + if (portnum(**seg, proto, 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, proto, 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, proto, pp, linenum) == 0) + return -1; + } + *cp = comp; + (*seg)++; + } + return 0; +} diff --git a/contrib/ipfilter/lib/print_toif.c b/contrib/ipfilter/lib/print_toif.c new file mode 100644 index 0000000..0e230cd --- /dev/null +++ b/contrib/ipfilter/lib/print_toif.c @@ -0,0 +1,32 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: print_toif.c,v 1.8 2002/01/28 06:50:47 darrenr Exp + */ + +#include "ipf.h" + + +void print_toif(tag, fdp) +char *tag; +frdest_t *fdp; +{ + printf("%s %s%s", tag, fdp->fd_ifname, + (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)"); +#ifdef USE_INET6 + if (use_inet6 && IP6_NOTZERO(&fdp->fd_ip6.in6)) { + char ipv6addr[80]; + + inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr, + sizeof(fdp->fd_ip6)); + printf(":%s", ipv6addr); + } else +#endif + if (fdp->fd_ip.s_addr) + printf(":%s", inet_ntoa(fdp->fd_ip)); + putchar(' '); +} diff --git a/contrib/ipfilter/lib/printactivenat.c b/contrib/ipfilter/lib/printactivenat.c new file mode 100644 index 0000000..3c56b14 --- /dev/null +++ b/contrib/ipfilter/lib/printactivenat.c @@ -0,0 +1,85 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: printactivenat.c,v 1.3.2.4 2004/05/11 16:07:32 darrenr Exp"; +#endif + + +void printactivenat(nat, opts) +nat_t *nat; +int opts; +{ + + printf("%s", getnattype(nat->nat_ptr)); + + if (nat->nat_flags & SI_CLONE) + printf(" CLONE"); + + printf(" %-15s", inet_ntoa(nat->nat_inip)); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + printf(" %-5hu", ntohs(nat->nat_inport)); + + printf(" <- -> %-15s",inet_ntoa(nat->nat_outip)); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + printf(" %-5hu", ntohs(nat->nat_outport)); + + printf(" [%s", inet_ntoa(nat->nat_oip)); + if ((nat->nat_flags & IPN_TCPUDP) != 0) + printf(" %hu", ntohs(nat->nat_oport)); + printf("]"); + + if (opts & OPT_VERBOSE) { + 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/%d flags %x\n", + getsumd(nat->nat_sumd[1]), nat->nat_p, + nat->nat_hv[0], nat->nat_hv[1], nat->nat_flags); + printf("\tifp %s", getifname(nat->nat_ifps[0])); + printf(",%s ", getifname(nat->nat_ifps[1])); +#ifdef USE_QUAD_T + printf("bytes %qu/%qu pkts %qu/%qu", + (unsigned long long)nat->nat_bytes[0], + (unsigned long long)nat->nat_bytes[1], + (unsigned long long)nat->nat_pkts[0], + (unsigned long long)nat->nat_pkts[1]); +#else + printf("bytes %lu/%lu pkts %lu/%lu", nat->nat_bytes[0], + nat->nat_bytes[1], nat->nat_pkts[0], nat->nat_pkts[1]); +#endif + printf(" ipsumd %x", nat->nat_ipsumd); + } + + if (opts & OPT_DEBUG) { + printf("\n\tnat_next %p _pnext %p _hm %p\n", + nat->nat_next, nat->nat_pnext, nat->nat_hm); + printf("\t_hnext %p/%p _phnext %p/%p\n", + nat->nat_hnext[0], nat->nat_hnext[1], + nat->nat_phnext[0], nat->nat_phnext[1]); + printf("\t_data %p _me %p _state %p _aps %p\n", + nat->nat_data, nat->nat_me, nat->nat_state, nat->nat_aps); + printf("\tfr %p ptr %p ifps %p/%p sync %p\n", + nat->nat_fr, nat->nat_ptr, nat->nat_ifps[0], + nat->nat_ifps[1], nat->nat_sync); + printf("\ttqe:pnext %p next %p ifq %p parent %p/%p\n", + nat->nat_tqe.tqe_pnext, nat->nat_tqe.tqe_next, + nat->nat_tqe.tqe_ifq, nat->nat_tqe.tqe_parent, nat); + printf("\ttqe:die %ld touched %ld flags %x state %d/%d\n", + nat->nat_tqe.tqe_die, nat->nat_tqe.tqe_touched, + nat->nat_tqe.tqe_flags, nat->nat_tqe.tqe_state[0], + nat->nat_tqe.tqe_state[1]); + } + putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printaps.c b/contrib/ipfilter/lib/printaps.c new file mode 100644 index 0000000..5c5c3dd --- /dev/null +++ b/contrib/ipfilter/lib/printaps.c @@ -0,0 +1,112 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" +#include "kmem.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: printaps.c,v 1.4 2004/01/08 13:34:32 darrenr Exp"; +#endif + + +void printaps(aps, opts) +ap_session_t *aps; +int opts; +{ + ipsec_pxy_t ipsec; + ap_session_t ap; + ftpinfo_t ftp; + aproxy_t apr; + raudio_t ra; + + if (kmemcpy((char *)&ap, (long)aps, sizeof(ap))) + return; + if (kmemcpy((char *)&apr, (long)ap.aps_apr, sizeof(apr))) + return; + printf("\tproxy %s/%d use %d flags %x\n", apr.apr_label, + 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", (unsigned long long)ap.aps_bytes, + (unsigned long long)ap.aps_pkts); +#else + printf("%lu pkts %lu", ap.aps_bytes, ap.aps_pkts); +#endif + printf(" data %s size %d\n", ap.aps_data ? "YES" : "NO", ap.aps_psiz); + if ((ap.aps_p == IPPROTO_TCP) && (opts & OPT_VERBOSE)) { + printf("\t\tstate[%u,%u], sel[%d,%d]\n", + ap.aps_state[0], ap.aps_state[1], + ap.aps_sel[0], ap.aps_sel[1]); +#if (defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011)) || \ + (__FreeBSD_version >= 300000) || defined(OpenBSD) + printf("\t\tseq: off %hd/%hd min %x/%x\n", + ap.aps_seqoff[0], ap.aps_seqoff[1], + ap.aps_seqmin[0], ap.aps_seqmin[1]); + printf("\t\tack: off %hd/%hd min %x/%x\n", + ap.aps_ackoff[0], ap.aps_ackoff[1], + ap.aps_ackmin[0], ap.aps_ackmin[1]); +#else + printf("\t\tseq: off %hd/%hd min %lx/%lx\n", + ap.aps_seqoff[0], ap.aps_seqoff[1], + ap.aps_seqmin[0], ap.aps_seqmin[1]); + printf("\t\tack: off %hd/%hd min %lx/%lx\n", + ap.aps_ackoff[0], ap.aps_ackoff[1], + ap.aps_ackmin[0], ap.aps_ackmin[1]); +#endif + } + + if (!strcmp(apr.apr_label, "raudio") && ap.aps_psiz == sizeof(ra)) { + if (kmemcpy((char *)&ra, (long)ap.aps_data, sizeof(ra))) + return; + printf("\tReal Audio Proxy:\n"); + printf("\t\tSeen PNA: %d\tVersion: %d\tEOS: %d\n", + ra.rap_seenpna, ra.rap_version, ra.rap_eos); + 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\tseq %x (ack %x) len %d junk %d cmds %d\n", + ftp.ftp_side[0].ftps_seq[0], + ftp.ftp_side[0].ftps_seq[1], + ftp.ftp_side[0].ftps_len, ftp.ftp_side[0].ftps_junk, + ftp.ftp_side[0].ftps_cmds); + printf("\t\tbuf ["); + printbuf(ftp.ftp_side[0].ftps_buf, FTP_BUFSZ, 1); + printf("]\n\tServer:\n"); + printf("\t\tseq %x (ack %x) len %d junk %d cmds %d\n", + ftp.ftp_side[1].ftps_seq[0], + ftp.ftp_side[1].ftps_seq[1], + ftp.ftp_side[1].ftps_len, ftp.ftp_side[1].ftps_junk, + ftp.ftp_side[1].ftps_cmds); + printf("\t\tbuf ["); + printbuf(ftp.ftp_side[1].ftps_buf, FTP_BUFSZ, 1); + printf("]\n"); + } else if (!strcmp(apr.apr_label, "ipsec") && + (ap.aps_psiz == sizeof(ipsec))) { + if (kmemcpy((char *)&ipsec, (long)ap.aps_data, sizeof(ipsec))) + return; + printf("\tIPSec Proxy:\n"); + printf("\t\tICookie %08x%08x RCookie %08x%08x %s\n", + (u_int)ntohl(ipsec.ipsc_icookie[0]), + (u_int)ntohl(ipsec.ipsc_icookie[1]), + (u_int)ntohl(ipsec.ipsc_rcookie[0]), + (u_int)ntohl(ipsec.ipsc_rcookie[1]), + ipsec.ipsc_rckset ? "(Set)" : "(Not set)"); + } +} diff --git a/contrib/ipfilter/lib/printbuf.c b/contrib/ipfilter/lib/printbuf.c new file mode 100644 index 0000000..f2b7faa --- /dev/null +++ b/contrib/ipfilter/lib/printbuf.c @@ -0,0 +1,32 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printbuf.c,v 1.5.4.1 2004/12/09 19:41:22 darrenr Exp + */ + +#include <ctype.h> + +#include "ipf.h" + + +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/lib/printfr.c b/contrib/ipfilter/lib/printfr.c new file mode 100644 index 0000000..f0f5a0e --- /dev/null +++ b/contrib/ipfilter/lib/printfr.c @@ -0,0 +1,445 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printfr.c,v 1.43.2.10 2005/03/16 15:38:13 darrenr Exp + */ + +#include "ipf.h" + +static void printaddr(int, int, char *, u_32_t *, u_32_t *); + +static void printaddr(v, type, ifname, addr, mask) +int v, type; +char *ifname; +u_32_t *addr, *mask; +{ + char *suffix; + + switch (type) + { + case FRI_BROADCAST : + suffix = "/bcast"; + break; + + case FRI_DYNAMIC : + printf("%s", ifname); + printmask(mask); + suffix = NULL; + break; + + case FRI_NETWORK : + suffix = "/net"; + break; + + case FRI_NETMASKED : + suffix = "/netmasked"; + break; + + case FRI_PEERADDR : + suffix = "/peer"; + break; + + case FRI_LOOKUP : + suffix = NULL; + printlookup((i6addr_t *)addr, (i6addr_t *)mask); + break; + + case FRI_NORMAL : + printhostmask(v, addr, mask); + suffix = NULL; + break; + default : + printf("<%d>", type); + printmask(mask); + suffix = NULL; + break; + } + + if (suffix != NULL) { + printf("%s/%s", ifname, suffix); + } +} + + +void printlookup(addr, mask) +i6addr_t *addr, *mask; +{ + switch (addr->iplookuptype) + { + case IPLT_POOL : + printf("pool/"); + break; + case IPLT_HASH : + printf("hash/"); + break; + default : + printf("lookup(%x)=", addr->iplookuptype); + break; + } + + printf("%u", addr->iplookupnum); + if (mask->iplookupptr == NULL) + printf("(!)"); +} + + +/* + * print the filter structure in a useful way + */ +void printfr(fp, iocfunc) +struct frentry *fp; +ioctlfunc_t iocfunc; +{ + struct protoent *p; + u_short sec[2]; + u_32_t type; + u_char *t; + char *s; + int pr; + + pr = -2; + type = fp->fr_type & ~FR_T_BUILTIN; + + if ((fp->fr_type & FR_T_BUILTIN) != 0) + printf("# Builtin: "); + + if (fp->fr_type == FR_T_CALLFUNC) { + ; + } else if (fp->fr_func != NULL) { + printf("call"); + if ((fp->fr_flags & FR_CALLNOW) != 0) + printf(" now"); + s = kvatoname(fp->fr_func, iocfunc); + printf(" %s/%u", s ? s : "?", fp->fr_arg); + } else if (FR_ISPASS(fp->fr_flags)) + printf("pass"); + else if (FR_ISBLOCK(fp->fr_flags)) { + printf("block"); + if (fp->fr_flags & FR_RETICMP) { + if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP) + printf(" return-icmp-as-dest"); + else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP) + printf(" return-icmp"); + if (fp->fr_icode) { + if (fp->fr_icode <= MAX_ICMPCODE) + printf("(%s)", + icmpcodes[(int)fp->fr_icode]); + else + printf("(%d)", fp->fr_icode); + } + } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST) + printf(" return-rst"); + } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) { + printlog(fp); + } else if (FR_ISACCOUNT(fp->fr_flags)) + printf("count"); + else if (FR_ISAUTH(fp->fr_flags)) + printf("auth"); + else if (FR_ISPREAUTH(fp->fr_flags)) + printf("preauth"); + else if (FR_ISNOMATCH(fp->fr_flags)) + printf("nomatch"); + else if (FR_ISSKIP(fp->fr_flags)) + printf("skip %u", fp->fr_arg); + else { + printf("%x", fp->fr_flags); + } + + if (fp->fr_flags & FR_OUTQUE) + printf(" out "); + else + printf(" in "); + + if (((fp->fr_flags & FR_LOGB) == FR_LOGB) || + ((fp->fr_flags & FR_LOGP) == FR_LOGP)) { + printlog(fp); + putchar(' '); + } + + if (fp->fr_flags & FR_QUICK) + printf("quick "); + + if (*fp->fr_ifname) { + printifname("on ", fp->fr_ifname, fp->fr_ifa); + if (*fp->fr_ifnames[1] && strcmp(fp->fr_ifnames[1], "*")) + printifname(",", fp->fr_ifnames[1], fp->fr_ifas[1]); + putchar(' '); + } + + if (*fp->fr_dif.fd_ifname || (fp->fr_flags & FR_DUP)) + print_toif("dup-to", &fp->fr_dif); + if (*fp->fr_tif.fd_ifname) + print_toif("to", &fp->fr_tif); + if (*fp->fr_rif.fd_ifname) + print_toif("reply-to", &fp->fr_rif); + if (fp->fr_flags & FR_FASTROUTE) + printf("fastroute "); + + if ((*fp->fr_ifnames[2] && strcmp(fp->fr_ifnames[2], "*")) || + (*fp->fr_ifnames[3] && strcmp(fp->fr_ifnames[3], "*"))) { + if (fp->fr_flags & FR_OUTQUE) + printf("in-via "); + else + printf("out-via "); + + if (*fp->fr_ifnames[2]) { + printifname("", fp->fr_ifnames[2], + fp->fr_ifas[2]); + putchar(' '); + + if (*fp->fr_ifnames[3]) { + printifname(",", fp->fr_ifnames[3], + fp->fr_ifas[3]); + } + } + } + + if (type == FR_T_IPF) { + if (fp->fr_mip.fi_tos) + printf("tos %#x ", fp->fr_tos); + if (fp->fr_mip.fi_ttl) + printf("ttl %d ", fp->fr_ttl); + if (fp->fr_flx & FI_TCPUDP) { + printf("proto tcp/udp "); + pr = -1; + } else if (fp->fr_mip.fi_p) { + pr = fp->fr_ip.fi_p; + if ((p = getprotobynumber(fp->fr_proto))) + printf("proto %s ", p->p_name); + else + printf("proto %d ", fp->fr_proto); + } + } + + if (type == FR_T_NONE) { + printf("all"); + } else if (type == FR_T_IPF) { + printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : ""); + printaddr(fp->fr_v, fp->fr_satype, fp->fr_ifname, + &fp->fr_src.s_addr, &fp->fr_smsk.s_addr); + if (fp->fr_scmp) + printportcmp(pr, &fp->fr_tuc.ftu_src); + + printf(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : ""); + printaddr(fp->fr_v, fp->fr_datype, fp->fr_ifname, + &fp->fr_dst.s_addr, &fp->fr_dmsk.s_addr); + if (fp->fr_dcmp) + printportcmp(pr, &fp->fr_tuc.ftu_dst); + + if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm) { + int type = fp->fr_icmp, code; + + type = ntohs(fp->fr_icmp); + code = type & 0xff; + type /= 256; + if (type < (sizeof(icmptypes) / sizeof(char *) - 1) && + icmptypes[type]) + printf(" icmp-type %s", icmptypes[type]); + else + printf(" icmp-type %d", type); + if (ntohs(fp->fr_icmpm) & 0xff) + printf(" code %d", code); + } + if ((fp->fr_proto == IPPROTO_TCP) && + (fp->fr_tcpf || fp->fr_tcpfm)) { + printf(" flags "); + if (fp->fr_tcpf & ~TCPF_ALL) + printf("0x%x", fp->fr_tcpf); + else + 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_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); + } + } + } else if (type == FR_T_BPFOPC) { + fakebpf_t *fb; + int i; + + printf("bpf-v%d { \"", fp->fr_v); + i = fp->fr_dsize / sizeof(*fb); + + for (fb = fp->fr_data, s = ""; i; i--, fb++, s = " ") + printf("%s%#x %#x %#x %#x", s, fb->fb_c, fb->fb_t, + fb->fb_f, fb->fb_k); + + printf("\" }"); + } else if (type == FR_T_COMPIPF) { + ; + } else if (type == FR_T_CALLFUNC) { + printf("call function at %p", fp->fr_data); + } else { + printf("[unknown filter type %#x]", fp->fr_type); + } + + if ((type == FR_T_IPF) && + ((fp->fr_flx & FI_WITH) || (fp->fr_mflx & FI_WITH) || + fp->fr_optbits || fp->fr_optmask || + fp->fr_secbits || fp->fr_secmask)) { + char *comma = " "; + + printf(" with"); + if (fp->fr_optbits || fp->fr_optmask || + fp->fr_secbits || fp->fr_secmask) { + sec[0] = fp->fr_secmask; + sec[1] = fp->fr_secbits; + if (fp->fr_v == 4) + optprint(sec, fp->fr_optmask, fp->fr_optbits); +#ifdef USE_INET6 + else + optprintv6(sec, fp->fr_optmask, + fp->fr_optbits); +#endif + } else if (fp->fr_mflx & FI_OPTIONS) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_OPTIONS)) + printf("not "); + printf("ipopts"); + comma = ","; + } + if (fp->fr_mflx & FI_SHORT) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_SHORT)) + printf("not "); + printf("short"); + comma = ","; + } + if (fp->fr_mflx & FI_FRAG) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_FRAG)) + printf("not "); + printf("frag"); + comma = ","; + } + if (fp->fr_mflx & FI_FRAGBODY) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_FRAGBODY)) + printf("not "); + printf("frag-body"); + comma = ","; + } + if (fp->fr_mflx & FI_NATED) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_NATED)) + printf("not "); + printf("nat"); + comma = ","; + } + if (fp->fr_mflx & FI_LOWTTL) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_LOWTTL)) + printf("not "); + printf("lowttl"); + comma = ","; + } + if (fp->fr_mflx & FI_BAD) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_BAD)) + printf("not "); + printf("bad"); + comma = ","; + } + if (fp->fr_mflx & FI_BADSRC) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_BADSRC)) + printf("not "); + printf("bad-src"); + comma = ","; + } + if (fp->fr_mflx & FI_BADNAT) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_BADNAT)) + printf("not "); + printf("bad-nat"); + comma = ","; + } + if (fp->fr_mflx & FI_OOW) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_OOW)) + printf("not "); + printf("oow"); + } + } + + if (fp->fr_flags & FR_KEEPSTATE) { + printf(" keep state"); + if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN|FR_NOICMPERR|FR_STATESYNC)) || + (fp->fr_statemax != 0) || (fp->fr_age[0] != 0)) { + char *comma = ""; + printf(" ("); + if (fp->fr_statemax != 0) { + printf("limit %u", fp->fr_statemax); + comma = ","; + } + if (fp->fr_flags & FR_STSTRICT) { + printf("%sstrict", comma); + comma = ","; + } + if (fp->fr_flags & FR_NEWISN) { + printf("%snewisn", comma); + comma = ","; + } + if (fp->fr_flags & FR_NOICMPERR) { + printf("%sno-icmp-err", comma); + comma = ","; + } + if (fp->fr_flags & FR_STATESYNC) { + printf("%ssync", comma); + comma = ","; + } + if (fp->fr_age[0] || fp->fr_age[1]) + printf("%sage %d/%d", comma, fp->fr_age[0], + fp->fr_age[1]); + printf(")"); + } + } + if (fp->fr_flags & FR_KEEPFRAG) { + printf(" keep frags"); + if (fp->fr_flags & (FR_FRSTRICT)) { + printf(" ("); + if (fp->fr_flags & FR_FRSTRICT) + printf(" strict"); + printf(" )"); + + } + } + if (fp->fr_isc != (struct ipscan *)-1) { + if (fp->fr_isctag[0]) + printf(" scan %s", fp->fr_isctag); + else + printf(" scan *"); + } + if (*fp->fr_grhead != '\0') + printf(" head %s", fp->fr_grhead); + if (*fp->fr_group != '\0') + printf(" group %s", fp->fr_group); + if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) { + char *s = ""; + + printf(" set-tag("); + if (fp->fr_logtag != FR_NOLOGTAG) { + printf("log=%u", fp->fr_logtag); + s = ", "; + } + if (*fp->fr_nattag.ipt_tag) { + printf("%snat=%-.*s", s, IPFTAG_LEN, + fp->fr_nattag.ipt_tag); + } + printf(")"); + } + if (fp->fr_pps) + printf(" pps %d", fp->fr_pps); + (void)putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printfraginfo.c b/contrib/ipfilter/lib/printfraginfo.c new file mode 100644 index 0000000..b521c83 --- /dev/null +++ b/contrib/ipfilter/lib/printfraginfo.c @@ -0,0 +1,29 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2004 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printfraginfo.c,v 1.1.2.2 2004/03/23 15:15:45 darrenr Exp + */ +#include "ipf.h" +#include "kmem.h" + +void printfraginfo(prefix, ifr) +char *prefix; +struct ipfr *ifr; +{ + frentry_t fr; + + fr.fr_flags = 0xffffffff; + + printf("%s%s -> ", prefix, hostname(4, &ifr->ipfr_src)); + if (kmemcpy((char *)&fr, (u_long)ifr->ipfr_rule, + sizeof(fr)) == -1) + return; + printf("%s id %d ttl %d pr %d seen0 %d ifp %p tos %#02x = %#x\n", + hostname(4, &ifr->ipfr_dst), ifr->ipfr_id, ifr->ipfr_seen0, + ifr->ipfr_ttl, ifr->ipfr_p, ifr->ipfr_ifp, ifr->ipfr_tos, + fr.fr_flags); +} diff --git a/contrib/ipfilter/lib/printhash.c b/contrib/ipfilter/lib/printhash.c new file mode 100644 index 0000000..80157bb --- /dev/null +++ b/contrib/ipfilter/lib/printhash.c @@ -0,0 +1,144 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf + + +iphtable_t *printhash(hp, copyfunc, name, opts) +iphtable_t *hp; +copyfunc_t copyfunc; +char *name; +int opts; +{ + iphtent_t *ipep, **table; + iphtable_t iph; + int i, printed; + size_t sz; + + if ((*copyfunc)((char *)hp, (char *)&iph, sizeof(iph))) + return NULL; + + if ((name != NULL) && strncmp(name, iph.iph_name, FR_GROUPLEN)) + return iph.iph_next; + + if ((opts & OPT_DEBUG) == 0) { + if ((iph.iph_type & IPHASH_ANON) == IPHASH_ANON) + PRINTF("# 'anonymous' table\n"); + switch (iph.iph_type & ~IPHASH_ANON) + { + case IPHASH_LOOKUP : + PRINTF("table"); + break; + case IPHASH_GROUPMAP : + PRINTF("group-map"); + if (iph.iph_flags & FR_INQUE) + PRINTF(" in"); + else if (iph.iph_flags & FR_OUTQUE) + PRINTF(" out"); + else + PRINTF(" ???"); + break; + default : + PRINTF("%#x", iph.iph_type); + break; + } + PRINTF(" role = "); + } else { + PRINTF("Hash Table Number: %s", iph.iph_name); + if ((iph.iph_type & IPHASH_ANON) == IPHASH_ANON) + PRINTF("(anon)"); + putchar(' '); + PRINTF("Role: "); + } + + switch (iph.iph_unit) + { + case IPL_LOGNAT : + PRINTF("nat"); + break; + case IPL_LOGIPF : + PRINTF("ipf"); + break; + case IPL_LOGAUTH : + PRINTF("auth"); + break; + case IPL_LOGCOUNT : + PRINTF("count"); + break; + default : + PRINTF("#%d", iph.iph_unit); + break; + } + + if ((opts & OPT_DEBUG) == 0) { + if ((iph.iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP) + PRINTF(" type = hash"); + PRINTF(" number = %s size = %lu", + iph.iph_name, (u_long)iph.iph_size); + if (iph.iph_seed != 0) + PRINTF(" seed = %lu", iph.iph_seed); + putchar('\n'); + } else { + PRINTF(" Type: "); + switch (iph.iph_type & ~IPHASH_ANON) + { + case IPHASH_LOOKUP : + PRINTF("lookup"); + break; + case IPHASH_GROUPMAP : + PRINTF("groupmap Group. %s", iph.iph_name); + break; + default : + break; + } + + putchar('\n'); + PRINTF("\t\tSize: %lu\tSeed: %lu", + (u_long)iph.iph_size, iph.iph_seed); + PRINTF("\tRef. Count: %d\tMasks: %#x\n", iph.iph_ref, + iph.iph_masks); + } + + if ((opts & OPT_DEBUG) != 0) { + struct in_addr m; + + for (i = 0; i < 32; i++) { + if ((1 << i) & iph.iph_masks) { + ntomask(4, i, &m.s_addr); + PRINTF("\t\tMask: %s\n", inet_ntoa(m)); + } + } + } + + if ((opts & OPT_DEBUG) == 0) + PRINTF("\t{"); + + sz = iph.iph_size * sizeof(*table); + table = malloc(sz); + if ((*copyfunc)((char *)iph.iph_table, (char *)table, sz)) + return NULL; + + for (i = 0, printed = 0; i < iph.iph_size; i++) { + for (ipep = table[i]; ipep != NULL; ) { + ipep = printhashnode(&iph, ipep, copyfunc, opts); + printed++; + } + } + if (printed == 0) + putchar(';'); + + free(table); + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + + return iph.iph_next; +} diff --git a/contrib/ipfilter/lib/printhashnode.c b/contrib/ipfilter/lib/printhashnode.c new file mode 100644 index 0000000..39255e7 --- /dev/null +++ b/contrib/ipfilter/lib/printhashnode.c @@ -0,0 +1,52 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf + +iphtent_t *printhashnode(iph, ipep, copyfunc, opts) +iphtable_t *iph; +iphtent_t *ipep; +copyfunc_t copyfunc; +int opts; +{ + iphtent_t ipe; + + if ((*copyfunc)(ipep, &ipe, sizeof(ipe))) + return NULL; + + ipe.ipe_addr.in4_addr = htonl(ipe.ipe_addr.in4_addr); + ipe.ipe_mask.in4_addr = htonl(ipe.ipe_mask.in4_addr); + + if ((opts & OPT_DEBUG) != 0) { + PRINTF("\tAddress: %s", + inet_ntoa(ipe.ipe_addr.in4)); + printmask((u_32_t *)&ipe.ipe_mask.in4_addr); + PRINTF("\tRef. Count: %d\tGroup: %s\n", ipe.ipe_ref, + ipe.ipe_group); + } else { + putchar(' '); + printip((u_32_t *)&ipe.ipe_addr.in4_addr); + printmask((u_32_t *)&ipe.ipe_mask.in4_addr); + if (ipe.ipe_value != 0) { + switch (iph->iph_type & ~IPHASH_ANON) + { + case IPHASH_GROUPMAP : + if (strncmp(ipe.ipe_group, iph->iph_name, + FR_GROUPLEN)) + PRINTF(", group = %s", ipe.ipe_group); + break; + } + } + putchar(';'); + } + ipep = ipe.ipe_next; + return ipep; +} diff --git a/contrib/ipfilter/lib/printhostmap.c b/contrib/ipfilter/lib/printhostmap.c new file mode 100644 index 0000000..bdb6702 --- /dev/null +++ b/contrib/ipfilter/lib/printhostmap.c @@ -0,0 +1,13 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +void printhostmap(hmp, hv) +hostmap_t *hmp; +u_int hv; +{ + printf("%s,", inet_ntoa(hmp->hm_srcip)); + printf("%s -> ", inet_ntoa(hmp->hm_dstip)); + printf("%s ", inet_ntoa(hmp->hm_mapip)); + printf("(use = %d hv = %u)\n", hmp->hm_ref, hv); +} diff --git a/contrib/ipfilter/lib/printhostmask.c b/contrib/ipfilter/lib/printhostmask.c new file mode 100644 index 0000000..c34bc43 --- /dev/null +++ b/contrib/ipfilter/lib/printhostmask.c @@ -0,0 +1,46 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printhostmask.c,v 1.8 2002/04/11 15:01:19 darrenr Exp + */ + +#include "ipf.h" + + +void printhostmask(v, addr, mask) +int v; +u_32_t *addr, *mask; +{ +#ifdef USE_INET6 + char ipbuf[64]; +#else + struct in_addr ipa; +#endif + + if (!*addr && !*mask) + printf("any"); + else { +#ifdef USE_INET6 + void *ptr = addr; + int af; + + if (v == 4) { + ptr = addr; + af = AF_INET; + } else if (v == 6) { + ptr = addr; + af = AF_INET6; + } else + af = 0; + printf("%s", inet_ntop(af, ptr, ipbuf, sizeof(ipbuf))); +#else + ipa.s_addr = *addr; + printf("%s", inet_ntoa(ipa)); +#endif + printmask(mask); + } +} diff --git a/contrib/ipfilter/lib/printifname.c b/contrib/ipfilter/lib/printifname.c new file mode 100644 index 0000000..53a7fd7 --- /dev/null +++ b/contrib/ipfilter/lib/printifname.c @@ -0,0 +1,20 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printifname.c,v 1.2 2002/01/28 06:50:47 darrenr Exp + */ + +#include "ipf.h" + +void printifname(format, name, ifp) +char *format, *name; +void *ifp; +{ + printf("%s%s", format, name); + if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*")) + printf("(!)"); +} diff --git a/contrib/ipfilter/lib/printip.c b/contrib/ipfilter/lib/printip.c new file mode 100644 index 0000000..1a04f1d --- /dev/null +++ b/contrib/ipfilter/lib/printip.c @@ -0,0 +1,24 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printip.c,v 1.3 2002/07/13 12:10:27 darrenr Exp + */ + +#include "ipf.h" + + +void printip(addr) +u_32_t *addr; +{ + struct in_addr ipa; + + ipa.s_addr = *addr; + if (ntohl(ipa.s_addr) < 256) + printf("%lu", (u_long)ntohl(ipa.s_addr)); + else + printf("%s", inet_ntoa(ipa)); +} diff --git a/contrib/ipfilter/lib/printlog.c b/contrib/ipfilter/lib/printlog.c new file mode 100644 index 0000000..d14add4 --- /dev/null +++ b/contrib/ipfilter/lib/printlog.c @@ -0,0 +1,44 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printlog.c,v 1.6 2002/01/28 06:50:47 darrenr Exp + */ + +#include "ipf.h" + +#include <syslog.h> + + +void printlog(fp) +frentry_t *fp; +{ + 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/lib/printmask.c b/contrib/ipfilter/lib/printmask.c new file mode 100644 index 0000000..d3d9a6f --- /dev/null +++ b/contrib/ipfilter/lib/printmask.c @@ -0,0 +1,30 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printmask.c,v 1.5 2002/06/15 04:48:33 darrenr Exp + */ + +#include "ipf.h" + + +void printmask(mask) +u_32_t *mask; +{ + struct in_addr ipa; + int ones; + +#ifdef USE_INET6 + if (use_inet6) + printf("/%d", count6bits(mask)); + else +#endif + if ((ones = count4bits(*mask)) == -1) { + ipa.s_addr = *mask; + printf("/%s", inet_ntoa(ipa)); + } else + printf("/%d", ones); +} diff --git a/contrib/ipfilter/lib/printnat.c b/contrib/ipfilter/lib/printnat.c new file mode 100644 index 0000000..15a6886 --- /dev/null +++ b/contrib/ipfilter/lib/printnat.c @@ -0,0 +1,247 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" +#include "kmem.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: printnat.c,v 1.22.2.8 2005/01/12 03:39:04 darrenr Exp"; +#endif + +static void printproto __P((ipnat_t *, struct protoent *)); + +/* + * Print out a NAT rule + */ +void printnat(np, opts) +ipnat_t *np; +int opts; +{ + struct protoent *pr; + int bits; + + pr = getprotobynumber(np->in_p); + + switch (np->in_redir) + { + case NAT_REDIRECT : + printf("rdr"); + break; + case NAT_MAP : + printf("map"); + break; + case NAT_MAPBLK : + printf("map-block"); + break; + case NAT_BIMAP : + printf("bimap"); + break; + default : + fprintf(stderr, "unknown value for in_redir: %#x\n", + np->in_redir); + break; + } + + printf(" %s", np->in_ifnames[0]); + if ((np->in_ifnames[1][0] != '\0') && + (strncmp(np->in_ifnames[0], np->in_ifnames[1], LIFNAMSIZ) != 0)) { + printf(",%s ", np->in_ifnames[1]); + } + putchar(' '); + + if (np->in_flags & IPN_FILTER) { + if (np->in_flags & IPN_NOTSRC) + printf("! "); + 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); + + if (np->in_flags & IPN_NOTDST) + printf(" !"); + printf(" to "); + if (np->in_redir == NAT_REDIRECT) { + printhostmask(4, (u_32_t *)&np->in_outip, + (u_32_t *)&np->in_outmsk); + } 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) { + if (!(np->in_flags & IPN_FILTER)) { + printf("%s", inet_ntoa(np->in_out[0].in4)); + bits = count4bits(np->in_outmsk); + if (bits != -1) + printf("/%d", bits); + else + printf("/%s", inet_ntoa(np->in_out[1].in4)); + if (np->in_flags & IPN_TCPUDP) { + 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].in4)); + if (np->in_flags & IPN_SPLIT) + printf(",%s", inet_ntoa(np->in_in[1].in4)); + if (np->in_flags & IPN_TCPUDP) { + if ((np->in_flags & IPN_FIXEDDPORT) != 0) + printf(" port = %d", ntohs(np->in_pnext)); + else + printf(" port %d", ntohs(np->in_pnext)); + } + printproto(np, pr); + if (np->in_flags & IPN_ROUNDR) + printf(" round-robin"); + if (np->in_flags & IPN_FRAG) + printf(" frag"); + if (np->in_age[0] != 0 || np->in_age[1] != 0) { + printf(" age %d/%d", np->in_age[0], np->in_age[1]); + } + if (np->in_flags & IPN_STICKY) + printf(" sticky"); + if (np->in_mssclamp != 0) + printf(" mssclamp %d", np->in_mssclamp); + if (*np->in_plabel != '\0') + printf(" proxy %.*s", (int)sizeof(np->in_plabel), + np->in_plabel); + if (np->in_tag.ipt_tag[0] != '\0') + printf(" tag %-.*s", IPFTAG_LEN, np->in_tag.ipt_tag); + printf("\n"); + if (opts & OPT_DEBUG) + printf("\tpmax %u\n", np->in_pmax); + } else { + if (!(np->in_flags & IPN_FILTER)) { + printf("%s/", inet_ntoa(np->in_in[0].in4)); + bits = count4bits(np->in_inmsk); + if (bits != -1) + printf("%d", bits); + else + printf("%s", inet_ntoa(np->in_in[1].in4)); + } + printf(" -> "); + if (np->in_flags & IPN_IPRANGE) { + printf("range %s-", inet_ntoa(np->in_out[0].in4)); + printf("%s", inet_ntoa(np->in_out[1].in4)); + } else { + printf("%s/", inet_ntoa(np->in_out[0].in4)); + bits = count4bits(np->in_outmsk); + if (bits != -1) + printf("%d", bits); + else + printf("%s", inet_ntoa(np->in_out[1].in4)); + } + if (*np->in_plabel != '\0') { + printf(" proxy port "); + if (np->in_dcmp != 0) + np->in_dport = htons(np->in_dport); + if (np->in_dport != 0) { + char *s; + + s = portname(np->in_p, ntohs(np->in_dport)); + if (s != NULL) + fputs(s, stdout); + else + fputs("???", stdout); + } + printf(" %.*s/", (int)sizeof(np->in_plabel), + np->in_plabel); + if (pr != NULL) + fputs(pr->p_name, stdout); + else + printf("%d", np->in_p); + } else if (np->in_redir == NAT_MAPBLK) { + if ((np->in_pmin == 0) && + (np->in_flags & IPN_AUTOPORTMAP)) + printf(" ports auto"); + else + printf(" ports %d", np->in_pmin); + if (opts & OPT_DEBUG) + printf("\n\tip modulous %d", np->in_pmax); + } else if (np->in_pmin || np->in_pmax) { + if (np->in_flags & IPN_ICMPQUERY) { + printf(" icmpidmap"); + } else { + printf(" portmap"); + } + printproto(np, pr); + if (np->in_flags & IPN_AUTOPORTMAP) { + printf(" auto"); + if (opts & OPT_DEBUG) + printf(" [%d:%d %d %d]", + ntohs(np->in_pmin), + ntohs(np->in_pmax), + np->in_ippip, np->in_ppip); + } else { + printf(" %d:%d", ntohs(np->in_pmin), + ntohs(np->in_pmax)); + } + } else if (np->in_flags & IPN_TCPUDP || np->in_p) + printproto(np, pr); + + if (np->in_flags & IPN_FRAG) + printf(" frag"); + if (np->in_age[0] != 0 || np->in_age[1] != 0) { + printf(" age %d/%d", np->in_age[0], np->in_age[1]); + } + if (np->in_mssclamp != 0) + printf(" mssclamp %d", np->in_mssclamp); + if (np->in_tag.ipt_tag[0] != '\0') + printf(" tag %s", np->in_tag.ipt_tag); + printf("\n"); + if (opts & OPT_DEBUG) { + struct in_addr nip; + + nip.s_addr = htonl(np->in_nextip.s_addr); + + printf("\tnextip %s pnext %d\n", + inet_ntoa(nip), np->in_pnext); + } + } + + if (opts & OPT_DEBUG) { + printf("\tspace %lu use %u hits %lu flags %#x proto %d hv %d\n", + np->in_space, np->in_use, np->in_hits, + np->in_flags, np->in_p, np->in_hv); + printf("\tifp[0] %p ifp[1] %p apr %p\n", + np->in_ifps[0], np->in_ifps[1], np->in_apr); + printf("\ttqehead %p/%p comment %p\n", + np->in_tqehead[0], np->in_tqehead[1], np->in_comment); + } +} + +static void printproto(np, pr) +ipnat_t *np; +struct protoent *pr; +{ + if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) + printf(" tcp/udp"); + else if (np->in_flags & IPN_TCP) + printf(" tcp"); + else if (np->in_flags & IPN_UDP) + printf(" udp"); + else if (np->in_flags & IPN_ICMPQUERY) + printf(" icmp"); + else if (pr != NULL) + printf(" %s", pr->p_name); + else + printf(" %d", np->in_p); +} diff --git a/contrib/ipfilter/lib/printpacket.c b/contrib/ipfilter/lib/printpacket.c new file mode 100644 index 0000000..58460be --- /dev/null +++ b/contrib/ipfilter/lib/printpacket.c @@ -0,0 +1,89 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printpacket.c,v 1.12.4.1 2005/02/21 05:09:24 darrenr Exp + */ + +#include "ipf.h" + +#ifndef IP_OFFMASK +# define IP_OFFMASK 0x3fff +#endif + + +void printpacket(ip) +struct ip *ip; +{ + struct tcphdr *tcp; + u_short len; + u_short off; + + if (IP_V(ip) == 6) { + off = 0; + len = ntohs(((u_short *)ip)[2]) + 40; + } else { + off = ntohs(ip->ip_off); + len = ntohs(ip->ip_len); + } + + if ((opts & OPT_HEX) == OPT_HEX) { + u_char *s; + int i; + + for (s = (u_char *)ip, i = 0; i < len; i++) { + printf("%02x", *s++ & 0xff); + if (len - i > 1) { + i++; + printf("%02x", *s++ & 0xff); + } + putchar(' '); + } + putchar('\n'); + return; + } + + if (IP_V(ip) == 6) { + printpacket6(ip); + return; + } + + tcp = (struct tcphdr *)((char *)ip + (IP_HL(ip) << 2)); + printf("ip %d(%d) %d", ntohs(ip->ip_len), IP_HL(ip) << 2, ip->ip_p); + if (off & IP_OFFMASK) + printf(" @%d", off << 3); + printf(" %s", inet_ntoa(ip->ip_src)); + if (!(off & IP_OFFMASK)) + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + printf(",%d", ntohs(tcp->th_sport)); + printf(" > "); + printf("%s", inet_ntoa(ip->ip_dst)); + if (!(off & IP_OFFMASK)) { + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + printf(",%d", ntohs(tcp->th_dport)); + if ((ip->ip_p == IPPROTO_TCP) && (tcp->th_flags != 0)) { + putchar(' '); + if (tcp->th_flags & TH_FIN) + putchar('F'); + if (tcp->th_flags & TH_SYN) + putchar('S'); + if (tcp->th_flags & TH_RST) + putchar('R'); + if (tcp->th_flags & TH_PUSH) + putchar('P'); + if (tcp->th_flags & TH_ACK) + putchar('A'); + if (tcp->th_flags & TH_URG) + putchar('U'); + if (tcp->th_flags & TH_ECN) + putchar('E'); + if (tcp->th_flags & TH_CWR) + putchar('C'); + } + } + + putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printpacket6.c b/contrib/ipfilter/lib/printpacket6.c new file mode 100644 index 0000000..2f9ea1d --- /dev/null +++ b/contrib/ipfilter/lib/printpacket6.c @@ -0,0 +1,43 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +/* + * This is meant to work without the IPv6 header files being present or + * the inet_ntop() library. + */ +void printpacket6(ip) +struct ip *ip; +{ + u_char *buf, p; + u_short plen, *addrs; + tcphdr_t *tcp; + u_32_t flow; + + buf = (u_char *)ip; + tcp = (tcphdr_t *)(buf + 40); + p = buf[6]; + flow = ntohl(*(u_32_t *)buf); + flow &= 0xfffff; + plen = ntohs(*((u_short *)buf +2)); + addrs = (u_short *)buf + 4; + + printf("ip6/%d %d %#x %d", buf[0] & 0xf, plen, flow, p); + printf(" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]), + ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]), + ntohs(addrs[6]), ntohs(addrs[7])); + if (plen >= 4) + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + (void)printf(",%d", ntohs(tcp->th_sport)); + printf(" >"); + addrs += 8; + printf(" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]), + ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]), + ntohs(addrs[6]), ntohs(addrs[7])); + if (plen >= 4) + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + (void)printf(",%d", ntohs(tcp->th_dport)); + putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printpool.c b/contrib/ipfilter/lib/printpool.c new file mode 100644 index 0000000..6291306 --- /dev/null +++ b/contrib/ipfilter/lib/printpool.c @@ -0,0 +1,108 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf + +ip_pool_t *printpool(pp, copyfunc, name, opts) +ip_pool_t *pp; +copyfunc_t copyfunc; +char *name; +int opts; +{ + ip_pool_node_t *ipnp, *ipnpn, ipn; + ip_pool_t ipp; + + if ((*copyfunc)(pp, &ipp, sizeof(ipp))) + return NULL; + + if ((name != NULL) && strncmp(name, ipp.ipo_name, FR_GROUPLEN)) + return ipp.ipo_next; + + if ((opts & OPT_DEBUG) == 0) { + if ((ipp.ipo_flags & IPOOL_ANON) != 0) + PRINTF("# 'anonymous' tree %s\n", ipp.ipo_name); + PRINTF("table role = "); + } else { + PRINTF("Name: %s", ipp.ipo_name); + if ((ipp.ipo_flags & IPOOL_ANON) == IPOOL_ANON) + PRINTF("(anon)"); + putchar(' '); + PRINTF("Role: "); + } + + switch (ipp.ipo_unit) + { + case IPL_LOGIPF : + printf("ipf"); + break; + case IPL_LOGNAT : + printf("nat"); + break; + case IPL_LOGSTATE : + printf("state"); + break; + case IPL_LOGAUTH : + printf("auth"); + break; + case IPL_LOGSYNC : + printf("sync"); + break; + case IPL_LOGSCAN : + printf("scan"); + break; + case IPL_LOGLOOKUP : + printf("lookup"); + break; + case IPL_LOGCOUNT : + printf("count"); + break; + default : + printf("unknown(%d)", ipp.ipo_unit); + } + + if ((opts & OPT_DEBUG) == 0) { + PRINTF(" type = tree number = %s\n", ipp.ipo_name); + PRINTF("\t{"); + } else { + putchar(' '); + + PRINTF("\tReferences: %d\tHits: %lu\n", ipp.ipo_ref, + ipp.ipo_hits); + PRINTF("\tNodes Starting at %p\n", ipp.ipo_list); + } + + ipnpn = ipp.ipo_list; + ipp.ipo_list = NULL; + while (ipnpn != NULL) { + ipnp = (ip_pool_node_t *)malloc(sizeof(*ipnp)); + (*copyfunc)(ipnpn, ipnp, sizeof(ipn)); + ipnpn = ipnp->ipn_next; + ipnp->ipn_next = ipp.ipo_list; + ipp.ipo_list = ipnp; + } + + if (ipp.ipo_list == NULL) { + putchar(';'); + } else { + for (ipnp = ipp.ipo_list; ipnp != NULL; ) { + ipnp = printpoolnode(ipnp, opts); + + if ((opts & OPT_DEBUG) == 0) { + putchar(';'); + } + } + } + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + + return ipp.ipo_next; +} diff --git a/contrib/ipfilter/lib/printpoolnode.c b/contrib/ipfilter/lib/printpoolnode.c new file mode 100644 index 0000000..dd0ef97 --- /dev/null +++ b/contrib/ipfilter/lib/printpoolnode.c @@ -0,0 +1,33 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf + +ip_pool_node_t *printpoolnode(np, opts) +ip_pool_node_t *np; +int opts; +{ + + if ((opts & OPT_DEBUG) == 0) { + putchar(' '); + if (np->ipn_info == 1) + PRINTF("! "); + printip((u_32_t *)&np->ipn_addr.adf_addr.in4); + printmask((u_32_t *)&np->ipn_mask.adf_addr); + } else { + PRINTF("\t\t%s%s", np->ipn_info ? "! " : "", + inet_ntoa(np->ipn_addr.adf_addr.in4)); + printmask((u_32_t *)&np->ipn_mask.adf_addr); + PRINTF("\n\t\tHits %lu\tName %s\n", + np->ipn_hits, np->ipn_name); + } + return np->ipn_next; +} diff --git a/contrib/ipfilter/lib/printportcmp.c b/contrib/ipfilter/lib/printportcmp.c new file mode 100644 index 0000000..7ec0116 --- /dev/null +++ b/contrib/ipfilter/lib/printportcmp.c @@ -0,0 +1,29 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: printportcmp.c,v 1.7 2003/02/16 02:31:05 darrenr Exp + */ + +#include "ipf.h" + + +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 if (frp->frp_cmp == FR_INCRANGE) + printf(" port %d:%d", frp->frp_port, frp->frp_top); + else + printf(" port %s %s", pcmp1[frp->frp_cmp], + portname(pr, frp->frp_port)); +} diff --git a/contrib/ipfilter/lib/printsbuf.c b/contrib/ipfilter/lib/printsbuf.c new file mode 100644 index 0000000..805c03b --- /dev/null +++ b/contrib/ipfilter/lib/printsbuf.c @@ -0,0 +1,24 @@ +/* $NetBSD$ */ + +#ifdef IPFILTER_SCAN + +#include <ctype.h> +#include <stdio.h> +#include "ipf.h" +#include "netinet/ip_scan.h" + +void printsbuf(buf) +char *buf; +{ + u_char *s; + int i; + + for (s = (u_char *)buf, i = ISC_TLEN; i; i--, s++) { + if (ISPRINT(*s)) + putchar(*s); + else + printf("\\%o", *s); + } +} + +#endif diff --git a/contrib/ipfilter/lib/printstate.c b/contrib/ipfilter/lib/printstate.c new file mode 100644 index 0000000..9cfdc8a --- /dev/null +++ b/contrib/ipfilter/lib/printstate.c @@ -0,0 +1,189 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" +#include "kmem.h" + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf + +ipstate_t *printstate(sp, opts, now) +ipstate_t *sp; +int opts; +u_long now; +{ + ipstate_t ips; + synclist_t ipsync; + + if (kmemcpy((char *)&ips, (u_long)sp, sizeof(ips))) + return NULL; + + PRINTF("%s -> ", hostname(ips.is_v, &ips.is_src.in4)); + PRINTF("%s pass %#x pr %d state %d/%d bkt %d\n", + hostname(ips.is_v, &ips.is_dst.in4), ips.is_pass, ips.is_p, + ips.is_state[0], ips.is_state[1], ips.is_hv); + PRINTF("\ttag %u ttl %lu", ips.is_tag, ips.is_die - now); + + if (ips.is_p == IPPROTO_TCP) { + PRINTF("\n\t%hu -> %hu %x:%x %hu<<%d:%hu<<%d\n", + ntohs(ips.is_sport), ntohs(ips.is_dport), + ips.is_send, ips.is_dend, + ips.is_maxswin, ips.is_swinscale, + ips.is_maxdwin, ips.is_dwinscale); + PRINTF("\tcmsk %04x smsk %04x isc %p s0 %08x/%08x\n", + ips.is_smsk[0], ips.is_smsk[1], ips.is_isc, + ips.is_s0[0], ips.is_s0[1]); + PRINTF("\tFWD:ISN inc %x sumd %x\n", + ips.is_isninc[0], ips.is_sumd[0]); + PRINTF("\tREV:ISN inc %x sumd %x\n", + ips.is_isninc[1], ips.is_sumd[1]); +#ifdef IPFILTER_SCAN + PRINTF("\tsbuf[0] ["); + printsbuf(ips.is_sbuf[0]); + PRINTF("] sbuf[1] ["); + printsbuf(ips.is_sbuf[1]); + PRINTF("]\n"); +#endif + } else if (ips.is_p == IPPROTO_UDP) { + PRINTF(" %hu -> %hu\n", ntohs(ips.is_sport), + ntohs(ips.is_dport)); + } else if (ips.is_p == IPPROTO_GRE) { + PRINTF(" call %hx/%hx\n", ntohs(ips.is_gre.gs_call[0]), + ntohs(ips.is_gre.gs_call[1])); + } else if (ips.is_p == IPPROTO_ICMP +#ifdef USE_INET6 + || ips.is_p == IPPROTO_ICMPV6 +#endif + ) + PRINTF(" id %hu seq %hu type %d\n", ips.is_icmp.ici_id, + ips.is_icmp.ici_seq, ips.is_icmp.ici_type); + +#ifdef USE_QUAD_T + PRINTF("\tforward: pkts in %qd bytes in %qd pkts out %qd bytes out %qd\n\tbackward: pkts in %qd bytes in %qd pkts out %qd bytes out %qd\n", + ips.is_pkts[0], ips.is_bytes[0], + ips.is_pkts[1], ips.is_bytes[1], + ips.is_pkts[2], ips.is_bytes[2], + ips.is_pkts[3], ips.is_bytes[3]); +#else + PRINTF("\tforward: pkts in %ld bytes in %ld pkts out %ld bytes out %ld\n\tbackward: pkts in %ld bytes in %ld pkts out %ld bytes out %ld\n", + ips.is_pkts[0], ips.is_bytes[0], + ips.is_pkts[1], ips.is_bytes[1], + ips.is_pkts[2], ips.is_bytes[2], + ips.is_pkts[3], ips.is_bytes[3]); +#endif + + PRINTF("\t"); + + /* + * Print out bits set in the result code for the state being + * kept as they would for a rule. + */ + if (FR_ISPASS(ips.is_pass)) { + PRINTF("pass"); + } else if (FR_ISBLOCK(ips.is_pass)) { + 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 (FR_ISACCOUNT(ips.is_pass)) { + PRINTF("count"); + } else if (FR_ISPREAUTH(ips.is_pass)) { + PRINTF("preauth"); + } else if (FR_ISAUTH(ips.is_pass)) + PRINTF("auth"); + + 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"); + if (ips.is_pass & FR_STATESYNC) + PRINTF(" ( sync )"); + } + 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("\tis_flx %#x %#x %#x %#x\n", ips.is_flx[0][0], ips.is_flx[0][1], + ips.is_flx[1][0], ips.is_flx[1][1]); + PRINTF("\tinterfaces: in %s[%s", getifname(ips.is_ifp[0]), + ips.is_ifname[0]); + if (opts & OPT_DEBUG) + PRINTF("/%p", ips.is_ifp[0]); + putchar(']'); + PRINTF(",%s[%s", getifname(ips.is_ifp[1]), ips.is_ifname[1]); + if (opts & OPT_DEBUG) + PRINTF("/%p", ips.is_ifp[1]); + putchar(']'); + PRINTF(" out %s[%s", getifname(ips.is_ifp[2]), ips.is_ifname[2]); + if (opts & OPT_DEBUG) + PRINTF("/%p", ips.is_ifp[2]); + putchar(']'); + PRINTF(",%s[%s", getifname(ips.is_ifp[3]), ips.is_ifname[3]); + if (opts & OPT_DEBUG) + PRINTF("/%p", ips.is_ifp[3]); + PRINTF("]\n"); + + if (ips.is_sync != NULL) { + + if (kmemcpy((char *)&ipsync, (u_long)ips.is_sync, sizeof(ipsync))) { + + PRINTF("\tSync status: status could not be retrieved\n"); + return NULL; + } + + PRINTF("\tSync status: idx %d num %d v %d pr %d rev %d\n", + ipsync.sl_idx, ipsync.sl_num, ipsync.sl_v, + ipsync.sl_p, ipsync.sl_rev); + + } else { + PRINTF("\tSync status: not synchronized\n"); + } + + return ips.is_next; +} diff --git a/contrib/ipfilter/lib/printtunable.c b/contrib/ipfilter/lib/printtunable.c new file mode 100644 index 0000000..46e9f80 --- /dev/null +++ b/contrib/ipfilter/lib/printtunable.c @@ -0,0 +1,21 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +void printtunable(tup) +ipftune_t *tup; +{ + printf("%s\tmin %#lx\tmax %#lx\tcurrent ", + tup->ipft_name, tup->ipft_min, tup->ipft_max); + if (tup->ipft_sz == sizeof(u_long)) + printf("%lu\n", tup->ipft_vlong); + else if (tup->ipft_sz == sizeof(u_int)) + printf("%u\n", tup->ipft_vint); + else if (tup->ipft_sz == sizeof(u_short)) + printf("%hu\n", tup->ipft_vshort); + else if (tup->ipft_sz == sizeof(u_char)) + printf("%u\n", (u_int)tup->ipft_vchar); + else { + printf("sz = %d\n", tup->ipft_sz); + } +} diff --git a/contrib/ipfilter/lib/ratoi.c b/contrib/ipfilter/lib/ratoi.c new file mode 100644 index 0000000..31ee122 --- /dev/null +++ b/contrib/ipfilter/lib/ratoi.c @@ -0,0 +1,26 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ratoi.c,v 1.4 2001/06/09 17:09:25 darrenr Exp + */ + +#include "ipf.h" + + +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; +} diff --git a/contrib/ipfilter/lib/ratoui.c b/contrib/ipfilter/lib/ratoui.c new file mode 100644 index 0000000..e4d0cbf --- /dev/null +++ b/contrib/ipfilter/lib/ratoui.c @@ -0,0 +1,26 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ratoui.c,v 1.4 2001/06/09 17:09:25 darrenr Exp + */ + +#include "ipf.h" + + +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; +} diff --git a/contrib/ipfilter/lib/remove_hash.c b/contrib/ipfilter/lib/remove_hash.c new file mode 100644 index 0000000..256751f --- /dev/null +++ b/contrib/ipfilter/lib/remove_hash.c @@ -0,0 +1,53 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: remove_hash.c,v 1.1 2003/04/13 06:40:14 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + +static int hashfd = -1; + + +int remove_hash(iphp, iocfunc) +iphtable_t *iphp; +ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtable_t iph; + + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + hashfd = open(IPLOOKUP_NAME, O_RDWR); + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + op.iplo_type = IPLT_HASH; + op.iplo_unit = iphp->iph_unit; + strncpy(op.iplo_name, iphp->iph_name, sizeof(op.iplo_name)); + if (*op.iplo_name == '\0') + op.iplo_arg = IPHASH_ANON; + op.iplo_size = sizeof(iph); + op.iplo_struct = &iph; + + bzero((char *)&iph, sizeof(iph)); + iph.iph_unit = iphp->iph_unit; + iph.iph_type = iphp->iph_type; + strncpy(iph.iph_name, iphp->iph_name, sizeof(iph.iph_name)); + iph.iph_flags = iphp->iph_flags; + + if ((*iocfunc)(hashfd, SIOCLOOKUPDELTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + perror("remove_hash:SIOCLOOKUPDELTABLE"); + return -1; + } + + return 0; +} diff --git a/contrib/ipfilter/lib/remove_hashnode.c b/contrib/ipfilter/lib/remove_hashnode.c new file mode 100644 index 0000000..5e5b634 --- /dev/null +++ b/contrib/ipfilter/lib/remove_hashnode.c @@ -0,0 +1,58 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: remove_hashnode.c,v 1.1 2003/04/13 06:40:14 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + +static int hashfd = -1; + + +int remove_hashnode(unit, name, node, iocfunc) +int unit; +char *name; +iphtent_t *node; +ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtent_t ipe; + + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + hashfd = open(IPLOOKUP_NAME, O_RDWR); + if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + op.iplo_type = IPLT_HASH; + op.iplo_unit = unit; + op.iplo_size = sizeof(ipe); + op.iplo_struct = &ipe; + op.iplo_arg = 0; + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + + bzero((char *)&ipe, sizeof(ipe)); + bcopy((char *)&node->ipe_addr, (char *)&ipe.ipe_addr, + sizeof(ipe.ipe_addr)); + bcopy((char *)&node->ipe_mask, (char *)&ipe.ipe_mask, + sizeof(ipe.ipe_mask)); + + if (opts & OPT_DEBUG) { + printf("\t%s - ", inet_ntoa(ipe.ipe_addr.in4)); + printf("%s\n", inet_ntoa(ipe.ipe_mask.in4)); + } + + if ((*iocfunc)(hashfd, SIOCLOOKUPDELNODE, &op)) + if (!(opts & OPT_DONOTHING)) { + perror("remove_hash:SIOCLOOKUPDELNODE"); + return -1; + } + return 0; +} diff --git a/contrib/ipfilter/lib/remove_pool.c b/contrib/ipfilter/lib/remove_pool.c new file mode 100644 index 0000000..3f5e004 --- /dev/null +++ b/contrib/ipfilter/lib/remove_pool.c @@ -0,0 +1,50 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: remove_pool.c,v 1.1 2003/04/13 06:40:14 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + +static int poolfd = -1; + + +int remove_pool(poolp, iocfunc) +ip_pool_t *poolp; +ioctlfunc_t iocfunc; +{ + iplookupop_t op; + ip_pool_t pool; + + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + poolfd = open(IPLOOKUP_NAME, O_RDWR); + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + op.iplo_type = IPLT_POOL; + op.iplo_unit = poolp->ipo_unit; + strncpy(op.iplo_name, poolp->ipo_name, sizeof(op.iplo_name)); + op.iplo_size = sizeof(pool); + op.iplo_struct = &pool; + + bzero((char *)&pool, sizeof(pool)); + pool.ipo_unit = poolp->ipo_unit; + strncpy(pool.ipo_name, poolp->ipo_name, sizeof(pool.ipo_name)); + pool.ipo_flags = poolp->ipo_flags; + + if ((*iocfunc)(poolfd, SIOCLOOKUPDELTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + perror("remove_pool:SIOCLOOKUPDELTABLE"); + return -1; + } + + return 0; +} diff --git a/contrib/ipfilter/lib/remove_poolnode.c b/contrib/ipfilter/lib/remove_poolnode.c new file mode 100644 index 0000000..aff4694 --- /dev/null +++ b/contrib/ipfilter/lib/remove_poolnode.c @@ -0,0 +1,57 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2002 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: remove_poolnode.c,v 1.3 2003/11/22 10:14:36 darrenr Exp + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + +static int poolfd = -1; + + +int remove_poolnode(unit, name, node, iocfunc) +int unit; +char *name; +ip_pool_node_t *node; +ioctlfunc_t iocfunc; +{ + ip_pool_node_t pn; + iplookupop_t op; + + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + poolfd = open(IPLOOKUP_NAME, O_RDWR); + if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) + return -1; + + op.iplo_unit = unit; + op.iplo_type = IPLT_POOL; + op.iplo_arg = 0; + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + op.iplo_struct = &pn; + op.iplo_size = sizeof(pn); + + bzero((char *)&pn, sizeof(pn)); + bcopy((char *)&node->ipn_addr, (char *)&pn.ipn_addr, + sizeof(pn.ipn_addr)); + bcopy((char *)&node->ipn_mask, (char *)&pn.ipn_mask, + sizeof(pn.ipn_mask)); + pn.ipn_info = node->ipn_info; + strncpy(pn.ipn_name, node->ipn_name, sizeof(pn.ipn_name)); + + if ((*iocfunc)(poolfd, SIOCLOOKUPDELNODE, &op)) { + if ((opts & OPT_DONOTHING) == 0) { + perror("remove_pool:SIOCLOOKUPDELNODE"); + return -1; + } + } + + return 0; +} diff --git a/contrib/ipfilter/lib/resetlexer.c b/contrib/ipfilter/lib/resetlexer.c new file mode 100644 index 0000000..0801242 --- /dev/null +++ b/contrib/ipfilter/lib/resetlexer.c @@ -0,0 +1,17 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +long string_start = -1; +long string_end = -1; +char *string_val = NULL; +long pos = 0; + + +void resetlexer() +{ + string_start = -1; + string_end = -1; + string_val = NULL; + pos = 0; +} diff --git a/contrib/ipfilter/lib/rwlock_emul.c b/contrib/ipfilter/lib/rwlock_emul.c new file mode 100644 index 0000000..64b807e --- /dev/null +++ b/contrib/ipfilter/lib/rwlock_emul.c @@ -0,0 +1,125 @@ +/* $NetBSD$ */ + +#include "ipf.h" + +#define EMM_MAGIC 0x97dd8b3a + +void eMrwlock_read_enter(rw, file, line) +eMrwlock_t *rw; +char *file; +int line; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_read_enter(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 0 || rw->eMrw_write != 0) { + fprintf(stderr, + "%s:eMrwlock_read_enter(%p): already locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + rw->eMrw_read++; + rw->eMrw_heldin = file; + rw->eMrw_heldat = line; +} + + +void eMrwlock_write_enter(rw, file, line) +eMrwlock_t *rw; +char *file; +int line; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_write_enter(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 0 || rw->eMrw_write != 0) { + fprintf(stderr, + "%s:eMrwlock_write_enter(%p): already locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + rw->eMrw_write++; + rw->eMrw_heldin = file; + rw->eMrw_heldat = line; +} + + +void eMrwlock_downgrade(rw, file, line) +eMrwlock_t *rw; +char *file; +int line; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_write_enter(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 0 || rw->eMrw_write != 1) { + fprintf(stderr, + "%s:eMrwlock_write_enter(%p): already locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + rw->eMrw_write--; + rw->eMrw_read++; + rw->eMrw_heldin = file; + rw->eMrw_heldat = line; +} + + +void eMrwlock_exit(rw) +eMrwlock_t *rw; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_exit(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 1 && rw->eMrw_write != 1) { + fprintf(stderr, "%s:eMrwlock_exit(%p): not locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + if (rw->eMrw_read == 1) + rw->eMrw_read--; + else if (rw->eMrw_write == 1) + rw->eMrw_write--; + rw->eMrw_heldin = NULL; + rw->eMrw_heldat = 0; +} + + +void eMrwlock_init(rw, who) +eMrwlock_t *rw; +char *who; +{ + if (rw->eMrw_magic == EMM_MAGIC) { /* safe bet ? */ + fprintf(stderr, + "%s:eMrwlock_init(%p): already initialised?: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + rw->eMrw_magic = EMM_MAGIC; + rw->eMrw_read = 0; + rw->eMrw_write = 0; + if (who != NULL) + rw->eMrw_owner = strdup(who); + else + rw->eMrw_owner = NULL; +} + + +void eMrwlock_destroy(rw) +eMrwlock_t *rw; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_destroy(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + memset(rw, 0xa5, sizeof(*rw)); +} diff --git a/contrib/ipfilter/lib/tcp_flags.c b/contrib/ipfilter/lib/tcp_flags.c new file mode 100644 index 0000000..314b9d2 --- /dev/null +++ b/contrib/ipfilter/lib/tcp_flags.c @@ -0,0 +1,50 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: tcp_flags.c,v 1.8 2004/02/07 18:15:54 darrenr Exp + */ + +#include "ipf.h" + +extern char flagset[]; +extern u_char flags[]; + + +u_char tcp_flags(flgs, mask, linenum) +char *flgs; +u_char *mask; +int linenum; +{ + u_char tcpf = 0, tcpfm = 0; + char *s; + + s = strchr(flgs, '/'); + if (s) + *s++ = '\0'; + + if (*flgs == '0') { + tcpf = strtol(flgs, NULL, 0); + } else { + tcpf = tcpflags(flgs); + } + + if (s != NULL) { + if (*s == '0') + tcpfm = strtol(s, NULL, 0); + else + tcpfm = tcpflags(s); + } + + if (!tcpfm) { + if (tcpf == TH_SYN) + tcpfm = 0xff & ~(TH_ECN|TH_CWR); + else + tcpfm = 0xff & ~(TH_ECN); + } + *mask = tcpfm; + return tcpf; +} diff --git a/contrib/ipfilter/lib/tcpflags.c b/contrib/ipfilter/lib/tcpflags.c new file mode 100644 index 0000000..b7ea4b8 --- /dev/null +++ b/contrib/ipfilter/lib/tcpflags.c @@ -0,0 +1,45 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: tcpflags.c,v 1.3 2002/11/02 07:18:01 darrenr Exp + */ + +#include "ipf.h" + + +/* + * ECN is a new addition to TCP - RFC 2481 + */ +#ifndef TH_ECN +# define TH_ECN 0x40 +#endif +#ifndef TH_CWR +# define TH_CWR 0x80 +#endif + +extern char flagset[]; +extern u_char flags[]; + + +u_char tcpflags(flgs) +char *flgs; +{ + u_char tcpf = 0; + char *s, *t; + + for (s = flgs; *s; s++) { + if (*s == 'W') + tcpf |= TH_CWR; + else { + if (!(t = strchr(flagset, *s))) { + return 0; + } + tcpf |= flags[t - flagset]; + } + } + return tcpf; +} diff --git a/contrib/ipfilter/lib/tcpoptnames.c b/contrib/ipfilter/lib/tcpoptnames.c new file mode 100644 index 0000000..b5e0cc7 --- /dev/null +++ b/contrib/ipfilter/lib/tcpoptnames.c @@ -0,0 +1,22 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: tcpoptnames.c,v 1.5 2002/01/28 06:50:48 darrenr Exp + */ + +#include "ipf.h" + + +struct ipopt_names tcpoptnames[] ={ + { TCPOPT_NOP, 0x000001, 1, "nop" }, + { TCPOPT_MAXSEG, 0x000002, 4, "maxseg" }, + { TCPOPT_WINDOW, 0x000004, 3, "wscale" }, + { TCPOPT_SACK_PERMITTED, 0x000008, 2, "sackok" }, + { TCPOPT_SACK, 0x000010, 3, "sack" }, + { TCPOPT_TIMESTAMP, 0x000020, 10, "tstamp" }, + { 0, 0, 0, (char *)NULL } /* must be last */ +}; diff --git a/contrib/ipfilter/lib/to_interface.c b/contrib/ipfilter/lib/to_interface.c new file mode 100644 index 0000000..50f9a70 --- /dev/null +++ b/contrib/ipfilter/lib/to_interface.c @@ -0,0 +1,31 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: to_interface.c,v 1.8 2002/01/28 06:50:48 darrenr Exp + */ + +#include "ipf.h" + + +int to_interface(fdp, to, linenum) +frdest_t *fdp; +char *to; +int linenum; +{ + char *s; + + s = strchr(to, ':'); + fdp->fd_ifp = NULL; + if (s) { + *s++ = '\0'; + if (hostnum((u_32_t *)&fdp->fd_ip, s, linenum, NULL) == -1) + return -1; + } + (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1); + fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0'; + return 0; +} diff --git a/contrib/ipfilter/lib/v6ionames.c b/contrib/ipfilter/lib/v6ionames.c new file mode 100644 index 0000000..087da5d --- /dev/null +++ b/contrib/ipfilter/lib/v6ionames.c @@ -0,0 +1,27 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: v6ionames.c,v 1.1.4.1 2005/01/02 13:08:49 darrenr Exp + */ +#include "ipf.h" + + +#ifdef USE_INET6 + +struct ipopt_names v6ionames[] ={ + { IPPROTO_HOPOPTS, 0x000001, 0, "hopopts" }, + { IPPROTO_IPV6, 0x000002, 0, "ipv6" }, + { IPPROTO_ROUTING, 0x000004, 0, "routing" }, + { IPPROTO_FRAGMENT, 0x000008, 0, "frag" }, + { IPPROTO_ESP, 0x000010, 0, "esp" }, + { IPPROTO_AH, 0x000020, 0, "ah" }, + { IPPROTO_NONE, 0x000040, 0, "none" }, + { IPPROTO_DSTOPTS, 0x000080, 0, "dstopts" }, + { 0, 0, 0, (char *)NULL } +}; + +#endif diff --git a/contrib/ipfilter/lib/v6optvalue.c b/contrib/ipfilter/lib/v6optvalue.c new file mode 100644 index 0000000..57dc2fb --- /dev/null +++ b/contrib/ipfilter/lib/v6optvalue.c @@ -0,0 +1,39 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: v6optvalue.c,v 1.1 2003/04/26 04:55:58 darrenr Exp + */ +#include "ipf.h" + + + +u_32_t getv6optbyname(optname) +char *optname; +{ +#ifdef USE_INET6 + struct ipopt_names *io; + + for (io = v6ionames; io->on_name; io++) + if (!strcasecmp(optname, io->on_name)) + return io->on_bit; +#endif + return -1; +} + + +u_32_t getv6optbyvalue(optval) +int optval; +{ +#ifdef USE_INET6 + struct ipopt_names *io; + + for (io = v6ionames; io->on_name; io++) + if (io->on_value == optval) + return io->on_bit; +#endif + return -1; +} diff --git a/contrib/ipfilter/lib/var.c b/contrib/ipfilter/lib/var.c new file mode 100644 index 0000000..79b2517 --- /dev/null +++ b/contrib/ipfilter/lib/var.c @@ -0,0 +1,171 @@ +/* $NetBSD$ */ + +#include <ctype.h> + +#include "ipf.h" + +typedef struct variable { + struct variable *v_next; + char *v_name; + char *v_value; +} variable_t; + +static variable_t *vtop = NULL; + +static variable_t *find_var __P((char *)); +static char *expand_string __P((char *, int)); + + +static variable_t *find_var(name) +char *name; +{ + variable_t *v; + + for (v = vtop; v != NULL; v = v->v_next) + if (!strcmp(name, v->v_name)) + return v; + return NULL; +} + + +char *get_variable(string, after, line) +char *string, **after; +int line; +{ + char c, *s, *t, *value; + variable_t *v; + + s = string; + + if (*s == '{') { + s++; + for (t = s; *t != '\0'; t++) + if (*t == '}') + break; + if (*t == '\0') { + fprintf(stderr, "%d: { without }\n", line); + return NULL; + } + } else if (ISALPHA(*s)) { + for (t = s + 1; *t != '\0'; t++) + if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_')) + break; + } else { + fprintf(stderr, "%d: variables cannot start with '%c'\n", + line, *s); + return NULL; + } + + if (after != NULL) + *after = t; + c = *t; + *t = '\0'; + v = find_var(s); + *t = c; + if (v == NULL) { + fprintf(stderr, "%d: unknown variable '%s'\n", line, s); + return NULL; + } + + s = strdup(v->v_value); + value = expand_string(s, line); + if (value != s) + free(s); + return value; +} + + +static char *expand_string(oldstring, line) +char *oldstring; +int line; +{ + char c, *s, *p1, *p2, *p3, *newstring, *value; + int len; + + p3 = NULL; + newstring = oldstring; + + for (s = oldstring; *s != '\0'; s++) + if (*s == '$') { + *s = '\0'; + s++; + + switch (*s) + { + case '$' : + bcopy(s, s - 1, strlen(s)); + break; + default : + c = *s; + if (c == '\0') + return newstring; + + value = get_variable(s, &p3, line); + if (value == NULL) + return NULL; + + p2 = expand_string(value, line); + if (p2 == NULL) + return NULL; + + len = strlen(newstring) + strlen(p2); + if (p3 != NULL) { + if (c == '{' && *p3 == '}') + p3++; + len += strlen(p3); + } + p1 = malloc(len + 1); + if (p1 == NULL) + return NULL; + + *(s - 1) = '\0'; + strcpy(p1, newstring); + strcat(p1, p2); + if (p3 != NULL) + strcat(p1, p3); + + s = p1 + len - strlen(p3) - 1; + if (newstring != oldstring) + free(newstring); + newstring = p1; + break; + } + } + return newstring; +} + + +void set_variable(name, value) +char *name; +char *value; +{ + variable_t *v; + int len; + + if (name == NULL || value == NULL || *name == '\0') + return; + + v = find_var(name); + if (v != NULL) { + free(v->v_value); + v->v_value = strdup(value); + return; + } + + len = strlen(value); + + if ((*value == '"' && value[len - 1] == '"') || + (*value == '\'' && value[len - 1] == '\'')) { + value[len - 1] = '\0'; + value++; + len -=2; + } + + v = (variable_t *)malloc(sizeof(*v)); + if (v == NULL) + return; + v->v_name = strdup(name); + v->v_value = strdup(value); + v->v_next = vtop; + vtop = v; +} diff --git a/contrib/ipfilter/lib/verbose.c b/contrib/ipfilter/lib/verbose.c new file mode 100644 index 0000000..d4f3012 --- /dev/null +++ b/contrib/ipfilter/lib/verbose.c @@ -0,0 +1,37 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: verbose.c,v 1.6 2001/06/09 17:09:25 darrenr Exp + */ + +#if defined(__STDC__) +# include <stdarg.h> +#else +# include <varargs.h> +#endif +#include <stdio.h> + +#include "ipt.h" +#include "opts.h" + + +#if defined(__STDC__) +void verbose(char *fmt, ...) +#else +void verbose(fmt, va_alist) +char *fmt; +va_dcl +#endif +{ + va_list pvar; + + va_start(pvar, fmt); + + if (opts & OPT_VERBOSE) + vprintf(fmt, pvar); + va_end(pvar); +} diff --git a/contrib/ipfilter/man/Makefile b/contrib/ipfilter/man/Makefile index 05164d7..3f12ccb 100644 --- a/contrib/ipfilter/man/Makefile +++ b/contrib/ipfilter/man/Makefile @@ -1,9 +1,7 @@ # # Copyright (C) 1993-1998 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. +# See the IPFILTER.LICENCE file for details on licencing. # all: @@ -12,12 +10,19 @@ install: $(INSTALL) -m 0644 -c -o root -g bin ipftest.1 $(MANDIR)/man1 $(INSTALL) -m 0644 -c -o root -g bin ipnat.8 $(MANDIR)/man8 $(INSTALL) -m 0644 -c -o root -g bin ipf.4 $(MANDIR)/man4 + $(INSTALL) -m 0644 -c -o root -g bin ipfilter.4 $(MANDIR)/man4 $(INSTALL) -m 0644 -c -o root -g bin ipl.4 $(MANDIR)/man4 $(INSTALL) -m 0644 -c -o root -g bin ipnat.4 $(MANDIR)/man4 $(INSTALL) -m 0644 -c -o root -g bin ipf.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipfilter.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 ipmon.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ippool.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ippool.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipscan.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipscan.5 $(MANDIR)/man5 $(INSTALL) -m 0644 -c -o root -g bin ipfstat.8 $(MANDIR)/man8 @echo "Remember to rebuild the whatis database." diff --git a/contrib/ipfilter/man/ipf.4 b/contrib/ipfilter/man/ipf.4 index 7d6436a..7a0b20a 100644 --- a/contrib/ipfilter/man/ipf.4 +++ b/contrib/ipfilter/man/ipf.4 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPF 4 .SH NAME ipf \- packet filtering kernel interface @@ -35,8 +37,8 @@ However, the full complement is as follows: ioctl(fd, SIOCFRSYN, u_int *) ioctl(fd, SIOCFRZST, struct friostat **) ioctl(fd, SIOCZRLST, struct frentry **) - ioctl(fd, SIOCAUTHW, struct frauth_t **) - ioctl(fd, SIOCAUTHR, struct frauth_t **) + ioctl(fd, SIOCAUTHW, struct fr_info **) + ioctl(fd, SIOCAUTHR, struct fr_info **) ioctl(fd, SIOCATHST, struct fr_authstat **) .fi .PP @@ -122,7 +124,7 @@ Flags which are recognised in fr_flags: FR_RETRST 0x000080 /* return a TCP RST packet if blocked */ FR_RETICMP 0x000100 /* return an ICMP packet if blocked */ FR_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */ - FR_NOMATCH 0x000200 /* No match occurred */ + FR_NOMATCH 0x000200 /* no match occured */ FR_ACCOUNT 0x000400 /* count packet bytes */ FR_KEEPFRAG 0x000800 /* keep fragment information */ FR_KEEPSTATE 0x001000 /* keep `connection' state information */ diff --git a/contrib/ipfilter/man/ipf.5 b/contrib/ipfilter/man/ipf.5 index 835d775..ab7f935 100644 --- a/contrib/ipfilter/man/ipf.5 +++ b/contrib/ipfilter/man/ipf.5 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPF 5 .SH NAME ipf, ipf.conf, ipf6.conf \- IP packet filter rule syntax @@ -19,12 +21,13 @@ described using the following grammar in BNF: \fC .nf filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] - [ proto ] [ ip ] [ group ]. + [ proto ] ip [ group ]. insert = "@" decnumber . action = block | "pass" | log | "count" | skip | auth | call . in-out = "in" | "out" . -options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] ] . +options = [ log ] [ tag ] [ "quick" ] [ "on" interface-name [ dup ] + [ froute ] [ replyto ] ] . tos = "tos" decnumber | "tos" hexnumber . ttl = "ttl" decnumber . proto = "proto" protocol . @@ -32,19 +35,24 @@ ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . group = [ "head" decnumber ] [ "group" decnumber ] . block = "block" [ return-icmp[return-code] | "return-rst" ] . -auth = "auth" | "preauth" . log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . -call = "call" [ "now" ] function-name . +tag = "tag" tagid . skip = "skip" decnumber . -dup = "dup-to" interface-name[":"ipaddr] . -froute = "fastroute" | "to" interface-name[":"ipaddr] . +auth = "auth" | "preauth" . +call = "call" [ "now" ] function-name . +dup = "dup-to" interface-name [ ":" ipaddr ] . +froute = "fastroute" | "to" interface-name [ ":" ipaddr ] . +replyto = "reply-to" interface-name [ ":" ipaddr ] . protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . srcdst = "all" | fromto . fromto = "from" [ "!" ] object "to" [ "!" ] object . return-icmp = "return-icmp" | "return-icmp-as-dest" . +return-code = "(" icmp-code ")" . object = addr [ port-comp | port-range ] . addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +addr = "any" | "<thishost>" | nummask | + host-name [ "mask" ipaddr | "mask" hexnumber ] . port-comp = "port" compare port-num . port-range = "port" port-num range port-num . flags = "flags" flag { flag } [ "/" flag { flag } ] . @@ -205,6 +213,13 @@ indicates that, should this be the last matching rule, the packet header will be written to the \fBipl\fP log (as described in the LOGGING section below). .TP +.B tag tagid +indicates that, if this rule causes the packet to be logged or entered +in the state table, the tagid will be logged as part of the log entry. +This can be used to quickly match "similar" rules in scripts that post +process the log files for e.g. generation of security reports or accounting +purposes. The tagid is a 32 bit unsigned integer. +.TP .B quick allows "short-cut" rules in order to speed up the filter or override later rules. If a packet matches a filter rule which is marked as @@ -374,7 +389,7 @@ against, e.g.: # packets with ONLY the SYN flag set. ... flags SA - # becomes "flags SA/AUPRFSC" and will match any + # becomes "flags SA/AUPRFS" and will match any # packet with only the SYN and ACK flags set. ... flags S/SA diff --git a/contrib/ipfilter/man/ipf.8 b/contrib/ipfilter/man/ipf.8 index 60261d2..c7d07c0 100644 --- a/contrib/ipfilter/man/ipf.8 +++ b/contrib/ipfilter/man/ipf.8 @@ -1,14 +1,19 @@ +.\" $NetBSD$ +.\" .TH IPF 8 .SH NAME ipf \- alters packet filtering lists for IP packet input and output .SH SYNOPSIS .B ipf [ -.B \-6AdDEInoPrsUvVyzZ +.B \-6AcdDEInoPrsvVyzZ ] [ .B \-l <block|pass|nomatch> ] [ +.B \-T +<optionlist> +] [ .B \-F <i|o|a|s|S> ] @@ -36,6 +41,15 @@ This option is required to parse IPv6 rules and to have them loaded. .B \-A Set the list to make changes to the active list (default). .TP +.B \-c <language> +This option causes \fBipf\fP to generate output files for a compiler that +supports \fBlanguage\fI. At present, the only target language supported is +\fBC\fB (-cc) for which two files - \fBip_rules.c\fP +and \fBip_rules.h\fP are generated in the \fBCURRENT DIRECTORY\fP when +\fBipf\fP is being run. These files can be used with the +\fBIPFILTER_COMPILED\fP kernel option to build filter rules staticly into +the kernel. +.TP .B \-d Turn debug mode on. Causes a hexdump of filter rules to be generated as it processes each one. @@ -58,7 +72,7 @@ To flush entries from the state table, the \fB-F\fP option is used in conjunction with either "s" (removes state information about any non-fully established connections) or "S" (deletes the entire state table). Only one of the two options may be given. A fully established connection -will show up in \fBipfstat -s\fP output as 4/4, with deviations either +will show up in \fBipfstat -s\fP output as 5/5, with deviations either way indicating it is not fully established any more. .TP .BR \-f \0<filename> @@ -92,10 +106,22 @@ Remove matching filter rules rather than add them to the internal lists .TP .B \-s Swap the active filter list in use to be the "other" one. -.TP -.B \-U -(SOLARIS 2 ONLY) Block packets travelling along the data stream which aren't -recognised as IP packets. They will be printed out on the console. +.B \-T <optionlist> +This option allows run-time changing of IPFilter kernel variables. Some +variables require IPFilter to be in a disabled state (\fB-D\fP) for changing, +others do not. The optionlist parameter is a comma separated list of tuning +commands. A tuning command is either "list" (retrieve a list of all variables +in the kernel, their maximum, minimum and current value), a single variable +name (retrieve its current value) and a variable name with a following +assignment to set a new value. Some examples follow. +.nf +# Print out all IPFilter kernel tunable parameters +ipf -T list +# Display the current TCP idle timeout and then set it to 3600 +ipf -D -T fr_tcpidletimeout,fr_tcpidletimeout=3600 -E +# Display current values for fr_pass and fr_chksrc, then set fr_chksrc to 1. +ipf -T fr_pass,fr_chksrc,fr_chksrc=1 +.fi .TP .B \-v Turn verbose mode on. Displays information relating to rule processing. diff --git a/contrib/ipfilter/man/ipfilter.4 b/contrib/ipfilter/man/ipfilter.4 new file mode 100644 index 0000000..cf8ca9f --- /dev/null +++ b/contrib/ipfilter/man/ipfilter.4 @@ -0,0 +1,241 @@ +.\" $NetBSD$ +.\" +.TH IP\ FILTER 4 +.SH NAME +ipfilter \- Introduction to IP packet filtering +.SH DESCRIPTION +IP Filter is a TCP/IP packet filter, suitable for use in a firewall +environment. To use, it can either be used as a loadable kernel module or +incorporated into your UNIX kernel; use as a loadable kernel module where +possible is highly recommended. Scripts are provided to install and patch +system files, as required. +.SH FEATURES +The IP packet filter can: +.IP +explicitly deny/permit any packet from passing through +.IP +distinguish between various interfaces +.IP +filter by IP networks or hosts +.IP +selectively filter any IP protocol +.IP +selectively filter fragmented IP packets +.IP +selectively filter packets with IP options +.IP +send back an ICMP error/TCP reset for blocked packets +.IP +keep packet state information for TCP, UDP and ICMP packet flows +.IP +keep fragment state information for any IP packet, applying the same rule +to all fragments. +.IP +act as a Network Address Translator (NAT) +.IP +use redirection to setup true transparent proxy connections +.IP +provide packet header details to a user program for authentication +.IP +in addition, supports temporary storage of pre-authenticated rules for passing packets through +.PP +Special provision is made for the three most common Internet protocols, TCP, +UDP and ICMP. The IP Packet filter allows filtering of: +.IP +Inverted host/net matchingTCP/UDP packets by port number or a port number +range +.IP +ICMP packets by type/code +.IP +"established" TCP packets +.IP +On any arbitrary combination of TCP flags +.IP +"short" (fragmented) IP packets with incomplete headers can be filtered +.IP +any of the 19 IP options or 8 registered IP security classes TOS (Type of +Service) field in packets +.PP +To keep track of the performance of the IP packet filter, a logging device +is used which supports logging of: +.IP +the TCP/UDP/ICMP and IP packet headers +.IP +the first 128 bytes of the packet (including headers) +.PP +A packet can be logged when: +.IP +it is successfully passed through +.IP +it is blocked from passing through +.IP +it matches a rule setup to look for suspicious packets +.PP +IP Filter keeps its own set of statistics on: +.IP +packets blocked +.IP +packets (and bytes!) used for accounting +.IP +packets passed +.lP +packets logged +.IP +attempts to log which failed (buffer full) +.IP +and much more, for packets going both in and out. + +.SH Tools +The current implementation provides a small set of tools, which can easily +be used and integrated with regular unix shells and tools. A brief description +of the tools provided: +.PP +ipf(8) +reads in a set of rules, from either stdin or a file, and adds them to +the kernels current list (appending them). It can also be used to flush the +current filter set or delete individual filter rules. The file format is +described in ipf(5). +.PP +ipfs(8) +is a utility to temporarily lock the IP Filter kernel tables (state tables +and NAT mappings) and write them to disk. After that the system can be +rebooted, and ipfs can be used to read these tables from disk and restore +them into the kernel. This way the system can be rebooted without the +connections being terminated. +.PP +ipfstat(8) +interrogates the kernel for statistics on packet filtering, so +far, and retrieves the list of filters in operation for inbound and outbound +packets. +.PP +ipftest(1) +reads in a filter rule file and then applies sample IP packets to +the rule file. This allows for testing of filter list and examination of how +a packet is passed along through it. +.PP +ipmon(8) +reads buffered data from the logging device (default is /dev/ipl) +for output to either: +.IP +screen (standard output) +.IP +file +.IP +syslog +.PP +ipsend(1) +generates arbitary IP packets for ethernet connected machines. +.PP +ipresend(1) +reads in a data file of saved IP packets (ie +snoop/tcpdump/etherfind output) and sends it back across the network. +.PP +iptest(1) +contains a set of test "programs" which send out a series of IP +packets, aimed at testing the strength of the TCP/IP stack at which it is +aimed at. WARNING: this may crash machine(s) targeted! +.PP +ipnat(8) +reads in a set of rules, from either stdin or a file and adds them +to the kernels current list of active NAT rules. NAT rules can also be +deleted using ipnat. The format of the configuration file to be used +with ipnat is described in ipnat(5). +.PP +For use in your own programs (e.g. for writing of transparent application +proxies), the programming interface and the associated ioctl's are +documented in ipf(4). + +Documentation on ioctl's and the format of data saved +to the logging character device is provided in ipl(4) +so that you may develop your own applications to work with or in place of any +of the above. + +Similar, the interface to the NAT code is documented in ipnat(4). + +.SH PACKET PROCESSING FLOW +The following diagram illustrates the flow of TCP/IP packets through the +various stages introduced by IP Filter. +.PP +.nf + IN + | + V + +-------------------------+--------------------------+ + | | | + | V | + | Network Address Translation | + | | | + | authenticated | | + | +-------<---------+ | + | | | | + | | V | + | V IP Accounting | + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | V V V | + | | Packet State Check-->+ | + | | | | | + | | +->--+ | | | + | | | | V | | + | V groups IP Filtering V | + | | | | | | | + | | +--<-+ | | | + | | | | | + | +---------------->|<-----------+ | + | | | + | V | + | +---<----+ | + | | | | + | function | | + | | V | + | +--->----+ | + | | | + | V | + +--|---<--- fast-route ---<--+ | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + | | + | V + V [KERNEL TCP/IP Processing] + | | + | +-------------------------+--------------------------+ + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | | V V | + | | Packet State Check-->+ | + | | | | | + | | V | | + V | IP Filtering | | + | | | V | + | | |<-----------+ | + | | V | + | | IP Accounting | + | | | | + | | V | + | | Network Address Translation | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + V | + +--------------------------->| + V + OUT +.fi + +.SH MORE INFORMATION +More information (including pointers to the FAQ and the mailing list) can be +obtained from the sofware's official homepage: www.ipfilter.org + +.SH SEE ALSO +ipf(4), ipf(5), ipf(8), ipfilter(5), ipfs(8), ipfstat(8), ipftest(1), +ipl(4), ipmon(8), ipnat(8), ipnat(4), + diff --git a/contrib/ipfilter/man/ipfilter.4.mandoc b/contrib/ipfilter/man/ipfilter.4.mandoc new file mode 100644 index 0000000..72534a7 --- /dev/null +++ b/contrib/ipfilter/man/ipfilter.4.mandoc @@ -0,0 +1,267 @@ +.Dd December 8, 2000 +.Dt IP\ FILTER 4 +.Os +.Sh NAME +.Nm IP Filter +.Nd Introduction to IP packet filtering +.Sh DESCRIPTION +IP Filter is a TCP/IP packet filter, suitable for use in a firewall +environment. To use, it can either be used as a loadable kernel module or +incorporated into your UNIX kernel; use as a loadable kernel module where +possible is highly recommended. Scripts are provided to install and patch +system files, as required. +.Sh FEATURES +The IP packet filter can: +.Bl -bullet -offset indent -compact +.It +explicitly deny/permit any packet from passing through +.It +distinguish between various interfaces +.It +filter by IP networks or hosts +.It +selectively filter any IP protocol +.It +selectively filter fragmented IP packets +.It +selectively filter packets with IP options +.It +send back an ICMP error/TCP reset for blocked packets +.It +keep packet state information for TCP, UDP and ICMP packet flows +.It +keep fragment state information for any IP packet, applying the same rule +to all fragments. +.It +act as a Network Address Translator (NAT) +.It +use redirection to setup true transparent proxy connections +.It +provide packet header details to a user program for authentication +.It +in addition, supports temporary storage of pre-authenticated rules for passing packets through +.El +.Pp +Special provision is made for the three most common Internet protocols, TCP, +UDP and ICMP. The IP Packet filter allows filtering of: +.Bl -bullet -offset indent -compact +.It +Inverted host/net matchingTCP/UDP packets by port number or a port number +range +.It +ICMP packets by type/code +.It +"established" TCP packets +.It +On any arbitrary combination of TCP flags +.It +"short" (fragmented) IP packets with incomplete headers can be filtered +.It +any of the 19 IP options or 8 registered IP security classes TOS (Type of +Service) field in packets +.El +.Pp +To keep track of the performance of the IP packet filter, a logging device +is used which supports logging of: +.Bl -bullet -offset indent -compact +.It +the TCP/UDP/ICMP and IP packet headers +.It +the first 128 bytes of the packet (including headers) +.El +.Pp +A packet can be logged when: +.Bl -bullet -offset indent -compact +.It +it is successfully passed through +.It +it is blocked from passing through +.It +it matches a rule setup to look for suspicious packets +.El +.Pp +IP Filter keeps its own set of statistics on: +.Bl -bullet -offset indent -compact +.It +packets blocked +.It +packets (and bytes!) used for accounting +.It +packets passed +.li +packets logged +.It +attempts to log which failed (buffer full) +.El +and much more, for packets going both in and out. + +.Sh Tools +The current implementation provides a small set of tools, which can easily +be used and integrated with regular unix shells and tools. A brief description +of the tools provided: +.Pp +.Xr ipf 8 +reads in a set of rules, from either stdin or a file, and adds them to +the kernels current list (appending them). It can also be used to flush the +current filter set or delete individual filter rules. The file format is +described in +.Xr ipf 5 . +.Pp +.Xr ipfs 8 +is a utility to temporarily lock the IP Filter kernel tables (state tables +and NAT mappings) and write them to disk. After that the system can be +rebooted, and ipfs can be used to read these tables from disk and restore +them into the kernel. This way the system can be rebooted without the +connections being terminated. +.Pp +.Xr ipfstat 8 +interrogates the kernel for statistics on packet filtering, so +far, and retrieves the list of filters in operation for inbound and outbound +packets. +.Pp +.Xr ipftest 1 +reads in a filter rule file and then applies sample IP packets to +the rule file. This allows for testing of filter list and examination of how +a packet is passed along through it. +.Pp +.Xr ipmon 8 +reads buffered data from the logging device (default is /dev/ipl) +for output to either: +.Bl -bullet -offset indent -compact +.It +screen (standard output) +.It +file +.It +syslog +.El +.Pp +.Xr ipsend 1 +generates arbitary IP packets for ethernet connected machines. +.Pp +.Xr ipresend 1 +reads in a data file of saved IP packets (ie +snoop/tcpdump/etherfind output) and sends it back across the network. +.Pp +.Xr iptest 1 +contains a set of test "programs" which send out a series of IP +packets, aimed at testing the strength of the TCP/IP stack at which it is +aimed at. WARNING: this may crash machine(s) targeted! +.Pp +.Xr ipnat 8 +reads in a set of rules, from either stdin or a file and adds them +to the kernels current list of active NAT rules. NAT rules can also be +deleted using ipnat. The format of the configuration file to be used +with ipnat is described in +.Xr ipnat 5 . +.Pp +For use in your own programs (e.g. for writing of transparent application +proxies), the programming interface and the associated ioctl's are +documented in +.Xr ipf 4 . + +Documentation on ioctl's and the format of data saved +to the logging character device is provided in +.Xr ipl 4 +so that you may develop your own applications to work with or in place of any +of the above. + +Similar, the interface to the NAT code is documented in +.Xr ipnat 4 . + +.Sh PACKET PROCESSING FLOW +The following diagram illustrates the flow of TCP/IP packets through the +various stages introduced by IP Filter. +.Pp +.nf + IN + | + V + +-------------------------+--------------------------+ + | | | + | V | + | Network Address Translation | + | | | + | authenticated | | + | +-------<---------+ | + | | | | + | | V | + | V IP Accounting | + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | V V V | + | | Packet State Check-->+ | + | | | | | + | | +->--+ | | | + | | | | V | | + | V groups IP Filtering V | + | | | | | | | + | | +--<-+ | | | + | | | | | + | +---------------->|<-----------+ | + | | | + | V | + | +---<----+ | + | | | | + | function | | + | | V | + | +--->----+ | + | | | + | V | + +--|---<--- fast-route ---<--+ | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + | | + | V + V [KERNEL TCP/IP Processing] + | | + | +-------------------------+--------------------------+ + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | | V V | + | | Packet State Check-->+ | + | | | | | + | | V | | + V | IP Filtering | | + | | | V | + | | |<-----------+ | + | | V | + | | IP Accounting | + | | | | + | | V | + | | Network Address Translation | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + V | + +--------------------------->| + V + OUT +.fi + +.Sh MORE INFORMATION +More information (including pointers to the FAQ and the mailing list) can be +obtained from the sofware's official homepage: www.ipfilter.org + +.Sh SEE ALSO +.Xr ipf 4 , +.Xr ipf 5 , +.Xr ipf 8 , +.Xr ipfilter 5 , +.Xr ipfs 8 , +.Xr ipfstat 8 , +.Xr ipftest 1 , +.Xr ipl 4 , +.Xr ipmon 8 , +.Xr ipnat 4 , +.Xr ipnat 8 , + diff --git a/contrib/ipfilter/man/ipfilter.5 b/contrib/ipfilter/man/ipfilter.5 index 0bba0f4..9fbb675 100644 --- a/contrib/ipfilter/man/ipfilter.5 +++ b/contrib/ipfilter/man/ipfilter.5 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPFILTER 1 .SH NAME IP Filter diff --git a/contrib/ipfilter/man/ipfs.8 b/contrib/ipfilter/man/ipfs.8 index b07935a..52f6fcb 100644 --- a/contrib/ipfilter/man/ipfs.8 +++ b/contrib/ipfilter/man/ipfs.8 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPFS 8 .SH NAME ipfs \- saves and restores information for NAT and state tables. @@ -54,7 +56,7 @@ and options for saving state information. .TP .B \-n -Don't actually take any action that would effect information stored in +Don't actually take any action that would affect information stored in the kernel or on disk. .TP .B \-v @@ -90,17 +92,17 @@ and does not change the lock once complete. .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 +directory unless otherwise specified by the .B \-d -option is used. The state tables are locked at the beginning of this +option. 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 +directory unless otherwise specified by the .B \-d -option is used. The state tables are locked at the beginning of this +option. The state tables are locked at the beginning of this operation and unlocked once complete. .DT .SH FILES diff --git a/contrib/ipfilter/man/ipfstat.8 b/contrib/ipfilter/man/ipfstat.8 index c506a15..549b31a 100644 --- a/contrib/ipfilter/man/ipfstat.8 +++ b/contrib/ipfilter/man/ipfstat.8 @@ -1,18 +1,17 @@ +.\" $NetBSD$ +.\" .TH ipfstat 8 .SH NAME ipfstat \- reports on packet filter statistics and filter list .SH SYNOPSIS .B ipfstat [ -.B \-6aAfghIinosv -] [ -.B \-d -<device> +.B \-6aAdfghIilnoRsv ] - +.br .B ipfstat -t [ -.B \-C +.B \-6C ] [ .B \-D <addrport> @@ -25,12 +24,8 @@ ipfstat \- reports on packet filter statistics and filter list ] [ .B \-T <refresh time> -] [ -.B \-d -<device> ] .SH DESCRIPTION -.PP \fBipfstat\fP examines /dev/kmem using the symbols \fB_fr_flags\fP, \fB_frstats\fP, \fB_filterin\fP, and \fB_filterout\fP. To run and work, it needs to be able to read both /dev/kmem and the @@ -42,7 +37,7 @@ accumulated over time as the kernel has put packets through the filter. .SH OPTIONS .TP .B \-6 -Display filter lists for IPv6, if available. +Display filter lists and states for IPv6, if available. .TP .B \-a Display the accounting filter list and show bytes counted against each rule. @@ -56,13 +51,13 @@ Display "closed" states as well in the top. Normally, a TCP connection is not displayed when it reaches the CLOSE_WAIT protocol state. With this option enabled, all state entries are displayed. .TP -.BR \-d \0<device> -Use a device other than \fB/dev/ipl\fP for interfacing with the kernel. +.BR \-d +Produce debugging output when displaying data. .TP .BR \-D \0<addrport> This option is only valid in combination with \fB\-t\fP. Limit the state top display to show only state entries whose destination IP address and port -match the addport argument. The addrport specification is of the form +match the addrport argument. The addrport specification is of the form ipaddress[,port]. The ipaddress and port should be either numerical or the string "any" (specifying any IP address resp. any port). If the \fB\-D\fP option is not specified, it defaults to "\fB\-D\fP any,any". @@ -98,6 +93,10 @@ argument can be a protocol name (as defined in \fB/etc/protocols\fP) or a protocol number. If this option is not specified, state entries for any protocol are specified. .TP +.BR \-R +Don't try to resolve addresses to hostnames and ports to services while +printing statistics. +.TP .B \-s Show packet/flow state information (statistics only). .TP @@ -107,15 +106,15 @@ Show held state information (in the kernel) if any is present (no statistics). .BR \-S \0<addrport> This option is only valid in combination with \fB\-t\fP. Limit the state top display to show only state entries whose source IP address and port match -the addport argument. The addrport specification is of the form +the addrport argument. The addrport specification is of the form ipaddress[,port]. The ipaddress and port should be either numerical or the -string "any" (specifying any ip address resp. any port). If the \fB\-S\fP +string "any" (specifying any IP address resp. any port). If the \fB\-S\fP option is not specified, it defaults to "\fB\-S\fP any,any". .TP .B \-t -Show the state table in a way similar to they way \fBtop(1)\fP shows the process -table. States can be sorted using a number of different ways. This options -requires \fBncurses(3)\fP and needs to be compiled in. It may not be available on +Show the state table in a way similar to the way \fBtop(1)\fP shows the process +table. States can be sorted using a number of different ways. This option +requires \fBcurses(3)\fP and needs to be compiled in. It may not be available on all operating systems. See below, for more information on the keys that can be used while ipfstat is in top mode. .TP @@ -136,6 +135,10 @@ parameters are present. When supplied with either \fB\-i\fP or \fB\-o\fP, it will retrieve and display the appropriate list of filter rules currently installed and in use by the kernel. +.PP +One of the statistics that \fBipfstat\fP shows is \fBticks\fP. +This number indicates how long the filter has been enabled. +The number is incremented every half\-second. .SH STATE TOP Using the \fB\-t\fP option \fBipfstat\fP will enter the state top mode. In this mode the state table is displayed similar to the way \fBtop\fP displays @@ -146,7 +149,9 @@ shown and to specify the frequency of display updates. In state top mode, the following keys can be used to influence the displayed information: .TP -\fBd\fP select information to display. +\fBb\fP show packets/bytes from backward direction. +.TP +\fBf\fP show packets/bytes from forward direction. (default) .TP \fBl\fP redraw the screen. .TP @@ -166,13 +171,12 @@ and protocol filters or the refresh frequency. This must be done from the command line. .PP The screen must have at least 80 columns. This is however not checked. +When running state top in IPv6 mode, the screen must be much wider to display +the very long IPv6 addresses. .PP Only the first X-5 entries that match the sort and filter criteria are -displayed (where X is the number of rows on the display. There is no way to -see more entries. -.PP -No support for IPv6 -.PP +displayed (where X is the number of rows on the display. The only way to see +more entries is to resize the screen. .SH FILES /dev/kmem .br diff --git a/contrib/ipfilter/man/ipftest.1 b/contrib/ipfilter/man/ipftest.1 index bbfbc0c..4a17576 100644 --- a/contrib/ipfilter/man/ipftest.1 +++ b/contrib/ipfilter/man/ipftest.1 @@ -1,22 +1,36 @@ +.\" $NetBSD$ +.\" .TH ipftest 1 .SH NAME ipftest \- test packet filter rules with arbitrary input. .SH SYNOPSIS .B ipftest [ -.B \-vbdPRSTEHX +.B \-6bdDoRvx +] [ +.B \-F +input-format +] [ +.B \-i +<filename> ] [ .B \-I interface -] -.B \-r +] [ +.B \-l <filename> -[ -.B \-i +] [ +.B \-N <filename> ] [ -.B \-s -<ipaddress> +.B \-P +<filename> +] [ +.B \-r +<filename> +] [ +.B \-T +<optionlist> ] .SH DESCRIPTION .PP @@ -25,70 +39,69 @@ filter rules without having to put them in place, in operation and proceed to test their effectiveness. The hope is that this minimises disruptions in providing a secure IP environment. .PP -\fBipftest\fP will parse any standard ruleset for use with \fBipf\fP +\fBipftest\fP will parse any standard ruleset for use with \fBipf\fP, +\fBipnat\fP and/or \fBippool\fP and apply input, returning output as to the result. However, \fBipftest\fP will return one of three values for packets passed through the filter: pass, block or nomatch. This is intended to give the operator a better idea of what is happening with packets passing through their filter ruleset. .PP -When used without either of \fB\-S\fP, \fB\-T\fP or \fB\-E\fP, -\fBipftest\fP uses its own text input format to generate "fake" IP packets. -The format used is as follows: -.nf - "in"|"out" "on" if ["tcp"|"udp"|"icmp"] - srchost[,srcport] dsthost[,destport] [FSRPAU] -.fi -.PP -This allows for a packet going "in" or "out" of an interface (if) to be -generated, being one of the three main protocols (optionally), and if -either TCP or UDP, a port parameter is also expected. If TCP is selected, -it is possible to (optionally) supply TCP flags at the end. Some examples -are: -.nf - # a UDP packet coming in on le0 - in on le0 udp 10.1.1.1,2210 10.2.1.5,23 - # an IP packet coming in on le0 from localhost - hmm :) - in on le0 localhost 10.4.12.1 - # a TCP packet going out of le0 with the SYN flag set. - out on le0 tcp 10.4.12.1,2245 10.1.1.1,23 S -.fi +At least one of \fB\-N\fP, \fB-P\fP or \fB\-r\fP must be specified. .SH OPTIONS .TP -.B \-v -Verbose mode. This provides more information about which parts of rule -matching the input packet passes and fails. -.TP -.B \-d -Turn on filter rule debugging. Currently, this only shows you what caused -the rule to not match in the IP header checking (addresses/netmasks, etc). +.B \-6 +Use IPv6. .TP .B \-b Cause the output to be a brief summary (one-word) of the result of passing the packet through the filter; either "pass", "block" or "nomatch". This is used in the regression testing. .TP -.BR \-I \0<interface> -Set the interface name (used in rule matching) to be the name supplied. -This is useful with the \fB\-P, \-S, \-T\fP and \fB\-E\fP options, where it is -not otherwise possible to associate a packet with an interface. Normal -"text packets" can override this setting. +.B \-d +Turn on filter rule debugging. Currently, this only shows you what caused +the rule to not match in the IP header checking (addresses/netmasks, etc). .TP -.B \-P +.B \-D +Dump internal tables before exiting. +This excludes log messages. +.TP +.B \-F +This option is used to select which input format the input file is in. +The following formats are available: etherfind, hex, pcap, snoop, tcpdump,text. +.RS +.TP +.B etherfind +The input file is to be text output from etherfind. The text formats which +are currently supported are those which result from the following etherfind +option combinations: +.PP +.nf + etherfind -n + etherfind -n -t +.fi +.TP +.B hex +The input file is to be hex digits, representing the binary makeup of the +packet. No length correction is made, if an incorrect length is put in +the IP header. A packet may be broken up over several lines of hex digits, +a blank line indicating the end of the packet. It is possible to specify +both the interface name and direction of the packet (for filtering purposes) +at the start of the line using this format: [direction,interface] To define +a packet going in on le0, we would use \fB[in,le0]\fP - the []'s are required +and part of the input syntax. +.HP +.B pcap The input file specified by \fB\-i\fP is a binary file produced using libpcap (i.e., tcpdump version 3). Packets are read from this file as being input (for rule purposes). An interface maybe specified using \fB\-I\fP. .TP -.B \-R -Remove rules rather than load them. This is not a toggle option, so once -set, it cannot be reset by further use of -R. -.TP -.B \-S +.B snoop The input file is to be in "snoop" format (see RFC 1761). Packets are read from this file and used as input from any interface. This is perhaps the most useful input type, currently. .TP -.B \-T +.B tcpdump The input file is to be text output from tcpdump. The text formats which are currently supported are those which result from the following tcpdump option combinations: @@ -100,42 +113,77 @@ option combinations: tcpdump -nqtt tcpdump -nqte .fi -.LP .TP -.B \-H -The input file is to be hex digits, representing the binary makeup of the -packet. No length correction is made, if an incorrect length is put in -the IP header. A packet may be broken up over several lines of hex digits, -a blank line indicating the end of the packet. It is possible to specify -both the interface name and direction of the packet (for filtering purposes) -at the start of the line using this format: [direction,interface] To define -a packet going in on le0, we would use \fB[in,le0]\fP - the []'s are required -and part of the input syntax. -.TP -.B \-X -The input file is composed of text descriptions of IP packets. -.TP -.B \-E -The input file is to be text output from etherfind. The text formats which -are currently supported are those which result from the following etherfind -option combinations: +.B text +The input file is in \fBipftest\fP text input format. +This is the default if no \fB\-F\fP argument is specified. +The format used is as follows: +.nf + "in"|"out" "on" if ["tcp"|"udp"|"icmp"] + srchost[,srcport] dsthost[,destport] [FSRPAU] +.fi .PP +This allows for a packet going "in" or "out" of an interface (if) to be +generated, being one of the three main protocols (optionally), and if +either TCP or UDP, a port parameter is also expected. If TCP is selected, +it is possible to (optionally) supply TCP flags at the end. Some examples +are: .nf - etherfind -n - etherfind -n -t + # a UDP packet coming in on le0 + in on le0 udp 10.1.1.1,2210 10.2.1.5,23 + # an IP packet coming in on le0 from localhost - hmm :) + in on le0 localhost 10.4.12.1 + # a TCP packet going out of le0 with the SYN flag set. + out on le0 tcp 10.4.12.1,2245 10.1.1.1,23 S .fi .LP +.RE +.DT .TP .BR \-i \0<filename> Specify the filename from which to take input. Default is stdin. .TP +.BR \-I \0<interface> +Set the interface name (used in rule matching) to be the name supplied. +This is useful where it is +not otherwise possible to associate a packet with an interface. Normal +"text packets" can override this setting. +.TP +.BR \-l \0<filename> +Dump log messages generated during testing to the specified file. +.TP +.BR \-N \0<filename> +Specify the filename from which to read NAT rules in \fBipnat\fP(5) format. +.TP +.B \-o +Save output packets that would have been written to each interface in +a file /tmp/\fIinterface_name\fP in raw format. +.TP +.BR \-P \0<filename> +Read IP pool configuration information in \fBippool\fP(5) format from the +specified file. +.TP .BR \-r \0<filename> -Specify the filename from which to read filter rules. +Specify the filename from which to read filter rules in \fBipf\fP(5) format. +.TP +.B \-R +Don't attempt to convert IP addresses to hostnames. +.TP +.BR \-T \0<optionlist> +This option simulates the run-time changing of IPFilter kernel variables +available with the \fB\-T\fP option of \fBipf\fP. +The optionlist parameter is a comma separated list of tuning +commands. A tuning command is either "list" (retrieve a list of all variables +in the kernel, their maximum, minimum and current value), a single variable +name (retrieve its current value) and a variable name with a following +assignment to set a new value. See \fBipf\fP(8) for examples. +.TP +.B \-v +Verbose mode. This provides more information about which parts of rule +matching the input packet passes and fails. .TP -.BR \-s \0<ipaddress> -Where the input format is incapable of telling \fBipftest\fP whther a packet is -going in or out, setting this option to an IP address results in the direction -being set to out if the source matches or in if the destination matches. +.B \-x +Print a hex dump of each packet before printing the decoded contents. .SH SEE ALSO ipf(5), ipf(8), snoop(1m), tcpdump(8), etherfind(8c) .SH BUGS diff --git a/contrib/ipfilter/man/ipl.4 b/contrib/ipfilter/man/ipl.4 index 0368f03..d45749b 100644 --- a/contrib/ipfilter/man/ipl.4 +++ b/contrib/ipfilter/man/ipl.4 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPL 4 .SH NAME ipl \- IP packet log device @@ -50,7 +52,7 @@ a buffer big enough to hold at least 1 complete log record - reading of partial log records is not supported. .PP If the packet contents are more than 128 bytes when \fBlog body\fP is used, -then only 128 bytes of the packet contents is logged. +then only 128 bytes of the packet contents are logged. .PP Although it is only possible to read from the \fBipl\fP device, opening it for writing is required when using an ioctl which changes any kernel data. @@ -76,4 +78,4 @@ ipf(4) .SH BUGS Packet headers are dropped when the internal buffer (static size) fills. .SH FILES -/dev/ipl +/dev/ipl0 diff --git a/contrib/ipfilter/man/ipmon.5 b/contrib/ipfilter/man/ipmon.5 new file mode 100644 index 0000000..bc48466 --- /dev/null +++ b/contrib/ipfilter/man/ipmon.5 @@ -0,0 +1,69 @@ +.\" $NetBSD$ +.\" +.TH IPMON 5 +.SH NAME +ipmon, ipmon.conf \- ipmon configuration file format +.SH DESCRIPTION +The format for files accepted by ipmon is described by the following grammar: +.LP +.nf +"match" "{" matchlist "}" "do" "{" doing "}" ";" + +matchlist ::= matching [ "," matching ] . +matching ::= direction | dstip | dstport | every | group | interface | + logtag | nattag | protocol | result | rule | srcip | srcport . + +dolist ::= doing [ "," doing ] . +doing ::= execute | save | syslog . + +direction ::= "in" | "out" . +dstip ::= "dstip" "=" ipv4 "/" number . +dstport ::= "dstport" "=" number . +every ::= "every" every-options . +execute ::= "execute" "=" string . +group ::= "group" "=" string | "group" "=" number . +interface ::= "interface" "=" string . +logtag ::= "logtag" "=" string | "logtag" "=" number . +nattag ::= "nattag" "=" string . +protocol ::= "protocol" "=" string | "protocol" "=" number . +result ::= "result" "=" result-option . +rule ::= "rule" "=" number . +srcip ::= "srcip" "=" ipv4 "/" number . +srcport ::= "srcport" "=" number . +type ::= "type" "=" ipftype . +ipv4 ::= number "." number "." number "." number . + +every-options ::= "second" | number "seconds" | "packet" | number "packets" . +result-option ::= "pass" | "block" | "short" | "nomatch" | "log" . +ipftype ::= "ipf" | "nat" | "state" . + +.fi +.PP +In addition, lines that start with a # are considered to be comments. +.TP +.SH OVERVIEW +.PP +The ipmon configuration file is used for defining rules to be executed when +logging records are read from +.B /dev/ipl. +.PP +At present, only IPv4 matching is available for source/destination address +matching. +.SH MATCHING +.PP +Each rule for ipmon consists of two primary segments: the first describes how +the log record is to be matched, the second defines what action to take if +there is a positive match. All entries of the rules present in the file are +compared for matches - there is no first or last rule match. +.SH FILES +/dev/ipl +.br +/dev/ipf +.br +/dev/ipnat +.br +/dev/ipstate +.br +/etc/ipmon.conf +.SH SEE ALSO +ipmon(8), ipl(4) diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8 index 2827797..0c2861c 100644 --- a/contrib/ipfilter/man/ipmon.8 +++ b/contrib/ipfilter/man/ipmon.8 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH ipmon 8 .SH NAME ipmon \- monitors /dev/ipl for logged packets @@ -46,11 +48,8 @@ long). 4. The group and rule number of the rule, e.g., \fB@0:17\fP. These can be viewed with \fBipfstat -n\fP. .LP -5. The action: \fBp\fP for passed, \fBb\fP for blocked, \fBS\fP for a short -packet, \fBn\fP did not match any rules, \fBL\fP for a log rule. The order -of precedence in showing flags is: S, p, b, n, L. A capital \fBP\fP or -\fBB\fP means that the packet has been logged due to a global logging -setting, not a particular rule. +5. The action: \fBp\fP for passed, \fBb\fP for blocked, \fB\fP for a short +packet, \fBn\fP did not match any rules or \fBL\fP for a log rule. .LP 6. The addresses. This is actually three fields: the source address and port diff --git a/contrib/ipfilter/man/ipnat.4 b/contrib/ipfilter/man/ipnat.4 index 54f55d3..6f696bd 100644 --- a/contrib/ipfilter/man/ipnat.4 +++ b/contrib/ipfilter/man/ipnat.4 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPNAT 4 .SH NAME ipnat \- Network Address Translation kernel interface diff --git a/contrib/ipfilter/man/ipnat.5 b/contrib/ipfilter/man/ipnat.5 index 2bedd0c..7db3308 100644 --- a/contrib/ipfilter/man/ipnat.5 +++ b/contrib/ipfilter/man/ipnat.5 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH IPNAT 5 .SH NAME ipnat, ipnat.conf \- IP NAT file format @@ -7,45 +9,47 @@ The format for files accepted by ipnat is described by the following grammar: .nf ipmap :: = mapblock | redir | map . -map ::= mapit ifname ipmask "->" dstipmask [ mapport ] mapoptions. -map ::= mapit ifname fromto "->" dstipmask [ mapport ] mapoptions. -mapblock ::= "map-block" ifname ipmask "->" ipmask [ ports ] mapoptions. +map ::= mapit ifname lhs "->" dstipmask [ mapicmp | mapport | mapproxy ] + mapoptions . +mapblock ::= "map-block" ifname lhs "->" ipmask [ ports ] mapoptions . redir ::= "rdr" ifname ipmask dport "->" ip [ "," ip ] rdrport rdroptions . -dport ::= "port" number [ "-" number ] . -ports ::= "ports" number | "auto" . -rdrport ::= "port" number . +lhs ::= ipmask | fromto . +dport ::= "port" portnum [ "-" portnum ] . +ports ::= "ports" numports | "auto" . +rdrport ::= "port" portnum . mapit ::= "map" | "bimap" . fromto ::= "from" object "to" object . ipmask ::= ip "/" bits | ip "/" mask | ip "netmask" mask . dstipmask ::= ipmask | "range" ip "-" ip . +mapicmp ::= "icmpidmap" "icmp" number ":" number . mapport ::= "portmap" tcpudp portspec . mapoptions ::= [ tcpudp ] [ "frag" ] [ age ] [ clamp ] . -rdroptions ::= [ tcpudp | protocol ] [ rr ] [ "frag" ] [ age ] [ clamp ] . +rdroptions ::= rdrproto [ rr ] [ "frag" ] [ age ] [ clamp ] [ rdrproxy ] . -object :: = addr [ port-comp | port-range ] . -addr :: = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +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 . +rdrproto ::= tcpudp | protocol . rr ::= "round-robin" . age ::= "age" decnumber [ "/" decnumber ] . clamp ::= "mssclamp" decnumber . -tcpudp ::= "tcp/udp" | "tcp" | "udp" . +tcpudp ::= "tcp/udp" | protocol . +mapproxy ::= "proxy" "port" port proxy-name '/' protocol +rdrproxy ::= "proxy" proxy-name . protocol ::= protocol-name | decnumber . -nummask ::= host-name [ "/" number ] . -portspec ::= "auto" | number ":" number . +nummask ::= host-name [ "/" decnumber ] . +portspec ::= "auto" | portnumber ":" portnumber . +port ::= portnumber | port-name . +portnumber ::= number { numbers } . ifname ::= 'A' - 'Z' { 'A' - 'Z' } numbers . -number ::= numbers [ number ] . numbers ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' . .fi .PP -In addition to this, # is used to mark the start of a comment and may -appear at the end of a line with a NAT rule (as described above) or on its -own lines. Blank lines are ignored. -.PP For standard NAT functionality, a rule should start with \fBmap\fP and then proceeds to specify the interface for which outgoing packets will have their source address rewritten. @@ -101,41 +105,12 @@ or as map de0 from 10.1.0.0/16 to any -> 201.2.3.4/32 .fi .LP -For even greater control, one may negate either of the "from" or "to" clauses -with a preceding exclamation mark ("!"). Please note that one may not use a -negated "from" within a \fBmap\fP rule or a negated "to" within a \fBrdr\fP -rule. Such a rule might look like the following: -.LP -.nf -+map de0 from 10.1.0.0/16 ! to 10.1.0.0/16 -> 201.2.3.4/32 -.fi -.PP Only IP address and port numbers can be compared against. This is available with all NAT rules. -.SH COMMAND QUALIFIERS -At the end of each rule, a number of qualifiers can be used to change how -the rule works. They are as follows: -.TP -protocol -A specific protocol may be given either by its name (as found in -/etc/protocols) or its number. A special case for supporting both -TCP and UDP is allowed with the name \fBtcp/udp\fP. -.TP -.B round-robin -Once a rule with this term has been successfully used, it is put at the -bottom of the list of those available so that each one will get used, in -turn, in a list of matching left hand sides. -.TP -.B frag -This qualifier is currently has no impact on NAT operation. -.TP -.B age -If more refined timeouts are required than those available globally for -NAT settings, this allows you to set them for \fBnon-TCP\fP use. .SH TRANSLATION .PP To the right of the "->" is the address and port specification which will be -written into the packet providing it has already successful matched the +written into the packet providing it has already successfully matched the prior constraints. The case of redirections (\fBrdr\fP) is the simplest: the new destination address is that specified in the rule. For \fBmap\fP rules, the destination address will be one for which the tuple combining @@ -149,13 +124,76 @@ the packet will not be translated. The \fBmap-block\fP is more limited in how it searches for a new, free and unique tuple, in that it will used an algorithm to determine what the new source address should be, along with the range of available ports - the IP address is never changed and nor does the -port number ever exceed its alloted range. +port number ever exceed its allotted range. +.SH ICMPIDMAP +.PP +ICMP messages can be divided into two groups: "errors" and "queries". ICMP +errors are generated as a response of another IP packet. IP Filter will take +care that ICMP errors that are the response of a NAT-ed IP packet are +handled properly. +.PP +For 4 types of ICMP queries (echo request, timestamp request, information +request and address mask request) IP Filter supports an additional mapping +called "ICMP id mapping". All these 4 types of ICMP queries use a unique +identifier called the ICMP id. This id is set by the process sending the +ICMP query and it is usually equal to the process id. The receiver of the +ICMP query will use the same id in its response, thus enabling the +sender to recognize that the incoming ICMP reply is intended for him and is +an answer to a query that he made. The "ICMP id mapping" feature modifies +these ICMP id in a way identical to \fBportmap\fP for TCP or UDP. +.PP +The reason that you might want this, is that using this feature you don't +need an IP address per host behind the NAT box, that wants to do ICMP queries. +The two numbers behind the \fBicmpidmap\fP keyword are the first and the +last icmp id number that can be used. There is one important caveat: if you +map to an IP address that belongs to the NAT box itself (notably if you have +only a single public IP address), then you must ensure that the NAT box does +not use the \fBicmpidmap\fP range that you specified in the \fBmap\fP rule. +Since the ICMP id is usually the process id, it is wise to restrict the +largest permittable process id (PID) on your operating system to e.g. 63999 and +use the range 64000:65535 for ICMP id mapping. Changing the maximal PID is +system dependent. For most BSD derived systems can be done by changing +PID_MAX in /usr/include/sys/proc.h and then rebuild the system. .SH KERNEL PROXIES .PP IP Filter comes with a few, simple, proxies built into the code that is loaded into the kernel to allow secondary channels to be opened without forcing the -packets through a user program. -.SH TRNSPARENT PROXIES +packets through a user program. The current state of the proxies is listed +below, as one of three states: +.HP +Aging - protocol is roughly understood from +the time at which the proxy was written but it is not well tested or +maintained; +.HP +Developmental - basic functionality exists, works most of the time but +may be problematic in extended real use; +.HP +Experimental - rough support for the protocol at best, may or may not +work as testing has been at best sporadic, possible large scale changes +to the code in order to properly support the protocol. +.HP +Mature - well tested, protocol is properly +understood by the proxy; +.PP +The currently compiled in proxy list is as follows: +.HP +FTP - Mature +.HP +IRC - Experimental +.HP +rpcbind - Experimental +.HP +H.323 - Experimental +.HP +Real Audio (PNA) - Aging +.HP +IPsec - Developmental +.HP +netbios - Experimental +.HP +R-command - Mature + +.SH TRANSPARENT PROXIES .PP 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 @@ -226,7 +264,13 @@ map ppp0 172.192.0.0/16 -> 209.1.2.0/24 portmap tcp/udp auto .fi .PP which would result in each IP address being given a small range of ports to -use (252). The problem here is that the \fBmap\fP directive tells the NAT +use (252). In all cases, the new port number that is used is deterministic. +That is, port X will always map to port Y. +WARNING: It is not advisable to use the \fBauto\fP feature if you are map'ing +to a /32 (i.e. 0/32) because the NAT code will try to map multiple hosts to +the same port number, outgoing and ultimately this will only succeed for one +of them. +The problem here is that the \fBmap\fP directive tells the NAT code to use the next address/port pair available for an outgoing connection, resulting in no easily discernible relation between external addresses/ports and internal ones. This is overcome by using \fBmap-block\fP as follows: @@ -241,7 +285,6 @@ own. As opposed to the above use of \fBmap\fP, if for some reason the user of (say) 172.192.0.2 wanted 260 simultaneous connections going out, they would be limited to 252 with \fBmap-block\fP but would just \fImove on\fP to the next IP address with the \fBmap\fP command. -.SH FILES /dev/ipnat .br /etc/services diff --git a/contrib/ipfilter/man/ipnat.8 b/contrib/ipfilter/man/ipnat.8 index 3b365ed..49a09be 100644 --- a/contrib/ipfilter/man/ipnat.8 +++ b/contrib/ipfilter/man/ipnat.8 @@ -1,10 +1,18 @@ +.\" $NetBSD$ +.\" .TH IPNAT 8 .SH NAME -ipnat \- user interface to the NAT +ipnat \- user interface to the NAT subsystem .SH SYNOPSIS .B ipnat [ -.B \-lnrsvCF +.B \-dhlnrsvCF +] +[ +.B \-M core +] +[ +.B \-N system ] .B \-f <\fIfilename\fP> .SH DESCRIPTION @@ -16,33 +24,48 @@ Each rule processed by \fBipnat\fP is added to the kernels internal lists if there are no parsing problems. Rules are added to the end of the internal lists, matching the order in which they appear when given to \fBipnat\fP. +.PP +Note that if +\fBipf(8)\fP +is not enabled when NAT is configured, it will be enabled +automatically, as the same kernel facilities are used for +NAT functionality. In addition, packet forwarding must be +enabled. .SH OPTIONS .TP .B \-C delete all entries in the current NAT rule listing (NAT rules) + .TP +.B \-d +Enable printing of some extra debugging information. .TP .B \-F delete all active entries in the current NAT translation table (currently active NAT mappings) .TP +.B \-h +Print number of hits for each MAP/Redirect filter. +.TP .B \-l Show the list of current NAT table entry mappings. .TP .B \-n -This flag (no-change) prevents \fBipnat\fP from actually making any ioctl +This flag (no-change) prevents \fBipf\fP from actually making any ioctl calls or doing anything which would alter the currently running kernel. .TP -.B \-s -Retrieve and display NAT statistics -.TP .B \-r Remove matching NAT rules rather than add them to the internal lists .TP +.B \-s +Retrieve and display NAT statistics +.TP .B \-v Turn verbose mode on. Displays information relating to rule processing and active rules/table entries. .DT .SH FILES /dev/ipnat +.br +/usr/share/examples/ipf Directory with examples. .SH SEE ALSO ipnat(5), ipf(8), ipfstat(8) diff --git a/contrib/ipfilter/man/ippool.5 b/contrib/ipfilter/man/ippool.5 new file mode 100644 index 0000000..c9eaaca --- /dev/null +++ b/contrib/ipfilter/man/ippool.5 @@ -0,0 +1,155 @@ +.\" $NetBSD$ +.\" +.TH IPPOOL 5 +.SH NAME +ippool, ippool.conf \- IP Pool file format +.SH DESCRIPTION +The format for files accepted by ippool is described by the following grammar: +.LP +.nf +line ::= table | groupmap . +table ::= "table" role tabletype . +groupmap ::= "group-map" inout role number ipfgroup +tabletype ::= ipftree | ipfhash . + +role ::= "role" "=" "ipf" . +inout ::= "in" | "out" . + +ipftree ::= "type" "=" "tree" number "{" addrlist "}" . +ipfhash ::= "type" "=" "hash" number hashopts "{" hashlist "}" . + +ipfgroup ::= setgroup hashopts "{" grouplist "}" | + hashopts "{" setgrouplist "}" . +setgroup ::= "group" "=" groupname . + +hashopts ::= size [ seed ] | seed . + +size ::= "size" number . +seed ::= "seed" number . + +addrlist ::= [ "!" ] addrmask ";" [ addrlist ] . +grouplist ::= groupentry ";" [ grouplist ] | addrmask ";" [ grouplist ] . + +setgrouplist ::= groupentry ";" [ setgrouplist ] . + +groupentry ::= addrmask "," setgroup . + +hashlist ::= hashentry ";" [ hashlist ] . +hashentry ::= addrmask . + +addrmask ::= ipaddr | ipaddr "/" mask . + +mask ::= number | ipaddr . + +groupname ::= number | name . + +number ::= digit { digit } . + +ipaddr = host-num "." host-num "." host-num "." host-num . +host-num = digit [ digit [ digit ] ] . + +digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . +name ::= letter { letter | digit } . +.fi +.PP +The IP pool configuration file is used for defining a single object that +contains a reference to multiple IP address/netmask pairs. A pool may consist +of a mixture of netmask sizes, from 0 to 32. +.PP +At this point in time, only IPv4 addressing is supported. +.TP +.SH OVERVIEW +.PP +The IP pool configuration file provides for defining two different mechanisms +for improving speed in matching IP addresses with rules. +The first, +.B table +, defines a lookup +.I table +to provide a single reference in a +filter rule to multiple targets and the second, +.B group-map +, provides a mechanism to target multiple groups from a single filter line. +.PP +The +.B group-map +command can only be used with filter rules that use the +.B call +command to invoke either +.B fr_srcgrpmap +or +.B fr_dstgrpmap +, to use the source or destination address, +respectively, for determining which filter group to jump to next for +continuation of filter packet processing. +.SH POOL TYPES +.PP +Two storage formats are provided: hash tables and tree structure. The hash +table is intended for use with objects all containing the same netmask or a +few different sized netmasks of non-overlapping address space and the tree +is designed for being able to support exceptions to a covering mask, in +addition to normal searching as you would do with a table. It is not possible +to use the tree data storage type with +.B group-map +configuration entries. +.SH POOL ROLES +.PP +When a pool is defined in the configruation file, it must have an associated +role. At present the only supported role is +.B ipf. +Future development will see futher expansion of their use by other sections +of IPFilter code. +.SH EXAMPLES +The following examples show how the pool configuration file is used with +the ipf configuration file to enhance the ability for the ipf configuration +file to be succinct in meaning. +.TP +1 +The first example shows how a filter rule makes reference to a specific +pool for matching of the source address. +.nf +pass in from pool/100 to any +.fi +.PP +The pool configuration, which matches IP addresses 1.1.1.1 and any +in 2.2.0.0/16, except for those in 2.2.2.0/24. +.PP +.nf +table role = ipf type = tree number = 100 + { 1.1.1.1/32; 2.2.0.0/16; !2.2.2.0/24 }; +.fi +.TP +2 +The following ipf.conf extract uses the +fr_srcgrpmap/fr_dstgrpmap lookups to use the +.B group-map +facility to lookup the next group to use for filter processing, providing +the +.B call +filter rule is matched. +.nf +call now fr_srcgrpmap/1010 in all +call now fr_dstgrpmap/2010 out all +pass in all group 1020 +block in all group 1030 +pass out all group 2020 +block out all group 2040 +.fi +.PP +A ippool configuration to work with the above ipf.conf file might +look like this: +.PP +.nf +group-map in role = ipf number = 1010 + { 1.1.1.1/32, group = 1020; 3.3.0.0/16, group = 1030; }; +group-map out role = ipf number = 2010 group = 2020 + { 2.2.2.2/32; 4.4.0.0/16; 5.0.0.0/8, group = 2040; }; +.fi +.SH FILES +/dev/iplookup +.br +/etc/ippool.conf +.br +/etc/hosts +.SH SEE ALSO +ippool(8), hosts(5), ipf(5), ipf(8), ipnat(8) diff --git a/contrib/ipfilter/man/ippool.8 b/contrib/ipfilter/man/ippool.8 new file mode 100644 index 0000000..6ed1e88 --- /dev/null +++ b/contrib/ipfilter/man/ippool.8 @@ -0,0 +1,126 @@ +.\" $NetBSD$ +.\" +.TH IPPOOL 8 +.SH NAME +ippool \- user interface to the IPFilter pools +.SH SYNOPSIS +.br +.B ippool +-a [-dnv] [-m <name>] [-o <role>] -i <ipaddr>[/<netmask>] +.br +.B ippool +-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>] +.br +.B ippool +-f <file> [-dnuv] +.br +.B ippool +-F [-dv] [-o <role>] [-t <type>] +.br +.B ippool +-l [-dv] [-m <name>] [-t <type>] +.br +.B ippool +-r [-dnv] [-m <name>] [-o <role>] -i <ipaddr>[/<netmask>] +.br +.B ippool +-R [-dnv] [-m <name>] [-o <role>] [-t <type>] +.br +.B ippool +-s [-dtv] [-M <core>] [-N <namelist>] +.SH DESCRIPTION +.PP +.B Ippool +is used to manage information stored in the IP pools subsystem of IPFilter. +Configuration file information may be parsed and loaded into the kernel, +currently configured pools removed or changed as well as inspected. +.PP +The command line options used are broken into two sections: the global +options and the instance specific options. +.SH GLOBAL OPTIONS +.TP +.B \-d +Toggle debugging of processing the configuration file. +.TP +.B \-n +This flag (no-change) prevents +.B ippool +from actually making any ioctl +calls or doing anything which would alter the currently running kernel. +.TP +.B \-v +Turn verbose mode on. +.SH COMMAND OPTIONS +.TP +.B -a +Add a new data node to an existing pool in the kernel. +.TP +.B -A +Add a new (empty) pool to the kernel. +.TP +.B -f <file> +Read in IP pool configuration information from the file and load it into +the kernel. +.TP +.B -F +Flush loaded pools from the kernel. +.TP +.B -l +Display a list of pools currently loaded into the kernel. +.TP +.B -r +Remove an existing data node from a pool in the kernel. +.TP +.B -R +Remove an existing pool from within the kernel. +.TP +.B -s +Display IP pool statistical information. +.SH OPTIONS +.TP +.B -i <ipaddr>[/<netmask>] +Sets the IP address for the operation being undertaken with an +all-one's mask or, optionally, a specific netmask given in either +the dotted-quad notation or a single integer. +.TP +.B -m <name> +Sets the pool name for the current operation. +.TP +.B -M <core> +Specify an alternative path to /dev/kmem to retrieve statistical information +from. +.TP +.B -N <namelist> +Specify an alternative path to lookup symbol name information from when +retrieving statistical information. +.TP +.B -o <role> +Sets the role with which this pool is to be used. Currently only +.B ipf, +.B auth +and +.B count +are accepted as arguments to this option. +.TP +.B -S <seed> +Sets the hashing seed to the number specified. Only for use with +.B hash +type pools. +.TP +.B -t <type> +Sets the type of pool being defined. Myst be one of +.B tree, +.B hash, +.B group-map. +.TP +.B -u +When parsing a configuration file, rather than load new pool data into the +kernel, unload it. +.DT +.SH FILES +.br +/dev/iplookup +.br +/etc/ippool.conf +.SH SEE ALSO +ippool(5), ipf(8), ipfstat(8) diff --git a/contrib/ipfilter/man/ipscan.5 b/contrib/ipfilter/man/ipscan.5 new file mode 100644 index 0000000..4a00174 --- /dev/null +++ b/contrib/ipfilter/man/ipscan.5 @@ -0,0 +1,52 @@ +.\" $NetBSD$ +.\" +.TH IPSCAN 5 +.SH NAME +ipscan, ipscan.conf \- ipscan file format +.SH DESCRIPTION +.PP +WARNING: This feature is to be considered experimental and may change +significantly until a final implementation is drawn up. +.PP +The format for files accept by ipscan currently follow this rough grammar: +.LP +.nf +line ::= name ":" matchup [ "," matchup ] "=" action . +matchup ::= "(" ")" | "(" literal ")" | "(" literal "," match ")" . +action ::= result | result "else" result . +result ::= "close" | "track" | redirect . +redirect ::= "redirect" ip-address [ "(" "," port-number ")" ] . +match ::= { match-char } +match-char ::= "*" | "?" | "." +.fi +.PP +In this example an ip-address is a dotted-quad IPv4 address and a port-number +is a number betwee 1 and 65535, inclusive. The match string is must be of +same length as the literal string that it is matching (literal). The length +of either string is limited to 16 bytes. +.PP +Currently, the redirect option is not yet been implemented. +.LP +.nf +# +# * = match any character, . = exact match, ? = case insensitive +# +# Scan for anything that looks like HTTP and redirect it to the local +# proxy. One catch - this feature (redirect) is not yet implemented. +# +http : ("GET ", "???." ) = redirect(127.0.0.1) +# +# Track ssh connections (i.e do nothing) +# +ssh : (), ("SSH-") = track +# +# Things which look like smtp to be tracked else closed. +# Client can start with EHLO (ESMTP) or HELO (SMTP). +# +smtp : ("HELO ", "**??."), ("220 ", "....") = track else close +# +.fi +.SH FILES +/etc/ipscan.conf +.SH SEE ALSO +ipscan(8) diff --git a/contrib/ipfilter/man/ipscan.8 b/contrib/ipfilter/man/ipscan.8 new file mode 100644 index 0000000..d3ce952 --- /dev/null +++ b/contrib/ipfilter/man/ipscan.8 @@ -0,0 +1,44 @@ +.\" $NetBSD$ +.\" +.TH IPSCAN 8 +.SH NAME +ipscan \- user interface to the IPFilter content scanning +.SH SYNOPSIS +.B ipscan +[ +.B \-dlnrsv +] [ +] +.B \-f <\fIfilename\fP> +.SH DESCRIPTION +.PP +\fBipscan\fP opens the filename given (treating "\-" as stdin) and parses the +file to build up a content scanning configuration to load into the kernel. +Currently only the first 16 bytes of a connection can be compared. +.SH OPTIONS +.TP +.B \-d +Toggle debugging of processing the configuration file. +.TP +.B \-l +Show the list of currently configured content scanning entries. +.TP +.B \-n +This flag (no-change) prevents \fBipscan\fP from actually making any ioctl +calls or doing anything which would alter the currently running kernel. +.TP +.B \-r +Remove commands from kernel configuration as they are read from the +configuration file rather than adding new ones. +.TP +.B \-s +Retrieve and display content scanning statistics +.TP +.B \-v +Turn verbose mode on. +.DT +.SH FILES +/dev/ipscan +/etc/ipscan.conf +.SH SEE ALSO +ipscan(5), ipf(8) diff --git a/contrib/ipfilter/man/mkfilters.1 b/contrib/ipfilter/man/mkfilters.1 index b5fd9dc..3bac7d1 100644 --- a/contrib/ipfilter/man/mkfilters.1 +++ b/contrib/ipfilter/man/mkfilters.1 @@ -1,3 +1,5 @@ +.\" $NetBSD$ +.\" .TH MKFILTERS 1 .SH NAME mkfilters \- generate a minimal firewall ruleset for ipfilter diff --git a/contrib/ipfilter/md5.c b/contrib/ipfilter/md5.c new file mode 100644 index 0000000..78a0eb7 --- /dev/null +++ b/contrib/ipfilter/md5.c @@ -0,0 +1,314 @@ +/* $NetBSD$ */ + + + +/* + *********************************************************************** + ** md5.c -- the source code for MD5 routines ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#if defined(_KERNEL) && !defined(__sgi) +# include <sys/systm.h> +#else +# include <string.h> +#endif + +#include "md5.h" + +/* + *********************************************************************** + ** Message-digest routines: ** + ** To form the message digest for a message M ** + ** (1) Initialize a context buffer mdContext using MD5Init ** + ** (2) Call MD5Update on mdContext and M ** + ** (3) Call MD5Final on mdContext ** + ** The message digest is now in mdContext->digest[0...15] ** + *********************************************************************** + */ + +/* forward declaration */ +static void Transform __P((UINT4 *, UINT4 *)); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#ifdef __STDC__ +#define UL(x) x##U +#else +#define UL(x) x +#endif + +/* The routine MD5Init initializes the message-digest context + mdContext. All fields are set to zero. + */ +void MD5Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +/* The routine MD5Update updates the message-digest context to + account for the presence of each of the characters inBuf[0..inLen-1] + in the message whose digest is being computed. + */ +void MD5Update (mdContext, inBuf, inLen) +MD5_CTX *mdContext; +unsigned char *inBuf; +unsigned int inLen; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +/* The routine MD5Final terminates the message-digest computation and + ends with the desired message digest in mdContext->digest[0...15]. + */ +void MD5Final (hash, mdContext) +unsigned char hash[]; +MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } + bcopy((char *)mdContext->digest, (char *)hash, 16); +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void Transform (buf, in) +UINT4 *buf; +UINT4 *in; +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ + FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ + FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ + FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ + FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ + FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ + FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ + GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ + GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ + GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ + GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ + GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ + GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ + HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ + HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ + HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ + HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ + HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ + HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ + II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ + II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ + II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ + II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ + II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ + II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ + II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ + II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ + II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ + II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ + II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ + II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ + II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ + II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ + II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + *********************************************************************** + ** End of md5.c ** + ******************************** (cut) ******************************** + */ diff --git a/contrib/ipfilter/md5.h b/contrib/ipfilter/md5.h new file mode 100644 index 0000000..40e8dc6 --- /dev/null +++ b/contrib/ipfilter/md5.h @@ -0,0 +1,72 @@ +/* $NetBSD$ */ + +/* + *********************************************************************** + ** md5.h -- header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#ifndef __MD5_INCLUDE__ + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +#ifndef __STDC__ +# undef const +# define const +#endif + +/* typedef a 32-bit type */ +typedef unsigned int UINT4; + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + UINT4 buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +extern void MD5Init __P((MD5_CTX *)); +extern void MD5Update __P((MD5_CTX *, unsigned char *, unsigned int)); +extern void MD5Final __P((unsigned char *, MD5_CTX *)); + +#define __MD5_INCLUDE__ +#endif /* __MD5_INCLUDE__ */ diff --git a/contrib/ipfilter/mlf_ipl.c b/contrib/ipfilter/mlf_ipl.c index a165c79..c0cdce8 100644 --- a/contrib/ipfilter/mlf_ipl.c +++ b/contrib/ipfilter/mlf_ipl.c @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1993-2001 by Darren Reed. * @@ -11,16 +13,22 @@ #include <sys/param.h> -#if defined(__FreeBSD__) -# ifndef __FreeBSD_version -# ifdef IPFILTER_LKM +#ifdef IPFILTER_LKM +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 # include <osreldate.h> -# else -# include <sys/osreldate.h> # endif # endif -# ifdef IPFILTER_LKM -# define ACTUALLY_LKM_NOT_KERNEL +# define ACTUALLY_LKM_NOT_KERNEL +#else +# ifndef __FreeBSD_cc_version +# include <sys/osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <sys/osreldate.h> +# endif # endif #endif #include <sys/systm.h> @@ -41,7 +49,6 @@ #endif #include <sys/stat.h> #include <sys/proc.h> -#include <sys/uio.h> #include <sys/kernel.h> #include <sys/vnode.h> #include <sys/namei.h> @@ -60,7 +67,6 @@ #include <netinet/in.h> #include <netinet/ip.h> #include <net/route.h> -#include <net/if.h> #include <netinet/ip_var.h> #include <netinet/tcp.h> #include <netinet/tcpip.h> @@ -73,68 +79,65 @@ #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) #define VOP_LEASE LEASE_CHECK #endif -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - int xxxinit __P((struct lkm_table *, int, int)); -#ifdef SYSCTL_INT +#ifdef SYSCTL_OID +int sysctl_ipf_int SYSCTL_HANDLER_ARGS; +# define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \ + ptr, val, sysctl_ipf_int, "I", descr); +# define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */ +# define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF) 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_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttllog, CTLFLAG_RW, - &fr_minttllog, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO, &fr_tcpidletimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO, &fr_tcphalfclosed, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO, &fr_tcpclosewait, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO, &fr_tcplastack, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO, &fr_tcptimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO, &fr_tcpclosed, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO, &fr_udptimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RW, - &fr_udpacktimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO, &fr_icmptimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmpacktimeout, CTLFLAG_RW, - &fr_icmpacktimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO, &fr_defnatage, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, +SYSCTL_IPF(_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, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, &fr_running, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO, + &fr_statesize, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO, + &fr_statemax, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO, &fr_authsize, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, &fr_authused, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, &fr_defaultauthage, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, &ippr_ftp_pasvonly, 0, ""); #endif #ifdef DEVFS -static void *ipf_devfs[IPL_LOGMAX + 1]; +static void *ipf_devfs[IPL_LOGSIZE]; #endif #if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) @@ -142,17 +145,17 @@ int ipl_major = 0; static struct cdevsw ipldevsw = { - iplopen, /* open */ - iplclose, /* close */ - iplread, /* read */ - (void *)nullop, /* write */ - iplioctl, /* ioctl */ - (void *)nullop, /* stop */ - (void *)nullop, /* reset */ - (void *)NULL, /* tty */ - (void *)nullop, /* select */ - (void *)nullop, /* mmap */ - NULL /* strategy */ + iplopen, /* open */ + iplclose, /* close */ + iplread, /* read */ + (void *)nullop, /* write */ + iplioctl, /* ioctl */ + (void *)nullop, /* stop */ + (void *)nullop, /* reset */ + (void *)NULL, /* tty */ + (void *)nullop, /* select */ + (void *)nullop, /* mmap */ + NULL /* strategy */ }; MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); @@ -183,7 +186,8 @@ static int if_ipl_remove __P((void)); static int ipl_major = CDEV_MAJOR; static int iplaction __P((struct lkm_table *, int)); -static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, NULL }; +static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, + IPL_SCAN, IPL_SYNC, IPL_POOL, NULL }; extern int lkmenodev __P((void)); @@ -236,6 +240,12 @@ int cmd; devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]); if (ipf_devfs[IPL_LOGAUTH]) devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]); + if (ipf_devfs[IPL_LOGSCAN]) + devfs_remove_dev(ipf_devfs[IPL_LOGSCAN]); + if (ipf_devfs[IPL_LOGSYNC]) + devfs_remove_dev(ipf_devfs[IPL_LOGSYNC]); + if (ipf_devfs[IPL_LOGLOOKUP]) + devfs_remove_dev(ipf_devfs[IPL_LOGLOOKUP]); #endif } return err; @@ -329,7 +339,7 @@ int cmd; VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); #if (__FreeBSD_version >= 300000) - vput(nd.ni_dvp); + vput(nd.ni_dvp); #endif if (error) return error; @@ -346,11 +356,11 @@ int cmd; size_t strlen(string) char *string; { - register char *s; + register char *s; - for (s = string; *s; s++) + for (s = string; *s; s++) ; - return (size_t)(s - string); + return (size_t)(s - string); } @@ -395,7 +405,7 @@ int cmd, ver; # endif } # endif /* IPFILTER_LKM */ -static int ipl_devsw_installed = 0; +static ipl_devsw_installed = 0; static void ipl_drvinit __P((void *unused)) { @@ -415,15 +425,43 @@ static void ipl_drvinit __P((void *unused)) tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT, DV_CHR, 0, 0, 0600, "ipnat"); tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE, - DV_CHR, 0, 0, 0600, + DV_CHR, 0, 0, 0600, "ipstate"); tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGAUTH, - DV_CHR, 0, 0, 0600, + DV_CHR, 0, 0, 0600, "ipauth"); # endif } } + +#ifdef SYSCTL_IPF +int +sysctl_ipf_int SYSCTL_HANDLER_ARGS +{ + int error = 0; + + if (arg1) + error = SYSCTL_OUT(req, arg1, sizeof(int)); + else + error = SYSCTL_OUT(req, &arg2, sizeof(int)); + + if (error || !req->newptr) + return (error); + + if (!arg1) + error = EPERM; + else { + if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0)) + error = EBUSY; + else + error = SYSCTL_IN(req, arg1, sizeof(int)); + } + return (error); +} +#endif + + # if defined(IPFILTER_LKM) || \ defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL) diff --git a/contrib/ipfilter/mlf_rule.c b/contrib/ipfilter/mlf_rule.c new file mode 100644 index 0000000..731ef5e --- /dev/null +++ b/contrib/ipfilter/mlf_rule.c @@ -0,0 +1,168 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ + + +#include <sys/param.h> + +#if defined(__FreeBSD__) && (__FreeBSD__ > 1) +# ifdef IPFILTER_LKM +# include <osreldate.h> +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include <sys/osreldate.h> +# endif +#endif +#include <sys/systm.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +# include <sys/conf.h> +# include <sys/kernel.h> +# ifdef DEVFS +# include <sys/devfsext.h> +# endif /*DEVFS*/ +#endif +#include <sys/conf.h> +#include <sys/file.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/lock.h> +#endif +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/vnode.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/exec.h> +#include <sys/mbuf.h> +#if BSD >= 199506 +# include <sys/sysctl.h> +#endif +#if (__FreeBSD_version >= 300000) +# include <sys/socket.h> +#endif +#if (__FreeBSD_version >= 199511) +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#endif +#if (__FreeBSD__ > 1) +# include <sys/sysent.h> +#endif +#include <sys/lkm.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_rules.h" + + +int xxxinit __P((struct lkm_table *, int, int)); + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) +MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); +#endif + +static int ipfrule_ioctl __P((struct lkm_table *, int)); + +#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000) + +int xxxinit(lkmtp, cmd, ver) +struct lkm_table *lkmtp; +int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, ipfrule_ioctl); +} +#else /* __FREEBSD_version >= 220000 */ +# ifdef IPFILTER_LKM +# include <sys/exec.h> + +# if (__FreeBSD_version >= 300000) +MOD_MISC(ipfrule); +# else +MOD_DECL(ipfrule); + + +static struct lkm_misc _module = { + LM_MISC, + LKM_VERSION, + "IP Filter rules", + 0, +}; +# endif + + +int ipfrule __P((struct lkm_table *, int, int)); + + +int ipfrule(lkmtp, cmd, ver) +struct lkm_table *lkmtp; +int cmd, ver; +{ +# if (__FreeBSD_version >= 300000) + MOD_DISPATCH(ipfrule, lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, + ipfrule_ioctl); +# else + DISPATCH(lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, ipfrule_ioctl); +# endif +} +# endif /* IPFILTER_LKM */ + + +int ipfrule_load(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + return ipfrule_add(); +} + + +int ipfrule_unload(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + return ipfrule_remove(); +} + + +static int ipfrule_ioctl(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + + err = ipfrule_load(lkmtp, cmd); + if (!err) + fr_refcnt++; + break; + case LKM_E_UNLOAD : + err = ipfrule_unload(lkmtp, cmd); + if (!err) + fr_refcnt--; + break; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return err; +} +#endif /* _FreeBSD_version */ diff --git a/contrib/ipfilter/mlfk_ipl.c b/contrib/ipfilter/mlfk_ipl.c index f33de37..0f50fea 100644 --- a/contrib/ipfilter/mlfk_ipl.c +++ b/contrib/ipfilter/mlfk_ipl.c @@ -1,29 +1,9 @@ +/* $NetBSD$ */ + /* - * 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. + * Copyright (C) 2000 by Darren Reed. * - * $Id: mlfk_ipl.c,v 2.1.2.7 2001/08/27 21:14:04 darrenr Exp $ + * See the IPFILTER.LICENCE file for details on licencing. */ @@ -37,13 +17,6 @@ #include <net/if.h> #include <netinet/in_systm.h> #include <netinet/in.h> -#include <netinet/ip.h> -#if (__FreeBSD_version >= 199511) -# include <net/route.h> -# include <netinet/ip_var.h> -# include <netinet/tcp.h> -# include <netinet/tcpip.h> -#endif #include <netinet/ipl.h> @@ -53,62 +26,92 @@ #include <netinet/ip_nat.h> #include <netinet/ip_auth.h> #include <netinet/ip_frag.h> -#include <netinet/ip_proxy.h> -static dev_t ipf_devs[IPL_LOGMAX + 1]; +#if __FreeBSD_version >= 502116 +static struct cdev *ipf_devs[IPL_LOGSIZE]; +#else +static dev_t ipf_devs[IPL_LOGSIZE]; +#endif + +static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ); +static int ipf_modload(void); +static int ipf_modunload(void); SYSCTL_DECL(_net_inet); +#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \ + ptr, val, sysctl_ipf_int, "I", descr); +#define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */ +#define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF) 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, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO, &fr_tcpidletimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO, + &fr_tcphalfclosed, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO, &fr_tcpclosewait, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO, &fr_tcplastack, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO, &fr_tcptimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO, &fr_tcpclosed, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, - &fr_tcphalfclosed, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO, &fr_udptimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO, &fr_udpacktimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO, &fr_icmptimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmpacktimeout, CTLFLAG_RW, - &fr_icmpacktimeout, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO, &fr_defnatage, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, +SYSCTL_IPF(_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, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, &fr_running, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO, + &fr_statesize, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO, + &fr_statemax, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO, + &ipf_nattable_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO, + &ipf_natrules_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO, + &ipf_rdrrules_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO, + &ipf_hostmap_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO, &fr_authsize, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, &fr_authused, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, &fr_defaultauthage, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, - &ippr_ftp_pasvonly, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttllog, CTLFLAG_RW, - &fr_minttllog, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); #define CDEV_MAJOR 79 +#if __FreeBSD_version >= 501000 +static struct cdevsw ipl_cdevsw = { +#if __FreeBSD_version >= 502103 + .d_version = D_VERSION, + .d_flags = 0, /* D_NEEDGIANT - Should be SMP safe */ +#endif + .d_open = iplopen, + .d_close = iplclose, + .d_read = iplread, + .d_ioctl = iplioctl, + .d_name = "ipl", + .d_maj = CDEV_MAJOR, +}; +#else static struct cdevsw ipl_cdevsw = { /* open */ iplopen, /* close */ iplclose, /* read */ iplread, - /* write */ nowrite, + /* write */ iplwrite, /* ioctl */ iplioctl, /* poll */ nopoll, /* mmap */ nommap, @@ -118,84 +121,151 @@ static struct cdevsw ipl_cdevsw = { /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, - /* bmaj */ -1 +# if (__FreeBSD_version < 500043) + /* bmaj */ -1, +# endif + /* kqfilter */ NULL }; +#endif + +static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME, + IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL }; + static int ipfilter_modevent(module_t mod, int type, void *unused) { - char *c; - int i, error = 0; + int error = 0; - switch (type) { + switch (type) + { case MOD_LOAD : + error = ipf_modload(); + break; - error = iplattach(); - if (error) - break; + case MOD_UNLOAD : + error = ipf_modunload(); + break; + default: + error = EINVAL; + break; + } + return error; +} - 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); +static int +ipf_modload() +{ + char *defpass, *c, *str; + int i, j, error; - 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); + error = iplattach(); + if (error) + return error; + + for (i = 0; i < IPL_LOGSIZE; i++) + ipf_devs[i] = NULL; + for (i = 0; (str = ipf_devfiles[i]); i++) { c = NULL; - for(i=strlen(IPL_AUTH); i>0; i--) - if (IPL_AUTH[i] == '/') { - c = &IPL_AUTH[i+1]; + for(j = strlen(str); j > 0; j--) + if (str[j] == '/') { + c = str + j + 1; break; } if (!c) - c = IPL_AUTH; - ipf_devs[IPL_LOGAUTH] = - make_dev(&ipl_cdevsw, IPL_LOGAUTH, 0, 0, 0600, c); + c = str; + ipf_devs[i] = make_dev(&ipl_cdevsw, i, 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]); + if (FR_ISPASS(fr_pass)) + defpass = "pass"; + else if (FR_ISBLOCK(fr_pass)) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s%s\n", + ipfilter_version, defpass, +#ifdef IPFILTER_LOG + "enabled", +#else + "disabled", +#endif +#ifdef IPFILTER_COMPILED + " (COMPILED)" +#else + "" +#endif + ); + return 0; +} + + +static int +ipf_modunload() +{ + int error, i; + + if (fr_refcnt) + return EBUSY; + + if (fr_running >= 0) { error = ipldetach(); - break; - default: - error = EINVAL; - break; + if (error != 0) + return error; + } else + error = 0; + + fr_running = -2; + + for (i = 0; ipf_devfiles[i]; i++) { + if (ipf_devs[i] != NULL) + destroy_dev(ipf_devs[i]); } + + printf("%s unloaded\n", ipfilter_version); + return error; } + static moduledata_t ipfiltermod = { - IPL_VERSION, + "ipfilter", ipfilter_modevent, - 0 + 0 }; + + DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); +#ifdef MODULE_VERSION +MODULE_VERSION(ipfilter, 1); +#endif + + +#ifdef SYSCTL_IPF +int +sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ) +{ + int error = 0; + + if (arg1) + error = SYSCTL_OUT(req, arg1, sizeof(int)); + else + error = SYSCTL_OUT(req, &arg2, sizeof(int)); + + if (error || !req->newptr) + return (error); + + if (!arg1) + error = EPERM; + else { + if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0)) + error = EBUSY; + else + error = SYSCTL_IN(req, arg1, sizeof(int)); + } + return (error); +} +#endif diff --git a/contrib/ipfilter/mlfk_rule.c b/contrib/ipfilter/mlfk_rule.c new file mode 100644 index 0000000..a4f3ba7 --- /dev/null +++ b/contrib/ipfilter/mlfk_rule.c @@ -0,0 +1,69 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2000 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: mlfk_rule.c,v 2.4.4.2 2004/04/16 23:32:08 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> + +#include "ip_rules.h" + + +static int +ipfrule_modevent(module_t mod, int type, void *unused) +{ + int error = 0; + + switch (type) + { + case MOD_LOAD : + error = ipfrule_add(); + if (!error) + fr_refcnt++; + break; + case MOD_UNLOAD : + error = ipfrule_remove(); + if (!error) + fr_refcnt--; + break; + default: + error = EINVAL; + break; + } + return error; +} + +static moduledata_t ipfrulemod = { + "ipfrule", + ipfrule_modevent, + 0 +}; +DECLARE_MODULE(ipfrule, ipfrulemod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); +#ifdef MODULE_DEPEND +MODULE_DEPEND(ipfrule, ipfilter, 1, 1, 1); +#endif +#ifdef MODULE_VERSION +MODULE_VERSION(ipfrule, 1); +#endif diff --git a/contrib/ipfilter/mlh_rule.c b/contrib/ipfilter/mlh_rule.c new file mode 100644 index 0000000..e71c7be --- /dev/null +++ b/contrib/ipfilter/mlh_rule.c @@ -0,0 +1,114 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-1998 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +/* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/ + +/*typedef unsigned int spustate_t;*/ +struct uio; + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/conf.h> +#include <sys/callout.h> +#include <sys/moddefs.h> +#include <sys/io.h> +#include <sys/wsio.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/byteorder.h> +#include <sys/socket.h> +#include <sys/stropts.h> +#include <net/if.h> +#include <net/af.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/tcpip.h> +#include <netinet/ip_icmp.h> + +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_rules.h" + + +/* + * Driver Header + */ +static drv_info_t ipf_drv_info = { + "IP Filter Rules", /* type */ + "pseudo", /* class */ + DRV_PSEUDO|DRV_SAVE_CONF|DRV_MP_SAFE, /* flags */ + -1, /* b_major */ + -1, /* c_major */ + NULL, /* cdio */ + NULL, /* gio_private */ + NULL, /* cdio_private */ +}; + + +extern struct mod_operations gio_mod_ops; +static drv_info_t ipf_drv_info; +extern struct mod_conf_data ipf_conf_data; + +static struct mod_type_data ipf_drv_link = { + IPL_VERSION, (void *)NULL +}; + +static struct modlink ipf_mod_link[] = { + { &gio_mod_ops, (void *)&ipf_drv_link }, + { NULL, (void *)NULL } +}; + +struct modwrapper ipf_wrapper = { + MODREV, + ipf_load, + ipf_unload, + (void (*)())NULL, + (void *)&ipf_conf_data, + ipf_mod_link +}; + + +static int ipf_load(void *arg) +{ + int i; + + i = ipfrule_add(); + if (!i) + fr_refcnt--; +#ifdef IPFDEBUG + printf("IP Filter Rules: ipfrule_add() = %d\n", i); +#endif + if (!i) + cmn_err(CE_CONT, "IP Filter Rules: Loaded\n"); + return i; +} + + +static int ipf_unload(void *arg) +{ + int i; + + i = ipfrule_remove(); + if (!i) + fr_refcnt--; +#ifdef IPFDEBUG + printf("IP Filter Rules: ipfrule_remove() = %d\n", i); +#endif + if (!i) + cmn_err(CE_CONT, "IP Filter Rules: Unloaded\n"); + return i; +} diff --git a/contrib/ipfilter/net/.cvsignore b/contrib/ipfilter/net/.cvsignore new file mode 100644 index 0000000..19f86f4 --- /dev/null +++ b/contrib/ipfilter/net/.cvsignore @@ -0,0 +1 @@ +done diff --git a/contrib/ipfilter/opts.h b/contrib/ipfilter/opts.h new file mode 100644 index 0000000..602c4e3 --- /dev/null +++ b/contrib/ipfilter/opts.h @@ -0,0 +1,67 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2000 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: opts.h,v 2.12 2003/08/14 14:24:27 darrenr Exp + */ + +#ifndef __OPTS_H__ +#define __OPTS_H__ + +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif +#define OPT_REMOVE 0x000001 +#define OPT_DEBUG 0x000002 +#define OPT_AUTHSTATS 0x000004 +#define OPT_RAW 0x000008 +#define OPT_LOG 0x000010 +#define OPT_SHOWLIST 0x000020 +#define OPT_VERBOSE 0x000040 +#define OPT_DONOTHING 0x000080 +#define OPT_HITS 0x000100 +#define OPT_BRIEF 0x000200 +#define OPT_ACCNT 0x000400 +#define OPT_FRSTATES 0x000800 +#define OPT_SHOWLINENO 0x001000 +#define OPT_PRINTFR 0x002000 +#define OPT_OUTQUE FR_OUTQUE /* 0x4000 */ +#define OPT_INQUE FR_INQUE /* 0x8000 */ +#define OPT_ZERORULEST 0x010000 +#define OPT_SAVEOUT 0x020000 +#define OPT_IPSTATES 0x040000 +#define OPT_INACTIVE 0x080000 +#define OPT_NAT 0x100000 +#define OPT_GROUPS 0x200000 +#define OPT_STATETOP 0x400000 +#define OPT_FLUSH 0x800000 +#define OPT_CLEAR 0x1000000 +#define OPT_HEX 0x2000000 +#define OPT_ASCII 0x4000000 +#define OPT_NORESOLVE 0x8000000 + +#define OPT_STAT OPT_FRSTATES +#define OPT_LIST OPT_SHOWLIST + + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +#if defined(sun) && !SOLARIS +# define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +# define STRERROR(x) strerror(x) +#endif + +extern int opts; + +#endif /* __OPTS_H__ */ diff --git a/contrib/ipfilter/pcap-ipf.h b/contrib/ipfilter/pcap-ipf.h new file mode 100644 index 0000000..a6b974c --- /dev/null +++ b/contrib/ipfilter/pcap-ipf.h @@ -0,0 +1,35 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +/* + * This header file is constructed to match the version described by + * PCAP_VERSION_MAJ. + * + * The structure largely derives from libpcap which wouldn't include + * nicely without bpf. + */ +typedef struct pcap_filehdr { + u_int pc_id; + u_short pc_v_maj; + u_short pc_v_min; + u_int pc_zone; + u_int pc_sigfigs; + u_int pc_slen; + u_int pc_type; +} pcaphdr_t; + +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +#define PCAP_VERSION_MAJ 2 + +typedef struct pcap_pkthdr { + struct timeval ph_ts; + u_int ph_clen; + u_int ph_len; +} pcappkt_t; + diff --git a/contrib/ipfilter/perl/ipf-mrtg.pl b/contrib/ipfilter/perl/ipf-mrtg.pl index cce30ab..a96a7cd 100644 --- a/contrib/ipfilter/perl/ipf-mrtg.pl +++ b/contrib/ipfilter/perl/ipf-mrtg.pl @@ -19,4 +19,4 @@ print "$in_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 + "$firewall\n"; diff --git a/contrib/ipfilter/perl/ipfmeta.pl b/contrib/ipfilter/perl/ipfmeta.pl new file mode 100644 index 0000000..1a7bb3f --- /dev/null +++ b/contrib/ipfilter/perl/ipfmeta.pl @@ -0,0 +1,210 @@ +#!/usr/bin/perl -w +# +# Written by Camiel Dobbelaar <cd@sentia.nl>, Aug-2000 +# ipfmeta is in the Public Domain. +# + +use strict; +use Getopt::Std; + +## PROCESS COMMANDLINE +our($opt_v); $opt_v=1; +getopts('v:') || die "usage: ipfmeta [-v verboselevel] [objfile]\n"; +my $verbose = $opt_v + 0; +my $objfile = shift || "ipf.objs"; +my $MAXRECURSION = 10; + +## READ OBJECTS +open(FH, "$objfile") || die "cannot open $objfile: $!\n"; +my @tokens; +while (<FH>) { + chomp; + s/#.*$//; # remove comments + s/^\s+//; # compress whitespace + s/\s+$//; + next if m/^$/; # skip empty lines + push (@tokens, split); +} +close(FH) || die "cannot close $objfile: $!\n"; +# link objects with their values +my $obj=""; +my %objs; +while (@tokens) { + my $token = shift(@tokens); + if ($token =~ m/^\[([^]]*)\]$/) { + # new object + $obj = $1; + } else { + # new value + push(@{$objs{$obj}}, $token) unless ($obj eq ""); + } +} + +# sort objects: longest first +my @objs = sort { length($b) <=> length($a) } keys %objs; + +## SUBSTITUTE OBJECTS WITH THEIR VALUES FROM STDIN +foreach (<STDIN>) { + foreach (expand($_, 0)) { + print; + } +} + +## END + +sub expand { + my $line = shift; + my $level = shift; + my @retlines = $line; + my $obj; + my $val; + + # coarse protection + if ($level > $MAXRECURSION) { + print STDERR "ERR: recursion exceeds $MAXRECURSION levels\n"; + return; + } + + foreach $obj (@objs) { + if ($line =~ m/$obj/) { + @retlines = ""; + if ($level < $verbose) { + # add metarule as a comment + push(@retlines, "# ".$line); + } + foreach $val (@{$objs{$obj}}) { + my $newline = $line; + $newline =~ s/$obj/$val/; + push(@retlines, expand($newline, $level+1)); + } + last; + } + } + + return @retlines; +} + +__END__ + +=head1 NAME + +B<ipfmeta> - use objects in IP filter files + +=head1 SYNOPSIS + +B<ipfmeta> [F<options>] [F<objfile>] + +=head1 DESCRIPTION + +B<ipfmeta> is used to simplify the maintenance of your IP filter +ruleset. It does this through the use of 'objects'. A matching +object gets replaced by its values at runtime. This is similar to +what a macro processor like m4 does. + +B<ipfmeta> is specifically geared towards IP filter. It is line +oriented, if an object has multiple values, the line with the object +is duplicated and substituted for each value. It is also recursive, +an object may have another object as a value. + +Rules to be processed are read from stdin, output goes to stdout. + +The verbose option allows for the inclusion of the metarules in the +output as comments. + +Definition of the objects and their values is done in a separate +file, the filename defaults to F<ipf.objs>. An object is delimited +by square brackets. A value is delimited by whitespace. Comments +start with '#' and end with a newline. Empty lines and extraneous +whitespace are allowed. A value belongs to the first object that +precedes it. + +It is recommended that you use all caps or another distinguishing +feature for object names. You can use B<ipfmeta> for NAT rules also, +for instance to keep them in sync with filter rules. Combine +B<ipfmeta> with a Makefile to save typing. + +=head1 OPTIONS + +=over 4 + +=item B<-v> I<verboselevel> + +Include metarules in output as comments. Default is 1, the top level +metarules. Higher levels cause expanded metarules to be included. +Level 0 does not add comments at all. + +=back + +=head1 BUGS + +A value can not have whitespace in it. + +=head1 EXAMPLE + +(this does not look good, formatted) + +I<ipf.objs> + +[PRIVATE] 10.0.0.0/8 127.0.0.0/8 172.16.0.0/12 192.168.0.0/16 + +[MULTICAST] 224.0.0.0/4 + +[UNWANTED] PRIVATE MULTICAST + +[NOC] xxx.yy.zz.1/32 xxx.yy.zz.2/32 + +[WEBSERVERS] 192.168.1.1/32 192.168.1.2/32 + +[MGMT-PORTS] 22 23 + +I<ipf.metarules> + +block in from UNWANTED to any + +pass in from NOC to WEBSERVERS port = MGMT-PORTS + +pass out all + +I<Run> + +ipfmeta ipf.objs <ipf.metarules >ipf.rules + +I<Output> + +# block in from UNWANTED to any + +block in from 10.0.0.0/8 to any + +block in from 127.0.0.0/8 to any + +block in from 172.16.0.0/12 to any + +block in from 192.168.0.0/16 to any + +block in from 224.0.0.0/4 to any + +# pass in from NOC to WEBSERVERS port = MGMT-PORTS + +pass in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 22 + +pass in from xxx.yy.zz.1/32 to 192.168.1.1/32 port = 23 + +pass in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 22 + +pass in from xxx.yy.zz.1/32 to 192.168.1.2/32 port = 23 + +pass in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 22 + +pass in from xxx.yy.zz.2/32 to 192.168.1.1/32 port = 23 + +pass in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 22 + +pass in from xxx.yy.zz.2/32 to 192.168.1.2/32 port = 23 + +pass out all + +=head1 AUTHOR + +Camiel Dobbelaar <cd@sentia.nl>. B<ipfmeta> is in the Public Domain. + +=cut diff --git a/contrib/ipfilter/perl/logfilter.pl b/contrib/ipfilter/perl/logfilter.pl index 6ebe401..a75eafd 100644 --- a/contrib/ipfilter/perl/logfilter.pl +++ b/contrib/ipfilter/perl/logfilter.pl @@ -178,4 +178,4 @@ tcp 6667 irc.log tcp 7070 realaudio.log tcp 8080 http.log tcp 12345 netbus.log -udp 31337 backorifice.log
\ No newline at end of file +udp 31337 backorifice.log diff --git a/contrib/ipfilter/radix.c b/contrib/ipfilter/radix.c new file mode 100644 index 0000000..964c1095 --- /dev/null +++ b/contrib/ipfilter/radix.c @@ -0,0 +1,1202 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1988, 1989, 1993 + * The Regents of the University of California. 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 REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)radix.c 8.6 (Berkeley) 10/17/95 + */ + +/* + * Routines to build and maintain radix trees for routing lookups. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#define __SYS_ATOMIC_OPS_H__ +#if !defined(__svr4__) && !defined(__SVR4) && !defined(__osf__) && \ + !defined(__hpux) && !defined(__sgi) +#include <sys/cdefs.h> +#endif +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +#ifdef __osf__ +# define CONST +# define _IPV6_SWTAB_H +# define _PROTO_NET_H_ +# define _PROTO_IPV6_H +# include <sys/malloc.h> +#endif + +#include <sys/param.h> +#ifdef _KERNEL +#include <sys/systm.h> +#else +void panic __P((char *str)); +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#endif +#ifdef __hpux +#include <syslog.h> +#else +#include <sys/syslog.h> +#endif +#include <sys/time.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <net/if.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +/* END OF INCLUDES */ +#include "radix_ipf.h" +#ifndef min +# define min MIN +#endif +#ifndef max +# define max MAX +#endif + +int max_keylen = 16; +static struct radix_mask *rn_mkfreelist; +static struct radix_node_head *mask_rnhead; +static char *addmask_key; +static u_char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; +static char *rn_zeros = NULL, *rn_ones = NULL; + +#define rn_masktop (mask_rnhead->rnh_treetop) +#undef Bcmp +#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l)) + +static int rn_satisfies_leaf __P((char *, struct radix_node *, int)); +static int rn_lexobetter __P((void *, void *)); +static struct radix_mask *rn_new_radix_mask __P((struct radix_node *, + struct radix_mask *)); +static int rn_freenode __P((struct radix_node *, void *)); + +/* + * The data structure for the keys is a radix tree with one way + * branching removed. The index rn_b at an internal node n represents a bit + * position to be tested. The tree is arranged so that all descendants + * of a node n have keys whose bits all agree up to position rn_b - 1. + * (We say the index of n is rn_b.) + * + * There is at least one descendant which has a one bit at position rn_b, + * and at least one with a zero there. + * + * A route is determined by a pair of key and mask. We require that the + * bit-wise logical and of the key and mask to be the key. + * We define the index of a route to associated with the mask to be + * the first bit number in the mask where 0 occurs (with bit number 0 + * representing the highest order bit). + * + * We say a mask is normal if every bit is 0, past the index of the mask. + * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b, + * and m is a normal mask, then the route applies to every descendant of n. + * If the index(m) < rn_b, this implies the trailing last few bits of k + * before bit b are all 0, (and hence consequently true of every descendant + * of n), so the route applies to all descendants of the node as well. + * + * Similar logic shows that a non-normal mask m such that + * index(m) <= index(n) could potentially apply to many children of n. + * Thus, for each non-host route, we attach its mask to a list at an internal + * node as high in the tree as we can go. + * + * The present version of the code makes use of normal routes in short- + * circuiting an explict mask and compare operation when testing whether + * a key satisfies a normal route, and also in remembering the unique leaf + * that governs a subtree. + */ + +struct radix_node * +rn_search(v_arg, head) + void *v_arg; + struct radix_node *head; +{ + struct radix_node *x; + caddr_t v; + + for (x = head, v = v_arg; x->rn_b >= 0;) { + if (x->rn_bmask & v[x->rn_off]) + x = x->rn_r; + else + x = x->rn_l; + } + return (x); +} + +struct radix_node * +rn_search_m(v_arg, head, m_arg) + struct radix_node *head; + void *v_arg, *m_arg; +{ + struct radix_node *x; + caddr_t v = v_arg, m = m_arg; + + for (x = head; x->rn_b >= 0;) { + if ((x->rn_bmask & m[x->rn_off]) && + (x->rn_bmask & v[x->rn_off])) + x = x->rn_r; + else + x = x->rn_l; + } + return x; +} + +int +rn_refines(m_arg, n_arg) + void *m_arg, *n_arg; +{ + caddr_t m = m_arg, n = n_arg; + caddr_t lim, lim2 = lim = n + *(u_char *)n; + int longer = (*(u_char *)n++) - (int)(*(u_char *)m++); + int masks_are_equal = 1; + + if (longer > 0) + lim -= longer; + while (n < lim) { + if (*n & ~(*m)) + return 0; + if (*n++ != *m++) + masks_are_equal = 0; + } + while (n < lim2) + if (*n++) + return 0; + if (masks_are_equal && (longer < 0)) + for (lim2 = m - longer; m < lim2; ) + if (*m++) + return 1; + return (!masks_are_equal); +} + +struct radix_node * +rn_lookup(v_arg, m_arg, head) + void *v_arg, *m_arg; + struct radix_node_head *head; +{ + struct radix_node *x; + caddr_t netmask = 0; + + if (m_arg) { + if ((x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_off)) == 0) + return (0); + netmask = x->rn_key; + } + x = rn_match(v_arg, head); + if (x && netmask) { + while (x && x->rn_mask != netmask) + x = x->rn_dupedkey; + } + return x; +} + +static int +rn_satisfies_leaf(trial, leaf, skip) + char *trial; + struct radix_node *leaf; + int skip; +{ + char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask; + char *cplim; + int length = min(*(u_char *)cp, *(u_char *)cp2); + + if (cp3 == 0) + cp3 = rn_ones; + else + length = min(length, *(u_char *)cp3); + cplim = cp + length; + cp3 += skip; + cp2 += skip; + for (cp += skip; cp < cplim; cp++, cp2++, cp3++) + if ((*cp ^ *cp2) & *cp3) + return 0; + return 1; +} + +struct radix_node * +rn_match(v_arg, head) + void *v_arg; + struct radix_node_head *head; +{ + caddr_t v = v_arg; + struct radix_node *t = head->rnh_treetop, *x; + caddr_t cp = v, cp2; + caddr_t cplim; + struct radix_node *saved_t, *top = t; + int off = t->rn_off, vlen = *(u_char *)cp, matched_off; + int test, b, rn_b; + + /* + * Open code rn_search(v, top) to avoid overhead of extra + * subroutine call. + */ + for (; t->rn_b >= 0; ) { + if (t->rn_bmask & cp[t->rn_off]) + t = t->rn_r; + else + t = t->rn_l; + } + /* + * See if we match exactly as a host destination + * or at least learn how many bits match, for normal mask finesse. + * + * It doesn't hurt us to limit how many bytes to check + * to the length of the mask, since if it matches we had a genuine + * match and the leaf we have is the most specific one anyway; + * if it didn't match with a shorter length it would fail + * with a long one. This wins big for class B&C netmasks which + * are probably the most common case... + */ + if (t->rn_mask) + vlen = *(u_char *)t->rn_mask; + cp += off; + cp2 = t->rn_key + off; + cplim = v + vlen; + for (; cp < cplim; cp++, cp2++) + if (*cp != *cp2) + goto on1; + /* + * This extra grot is in case we are explicitly asked + * to look up the default. Ugh! + */ + if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey) + t = t->rn_dupedkey; + return t; +on1: + test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */ + for (b = 7; (test >>= 1) > 0;) + b--; + matched_off = cp - v; + b += matched_off << 3; + rn_b = -1 - b; + /* + * If there is a host route in a duped-key chain, it will be first. + */ + if ((saved_t = t)->rn_mask == 0) + t = t->rn_dupedkey; + for (; t; t = t->rn_dupedkey) + /* + * Even if we don't match exactly as a host, + * we may match if the leaf we wound up at is + * a route to a net. + */ + if (t->rn_flags & RNF_NORMAL) { + if (rn_b <= t->rn_b) + return t; + } else if (rn_satisfies_leaf(v, t, matched_off)) + return t; + t = saved_t; + /* start searching up the tree */ + do { + struct radix_mask *m; + t = t->rn_p; + m = t->rn_mklist; + if (m) { + /* + * If non-contiguous masks ever become important + * we can restore the masking and open coding of + * the search and satisfaction test and put the + * calculation of "off" back before the "do". + */ + do { + if (m->rm_flags & RNF_NORMAL) { + if (rn_b <= m->rm_b) + return (m->rm_leaf); + } else { + off = min(t->rn_off, matched_off); + x = rn_search_m(v, t, m->rm_mask); + while (x && x->rn_mask != m->rm_mask) + x = x->rn_dupedkey; + if (x && rn_satisfies_leaf(v, x, off)) + return x; + } + m = m->rm_mklist; + } while (m); + } + } while (t != top); + return 0; +} + +#ifdef RN_DEBUG +int rn_nodenum; +struct radix_node *rn_clist; +int rn_saveinfo; +int rn_debug = 1; +#endif + +struct radix_node * +rn_newpair(v, b, nodes) + void *v; + int b; + struct radix_node nodes[2]; +{ + struct radix_node *tt = nodes, *t = tt + 1; + t->rn_b = b; + t->rn_bmask = 0x80 >> (b & 7); + t->rn_l = tt; + t->rn_off = b >> 3; + tt->rn_b = -1; + tt->rn_key = (caddr_t)v; + tt->rn_p = t; + tt->rn_flags = t->rn_flags = RNF_ACTIVE; +#ifdef RN_DEBUG + tt->rn_info = rn_nodenum++; + t->rn_info = rn_nodenum++; + tt->rn_twin = t; + tt->rn_ybro = rn_clist; + rn_clist = tt; +#endif + return t; +} + +struct radix_node * +rn_insert(v_arg, head, dupentry, nodes) + void *v_arg; + struct radix_node_head *head; + int *dupentry; + struct radix_node nodes[2]; +{ + caddr_t v = v_arg; + struct radix_node *top = head->rnh_treetop; + int head_off = top->rn_off, vlen = (int)*((u_char *)v); + struct radix_node *t = rn_search(v_arg, top); + caddr_t cp = v + head_off; + int b; + struct radix_node *tt; + +#ifdef RN_DEBUG + if (rn_debug) + log(LOG_DEBUG, "rn_insert(%p,%p,%p,%p)\n", v_arg, head, dupentry, nodes); +#endif + /* + * Find first bit at which v and t->rn_key differ + */ + { + caddr_t cp2 = t->rn_key + head_off; + int cmp_res; + caddr_t cplim = v + vlen; + + while (cp < cplim) + if (*cp2++ != *cp++) + goto on1; + *dupentry = 1; + return t; +on1: + *dupentry = 0; + cmp_res = (cp[-1] ^ cp2[-1]) & 0xff; + for (b = (cp - v) << 3; cmp_res; b--) + cmp_res >>= 1; + } + { + struct radix_node *p, *x = top; + cp = v; + do { + p = x; + if (cp[x->rn_off] & x->rn_bmask) + x = x->rn_r; + else + x = x->rn_l; + } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */ +#ifdef RN_DEBUG + if (rn_debug) + log(LOG_DEBUG, "rn_insert: Going In:\n"); // traverse(p); +#endif + t = rn_newpair(v_arg, b, nodes); + tt = t->rn_l; + if ((cp[p->rn_off] & p->rn_bmask) == 0) + p->rn_l = t; + else + p->rn_r = t; + x->rn_p = t; + t->rn_p = p; /* frees x, p as temp vars below */ + if ((cp[t->rn_off] & t->rn_bmask) == 0) { + t->rn_r = x; + } else { + t->rn_r = tt; + t->rn_l = x; + } +#ifdef RN_DEBUG + if (rn_debug) + log(LOG_DEBUG, "rn_insert: Coming Out:\n"); // traverse(p); +#endif + } + return (tt); +} + +struct radix_node * +rn_addmask(n_arg, search, skip) + int search, skip; + void *n_arg; +{ + caddr_t netmask = (caddr_t)n_arg; + struct radix_node *x; + caddr_t cp, cplim; + int b = 0, mlen, j; + int maskduplicated, m0, isnormal; + struct radix_node *saved_x; + static int last_zeroed = 0; + +#ifdef RN_DEBUG + if (rn_debug) + log(LOG_DEBUG, "rn_addmask(%p,%d,%d)\n", n_arg, search, skip); +#endif + mlen = *(u_char *)netmask; + if ((mlen = *(u_char *)netmask) > max_keylen) + mlen = max_keylen; + if (skip == 0) + skip = 1; + if (mlen <= skip) + return (mask_rnhead->rnh_nodes); + if (skip > 1) + Bcopy(rn_ones + 1, addmask_key + 1, skip - 1); + if ((m0 = mlen) > skip) + Bcopy(netmask + skip, addmask_key + skip, mlen - skip); + /* + * Trim trailing zeroes. + */ + for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;) + cp--; + mlen = cp - addmask_key; + if (mlen <= skip) { + if (m0 >= last_zeroed) + last_zeroed = mlen; + return (mask_rnhead->rnh_nodes); + } + if (m0 < last_zeroed) + Bzero(addmask_key + m0, last_zeroed - m0); + *addmask_key = last_zeroed = mlen; + x = rn_search(addmask_key, rn_masktop); + if (Bcmp(addmask_key, x->rn_key, mlen) != 0) + x = 0; + if (x || search) + return (x); + R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x)); + if ((saved_x = x) == 0) + return (0); + Bzero(x, max_keylen + 2 * sizeof (*x)); + netmask = cp = (caddr_t)(x + 2); + Bcopy(addmask_key, cp, mlen); + x = rn_insert(cp, mask_rnhead, &maskduplicated, x); + if (maskduplicated) { +#if 0 + log(LOG_ERR, "rn_addmask: mask impossibly already in tree\n"); +#endif + Free(saved_x); + return (x); + } + /* + * Calculate index of mask, and check for normalcy. + */ + cplim = netmask + mlen; + isnormal = 1; + for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;) + cp++; + if (cp != cplim) { + for (j = 0x80; (j & *cp) != 0; j >>= 1) + b++; + if (*cp != normal_chars[b] || cp != (cplim - 1)) + isnormal = 0; + } + b += (cp - netmask) << 3; + x->rn_b = -1 - b; + if (isnormal) + x->rn_flags |= RNF_NORMAL; + return (x); +} + +static int /* XXX: arbitrary ordering for non-contiguous masks */ +rn_lexobetter(m_arg, n_arg) + void *m_arg, *n_arg; +{ + u_char *mp = m_arg, *np = n_arg, *lim; + + if (*mp > *np) + return 1; /* not really, but need to check longer one first */ + if (*mp == *np) + for (lim = mp + *mp; mp < lim;) + if (*mp++ > *np++) + return 1; + return 0; +} + +static struct radix_mask * +rn_new_radix_mask(tt, next) + struct radix_node *tt; + struct radix_mask *next; +{ + struct radix_mask *m; + + MKGet(m); + if (m == 0) { +#if 0 + log(LOG_ERR, "Mask for route not entered\n"); +#endif + return (0); + } + Bzero(m, sizeof *m); + m->rm_b = tt->rn_b; + m->rm_flags = tt->rn_flags; + if (tt->rn_flags & RNF_NORMAL) + m->rm_leaf = tt; + else + m->rm_mask = tt->rn_mask; + m->rm_mklist = next; + tt->rn_mklist = m; + return m; +} + +struct radix_node * +rn_addroute(v_arg, n_arg, head, treenodes) + void *v_arg, *n_arg; + struct radix_node_head *head; + struct radix_node treenodes[2]; +{ + caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg; + struct radix_node *t, *x = NULL, *tt; + struct radix_node *saved_tt, *top = head->rnh_treetop; + short b = 0, b_leaf = 0; + int keyduplicated; + caddr_t mmask; + struct radix_mask *m, **mp; + +#ifdef RN_DEBUG + if (rn_debug) + log(LOG_DEBUG, "rn_addroute(%p,%p,%p,%p)\n", v_arg, n_arg, head, treenodes); +#endif + /* + * In dealing with non-contiguous masks, there may be + * many different routes which have the same mask. + * We will find it useful to have a unique pointer to + * the mask to speed avoiding duplicate references at + * nodes and possibly save time in calculating indices. + */ + if (netmask) { + if ((x = rn_addmask(netmask, 0, top->rn_off)) == 0) + return (0); + b_leaf = x->rn_b; + b = -1 - x->rn_b; + netmask = x->rn_key; + } + /* + * Deal with duplicated keys: attach node to previous instance + */ + saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes); + if (keyduplicated) { + for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) { + if (tt->rn_mask == netmask) + return (0); + if (netmask == 0 || + (tt->rn_mask && + ((b_leaf < tt->rn_b) || /* index(netmask) > node */ + rn_refines(netmask, tt->rn_mask) || + rn_lexobetter(netmask, tt->rn_mask)))) + break; + } + /* + * If the mask is not duplicated, we wouldn't + * find it among possible duplicate key entries + * anyway, so the above test doesn't hurt. + * + * We sort the masks for a duplicated key the same way as + * in a masklist -- most specific to least specific. + * This may require the unfortunate nuisance of relocating + * the head of the list. + * + * We also reverse, or doubly link the list through the + * parent pointer. + */ + if (tt == saved_tt) { + struct radix_node *xx = x; + /* link in at head of list */ + (tt = treenodes)->rn_dupedkey = t; + tt->rn_flags = t->rn_flags; + tt->rn_p = x = t->rn_p; + t->rn_p = tt; + if (x->rn_l == t) + x->rn_l = tt; + else + x->rn_r = tt; + saved_tt = tt; + x = xx; + } else { + (tt = treenodes)->rn_dupedkey = t->rn_dupedkey; + t->rn_dupedkey = tt; + tt->rn_p = t; + if (tt->rn_dupedkey) + tt->rn_dupedkey->rn_p = tt; + } +#ifdef RN_DEBUG + t=tt+1; + tt->rn_info = rn_nodenum++; + t->rn_info = rn_nodenum++; + tt->rn_twin = t; + tt->rn_ybro = rn_clist; + rn_clist = tt; +#endif + tt->rn_key = (caddr_t) v; + tt->rn_b = -1; + tt->rn_flags = RNF_ACTIVE; + } + /* + * Put mask in tree. + */ + if (netmask) { + tt->rn_mask = netmask; + tt->rn_b = x->rn_b; + tt->rn_flags |= x->rn_flags & RNF_NORMAL; + } + t = saved_tt->rn_p; + if (keyduplicated) + goto on2; + b_leaf = -1 - t->rn_b; + if (t->rn_r == saved_tt) + x = t->rn_l; + else + x = t->rn_r; + /* Promote general routes from below */ + if (x->rn_b < 0) { + for (mp = &t->rn_mklist; x; x = x->rn_dupedkey) + if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) { + *mp = m = rn_new_radix_mask(x, 0); + if (m) + mp = &m->rm_mklist; + } + } else if (x->rn_mklist) { + /* + * Skip over masks whose index is > that of new node + */ + for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist) + if (m->rm_b >= b_leaf) + break; + t->rn_mklist = m; + *mp = 0; + } +on2: + /* Add new route to highest possible ancestor's list */ + if ((netmask == 0) || (b > t->rn_b )) + return tt; /* can't lift at all */ + b_leaf = tt->rn_b; + do { + x = t; + t = t->rn_p; + } while (b <= t->rn_b && x != top); + /* + * Search through routes associated with node to + * insert new route according to index. + * Need same criteria as when sorting dupedkeys to avoid + * double loop on deletion. + */ + for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist) { + if (m->rm_b < b_leaf) + continue; + if (m->rm_b > b_leaf) + break; + if (m->rm_flags & RNF_NORMAL) { + mmask = m->rm_leaf->rn_mask; + if (tt->rn_flags & RNF_NORMAL) { +#if 0 + log(LOG_ERR, "Non-unique normal route," + " mask not entered\n"); +#endif + return tt; + } + } else + mmask = m->rm_mask; + if (mmask == netmask) { + m->rm_refs++; + tt->rn_mklist = m; + return tt; + } + if (rn_refines(netmask, mmask) + || rn_lexobetter(netmask, mmask)) + break; + } + *mp = rn_new_radix_mask(tt, *mp); + return tt; +} + +struct radix_node * +rn_delete(v_arg, netmask_arg, head) + void *v_arg, *netmask_arg; + struct radix_node_head *head; +{ + struct radix_node *t, *p, *x, *tt; + struct radix_mask *m, *saved_m, **mp; + struct radix_node *dupedkey, *saved_tt, *top; + caddr_t v, netmask; + int b, head_off, vlen; + + v = v_arg; + netmask = netmask_arg; + x = head->rnh_treetop; + tt = rn_search(v, x); + head_off = x->rn_off; + vlen = *(u_char *)v; + saved_tt = tt; + top = x; + if (tt == 0 || + Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off)) + return (0); + /* + * Delete our route from mask lists. + */ + if (netmask) { + if ((x = rn_addmask(netmask, 1, head_off)) == 0) + return (0); + netmask = x->rn_key; + while (tt->rn_mask != netmask) + if ((tt = tt->rn_dupedkey) == 0) + return (0); + } + if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0) + goto on1; + if (tt->rn_flags & RNF_NORMAL) { + if (m->rm_leaf != tt || m->rm_refs > 0) { +#if 0 + log(LOG_ERR, "rn_delete: inconsistent annotation\n"); +#endif + return 0; /* dangling ref could cause disaster */ + } + } else { + if (m->rm_mask != tt->rn_mask) { +#if 0 + log(LOG_ERR, "rn_delete: inconsistent annotation\n"); +#endif + goto on1; + } + if (--m->rm_refs >= 0) + goto on1; + } + b = -1 - tt->rn_b; + t = saved_tt->rn_p; + if (b > t->rn_b) + goto on1; /* Wasn't lifted at all */ + do { + x = t; + t = t->rn_p; + } while (b <= t->rn_b && x != top); + for (mp = &x->rn_mklist; (m = *mp) != NULL; mp = &m->rm_mklist) + if (m == saved_m) { + *mp = m->rm_mklist; + MKFree(m); + break; + } + if (m == 0) { +#if 0 + log(LOG_ERR, "rn_delete: couldn't find our annotation\n"); +#endif + if (tt->rn_flags & RNF_NORMAL) + return (0); /* Dangling ref to us */ + } +on1: + /* + * Eliminate us from tree + */ + if (tt->rn_flags & RNF_ROOT) + return (0); +#ifdef RN_DEBUG + /* Get us out of the creation list */ + for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) + ; + if (t) t->rn_ybro = tt->rn_ybro; +#endif + t = tt->rn_p; + dupedkey = saved_tt->rn_dupedkey; + if (dupedkey) { + /* + * Here, tt is the deletion target and + * saved_tt is the head of the dupedkey chain. + */ + if (tt == saved_tt) { + x = dupedkey; + x->rn_p = t; + if (t->rn_l == tt) + t->rn_l = x; + else + t->rn_r = x; + } else { + /* find node in front of tt on the chain */ + for (x = p = saved_tt; p && p->rn_dupedkey != tt;) + p = p->rn_dupedkey; + if (p) { + p->rn_dupedkey = tt->rn_dupedkey; + if (tt->rn_dupedkey) + tt->rn_dupedkey->rn_p = p; + } +#if 0 + else + log(LOG_ERR, "rn_delete: couldn't find us\n"); +#endif + } + t = tt + 1; + if (t->rn_flags & RNF_ACTIVE) { +#ifndef RN_DEBUG + *++x = *t; + p = t->rn_p; +#else + b = t->rn_info; + *++x = *t; + t->rn_info = b; + p = t->rn_p; +#endif + if (p->rn_l == t) + p->rn_l = x; + else + p->rn_r = x; + x->rn_l->rn_p = x; + x->rn_r->rn_p = x; + } + goto out; + } + if (t->rn_l == tt) + x = t->rn_r; + else + x = t->rn_l; + p = t->rn_p; + if (p->rn_r == t) + p->rn_r = x; + else + p->rn_l = x; + x->rn_p = p; + /* + * Demote routes attached to us. + */ + if (t->rn_mklist) { + if (x->rn_b >= 0) { + for (mp = &x->rn_mklist; (m = *mp) != NULL;) + mp = &m->rm_mklist; + *mp = t->rn_mklist; + } else { + /* If there are any key,mask pairs in a sibling + duped-key chain, some subset will appear sorted + in the same order attached to our mklist */ + for (m = t->rn_mklist; m && x; x = x->rn_dupedkey) + if (m == x->rn_mklist) { + struct radix_mask *mm = m->rm_mklist; + x->rn_mklist = 0; + if (--(m->rm_refs) < 0) + MKFree(m); + m = mm; + } +#if 0 + if (m) + log(LOG_ERR, "%s %p at %p\n", + "rn_delete: Orphaned Mask", m, x); +#endif + } + } + /* + * We may be holding an active internal node in the tree. + */ + x = tt + 1; + if (t != x) { +#ifndef RN_DEBUG + *t = *x; +#else + b = t->rn_info; + *t = *x; + t->rn_info = b; +#endif + t->rn_l->rn_p = t; + t->rn_r->rn_p = t; + p = x->rn_p; + if (p->rn_l == x) + p->rn_l = t; + else + p->rn_r = t; + } +out: + tt->rn_flags &= ~RNF_ACTIVE; + tt[1].rn_flags &= ~RNF_ACTIVE; + return (tt); +} + +int +rn_walktree(h, f, w) + struct radix_node_head *h; + int (*f) __P((struct radix_node *, void *)); + void *w; +{ + int error; + struct radix_node *base, *next; + struct radix_node *rn = h->rnh_treetop; + /* + * This gets complicated because we may delete the node + * while applying the function f to it, so we need to calculate + * the successor node in advance. + */ + /* First time through node, go left */ + while (rn->rn_b >= 0) + rn = rn->rn_l; + for (;;) { + base = rn; + /* If at right child go back up, otherwise, go right */ + while (rn->rn_p->rn_r == rn && (rn->rn_flags & RNF_ROOT) == 0) + rn = rn->rn_p; + /* Find the next *leaf* since next node might vanish, too */ + for (rn = rn->rn_p->rn_r; rn->rn_b >= 0;) + rn = rn->rn_l; + next = rn; + /* Process leaves */ + while ((rn = base) != NULL) { + base = rn->rn_dupedkey; + if (!(rn->rn_flags & RNF_ROOT) + && (error = (*f)(rn, w))) + return (error); + } + rn = next; + if (rn->rn_flags & RNF_ROOT) + return (0); + } + /* NOTREACHED */ +} + +int +rn_inithead(head, off) + void **head; + int off; +{ + struct radix_node_head *rnh; + + if (*head) + return (1); + R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh)); + if (rnh == 0) + return (0); + *head = rnh; + return rn_inithead0(rnh, off); +} + +int +rn_inithead0(rnh, off) + struct radix_node_head *rnh; + int off; +{ + struct radix_node *t, *tt, *ttt; + + Bzero(rnh, sizeof (*rnh)); + t = rn_newpair(rn_zeros, off, rnh->rnh_nodes); + ttt = rnh->rnh_nodes + 2; + t->rn_r = ttt; + t->rn_p = t; + tt = t->rn_l; + tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE; + tt->rn_b = -1 - off; + *ttt = *tt; + ttt->rn_key = rn_ones; + rnh->rnh_addaddr = rn_addroute; + rnh->rnh_deladdr = rn_delete; + rnh->rnh_matchaddr = rn_match; + rnh->rnh_lookup = rn_lookup; + rnh->rnh_walktree = rn_walktree; + rnh->rnh_treetop = t; + return (1); +} + +void +rn_init() +{ + char *cp, *cplim; + + if (max_keylen == 0) { +#if 0 + log(LOG_ERR, + "rn_init: radix functions require max_keylen be set\n"); +#endif + return; + } + if (rn_zeros == NULL) { + R_Malloc(rn_zeros, char *, 3 * max_keylen); + } + if (rn_zeros == NULL) + panic("rn_init"); + Bzero(rn_zeros, 3 * max_keylen); + rn_ones = cp = rn_zeros + max_keylen; + addmask_key = cplim = rn_ones + max_keylen; + while (cp < cplim) + *cp++ = -1; + if (rn_inithead((void *)&mask_rnhead, 0) == 0) + panic("rn_init 2"); +} + + +static int +rn_freenode(struct radix_node *n, void *p) +{ + struct radix_node_head *rnh = p; + struct radix_node *d; + + d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); + if (d != NULL) { + FreeS(d, max_keylen + 2 * sizeof (*d)); + } + return 0; +} + + +void +rn_freehead(rnh) + struct radix_node_head *rnh; +{ + + (void)rn_walktree(rnh, rn_freenode, rnh); + + rnh->rnh_addaddr = NULL; + rnh->rnh_deladdr = NULL; + rnh->rnh_matchaddr = NULL; + rnh->rnh_lookup = NULL; + rnh->rnh_walktree = NULL; + + Free(rnh); +} + + +void +rn_fini() +{ + struct radix_mask *m; + + if (rn_zeros != NULL) { + FreeS(rn_zeros, 3 * max_keylen); + rn_zeros = NULL; + } + + if (mask_rnhead != NULL) { + rn_freehead(mask_rnhead); + mask_rnhead = NULL; + } + + while ((m = rn_mkfreelist) != NULL) { + rn_mkfreelist = m->rm_mklist; + KFREE(m); + } +} + + +#ifdef USE_MAIN + +typedef struct myst { + addrfamily_t dst; + addrfamily_t mask; + struct radix_node nodes[2]; +} myst_t; + +int +main(int argc, char *argv[]) +{ + struct radix_node_head *rnh; + struct radix_node *rn; + addrfamily_t af, mf; + myst_t st1, st2, *stp; + + memset(&st1, 0, sizeof(st1)); + memset(&st2, 0, sizeof(st2)); + memset(&af, 0, sizeof(af)); + + rn_init(); + + rnh = NULL; + rn_inithead(&rnh, offsetof(addrfamily_t, adf_addr) << 3); + + st1.dst.adf_len = sizeof(st1); + st1.mask.adf_len = sizeof(st1); + st1.dst.adf_addr.in4.s_addr = inet_addr("127.0.0.0"); + st1.mask.adf_addr.in4.s_addr = inet_addr("255.0.0.0"); + rn = rnh->rnh_addaddr(&st1.dst, &st1.mask, rnh, st1.nodes); + printf("add.1 %p\n", rn); + + st2.dst.adf_len = sizeof(st2); + st2.mask.adf_len = sizeof(st2); + st2.dst.adf_addr.in4.s_addr = inet_addr("127.0.1.0"); + st2.mask.adf_addr.in4.s_addr = inet_addr("255.255.255.0"); + rn = rnh->rnh_addaddr(&st2.dst, &st2.mask, rnh, st2.nodes); + printf("add.2 %p\n", rn); + + af.adf_len = sizeof(af); + af.adf_addr.in4.s_addr = inet_addr("127.0.1.0"); + rn = rnh->rnh_matchaddr(&af, rnh); + if (rn != NULL) { + printf("1.lookup = %p key %p mask %p\n", rn, rn->rn_key, rn->rn_mask); + stp = rn->rn_key; + printf("%s/", inet_ntoa(stp->dst.adf_addr.in4)); + stp = rn->rn_mask; + printf("%s\n", inet_ntoa(stp->dst.adf_addr.in4)); + } + + mf.adf_len = sizeof(mf); + mf.adf_addr.in4.s_addr = inet_addr("255.255.255.0"); + rn = rnh->rnh_lookup(&af, &mf, rnh); + if (rn != NULL) { + printf("2.lookup = %p key %p mask %p\n", rn, rn->rn_key, rn->rn_mask); + stp = rn->rn_key; + printf("%s/", inet_ntoa(stp->dst.adf_addr.in4)); + stp = rn->rn_mask; + printf("%s\n", inet_ntoa(stp->dst.adf_addr.in4)); + } + + af.adf_len = sizeof(af); + af.adf_addr.in4.s_addr = inet_addr("126.0.0.1"); + rn = rnh->rnh_matchaddr(&af, rnh); + if (rn != NULL) { + printf("3.lookup = %p key %p mask %p\n", rn, rn->rn_key, rn->rn_mask); + stp = rn->rn_key; + printf("%s/", inet_ntoa(stp->dst.adf_addr.in4)); + stp = rn->rn_mask; + printf("%s\n", inet_ntoa(stp->dst.adf_addr.in4)); + } + + return 0; +} + + +void +log(int level, char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); +} +#endif + + +#ifndef _KERNEL +void +panic(char *str) +{ + fputs(str, stderr); + abort(); +} +#endif diff --git a/contrib/ipfilter/radix_ipf.h b/contrib/ipfilter/radix_ipf.h new file mode 100644 index 0000000..1dada60 --- /dev/null +++ b/contrib/ipfilter/radix_ipf.h @@ -0,0 +1,208 @@ +/* $NetBSD$ */ + +/* + * Copyright (c) 1988, 1989, 1993 + * The Regents of the University of California. 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 REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * @(#)radix.h 8.2 (Berkeley) 10/31/94 + */ + +#ifndef _NET_RADIX_H_ +#define _NET_RADIX_H_ +#ifndef _RADIX_H_ +#define _RADIX_H_ +#endif /* _RADIX_H_ */ + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +#ifdef __sgi +# define radix_mask ipf_radix_mask +# define radix_node ipf_radix_node +# define radix_node_head ipf_radix_node_head +#endif + +/* + * Radix search tree node layout. + */ + +struct radix_node { + struct radix_mask *rn_mklist; /* list of masks contained in subtree */ + struct radix_node *rn_p; /* parent */ + short rn_b; /* bit offset; -1-index(netmask) */ + char rn_bmask; /* node: mask for bit test*/ + u_char rn_flags; /* enumerated next */ +#define RNF_NORMAL 1 /* leaf contains normal route */ +#define RNF_ROOT 2 /* leaf is root leaf for tree */ +#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */ + union { + struct { /* leaf only data: */ + caddr_t rn_Key; /* object of search */ + caddr_t rn_Mask; /* netmask, if present */ + struct radix_node *rn_Dupedkey; + } rn_leaf; + struct { /* node only data: */ + int rn_Off; /* where to start compare */ + struct radix_node *rn_L;/* progeny */ + struct radix_node *rn_R;/* progeny */ + } rn_node; + } rn_u; +#ifdef RN_DEBUG + int rn_info; + struct radix_node *rn_twin; + struct radix_node *rn_ybro; +#endif +}; + +#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey +#define rn_key rn_u.rn_leaf.rn_Key +#define rn_mask rn_u.rn_leaf.rn_Mask +#define rn_off rn_u.rn_node.rn_Off +#define rn_l rn_u.rn_node.rn_L +#define rn_r rn_u.rn_node.rn_R + +/* + * Annotations to tree concerning potential routes applying to subtrees. + */ + +struct radix_mask { + short rm_b; /* bit offset; -1-index(netmask) */ + char rm_unused; /* cf. rn_bmask */ + u_char rm_flags; /* cf. rn_flags */ + struct radix_mask *rm_mklist; /* more masks to try */ + union { + caddr_t rmu_mask; /* the mask */ + struct radix_node *rmu_leaf; /* for normal routes */ + } rm_rmu; + int rm_refs; /* # of references to this struct */ +}; + +#define rm_mask rm_rmu.rmu_mask +#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */ + +#define MKGet(m) {\ + if (rn_mkfreelist) {\ + m = rn_mkfreelist; \ + rn_mkfreelist = (m)->rm_mklist; \ + } else \ + R_Malloc(m, struct radix_mask *, sizeof (*(m))); }\ + +#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);} + +struct radix_node_head { + struct radix_node *rnh_treetop; + struct radix_node *rnh_leaflist; + u_long rnh_hits; + u_int rnh_number; + u_int rnh_ref; + int rnh_addrsize; /* permit, but not require fixed keys */ + int rnh_pktsize; /* permit, but not require fixed keys */ + struct radix_node *(*rnh_addaddr) /* add based on sockaddr */ + __P((void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[])); + struct radix_node *(*rnh_addpkt) /* add based on packet hdr */ + __P((void *v, void *mask, + struct radix_node_head *head, struct radix_node nodes[])); + struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */ + __P((void *v, void *mask, struct radix_node_head *head)); + struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */ + __P((void *v, void *mask, struct radix_node_head *head)); + struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */ + __P((void *v, struct radix_node_head *head)); + struct radix_node *(*rnh_lookup) /* locate based on sockaddr */ + __P((void *v, void *mask, struct radix_node_head *head)); + struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */ + __P((void *v, struct radix_node_head *head)); + int (*rnh_walktree) /* traverse tree */ + __P((struct radix_node_head *, + int (*)(struct radix_node *, void *), void *)); + struct radix_node rnh_nodes[3]; /* empty tree for common case */ +}; + + +#define Bcmp(a, b, n) bcmp(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n)) +#if defined(linux) && defined(_KERNEL) +# define Bcopy(a, b, n) memmove(((caddr_t)(b)), ((caddr_t)(a)), (unsigned)(n)) +#else +# define Bcopy(a, b, n) bcopy(((caddr_t)(a)), ((caddr_t)(b)), (unsigned)(n)) +#endif +#define Bzero(p, n) bzero((caddr_t)(p), (unsigned)(n)); +#define R_Malloc(p, t, n) KMALLOCS(p, t, n) +#define FreeS(p, z) KFREES(p, z) +#define Free(p) KFREE(p) + +#if (defined(__osf__) || (IRIX >= 60516)) && defined(_KERNEL) +# define rn_init ipf_rn_init +# define rn_fini ipf_rn_fini +# define rn_inithead ipf_rn_inithead +# define rn_freehead ipf_rn_freehead +# define rn_inithead0 ipf_rn_inithead0 +# define rn_refines ipf_rn_refines +# define rn_walktree ipf_rn_walktree +# define rn_addmask ipf_rn_addmask +# define rn_addroute ipf_rn_addroute +# define rn_delete ipf_rn_delete +# define rn_insert ipf_rn_insert +# define rn_lookup ipf_rn_lookup +# define rn_match ipf_rn_match +# define rn_newpair ipf_rn_newpair +# define rn_search ipf_rn_search +# define rn_search_m ipf_rn_search_m +# define max_keylen ipf_maxkeylen +# define rn_mkfreelist ipf_rn_mkfreelist +# define rn_zeros ipf_rn_zeros +# define rn_ones ipf_rn_ones +# define rn_satisfies_leaf ipf_rn_satisfies_leaf +# define rn_lexobetter ipf_rn_lexobetter +# define rn_new_radix_mask ipf_rn_new_radix_mask +# define rn_freenode ipf_rn_freenode +#endif + +void rn_init __P((void)); +void rn_fini __P((void)); +int rn_inithead __P((void **, int)); +void rn_freehead __P((struct radix_node_head *)); +int rn_inithead0 __P((struct radix_node_head *, int)); +int rn_refines __P((void *, void *)); +int rn_walktree __P((struct radix_node_head *, + int (*)(struct radix_node *, void *), void *)); +struct radix_node + *rn_addmask __P((void *, int, int)), + *rn_addroute __P((void *, void *, struct radix_node_head *, + struct radix_node [2])), + *rn_delete __P((void *, void *, struct radix_node_head *)), + *rn_insert __P((void *, struct radix_node_head *, int *, + struct radix_node [2])), + *rn_lookup __P((void *, void *, struct radix_node_head *)), + *rn_match __P((void *, struct radix_node_head *)), + *rn_newpair __P((void *, int, struct radix_node[2])), + *rn_search __P((void *, struct radix_node *)), + *rn_search_m __P((void *, struct radix_node *, void *)); + +#endif /* _NET_RADIX_H_ */ diff --git a/contrib/ipfilter/rules/.cvsignore b/contrib/ipfilter/rules/.cvsignore new file mode 100644 index 0000000..3e75765 --- /dev/null +++ b/contrib/ipfilter/rules/.cvsignore @@ -0,0 +1 @@ +new diff --git a/contrib/ipfilter/rules/example.1 b/contrib/ipfilter/rules/example.1 index ff93f49..3da9f3c 100644 --- a/contrib/ipfilter/rules/example.1 +++ b/contrib/ipfilter/rules/example.1 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # block all incoming TCP packets on le0 from host 10.1.1.1 to any destination. # diff --git a/contrib/ipfilter/rules/example.10 b/contrib/ipfilter/rules/example.10 index 560d1e6..f7a0b01 100644 --- a/contrib/ipfilter/rules/example.10 +++ b/contrib/ipfilter/rules/example.10 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # pass ack packets (ie established connection) # diff --git a/contrib/ipfilter/rules/example.11 b/contrib/ipfilter/rules/example.11 index c6b4e7f..1cefa9a 100644 --- a/contrib/ipfilter/rules/example.11 +++ b/contrib/ipfilter/rules/example.11 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # allow any TCP packets from the same subnet as foo is on through to host # 10.1.1.2 if they are destined for port 6667. diff --git a/contrib/ipfilter/rules/example.12 b/contrib/ipfilter/rules/example.12 index c0ba1d3..6dbaef5 100644 --- a/contrib/ipfilter/rules/example.12 +++ b/contrib/ipfilter/rules/example.12 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # get rid of all short IP fragments (too small for valid comparison) # diff --git a/contrib/ipfilter/rules/example.13 b/contrib/ipfilter/rules/example.13 index 854f07f..ca74114 100644 --- a/contrib/ipfilter/rules/example.13 +++ b/contrib/ipfilter/rules/example.13 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # Log all short TCP packets to qe3, with 10.3.3.3 as the intended # destination for the packet. diff --git a/contrib/ipfilter/rules/example.2 b/contrib/ipfilter/rules/example.2 index 4f81725..81e7d25 100644 --- a/contrib/ipfilter/rules/example.2 +++ b/contrib/ipfilter/rules/example.2 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # block all outgoing TCP packets on le0 from any host to port 23 of # host 10.1.1.2 diff --git a/contrib/ipfilter/rules/example.3 b/contrib/ipfilter/rules/example.3 index cd31f73..c5b4344 100644 --- a/contrib/ipfilter/rules/example.3 +++ b/contrib/ipfilter/rules/example.3 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # block all inbound packets. # diff --git a/contrib/ipfilter/rules/example.4 b/contrib/ipfilter/rules/example.4 index 7918ec2..f18dcdd 100644 --- a/contrib/ipfilter/rules/example.4 +++ b/contrib/ipfilter/rules/example.4 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # block all ICMP packets. # diff --git a/contrib/ipfilter/rules/example.5 b/contrib/ipfilter/rules/example.5 index 6d688b5..959dfb8 100644 --- a/contrib/ipfilter/rules/example.5 +++ b/contrib/ipfilter/rules/example.5 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # test ruleset # diff --git a/contrib/ipfilter/rules/example.6 b/contrib/ipfilter/rules/example.6 index d40f0f3..e9ce23a 100644 --- a/contrib/ipfilter/rules/example.6 +++ b/contrib/ipfilter/rules/example.6 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # block all TCP packets with only the SYN flag set (this is the first # packet sent to establish a connection) out of the SYN-ACK pair. diff --git a/contrib/ipfilter/rules/example.7 b/contrib/ipfilter/rules/example.7 index 062de98..0ddd7f7 100644 --- a/contrib/ipfilter/rules/example.7 +++ b/contrib/ipfilter/rules/example.7 @@ -1,3 +1,4 @@ +# $FreeBSD$ # block all ICMP packets. # block in proto icmp all diff --git a/contrib/ipfilter/rules/example.8 b/contrib/ipfilter/rules/example.8 index baa0258..2276b52 100644 --- a/contrib/ipfilter/rules/example.8 +++ b/contrib/ipfilter/rules/example.8 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # block all incoming TCP connections but send back a TCP-RST for ones to # the ident port diff --git a/contrib/ipfilter/rules/example.9 b/contrib/ipfilter/rules/example.9 index daff203..50bb46a 100644 --- a/contrib/ipfilter/rules/example.9 +++ b/contrib/ipfilter/rules/example.9 @@ -1,3 +1,4 @@ +# $FreeBSD$ # # drop all packets without IP security options # diff --git a/contrib/ipfilter/rules/example.sr b/contrib/ipfilter/rules/example.sr index c4c1994..46fb6f1 100644 --- a/contrib/ipfilter/rules/example.sr +++ b/contrib/ipfilter/rules/example.sr @@ -1,3 +1,4 @@ +# $FreeBSD$ # # log all inbound packet on le0 which has IP options present # diff --git a/contrib/ipfilter/rules/ip_rules b/contrib/ipfilter/rules/ip_rules new file mode 100644 index 0000000..9850f16 --- /dev/null +++ b/contrib/ipfilter/rules/ip_rules @@ -0,0 +1,3 @@ +# Used to generate ../ip_rules.c and ../ip_rules.h +pass in all +pass out all diff --git a/contrib/ipfilter/rules/ipmon.conf b/contrib/ipfilter/rules/ipmon.conf new file mode 100644 index 0000000..47b0146 --- /dev/null +++ b/contrib/ipfilter/rules/ipmon.conf @@ -0,0 +1,24 @@ +# +# +# +# +match { logtag = 10000 } + do { execute "/usr/bin/mail -s 'logtag 10000' root" }; +match { logtag = 2000, every 10 seconds } + do { execute "echo 'XXXXXXXX tag 2000 packet XXXXXXXX'" }; +# +match { protocol = udp, result = block } + do { execute "/usr/bin/mail -s 'blocked udp' root" +}; +# +match { + srcip = 10.1.0.0/16, dstip = 192.168.1.0/24 } + do { execute "/usr/bin/mail -s 'from 10.1 to 192.168.1' root" +}; +# +match { + rule = 12, logtag = 101, direction = in, result = block, + protocol = udp, srcip = 10.1.0.0/16, dstip = 192.168.1.0/24 } + do { execute "run shell command" +}; +# diff --git a/contrib/ipfilter/rules/pool.conf b/contrib/ipfilter/rules/pool.conf new file mode 100644 index 0000000..285398d --- /dev/null +++ b/contrib/ipfilter/rules/pool.conf @@ -0,0 +1,4 @@ +# +pool 0 = { !10.0.0.0 - 10.255.255.255, 10.1.0.0 - 10.1.255.255, + 10.1.1.0 - 10.1.1.255, !10.1.2.0 - 10.2.2.255, + 10.1.2.3 - 10.1.2.3, 10.1.2.15 - 10.1.2.15 }; diff --git a/contrib/ipfilter/samples/.cvsignore b/contrib/ipfilter/samples/.cvsignore new file mode 100644 index 0000000..4d38251 --- /dev/null +++ b/contrib/ipfilter/samples/.cvsignore @@ -0,0 +1,4 @@ +userauth +proxy +relay +trans_relay diff --git a/contrib/ipfilter/samples/Makefile b/contrib/ipfilter/samples/Makefile index 1dad079..47ab4a2 100644 --- a/contrib/ipfilter/samples/Makefile +++ b/contrib/ipfilter/samples/Makefile @@ -11,14 +11,14 @@ all: @echo "make sunos5" sunos5: - $(CC) -DSOLARIS2=`uname -r | sh -c 'IFS=. read j n x; echo $$n'` \ - -I.. userauth.c -o userauth -lsocket -lnsl - $(CC) -DSOLARIS2=`uname -r | sh -c 'IFS=. read j n x; echo $$n'` \ - -I.. proxy.c -o proxy -lsocket -lnsl + $(CC) -I.. userauth.c -o userauth -lsocket -lnsl + $(CC) -I.. proxy.c -o proxy -lsocket -lnsl + $(CC) -I.. relay.c -o relay -lsocket -lnsl freebsd freebsd22 netbsd bsd bsdi sunos4 openbsd: $(CC) -I.. userauth.c -o userauth $(CC) -I.. proxy.c -o proxy + $(CC) -I.. relay.c -o relay clean: - /bin/rm -f userauth proxy + /bin/rm -f userauth proxy relay diff --git a/contrib/ipfilter/samples/ipfilter-pb.gif b/contrib/ipfilter/samples/ipfilter-pb.gif Binary files differindex afaefa8..f729ab1 100644 --- a/contrib/ipfilter/samples/ipfilter-pb.gif +++ b/contrib/ipfilter/samples/ipfilter-pb.gif diff --git a/contrib/ipfilter/samples/proxy.c b/contrib/ipfilter/samples/proxy.c index ef9a69c..ccf2ac6 100644 --- a/contrib/ipfilter/samples/proxy.c +++ b/contrib/ipfilter/samples/proxy.c @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Sample transparent proxy program. * @@ -45,6 +47,7 @@ #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" +#include "netinet/ipl.h" main(argc, argv) @@ -52,6 +55,7 @@ int argc; char *argv[]; { struct sockaddr_in sin, sloc, sout; + ipfobj_t obj; natlookup_t natlook; natlookup_t *natlookp = &natlook; char buffer[512]; @@ -77,21 +81,27 @@ char *argv[]; exit(-1); } + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(natlook); + obj.ipfo_ptr = &natlook; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + /* * Build up the NAT natlookup structure. */ bzero((char *)&natlook, sizeof(natlook)); natlook.nl_outip = sin.sin_addr; natlook.nl_inip = sloc.sin_addr; - natlook.nl_flags = IPN_TCPUDP; + natlook.nl_flags = IPN_TCP; natlook.nl_outport = ntohs(sin.sin_port); natlook.nl_inport = ntohs(sloc.sin_port); /* * Open the NAT device and lookup the mapping pair. */ - fd = open(IPL_NAT, O_RDONLY); - if (ioctl(fd, SIOCGNATL, &natlookp) == -1) { + fd = open(IPNAT_NAME, O_RDONLY); + if (ioctl(fd, SIOCGNATL, &obj) == -1) { perror("ioctl(SIOCGNATL)"); exit(-1); } @@ -131,6 +141,7 @@ char *extif; struct sockaddr_in usin; u_32_t sum1, sum2, sumd; int onoff, ofd, slen; + ipfobj_t obj; ipnat_t *ipn; nat_t *nat; @@ -140,8 +151,12 @@ char *extif; nat->nat_p = IPPROTO_TCP; nat->nat_dir = NAT_OUTBOUND; if ((extif != NULL) && (*extif != '\0')) { - strncpy(nat->nat_ifname, extif, sizeof(nat->nat_ifname)); - nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0'; + strncpy(nat->nat_ifnames[0], extif, + sizeof(nat->nat_ifnames[0])); + strncpy(nat->nat_ifnames[1], extif, + sizeof(nat->nat_ifnames[1])); + nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0'; + nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0'; } ofd = socket(AF_INET, SOCK_DGRAM, 0); @@ -186,9 +201,15 @@ printf("local port# to use: %d\n", ntohs(usin.sin_port)); nat->nat_flags = IPN_TCPUDP; + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*nsp); + obj.ipfo_ptr = nsp; + obj.ipfo_type = IPFOBJ_NATSAVE; + onoff = 1; if (ioctl(fd, SIOCSTLCK, &onoff) == 0) { - if (ioctl(fd, SIOCSTPUT, &nsp) != 0) + if (ioctl(fd, SIOCSTPUT, &obj) != 0) perror("SIOCSTPUT"); onoff = 0; if (ioctl(fd, SIOCSTLCK, &onoff) != 0) diff --git a/contrib/ipfilter/samples/relay.c b/contrib/ipfilter/samples/relay.c new file mode 100644 index 0000000..b91779a --- /dev/null +++ b/contrib/ipfilter/samples/relay.c @@ -0,0 +1,196 @@ +/* $NetBSD$ */ + +/* + * Sample program to be used as a transparent proxy. + * + * Must be executed with permission enough to do an ioctl on /dev/ipl + * or equivalent. This is just a sample and is only alpha quality. + * - Darren Reed (8 April 1996) + */ +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <net/if.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_nat.h" +#include "ipl.h" + +#define RELAY_BUFSZ 8192 + +char ibuff[RELAY_BUFSZ]; +char obuff[RELAY_BUFSZ]; + +int relay(ifd, ofd, rfd) +int ifd, ofd, rfd; +{ + fd_set rfds, wfds; + char *irh, *irt, *rrh, *rrt; + char *iwh, *iwt, *rwh, *rwt; + int nfd, n, rw; + + irh = irt = ibuff; + iwh = iwt = obuff; + nfd = ifd; + if (nfd < ofd) + nfd = ofd; + if (nfd < rfd) + nfd = rfd; + + while (1) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + if (irh > irt) + FD_SET(rfd, &wfds); + if (irh < (ibuff + RELAY_BUFSZ)) + FD_SET(ifd, &rfds); + if (iwh > iwt) + FD_SET(ofd, &wfds); + if (iwh < (obuff + RELAY_BUFSZ)) + FD_SET(rfd, &rfds); + + switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL))) + { + case -1 : + case 0 : + return -1; + default : + if (FD_ISSET(ifd, &rfds)) { + rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh); + if (rw == -1) + return -1; + if (rw == 0) + return 0; + irh += rw; + n--; + } + if (n && FD_ISSET(ofd, &wfds)) { + rw = write(ofd, iwt, iwh - iwt); + if (rw == -1) + return -1; + iwt += rw; + n--; + } + if (n && FD_ISSET(rfd, &rfds)) { + rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh); + if (rw == -1) + return -1; + if (rw == 0) + return 0; + iwh += rw; + n--; + } + if (n && FD_ISSET(rfd, &wfds)) { + rw = write(rfd, irt, irh - irt); + if (rw == -1) + return -1; + irt += rw; + n--; + } + if (irh == irt) + irh = irt = ibuff; + if (iwh == iwt) + iwh = iwt = obuff; + } + } +} + +main(argc, argv) +int argc; +char *argv[]; +{ + struct sockaddr_in sin; + ipfobj_t obj; + natlookup_t nl; + natlookup_t *nlp = &nl; + int fd, sl = sizeof(sl), se; + + openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON); + if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) { + se = errno; + perror("open"); + errno = se; + syslog(LOG_ERR, "open: %m\n"); + exit(-1); + } + + bzero(&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(nl); + obj.ipfo_ptr = &nl; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + + bzero(&nl, sizeof(nl)); + nl.nl_flags = IPN_TCP; + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getsockname"); + errno = se; + syslog(LOG_ERR, "getsockname: %m\n"); + exit(-1); + } else { + nl.nl_inip.s_addr = sin.sin_addr.s_addr; + nl.nl_inport = sin.sin_port; + } + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getpeername"); + errno = se; + syslog(LOG_ERR, "getpeername: %m\n"); + exit(-1); + } else { + nl.nl_outip.s_addr = sin.sin_addr.s_addr; + nl.nl_outport = sin.sin_port; + } + + if (ioctl(fd, SIOCGNATL, &obj) == -1) { + se = errno; + perror("ioctl"); + errno = se; + syslog(LOG_ERR, "ioctl: %m\n"); + exit(-1); + } + + sin.sin_port = nl.nl_realport; + sin.sin_addr = nl.nl_realip; + sl = sizeof(sin); + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (connect(fd, (struct sockaddr *)&sin, sl) == -1) { + se = errno; + perror("connect"); + errno = se; + syslog(LOG_ERR, "connect: %m\n"); + exit(-1); + } + + (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + + syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr), + ntohs(sin.sin_port)); + if (relay(0, 1, fd) == -1) { + se = errno; + perror("relay"); + errno = se; + syslog(LOG_ERR, "relay: %m\n"); + exit(-1); + } + exit(0); +} diff --git a/contrib/ipfilter/samples/userauth.c b/contrib/ipfilter/samples/userauth.c index 5b50a94..ef059ac 100644 --- a/contrib/ipfilter/samples/userauth.c +++ b/contrib/ipfilter/samples/userauth.c @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> @@ -21,7 +23,9 @@ main() char yn[16]; int fd; - fd = open(IPL_AUTH, O_RDWR); + fd = open(IPL_NAME, O_RDWR); + fra.fra_len = 0; + fra.fra_buf = NULL; while (ioctl(fd, SIOCAUTHW, &frap) == 0) { if (fra.fra_info.fin_out) fra.fra_pass = FR_OUTQUE; @@ -29,10 +33,10 @@ main() fra.fra_pass = FR_INQUE; printf("%s ", inet_ntoa(fi->fi_src)); - if (fi->fi_fl & FI_TCPUDP) + if (fi->fi_flx & FI_TCPUDP) printf("port %d ", fin->fin_data[0]); printf("-> %s ", inet_ntoa(fi->fi_dst)); - if (fi->fi_fl & FI_TCPUDP) + if (fi->fi_flx & FI_TCPUDP) printf("port %d ", fin->fin_data[1]); printf("\n"); printf("Allow packet through ? [y/n]"); @@ -44,7 +48,7 @@ main() fra.fra_pass |= FR_BLOCK; else if (yn[0] == 'y' || yn[0] == 'Y') { fra.fra_pass |= FR_PASS; - if (fra.fra_info.fin_fi.fi_fl & FI_TCPUDP) + if (fra.fra_info.fin_fi.fi_flx & FI_TCPUDP) fra.fra_pass |= FR_KEEPSTATE; } else fra.fra_pass |= FR_NOMATCH; diff --git a/contrib/ipfilter/snoop.h b/contrib/ipfilter/snoop.h index 2f6c305..12dea37 100644 --- a/contrib/ipfilter/snoop.h +++ b/contrib/ipfilter/snoop.h @@ -1,3 +1,5 @@ +/* $NetBSD$ */ + /* * Copyright (C) 1993-2001 by Darren Reed. * @@ -9,7 +11,7 @@ /* * written to comply with the RFC (1761) from Sun. - * $Id: snoop.h,v 2.2.2.1 2001/06/26 10:43:20 darrenr Exp $ + * Id: snoop.h,v 2.3 2001/06/09 17:09:23 darrenr Exp */ struct snoophdr { char s_id[8]; diff --git a/contrib/ipfilter/test/.cvsignore b/contrib/ipfilter/test/.cvsignore new file mode 100644 index 0000000..5825abc --- /dev/null +++ b/contrib/ipfilter/test/.cvsignore @@ -0,0 +1,87 @@ +results +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +i1 +i2 +i3 +i4 +i5 +i6 +i7 +i8 +i9 +i10 +i11 +f1 +f2 +f3 +f4 +f5 +f6 +f7 +f8 +f9 +f10 +f11 +f12 +f13 +f14 +n1 +n2 +n3 +n4 +n5 +n6 +n7 +f15 +f16 +ipv6.1 +ipv6.2 +l1 +ni1 +ni2 +ni3 +ni4 +f17 +in1 +in2 +in3 +in4 +p1 +p2 +i12 +ip1 +p3 +i13 +ni5 +ni6 +i14 +in5 +ipv6.3 +n8 +n9 +n10 +n11 +ni7 +ni8 +ni9 +ni10 +ni11 +ni12 +n12 +in6 +i15 +ni13 +ni14 +ni15 +ni16 diff --git a/contrib/ipfilter/test/Makefile b/contrib/ipfilter/test/Makefile index a7a6c29..7f17241 100644 --- a/contrib/ipfilter/test/Makefile +++ b/contrib/ipfilter/test/Makefile @@ -1,15 +1,21 @@ # # (C)opyright 1993-1996 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. +# See the IPFILTER.LICENCE file for details on licencing. # BINDEST=/usr/local/bin SBINDEST=/sbin MANDIR=/usr/share/man +all: results tests -tests: first 0 ftests ptests ntests nitests logtests ipv6 intests +results: + mkdir -p results + +tests: ipf nat logtests ipv6 pools + +ipf: ftests ptests + +nat: ntests nitests intests first: -mkdir -p results @@ -18,57 +24,70 @@ first: ftests: f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 f16 f17 # Rule parsing tests -ptests: i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 +ptests: i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 -ntests: n1 n2 n3 n4 n5 n6 n7 +ntests: n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12 -nitests: ni1 ni2 ni3 ni4 ni5 +nitests: ni1 ni2 ni3 ni4 ni5 ni6 ni7 ni8 ni9 ni10 ni11 ni12 ni13 ni14 ni15 ni16 -intests: in1 in2 in3 in4 +intests: in1 in2 in3 in4 in5 in6 logtests: l1 -ipv6: ipv6.1 ipv6.2 ipv6.3 +pools: p1 p2 p3 ip1 -0: - @(cd ..; make ipftest; ) +ipv6: ipv6.1 ipv6.2 ipv6.3 -f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f14: - @/bin/sh ./dotest $@ +bpf: bpf1 bpf-f1 -f12 f13: - @/bin/sh ./hextest $@ +f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14: + @/bin/sh ./dotest `awk "/^$@ / { print; } " test.format` -f15 f16: - @/bin/sh ./mtest $@ +f15 f16 f17: + @/bin/sh ./mtest `awk "/^$@ / { print; } " test.format` -f17: - @/bin/sh ./mhtest $@ +i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 bpf1: + @/bin/sh ./itest `awk "/^$@ / { print; } " test.format` -i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12: - @/bin/sh ./itest $@ +n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12: + @/bin/sh ./nattest `awk "/^$@ / { print; } " test.format` -n1 n2 n3 n4 n5 n6 n7: - @/bin/sh ./nattest $@ +ni1 ni2 ni3 ni4 ni5 ni7 ni8 ni9 ni10 ni11 ni12 ni13 ni14 ni15 ni16: + @/bin/sh ./natipftest single `awk "/^$@ / { print; } " test.format` -ni1 ni2 ni3 ni4 ni5 ni7 ni8 ni10 ni11: - @/bin/sh ./natipftest $@ +ni6: + @/bin/sh ./natipftest multi `awk "/^$@ / { print; } " test.format` -in1 in2 in3 in4: - @/bin/sh ./intest $@ +in1 in2 in3 in4 in5 in6: + @/bin/sh ./intest `awk "/^$@ / { print; } " test.format` l1: - @/bin/sh ./logtest $@ + @/bin/sh ./logtest `awk "/^$@ / { print; } " test.format` ipv6.1 ipv6.2 ipv6.3: - @/bin/sh ./dotest6 $@ + @/bin/sh ./dotest6 `awk "/^$@ / { print; } " test.format` + +p1 p2 p3: + @/bin/sh ./ptest `awk "/^$@ / { print; } " test.format` + +ip1: + @/bin/sh ./iptest `awk "/^$@ / { print; } " test.format` + +bpf-f1: + /bin/sh ./bpftest `awk "/^$@ / { print; } " test.format` clean: - /bin/rm -f f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f13 f12 f14 f15 f16 f17 - /bin/rm -f i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 - /bin/rm -f n1 n2 n3 n4 n5 n6 n7 - /bin/rm -f ni1 ni2 ni3 ni4 ni5 - /bin/rm -f in1 in2 in3 in4 + /bin/rm -f f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 f13 f14 f15 f16 f17 + /bin/rm -f i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 + /bin/rm -f n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12 + /bin/rm -f ni1 ni2 ni3 ni4 ni5 ni6 ni7 ni8 ni9 + /bin/rm -f ni10 ni11 ni12 ni13 ni14 ni15 ni16 + /bin/rm -f in1 in2 in3 in4 in5 in6 + /bin/rm -f p1 p2 p3 ip1 /bin/rm -f l1 /bin/rm -f ipv6.1 ipv6.2 ipv6.3 - /bin/rm -f results/* + /bin/rm -f bpf1 bpf-f1 + /bin/rm -f results/* logout + +diffs: + -cd expected; for i in *; do if [ -f $$i -a ! -f ../$$i -a -f ../results/$$i ] ; then diff -c $$i ../results/$$i >> ../diff.out; fi done diff --git a/contrib/ipfilter/test/bpftest b/contrib/ipfilter/test/bpftest new file mode 100644 index 0000000..b24c0f1 --- /dev/null +++ b/contrib/ipfilter/test/bpftest @@ -0,0 +1,28 @@ +#!/bin/sh +if [ -f /usr/ucb/touch ] ; then + TOUCH=/usr/ucb/touch +else + if [ -f /usr/bin/touch ] ; then + TOUCH=/usr/bin/touch + else + if [ -f /bin/touch ] ; then + TOUCH=/bin/touch + fi + fi +fi +echo "$1..."; +input=`expr $1 : 'bpf-\(.*\)'` +/bin/cp /dev/null results/$1 +( while read rule; do + echo "$rule" | ../ipftest -Rbr - -i input/$input >> results/$1; + if [ $? -ne 0 ] ; then + exit 1; + fi + echo "--------" >> results/$1 +done ) < regress/$1 +cmp expected/$1 results/$1 +status=$? +if [ $status = 0 ] ; then + $TOUCH $1 +fi +exit $status diff --git a/contrib/ipfilter/test/dotest b/contrib/ipfilter/test/dotest index 5a11605..71c8cce 100644 --- a/contrib/ipfilter/test/dotest +++ b/contrib/ipfilter/test/dotest @@ -1,4 +1,5 @@ #!/bin/sh +format=$2 if [ -f /usr/ucb/touch ] ; then TOUCH=/usr/ucb/touch else @@ -13,7 +14,7 @@ fi echo "$1..."; /bin/cp /dev/null results/$1 ( while read rule; do - echo "$rule" | ../ipftest -br - -i input/$1 >> results/$1; + echo "$rule" | ../ipftest -F $format -Rbr - -i input/$1 >> results/$1; if [ $? -ne 0 ] ; then exit 1; fi diff --git a/contrib/ipfilter/test/dotest6 b/contrib/ipfilter/test/dotest6 index 297de6f..d6db564 100755 --- a/contrib/ipfilter/test/dotest6 +++ b/contrib/ipfilter/test/dotest6 @@ -1,4 +1,6 @@ #!/bin/sh +format=$2 +mkdir -p results if [ -f /usr/ucb/touch ] ; then TOUCH=/usr/ucb/touch else @@ -19,7 +21,7 @@ if [ $? -ne 0 ] ; then exit 0 fi ( while read rule; do - echo "$rule" | ../ipftest -6Hbr - -i input/$1 >> results/$1; + echo "$rule" | ../ipftest -F $format -6br - -i input/$1 >> results/$1; if [ $? -ne 0 ] ; then exit 1; fi diff --git a/contrib/ipfilter/test/expected/bpf-f1 b/contrib/ipfilter/test/expected/bpf-f1 new file mode 100644 index 0000000..85ce84c --- /dev/null +++ b/contrib/ipfilter/test/expected/bpf-f1 @@ -0,0 +1,20 @@ +nomatch +pass +nomatch +nomatch +-------- +nomatch +nomatch +nomatch +pass +-------- +nomatch +nomatch +nomatch +nomatch +-------- +nomatch +nomatch +nomatch +nomatch +-------- diff --git a/contrib/ipfilter/test/expected/bpf1 b/contrib/ipfilter/test/expected/bpf1 new file mode 100644 index 0000000..9d0ad1b --- /dev/null +++ b/contrib/ipfilter/test/expected/bpf1 @@ -0,0 +1,4 @@ +pass in bpf { "0x20 0 0 0xc 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass out bpf { "0x20 0 0 0xc 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass in bpf { "0x20 0 0 0x10 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass out bpf { "0x20 0 0 0x10 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } diff --git a/contrib/ipfilter/test/expected/f17 b/contrib/ipfilter/test/expected/f17 index 99eee84..4fe3acf 100644 --- a/contrib/ipfilter/test/expected/f17 +++ b/contrib/ipfilter/test/expected/f17 @@ -3,8 +3,4 @@ block return-rst pass pass pass -pass -pass -pass -pass -------- diff --git a/contrib/ipfilter/test/expected/i1 b/contrib/ipfilter/test/expected/i1 index 3eb14be..93530f9 100644 --- a/contrib/ipfilter/test/expected/i1 +++ b/contrib/ipfilter/test/expected/i1 @@ -1,7 +1,7 @@ -pass in from any to any -block out from any to any -log in from any to any -log body in from any to any +pass in all +block out all +log in all +log body in all count in from any to any pass in from !any to any block in from any to !any @@ -11,3 +11,5 @@ pass in log body quick from any to any block return-rst in quick on le0(!) proto tcp from any to any block return-icmp in on qe0(!) from any to any block return-icmp(host-unr) in on qe0(!) from any to any +block return-icmp-as-dest(port-unr) in on qe0(!) from any to any +pass out on longNICname0(!) from 254.220.186.152/32 to 254.220.186.152/32 diff --git a/contrib/ipfilter/test/expected/i11 b/contrib/ipfilter/test/expected/i11 index ddf8000..058d03a 100644 --- a/contrib/ipfilter/test/expected/i11 +++ b/contrib/ipfilter/test/expected/i11 @@ -1,5 +1,8 @@ pass in on ed0(!) proto tcp from 127.0.0.1/32 to 127.0.0.1/32 port = 23 keep state block in log first on lo0(!) proto tcp/udp from any to any keep state -pass in proto udp from 127.0.0.1/32 to 127.0.0.1/32 port = 2049 keep frags +pass in proto udp from 127.0.0.1/32 to 127.0.0.1/32 port = 20499 keep frags pass in proto udp from 127.0.0.1/32 to 127.0.0.1/32 port = 53 keep state keep frags -pass in proto tcp from any port > 1024 to 127.0.0.1/32 port = 25 keep state +pass in on ed0(!) out-via vx0(!) proto udp from any to any keep state +pass out on ppp0(!) in-via le0(!) proto tcp from any to any keep state +pass in proto tcp from any port > 1024 to 127.0.0.1/32 port = 1024 keep state +pass in proto tcp from any to any flags S/FSRPAU keep state (limit 101,strict,newisn,no-icmp-err) diff --git a/contrib/ipfilter/test/expected/i12 b/contrib/ipfilter/test/expected/i12 index 2a904a3..22a3488 100644 --- a/contrib/ipfilter/test/expected/i12 +++ b/contrib/ipfilter/test/expected/i12 @@ -1,4 +1,34 @@ -block in on eri0(!) from any to any head 1 -pass in on eri0(!) proto icmp from any to any group 1 -pass out on ed0(!) from any to any head 1000000 -block out on ed0(!) proto udp from any to any group 1000000 +pass in from 1.1.1.1/32 to 2.2.2.2/32 +pass in from 2.2.2.0/24 to 4.4.4.4/32 +pass in from 3.3.3.3/32 to 4.4.4.4/32 +pass in from 2.2.2.0/24 to 5.5.5.5/32 +pass in from 3.3.3.3/32 to 5.5.5.5/32 +pass in from 2.2.2.0/24 to 6.6.6.6/32 +pass in from 3.3.3.3/32 to 6.6.6.6/32 +pass in from 2.2.2.0/24 to 5.5.5.5/32 port = 22 +pass in from 3.3.3.3/32 to 5.5.5.5/32 port = 22 +pass in from 2.2.2.0/24 to 6.6.6.6/32 port = 22 +pass in from 3.3.3.3/32 to 6.6.6.6/32 port = 22 +pass in from 2.2.2.0/24 to 5.5.5.5/32 port = 25 +pass in from 3.3.3.3/32 to 5.5.5.5/32 port = 25 +pass in from 2.2.2.0/24 to 6.6.6.6/32 port = 25 +pass in from 3.3.3.3/32 to 6.6.6.6/32 port = 25 +pass in proto tcp from 2.2.2.0/24 to 5.5.5.5/32 port = 53 +pass in proto tcp from 3.3.3.3/32 to 5.5.5.5/32 port = 53 +pass in proto tcp from 2.2.2.0/24 to 6.6.6.6/32 port = 53 +pass in proto tcp from 3.3.3.3/32 to 6.6.6.6/32 port = 53 +pass in proto tcp from 2.2.2.0/24 to 5.5.5.5/32 port = 9 +pass in proto tcp from 3.3.3.3/32 to 5.5.5.5/32 port = 9 +pass in proto tcp from 2.2.2.0/24 to 6.6.6.6/32 port = 9 +pass in proto tcp from 3.3.3.3/32 to 6.6.6.6/32 port = 9 +pass in proto udp from 2.2.2.0/24 to 5.5.5.5/32 port = 53 +pass in proto udp from 3.3.3.3/32 to 5.5.5.5/32 port = 53 +pass in proto udp from 2.2.2.0/24 to 6.6.6.6/32 port = 53 +pass in proto udp from 3.3.3.3/32 to 6.6.6.6/32 port = 53 +pass in proto udp from 2.2.2.0/24 to 5.5.5.5/32 port = 9 +pass in proto udp from 3.3.3.3/32 to 5.5.5.5/32 port = 9 +pass in proto udp from 2.2.2.0/24 to 6.6.6.6/32 port = 9 +pass in proto udp from 3.3.3.3/32 to 6.6.6.6/32 port = 9 +pass in from 10.10.10.10/32 to 11.11.11.11/32 +pass in from pool/101(!) to hash/202(!) +pass in from hash/303(!) to pool/404(!) diff --git a/contrib/ipfilter/test/expected/i13 b/contrib/ipfilter/test/expected/i13 new file mode 100644 index 0000000..5c8d945 --- /dev/null +++ b/contrib/ipfilter/test/expected/i13 @@ -0,0 +1,2 @@ +block in from any to any +pass in from any to any diff --git a/contrib/ipfilter/test/expected/i14 b/contrib/ipfilter/test/expected/i14 new file mode 100644 index 0000000..5a10155 --- /dev/null +++ b/contrib/ipfilter/test/expected/i14 @@ -0,0 +1,8 @@ +block in on eri0(!) all head 1 +pass in on eri0(!) proto icmp from any to any group 1 +pass out on ed0(!) all head 1000000 +block out on ed0(!) proto udp from any to any group 1000000 +block in on vm0(!) proto tcp/udp from any to any head 101 +pass in proto tcp/udp from 1.1.1.1/32 to 2.2.2.2/32 group 101 +pass in proto tcp from 1.0.0.1/32 to 2.0.0.2/32 group 101 +pass in proto udp from 2.0.0.2/32 to 3.0.0.3/32 group 101 diff --git a/contrib/ipfilter/test/expected/i15 b/contrib/ipfilter/test/expected/i15 new file mode 100644 index 0000000..4974659 --- /dev/null +++ b/contrib/ipfilter/test/expected/i15 @@ -0,0 +1,4 @@ +pass out on fxp0(!) all set-tag(log=100) +pass out on fxp0(!) all set-tag(nat=foo) +pass out on fxp0(!) all set-tag(log=100, nat=200) +pass out on fxp0(!) all set-tag(log=2147483648, nat=overtherainbowis) diff --git a/contrib/ipfilter/test/expected/i2 b/contrib/ipfilter/test/expected/i2 index 9d3398d..37ec9c4 100644 --- a/contrib/ipfilter/test/expected/i2 +++ b/contrib/ipfilter/test/expected/i2 @@ -1,6 +1,7 @@ log in proto tcp from any to any pass in proto tcp from any to any pass in proto udp from 127.0.0.1/32 to 127.0.0.1/32 +block in proto ipv6 from any to any block in proto udp from any to any block in proto 250 from any to any pass in proto tcp/udp from any to any diff --git a/contrib/ipfilter/test/expected/i3 b/contrib/ipfilter/test/expected/i3 index 18d9161..6150c7e 100644 --- a/contrib/ipfilter/test/expected/i3 +++ b/contrib/ipfilter/test/expected/i3 @@ -1,4 +1,5 @@ -log in from any to any +log in all +pass in from 128.16.0.0/16 to 129.10.10.0/24 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 128.0.0.0/24 to 128.0.0.0/16 @@ -6,5 +7,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 +block in log level auth.info on hme0(!) all +log level local5.warn out all diff --git a/contrib/ipfilter/test/expected/i4 b/contrib/ipfilter/test/expected/i4 index dfa3674..89c0995 100644 --- a/contrib/ipfilter/test/expected/i4 +++ b/contrib/ipfilter/test/expected/i4 @@ -2,6 +2,7 @@ log in proto tcp from any port > 0 to any log in proto tcp from any to any port > 0 pass in proto tcp from any port != 0 to any port 0 >< 65535 pass in proto udp from 127.0.0.1/32 port > 32000 to 127.0.0.1/32 port < 29000 -block in proto udp from any port != 123 to any port < 123 +block in proto udp from any port != 123 to any port < 7 block in proto tcp from any port = 25 to any port > 25 pass in proto tcp/udp from any port 1 >< 3 to any port 1 <> 3 +pass in log first quick proto tcp from any port > 1023 to any port = 1723 flags S/FSRPAU keep state diff --git a/contrib/ipfilter/test/expected/i5 b/contrib/ipfilter/test/expected/i5 index 3bcb10b..6947ad3 100644 --- a/contrib/ipfilter/test/expected/i5 +++ b/contrib/ipfilter/test/expected/i5 @@ -1,4 +1,4 @@ -log in from any to any +log in all count in tos 0x80 from any to any pass in on ed0(!) tos 0x40 from 127.0.0.1/32 to 127.0.0.1/32 block in log on lo0(!) ttl 0 from any to any diff --git a/contrib/ipfilter/test/expected/i6 b/contrib/ipfilter/test/expected/i6 index 4849626..40fe185 100644 --- a/contrib/ipfilter/test/expected/i6 +++ b/contrib/ipfilter/test/expected/i6 @@ -1,4 +1,10 @@ pass in on lo0(!) fastroute from any to any +pass in on lo0(!) to qe0(!) from 127.0.0.1/32 to 127.0.0.1/32 +pass in on le0(!) to qe0(!):127.0.0.1 from 127.0.0.1/32 to 127.0.0.1/32 pass in on lo0(!) dup-to qe0(!) from 127.0.0.1/32 to 127.0.0.1/32 -pass in on qe0(!) dup-to qe0(!):127.0.0.1 from 127.0.0.1/32 to 127.0.0.1/32 +pass in on le0(!) dup-to qe0(!):127.0.0.1 from 127.0.0.1/32 to 127.0.0.1/32 +pass in on le0(!) dup-to qe0(!):127.0.0.1 to hme0(!):10.1.1.1 from 127.0.0.1/32 to 127.0.0.1/32 block in quick on qe0(!) to qe1(!) from any to any +block in quick to qe1(!) from any to any +pass out quick dup-to hme0(!) from any to any +pass in quick fastroute all diff --git a/contrib/ipfilter/test/expected/i7 b/contrib/ipfilter/test/expected/i7 index db9cd01..c46364b 100644 --- a/contrib/ipfilter/test/expected/i7 +++ b/contrib/ipfilter/test/expected/i7 @@ -1,4 +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/FSRPAUC +block in on lo0(!) proto tcp from any to any flags A/FSRPAU pass in on lo0(!) proto tcp from any to any flags /SPA block in on lo0(!) proto tcp from any to any flags C/A diff --git a/contrib/ipfilter/test/expected/i9 b/contrib/ipfilter/test/expected/i9 index b36d864..bae7c9b 100644 --- a/contrib/ipfilter/test/expected/i9 +++ b/contrib/ipfilter/test/expected/i9 @@ -1,5 +1,7 @@ -pass in from 127.0.0.1/32 to 127.0.0.1/32 with short -block in from any to any with ipopt +pass in from 127.0.0.1/32 to 127.0.0.1/32 with short,frag +block in from any to any with ipopts pass in from any to any with opt nop,rr,zsu pass in from any to any with opt nop,rr,zsu not opt lsrr,ssrr pass in from 127.0.0.1/32 to 127.0.0.1/32 with not frag +pass in proto tcp from any to any flags S/FSRPAU with not oow keep state +pass in proto tcp from any to any flags S/FSRPAU with not bad,bad-src,bad-nat diff --git a/contrib/ipfilter/test/expected/in1 b/contrib/ipfilter/test/expected/in1 index c507db7..ce5a610 100644 --- a/contrib/ipfilter/test/expected/in1 +++ b/contrib/ipfilter/test/expected/in1 @@ -10,16 +10,18 @@ map ppp0 192.168.0.0/16 -> 0.0.0.0/32 portmap tcp/udp 30000:39999 map ppp0 192.168.0.0/16 -> 0.0.0.0/32 portmap tcp auto map ppp0 192.168.0.0/16 -> 0.0.0.0/32 portmap udp auto map ppp0 192.168.0.0/16 -> 0.0.0.0/32 portmap tcp/udp auto -map ppp0 192.168.0.0/16 -> 0.0.0.0/32 proxy port ftp ftp/tcp +map ppp0 192.168.0.0/16 -> 0.0.0.0/32 proxy port 21 ftp/tcp map ppp0 192.168.0.0/16 -> 0.0.0.0/32 proxy port 1010 ftp/tcp map le0 0.0.0.0/0 -> 0.0.0.0/32 frag map le0 192.168.0.0/16 -> range 203.1.1.23-203.1.3.45 frag map ppp0 192.168.0.0/16 -> 0.0.0.0/32 portmap tcp 10000:19999 frag -map ppp0 192.168.0.0/16 -> 0.0.0.0/32 proxy port ftp ftp/tcp frag +map ppp0 192.168.0.0/16 -> 0.0.0.0/32 proxy port 21 ftp/tcp frag map le0 0.0.0.0/0 -> 0.0.0.0/32 age 10/10 map le0 192.168.0.0/16 -> range 203.1.1.23-203.1.3.45 age 10/20 map ppp0 192.168.0.0/16 -> 0.0.0.0/32 portmap tcp 10000:19999 age 30/30 map le0 0.0.0.0/0 -> 0.0.0.0/32 frag age 10/10 map le0 192.168.0.0/16 -> range 203.1.1.23-203.1.3.45 frag age 10/20 map ppp0 192.168.0.0/16 -> 0.0.0.0/32 portmap tcp 10000:19999 frag age 30/30 -map fxp0 from 192.168.0.0/18 to any port = ftp -> 1.2.3.4/32 proxy port ftp ftp/tcp +map fxp0 from 192.168.0.0/18 to any port = 21 -> 1.2.3.4/32 proxy port 21 ftp/tcp +map thisisalonginte 0.0.0.0/0 -> 0.0.0.0/32 mssclamp 1452 tag freddyliveshere +map bar0 0.0.0.0/0 -> 0.0.0.0/32 icmpidmap icmp 1000:2000 diff --git a/contrib/ipfilter/test/expected/in2 b/contrib/ipfilter/test/expected/in2 index ebe747b..61c0d18 100644 --- a/contrib/ipfilter/test/expected/in2 +++ b/contrib/ipfilter/test/expected/in2 @@ -1,22 +1,67 @@ -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 tcp -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 ip -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1 port 80 tcp -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 ip -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1 port 80 tcp -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1 port 80 udp -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1 port 80 tcp/udp -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 icmp -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1 port 80 tcp round-robin -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 ip frag -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 icmp frag -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1 port 80 tcp round-robin frag -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 ip frag age 10/10 -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 ip frag age 10/20 -rdr le0 0.0.0.0/0 port 0 -> 1.1.1.1 port 0 icmp frag age 10/10 -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20/20 -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30/30 -rdr le0 0.0.0.0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40/40 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 tcp +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 udp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp/udp +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/10 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/20 +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag age 10/10 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20/20 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30/30 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40/40 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag sticky +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/10 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/20 +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag age 10/10 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20/20 sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30/30 sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40/40 sticky +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip mssclamp 1000 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip mssclamp 1000 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag mssclamp 1000 +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/10 mssclamp 1000 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/20 mssclamp 1000 +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag age 10/10 mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20/20 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30/30 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40/40 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip tag nattagcacheline +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/10 mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/20 mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 -> 1.1.1.1 icmp frag age 10/10 mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20/20 sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30/30 sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40/40 sticky mssclamp 1000 tag nattagcacheline +rdr ge0 9.8.7.6/32 port 21 -> 1.1.1.1 port 21 tcp proxy ftp +rdr ge0 9.8.7.6/32 port 21 -> 1.1.1.1 port 21 tcp proxy ftp +rdr le0 9.8.7.6/32 port 1000-2000 -> 1.1.1.1 port 5555 tcp +rdr le0 9.8.7.6/32 port 1000-2000 -> 1.1.1.1 port = 5555 tcp +rdr le0 0.0.0.0/0 -> 254.220.186.152 ip +rdr le0 0.0.0.0/0 -> 254.220.186.152,254.220.186.152 ip diff --git a/contrib/ipfilter/test/expected/in5 b/contrib/ipfilter/test/expected/in5 new file mode 100644 index 0000000..7b3120a --- /dev/null +++ b/contrib/ipfilter/test/expected/in5 @@ -0,0 +1,22 @@ +rdr le0 from any to 9.8.7.6/32 port = 0 -> 1.1.1.1 port 0 tcp +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 ip +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 ip +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 udp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp/udp +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 icmp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp round-robin +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp round-robin +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 ip frag +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 icmp frag +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp frag +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp round-robin frag +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp round-robin frag +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/10 +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 ip frag age 10/20 +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 icmp frag age 10/10 +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp frag age 20/20 +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp round-robin frag age 30/30 +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp round-robin frag age 40/40 diff --git a/contrib/ipfilter/test/expected/in6 b/contrib/ipfilter/test/expected/in6 new file mode 100644 index 0000000..08bbff0 --- /dev/null +++ b/contrib/ipfilter/test/expected/in6 @@ -0,0 +1,3 @@ +map foo0 from any port = 1 to any port != 0 -> 0.0.0.0/32 udp +map foo0 from any port < 1 to any port > 0 -> 0.0.0.0/32 tcp +map foo0 from any port <= 1 to any port >= 0 -> 0.0.0.0/32 tcp/udp diff --git a/contrib/ipfilter/test/expected/ip1 b/contrib/ipfilter/test/expected/ip1 new file mode 100644 index 0000000..b04fa9d --- /dev/null +++ b/contrib/ipfilter/test/expected/ip1 @@ -0,0 +1,68 @@ +table role = ipf type = tree number = 1 + {; }; +table role = ipf type = tree number = 100 + { 2.2.2.0/24; ! 2.2.0.0/16; 1.2.3.4/32; }; +table role = ipf type = tree number = 110 + { 2.2.2.0/24; ! 2.2.0.0/16; 1.2.3.4/32; }; +table role = ipf type = tree number = 120 + { 2.2.2.0/24; ! 2.2.0.0/16; 1.2.3.4/32; }; +table role = ipf type = tree number = 130 + { 2.2.2.0/24; ! 2.2.0.0/16; 1.2.3.4/32; }; +table role = ipf type = hash number = 2 size = 1 + {; }; +table role = ipf type = hash number = 200 size = 5 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 210 size = 5 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 220 size = 5 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 230 size = 5 + { 0/0; 4/32; 1.2.3.4/32; }; +table role = ipf type = hash number = 240 size = 5 seed = 101 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 250 size = 5 seed = 101 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 260 size = 5 seed = 101 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 270 size = 5 seed = 101 + { 0/0; 4/32; 1.2.3.4/32; }; +table role = ipf type = hash number = 2000 size = 1001 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 2000 size = 1001 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 2000 size = 1001 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 2000 size = 1001 + { 0/0; 4/32; 1.2.3.4/32; }; +table role = ipf type = hash number = 100 size = 1001 seed = 101 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 100 size = 1001 seed = 101 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 100 size = 1001 seed = 101 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 100 size = 1001 seed = 101 + { 0/0; 4/32; 1.2.3.4/32; }; +group-map in role = ipf number = 300 size = 5 + { 0/0, group = 303; 5/32, group = 303; 1.2.3.4/32, group = 303; }; +group-map in role = nat number = 300 size = 5 + { 0/0, group = 303; 6/32, group = 303; 1.2.3.4/32, group = 303; }; +group-map in role = auth number = 300 size = 5 + { 0/0, group = 303; 7/32, group = 303; 1.2.3.4/32, group = 303; }; +group-map in role = count number = 300 size = 5 + { 0/0, group = 303; 8/32, group = 303; 1.2.3.4/32, group = 303; }; +group-map out role = ipf number = 400 size = 5 + { 0/0, group = 303; 5/32, group = 303; 1.2.3.4/32, group = 606; }; +group-map out role = nat number = 400 size = 5 + { 0/0, group = 303; 6/32, group = 303; 1.2.3.4/32, group = 606; }; +group-map out role = auth number = 400 size = 5 + { 0/0, group = 303; 7/32, group = 303; 1.2.3.4/32, group = 606; }; +group-map out role = count number = 400 size = 5 + { 0/0, group = 303; 8/32, group = 303; 1.2.3.4/32, group = 606; }; +group-map in role = ipf number = 500 size = 5 + { 0/0, group = 10; 5/32, group = 800; 1.2.3.4/32, group = 606; }; +group-map in role = nat number = 500 size = 5 + { 0/0, group = 10; 6/32, group = 800; 1.2.3.4/32, group = 606; }; +group-map in role = auth number = 500 size = 5 + { 0/0, group = 10; 7/32, group = 800; 1.2.3.4/32, group = 606; }; +group-map in role = count number = 500 size = 5 + { 0/0, group = 10; 8/32, group = 800; 1.2.3.4/32, group = 606; }; diff --git a/contrib/ipfilter/test/expected/l1 b/contrib/ipfilter/test/expected/l1 index dbd6b01..ba0de69 100644 --- a/contrib/ipfilter/test/expected/l1 +++ b/contrib/ipfilter/test/expected/l1 @@ -2,7 +2,7 @@ log in all 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -S IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -AS IN -01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -F IN +01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -AF IN 01/01/1970 00:00:00.000000 2x anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1 -> 4.4.4.4,53 PR udp len 20 40 IN 01/01/1970 00:00:00.000000 2x anon0 @-1:-1 L 2.2.2.2,1 -> 4.4.4.4,53 PR udp len 20 40 IN @@ -24,7 +24,7 @@ pass in log quick proto tcp from 1.1.1.1 to any flags S keep state 01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A K-S IN 01/01/1970 00:00:00.000000 anon0 @0:1 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -AS K-S IN 01/01/1970 00:00:00.000000 e1 @0:1 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -A K-S OUT -01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -F K-S IN +01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -AF K-S IN -------- pass in log first quick proto tcp from 1.1.1.1 to any flags S keep state 01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -S K-S IN @@ -34,7 +34,7 @@ pass in log first quick proto tcp from 1.1.1.1 to any flags S keep state 01/01/1970 00:00:00.000000 anon0 @0:4 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A K-S IN 01/01/1970 00:00:00.000000 anon0 @0:4 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -AS K-S IN 01/01/1970 00:00:00.000000 e1 @0:4 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -A K-S OUT -01/01/1970 00:00:00.000000 anon0 @0:4 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -F K-S IN +01/01/1970 00:00:00.000000 anon0 @0:4 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -AF K-S IN 01/01/1970 00:00:00.000000 2x anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1 -> 4.4.4.4,53 PR udp len 20 40 IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 2.2.2.2,1 -> 4.4.4.4,53 PR udp len 20 40 IN diff --git a/contrib/ipfilter/test/expected/l1.b b/contrib/ipfilter/test/expected/l1.b index e5c1077..c060086 100644 --- a/contrib/ipfilter/test/expected/l1.b +++ b/contrib/ipfilter/test/expected/l1.b @@ -1,7 +1,7 @@ 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -S IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -AS IN -01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -F IN +01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -AF IN 01/01/1970 00:00:00.000000 2x anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1 -> 4.4.4.4,53 PR udp len 20 40 IN 01/01/1970 00:00:00.000000 2x anon0 @-1:-1 L 2.2.2.2,1 -> 4.4.4.4,53 PR udp len 20 40 IN @@ -20,7 +20,7 @@ 01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A K-S IN 01/01/1970 00:00:00.000000 anon0 @0:1 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -AS K-S IN 01/01/1970 00:00:00.000000 e1 @0:1 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -A K-S OUT -01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -F K-S IN +01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -AF K-S IN -------- 01/01/1970 00:00:00.000000 anon0 @0:1 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -S K-S IN -------- @@ -29,7 +29,7 @@ 01/01/1970 00:00:00.000000 anon0 @0:4 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A K-S IN 01/01/1970 00:00:00.000000 anon0 @0:4 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -AS K-S IN 01/01/1970 00:00:00.000000 e1 @0:4 p 2.2.2.2,25 -> 1.1.1.1,1025 PR tcp len 20 40 -A K-S OUT -01/01/1970 00:00:00.000000 anon0 @0:4 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -F K-S IN +01/01/1970 00:00:00.000000 anon0 @0:4 p 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -AF K-S IN 01/01/1970 00:00:00.000000 2x anon0 @-1:-1 L 1.1.1.1,1025 -> 2.2.2.2,25 PR tcp len 20 40 -A IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 1.1.1.1,1 -> 4.4.4.4,53 PR udp len 20 40 IN 01/01/1970 00:00:00.000000 anon0 @-1:-1 L 2.2.2.2,1 -> 4.4.4.4,53 PR udp len 20 40 IN diff --git a/contrib/ipfilter/test/expected/n1 b/contrib/ipfilter/test/expected/n1 index c195f6f..0f87034 100644 --- a/contrib/ipfilter/test/expected/n1 +++ b/contrib/ipfilter/test/expected/n1 @@ -19,7 +19,10 @@ 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.2.2.2 > 10.4.3.2 ip 48(20) 1 10.4.3.2 > 10.1.1.1 +ip 48(20) 1 10.4.3.2 > 10.3.4.1 +ip 48(20) 1 10.4.3.2 > 10.3.4.2 ip 48(20) 1 10.4.3.2 > 10.3.4.3 +ip 48(20) 1 10.4.3.2 > 10.3.4.4 ip 48(20) 1 10.4.3.2 > 10.3.4.5 ip 20(20) 34 10.1.1.2 > 10.4.3.2 ip 20(20) 34 10.4.3.2 > 10.3.4.4 @@ -51,7 +54,10 @@ ip 20(20) 255 10.1.1.2 > 10.1.1.0 ip 40(20) 6 10.1.1.1,1025 > 10.1.1.2,1025 ip 48(20) 1 10.3.4.5 > 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.1 +ip 48(20) 1 10.4.3.2 > 10.3.4.2 ip 48(20) 1 10.4.3.2 > 10.3.4.3 +ip 48(20) 1 10.4.3.2 > 10.3.4.4 ip 48(20) 1 10.4.3.2 > 10.1.1.1 ip 20(20) 34 10.3.4.5 > 10.4.3.2 ip 20(20) 34 10.4.3.2 > 10.3.4.4 @@ -81,9 +87,12 @@ 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.2 > 10.4.3.2 +ip 48(20) 1 10.3.4.3 > 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.1 +ip 48(20) 1 10.4.3.2 > 10.3.4.2 +ip 48(20) 1 10.4.3.2 > 10.1.1.1 +ip 48(20) 1 10.4.3.2 > 10.3.4.4 ip 48(20) 1 10.4.3.2 > 10.3.4.5 ip 20(20) 34 10.3.4.3 > 10.4.3.2 ip 20(20) 34 10.4.3.2 > 10.3.4.4 diff --git a/contrib/ipfilter/test/expected/n10 b/contrib/ipfilter/test/expected/n10 new file mode 100644 index 0000000..f30d757 --- /dev/null +++ b/contrib/ipfilter/test/expected/n10 @@ -0,0 +1,6 @@ +4500 002c 10c9 4000 ff06 5c9d cbcb cbcb 96cb e002 8032 0015 bd6b c9c8 0000 0000 6002 2238 655d 0000 0204 0064 +------------------------------- +4500 002c 10c9 4000 ff06 5c9d cbcb cbcb 96cb e002 8032 0015 bd6b c9c8 0000 0000 6002 2238 61d9 0000 0204 03e8 +------------------------------- +4500 002c 10c9 4000 ff06 5c9d cbcb cbcb 96cb e002 8032 0015 bd6b c9c8 0000 0000 6002 2238 600d 0000 0204 05b4 +------------------------------- diff --git a/contrib/ipfilter/test/expected/n11 b/contrib/ipfilter/test/expected/n11 new file mode 100644 index 0000000..3732709 --- /dev/null +++ b/contrib/ipfilter/test/expected/n11 @@ -0,0 +1,51 @@ +ip 20(20) 255 10.1.1.0 > 10.1.1.2 +ip 20(20) 255 1.6.7.8 > 10.1.1.2 +ip 20(20) 255 10.1.1.2 > 10.1.1.1 +ip 20(20) 255 10.2.2.1 > 10.1.2.1 +ip 20(20) 255 10.2.2.2 > 10.1.2.1 +ip 20(20) 255 10.1.1.1 > 10.1.1.2 +ip 20(20) 255 10.1.1.2 > 10.1.1.1 +ip 20(20) 255 10.2.2.1 > 10.2.1.1 +ip 20(20) 255 10.2.2.2 > 10.2.1.1 +ip 20(20) 255 10.2.2.3 > 10.1.1.1 +ip 20(20) 255 10.2.3.4 > 10.2.2.2 +ip 20(20) 255 10.1.1.1 > 10.2.2.2 +ip 20(20) 255 10.1.1.2 > 10.2.2.2 +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 20(20) 255 10.2.2.2 > 10.1.1.2 +ip 20(20) 255 10.1.1.1 > 10.1.1.2 +ip 20(20) 255 10.2.2.2 > 10.1.1.1 +ip 20(20) 255 10.2.2.1 > 10.1.2.1 +ip 20(20) 255 10.2.2.2 > 10.1.2.1 +ip 20(20) 255 10.1.1.1 > 10.1.1.2 +ip 20(20) 255 10.1.1.2 > 10.1.1.1 +ip 20(20) 255 10.2.2.1 > 10.2.1.1 +ip 20(20) 255 10.2.2.2 > 10.2.1.1 +ip 20(20) 255 10.2.2.3 > 10.1.1.1 +ip 20(20) 255 10.2.3.4 > 10.1.1.0 +ip 20(20) 255 10.1.1.1 > 10.1.1.2 +ip 20(20) 255 10.1.1.2 > 10.1.1.0 +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 20(20) 255 10.3.4.0 > 10.1.1.2 +ip 20(20) 255 10.3.4.1 > 10.1.1.2 +ip 20(20) 255 10.3.4.2 > 10.1.1.1 +ip 20(20) 255 10.2.2.1 > 10.1.2.1 +ip 20(20) 255 10.2.2.2 > 10.1.2.1 +ip 20(20) 255 10.1.1.1 > 10.1.1.2 +ip 20(20) 255 10.1.1.2 > 10.1.1.1 +ip 20(20) 255 10.2.2.1 > 10.2.1.1 +ip 20(20) 255 10.2.2.2 > 10.2.1.1 +ip 20(20) 255 10.2.2.3 > 10.1.1.1 +ip 20(20) 255 10.2.3.4 > 10.2.2.2 +ip 20(20) 255 10.1.1.1 > 10.2.2.2 +ip 20(20) 255 10.1.1.2 > 10.2.2.2 +ip 20(20) 255 10.1.1.0 > 10.1.1.5 +ip 20(20) 255 10.1.1.1 > 10.1.1.5 +ip 20(20) 255 10.1.1.2 > 10.1.1.5 +------------------------------- diff --git a/contrib/ipfilter/test/expected/n12 b/contrib/ipfilter/test/expected/n12 new file mode 100644 index 0000000..010b77b --- /dev/null +++ b/contrib/ipfilter/test/expected/n12 @@ -0,0 +1,4 @@ +4510 0040 2020 4000 4006 9478 c0a8 01bc c0a8 0303 2710 0017 4e33 298e 0000 0000 b002 4000 6ff8 0000 0204 05b4 0101 0402 0103 0300 0101 080a 0c72 549e 0000 0000 +4500 003c 00b0 4000 fe06 7964 c0a8 0303 c0a8 7e53 0017 12c2 f674 e02c 4e33 298f a012 2798 7ace 0000 0101 080a 2c05 b797 0c72 549e 0103 0300 0204 05b4 +4510 0034 493b 4000 4006 6b69 c0a8 01bc c0a8 0303 2710 0017 4e33 298f f674 e02d 8010 4000 f673 0000 0101 080a 0c72 549e 2c05 b797 +------------------------------- diff --git a/contrib/ipfilter/test/expected/n4 b/contrib/ipfilter/test/expected/n4 index c6fb4d4..8cdf78c 100644 --- a/contrib/ipfilter/test/expected/n4 +++ b/contrib/ipfilter/test/expected/n4 @@ -1,30 +1,66 @@ ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,10023 +ip 40(20) 6 10.1.1.1,23 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.1,53 -ip 40(20) 6 10.3.3.3,12345 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10053 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12346 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12346 ip 28(20) 17 10.3.3.3,12345 > 10.1.1.0,53 +ip 28(20) 17 10.2.2.1,10053 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.0,53 +ip 40(20) 6 10.2.2.1,53 > 10.3.3.3,12345 ------------------------------- ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,10023 +ip 40(20) 6 10.1.1.1,23 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.1,53 -ip 40(20) 6 10.3.3.3,12345 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10053 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12346 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12346 ip 28(20) 17 10.3.3.3,12345 > 10.1.1.0,53 +ip 28(20) 17 10.2.2.1,10053 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.0,53 +ip 40(20) 6 10.2.2.1,53 > 10.3.3.3,12345 ------------------------------- ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,10023 +ip 40(20) 6 10.1.1.1,23 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.1,53 -ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,10023 +ip 40(20) 6 10.2.2.1,10053 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12346 > 10.2.2.1,10023 +ip 40(20) 6 10.1.0.0,23 > 10.3.3.3,12346 ip 28(20) 17 10.3.3.3,12345 > 10.1.1.0,53 +ip 28(20) 17 10.2.2.1,10053 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.0,53 +ip 40(20) 6 10.2.2.1,53 > 10.3.3.3,12345 ------------------------------- ip 40(20) 6 10.3.3.3,12345 > 10.1.1.1,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.1,53 -ip 40(20) 6 10.3.3.3,12345 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10053 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12346 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12346 ip 28(20) 17 10.3.3.3,12345 > 10.2.2.1,10053 +ip 28(20) 17 10.1.1.0,53 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.1.1.0,53 +ip 40(20) 6 10.2.2.1,53 > 10.3.3.3,12345 ------------------------------- ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,53 -ip 40(20) 6 10.3.3.3,12345 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10053 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12346 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12346 ip 28(20) 17 10.3.3.3,12345 > 10.1.1.0,53 +ip 28(20) 17 10.2.2.1,10053 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,53 +ip 40(20) 6 10.1.1.0,53 > 10.3.3.3,12345 +------------------------------- +ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,53 +ip 40(20) 6 10.2.2.1,10053 > 10.3.3.3,12345 +ip 40(20) 6 10.3.3.3,12346 > 10.1.0.0,23 +ip 40(20) 6 10.2.2.1,10023 > 10.3.3.3,12346 +ip 28(20) 17 10.3.3.3,12345 > 10.2.2.1,53 +ip 28(20) 17 10.2.2.1,10053 > 10.3.3.3,12345 ip 40(20) 6 10.3.3.3,12345 > 10.2.2.1,53 +ip 40(20) 6 10.1.1.0,53 > 10.3.3.3,12345 ------------------------------- diff --git a/contrib/ipfilter/test/expected/n5 b/contrib/ipfilter/test/expected/n5 index 75f174b..521c737 100644 --- a/contrib/ipfilter/test/expected/n5 +++ b/contrib/ipfilter/test/expected/n5 @@ -154,11 +154,11 @@ ip 40(20) 6 10.1.1.3,2003 > 10.1.4.1,80 ip 20(20) 0 10.1.1.1 > 10.1.1.2 ip 40(20) 6 10.1.1.1,1025 > 10.1.1.2,1025 ip 20(20) 0 10.1.1.2 > 10.1.1.1 -ip 40(20) 6 10.3.4.1,1026 > 10.3.4.5,40000 +ip 40(20) 6 10.3.4.3,1026 > 10.3.4.5,40000 ip 40(20) 6 10.1.1.1,1026 > 10.3.4.5,40000 -ip 40(20) 6 10.3.4.1,1025 > 10.3.4.5,40000 +ip 40(20) 6 10.3.4.3,1025 > 10.3.4.5,40000 ip 40(20) 6 10.1.1.1,1025 > 10.3.4.5,40000 -ip 28(20) 17 10.3.4.1,1025 > 10.3.4.5,40001 +ip 28(20) 17 10.3.4.3,1025 > 10.3.4.5,40001 ip 28(20) 17 10.1.1.2,1025 > 10.3.4.5,40001 ip 40(20) 6 10.1.2.1,80 > 10.3.4.5,40001 ip 40(20) 6 10.1.2.1,80 > 10.3.4.5,40001 diff --git a/contrib/ipfilter/test/expected/n7 b/contrib/ipfilter/test/expected/n7 index 51aa987..db8bb50 100644 --- a/contrib/ipfilter/test/expected/n7 +++ b/contrib/ipfilter/test/expected/n7 @@ -9,6 +9,16 @@ ip 40(20) 6 10.2.3.1,1237 > 10.1.1.4,80 ip 40(20) 6 10.2.3.1,1238 > 10.1.1.4,80 ------------------------------- ip 40(20) 6 10.2.3.1,1230 > 10.1.1.1,22 +ip 40(20) 6 10.2.3.1,1231 > 10.2.2.1,10023 +ip 40(20) 6 10.2.3.1,1232 > 10.2.2.1,10023 +ip 40(20) 6 10.2.3.1,1233 > 10.2.2.1,10023 +ip 40(20) 6 10.2.3.1,1234 > 10.1.1.1,80 +ip 40(20) 6 10.2.3.1,1235 > 10.1.1.2,80 +ip 40(20) 6 10.2.3.1,1236 > 10.1.1.3,80 +ip 40(20) 6 10.2.3.1,1237 > 10.1.1.4,80 +ip 40(20) 6 10.2.3.1,1238 > 10.1.1.4,80 +------------------------------- +ip 40(20) 6 10.2.3.1,1230 > 10.1.1.1,22 ip 40(20) 6 10.2.3.1,1231 > 10.1.1.1,23 ip 40(20) 6 10.2.3.1,1232 > 10.1.1.1,50 ip 40(20) 6 10.2.3.1,1233 > 10.1.1.1,79 diff --git a/contrib/ipfilter/test/expected/n8 b/contrib/ipfilter/test/expected/n8 new file mode 100644 index 0000000..7a26a26 --- /dev/null +++ b/contrib/ipfilter/test/expected/n8 @@ -0,0 +1,5 @@ +4500 0054 8bc1 0000 ff01 13d5 0a0a 0a01 0404 0404 0800 efdf 6220 0000 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +4500 0054 3fd5 4000 ff01 2fc8 0404 0404 0202 0202 0000 f7df 6220 0000 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +4500 0054 8bc1 0000 ff01 13d5 0a0a 0a01 0404 0404 0800 efde 6220 0001 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +4500 0054 3fd5 4000 ff01 2fc8 0404 0404 0202 0202 0000 f7de 6220 0001 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +------------------------------- diff --git a/contrib/ipfilter/test/expected/n9 b/contrib/ipfilter/test/expected/n9 new file mode 100644 index 0000000..39979fa --- /dev/null +++ b/contrib/ipfilter/test/expected/n9 @@ -0,0 +1,5 @@ +4500 0054 8bc1 0000 ff01 17d9 0202 0202 0a0a 0a01 0800 efdf 6220 0000 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +4500 0054 3fd5 4000 ff01 2fc8 0404 0404 0202 0202 0000 f7df 6220 0000 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +4500 0054 8bc1 0000 ff01 17d9 0202 0202 0a0a 0a01 0800 efde 6220 0001 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +4500 0054 3fd5 4000 ff01 2fc8 0404 0404 0202 0202 0000 f7de 6220 0001 3f6f 6e80 000b 0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 3637 +------------------------------- diff --git a/contrib/ipfilter/test/expected/ni1 b/contrib/ipfilter/test/expected/ni1 index 724d38e..be981f1 100644 --- a/contrib/ipfilter/test/expected/ni1 +++ b/contrib/ipfilter/test/expected/ni1 @@ -1,4 +1,4 @@ -4500 0028 4706 4000 0111 1eac 0606 0606 0404 0404 afc9 829e 0014 6308 0402 0000 3be5 468d 000a cfc3 -4500 0038 809a 0000 ff01 3121 0303 0303 0202 0202 0b00 5773 0000 0000 4500 0028 4706 4000 0111 26b4 0202 0202 0404 0404 afc9 829e 0014 6b10 -4500 0044 809a 0000 ff01 3115 0303 0303 0202 0202 0b00 0131 0000 0000 4500 0028 4706 4000 0111 26b4 0202 0202 0404 0404 afc9 829e 0014 6b10 0402 0000 3be5 468d 000a cfc3 +4500 0028 0000 4000 0111 65b2 0606 0606 0404 0404 afc9 829e 0014 6308 0402 0000 3be5 468d 000a cfc3 +4500 0038 809a 0000 ff01 3121 0303 0303 0202 0202 0b00 5773 0000 0000 4500 0028 0000 4000 0111 6dba 0202 0202 0404 0404 afc9 829e 0014 6b10 +4500 0044 809a 0000 ff01 3115 0303 0303 0202 0202 0b00 0131 0000 0000 4500 0028 0000 4000 0111 6dba 0202 0202 0404 0404 afc9 829e 0014 6b10 0402 0000 3be5 468d 000a cfc3 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni10 b/contrib/ipfilter/test/expected/ni10 index e784581..df7b03f 100644 --- a/contrib/ipfilter/test/expected/ni10 +++ b/contrib/ipfilter/test/expected/ni10 @@ -1,5 +1,5 @@ -4500 003c 4706 4000 ff06 20a2 0404 0404 0606 0606 5000 0050 0000 0001 0000 0000 a002 16d0 d0da 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 2f1f 0202 0202 0404 0404 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28aa 0404 0404 0202 0202 5000 0050 0000 0001 -4500 0058 809a 0000 ff01 2cfd 0303 0303 0404 0404 0303 113f 0000 0000 4500 003c 4706 4000 ff06 20a2 0404 0404 0606 0606 5000 0050 0000 0001 0000 0000 a002 16d0 d0da 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28ab 0404 0404 0202 0201 5000 0050 0000 0001 +4500 003c 4706 4000 ff06 20a2 0404 0404 0606 0606 5000 0050 0000 0001 0000 0000 a002 16d0 d0da 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 0000 0000 ff01 afb9 0202 0202 0404 0404 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28aa 0404 0404 0202 0202 5000 0050 0000 0001 +4500 0058 0001 0000 ff01 af98 0202 0202 0404 0404 0303 0937 0000 0000 4500 003c 4706 4000 ff06 28aa 0404 0404 0202 0202 5000 0050 0000 0001 0000 0000 a002 16d0 d8e2 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28ab 0404 0404 0202 0201 5000 0050 0000 0001 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni11 b/contrib/ipfilter/test/expected/ni11 index 8cc37f4..d6db012 100644 --- a/contrib/ipfilter/test/expected/ni11 +++ b/contrib/ipfilter/test/expected/ni11 @@ -1,5 +1,5 @@ -4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 271f 0a02 0202 0404 0404 0303 a7fb 0000 0000 4500 003c 4706 4000 ff06 20aa 0404 0404 0a02 0202 5000 0500 0000 0001 -4500 0058 809a 0000 ff01 2cfd 0303 0303 0404 0404 0303 0735 0000 0000 4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 0000 0000 ff01 a7b9 0a02 0202 0404 0404 0303 a7fb 0000 0000 4500 003c 4706 4000 ff06 20aa 0404 0404 0a02 0202 5000 0500 0000 0001 +4500 0058 0001 0000 ff01 a798 0a02 0202 0404 0404 0303 1137 0000 0000 4500 003c 4706 4000 ff06 20aa 0404 0404 0a02 0202 5000 0500 0000 0001 0000 0000 a002 16d0 cc32 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni12 b/contrib/ipfilter/test/expected/ni12 new file mode 100644 index 0000000..70f991b --- /dev/null +++ b/contrib/ipfilter/test/expected/ni12 @@ -0,0 +1,5 @@ +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9c40 0000 0001 0000 0000 a002 16d0 3ef4 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 809a 0000 ff01 2d1d 0303 0303 0404 0404 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 +4500 0058 809a 0000 ff01 2cfd 0303 0303 0404 0404 0303 0735 0000 0000 4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 +------------------------------- diff --git a/contrib/ipfilter/test/expected/ni13 b/contrib/ipfilter/test/expected/ni13 new file mode 100644 index 0000000..3848d39 --- /dev/null +++ b/contrib/ipfilter/test/expected/ni13 @@ -0,0 +1,32 @@ +4500 0030 5e11 4000 8006 3961 c0a8 7101 c0a8 7103 05e7 06bb abf0 4aa5 0000 0000 7002 faf0 21a1 0000 0204 05b4 0101 0402 +4500 002c 0000 4000 4006 d776 c0a8 7103 c0a8 7101 06bb 05e7 a564 68da abf0 4aa6 6012 8000 a348 0000 0204 05b4 +4500 00c4 5e12 4000 8006 38cc c0a8 7101 c0a8 7103 05e7 06bb abf0 4aa6 a564 68db 5018 faf0 e2a0 0000 009c 0001 1a2b 3c4d 0001 0000 0100 0000 0000 0001 0000 0001 0000 0a28 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 4d69 6372 6f73 6f66 7420 5769 6e64 6f77 7320 4e54 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00c4 0001 4000 4006 d6dd c0a8 7103 c0a8 7101 06bb 05e7 a564 68db abf0 4b42 5018 832c cecf 0000 009c 0001 1a2b 3c4d 0002 0000 0100 0100 0000 0000 0000 0000 0001 0001 6c6f 6361 6c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6c69 6e75 7800 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00d0 5e13 4000 8006 38bf c0a8 7101 c0a8 7103 05e7 06bb abf0 4b42 a564 6977 5018 fa54 ac07 0000 00a8 0001 1a2b 3c4d 0007 0000 4000 1331 0000 012c 05f5 e100 0000 0003 0000 0003 0040 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0048 0002 4000 4006 d758 c0a8 7103 c0a8 7101 06bb 05e7 a564 6977 abf0 4bea 5018 832c 36fa 0000 0020 0001 1a2b 3c4d 0008 0000 0000 4000 0100 0000 05f5 e100 0040 0000 0000 0000 +4500 0040 5e14 4000 8006 394e c0a8 7101 c0a8 7103 05e7 06bb abf0 4bea a564 6997 5018 fa34 e810 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 ffff ffff ffff ffff +4500 0039 5e15 0000 802f 792b c0a8 7101 c0a8 7103 3001 880b 0019 0000 0000 0000 ff03 c021 0100 0015 0104 0578 0506 577f 7c5b 0702 0802 0d03 06 +4500 0020 0003 0000 ff2f 5856 c0a8 7103 c0a8 7101 2081 880b 0000 4000 ffff ffff +4500 0028 0004 4000 4006 d776 c0a8 7103 c0a8 7101 06bb 05e7 a564 6997 abf0 4c02 5010 832c b5c1 0000 +4500 0038 0005 0000 ff2f 583c c0a8 7103 c0a8 7101 3001 880b 0018 4000 0000 0000 ff03 c021 0101 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 002f 0006 0000 ff2f 5844 c0a8 7103 c0a8 7101 3081 880b 000b 4000 0000 0001 0000 0000 ff03 c021 0400 0007 0d03 06 +4500 003c 5e16 0000 802f 7927 c0a8 7101 c0a8 7103 3081 880b 0018 0000 0000 0001 0000 0001 ff03 c021 0201 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 0036 5e17 0000 802f 792c c0a8 7101 c0a8 7103 3001 880b 0016 0000 0000 0002 ff03 c021 0101 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 003a 0007 0000 ff2f 5838 c0a8 7103 c0a8 7101 3081 880b 0016 4000 0000 0002 0000 0002 ff03 c021 0201 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 0032 0008 0000 ff2f 583f c0a8 7103 c0a8 7101 3001 880b 0012 4000 0000 0003 8021 0101 0010 0306 c0a8 0001 0206 002d 0f01 +4500 0040 5e18 4000 8006 394a c0a8 7101 c0a8 7103 05e7 06bb abf0 4c02 a564 6997 5018 fa34 e7f8 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 0000 0000 ffff ffff +4500 0038 5e19 0000 802f 7928 c0a8 7101 c0a8 7103 3081 880b 0014 0000 0000 0003 0000 0003 c021 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 0009 0000 ff2f 5832 c0a8 7103 c0a8 7101 3081 880b 001a 4000 0000 0004 0000 0003 ff03 c021 0702 0016 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 5e1a 0000 802f 7921 c0a8 7101 c0a8 7103 3081 880b 001a 0000 0000 0004 0000 0004 c021 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0044 000a 0000 ff2f 582b c0a8 7103 c0a8 7101 3081 880b 0020 4000 0000 0005 0000 0004 ff03 c021 0703 001c 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0030 5e1b 0000 802f 792e c0a8 7101 c0a8 7103 3081 880b 000c 0000 0000 0005 0000 0005 80fd 0104 000a 1206 0100 0001 +4500 002a 000b 0000 ff2f 5844 c0a8 7103 c0a8 7101 3081 880b 0006 4000 0000 0006 0000 0005 80fd 0101 0004 +4500 002c 000c 0000 ff2f 5841 c0a8 7103 c0a8 7101 3001 880b 000c 4000 0000 0007 80fd 0404 000a 1206 0100 0001 +4500 0048 5e1c 0000 802f 7915 c0a8 7101 c0a8 7103 3081 880b 0024 0000 0000 0006 0000 0007 8021 0105 0022 0306 0000 0000 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0042 000d 0000 ff2f 582a c0a8 7103 c0a8 7101 3081 880b 001e 4000 0000 0008 0000 0006 8021 0405 001c 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0030 5e1d 0000 802f 792c c0a8 7101 c0a8 7103 3081 880b 000c 0000 0000 0007 0000 0008 8021 0401 000a 0206 002d 0f01 +4500 0030 000e 0000 ff2f 583b c0a8 7103 c0a8 7101 3081 880b 000c 4000 0000 0009 0000 0007 8021 0102 000a 0306 c0a8 0001 +4500 002a 5e1e 0000 802f 7933 c0a8 7101 c0a8 7103 3081 880b 0006 0000 0000 0008 0000 0009 80fd 0201 0004 +4500 0032 5e1f 0000 802f 792a c0a8 7101 c0a8 7103 3001 880b 0012 0000 0000 0009 80fd 0506 0010 577f 7c5b 003c cd74 0000 02dc +4500 002a 000f 0000 ff2f 5840 c0a8 7103 c0a8 7101 3081 880b 0006 4000 0000 000a 0000 0009 80fd 0606 0004 +------------------------------- diff --git a/contrib/ipfilter/test/expected/ni14 b/contrib/ipfilter/test/expected/ni14 new file mode 100644 index 0000000..8521323 --- /dev/null +++ b/contrib/ipfilter/test/expected/ni14 @@ -0,0 +1,32 @@ +4500 0030 5e11 4000 8006 ec0b c0a8 7101 7f00 0001 05e7 06bb abf0 4aa5 0000 0000 7002 faf0 d44b 0000 0204 05b4 0101 0402 +4500 002c 0000 4000 4006 d776 c0a8 7103 c0a8 7101 06bb 05e7 a564 68da abf0 4aa6 6012 8000 a348 0000 0204 05b4 +4500 00c4 5e12 4000 8006 eb76 c0a8 7101 7f00 0001 05e7 06bb abf0 4aa6 a564 68db 5018 faf0 954b 0000 009c 0001 1a2b 3c4d 0001 0000 0100 0000 0000 0001 0000 0001 0000 0a28 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 4d69 6372 6f73 6f66 7420 5769 6e64 6f77 7320 4e54 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00c4 0001 4000 4006 d6dd c0a8 7103 c0a8 7101 06bb 05e7 a564 68db abf0 4b42 5018 832c cecf 0000 009c 0001 1a2b 3c4d 0002 0000 0100 0100 0000 0000 0000 0000 0001 0001 6c6f 6361 6c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6c69 6e75 7800 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00d0 5e13 4000 8006 eb69 c0a8 7101 7f00 0001 05e7 06bb abf0 4b42 a564 6977 5018 fa54 5eb2 0000 00a8 0001 1a2b 3c4d 0007 0000 4000 1331 0000 012c 05f5 e100 0000 0003 0000 0003 0040 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0048 0002 4000 4006 d758 c0a8 7103 c0a8 7101 06bb 05e7 a564 6977 abf0 4bea 5018 832c 36fa 0000 0020 0001 1a2b 3c4d 0008 0000 0000 4000 0100 0000 05f5 e100 0040 0000 0000 0000 +4500 0040 5e14 4000 8006 ebf8 c0a8 7101 7f00 0001 05e7 06bb abf0 4bea a564 6997 5018 fa34 9abb 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 ffff ffff ffff ffff +4500 0039 5e15 0000 802f 2bd6 c0a8 7101 7f00 0001 3001 880b 0019 0000 0000 0000 ff03 c021 0100 0015 0104 0578 0506 577f 7c5b 0702 0802 0d03 06 +4500 0020 0003 0000 ff2f 5856 c0a8 7103 c0a8 7101 2081 880b 0000 4000 ffff ffff +4500 0028 0004 4000 4006 d776 c0a8 7103 c0a8 7101 06bb 05e7 a564 6997 abf0 4c02 5010 832c b5c1 0000 +4500 0038 0005 0000 ff2f 583c c0a8 7103 c0a8 7101 3001 880b 0018 4000 0000 0000 ff03 c021 0101 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 002f 0006 0000 ff2f 5844 c0a8 7103 c0a8 7101 3081 880b 000b 4000 0000 0001 0000 0000 ff03 c021 0400 0007 0d03 06 +4500 003c 5e16 0000 802f 2bd2 c0a8 7101 7f00 0001 3081 880b 0018 0000 0000 0001 0000 0001 ff03 c021 0201 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 0036 5e17 0000 802f 2bd7 c0a8 7101 7f00 0001 3001 880b 0016 0000 0000 0002 ff03 c021 0101 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 003a 0007 0000 ff2f 5838 c0a8 7103 c0a8 7101 3081 880b 0016 4000 0000 0002 0000 0002 ff03 c021 0201 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 0032 0008 0000 ff2f a594 c0a8 7103 c0a8 7101 3001 880b 0012 4000 0000 0003 8021 0101 0010 0306 c0a8 0001 0206 002d 0f01 +4500 0040 5e18 4000 8006 ebf4 c0a8 7101 7f00 0001 05e7 06bb abf0 4c02 a564 6997 5018 fa34 9aa3 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 0000 0000 ffff ffff +4500 0038 5e19 0000 802f 2bd3 c0a8 7101 7f00 0001 3081 880b 0014 0000 0000 0003 0000 0003 c021 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 0009 0000 ff2f a587 c0a8 7103 c0a8 7101 3081 880b 001a 4000 0000 0004 0000 0003 ff03 c021 0702 0016 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 5e1a 0000 802f 2bcc c0a8 7101 7f00 0001 3081 880b 001a 0000 0000 0004 0000 0004 c021 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0044 000a 0000 ff2f a580 c0a8 7103 c0a8 7101 3081 880b 0020 4000 0000 0005 0000 0004 ff03 c021 0703 001c 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0030 5e1b 0000 802f 2bd9 c0a8 7101 7f00 0001 3081 880b 000c 0000 0000 0005 0000 0005 80fd 0104 000a 1206 0100 0001 +4500 002a 000b 0000 ff2f a599 c0a8 7103 c0a8 7101 3081 880b 0006 4000 0000 0006 0000 0005 80fd 0101 0004 +4500 002c 000c 0000 ff2f a596 c0a8 7103 c0a8 7101 3001 880b 000c 4000 0000 0007 80fd 0404 000a 1206 0100 0001 +4500 0048 5e1c 0000 802f 2bc0 c0a8 7101 7f00 0001 3081 880b 0024 0000 0000 0006 0000 0007 8021 0105 0022 0306 0000 0000 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0042 000d 0000 ff2f a57f c0a8 7103 c0a8 7101 3081 880b 001e 4000 0000 0008 0000 0006 8021 0405 001c 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0030 5e1d 0000 802f 2bd7 c0a8 7101 7f00 0001 3081 880b 000c 0000 0000 0007 0000 0008 8021 0401 000a 0206 002d 0f01 +4500 0030 000e 0000 ff2f a590 c0a8 7103 c0a8 7101 3081 880b 000c 4000 0000 0009 0000 0007 8021 0102 000a 0306 c0a8 0001 +4500 002a 5e1e 0000 802f 2bdc c0a8 7101 7f00 0001 3081 880b 0006 0000 0000 0008 0000 0009 80fd 0201 0004 +4500 0032 5e1f 0000 802f 2bd3 c0a8 7101 7f00 0001 3001 880b 0012 0000 0000 0009 80fd 0506 0010 577f 7c5b 003c cd74 0000 02dc +4500 002a 000f 0000 ff2f a595 c0a8 7103 c0a8 7101 3081 880b 0006 4000 0000 000a 0000 0009 80fd 0606 0004 +------------------------------- diff --git a/contrib/ipfilter/test/expected/ni15 b/contrib/ipfilter/test/expected/ni15 new file mode 100644 index 0000000..1c59de1 --- /dev/null +++ b/contrib/ipfilter/test/expected/ni15 @@ -0,0 +1,32 @@ +4500 0030 0000 4000 8006 9772 c0a8 7101 c0a8 7103 05e7 06bb abf0 4aa5 0000 0000 7002 faf0 21a1 0000 0204 05b4 0101 0402 +4500 002c 69a6 4000 4006 6dd0 c0a8 7103 c0a8 7101 06bb 05e7 a564 68da abf0 4aa6 6012 8000 a348 0000 0204 05b4 +4500 00c4 0001 4000 8006 96dd c0a8 7101 c0a8 7103 05e7 06bb abf0 4aa6 a564 68db 5018 faf0 e2a0 0000 009c 0001 1a2b 3c4d 0001 0000 0100 0000 0000 0001 0000 0001 0000 0a28 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 4d69 6372 6f73 6f66 7420 5769 6e64 6f77 7320 4e54 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00c4 69a7 4000 4006 6d37 c0a8 7103 c0a8 7101 06bb 05e7 a564 68db abf0 4b42 5018 832c cecf 0000 009c 0001 1a2b 3c4d 0002 0000 0100 0100 0000 0000 0000 0000 0001 0001 6c6f 6361 6c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6c69 6e75 7800 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00d0 0002 4000 8006 96d0 c0a8 7101 c0a8 7103 05e7 06bb abf0 4b42 a564 6977 5018 fa54 ac07 0000 00a8 0001 1a2b 3c4d 0007 0000 4000 1331 0000 012c 05f5 e100 0000 0003 0000 0003 0040 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0048 69a8 4000 4006 6db2 c0a8 7103 c0a8 7101 06bb 05e7 a564 6977 abf0 4bea 5018 832c 36fa 0000 0020 0001 1a2b 3c4d 0008 0000 0000 4000 0100 0000 05f5 e100 0040 0000 0000 0000 +4500 0040 0003 4000 8006 975f c0a8 7101 c0a8 7103 05e7 06bb abf0 4bea a564 6997 5018 fa34 e810 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 ffff ffff ffff ffff +4500 0039 0004 0000 802f d73c c0a8 7101 c0a8 7103 3001 880b 0019 0000 0000 0000 ff03 c021 0100 0015 0104 0578 0506 577f 7c5b 0702 0802 0d03 06 +4500 0020 69a9 0000 ff2f eeaf c0a8 7103 c0a8 7101 2081 880b 0000 4000 ffff ffff +4500 0028 69aa 4000 4006 6dd0 c0a8 7103 c0a8 7101 06bb 05e7 a564 6997 abf0 4c02 5010 832c b5c1 0000 +4500 0038 69ab 0000 ff2f ee95 c0a8 7103 c0a8 7101 3001 880b 0018 4000 0000 0000 ff03 c021 0101 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 002f 69ac 0000 ff2f ee9d c0a8 7103 c0a8 7101 3081 880b 000b 4000 0000 0001 0000 0000 ff03 c021 0400 0007 0d03 06 +4500 003c 0005 0000 802f d738 c0a8 7101 c0a8 7103 3081 880b 0018 0000 0000 0001 0000 0001 ff03 c021 0201 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 0036 0006 0000 802f d73d c0a8 7101 c0a8 7103 3001 880b 0016 0000 0000 0002 ff03 c021 0101 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 003a 69ad 0000 ff2f ee91 c0a8 7103 c0a8 7101 3081 880b 0016 4000 0000 0002 0000 0002 ff03 c021 0201 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 0032 69ae 0000 ff2f ee98 c0a8 7103 c0a8 7101 3001 880b 0012 4000 0000 0003 8021 0101 0010 0306 c0a8 0001 0206 002d 0f01 +4500 0040 0007 4000 8006 975b c0a8 7101 c0a8 7103 05e7 06bb abf0 4c02 a564 6997 5018 fa34 e7f8 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 0000 0000 ffff ffff +4500 0038 0008 0000 802f d739 c0a8 7101 c0a8 7103 3081 880b 0014 0000 0000 0003 0000 0003 c021 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 69af 0000 ff2f ee8b c0a8 7103 c0a8 7101 3081 880b 001a 4000 0000 0004 0000 0003 ff03 c021 0702 0016 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 0009 0000 802f d732 c0a8 7101 c0a8 7103 3081 880b 001a 0000 0000 0004 0000 0004 c021 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0044 69b0 0000 ff2f ee84 c0a8 7103 c0a8 7101 3081 880b 0020 4000 0000 0005 0000 0004 ff03 c021 0703 001c 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0030 000a 0000 802f d73f c0a8 7101 c0a8 7103 3081 880b 000c 0000 0000 0005 0000 0005 80fd 0104 000a 1206 0100 0001 +4500 002a 69b1 0000 ff2f ee9d c0a8 7103 c0a8 7101 3081 880b 0006 4000 0000 0006 0000 0005 80fd 0101 0004 +4500 002c 69b2 0000 ff2f ee9a c0a8 7103 c0a8 7101 3001 880b 000c 4000 0000 0007 80fd 0404 000a 1206 0100 0001 +4500 0048 000b 0000 802f d726 c0a8 7101 c0a8 7103 3081 880b 0024 0000 0000 0006 0000 0007 8021 0105 0022 0306 0000 0000 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0042 69b3 0000 ff2f ee83 c0a8 7103 c0a8 7101 3081 880b 001e 4000 0000 0008 0000 0006 8021 0405 001c 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0030 000c 0000 802f d73d c0a8 7101 c0a8 7103 3081 880b 000c 0000 0000 0007 0000 0008 8021 0401 000a 0206 002d 0f01 +4500 0030 69b4 0000 ff2f ee94 c0a8 7103 c0a8 7101 3081 880b 000c 4000 0000 0009 0000 0007 8021 0102 000a 0306 c0a8 0001 +4500 002a 000d 0000 802f d742 c0a8 7101 c0a8 7103 3081 880b 0006 0000 0000 0008 0000 0009 80fd 0201 0004 +4500 0032 000e 0000 802f d739 c0a8 7101 c0a8 7103 3001 880b 0012 0000 0000 0009 80fd 0506 0010 577f 7c5b 003c cd74 0000 02dc +4500 002a 69b5 0000 ff2f ee99 c0a8 7103 c0a8 7101 3081 880b 0006 4000 0000 000a 0000 0009 80fd 0606 0004 +------------------------------- diff --git a/contrib/ipfilter/test/expected/ni16 b/contrib/ipfilter/test/expected/ni16 new file mode 100644 index 0000000..c30b0d2 --- /dev/null +++ b/contrib/ipfilter/test/expected/ni16 @@ -0,0 +1,32 @@ +4500 0030 0000 4000 8006 9772 c0a8 7101 c0a8 7103 05e7 06bb abf0 4aa5 0000 0000 7002 faf0 21a1 0000 0204 05b4 0101 0402 +4500 002c 69a6 4000 4006 9376 c0a8 7103 0a02 0202 06bb 05e7 a564 68da abf0 4aa6 6012 8000 c8ee 0000 0204 05b4 +4500 00c4 0001 4000 8006 96dd c0a8 7101 c0a8 7103 05e7 06bb abf0 4aa6 a564 68db 5018 faf0 e2a0 0000 009c 0001 1a2b 3c4d 0001 0000 0100 0000 0000 0001 0000 0001 0000 0a28 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 4d69 6372 6f73 6f66 7420 5769 6e64 6f77 7320 4e54 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00c4 69a7 4000 4006 92dd c0a8 7103 0a02 0202 06bb 05e7 a564 68db abf0 4b42 5018 832c f475 0000 009c 0001 1a2b 3c4d 0002 0000 0100 0100 0000 0000 0000 0000 0001 0001 6c6f 6361 6c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6c69 6e75 7800 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 00d0 0002 4000 8006 96d0 c0a8 7101 c0a8 7103 05e7 06bb abf0 4b42 a564 6977 5018 fa54 ac07 0000 00a8 0001 1a2b 3c4d 0007 0000 4000 1331 0000 012c 05f5 e100 0000 0003 0000 0003 0040 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0048 69a8 4000 4006 9358 c0a8 7103 0a02 0202 06bb 05e7 a564 6977 abf0 4bea 5018 832c 5ca0 0000 0020 0001 1a2b 3c4d 0008 0000 0000 4000 0100 0000 05f5 e100 0040 0000 0000 0000 +4500 0040 0003 4000 8006 975f c0a8 7101 c0a8 7103 05e7 06bb abf0 4bea a564 6997 5018 fa34 e810 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 ffff ffff ffff ffff +4500 0039 0004 0000 802f d73c c0a8 7101 c0a8 7103 3001 880b 0019 0000 0000 0000 ff03 c021 0100 0015 0104 0578 0506 577f 7c5b 0702 0802 0d03 06 +4500 0020 69a9 0000 ff2f 1456 c0a8 7103 0a02 0202 2081 880b 0000 4000 ffff ffff +4500 0028 69aa 4000 4006 9376 c0a8 7103 0a02 0202 06bb 05e7 a564 6997 abf0 4c02 5010 832c db67 0000 +4500 0038 69ab 0000 ff2f 143c c0a8 7103 0a02 0202 3001 880b 0018 4000 0000 0000 ff03 c021 0101 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 002f 69ac 0000 ff2f 1444 c0a8 7103 0a02 0202 3081 880b 000b 4000 0000 0001 0000 0000 ff03 c021 0400 0007 0d03 06 +4500 003c 0005 0000 802f d738 c0a8 7101 c0a8 7103 3081 880b 0018 0000 0000 0001 0000 0001 ff03 c021 0201 0014 0206 0000 0000 0506 22d9 0cfa 0702 0802 +4500 0036 0006 0000 802f d73d c0a8 7101 c0a8 7103 3001 880b 0016 0000 0000 0002 ff03 c021 0101 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 003a 69ad 0000 ff2f 1438 c0a8 7103 0a02 0202 3081 880b 0016 4000 0000 0002 0000 0002 ff03 c021 0201 0012 0104 0578 0506 577f 7c5b 0702 0802 +4500 0032 69ae 0000 ff2f 143f c0a8 7103 0a02 0202 3001 880b 0012 4000 0000 0003 8021 0101 0010 0306 c0a8 0001 0206 002d 0f01 +4500 0040 0007 4000 8006 975b c0a8 7101 c0a8 7103 05e7 06bb abf0 4c02 a564 6997 5018 fa34 e7f8 0000 0018 0001 1a2b 3c4d 000f 0000 0000 0000 0000 0000 ffff ffff +4500 0038 0008 0000 802f d739 c0a8 7101 c0a8 7103 3081 880b 0014 0000 0000 0003 0000 0003 c021 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 69af 0000 ff2f 1432 c0a8 7103 0a02 0202 3081 880b 001a 4000 0000 0004 0000 0003 ff03 c021 0702 0016 0c02 0012 577f 7c5b 4d53 5241 5356 352e 3130 +4500 003e 0009 0000 802f d732 c0a8 7101 c0a8 7103 3081 880b 001a 0000 0000 0004 0000 0004 c021 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0044 69b0 0000 ff2f 142b c0a8 7103 0a02 0202 3081 880b 0020 4000 0000 0005 0000 0004 ff03 c021 0703 001c 0c03 0018 577f 7c5b 4d53 5241 532d 302d 434c 4159 4d4f 4f52 +4500 0030 000a 0000 802f d73f c0a8 7101 c0a8 7103 3081 880b 000c 0000 0000 0005 0000 0005 80fd 0104 000a 1206 0100 0001 +4500 002a 69b1 0000 ff2f 1444 c0a8 7103 0a02 0202 3081 880b 0006 4000 0000 0006 0000 0005 80fd 0101 0004 +4500 002c 69b2 0000 ff2f 1441 c0a8 7103 0a02 0202 3001 880b 000c 4000 0000 0007 80fd 0404 000a 1206 0100 0001 +4500 0048 000b 0000 802f d726 c0a8 7101 c0a8 7103 3081 880b 0024 0000 0000 0006 0000 0007 8021 0105 0022 0306 0000 0000 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0042 69b3 0000 ff2f 142a c0a8 7103 0a02 0202 3081 880b 001e 4000 0000 0008 0000 0006 8021 0405 001c 8106 0000 0000 8206 0000 0000 8306 0000 0000 8406 0000 0000 +4500 0030 000c 0000 802f d73d c0a8 7101 c0a8 7103 3081 880b 000c 0000 0000 0007 0000 0008 8021 0401 000a 0206 002d 0f01 +4500 0030 69b4 0000 ff2f 143b c0a8 7103 0a02 0202 3081 880b 000c 4000 0000 0009 0000 0007 8021 0102 000a 0306 c0a8 0001 +4500 002a 000d 0000 802f d744 c0a8 7101 c0a8 7103 3081 880b 0006 0000 0000 0008 0000 0009 80fd 0201 0004 +4500 0032 000e 0000 802f d73b c0a8 7101 c0a8 7103 3001 880b 0012 0000 0000 0009 80fd 0506 0010 577f 7c5b 003c cd74 0000 02dc +4500 002a 69b5 0000 ff2f 1440 c0a8 7103 0a02 0202 3081 880b 0006 4000 0000 000a 0000 0009 80fd 0606 0004 +------------------------------- diff --git a/contrib/ipfilter/test/expected/ni2 b/contrib/ipfilter/test/expected/ni2 index bf05cf0..6aef39f 100644 --- a/contrib/ipfilter/test/expected/ni2 +++ b/contrib/ipfilter/test/expected/ni2 @@ -1,10 +1,10 @@ -4510 002c bd0d 4000 3e06 bbd1 0101 0101 c0a8 0133 9c40 0077 a664 2485 0000 0000 6002 4000 2ca8 0000 0204 05b4 -4500 002c ce83 4000 7e06 606b c0a8 0133 0a01 0201 0077 05f6 fbdf 1a21 a664 2486 6012 2238 c0a8 0000 0204 05b4 -4510 0028 bd0e 4000 3e06 bbd4 0101 0101 c0a8 0133 9c40 0077 a664 2486 fbdf 1a22 5010 4470 29e3 0000 -4500 005b cf83 4000 7e06 5f3c c0a8 0133 0a01 0201 0077 05f6 fbdf 1a22 a664 2486 5018 2238 ce2a 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0a -4510 0028 bd18 4000 3e06 bbca 0101 0101 c0a8 0133 9c40 0077 a664 2486 fbdf 1a55 5010 4470 29b0 0000 -4510 002e bd1e 4000 3e06 bbbe 0101 0101 c0a8 0133 9c40 0077 a664 2486 fbdf 1a55 5018 4470 1c98 0000 0000 0000 0d0a -4500 0048 e383 4000 7e06 4b4f c0a8 0133 0a01 0201 0077 05f6 fbdf 1a55 a664 248c 5018 2232 d80a 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 -4500 05dc e483 4000 7e06 44bb c0a8 0133 0a01 0201 0077 05f6 fbdf 1a75 a664 248c 5010 2232 9f2d 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3331 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 -4500 0038 d71d 4000 4001 9fca 0101 0101 c0a8 0133 0304 444f 0000 05a0 4500 05dc e483 4000 7e06 4ebb c0a8 0133 0101 0101 0077 9c40 fbdf 1a75 +4510 002c 0000 4000 3e06 78df 0101 0101 c0a8 0133 9c40 0077 a664 2485 0000 0000 6002 4000 2ca8 0000 0204 05b4 +4500 002c ce83 4000 7e06 606b c0a8 0133 0a01 0201 0077 05f6 fbdf 1a21 a664 2486 6012 2238 c0a8 0000 0204 05b4 +4510 0028 0001 4000 3e06 78e2 0101 0101 c0a8 0133 9c40 0077 a664 2486 fbdf 1a22 5010 4470 29e3 0000 +4500 005b cf83 4000 7e06 5f3c c0a8 0133 0a01 0201 0077 05f6 fbdf 1a22 a664 2486 5018 2238 ce2a 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0a +4510 0028 0002 4000 3e06 78e1 0101 0101 c0a8 0133 9c40 0077 a664 2486 fbdf 1a55 5010 4470 29b0 0000 +4510 002e 0003 4000 3e06 78da 0101 0101 c0a8 0133 9c40 0077 a664 2486 fbdf 1a55 5018 4470 1c98 0000 0000 0000 0d0a +4500 0048 e383 4000 7e06 4b4f c0a8 0133 0a01 0201 0077 05f6 fbdf 1a55 a664 248c 5018 2232 d80a 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 05dc e483 4000 7e06 44bb c0a8 0133 0a01 0201 0077 05f6 fbdf 1a75 a664 248c 5010 2232 9f2d 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3331 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 1111 2222 3333 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0038 0004 4000 4001 76e4 0101 0101 c0a8 0133 0304 444f 0000 05a0 4500 05dc e483 4000 7e06 4ebb c0a8 0133 0101 0101 0077 9c40 fbdf 1a75 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni3 b/contrib/ipfilter/test/expected/ni3 index cf535f3..600b624 100644 --- a/contrib/ipfilter/test/expected/ni3 +++ b/contrib/ipfilter/test/expected/ni3 @@ -1,4 +1,4 @@ -4500 003c 4706 4000 ff06 20a2 0606 0606 0404 0404 5000 0050 0000 0001 0000 0000 a002 16d0 d0da 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 3121 0303 0303 0202 0202 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 -4500 0058 809a 0000 ff01 3101 0303 0303 0202 0202 0303 0937 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 0000 0000 a002 16d0 d8e2 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 003c 0000 4000 ff06 67a8 0606 0606 0404 0404 5000 0050 0000 0001 0000 0000 a002 16d0 d0da 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 809a 0000 ff01 3121 0303 0303 0202 0202 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 +4500 0058 809a 0000 ff01 3101 0303 0303 0202 0202 0303 0937 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 0000 0000 a002 16d0 d8e2 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni4 b/contrib/ipfilter/test/expected/ni4 index 95382cd..cd5ebac 100644 --- a/contrib/ipfilter/test/expected/ni4 +++ b/contrib/ipfilter/test/expected/ni4 @@ -1,4 +1,4 @@ -4500 003c 4706 4000 ff06 20a2 0606 0606 0404 0404 9c40 0050 0000 0001 0000 0000 a002 16d0 849a 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 3121 0303 0303 0202 0202 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 -4500 0058 809a 0000 ff01 3101 0303 0303 0202 0202 0303 0937 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 0000 0000 a002 16d0 d8e2 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 003c 0000 4000 ff06 67a8 0606 0606 0404 0404 9c40 0050 0000 0001 0000 0000 a002 16d0 849a 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 809a 0000 ff01 3121 0303 0303 0202 0202 0303 acab 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 +4500 0058 809a 0000 ff01 3101 0303 0303 0202 0202 0303 0937 0000 0000 4500 003c 4706 4000 ff06 28aa 0202 0202 0404 0404 5000 0050 0000 0001 0000 0000 a002 16d0 d8e2 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni5 b/contrib/ipfilter/test/expected/ni5 index 449c2c4..a64d812 100644 --- a/contrib/ipfilter/test/expected/ni5 +++ b/contrib/ipfilter/test/expected/ni5 @@ -1,48 +1,47 @@ -4500 002c 10c9 4000 ff06 f232 0101 0101 96cb e002 8032 0015 bd6b c9c8 0000 0000 6002 2238 f5a2 0000 0204 05b4 -4500 002c ffdd 4000 ef06 5374 96cb e002 c0a8 0103 0015 8032 3786 76c4 bd6b c9c9 6012 269c 8369 0000 0204 0584 -4500 0028 10ca 4000 ff06 f235 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 76c5 5010 269c 5aa0 0000 -4500 006f ffde 4000 ef06 5330 96cb e002 c0a8 0103 0015 8032 3786 76c5 bd6b c9c9 5018 269c 967e 0000 3232 302d 636f 6f6d 6273 2e61 6e75 2e65 6475 2e61 7520 4e63 4654 5064 2053 6572 7665 7220 2866 7265 6520 6564 7563 6174 696f 6e61 6c20 6c69 6365 6e73 6529 2072 6561 6479 2e0d 0a -4500 0028 10cb 4000 ff06 f234 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 770c 5010 269c 5a59 0000 -ippr_ftp_server_valid:junk after cmd[220-Maintained by RSSS and RSPAS IT Staff (previously known as Coombs Comp] -4500 00c7 ffdf 4000 ef06 52d7 96cb e002 c0a8 0103 0015 8032 3786 770c bd6b c9c9 5018 269c 1087 0000 3232 302d 0d0a 3232 302d 4d61 696e 7461 696e 6564 2062 7920 5253 5353 2061 6e64 2052 5350 4153 2049 5420 5374 6166 6620 2870 7265 7669 6f75 736c 7920 6b6e 6f77 6e20 6173 2043 6f6f 6d62 7320 436f 6d70 7574 696e 6720 556e 6974 290d 0a32 3230 2d41 6e79 2070 726f 626c 656d 7320 636f 6e74 6163 7420 6674 706d 6173 7465 7240 636f 6f6d 6273 2e61 6e75 2e65 6475 2e61 750d 0a32 3230 2d0d 0a32 3230 200d 0a -4500 0028 10cc 4000 ff06 f233 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 77ab 5010 269c 59ba 0000 -4500 0038 10cd 4000 ff06 f222 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 77ab 5018 269c d1c5 0000 5553 4552 2061 6e6f 6e79 6d6f 7573 0d0a -4500 0028 ffe0 4000 ef06 5375 96cb e002 c0a8 0103 0015 8032 3786 77ab bd6b c9d9 5010 269c 9a00 0000 -4500 006c ffe1 4000 ef06 5330 96cb e002 c0a8 0103 0015 8032 3786 77ab bd6b c9d9 5018 269c b00f 0000 3333 3120 4775 6573 7420 6c6f 6769 6e20 6f6b 2c20 7365 6e64 2079 6f75 7220 636f 6d70 6c65 7465 2065 2d6d 6169 6c20 6164 6472 6573 7320 6173 2070 6173 7377 6f72 642e 0d0a -4500 0028 10ce 4000 ff06 f231 0101 0101 96cb e002 8032 0015 bd6b c9d9 3786 77ef 5010 269c 5966 0000 -4500 0036 10cf 4000 ff06 f222 0101 0101 96cb e002 8032 0015 bd6b c9d9 3786 77ef 5018 269c 373f 0000 5041 5353 2061 7661 6c6f 6e40 0d0a -4500 005f ffe2 4000 ef06 533c 96cb e002 c0a8 0103 0015 8032 3786 77ef bd6b c9e7 5018 269c 895e 0000 3233 302d 596f 7520 6172 6520 7573 6572 2023 3420 6f66 2035 3020 7369 6d75 6c74 616e 656f 7573 2075 7365 7273 2061 6c6c 6f77 6564 2e0d 0a -4500 0028 10d0 4000 ff06 f22f 0101 0101 96cb e002 8032 0015 bd6b c9e7 3786 7826 5010 269c 5921 0000 -4500 0099 ffe3 4000 ef06 5301 96cb e002 c0a8 0103 0015 8032 3786 7826 bd6b c9e7 5018 269c d399 0000 3233 302d 0d0a 3233 302d 0d0a 3233 302d 4869 2e20 2057 6527 7265 2063 6c65 616e 696e 6720 7570 2e20 2041 6e79 2066 6565 6462 6163 6b20 6d6f 7374 2077 656c 636f 6d65 2e20 3130 2041 7567 2030 300d 0a32 3330 2d0d 0a32 3330 204c 6f67 6765 6420 696e 2061 6e6f 6e79 6d6f 7573 6c79 2e0d 0a -4500 0028 10d1 4000 ff06 f22e 0101 0101 96cb e002 8032 0015 bd6b c9e7 3786 7897 5010 269c 58b0 0000 -4500 0030 10d2 4000 ff06 f225 0101 0101 96cb e002 8032 0015 bd6b c9e7 3786 7897 5018 269c 86ae 0000 5459 5045 2049 0d0a -4500 0038 ffe4 4000 ef06 5361 96cb e002 c0a8 0103 0015 8032 3786 7897 bd6b c9ef 5018 269c 5fae 0000 3230 3020 5479 7065 206f 6b61 792e 0d0a -4500 0028 10d3 4000 ff06 f22c 0101 0101 96cb e002 8032 0015 bd6b c9ef 3786 78a7 5010 269c 5898 0000 -4500 003d 10d4 4000 ff06 f216 0101 0101 96cb e002 8032 0015 bd6b c9ef 3786 78a7 5018 269c 4b67 0000 504f 5254 2031 2c31 2c31 2c31 2c31 3238 2c35 310d 0a -4500 0046 ffe5 4000 ef06 5352 96cb e002 c0a8 0103 0015 8032 3786 78a7 bd6b ca0c 5018 269c dbc3 0000 3230 3020 504f 5254 2063 6f6d 6d61 6e64 2073 7563 6365 7373 6675 6c2e 0d0a -4500 0030 10d5 4000 ff06 f222 0101 0101 96cb e002 8032 0015 bd6b ca04 3786 78c5 5018 269c 866b 0000 5459 5045 2041 0d0a -4500 0038 ffe6 4000 ef06 535f 96cb e002 c0a8 0103 0015 8032 3786 78c5 bd6b ca14 5018 269c 5f5b 0000 3230 3020 5479 7065 206f 6b61 792e 0d0a -4500 002e 10d6 4000 ff06 f223 0101 0101 96cb e002 8032 0015 bd6b ca0c 3786 78d5 5018 269c a994 0000 4e4c 5354 0d0a -4500 002c ffe7 4000 ef06 536a 96cb e002 c0a8 0103 0014 8033 d9f8 11d4 0000 0000 6002 2238 d190 0000 0204 0584 -4500 002c 10d7 4000 ff06 327b c0a8 0103 96cb e002 8033 0014 bd78 5c12 d9f8 11d5 6012 02f8 d734 0000 0204 0584 -4500 0028 ffe8 4000 ef06 536d 96cb e002 c0a8 0103 0014 8033 d9f8 11d5 bd78 5c13 5010 269c cb1d 0000 -4500 005d ffe9 4000 ef06 5337 96cb e002 c0a8 0103 0015 8032 3786 78d5 bd6b ca1a 5018 269c eed0 0000 3135 3020 4f70 656e 696e 6720 4153 4349 4920 6d6f 6465 2064 6174 6120 636f 6e6e 6563 7469 6f6e 2066 6f72 202f 6269 6e2f 6c73 2e0d 0a -4500 0028 10d8 4000 ff06 327e c0a8 0103 96cb e002 8033 0014 bd78 5c13 d9f8 11d5 5010 6348 8e71 0000 -4500 0063 ffea 4000 ef06 5330 96cb e002 c0a8 0103 0014 8033 d9f8 11d5 bd78 5c13 5018 269c a315 0000 636f 6f6d 6273 7061 7065 7273 0d0a 6465 7074 730d 0a66 6f75 6e64 2d66 696c 6573 0d0a 696e 636f 6d69 6e67 0d0a 6e6c 632d 7465 7374 0d0a 7075 620d 0a -4500 0028 10d9 4000 ff06 327d c0a8 0103 96cb e002 8033 0014 bd78 5c13 d9f8 1210 5010 6348 8e36 0000 -4500 0028 ffeb 4000 ef06 536a 96cb e002 c0a8 0103 0014 8033 d9f8 1210 bd78 5c13 5011 269c cae1 0000 -4500 0028 10da 4000 ff06 327c c0a8 0103 96cb e002 8033 0014 bd78 5c13 d9f8 1211 5010 6348 8e35 0000 -4500 0028 10db 4000 ff06 327b c0a8 0103 96cb e002 8033 0014 bd78 5c13 d9f8 1211 5011 6348 8e34 0000 -4500 0028 ffec 4000 ef06 5369 96cb e002 c0a8 0103 0014 8033 d9f8 1211 bd78 5c14 5010 269c cae0 0000 -4500 0028 10dc 4000 ff06 f223 0101 0101 96cb e002 8032 0015 bd6b ca12 3786 790a 5010 269c 5812 0000 -4500 0040 ffed 4000 ef06 5350 96cb e002 c0a8 0103 0015 8032 3786 790a bd6b ca1a 5018 269c 7c9e 0000 3232 3620 4c69 7374 696e 6720 636f 6d70 6c65 7465 642e 0d0a -4500 0030 10dd 4000 ff06 f21a 0101 0101 96cb e002 8032 0015 bd6b ca12 3786 7922 5018 269c 85f8 0000 5459 5045 2049 0d0a -4500 0038 ffee 4000 ef06 5357 96cb e002 c0a8 0103 0015 8032 3786 7922 bd6b ca22 5018 269c 5ef0 0000 3230 3020 5479 7065 206f 6b61 792e 0d0a -4500 0028 10de 4000 ff06 f221 0101 0101 96cb e002 8032 0015 bd6b ca1a 3786 7932 5010 269c 57e2 0000 -4500 002e 10df 4000 ff06 f21a 0101 0101 96cb e002 8032 0015 bd6b ca1a 3786 7932 5018 269c b020 0000 5155 4954 0d0a -4500 0036 ffef 4000 ef06 5358 96cb e002 c0a8 0103 0015 8032 3786 7932 bd6b ca28 5018 269c a93c 0000 3232 3120 476f 6f64 6279 652e 0d0a -4500 0028 10e0 4000 ff06 f21f 0101 0101 96cb e002 8032 0015 bd6b ca20 3786 7940 5011 269c 57cd 0000 -4500 0028 fff0 4000 ef06 5365 96cb e002 c0a8 0103 0015 8032 3786 7940 bd6b ca28 5011 269c 981b 0000 -4500 0028 10e1 4000 ff06 3275 c0a8 0103 96cb e002 8032 0015 bd6b ca25 3786 7941 5010 269c 981e 0000 -4500 0028 fff1 4000 ef06 5364 96cb e002 c0a8 0103 0015 8032 3786 7941 bd6b ca29 5010 269c 981a 0000 +4500 002c 0000 4000 ff06 02fc 0101 0101 96cb e002 8032 0015 bd6b c9c8 0000 0000 6002 2238 f5a2 0000 0204 05b4 +4500 002c ffdd 4000 ef06 5374 96cb e002 c0a8 0103 0015 8032 3786 76c4 bd6b c9c9 6012 269c 8369 0000 0204 0584 +4500 0028 0001 4000 ff06 02ff 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 76c5 5010 269c 5aa0 0000 +4500 006f ffde 4000 ef06 5330 96cb e002 c0a8 0103 0015 8032 3786 76c5 bd6b c9c9 5018 269c 967e 0000 3232 302d 636f 6f6d 6273 2e61 6e75 2e65 6475 2e61 7520 4e63 4654 5064 2053 6572 7665 7220 2866 7265 6520 6564 7563 6174 696f 6e61 6c20 6c69 6365 6e73 6529 2072 6561 6479 2e0d 0a +4500 0028 0002 4000 ff06 02fe 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 770c 5010 269c 5a59 0000 +4500 00c7 ffdf 4000 ef06 52d7 96cb e002 c0a8 0103 0015 8032 3786 770c bd6b c9c9 5018 269c 1087 0000 3232 302d 0d0a 3232 302d 4d61 696e 7461 696e 6564 2062 7920 5253 5353 2061 6e64 2052 5350 4153 2049 5420 5374 6166 6620 2870 7265 7669 6f75 736c 7920 6b6e 6f77 6e20 6173 2043 6f6f 6d62 7320 436f 6d70 7574 696e 6720 556e 6974 290d 0a32 3230 2d41 6e79 2070 726f 626c 656d 7320 636f 6e74 6163 7420 6674 706d 6173 7465 7240 636f 6f6d 6273 2e61 6e75 2e65 6475 2e61 750d 0a32 3230 2d0d 0a32 3230 200d 0a +4500 0028 0003 4000 ff06 02fd 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 77ab 5010 269c 59ba 0000 +4500 0038 0004 4000 ff06 02ec 0101 0101 96cb e002 8032 0015 bd6b c9c9 3786 77ab 5018 269c d1c5 0000 5553 4552 2061 6e6f 6e79 6d6f 7573 0d0a +4500 0028 ffe0 4000 ef06 5375 96cb e002 c0a8 0103 0015 8032 3786 77ab bd6b c9d9 5010 269c 9a00 0000 +4500 006c ffe1 4000 ef06 5330 96cb e002 c0a8 0103 0015 8032 3786 77ab bd6b c9d9 5018 269c b00f 0000 3333 3120 4775 6573 7420 6c6f 6769 6e20 6f6b 2c20 7365 6e64 2079 6f75 7220 636f 6d70 6c65 7465 2065 2d6d 6169 6c20 6164 6472 6573 7320 6173 2070 6173 7377 6f72 642e 0d0a +4500 0028 0005 4000 ff06 02fb 0101 0101 96cb e002 8032 0015 bd6b c9d9 3786 77ef 5010 269c 5966 0000 +4500 0036 0006 4000 ff06 02ec 0101 0101 96cb e002 8032 0015 bd6b c9d9 3786 77ef 5018 269c 373f 0000 5041 5353 2061 7661 6c6f 6e40 0d0a +4500 005f ffe2 4000 ef06 533c 96cb e002 c0a8 0103 0015 8032 3786 77ef bd6b c9e7 5018 269c 895e 0000 3233 302d 596f 7520 6172 6520 7573 6572 2023 3420 6f66 2035 3020 7369 6d75 6c74 616e 656f 7573 2075 7365 7273 2061 6c6c 6f77 6564 2e0d 0a +4500 0028 0007 4000 ff06 02f9 0101 0101 96cb e002 8032 0015 bd6b c9e7 3786 7826 5010 269c 5921 0000 +4500 0099 ffe3 4000 ef06 5301 96cb e002 c0a8 0103 0015 8032 3786 7826 bd6b c9e7 5018 269c d399 0000 3233 302d 0d0a 3233 302d 0d0a 3233 302d 4869 2e20 2057 6527 7265 2063 6c65 616e 696e 6720 7570 2e20 2041 6e79 2066 6565 6462 6163 6b20 6d6f 7374 2077 656c 636f 6d65 2e20 3130 2041 7567 2030 300d 0a32 3330 2d0d 0a32 3330 204c 6f67 6765 6420 696e 2061 6e6f 6e79 6d6f 7573 6c79 2e0d 0a +4500 0028 0008 4000 ff06 02f8 0101 0101 96cb e002 8032 0015 bd6b c9e7 3786 7897 5010 269c 58b0 0000 +4500 0030 0009 4000 ff06 02ef 0101 0101 96cb e002 8032 0015 bd6b c9e7 3786 7897 5018 269c 86ae 0000 5459 5045 2049 0d0a +4500 0038 ffe4 4000 ef06 5361 96cb e002 c0a8 0103 0015 8032 3786 7897 bd6b c9ef 5018 269c 5fae 0000 3230 3020 5479 7065 206f 6b61 792e 0d0a +4500 0028 000a 4000 ff06 02f6 0101 0101 96cb e002 8032 0015 bd6b c9ef 3786 78a7 5010 269c 5898 0000 +4500 003d 000b 4000 ff06 02e0 0101 0101 96cb e002 8032 0015 bd6b c9ef 3786 78a7 5018 269c 4b67 0000 504f 5254 2031 2c31 2c31 2c31 2c31 3238 2c35 310d 0a +4500 0046 ffe5 4000 ef06 5352 96cb e002 c0a8 0103 0015 8032 3786 78a7 bd6b ca0c 5018 269c dbc3 0000 3230 3020 504f 5254 2063 6f6d 6d61 6e64 2073 7563 6365 7373 6675 6c2e 0d0a +4500 0030 000c 4000 ff06 02ec 0101 0101 96cb e002 8032 0015 bd6b ca04 3786 78c5 5018 269c 866b 0000 5459 5045 2041 0d0a +4500 0038 ffe6 4000 ef06 535f 96cb e002 c0a8 0103 0015 8032 3786 78c5 bd6b ca14 5018 269c 5f5b 0000 3230 3020 5479 7065 206f 6b61 792e 0d0a +4500 002e 000d 4000 ff06 02ed 0101 0101 96cb e002 8032 0015 bd6b ca0c 3786 78d5 5018 269c a994 0000 4e4c 5354 0d0a +4500 002c ffe7 4000 ef06 536a 96cb e002 c0a8 0103 0014 8033 d9f8 11d4 0000 0000 6002 2238 d190 0000 0204 0584 +4500 002c 000e 4000 ff06 02ee 0101 0101 96cb e002 8033 0014 bd78 5c12 d9f8 11d5 6012 02f8 96de 0000 0204 0584 +4500 0028 ffe8 4000 ef06 536d 96cb e002 c0a8 0103 0014 8033 d9f8 11d5 bd78 5c13 5010 269c cb1d 0000 +4500 005d ffe9 4000 ef06 5337 96cb e002 c0a8 0103 0015 8032 3786 78d5 bd6b ca1a 5018 269c eed0 0000 3135 3020 4f70 656e 696e 6720 4153 4349 4920 6d6f 6465 2064 6174 6120 636f 6e6e 6563 7469 6f6e 2066 6f72 202f 6269 6e2f 6c73 2e0d 0a +4500 0028 000f 4000 ff06 02f1 0101 0101 96cb e002 8033 0014 bd78 5c13 d9f8 11d5 5010 6348 4e1b 0000 +4500 0063 ffea 4000 ef06 5330 96cb e002 c0a8 0103 0014 8033 d9f8 11d5 bd78 5c13 5018 269c a315 0000 636f 6f6d 6273 7061 7065 7273 0d0a 6465 7074 730d 0a66 6f75 6e64 2d66 696c 6573 0d0a 696e 636f 6d69 6e67 0d0a 6e6c 632d 7465 7374 0d0a 7075 620d 0a +4500 0028 0010 4000 ff06 02f0 0101 0101 96cb e002 8033 0014 bd78 5c13 d9f8 1210 5010 6348 4de0 0000 +4500 0028 ffeb 4000 ef06 536a 96cb e002 c0a8 0103 0014 8033 d9f8 1210 bd78 5c13 5011 269c cae1 0000 +4500 0028 10da 4000 ff06 327c c0a8 0103 96cb e002 8033 0014 bd78 5c13 d9f8 1211 5010 6348 8e35 0000 +4500 0028 10db 4000 ff06 327b c0a8 0103 96cb e002 8033 0014 bd78 5c13 d9f8 1211 5011 6348 8e34 0000 +4500 0028 ffec 4000 ef06 5369 96cb e002 c0a8 0103 0014 8033 d9f8 1211 bd78 5c14 5010 269c cae0 0000 +4500 0028 0011 4000 ff06 02ef 0101 0101 96cb e002 8032 0015 bd6b ca12 3786 790a 5010 269c 5812 0000 +4500 0040 ffed 4000 ef06 5350 96cb e002 c0a8 0103 0015 8032 3786 790a bd6b ca1a 5018 269c 7c9e 0000 3232 3620 4c69 7374 696e 6720 636f 6d70 6c65 7465 642e 0d0a +4500 0030 0012 4000 ff06 02e6 0101 0101 96cb e002 8032 0015 bd6b ca12 3786 7922 5018 269c 85f8 0000 5459 5045 2049 0d0a +4500 0038 ffee 4000 ef06 5357 96cb e002 c0a8 0103 0015 8032 3786 7922 bd6b ca22 5018 269c 5ef0 0000 3230 3020 5479 7065 206f 6b61 792e 0d0a +4500 0028 0013 4000 ff06 02ed 0101 0101 96cb e002 8032 0015 bd6b ca1a 3786 7932 5010 269c 57e2 0000 +4500 002e 0014 4000 ff06 02e6 0101 0101 96cb e002 8032 0015 bd6b ca1a 3786 7932 5018 269c b020 0000 5155 4954 0d0a +4500 0036 ffef 4000 ef06 5358 96cb e002 c0a8 0103 0015 8032 3786 7932 bd6b ca28 5018 269c a93c 0000 3232 3120 476f 6f64 6279 652e 0d0a +4500 0028 0015 4000 ff06 02eb 0101 0101 96cb e002 8032 0015 bd6b ca20 3786 7940 5011 269c 57cd 0000 +4500 0028 fff0 4000 ef06 5365 96cb e002 c0a8 0103 0015 8032 3786 7940 bd6b ca28 5011 269c 981b 0000 +4500 0028 10e1 4000 ff06 3275 c0a8 0103 96cb e002 8032 0015 bd6b ca25 3786 7941 5010 269c 981e 0000 +4500 0028 fff1 4000 ef06 5364 96cb e002 c0a8 0103 0015 8032 3786 7941 bd6b ca29 5010 269c 981a 0000 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni6 b/contrib/ipfilter/test/expected/ni6 new file mode 100644 index 0000000..a4e4ace --- /dev/null +++ b/contrib/ipfilter/test/expected/ni6 @@ -0,0 +1,9 @@ +4500 0054 cd8a 4000 ff11 1fbb c0a8 0601 c0a8 0701 8075 006f 0040 d26e 3e1d d249 0000 0000 0000 0002 0001 86a0 0000 0002 0000 0003 0000 0000 0000 0000 0000 0000 0000 0000 0001 86a3 0000 0003 0000 0011 0000 0000 +4500 0054 0000 4000 ff11 ec44 c0a8 0702 c0a8 0701 8075 006f 0040 d16d 3e1d d249 0000 0000 0000 0002 0001 86a0 0000 0002 0000 0003 0000 0000 0000 0000 0000 0000 0000 0000 0001 86a3 0000 0003 0000 0011 0000 0000 +4500 0038 cd83 4000 ff11 1fde c0a8 0701 c0a8 0601 006f 8075 0024 d805 3e1d d249 0000 0001 0000 0000 0000 0000 0000 0000 0000 0000 0000 0801 +4500 0038 0001 4000 ff11 ee5f c0a8 0602 c0a8 0601 006f 8075 0024 d904 3e1d d249 0000 0001 0000 0000 0000 0000 0000 0000 0000 0000 0000 0801 +4500 0044 d5a6 4000 ff11 17af c0a8 0601 c0a8 0701 80df 0801 0030 03f1 3e10 1fb1 0000 0000 0000 0002 0001 86a3 0000 0002 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0044 0002 4000 ff11 ec52 c0a8 0702 c0a8 0701 80df 0801 0030 02f0 3e10 1fb1 0000 0000 0000 0002 0001 86a3 0000 0002 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0034 0000 4000 fe11 ee65 c0a8 0701 c0a8 0601 0801 80df 0020 8ab8 3e10 1fb1 0000 0001 0000 0000 0000 0000 0000 0000 0000 0000 +4500 0034 0003 4000 fe11 ef61 c0a8 0602 c0a8 0601 0801 80df 0020 0000 3e10 1fb1 0000 0001 0000 0000 0000 0000 0000 0000 0000 0000 +------------------------------- diff --git a/contrib/ipfilter/test/expected/ni7 b/contrib/ipfilter/test/expected/ni7 index d03ec58..f0d0010 100644 --- a/contrib/ipfilter/test/expected/ni7 +++ b/contrib/ipfilter/test/expected/ni7 @@ -1,3 +1,3 @@ -4500 0028 4706 4000 0111 1eac 0404 0404 0606 0606 afc9 829e 0014 6308 0402 0000 3be5 468d 000a cfc3 -4500 0038 809a 0000 ff01 2f1f 0202 0202 0404 0404 0b00 f91c 0000 0000 4500 0028 4706 4000 0111 26b4 0404 0404 0202 0202 afc9 829e 0014 c966 +4500 0028 4706 4000 0111 1eac 0404 0404 0606 0606 afc9 829e 0014 6308 0402 0000 3be5 468d 000a cfc3 +4500 0038 0000 0000 ff01 afb9 0202 0202 0404 0404 0b00 f91c 0000 0000 4500 0028 4706 4000 0111 26b4 0404 0404 0202 0202 afc9 829e 0014 c966 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni8 b/contrib/ipfilter/test/expected/ni8 index ebee8bc..4741b18 100644 --- a/contrib/ipfilter/test/expected/ni8 +++ b/contrib/ipfilter/test/expected/ni8 @@ -1,5 +1,5 @@ -4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 271f 0a02 0202 0404 0404 0303 a7fb 0000 0000 4500 003c 4706 4000 ff06 20aa 0404 0404 0a02 0202 5000 0500 0000 0001 -4500 0058 809a 0000 ff01 26ff 0a02 0202 0404 0404 0303 1137 0000 0000 4500 003c 4706 4000 ff06 20aa 0404 0404 0a02 0202 5000 0500 0000 0001 0000 0000 a002 16d0 cc32 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 -4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 0000 0000 ff01 a7b9 0a02 0202 0404 0404 0303 a7fb 0000 0000 4500 003c 4706 4000 ff06 20aa 0404 0404 0a02 0202 5000 0500 0000 0001 +4500 0058 0001 0000 ff01 a798 0a02 0202 0404 0404 0303 1137 0000 0000 4500 003c 4706 4000 ff06 20aa 0404 0404 0a02 0202 5000 0500 0000 0001 0000 0000 a002 16d0 cc32 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 0002 0000 ff01 abb3 0303 0303 0505 0505 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 ------------------------------- diff --git a/contrib/ipfilter/test/expected/ni9 b/contrib/ipfilter/test/expected/ni9 new file mode 100644 index 0000000..9effc52 --- /dev/null +++ b/contrib/ipfilter/test/expected/ni9 @@ -0,0 +1,5 @@ +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9c40 0000 0001 0000 0000 a002 16d0 3ef4 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 0000 0000 ff01 adb7 0303 0303 0404 0404 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 +4500 0058 0001 0000 ff01 ad96 0303 0303 0404 0404 0303 0735 0000 0000 4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 +4500 0038 0002 0000 ff01 abb3 0303 0303 0505 0505 0303 0fa3 0000 0000 4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 +------------------------------- diff --git a/contrib/ipfilter/test/expected/p1 b/contrib/ipfilter/test/expected/p1 new file mode 100644 index 0000000..c3f7afa --- /dev/null +++ b/contrib/ipfilter/test/expected/p1 @@ -0,0 +1,19 @@ +nomatch +pass +nomatch +nomatch +nomatch +pass +nomatch +nomatch +List of active MAP/Redirect filters: + +List of active sessions: +List of active state sessions: +List of configured pools +table role = ipf type = tree number = 100 + { 1.1.1.1/32; ! 2.2.0.0/16; 2.2.2.0/24; }; +List of configured hash tables +List of groups configured (set 0) +List of groups configured (set 1) +------------------------------- diff --git a/contrib/ipfilter/test/expected/p2 b/contrib/ipfilter/test/expected/p2 new file mode 100644 index 0000000..bb15bdf --- /dev/null +++ b/contrib/ipfilter/test/expected/p2 @@ -0,0 +1,20 @@ +nomatch +nomatch +pass +nomatch +nomatch +nomatch +nomatch +pass +List of active MAP/Redirect filters: + +List of active sessions: +List of active state sessions: +List of configured pools +List of configured hash tables +# 'anonymous' table +table role = ipf type = hash number = 2147483649 size = 3 + { 4.4.0.0/16; 127.0.0.1/32; }; +List of groups configured (set 0) +List of groups configured (set 1) +------------------------------- diff --git a/contrib/ipfilter/test/expected/p3 b/contrib/ipfilter/test/expected/p3 new file mode 100644 index 0000000..136543f --- /dev/null +++ b/contrib/ipfilter/test/expected/p3 @@ -0,0 +1,33 @@ +pass +nomatch +nomatch +nomatch +nomatch +pass +block +nomatch +nomatch +pass +nomatch +block +List of active MAP/Redirect filters: + +List of active sessions: +List of active state sessions: +List of configured pools +List of configured hash tables +group-map out role = ipf number = 2010 size = 5 + { 5.0.0.0/8, group = 2040; 4.4.0.0/16, group = 2020; 2.2.2.2/32, group = 2020; }; +group-map in role = ipf number = 1010 size = 3 + { 3.3.0.0/16, group = 1030; 1.1.1.1/32, group = 1020; }; +List of groups configured (set 0) +Dev.0. Group 1020 Ref 1 Flags 0x8000 +2 pass in all group 1020 +Dev.0. Group 1030 Ref 1 Flags 0x8000 +2 block in all group 1030 +Dev.0. Group 2020 Ref 2 Flags 0x4000 +4 pass out all group 2020 +Dev.0. Group 2040 Ref 1 Flags 0x4000 +2 block out all group 2040 +List of groups configured (set 1) +------------------------------- diff --git a/contrib/ipfilter/test/hextest b/contrib/ipfilter/test/hextest index c500c6b..b7b0b2c 100644 --- a/contrib/ipfilter/test/hextest +++ b/contrib/ipfilter/test/hextest @@ -13,7 +13,7 @@ fi echo "$1..."; /bin/cp /dev/null results/$1 ( while read rule; do - echo "$rule" | ../ipftest -br - -Hi input/$1 >> results/$1; + echo "$rule" | ../ipftest -br - -F hex -i input/$1 >> results/$1; if [ $? -ne 0 ] ; then exit 1; fi diff --git a/contrib/ipfilter/test/input/f11 b/contrib/ipfilter/test/input/f11 index 25c670d..c54bb80 100644 --- a/contrib/ipfilter/test/input/f11 +++ b/contrib/ipfilter/test/input/f11 @@ -6,7 +6,7 @@ in on e0 tcp 1.1.1.1,1 2.1.2.2,23 A in on e0 tcp 1.1.1.1,1 2.1.2.2,25 A in on e1 tcp 2.1.2.2,23 1.1.1.1,1 A in on e1 tcp 2.1.2.2,25 1.1.1.1,1 A -in on e0 tcp 1.1.1.1,1 2.1.2.2,23 F +in on e0 tcp 1.1.1.1,1 2.1.2.2,23 FA in on e0 tcp 1.1.1.1,1 2.1.2.2,23 A in on e0 tcp 1.1.1.1,2 2.1.2.2,23 A in on e1 udp 1.1.1.1,1 4.4.4.4,53 diff --git a/contrib/ipfilter/test/input/f12 b/contrib/ipfilter/test/input/f12 index 682202f..52edde1 100644 --- a/contrib/ipfilter/test/input/f12 +++ b/contrib/ipfilter/test/input/f12 @@ -1,35 +1,44 @@ # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF SYN -45 00 0028 0000 4000 3f 06 36cd 01010101 02010101 -0401 0019 00000000 00000000 50 02 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 36cd 0101 0101 0201 0101 +0401 0019 0000 0000 0000 0000 5002 2000 86c5 0000 # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF ACK -45 00 0028 0000 4000 3f 06 36cd 01010101 02010101 -0401 0019 00000000 00000000 50 10 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 36cd 0101 0101 0201 0101 +0401 0019 0000 0000 0000 0000 5010 2000 86b7 0000 # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF MF FO=0 ACK -45 00 0028 0000 6000 3f 06 16cd 01010101 02010101 -0401 0019 00000000 00000000 50 10 2000 0000 0000 +[] +4500 0028 0000 6000 3f06 16cd 0101 0101 0201 0101 +0401 0019 0000 0000 0000 0000 5010 2000 86b7 0000 # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF FO=0 -45 00 001c 0000 6000 3f 06 16d9 01010101 02010101 -0401 0019 00000000 +[] +4500 001c 0000 6000 3f06 16d9 0101 0101 0201 0101 +0401 0019 0000 0000 # 1.1.1.1 -> 2.1.1.1 TTL=63 TCP DF FO=1 ACK -45 00 001c 0000 6001 3f 06 16d8 01010101 02010101 -00000000 50 10 2000 +[] +4500 001c 0000 6001 3f06 16d8 0101 0101 0201 0101 +0000 0000 5010 2000 # 1.1.1.1 -> 2.1.1.1 TTL=63 UDP DF MF FO=0 -45 00 0014 0000 6000 3f 11 16d6 01010101 02010101 +[] +4500 0014 0000 6000 3f11 16d6 0101 0101 0201 0101 # 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP MF FO=0 -45 00 0018 0000 2000 3f 11 56d2 01010101 02010101 +[] +4500 0018 0000 2000 3f11 56d2 0101 0101 0201 0101 0035 0035 # 1.1.1.1,1 -> 2.1.1.1,1 TTL=63 UDP MF FO=0 -45 00 001c 0000 2000 3f 11 56ce 01010101 02010101 -0001 0001 0004 0000 +[] +4500 001c 0000 2000 3f11 56ce 0101 0101 0201 0101 +0001 0001 0004 fadc # 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP MF FO=0 -45 00 001c 0000 2000 3f 11 56ce 01010101 02010101 -0035 0035 0004 0000 +[] +4500 001c 0000 2000 3f11 56ce 0101 0101 0201 0101 +0035 0035 0004 fa74 diff --git a/contrib/ipfilter/test/input/f13 b/contrib/ipfilter/test/input/f13 index d1c04d8..0ca607e 100644 --- a/contrib/ipfilter/test/input/f13 +++ b/contrib/ipfilter/test/input/f13 @@ -1,51 +1,51 @@ # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF,MF,FO=0 SYN -45 00 0028 0001 4000 3f 06 36cc 01010101 02010101 -0401 0019 00000000 00000000 50 02 2000 0000 0000 +4500 0028 0001 4000 3f06 36cc 0101 0101 0201 0101 +0401 0019 0000 0000 0000 0000 50 02 2000 86c5 0000 # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP MF ACK -45 00 0024 0002 2000 3f 06 56cf 01010101 02010101 -0401001900000000 0000000050102000 +4500 0024 0002 2000 3f06 56cf 0101 0101 0201 0101 +0401 0019 0000 0000 0000 0000 5010 2000 # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP FO=2 ACK -45 00 002c 0002 0002 3f 06 76c5 01010101 02010101 -0000000000010203 0405060708090a0b 0c0d0e0f10111213 +4500 002c 0002 0002 3f06 76c5 0101 0101 0201 0101 +0000 0000 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f 1011 1213 # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF MF FO=0 SYN -45 00 0028 0003 6000 3f 06 16ca 01010101 02010101 -0401 0019 00000000 00000000 50 10 2000 0000 0000 +4500 0028 0003 6000 3f06 16ca 0101 0101 0201 0101 +0401 0019 0000 0000 0000 0000 5010 2000 0000 0000 # 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF FO=0 -45 00 001c 0004 6000 3f 06 16d5 01010101 02010101 -0401 0019 00000000 +4500 001c 0004 6000 3f06 16d5 0101 0101 0201 0101 +0401 0019 0000 0000 # 1.1.1.1 -> 2.1.1.1 TTL=63 TCP DF FO=1 SYN -45 00 001c 0005 6001 3f 06 16d3 01010101 02010101 -00000000 50 10 2000 +4500 001c 0005 6001 3f06 16d3 0101 0101 0201 0101 +0000 0000 5010 2000 # 1.1.1.1 -> 2.1.1.1 TTL=63 UDP DF MF FO=0 -45 00 0014 0006 6000 3f 11 16d0 01010101 02010101 +4500 0014 0006 6000 3f11 16d0 0101 0101 0201 0101 # 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP MF FO=0 -45 00 0018 0007 2000 3f 11 56cb 01010101 02010101 +4500 0018 0007 2000 3f11 56cb 0101 0101 0201 0101 0035 0035 # 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP MF FO=0 -45 00 001c 0008 2000 3f 11 56c6 01010101 02010101 -0035003500040000 +4500 001c 0008 2000 3f11 56c6 0101 0101 0201 0101 +0035 0035 0004 0000 # 1.1.1.1,53 -> 2.1.1.1,54 TTL=63 UDP MF FO=0 (short) -45 00 0018 0008 2000 3f 11 56ca 01010101 02010101 -00350036 +4500 0018 0008 2000 3f11 56ca 0101 0101 0201 0101 +0035 0036 # 1.1.1.1,21 -> 2.1.1.1,54 TTL=63 UDP MF FO=0 -45 00 001c 0008 2000 3f 11 56c6 01010101 02010101 -0015003600040000 +4500 001c 0008 2000 3f11 56c6 0101 0101 0201 0101 +0015 0036 0004 0000 # 1.1.1.1,21 -> 2.1.1.1,54 TTL=63 TCP MF FO=0 -45 00 001c 0008 2000 3f 06 56d1 01010101 02010101 -0015 0036 00000000 00000000 50 02 2000 0000 0000 +4500 001c 0008 2000 3f06 56d1 0101 0101 0201 0101 +0015 0036 0000 0000 0000 0000 50 02 2000 0000 0000 # 1.1.1.1 -> 2.1.1.1 TTL=63 UDP FO=1 -45 00 001c 0008 0001 3f 11 76c5 01010101 02010101 -0000000000000000 +4500 001c 0008 0001 3f11 76c5 0101 0101 0201 0101 +0000 0000 0000 0000 diff --git a/contrib/ipfilter/test/input/f17 b/contrib/ipfilter/test/input/f17 index 1eba7e7..18af566 100644 --- a/contrib/ipfilter/test/input/f17 +++ b/contrib/ipfilter/test/input/f17 @@ -1,61 +1,28 @@ -# (1.1.1.1,54076,seq=0xbfd08989) -> (2.2.2.2,25,seq=0) SYN [out,ppp0] 4500 003c 8262 0000 4006 f254 0101 0101 0202 0202 d33c 0019 bfd0 8989 0000 0000 a002 4000 cfcd 0000 0204 05b4 0103 0300 0101 080a 008e 17f7 0000 0000 -# (2.2.2.2,25,seq=0x40203436) -> (1.1.1.1,54076,seq=0xbfdfcbc9) ACK [in,ppp0] 4500 003c 8262 0000 1106 2155 0202 0202 0101 0101 0019 d33c 4020 3436 bfdf cbc9 5010 4000 694a 0000 0204 0584 0103 0300 0101 080a 008e 17f7 0000 0000 -# (1.1.1.1,54076,seq=0xbfd08989) -> (2.2.2.2,25,seq=0x0) SYN [out,ppp0] 4500 003c 8265 0000 4006 f251 0101 0101 0202 0202 d33c 0019 bfd0 8989 0000 0000 a002 4000 cfc2 0000 0204 05b4 0103 0300 0101 080a 008e 1802 0000 0000 -# (2.2.2.2,25,seq=0xed674d4e) -> (1.1.1.1,54076,seq=0xbfd0898a) SYN-ACK [in,ppp0] 4500 002c 7442 4000 2906 d784 0202 0202 0101 0101 0019 d33c ed67 4d4e bfd0 898a 6012 2118 19c2 0000 0204 0584 -# -# (2.2.2.2,25,seq=0xbfd0898a) -> (1.1.1.1,54076,seq=0xed674d4e) ACK [out,ppp0] 4500 002c 8262 0000 4006 f264 0101 0101 0202 0202 d33c 0019 bfd0 898a ed67 4d4e -5010 4000 6190 0000 0000 - -# (1.1.1.1,54076,seq=0xcfd08989) -> (2.2.2.2,25,seq=0x0) SYN -[out,ppp0] -4500 003c 8265 0000 4006 f251 0101 0101 -0202 0202 d33c 0019 cfd0 8989 0000 0000 -a002 4000 bfc2 0000 0204 05b4 0103 0300 -0101 080a 008e 1802 0000 0000 - -# (1.1.1.1,54076,seq=0xcfd08989) -> (2.2.2.2,25,seq=0x0) SYN -[out,ppp0] -4500 003c 8266 0000 4006 f250 0101 0101 -0202 0202 d33c 0019 cfd0 8989 0000 0000 -a002 4000 bfc2 0000 0204 05b4 0103 0300 -0101 080a 008e 1802 0000 0000 - -# (2.2.2.2,25,seq=0xed674d4e) -> (1.1.1.1,54076,seq=0xcfd0898a) SYN-ACK -[in,ppp0] -4500 002c 7442 4000 2906 d784 0202 0202 -0101 0101 0019 d33c ed67 4d4e cfd0 898a -6012 2118 09c2 0000 0204 0584 - -# -# (2.2.2.2,25,seq=0xcfd0898a) -> (1.1.1.1,54076,seq=0xed674d4e) ACK -[out,ppp0] -4500 002c 8262 0000 4006 f264 0101 0101 -0202 0202 d33c 0019 cfd0 898a ed67 4d4e -5010 4000 6190 0000 0000 +5010 4000 0ce0 0000 0000 diff --git a/contrib/ipfilter/test/input/ipv6.1 b/contrib/ipfilter/test/input/ipv6.1 index 1d7d546..3920810 100644 --- a/contrib/ipfilter/test/input/ipv6.1 +++ b/contrib/ipfilter/test/input/ipv6.1 @@ -3,7 +3,7 @@ ef00 1001 2002 0001 0000 0000 0000 0070 2001 1002 3333 0001 0000 0000 0000 0001 8083 829a 0018 -f427 +f4c1 0000 0344 0000 0004 f8f1 9d3c ddba 0e00 [in,gif0] 6000 0000 0048 3a40 diff --git a/contrib/ipfilter/test/input/l1 b/contrib/ipfilter/test/input/l1 index afda0db..56d766a 100644 --- a/contrib/ipfilter/test/input/l1 +++ b/contrib/ipfilter/test/input/l1 @@ -1,52 +1,64 @@ # 1.1.1.1,1025 -> 2.2.2.2,25 TTL=63 TCP DF SYN -45 00 0028 0000 4000 3f 06 0000 01010101 02020202 -0401 0019 00000000 00000000 50 02 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 35cb 0101 0101 0202 0202 +0401 0019 0000 0000 0000 0000 5002 2000 85c3 0000 #in on e0 tcp 1.1.1.1,1025 2.1.2.2,25 A -45 00 0028 0000 4000 3f 06 0000 01010101 02020202 -0401 0019 00000000 00000000 50 10 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 35cb 0101 0101 0202 0202 +0401 0019 0000 0000 0000 0000 5010 2000 85b5 0000 #in on e1 tcp 2.1.2.2,25 1.1.1.1,1025 AS -45 00 0028 0000 4000 3f 06 0000 02020202 01010101 -0019 0401 00000000 00000000 50 12 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 35cb 0202 0202 0101 0101 +0019 0401 0000 0000 0000 0000 5012 2000 85b3 0000 #in on e1 tcp 2.1.2.2,25 1.1.1.1,1025 A -[out,e1] 45 00 0028 0000 4000 3f 06 0000 02020202 01010101 -0019 0401 00000000 00000000 50 10 2000 0000 0000 +[out,e1] 4500 0028 0000 4000 3f06 35cb 0202 0202 0101 0101 +0019 0401 0000 0000 0000 0000 5010 2000 85b5 0000 #in on e0 tcp 1.1.1.1,1025 2.1.2.2,25 F -45 00 0028 0000 4000 3f 06 0000 01010101 02020202 -0401 0019 00000000 00000000 50 01 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 35cb 0101 0101 0202 0202 +0401 0019 0000 0000 0000 0000 5011 2000 85b4 0000 #in on e0 tcp 1.1.1.1,1025 2.1.2.2,25 A -45 00 0028 0000 4000 3f 06 0000 01010101 02020202 -0401 0019 00000000 00000000 50 10 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 35cb 0101 0101 0202 0202 +0401 0019 0000 0000 0000 0000 5010 2000 85b5 0000 #in on e0 tcp 1.1.1.1,1025 2.1.2.2,25 A -45 00 0028 0000 4000 3f 06 0000 01010101 02020202 -0401 0019 00000000 00000000 50 10 2000 0000 0000 +[] +4500 0028 0000 4000 3f06 35cb 0101 0101 0202 0202 +0401 0019 0000 0000 0000 0000 5010 2000 85b5 0000 #in on e1 udp 1.1.1.1,1 4.4.4.4,53 -45 00 0028 0000 4000 3f 11 0000 01010101 04040404 -0001 0035 0000 0000 0102 0304 0506 0708 090a 0b0d +[] +4500 0028 0000 4000 3f11 31bc 0101 0101 0404 0404 +0001 0035 0000 d16f 0102 0304 0506 0708 090a 0b0d #in on e1 udp 2.2.2.2,2 4.4.4.4,53 -45 00 0028 0000 4000 3f 11 0000 02020202 04040404 +[] +4500 0028 0000 4000 3f11 2fba 0202 0202 0404 0404 0001 0035 0000 0000 0102 0304 0506 0708 090a 0b0d #in on e1 udp 2.2.2.2,2 4.4.4.4,53 -45 00 0038 0000 4000 3f 11 0000 02020202 04040404 -0001 0035 0000 0000 0102 0304 0506 0708 090a 0b0d +[] +4500 0038 0000 4000 3f11 2faa 0202 0202 0404 0404 +0001 0035 0000 d47b 0102 0304 0506 0708 090a 0b0d 0e0f 4061 4263 4465 4667 4869 4a6b 4c6d #in on e0 ip 4.4.4.4,53 1.1.1.1,1 -45 00 0014 0000 4000 3f 00 0000 02020202 04040404 +[] +4500 0014 0000 4000 3f00 2fdf 0202 0202 0404 0404 #in on e0 udp 3.3.3.3,1023 1.1.1.1,2049 -45 00 001c 0000 4000 3f 11 0000 03030303 01010101 -03ff 0801 0000 0000 +[] +4500 001c 0000 4000 3f11 33ca 0303 0303 0101 0101 +03ff 0801 0000 ebde #in on e0 udp 1.1.1.1,2049 3.3.3.3,1023 -45 00 001c 0000 4000 3f 11 0000 01010101 03030303 +[] +4500 001c 0000 4000 3f11 33ca 0101 0101 0303 0303 0801 03ff 0000 0000 diff --git a/contrib/ipfilter/test/input/n1 b/contrib/ipfilter/test/input/n1 index a607390..04b24ef 100644 --- a/contrib/ipfilter/test/input/n1 +++ b/contrib/ipfilter/test/input/n1 @@ -19,7 +19,10 @@ in on zx0 255 10.1.1.2 10.3.4.5 in on zx0 tcp 10.1.1.1,1025 10.3.4.5,1025 out on zx0 icmp 10.1.1.1 10.4.3.2 in on zx0 icmp 10.4.3.2 10.2.2.2 +in on zx0 icmp 10.4.3.2 10.3.4.1 +in on zx0 icmp 10.4.3.2 10.3.4.2 in on zx0 icmp 10.4.3.2 10.3.4.3 +in on zx0 icmp 10.4.3.2 10.3.4.4 in on zx0 icmp 10.4.3.2 10.3.4.5 out on zx0 34 10.1.1.2 10.4.3.2 in on zx0 34 10.4.3.2 10.3.4.4 diff --git a/contrib/ipfilter/test/input/n10 b/contrib/ipfilter/test/input/n10 new file mode 100644 index 0000000..321ed0b --- /dev/null +++ b/contrib/ipfilter/test/input/n10 @@ -0,0 +1,6 @@ +# TCP SYN packet with an MSS option +[out,ppp0] +4500 002c 10c9 4000 ff06 3289 c0a8 0103 +96cb e002 8032 0015 bd6b c9c8 0000 0000 +6002 2238 35f9 0000 0204 05b4 + diff --git a/contrib/ipfilter/test/input/n11 b/contrib/ipfilter/test/input/n11 new file mode 100644 index 0000000..8712674 --- /dev/null +++ b/contrib/ipfilter/test/input/n11 @@ -0,0 +1,16 @@ +out on zx0 255 10.1.1.0 10.1.1.2 +out on zx0 255 10.1.1.1 10.1.1.2 +out on zx0 255 10.1.1.2 10.1.1.1 +out on zx0 255 10.2.2.1 10.1.2.1 +out on zx0 255 10.2.2.2 10.1.2.1 +in on zx0 255 10.1.1.1 10.1.1.2 +in on zx0 255 10.1.1.2 10.1.1.1 +in on zx0 255 10.2.2.1 10.2.1.1 +in on zx0 255 10.2.2.2 10.2.1.1 +in on zx0 255 10.2.2.3 10.1.1.1 +in on zx0 255 10.2.3.4 10.2.2.2 +in on zx0 255 10.1.1.1 10.2.2.2 +in on zx0 255 10.1.1.2 10.2.2.2 +in on zx0 255 10.1.1.0 10.3.4.5 +in on zx0 255 10.1.1.1 10.3.4.5 +in on zx0 255 10.1.1.2 10.3.4.5 diff --git a/contrib/ipfilter/test/input/n12 b/contrib/ipfilter/test/input/n12 new file mode 100644 index 0000000..fb4d76d --- /dev/null +++ b/contrib/ipfilter/test/input/n12 @@ -0,0 +1,18 @@ +[out,le0=192.168.1.188] +4510 0040 2020 4000 4006 17e1 c0a8 7e53 +c0a8 0303 12c2 0017 4e33 298e 0000 0000 +b002 4000 07af 0000 0204 05b4 0101 0402 +0103 0300 0101 080a 0c72 549e 0000 0000 + +[in,le0] +4500 003c 00b0 4000 fe06 f5fb c0a8 0303 +c0a8 01bc 0017 2710 f674 e02c 4e33 298f +a012 2798 e317 0000 0101 080a 2c05 b797 +0c72 549e 0103 0300 0204 05b4 + +[out,le0] +4510 0034 493b 4000 4006 eed1 c0a8 7e53 +c0a8 0303 12c2 0017 4e33 298f f674 e02d +8010 4000 8e2a 0000 0101 080a 0c72 549e +2c05 b797 + diff --git a/contrib/ipfilter/test/input/n4 b/contrib/ipfilter/test/input/n4 index 52c2d88..1218ef9 100644 --- a/contrib/ipfilter/test/input/n4 +++ b/contrib/ipfilter/test/input/n4 @@ -1,5 +1,10 @@ in on zx0 tcp 10.3.3.3,12345 10.1.1.1,23 +out on zx0 tcp 10.2.2.1,10023 10.3.3.3,12345 in on zx0 tcp 10.3.3.3,12345 10.1.1.1,53 -in on zx0 tcp 10.3.3.3,12345 10.1.0.0,23 +out on zx0 tcp 10.2.2.1,10053 10.3.3.3,12345 +in on zx0 tcp 10.3.3.3,12346 10.1.0.0,23 +out on zx0 tcp 10.2.2.1,10023 10.3.3.3,12346 in on zx0 udp 10.3.3.3,12345 10.1.1.0,53 +out on zx0 udp 10.2.2.1,10053 10.3.3.3,12345 in on zx0 tcp 10.3.3.3,12345 10.1.1.0,53 +out on zx0 tcp 10.2.2.1,53 10.3.3.3,12345 diff --git a/contrib/ipfilter/test/input/n8 b/contrib/ipfilter/test/input/n8 new file mode 100644 index 0000000..1f5b213 --- /dev/null +++ b/contrib/ipfilter/test/input/n8 @@ -0,0 +1,30 @@ +#v tos len id off ttl p sum src dst +# ICMP ECHO (ping) exchange +[out,icmp0] 4500 0054 8bc1 0000 ff01 23dc 0202 0202 0404 0404 +0800 efdf 6220 0000 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + +[in,icmp0] 4500 0054 3fd5 4000 ff01 1fc1 0404 0404 0a0a 0a01 +0000 f7df 6220 0000 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + +[out,icmp0] 4500 0054 8bc1 0000 ff01 23dc 0202 0202 0404 0404 +0800 efde 6220 0001 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + +[in,icmp0] 4500 0054 3fd5 4000 ff01 1fc1 0404 0404 0a0a 0a01 +0000 f7de 6220 0001 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + diff --git a/contrib/ipfilter/test/input/n9 b/contrib/ipfilter/test/input/n9 new file mode 100644 index 0000000..c4aada8 --- /dev/null +++ b/contrib/ipfilter/test/input/n9 @@ -0,0 +1,30 @@ +#v tos len id off ttl p sum src dst +# ICMP ECHO (ping) exchange +[in,icmp0] 4500 0054 8bc1 0000 ff01 23dc 0202 0202 0404 0404 +0800 efdf 6220 0000 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + +[out,icmp0] 4500 0054 3fd5 4000 ff01 23c5 0a0a 0a01 0202 0202 +0000 f7df 6220 0000 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + +[in,icmp0] 4500 0054 8bc1 0000 ff01 23dc 0202 0202 0404 0404 +0800 efde 6220 0001 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + +[out,icmp0] 4500 0054 3fd5 4000 ff01 23c5 0a0a 0a01 0202 0202 +0000 f7de 6220 0001 3f6f 6e80 000b +0d02 0809 0a0b 0c0d 0e0f 1011 1213 1415 +1617 1819 1a1b 1c1d 1e1f 2021 2223 2425 +2627 2829 2a2b 2c2d 2e2f 3031 3233 3435 +3637 + diff --git a/contrib/ipfilter/test/input/ni1 b/contrib/ipfilter/test/input/ni1 index dc2f05e..8f548d5 100644 --- a/contrib/ipfilter/test/input/ni1 +++ b/contrib/ipfilter/test/input/ni1 @@ -8,12 +8,13 @@ [in,df0] 4500 0038 809a 0000 ff01 2919 0303 0303 0606 0606 0b00 5f7b 0000 0000 -4500 0028 4706 4000 0111 1eac 0606 0606 0404 0404 -afc9 829e 0014 6308 +4500 0028 0000 4000 0111 65b2 0606 0606 0404 0404 +afc9 829e 0014 6308 [in,df0] 4500 0044 809a 0000 ff01 290d 0303 0303 0606 0606 0b00 0939 0000 0000 -4500 0028 4706 4000 0111 1eac 0606 0606 0404 0404 -afc9 829e 0014 6308 0402 0000 3be5 468d 000a cfc3 +4500 0028 0000 4000 0111 65b2 0606 0606 0404 0404 +afc9 829e 0014 6308 +0402 0000 3be5 468d 000a cfc3 diff --git a/contrib/ipfilter/test/input/ni10 b/contrib/ipfilter/test/input/ni10 index 041326f..48ac225 100644 --- a/contrib/ipfilter/test/input/ni10 +++ b/contrib/ipfilter/test/input/ni10 @@ -1,17 +1,21 @@ #v tos len id off ttl p sum src dst # ICMP dest unreachable with 64 bits in payload (in reply to a TCP packet # going out) +# IP 4.4.4.4 2.2.2.2 TCP(20480,80) [in,df0] 45 00 00 3c 47 06 40 00 ff 06 28 aa 04 04 04 04 02 02 02 02 50 00 00 50 00 00 00 01 00 00 00 00 a0 02 16 d0 d8 e2 00 00 02 04 05 b4 04 02 08 0a 00 47 fb b0 00 00 00 00 01 03 03 00 +# IP 3.3.3.3 -> 4.4.4.4 ICMP (IP(4.4.4.4,6.6.6.6) TCP(20480,80)) [out,df0] 4500 0038 809a 0000 ff01 2d1d 0303 0303 0404 0404 0303 acab 0000 0000 4500 003c 4706 4000 ff06 20a2 0404 0404 0606 0606 5000 0050 0000 0001 +# IP 3.3.3.3 -> 4.4.4.4 ICMP (IP(4.4.4.4,6.6.6.6) TCP(20480,80)) # ICMP dest unreachable with whole packet in payload (40 bytes = 320 bits) [out,df0] 45 00 00 58 80 9a 00 00 ff 01 2c fd 03 03 03 03 04 04 04 04 03 03 11 3f 00 00 00 00 45 00 00 3c 47 06 40 00 ff 06 20 a2 04 04 04 04 06 06 06 06 50 00 00 50 00 00 00 01 00 00 00 00 a0 02 16 d0 d0 da 00 00 02 04 05 b4 04 02 08 0a 00 47 fb b0 00 00 00 00 01 03 03 00 +# IP 3.3.3.3 -> 4.4.4.4 ICMP (IP(4.4.4.4,6.6.6.6) TCP(20480,80)) [out,df0] 4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 0303 acab 0000 0000 diff --git a/contrib/ipfilter/test/input/ni12 b/contrib/ipfilter/test/input/ni12 new file mode 100644 index 0000000..788e603 --- /dev/null +++ b/contrib/ipfilter/test/input/ni12 @@ -0,0 +1,24 @@ +#v tos len id off ttl p sum src dst +# ICMP dest unreachable with 64 bits in payload (in reply to a TCP packet +# going out) +[in,df0] 45 00 00 3c 47 06 40 00 ff 06 20 aa 04 04 04 04 0a 02 02 02 50 00 05 00 00 00 00 01 00 00 00 00 a0 02 16 d0 cc 32 00 00 02 04 05 b4 04 02 08 0a 00 47 fb b0 00 00 00 00 01 03 03 00 + +[out,df0] +4500 0038 809a 0000 ff01 2d1d 0303 0303 0404 0404 +0303 0fa3 0000 0000 +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 +5000 9d58 0000 0001 + +# ICMP dest unreachable with whole packet in payload (40 bytes = 320 bits) +[out,df0] +4500 0058 809a 0000 ff01 2cfd 0303 0303 0404 0404 +0303 0735 0000 0000 +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 +5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 +0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 + +[out,df0] +4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 +0303 0fa3 0000 0000 +4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 + diff --git a/contrib/ipfilter/test/input/ni13 b/contrib/ipfilter/test/input/ni13 new file mode 100644 index 0000000..56ddb79 --- /dev/null +++ b/contrib/ipfilter/test/input/ni13 @@ -0,0 +1,235 @@ +# 23:18:36.130424 192.168.113.1.1511 > 192.168.113.3.1723: S 2884651685:2884651685(0) win 64240 <mss 1460,nop,nop,sackOK> (DF) +[in,pcn1=192.168.113.3] +4500 0030 5e11 4000 8006 3961 c0a8 7101 +c0a8 7103 05e7 06bb abf0 4aa5 0000 0000 +7002 faf0 21a1 0000 0204 05b4 0101 0402 + +# 23:18:36.130778 192.168.113.3.1723 > 192.168.113.1.1511: S 2774821082:2774821082(0) ack 2884651686 win 32768 <mss 1460> (DF) +[out,pcn1] +4500 002c 69a6 4000 4006 6dd0 c0a8 7103 +c0a8 7101 06bb 05e7 a564 68da abf0 4aa6 +6012 8000 a348 0000 0204 05b4 + +# 23:18:36.130784 192.168.113.1.1511 > 192.168.113.3.1723: P 1:157(156) ack 1 win 64240: pptp CTRL_MSGTYPE=SCCRQ PROTO_VER(1.0) FRAME_CAP(A) BEARER_CAP(A) MAX_CHAN(0) FIRM_REV(2600) HOSTNAME() VENDOR(Microsoft Windows NT) (DF) +[in,pcn1] +4500 00c4 5e12 4000 8006 38cc c0a8 7101 +c0a8 7103 05e7 06bb abf0 4aa6 a564 68db +5018 faf0 e2a0 0000 009c 0001 1a2b 3c4d +0001 0000 0100 0000 0000 0001 0000 0001 +0000 0a28 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 4d69 6372 6f73 6f66 7420 5769 +6e64 6f77 7320 4e54 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260235 192.168.113.3.1723 > 192.168.113.1.1511: P 1:157(156) ack 157 win 33580: pptp CTRL_MSGTYPE=SCCRP PROTO_VER(1.0) RESULT_CODE(1) ERR_CODE(0) FRAME_CAP() BEARER_CAP() MAX_CHAN(1) FIRM_REV(1) HOSTNAME(local) VENDOR(linux) (DF) +[out,pcn1] +4500 00c4 69a7 4000 4006 6d37 c0a8 7103 +c0a8 7101 06bb 05e7 a564 68db abf0 4b42 +5018 832c cecf 0000 009c 0001 1a2b 3c4d +0002 0000 0100 0100 0000 0000 0000 0000 +0001 0001 6c6f 6361 6c00 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 6c69 6e75 7800 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260252 192.168.113.1.1511 > 192.168.113.3.1723: P 157:325(168) ack 157 win 64084: pptp CTRL_MSGTYPE=OCRQ CALL_ID(16384) CALL_SER_NUM(4913) MIN_BPS(300) MAX_BPS(100000000) BEARER_TYPE(Any) FRAME_TYPE(E) RECV_WIN(64) PROC_DELAY(0) PHONE_NO_LEN(0) PHONE_NO() SUB_ADDR() (DF) +[in,pcn1] +4500 00d0 5e13 4000 8006 38bf c0a8 7101 +c0a8 7103 05e7 06bb abf0 4b42 a564 6977 +5018 fa54 ac07 0000 00a8 0001 1a2b 3c4d +0007 0000 4000 1331 0000 012c 05f5 e100 +0000 0003 0000 0003 0040 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 + +# 23:18:36.272856 192.168.113.3.1723 > 192.168.113.1.1511: P 157:189(32) ack 325 win 33580: pptp CTRL_MSGTYPE=OCRP CALL_ID(0) PEER_CALL_ID(16384) RESULT_CODE(1) ERR_CODE(0) CAUSE_CODE(0) CONN_SPEED(100000000) RECV_WIN(64) PROC_DELAY(0) PHY_CHAN_ID(0) (DF) +[out,pcn1] +4500 0048 69a8 4000 4006 6db2 c0a8 7103 +c0a8 7101 06bb 05e7 a564 6977 abf0 4bea +5018 832c 36fa 0000 0020 0001 1a2b 3c4d +0008 0000 0000 4000 0100 0000 05f5 e100 +0040 0000 0000 0000 + +# 23:18:36.321819 192.168.113.1.1511 > 192.168.113.3.1723: P 325:349(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0xffffffff) RECV_ACCM(0xffffffff) (DF) +[in,pcn1] +4500 0040 5e14 4000 8006 394e c0a8 7101 +c0a8 7103 05e7 06bb abf0 4bea a564 6997 +5018 fa34 e810 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 ffff ffff ffff ffff + +# 23:18:36.349759 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:0 ppp: LCP 25: Conf-Req(0), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC, Call-Back CBCP +[in,pcn1] +4500 0039 5e15 0000 802f 792b c0a8 7101 +c0a8 7103 3001 880b 0019 0000 0000 0000 +ff03 c021 0100 0015 0104 0578 0506 577f +7c5b 0702 0802 0d03 06 + +# 23:18:36.389970 192.168.113.3 > 192.168.113.1: gre [KAv1] ID:4000 A:4294967295 [|gre] +[out,pcn1] +4500 0020 69a9 0000 ff2f eeaf c0a8 7103 +c0a8 7101 2081 880b 0000 4000 ffff ffff + +# 23:18:36.518426 192.168.113.3.1723 > 192.168.113.1.1511: . ack 349 win 33580 (DF) +[out,pcn1] +4500 0028 69aa 4000 4006 6dd0 c0a8 7103 +c0a8 7101 06bb 05e7 a564 6997 abf0 4c02 +5010 832c b5c1 0000 + +# 23:18:36.555363 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:0 ppp: LCP 24: Conf-Req(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[out,pcn1] +4500 0038 69ab 0000 ff2f ee95 c0a8 7103 +c0a8 7101 3001 880b 0018 4000 0000 0000 +ff03 c021 0101 0014 0206 0000 0000 0506 +22d9 0cfa 0702 0802 + +# 23:18:36.556030 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:1 A:0 ppp: LCP 11: Conf-Rej(0), Call-Back CBCP +[out,pcn1] +4500 002f 69ac 0000 ff2f ee9d c0a8 7103 +c0a8 7101 3081 880b 000b 4000 0000 0001 +0000 0000 ff03 c021 0400 0007 0d03 06 + +# 23:18:36.557166 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:1 A:1 ppp: LCP 24: Conf-Ack(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[in,pcn1] +4500 003c 5e16 0000 802f 7927 c0a8 7101 +c0a8 7103 3081 880b 0018 0000 0000 0001 +0000 0001 ff03 c021 0201 0014 0206 0000 +0000 0506 22d9 0cfa 0702 0802 + +# 23:18:36.557764 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:2 ppp: LCP 22: Conf-Req(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[in,pcn1] +4500 0036 5e17 0000 802f 792c c0a8 7101 +c0a8 7103 3001 880b 0016 0000 0000 0002 +ff03 c021 0101 0012 0104 0578 0506 577f +7c5b 0702 0802 + +# 23:18:36.564658 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:2 A:2 ppp: LCP 22: Conf-Ack(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[out,pcn1] +4500 003a 69ad 0000 ff2f ee91 c0a8 7103 +c0a8 7101 3081 880b 0016 4000 0000 0002 +0000 0002 ff03 c021 0201 0012 0104 0578 +0506 577f 7c5b 0702 0802 + +# 23:18:36.564803 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:3 ppp: IPCP 18: Conf-Req(1), IP-Addr=192.168.0.1, IP-Comp VJ-Comp +[out,pcn1] +4500 0032 69ae 0000 ff2f ee98 c0a8 7103 +c0a8 7101 3001 880b 0012 4000 0000 0003 +8021 0101 0010 0306 c0a8 0001 0206 002d +0f01 + +# 23:18:36.570395 192.168.113.1.1511 > 192.168.113.3.1723: P 349:373(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0x00000000) RECV_ACCM(0xffffffff) (DF) +[in,pcn1] +4500 0040 5e18 4000 8006 394a c0a8 7101 +c0a8 7103 05e7 06bb abf0 4c02 a564 6997 +5018 fa34 e7f8 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 0000 0000 ffff ffff + +# 23:18:36.573307 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:3 A:3 ppp: LCP 20: Ident(2), Magic-Num=577f7c5b +[in,pcn1] +4500 0038 5e19 0000 802f 7928 c0a8 7101 +c0a8 7103 3081 880b 0014 0000 0000 0003 +0000 0003 c021 0c02 0012 577f 7c5b 4d53 +5241 5356 352e 3130 + +# 23:18:36.573856 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:4 A:3 ppp: LCP 26: Code-Rej(2) +[out,pcn1] +4500 003e 69af 0000 ff2f ee8b c0a8 7103 +c0a8 7101 3081 880b 001a 4000 0000 0004 +0000 0003 ff03 c021 0702 0016 0c02 0012 +577f 7c5b 4d53 5241 5356 352e 3130 + +# 23:18:36.584936 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:4 A:4 ppp: LCP 26: Ident(3), Magic-Num=577f7c5b +[in,pcn1] +4500 003e 5e1a 0000 802f 7921 c0a8 7101 +c0a8 7103 3081 880b 001a 0000 0000 0004 +0000 0004 c021 0c03 0018 577f 7c5b 4d53 +5241 532d 302d 434c 4159 4d4f 4f52 + +# 23:18:36.585562 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:5 A:4 ppp: LCP 32: Code-Rej(3) +[out,pcn1] +4500 0044 69b0 0000 ff2f ee84 c0a8 7103 +c0a8 7101 3081 880b 0020 4000 0000 0005 +0000 0004 ff03 c021 0703 001c 0c03 0018 +577f 7c5b 4d53 5241 532d 302d 434c 4159 +4d4f 4f52 + +# 23:18:36.588721 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:5 A:5 ppp: CCP 12: Conf-Req(4), MPPC +[in,pcn1] +4500 0030 5e1b 0000 802f 792e c0a8 7101 +c0a8 7103 3081 880b 000c 0000 0000 0005 +0000 0005 80fd 0104 000a 1206 0100 0001 + +# 23:18:36.589445 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:6 A:5 ppp: CCP 6: Conf-Req(1) +[out,pcn1] +4500 002a 69b1 0000 ff2f ee9d c0a8 7103 +c0a8 7101 3081 880b 0006 4000 0000 0006 +0000 0005 80fd 0101 0004 + +# 23:18:36.589540 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:7 ppp: CCP 12: Conf-Rej(4), MPPC +[out,pcn1] +4500 002c 69b2 0000 ff2f ee9a c0a8 7103 +c0a8 7101 3001 880b 000c 4000 0000 0007 +80fd 0404 000a 1206 0100 0001 + +# 23:18:36.590023 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:6 A:7 ppp: IPCP 36: Conf-Req(5), IP-Addr=0.0.0.0, Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[in,pcn1] +4500 0048 5e1c 0000 802f 7915 c0a8 7101 +c0a8 7103 3081 880b 0024 0000 0000 0006 +0000 0007 8021 0105 0022 0306 0000 0000 +8106 0000 0000 8206 0000 0000 8306 0000 +0000 8406 0000 0000 + +# 23:18:36.590489 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:8 A:6 ppp: IPCP 30: Conf-Rej(5), Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[out,pcn1] +4500 0042 69b3 0000 ff2f ee83 c0a8 7103 +c0a8 7101 3081 880b 001e 4000 0000 0008 +0000 0006 8021 0405 001c 8106 0000 0000 +8206 0000 0000 8306 0000 0000 8406 0000 +0000 + +# 23:18:36.591003 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:7 A:8 ppp: IPCP 12: Conf-Rej(1), IP-Comp VJ-Comp +[in,pcn1] +4500 0030 5e1d 0000 802f 792c c0a8 7101 +c0a8 7103 3081 880b 000c 0000 0000 0007 +0000 0008 8021 0401 000a 0206 002d 0f01 + +# 23:18:36.593819 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:9 A:7 ppp: IPCP 12: Conf-Req(2), IP-Addr=192.168.0.1 +[out,pcn1] +4500 0030 69b4 0000 ff2f ee94 c0a8 7103 +c0a8 7101 3081 880b 000c 4000 0000 0009 +0000 0007 8021 0102 000a 0306 c0a8 0001 + +# 23:18:36.594840 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:8 A:9 ppp: CCP 6: Conf-Ack(1) +[in,pcn1] +4500 002a 5e1e 0000 802f 7933 c0a8 7101 +c0a8 7103 3081 880b 0006 0000 0000 0008 +0000 0009 80fd 0201 0004 0000 0000 + +# 23:18:36.595525 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:9 ppp: CCP 18: Term-Req(6) +[in,pcn1] +4500 0032 5e1f 0000 802f 792a c0a8 7101 +c0a8 7103 3001 880b 0012 0000 0000 0009 +80fd 0506 0010 577f 7c5b 003c cd74 0000 +02dc + +# 23:18:36.595937 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:10 A:9 ppp: CCP 6: Term-Ack(6) +[out,pcn1] +4500 002a 69b5 0000 ff2f ee99 c0a8 7103 +c0a8 7101 3081 880b 0006 4000 0000 000a +0000 0009 80fd 0606 0004 + diff --git a/contrib/ipfilter/test/input/ni14 b/contrib/ipfilter/test/input/ni14 new file mode 100644 index 0000000..00f0290 --- /dev/null +++ b/contrib/ipfilter/test/input/ni14 @@ -0,0 +1,235 @@ +# 23:18:36.130424 192.168.113.1.1511 > 192.168.113.3.1723: S 2884651685:2884651685(0) win 64240 <mss 1460,nop,nop,sackOK> (DF) +[in,pcn1=192.168.113.3] +4500 0030 5e11 4000 8006 3961 c0a8 7101 +c0a8 7103 05e7 06bb abf0 4aa5 0000 0000 +7002 faf0 21a1 0000 0204 05b4 0101 0402 + +# 23:18:36.130778 192.168.113.3.1723 > 192.168.113.1.1511: S 2774821082:2774821082(0) ack 2884651686 win 32768 <mss 1460> (DF) +[out,pcn1] +4500 002c 69a6 4000 4006 207b 7f00 0001 +c0a8 7101 06bb 05e7 a564 68da abf0 4aa6 +6012 8000 55f3 0000 0204 05b4 + +# 23:18:36.130784 192.168.113.1.1511 > 192.168.113.3.1723: P 1:157(156) ack 1 win 64240: pptp CTRL_MSGTYPE=SCCRQ PROTO_VER(1.0) FRAME_CAP(A) BEARER_CAP(A) MAX_CHAN(0) FIRM_REV(2600) HOSTNAME() VENDOR(Microsoft Windows NT) (DF) +[in,pcn1] +4500 00c4 5e12 4000 8006 38cc c0a8 7101 +c0a8 7103 05e7 06bb abf0 4aa6 a564 68db +5018 faf0 e2a0 0000 009c 0001 1a2b 3c4d +0001 0000 0100 0000 0000 0001 0000 0001 +0000 0a28 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 4d69 6372 6f73 6f66 7420 5769 +6e64 6f77 7320 4e54 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260235 192.168.113.3.1723 > 192.168.113.1.1511: P 1:157(156) ack 157 win 33580: pptp CTRL_MSGTYPE=SCCRP PROTO_VER(1.0) RESULT_CODE(1) ERR_CODE(0) FRAME_CAP() BEARER_CAP() MAX_CHAN(1) FIRM_REV(1) HOSTNAME(local) VENDOR(linux) (DF) +[out,pcn1] +4500 00c4 69a7 4000 4006 1fe2 7f00 0001 +c0a8 7101 06bb 05e7 a564 68db abf0 4b42 +5018 832c 817a 0000 009c 0001 1a2b 3c4d +0002 0000 0100 0100 0000 0000 0000 0000 +0001 0001 6c6f 6361 6c00 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 6c69 6e75 7800 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260252 192.168.113.1.1511 > 192.168.113.3.1723: P 157:325(168) ack 157 win 64084: pptp CTRL_MSGTYPE=OCRQ CALL_ID(16384) CALL_SER_NUM(4913) MIN_BPS(300) MAX_BPS(100000000) BEARER_TYPE(Any) FRAME_TYPE(E) RECV_WIN(64) PROC_DELAY(0) PHONE_NO_LEN(0) PHONE_NO() SUB_ADDR() (DF) +[in,pcn1] +4500 00d0 5e13 4000 8006 38bf c0a8 7101 +c0a8 7103 05e7 06bb abf0 4b42 a564 6977 +5018 fa54 ac07 0000 00a8 0001 1a2b 3c4d +0007 0000 4000 1331 0000 012c 05f5 e100 +0000 0003 0000 0003 0040 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 + +# 23:18:36.272856 192.168.113.3.1723 > 192.168.113.1.1511: P 157:189(32) ack 325 win 33580: pptp CTRL_MSGTYPE=OCRP CALL_ID(0) PEER_CALL_ID(16384) RESULT_CODE(1) ERR_CODE(0) CAUSE_CODE(0) CONN_SPEED(100000000) RECV_WIN(64) PROC_DELAY(0) PHY_CHAN_ID(0) (DF) +[out,pcn1] +4500 0048 69a8 4000 4006 205d 7f00 0001 +c0a8 7101 06bb 05e7 a564 6977 abf0 4bea +5018 832c e9a4 0000 0020 0001 1a2b 3c4d +0008 0000 0000 4000 0100 0000 05f5 e100 +0040 0000 0000 0000 + +# 23:18:36.321819 192.168.113.1.1511 > 192.168.113.3.1723: P 325:349(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0xffffffff) RECV_ACCM(0xffffffff) (DF) +[in,pcn1] +4500 0040 5e14 4000 8006 394e c0a8 7101 +c0a8 7103 05e7 06bb abf0 4bea a564 6997 +5018 fa34 e810 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 ffff ffff ffff ffff + +# 23:18:36.349759 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:0 ppp: LCP 25: Conf-Req(0), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC, Call-Back CBCP +[in,pcn1] +4500 0039 5e15 0000 802f 792b c0a8 7101 +c0a8 7103 3001 880b 0019 0000 0000 0000 +ff03 c021 0100 0015 0104 0578 0506 577f +7c5b 0702 0802 0d03 06 + +# 23:18:36.389970 192.168.113.3 > 192.168.113.1: gre [KAv1] ID:4000 A:4294967295 [|gre] +[out,pcn1] +4500 0020 69a9 0000 ff2f a15a 7f00 0001 +c0a8 7101 2081 880b 0000 4000 ffff ffff + +# 23:18:36.518426 192.168.113.3.1723 > 192.168.113.1.1511: . ack 349 win 33580 (DF) +[out,pcn1] +4500 0028 69aa 4000 4006 207b 7f00 0001 +c0a8 7101 06bb 05e7 a564 6997 abf0 4c02 +5010 832c 686c 0000 + +# 23:18:36.555363 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:0 ppp: LCP 24: Conf-Req(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[out,pcn1] +4500 0038 69ab 0000 ff2f a140 7f00 0001 +c0a8 7101 3001 880b 0018 4000 0000 0000 +ff03 c021 0101 0014 0206 0000 0000 0506 +22d9 0cfa 0702 0802 + +# 23:18:36.556030 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:1 A:0 ppp: LCP 11: Conf-Rej(0), Call-Back CBCP +[out,pcn1] +4500 002f 69ac 0000 ff2f a148 7f00 0001 +c0a8 7101 3081 880b 000b 4000 0000 0001 +0000 0000 ff03 c021 0400 0007 0d03 06 + +# 23:18:36.557166 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:1 A:1 ppp: LCP 24: Conf-Ack(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[in,pcn1] +4500 003c 5e16 0000 802f 7927 c0a8 7101 +c0a8 7103 3081 880b 0018 0000 0000 0001 +0000 0001 ff03 c021 0201 0014 0206 0000 +0000 0506 22d9 0cfa 0702 0802 + +# 23:18:36.557764 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:2 ppp: LCP 22: Conf-Req(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[in,pcn1] +4500 0036 5e17 0000 802f 792c c0a8 7101 +c0a8 7103 3001 880b 0016 0000 0000 0002 +ff03 c021 0101 0012 0104 0578 0506 577f +7c5b 0702 0802 + +# 23:18:36.564658 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:2 A:2 ppp: LCP 22: Conf-Ack(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[out,pcn1] +4500 003a 69ad 0000 ff2f a13c 7f00 0001 +c0a8 7101 3081 880b 0016 4000 0000 0002 +0000 0002 ff03 c021 0201 0012 0104 0578 +0506 577f 7c5b 0702 0802 + +# 23:18:36.564803 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:3 ppp: IPCP 18: Conf-Req(1), IP-Addr=192.168.0.1, IP-Comp VJ-Comp +[out,pcn1] +4500 0032 69ae 0000 ff2f ee98 7f00 0001 +c0a8 7101 3001 880b 0012 4000 0000 0003 +8021 0101 0010 0306 c0a8 0001 0206 002d +0f01 + +# 23:18:36.570395 192.168.113.1.1511 > 192.168.113.3.1723: P 349:373(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0x00000000) RECV_ACCM(0xffffffff) (DF) +[in,pcn1] +4500 0040 5e18 4000 8006 394a c0a8 7101 +c0a8 7103 05e7 06bb abf0 4c02 a564 6997 +5018 fa34 e7f8 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 0000 0000 ffff ffff + +# 23:18:36.573307 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:3 A:3 ppp: LCP 20: Ident(2), Magic-Num=577f7c5b +[in,pcn1] +4500 0038 5e19 0000 802f 7928 c0a8 7101 +c0a8 7103 3081 880b 0014 0000 0000 0003 +0000 0003 c021 0c02 0012 577f 7c5b 4d53 +5241 5356 352e 3130 + +# 23:18:36.573856 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:4 A:3 ppp: LCP 26: Code-Rej(2) +[out,pcn1] +4500 003e 69af 0000 ff2f ee8b 7f00 0001 +c0a8 7101 3081 880b 001a 4000 0000 0004 +0000 0003 ff03 c021 0702 0016 0c02 0012 +577f 7c5b 4d53 5241 5356 352e 3130 + +# 23:18:36.584936 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:4 A:4 ppp: LCP 26: Ident(3), Magic-Num=577f7c5b +[in,pcn1] +4500 003e 5e1a 0000 802f 7921 c0a8 7101 +c0a8 7103 3081 880b 001a 0000 0000 0004 +0000 0004 c021 0c03 0018 577f 7c5b 4d53 +5241 532d 302d 434c 4159 4d4f 4f52 + +# 23:18:36.585562 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:5 A:4 ppp: LCP 32: Code-Rej(3) +[out,pcn1] +4500 0044 69b0 0000 ff2f ee84 7f00 0001 +c0a8 7101 3081 880b 0020 4000 0000 0005 +0000 0004 ff03 c021 0703 001c 0c03 0018 +577f 7c5b 4d53 5241 532d 302d 434c 4159 +4d4f 4f52 + +# 23:18:36.588721 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:5 A:5 ppp: CCP 12: Conf-Req(4), MPPC +[in,pcn1] +4500 0030 5e1b 0000 802f 792e c0a8 7101 +c0a8 7103 3081 880b 000c 0000 0000 0005 +0000 0005 80fd 0104 000a 1206 0100 0001 + +# 23:18:36.589445 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:6 A:5 ppp: CCP 6: Conf-Req(1) +[out,pcn1] +4500 002a 69b1 0000 ff2f ee9d 7f00 0001 +c0a8 7101 3081 880b 0006 4000 0000 0006 +0000 0005 80fd 0101 0004 + +# 23:18:36.589540 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:7 ppp: CCP 12: Conf-Rej(4), MPPC +[out,pcn1] +4500 002c 69b2 0000 ff2f ee9a 7f00 0001 +c0a8 7101 3001 880b 000c 4000 0000 0007 +80fd 0404 000a 1206 0100 0001 + +# 23:18:36.590023 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:6 A:7 ppp: IPCP 36: Conf-Req(5), IP-Addr=0.0.0.0, Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[in,pcn1] +4500 0048 5e1c 0000 802f 7915 c0a8 7101 +c0a8 7103 3081 880b 0024 0000 0000 0006 +0000 0007 8021 0105 0022 0306 0000 0000 +8106 0000 0000 8206 0000 0000 8306 0000 +0000 8406 0000 0000 + +# 23:18:36.590489 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:8 A:6 ppp: IPCP 30: Conf-Rej(5), Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[out,pcn1] +4500 0042 69b3 0000 ff2f ee83 7f00 0001 +c0a8 7101 3081 880b 001e 4000 0000 0008 +0000 0006 8021 0405 001c 8106 0000 0000 +8206 0000 0000 8306 0000 0000 8406 0000 +0000 + +# 23:18:36.591003 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:7 A:8 ppp: IPCP 12: Conf-Rej(1), IP-Comp VJ-Comp +[in,pcn1] +4500 0030 5e1d 0000 802f 792c c0a8 7101 +c0a8 7103 3081 880b 000c 0000 0000 0007 +0000 0008 8021 0401 000a 0206 002d 0f01 + +# 23:18:36.593819 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:9 A:7 ppp: IPCP 12: Conf-Req(2), IP-Addr=192.168.0.1 +[out,pcn1] +4500 0030 69b4 0000 ff2f ee94 7f00 0001 +c0a8 7101 3081 880b 000c 4000 0000 0009 +0000 0007 8021 0102 000a 0306 c0a8 0001 + +# 23:18:36.594840 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:8 A:9 ppp: CCP 6: Conf-Ack(1) +[in,pcn1] +4500 002a 5e1e 0000 802f 7931 c0a8 7101 +c0a8 7103 3081 880b 0006 0000 0000 0008 +0000 0009 80fd 0201 0004 0000 0000 + +# 23:18:36.595525 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:9 ppp: CCP 18: Term-Req(6) +[in,pcn1] +4500 0032 5e1f 0000 802f 7928 c0a8 7101 +c0a8 7103 3001 880b 0012 0000 0000 0009 +80fd 0506 0010 577f 7c5b 003c cd74 0000 +02dc + +# 23:18:36.595937 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:10 A:9 ppp: CCP 6: Term-Ack(6) +[out,pcn1] +4500 002a 69b5 0000 ff2f ee99 7f00 0001 +c0a8 7101 3081 880b 0006 4000 0000 000a +0000 0009 80fd 0606 0004 + diff --git a/contrib/ipfilter/test/input/ni15 b/contrib/ipfilter/test/input/ni15 new file mode 100644 index 0000000..fb445bb --- /dev/null +++ b/contrib/ipfilter/test/input/ni15 @@ -0,0 +1,235 @@ +# 23:18:36.130424 192.168.113.1.1511 > 192.168.113.3.1723: S 2884651685:2884651685(0) win 64240 <mss 1460,nop,nop,sackOK> (DF) +[out,pcn1=192.168.113.3] +4500 0030 5e11 4000 8006 3961 c0a8 7101 +c0a8 7103 05e7 06bb abf0 4aa5 0000 0000 +7002 faf0 21a1 0000 0204 05b4 0101 0402 + +# 23:18:36.130778 192.168.113.3.1723 > 192.168.113.1.1511: S 2774821082:2774821082(0) ack 2884651686 win 32768 <mss 1460> (DF) +[in,pcn1] +4500 002c 69a6 4000 4006 6dd0 c0a8 7103 +c0a8 7101 06bb 05e7 a564 68da abf0 4aa6 +6012 8000 a348 0000 0204 05b4 + +# 23:18:36.130784 192.168.113.1.1511 > 192.168.113.3.1723: P 1:157(156) ack 1 win 64240: pptp CTRL_MSGTYPE=SCCRQ PROTO_VER(1.0) FRAME_CAP(A) BEARER_CAP(A) MAX_CHAN(0) FIRM_REV(2600) HOSTNAME() VENDOR(Microsoft Windows NT) (DF) +[out,pcn1] +4500 00c4 5e12 4000 8006 38cc c0a8 7101 +c0a8 7103 05e7 06bb abf0 4aa6 a564 68db +5018 faf0 e2a0 0000 009c 0001 1a2b 3c4d +0001 0000 0100 0000 0000 0001 0000 0001 +0000 0a28 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 4d69 6372 6f73 6f66 7420 5769 +6e64 6f77 7320 4e54 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260235 192.168.113.3.1723 > 192.168.113.1.1511: P 1:157(156) ack 157 win 33580: pptp CTRL_MSGTYPE=SCCRP PROTO_VER(1.0) RESULT_CODE(1) ERR_CODE(0) FRAME_CAP() BEARER_CAP() MAX_CHAN(1) FIRM_REV(1) HOSTNAME(local) VENDOR(linux) (DF) +[in,pcn1] +4500 00c4 69a7 4000 4006 6d37 c0a8 7103 +c0a8 7101 06bb 05e7 a564 68db abf0 4b42 +5018 832c cecf 0000 009c 0001 1a2b 3c4d +0002 0000 0100 0100 0000 0000 0000 0000 +0001 0001 6c6f 6361 6c00 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 6c69 6e75 7800 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260252 192.168.113.1.1511 > 192.168.113.3.1723: P 157:325(168) ack 157 win 64084: pptp CTRL_MSGTYPE=OCRQ CALL_ID(16384) CALL_SER_NUM(4913) MIN_BPS(300) MAX_BPS(100000000) BEARER_TYPE(Any) FRAME_TYPE(E) RECV_WIN(64) PROC_DELAY(0) PHONE_NO_LEN(0) PHONE_NO() SUB_ADDR() (DF) +[out,pcn1] +4500 00d0 5e13 4000 8006 38bf c0a8 7101 +c0a8 7103 05e7 06bb abf0 4b42 a564 6977 +5018 fa54 ac07 0000 00a8 0001 1a2b 3c4d +0007 0000 4000 1331 0000 012c 05f5 e100 +0000 0003 0000 0003 0040 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 + +# 23:18:36.272856 192.168.113.3.1723 > 192.168.113.1.1511: P 157:189(32) ack 325 win 33580: pptp CTRL_MSGTYPE=OCRP CALL_ID(0) PEER_CALL_ID(16384) RESULT_CODE(1) ERR_CODE(0) CAUSE_CODE(0) CONN_SPEED(100000000) RECV_WIN(64) PROC_DELAY(0) PHY_CHAN_ID(0) (DF) +[in,pcn1] +4500 0048 69a8 4000 4006 6db2 c0a8 7103 +c0a8 7101 06bb 05e7 a564 6977 abf0 4bea +5018 832c 36fa 0000 0020 0001 1a2b 3c4d +0008 0000 0000 4000 0100 0000 05f5 e100 +0040 0000 0000 0000 + +# 23:18:36.321819 192.168.113.1.1511 > 192.168.113.3.1723: P 325:349(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0xffffffff) RECV_ACCM(0xffffffff) (DF) +[out,pcn1] +4500 0040 5e14 4000 8006 394e c0a8 7101 +c0a8 7103 05e7 06bb abf0 4bea a564 6997 +5018 fa34 e810 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 ffff ffff ffff ffff + +# 23:18:36.349759 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:0 ppp: LCP 25: Conf-Req(0), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC, Call-Back CBCP +[out,pcn1] +4500 0039 5e15 0000 802f 792b c0a8 7101 +c0a8 7103 3001 880b 0019 0000 0000 0000 +ff03 c021 0100 0015 0104 0578 0506 577f +7c5b 0702 0802 0d03 06 + +# 23:18:36.389970 192.168.113.3 > 192.168.113.1: gre [KAv1] ID:4000 A:4294967295 [|gre] +[in,pcn1] +4500 0020 69a9 0000 ff2f eeaf c0a8 7103 +c0a8 7101 2081 880b 0000 4000 ffff ffff + +# 23:18:36.518426 192.168.113.3.1723 > 192.168.113.1.1511: . ack 349 win 33580 (DF) +[in,pcn1] +4500 0028 69aa 4000 4006 6dd0 c0a8 7103 +c0a8 7101 06bb 05e7 a564 6997 abf0 4c02 +5010 832c b5c1 0000 + +# 23:18:36.555363 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:0 ppp: LCP 24: Conf-Req(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[in,pcn1] +4500 0038 69ab 0000 ff2f ee95 c0a8 7103 +c0a8 7101 3001 880b 0018 4000 0000 0000 +ff03 c021 0101 0014 0206 0000 0000 0506 +22d9 0cfa 0702 0802 + +# 23:18:36.556030 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:1 A:0 ppp: LCP 11: Conf-Rej(0), Call-Back CBCP +[in,pcn1] +4500 002f 69ac 0000 ff2f ee9d c0a8 7103 +c0a8 7101 3081 880b 000b 4000 0000 0001 +0000 0000 ff03 c021 0400 0007 0d03 06 + +# 23:18:36.557166 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:1 A:1 ppp: LCP 24: Conf-Ack(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[out,pcn1] +4500 003c 5e16 0000 802f 7927 c0a8 7101 +c0a8 7103 3081 880b 0018 0000 0000 0001 +0000 0001 ff03 c021 0201 0014 0206 0000 +0000 0506 22d9 0cfa 0702 0802 + +# 23:18:36.557764 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:2 ppp: LCP 22: Conf-Req(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[out,pcn1] +4500 0036 5e17 0000 802f 792c c0a8 7101 +c0a8 7103 3001 880b 0016 0000 0000 0002 +ff03 c021 0101 0012 0104 0578 0506 577f +7c5b 0702 0802 + +# 23:18:36.564658 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:2 A:2 ppp: LCP 22: Conf-Ack(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[in,pcn1] +4500 003a 69ad 0000 ff2f ee91 c0a8 7103 +c0a8 7101 3081 880b 0016 4000 0000 0002 +0000 0002 ff03 c021 0201 0012 0104 0578 +0506 577f 7c5b 0702 0802 + +# 23:18:36.564803 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:3 ppp: IPCP 18: Conf-Req(1), IP-Addr=192.168.0.1, IP-Comp VJ-Comp +[in,pcn1] +4500 0032 69ae 0000 ff2f ee98 c0a8 7103 +c0a8 7101 3001 880b 0012 4000 0000 0003 +8021 0101 0010 0306 c0a8 0001 0206 002d +0f01 + +# 23:18:36.570395 192.168.113.1.1511 > 192.168.113.3.1723: P 349:373(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0x00000000) RECV_ACCM(0xffffffff) (DF) +[out,pcn1] +4500 0040 5e18 4000 8006 394a c0a8 7101 +c0a8 7103 05e7 06bb abf0 4c02 a564 6997 +5018 fa34 e7f8 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 0000 0000 ffff ffff + +# 23:18:36.573307 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:3 A:3 ppp: LCP 20: Ident(2), Magic-Num=577f7c5b +[out,pcn1] +4500 0038 5e19 0000 802f 7928 c0a8 7101 +c0a8 7103 3081 880b 0014 0000 0000 0003 +0000 0003 c021 0c02 0012 577f 7c5b 4d53 +5241 5356 352e 3130 + +# 23:18:36.573856 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:4 A:3 ppp: LCP 26: Code-Rej(2) +[in,pcn1] +4500 003e 69af 0000 ff2f ee8b c0a8 7103 +c0a8 7101 3081 880b 001a 4000 0000 0004 +0000 0003 ff03 c021 0702 0016 0c02 0012 +577f 7c5b 4d53 5241 5356 352e 3130 + +# 23:18:36.584936 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:4 A:4 ppp: LCP 26: Ident(3), Magic-Num=577f7c5b +[out,pcn1] +4500 003e 5e1a 0000 802f 7921 c0a8 7101 +c0a8 7103 3081 880b 001a 0000 0000 0004 +0000 0004 c021 0c03 0018 577f 7c5b 4d53 +5241 532d 302d 434c 4159 4d4f 4f52 + +# 23:18:36.585562 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:5 A:4 ppp: LCP 32: Code-Rej(3) +[in,pcn1] +4500 0044 69b0 0000 ff2f ee84 c0a8 7103 +c0a8 7101 3081 880b 0020 4000 0000 0005 +0000 0004 ff03 c021 0703 001c 0c03 0018 +577f 7c5b 4d53 5241 532d 302d 434c 4159 +4d4f 4f52 + +# 23:18:36.588721 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:5 A:5 ppp: CCP 12: Conf-Req(4), MPPC +[out,pcn1] +4500 0030 5e1b 0000 802f 792e c0a8 7101 +c0a8 7103 3081 880b 000c 0000 0000 0005 +0000 0005 80fd 0104 000a 1206 0100 0001 + +# 23:18:36.589445 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:6 A:5 ppp: CCP 6: Conf-Req(1) +[in,pcn1] +4500 002a 69b1 0000 ff2f ee9d c0a8 7103 +c0a8 7101 3081 880b 0006 4000 0000 0006 +0000 0005 80fd 0101 0004 + +# 23:18:36.589540 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:7 ppp: CCP 12: Conf-Rej(4), MPPC +[in,pcn1] +4500 002c 69b2 0000 ff2f ee9a c0a8 7103 +c0a8 7101 3001 880b 000c 4000 0000 0007 +80fd 0404 000a 1206 0100 0001 + +# 23:18:36.590023 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:6 A:7 ppp: IPCP 36: Conf-Req(5), IP-Addr=0.0.0.0, Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[out,pcn1] +4500 0048 5e1c 0000 802f 7915 c0a8 7101 +c0a8 7103 3081 880b 0024 0000 0000 0006 +0000 0007 8021 0105 0022 0306 0000 0000 +8106 0000 0000 8206 0000 0000 8306 0000 +0000 8406 0000 0000 + +# 23:18:36.590489 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:8 A:6 ppp: IPCP 30: Conf-Rej(5), Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[in,pcn1] +4500 0042 69b3 0000 ff2f ee83 c0a8 7103 +c0a8 7101 3081 880b 001e 4000 0000 0008 +0000 0006 8021 0405 001c 8106 0000 0000 +8206 0000 0000 8306 0000 0000 8406 0000 +0000 + +# 23:18:36.591003 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:7 A:8 ppp: IPCP 12: Conf-Rej(1), IP-Comp VJ-Comp +[out,pcn1] +4500 0030 5e1d 0000 802f 792c c0a8 7101 +c0a8 7103 3081 880b 000c 0000 0000 0007 +0000 0008 8021 0401 000a 0206 002d 0f01 + +# 23:18:36.593819 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:9 A:7 ppp: IPCP 12: Conf-Req(2), IP-Addr=192.168.0.1 +[in,pcn1] +4500 0030 69b4 0000 ff2f ee94 c0a8 7103 +c0a8 7101 3081 880b 000c 4000 0000 0009 +0000 0007 8021 0102 000a 0306 c0a8 0001 + +# 23:18:36.594840 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:8 A:9 ppp: CCP 6: Conf-Ack(1) +[out,pcn1] +4500 002a 5e1e 0000 802f 7931 c0a8 7101 +c0a8 7103 3081 880b 0006 0000 0000 0008 +0000 0009 80fd 0201 0004 0000 0000 + +# 23:18:36.595525 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:9 ppp: CCP 18: Term-Req(6) +[out,pcn1] +4500 0032 5e1f 0000 802f 7928 c0a8 7101 +c0a8 7103 3001 880b 0012 0000 0000 0009 +80fd 0506 0010 577f 7c5b 003c cd74 0000 +02dc + +# 23:18:36.595937 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:10 A:9 ppp: CCP 6: Term-Ack(6) +[in,pcn1] +4500 002a 69b5 0000 ff2f ee99 c0a8 7103 +c0a8 7101 3081 880b 0006 4000 0000 000a +0000 0009 80fd 0606 0004 + diff --git a/contrib/ipfilter/test/input/ni16 b/contrib/ipfilter/test/input/ni16 new file mode 100644 index 0000000..b1cc521 --- /dev/null +++ b/contrib/ipfilter/test/input/ni16 @@ -0,0 +1,235 @@ +# 23:18:36.130424 192.168.113.1.1511 > 192.168.113.3.1723: S 2884651685:2884651685(0) win 64240 <mss 1460,nop,nop,sackOK> (DF) +[out,pcn1=192.168.113.1] +4500 0030 5e11 4000 8006 5f07 0a02 0202 +c0a8 7103 05e7 06bb abf0 4aa5 0000 0000 +7002 faf0 4747 0000 0204 05b4 0101 0402 + +# 23:18:36.130778 192.168.113.3.1723 > 192.168.113.1.1511: S 2774821082:2774821082(0) ack 2884651686 win 32768 <mss 1460> (DF) +[in,pcn1] +4500 002c 69a6 4000 4006 6dd0 c0a8 7103 +c0a8 7101 06bb 05e7 a564 68da abf0 4aa6 +6012 8000 a348 0000 0204 05b4 + +# 23:18:36.130784 192.168.113.1.1511 > 192.168.113.3.1723: P 1:157(156) ack 1 win 64240: pptp CTRL_MSGTYPE=SCCRQ PROTO_VER(1.0) FRAME_CAP(A) BEARER_CAP(A) MAX_CHAN(0) FIRM_REV(2600) HOSTNAME() VENDOR(Microsoft Windows NT) (DF) +[out,pcn1] +4500 00c4 5e12 4000 8006 5e72 0a02 0202 +c0a8 7103 05e7 06bb abf0 4aa6 a564 68db +5018 faf0 0847 0000 009c 0001 1a2b 3c4d +0001 0000 0100 0000 0000 0001 0000 0001 +0000 0a28 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 4d69 6372 6f73 6f66 7420 5769 +6e64 6f77 7320 4e54 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260235 192.168.113.3.1723 > 192.168.113.1.1511: P 1:157(156) ack 157 win 33580: pptp CTRL_MSGTYPE=SCCRP PROTO_VER(1.0) RESULT_CODE(1) ERR_CODE(0) FRAME_CAP() BEARER_CAP() MAX_CHAN(1) FIRM_REV(1) HOSTNAME(local) VENDOR(linux) (DF) +[in,pcn1] +4500 00c4 69a7 4000 4006 6d37 c0a8 7103 +c0a8 7101 06bb 05e7 a564 68db abf0 4b42 +5018 832c cecf 0000 009c 0001 1a2b 3c4d +0002 0000 0100 0100 0000 0000 0000 0000 +0001 0001 6c6f 6361 6c00 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 6c69 6e75 7800 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +# 23:18:36.260252 192.168.113.1.1511 > 192.168.113.3.1723: P 157:325(168) ack 157 win 64084: pptp CTRL_MSGTYPE=OCRQ CALL_ID(16384) CALL_SER_NUM(4913) MIN_BPS(300) MAX_BPS(100000000) BEARER_TYPE(Any) FRAME_TYPE(E) RECV_WIN(64) PROC_DELAY(0) PHONE_NO_LEN(0) PHONE_NO() SUB_ADDR() (DF) +[out,pcn1] +4500 00d0 5e13 4000 8006 5e65 0a02 0202 +c0a8 7103 05e7 06bb abf0 4b42 a564 6977 +5018 fa54 d1ad 0000 00a8 0001 1a2b 3c4d +0007 0000 4000 1331 0000 012c 05f5 e100 +0000 0003 0000 0003 0040 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 + +# 23:18:36.272856 192.168.113.3.1723 > 192.168.113.1.1511: P 157:189(32) ack 325 win 33580: pptp CTRL_MSGTYPE=OCRP CALL_ID(0) PEER_CALL_ID(16384) RESULT_CODE(1) ERR_CODE(0) CAUSE_CODE(0) CONN_SPEED(100000000) RECV_WIN(64) PROC_DELAY(0) PHY_CHAN_ID(0) (DF) +[in,pcn1] +4500 0048 69a8 4000 4006 6db2 c0a8 7103 +c0a8 7101 06bb 05e7 a564 6977 abf0 4bea +5018 832c 36fa 0000 0020 0001 1a2b 3c4d +0008 0000 0000 4000 0100 0000 05f5 e100 +0040 0000 0000 0000 + +# 23:18:36.321819 192.168.113.1.1511 > 192.168.113.3.1723: P 325:349(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0xffffffff) RECV_ACCM(0xffffffff) (DF) +[out,pcn1] +4500 0040 5e14 4000 8006 5ef4 0a02 0202 +c0a8 7103 05e7 06bb abf0 4bea a564 6997 +5018 fa34 0db7 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 ffff ffff ffff ffff + +# 23:18:36.349759 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:0 ppp: LCP 25: Conf-Req(0), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC, Call-Back CBCP +[out,pcn1] +4500 0039 5e15 0000 802f 9ed1 0a02 0202 +c0a8 7103 3001 880b 0019 0000 0000 0000 +ff03 c021 0100 0015 0104 0578 0506 577f +7c5b 0702 0802 0d03 06 + +# 23:18:36.389970 192.168.113.3 > 192.168.113.1: gre [KAv1] ID:4000 A:4294967295 [|gre] +[in,pcn1] +4500 0020 69a9 0000 ff2f eeaf c0a8 7103 +c0a8 7101 2081 880b 0000 4000 ffff ffff + +# 23:18:36.518426 192.168.113.3.1723 > 192.168.113.1.1511: . ack 349 win 33580 (DF) +[in,pcn1] +4500 0028 69aa 4000 4006 6dd0 c0a8 7103 +c0a8 7101 06bb 05e7 a564 6997 abf0 4c02 +5010 832c b5c1 0000 + +# 23:18:36.555363 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:0 ppp: LCP 24: Conf-Req(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[in,pcn1] +4500 0038 69ab 0000 ff2f ee95 c0a8 7103 +c0a8 7101 3001 880b 0018 4000 0000 0000 +ff03 c021 0101 0014 0206 0000 0000 0506 +22d9 0cfa 0702 0802 + +# 23:18:36.556030 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:1 A:0 ppp: LCP 11: Conf-Rej(0), Call-Back CBCP +[in,pcn1] +4500 002f 69ac 0000 ff2f ee9d c0a8 7103 +c0a8 7101 3081 880b 000b 4000 0000 0001 +0000 0000 ff03 c021 0400 0007 0d03 06 + +# 23:18:36.557166 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:1 A:1 ppp: LCP 24: Conf-Ack(1), ACCM=00000000, Magic-Num=22d90cfa, PFC, ACFC +[out,pcn1] +4500 003c 5e16 0000 802f 9ecd 0a02 0202 +c0a8 7103 3081 880b 0018 0000 0000 0001 +0000 0001 ff03 c021 0201 0014 0206 0000 +0000 0506 22d9 0cfa 0702 0802 + +# 23:18:36.557764 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:2 ppp: LCP 22: Conf-Req(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[out,pcn1] +4500 0036 5e17 0000 802f 9ed2 0a02 0202 +c0a8 7103 3001 880b 0016 0000 0000 0002 +ff03 c021 0101 0012 0104 0578 0506 577f +7c5b 0702 0802 + +# 23:18:36.564658 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:2 A:2 ppp: LCP 22: Conf-Ack(1), MRU=1400, Magic-Num=577f7c5b, PFC, ACFC +[in,pcn1] +4500 003a 69ad 0000 ff2f ee91 c0a8 7103 +c0a8 7101 3081 880b 0016 4000 0000 0002 +0000 0002 ff03 c021 0201 0012 0104 0578 +0506 577f 7c5b 0702 0802 + +# 23:18:36.564803 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:3 ppp: IPCP 18: Conf-Req(1), IP-Addr=192.168.0.1, IP-Comp VJ-Comp +[in,pcn1] +4500 0032 69ae 0000 ff2f ee98 c0a8 7103 +c0a8 7101 3001 880b 0012 4000 0000 0003 +8021 0101 0010 0306 c0a8 0001 0206 002d +0f01 + +# 23:18:36.570395 192.168.113.1.1511 > 192.168.113.3.1723: P 349:373(24) ack 189 win 64052: pptp CTRL_MSGTYPE=SLI PEER_CALL_ID(0) SEND_ACCM(0x00000000) RECV_ACCM(0xffffffff) (DF) +[out,pcn1] +4500 0040 5e18 4000 8006 5ef0 0a02 0202 +c0a8 7103 05e7 06bb abf0 4c02 a564 6997 +5018 fa34 0d9f 0000 0018 0001 1a2b 3c4d +000f 0000 0000 0000 0000 0000 ffff ffff + +# 23:18:36.573307 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:3 A:3 ppp: LCP 20: Ident(2), Magic-Num=577f7c5b +[out,pcn1] +4500 0038 5e19 0000 802f 9ece 0a02 0202 +c0a8 7103 3081 880b 0014 0000 0000 0003 +0000 0003 c021 0c02 0012 577f 7c5b 4d53 +5241 5356 352e 3130 + +# 23:18:36.573856 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:4 A:3 ppp: LCP 26: Code-Rej(2) +[in,pcn1] +4500 003e 69af 0000 ff2f ee8b c0a8 7103 +c0a8 7101 3081 880b 001a 4000 0000 0004 +0000 0003 ff03 c021 0702 0016 0c02 0012 +577f 7c5b 4d53 5241 5356 352e 3130 + +# 23:18:36.584936 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:4 A:4 ppp: LCP 26: Ident(3), Magic-Num=577f7c5b +[out,pcn1] +4500 003e 5e1a 0000 802f 9ec7 0a02 0202 +c0a8 7103 3081 880b 001a 0000 0000 0004 +0000 0004 c021 0c03 0018 577f 7c5b 4d53 +5241 532d 302d 434c 4159 4d4f 4f52 + +# 23:18:36.585562 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:5 A:4 ppp: LCP 32: Code-Rej(3) +[in,pcn1] +4500 0044 69b0 0000 ff2f ee84 c0a8 7103 +c0a8 7101 3081 880b 0020 4000 0000 0005 +0000 0004 ff03 c021 0703 001c 0c03 0018 +577f 7c5b 4d53 5241 532d 302d 434c 4159 +4d4f 4f52 + +# 23:18:36.588721 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:5 A:5 ppp: CCP 12: Conf-Req(4), MPPC +[out,pcn1] +4500 0030 5e1b 0000 802f 9ed4 0a02 0202 +c0a8 7103 3081 880b 000c 0000 0000 0005 +0000 0005 80fd 0104 000a 1206 0100 0001 + +# 23:18:36.589445 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:6 A:5 ppp: CCP 6: Conf-Req(1) +[in,pcn1] +4500 002a 69b1 0000 ff2f ee9d c0a8 7103 +c0a8 7101 3081 880b 0006 4000 0000 0006 +0000 0005 80fd 0101 0004 + +# 23:18:36.589540 192.168.113.3 > 192.168.113.1: gre [KSv1] ID:4000 S:7 ppp: CCP 12: Conf-Rej(4), MPPC +[in,pcn1] +4500 002c 69b2 0000 ff2f ee9a c0a8 7103 +c0a8 7101 3001 880b 000c 4000 0000 0007 +80fd 0404 000a 1206 0100 0001 + +# 23:18:36.590023 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:6 A:7 ppp: IPCP 36: Conf-Req(5), IP-Addr=0.0.0.0, Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[out,pcn1] +4500 0048 5e1c 0000 802f 9ebb 0a02 0202 +c0a8 7103 3081 880b 0024 0000 0000 0006 +0000 0007 8021 0105 0022 0306 0000 0000 +8106 0000 0000 8206 0000 0000 8306 0000 +0000 8406 0000 0000 + +# 23:18:36.590489 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:8 A:6 ppp: IPCP 30: Conf-Rej(5), Pri-DNS=0.0.0.0, Pri-NBNS=0.0.0.0, Sec-DNS=0.0.0.0, Sec-NBNS=0.0.0.0 +[in,pcn1] +4500 0042 69b3 0000 ff2f ee83 c0a8 7103 +c0a8 7101 3081 880b 001e 4000 0000 0008 +0000 0006 8021 0405 001c 8106 0000 0000 +8206 0000 0000 8306 0000 0000 8406 0000 +0000 + +# 23:18:36.591003 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:7 A:8 ppp: IPCP 12: Conf-Rej(1), IP-Comp VJ-Comp +[out,pcn1] +4500 0030 5e1d 0000 802f 9ed2 0a02 0202 +c0a8 7103 3081 880b 000c 0000 0000 0007 +0000 0008 8021 0401 000a 0206 002d 0f01 + +# 23:18:36.593819 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:9 A:7 ppp: IPCP 12: Conf-Req(2), IP-Addr=192.168.0.1 +[in,pcn1] +4500 0030 69b4 0000 ff2f ee94 c0a8 7103 +c0a8 7101 3081 880b 000c 4000 0000 0009 +0000 0007 8021 0102 000a 0306 c0a8 0001 + +# 23:18:36.594840 192.168.113.1 > 192.168.113.3: gre [KSAv1] ID:0000 S:8 A:9 ppp: CCP 6: Conf-Ack(1) +[out,pcn1] +4500 002a 5e1e 0000 802f 9ed9 0a02 0202 +c0a8 7103 3081 880b 0006 0000 0000 0008 +0000 0009 80fd 0201 0004 0000 0000 + +# 23:18:36.595525 192.168.113.1 > 192.168.113.3: gre [KSv1] ID:0000 S:9 ppp: CCP 18: Term-Req(6) +[out,pcn1] +4500 0032 5e1f 0000 802f 9ed0 0a02 0202 +c0a8 7103 3001 880b 0012 0000 0000 0009 +80fd 0506 0010 577f 7c5b 003c cd74 0000 +02dc + +# 23:18:36.595937 192.168.113.3 > 192.168.113.1: gre [KSAv1] ID:4000 S:10 A:9 ppp: CCP 6: Term-Ack(6) +[in,pcn1] +4500 002a 69b5 0000 ff2f ee99 c0a8 7103 +c0a8 7101 3081 880b 0006 4000 0000 000a +0000 0009 80fd 0606 0004 + diff --git a/contrib/ipfilter/test/input/ni6 b/contrib/ipfilter/test/input/ni6 new file mode 100644 index 0000000..70e80c0 --- /dev/null +++ b/contrib/ipfilter/test/input/ni6 @@ -0,0 +1,54 @@ +[in,nf0] +4500 0054 cd8a 4000 ff11 20ba c0a8 0601 +c0a8 0602 8075 006f 0040 d36d 3e1d d249 +0000 0000 0000 0002 0001 86a0 0000 0002 +0000 0003 0000 0000 0000 0000 0000 0000 +0000 0000 0001 86a3 0000 0003 0000 0011 +0000 0000 + +[out,qfe0] +4500 0054 cd8a 4000 ff11 1fbb c0a8 0601 +c0a8 0701 8075 006f 0040 d26e 3e1d d249 +0000 0000 0000 0002 0001 86a0 0000 0002 +0000 0003 0000 0000 0000 0000 0000 0000 +0000 0000 0001 86a3 0000 0003 0000 0011 +0000 0000 + +[in,qfe0] +4500 0038 cd83 4000 ff11 1edd c0a8 0701 +c0a8 0702 006f 8075 0024 d704 3e1d d249 +0000 0001 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0801 + +[out,nf0] +4500 0038 cd83 4000 ff11 1fde c0a8 0701 +c0a8 0601 006f 8075 0024 d805 3e1d d249 +0000 0001 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0801 + +[in,nf0] +4500 0044 d5a6 4000 ff11 18ae c0a8 0601 +c0a8 0602 80df 0801 0030 04f0 3e10 1fb1 +0000 0000 0000 0002 0001 86a3 0000 0002 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +[out,qfe0] +4500 0044 d5a6 4000 ff11 17af c0a8 0601 +c0a8 0701 80df 0801 0030 03f1 3e10 1fb1 +0000 0000 0000 0002 0001 86a3 0000 0002 +0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 + +[in,qfe0] +4500 0034 0000 4000 fe11 ed64 c0a8 0701 +c0a8 0702 0801 80df 0020 89b7 3e10 1fb1 +0000 0001 0000 0000 0000 0000 0000 0000 +0000 0000 + +[out,nf0] +4500 0034 0000 4000 fe11 ee65 c0a8 0701 +c0a8 0601 0801 80df 0020 0000 3e10 1fb1 +0000 0001 0000 0000 0000 0000 0000 0000 +0000 0000 + diff --git a/contrib/ipfilter/test/input/ni7 b/contrib/ipfilter/test/input/ni7 index 954bb7b..30f247d 100644 --- a/contrib/ipfilter/test/input/ni7 +++ b/contrib/ipfilter/test/input/ni7 @@ -7,7 +7,7 @@ [out,df0] 4500 0038 809a 0000 ff01 2d1d 0303 0303 -0404 0404 0b00 0125 0000 0000 -4500 0028 4706 4000 0111 1eac 0404 0404 0606 0606 +0404 0404 0b00 0125 0000 0000 4500 0028 +4706 4000 0111 1eac 0404 0404 0606 0606 afc9 829e 0014 c15e diff --git a/contrib/ipfilter/test/input/ni9 b/contrib/ipfilter/test/input/ni9 new file mode 100644 index 0000000..788e603 --- /dev/null +++ b/contrib/ipfilter/test/input/ni9 @@ -0,0 +1,24 @@ +#v tos len id off ttl p sum src dst +# ICMP dest unreachable with 64 bits in payload (in reply to a TCP packet +# going out) +[in,df0] 45 00 00 3c 47 06 40 00 ff 06 20 aa 04 04 04 04 0a 02 02 02 50 00 05 00 00 00 00 01 00 00 00 00 a0 02 16 d0 cc 32 00 00 02 04 05 b4 04 02 08 0a 00 47 fb b0 00 00 00 00 01 03 03 00 + +[out,df0] +4500 0038 809a 0000 ff01 2d1d 0303 0303 0404 0404 +0303 0fa3 0000 0000 +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 +5000 9d58 0000 0001 + +# ICMP dest unreachable with whole packet in payload (40 bytes = 320 bits) +[out,df0] +4500 0058 809a 0000 ff01 2cfd 0303 0303 0404 0404 +0303 0735 0000 0000 +4500 003c 4706 4000 ff06 2aac 0404 0404 0101 0101 +5000 9d58 0000 0001 0000 0000 a002 16d0 3ddc 0000 +0204 05b4 0402 080a 0047 fbb0 0000 0000 0103 0300 + +[out,df0] +4500 0038 809a 0000 ff01 2b1b 0303 0303 0505 0505 +0303 0fa3 0000 0000 +4500 003c 4706 4000 ff06 2aab 0404 0404 0101 0102 5000 9d58 0000 0001 + diff --git a/contrib/ipfilter/test/input/p1 b/contrib/ipfilter/test/input/p1 new file mode 100644 index 0000000..f6753fa --- /dev/null +++ b/contrib/ipfilter/test/input/p1 @@ -0,0 +1,8 @@ +in 127.0.0.1 127.0.0.1 +in 1.1.1.1 1.2.1.1 +out 127.0.0.1 127.0.0.1 +out 1.1.1.1 1.2.1.1 +in 2.3.0.1 1.2.1.1 +in 2.2.2.1 1.2.1.1 +in 2.2.0.1 1.2.1.1 +out 4.4.1.1 1.2.1.1 diff --git a/contrib/ipfilter/test/input/p2 b/contrib/ipfilter/test/input/p2 new file mode 100644 index 0000000..f6753fa --- /dev/null +++ b/contrib/ipfilter/test/input/p2 @@ -0,0 +1,8 @@ +in 127.0.0.1 127.0.0.1 +in 1.1.1.1 1.2.1.1 +out 127.0.0.1 127.0.0.1 +out 1.1.1.1 1.2.1.1 +in 2.3.0.1 1.2.1.1 +in 2.2.2.1 1.2.1.1 +in 2.2.0.1 1.2.1.1 +out 4.4.1.1 1.2.1.1 diff --git a/contrib/ipfilter/test/input/p3 b/contrib/ipfilter/test/input/p3 new file mode 100644 index 0000000..4a6666b --- /dev/null +++ b/contrib/ipfilter/test/input/p3 @@ -0,0 +1,12 @@ +in 1.1.1.1 1.2.1.1 +in 1.2.1.1 1.1.1.1 +out 1.1.1.1 1.2.1.1 +out 1.2.1.1 1.1.1.1 +in 2.2.2.2 2.1.2.1 +out 2.1.2.1 2.2.2.2 +in 3.3.1.1 3.1.3.1 +out 3.1.3.1 3.3.1.1 +in 4.4.1.1 4.1.4.1 +out 4.1.4.1 4.4.1.1 +in 5.5.1.1 5.1.5.1 +out 5.1.5.1 5.5.1.1 diff --git a/contrib/ipfilter/test/intest b/contrib/ipfilter/test/intest index 98241fc..e94ca08 100755 --- a/contrib/ipfilter/test/intest +++ b/contrib/ipfilter/test/intest @@ -1,4 +1,5 @@ #!/bin/sh +mkdir -p results if [ -f /usr/ucb/touch ] ; then TOUCH=/usr/ucb/touch else @@ -12,7 +13,7 @@ else fi echo "$1..."; /bin/cp /dev/null results/$1 -../ipnat -nvf regress/$1 2>/dev/null > results/$1 +../ipnat -Rnvf regress/$1 2>/dev/null > results/$1 cmp expected/$1 results/$1 status=$? if [ $status = 0 ] ; then diff --git a/contrib/ipfilter/test/iptest b/contrib/ipfilter/test/iptest new file mode 100644 index 0000000..bb3ab5e --- /dev/null +++ b/contrib/ipfilter/test/iptest @@ -0,0 +1,22 @@ +#!/bin/sh +mkdir -p results +if [ -f /usr/ucb/touch ] ; then + TOUCH=/usr/ucb/touch +else + if [ -f /usr/bin/touch ] ; then + TOUCH=/usr/bin/touch + else + if [ -f /bin/touch ] ; then + TOUCH=/bin/touch + fi + fi +fi +echo "$1..."; +/bin/cp /dev/null results/$1 +../ippool -f regress/$1 -nRv 2>/dev/null > results/$1 +cmp expected/$1 results/$1 +status=$? +if [ $status = 0 ] ; then + $TOUCH $1 +fi +exit $status diff --git a/contrib/ipfilter/test/itest b/contrib/ipfilter/test/itest index c1b5f57..333afde 100644 --- a/contrib/ipfilter/test/itest +++ b/contrib/ipfilter/test/itest @@ -1,4 +1,5 @@ #!/bin/sh +mkdir -p results if [ -f /usr/ucb/touch ] ; then TOUCH=/usr/ucb/touch else @@ -12,7 +13,7 @@ else fi echo "$1..."; /bin/cp /dev/null results/$1 -../ipf -nvf regress/$1 2>/dev/null > results/$1 +../ipf -Rnvf regress/$1 2>/dev/null > results/$1 cmp expected/$1 results/$1 status=$? if [ $status = 0 ] ; then diff --git a/contrib/ipfilter/test/logtest b/contrib/ipfilter/test/logtest index 38d93ee..089f915 100755 --- a/contrib/ipfilter/test/logtest +++ b/contrib/ipfilter/test/logtest @@ -1,4 +1,6 @@ #!/bin/sh +format=$2 +mkdir -p results if [ -f /usr/ucb/touch ] ; then TOUCH=/usr/ucb/touch else @@ -12,25 +14,34 @@ else fi echo "$1..."; +case `uname -s` in +OSF1) + GMT=: + ;; +*) + GMT=GMT + ;; +esac + /bin/cp /dev/null results/$1 /bin/cp /dev/null results/$1.b ( while read rule; do echo $rule >> results/$1 - echo $rule | ../ipftest -br - -Hi input/$1 -l logout > /dev/null + echo $rule | ../ipftest -br - -F $format -i input/$1 -l logout > /dev/null if [ $? -ne 0 ] ; then /bin/rm -f logout exit 1 fi - TZ=GMT ../ipmon -P /dev/null -f logout >> results/$1 + TZ=$GMT ../ipmon -P /dev/null -f logout >> results/$1 echo "--------" >> results/$1 - TZ=GMT ../ipmon -P /dev/null -bf logout >> results/$1.b + TZ=$GMT ../ipmon -P /dev/null -bf logout >> results/$1.b echo "--------" >> results/$1.b done ) < regress/$1 -../ipftest -br regress/$1 -Hi input/$1 -l logout > /dev/null -TZ=GMT ../ipmon -P /dev/null -f logout >> results/$1 +../ipftest -br regress/$1 -F $format -i input/$1 -l logout > /dev/null +TZ=$GMT ../ipmon -P /dev/null -f logout >> results/$1 echo "--------" >> results/$1 -TZ=GMT ../ipmon -P /dev/null -bf logout >> results/$1.b +TZ=$GMT ../ipmon -P /dev/null -bf logout >> results/$1.b echo "--------" >> results/$1.b cmp expected/$1 results/$1 diff --git a/contrib/ipfilter/test/mhtest b/contrib/ipfilter/test/mhtest index 52a0027..a4d48d6 100755 --- a/contrib/ipfilter/test/mhtest +++ b/contrib/ipfilter/test/mhtest @@ -16,7 +16,7 @@ echo "$1..."; /bin/cp /dev/null results/$1 -../ipftest -br regress/$1 -Hi input/$1 > results/$1 +../ipftest -br regress/$1 -F hex -i input/$1 > results/$1 if [ $? -ne 0 ] ; then exit 1 fi diff --git a/contrib/ipfilter/test/mtest b/contrib/ipfilter/test/mtest index b185abb..2a3ed38 100755 --- a/contrib/ipfilter/test/mtest +++ b/contrib/ipfilter/test/mtest @@ -1,4 +1,6 @@ #!/bin/sh +format=$2 +mkdir -p results # multiple rules at the same time if [ -f /usr/ucb/touch ] ; then @@ -16,7 +18,7 @@ echo "$1..."; /bin/cp /dev/null results/$1 -../ipftest -br regress/$1 -i input/$1 > results/$1 +../ipftest -F $format -Rbr regress/$1 -i input/$1 > results/$1 if [ $? -ne 0 ] ; then exit 1 fi diff --git a/contrib/ipfilter/test/natipftest b/contrib/ipfilter/test/natipftest index 8627168..f5cfdb8 100755 --- a/contrib/ipfilter/test/natipftest +++ b/contrib/ipfilter/test/natipftest @@ -1,4 +1,15 @@ #!/bin/sh +mode=$1 +shift +if [ $3 = hex ] ; then + format="-xF $2" +else + format="-F $2" +fi +if [ "$4" != "" ] ; then + format="-T $4 $format" +fi +mkdir -p results if [ -f /usr/ucb/touch ] ; then TOUCH=/usr/ucb/touch else @@ -10,19 +21,39 @@ else fi fi fi -echo "$1..."; -/bin/cp /dev/null results/$1 -( while read rule; do - echo "$rule" | ../ipftest -bHx -r regress/$1.ipf -Nr - -i input/$1 >> \ - results/$1; + +case $mode in +single) + echo "$1..."; + /bin/cp /dev/null results/$1 + ( while read rule; do + echo "$rule" | ../ipftest -R $format -bx -r regress/$1.ipf -N - -i input/$1 >> \ + results/$1; + if [ $? -ne 0 ] ; then + exit 1; + fi + echo "-------------------------------" >> results/$1 + done ) < regress/$1.nat + cmp expected/$1 results/$1 + status=$? + if [ $status = 0 ] ; then + $TOUCH $1 + fi + ;; +multi) + echo "$1..."; + /bin/cp /dev/null results/$1 + ../ipftest -R $format -bx -r regress/$1.ipf -N regress/$1.nat \ + -i input/$1 >> results/$1; if [ $? -ne 0 ] ; then - exit 1; + exit 2; fi echo "-------------------------------" >> results/$1 -done ) < regress/$1.nat -cmp expected/$1 results/$1 -status=$? -if [ $status = 0 ] ; then - $TOUCH $1 -fi + cmp expected/$1 results/$1 + status=$? + if [ $status = 0 ] ; then + $TOUCH $1 + fi + ;; +esac exit $status diff --git a/contrib/ipfilter/test/nattest b/contrib/ipfilter/test/nattest index 2b3e931..78b757e 100755 --- a/contrib/ipfilter/test/nattest +++ b/contrib/ipfilter/test/nattest @@ -1,4 +1,12 @@ #!/bin/sh +if [ $3 = hex ] ; then + format="-xF $2" +else + format="-F $2" +fi +if [ "$4" != "" ] ; then + format="-T $4 $format" +fi if [ -f /usr/ucb/touch ] ; then TOUCH=/usr/ucb/touch else @@ -13,7 +21,7 @@ fi echo "$1..."; /bin/cp /dev/null results/$1 ( while read rule; do - echo "$rule" | ../ipftest -Nbr - -i input/$1 >> results/$1; + echo "$rule" | ../ipftest $format -RbN - -i input/$1 >> results/$1; if [ $? -ne 0 ] ; then exit 1; fi diff --git a/contrib/ipfilter/test/ptest b/contrib/ipfilter/test/ptest new file mode 100644 index 0000000..7deccd3 --- /dev/null +++ b/contrib/ipfilter/test/ptest @@ -0,0 +1,31 @@ +#!/bin/sh +mkdir -p results +if [ -f /usr/ucb/touch ] ; then + TOUCH=/usr/ucb/touch +else + if [ -f /usr/bin/touch ] ; then + TOUCH=/usr/bin/touch + else + if [ -f /bin/touch ] ; then + TOUCH=/bin/touch + fi + fi +fi +echo "$1..."; +/bin/cp /dev/null results/$1 +if [ -f regress/$1.pool ] ; then + ../ipftest -RD -b -P regress/$1.pool -r regress/$1.ipf -i input/$1 >> \ + results/$1 +else + ../ipftest -RD -b -r regress/$1.ipf -i input/$1 >> results/$1 +fi +if [ $? -ne 0 ] ; then + exit 1; +fi +echo "-------------------------------" >> results/$1 +cmp expected/$1 results/$1 +status=$? +if [ $status = 0 ] ; then + $TOUCH $1 +fi +exit $status diff --git a/contrib/ipfilter/test/regress/bpf-f1 b/contrib/ipfilter/test/regress/bpf-f1 new file mode 100644 index 0000000..2c80283 --- /dev/null +++ b/contrib/ipfilter/test/regress/bpf-f1 @@ -0,0 +1,4 @@ +pass in bpf-v4 { "0x20 0 0 0xc 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass out bpf-v4 { "0x20 0 0 0xc 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass in bpf-v4 { "0x20 0 0 0x10 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass out bpf-v4 { "0x20 0 0 0x10 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } diff --git a/contrib/ipfilter/test/regress/bpf1 b/contrib/ipfilter/test/regress/bpf1 new file mode 100644 index 0000000..2c80283 --- /dev/null +++ b/contrib/ipfilter/test/regress/bpf1 @@ -0,0 +1,4 @@ +pass in bpf-v4 { "0x20 0 0 0xc 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass out bpf-v4 { "0x20 0 0 0xc 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass in bpf-v4 { "0x20 0 0 0x10 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } +pass out bpf-v4 { "0x20 0 0 0x10 0x15 0 0x1 0x1010101 0x6 0 0 0x60 0x6 0 0 0" } diff --git a/contrib/ipfilter/test/regress/i1 b/contrib/ipfilter/test/regress/i1 index 736801e..df60d2b 100644 --- a/contrib/ipfilter/test/regress/i1 +++ b/contrib/ipfilter/test/regress/i1 @@ -1,5 +1,6 @@ pass in all -block out all +block out \ +all log in all log body in all count in from any to any @@ -11,3 +12,5 @@ pass in log body quick from any to any block return-rst in quick on le0 proto tcp from any to any block return-icmp in on qe0 from any to any block return-icmp(1) in on qe0 from any to any +block return-icmp-as-dest(port-unr) in on qe0 from any to any +pass out on longNICname0 from test.host.dots to test\.host.dots diff --git a/contrib/ipfilter/test/regress/i11 b/contrib/ipfilter/test/regress/i11 index 68e9283..2999a85 100644 --- a/contrib/ipfilter/test/regress/i11 +++ b/contrib/ipfilter/test/regress/i11 @@ -1,5 +1,8 @@ pass in on ed0 proto tcp from localhost to localhost port = telnet keep state block in log first on lo0 proto tcp/udp from any to any keep state -pass in proto udp from localhost to localhost port = 2049 keep frags +pass in proto udp from localhost to localhost port = 20499 keep frag pass in proto udp from localhost to localhost port = 53 keep state keep frags -pass in proto tcp from any port gt 1024 to localhost port eq 25 keep state +pass in on ed0 out-via vx0 proto udp from any to any keep state +pass out on ppp0 in-via le0 proto tcp from any to any keep state +pass in proto tcp from any port gt 1024 to localhost port eq 1024 keep state +pass in proto tcp all flags S keep state(strict,newisn,no-icmp-err,limit 101) diff --git a/contrib/ipfilter/test/regress/i12 b/contrib/ipfilter/test/regress/i12 index d923f08..b8b2f3e 100644 --- a/contrib/ipfilter/test/regress/i12 +++ b/contrib/ipfilter/test/regress/i12 @@ -1,4 +1,9 @@ -block in on eri0 all head 1 -pass in on eri0 proto icmp all group 1 -pass out on ed0 all head 1000000 -block out on ed0 proto udp all group 1000000 +pass in from 1.1.1.1/32 to 2.2.2.2/32 +pass in from (2.2.2.2/24,3.3.3.3/32) to 4.4.4.4/32 +pass in from (2.2.2.2/24,3.3.3.3/32) to (5.5.5.5/32,6.6.6.6/32) +pass in from (2.2.2.2/24,3.3.3.3/32) to (5.5.5.5/32,6.6.6.6/32) port = (22,25) +pass in proto tcp from (2.2.2.2/24,3.3.3.3/32) to (5.5.5.5/32,6.6.6.6/32) port = (53,9) +pass in proto udp from (2.2.2.2/24,3.3.3.3/32) to (5.5.5.5/32,6.6.6.6/32) port = (53,9) +pass in from 10.10.10.10 to 11.11.11.11 +pass in from pool/101 to hash/202 +pass in from hash/303 to pool/404 diff --git a/contrib/ipfilter/test/regress/i13 b/contrib/ipfilter/test/regress/i13 new file mode 100644 index 0000000..3ba343d --- /dev/null +++ b/contrib/ipfilter/test/regress/i13 @@ -0,0 +1,8 @@ +a=any; +b="from $a"; +c='to $a'; +d=block; +e="pass in"; +$d in $b $c +f=" $b $c"; +$e${f} diff --git a/contrib/ipfilter/test/regress/i14 b/contrib/ipfilter/test/regress/i14 new file mode 100644 index 0000000..3c9d7b8 --- /dev/null +++ b/contrib/ipfilter/test/regress/i14 @@ -0,0 +1,8 @@ +block in on eri0 all head 1 +pass in on eri0 proto icmp all group 1 +pass out on ed0 all head 1000000 +block out on ed0 proto udp all group 1000000 +block in on vm0 proto tcp/udp all head 101 +pass in from 1.1.1.1 to 2.2.2.2 group 101 +pass in proto tcp from 1.0.0.1 to 2.0.0.2 group 101 +pass in proto udp from 2.0.0.2 to 3.0.0.3 group 101 diff --git a/contrib/ipfilter/test/regress/i15 b/contrib/ipfilter/test/regress/i15 new file mode 100644 index 0000000..5268ec35 --- /dev/null +++ b/contrib/ipfilter/test/regress/i15 @@ -0,0 +1,5 @@ +pass out on fxp0 all set-tag(log=100) +pass out on fxp0 all set-tag(nat=foo) +pass out on fxp0 all set-tag(log=100, nat=200) +pass out on fxp0 all set-tag(log=2147483648, nat=overtherainbowisapotof) + diff --git a/contrib/ipfilter/test/regress/i2 b/contrib/ipfilter/test/regress/i2 index 101deaa..a3b9cd8 100644 --- a/contrib/ipfilter/test/regress/i2 +++ b/contrib/ipfilter/test/regress/i2 @@ -1,6 +1,7 @@ log in proto tcp all pass in proto 6 from any to any pass in proto udp from localhost to localhost +block in proto ipv6 from any to any block in proto 17 from any to any block in proto 250 from any to any pass in proto tcp/udp from any to any diff --git a/contrib/ipfilter/test/regress/i3 b/contrib/ipfilter/test/regress/i3 index 15e98bf..0d82e8a 100644 --- a/contrib/ipfilter/test/regress/i3 +++ b/contrib/ipfilter/test/regress/i3 @@ -1,5 +1,7 @@ log in all -pass in from 128.0.0.1/24 to 128.0.0.1/16 +pass in from 128.16/16 to 129.10.10/24 +pass in from 128.0.0.1/24 to 128\ +.0.0.1/16 pass in from 128.0.0.1/0xffffff00 to 128.0.0.1/0xffff0000 pass in from 128.0.0.1/255.255.255.0 to 128.0.0.1/255.255.0.0 pass in from 128.0.0.1 mask 0xffffff00 to 128.0.0.1 mask 0xffff0000 diff --git a/contrib/ipfilter/test/regress/i4 b/contrib/ipfilter/test/regress/i4 index 1095ed9..7170dc2 100644 --- a/contrib/ipfilter/test/regress/i4 +++ b/contrib/ipfilter/test/regress/i4 @@ -2,6 +2,7 @@ log in proto tcp from any port > 0 to any log in proto tcp from any to any port > 0 pass in proto 6 from any port != 0 to any port 0 >< 65535 pass in proto 17 from localhost port > 32000 to localhost port < 29000 -block in proto udp from any port != ntp to any port < ntp +block in proto udp from any port != \ntp to any port < echo block in proto tcp from any port = smtp to any port > 25 pass in proto tcp/udp from any port 1 >< 3 to any port 1 <> 3 +pass in log first quick proto tcp from any port > 1023 to any port = 1723 flags S keep state diff --git a/contrib/ipfilter/test/regress/i6 b/contrib/ipfilter/test/regress/i6 index a35633b..1a53089 100644 --- a/contrib/ipfilter/test/regress/i6 +++ b/contrib/ipfilter/test/regress/i6 @@ -1,4 +1,10 @@ pass in on lo0 fastroute from any to any +pass in on lo0 to qe0 from localhost to localhost +pass in on le0 to qe0:127.0.0.1 from localhost to localhost pass in on lo0 dup-to qe0 from localhost to localhost -pass in on qe0 dup-to qe0:127.0.0.1 from localhost to localhost +pass in on le0 dup-to qe0:127.0.0.1 from localhost to localhost +pass in on le0 to hme0:10.1.1.1 dup-to qe0:127.0.0.1 from localhost to localhost block in quick on qe0 to qe1 from any to any +block in quick to qe1 from any to any +pass out quick dup-to hme0 from any to any +pass in quick fastroute all diff --git a/contrib/ipfilter/test/regress/i9 b/contrib/ipfilter/test/regress/i9 index 327cff4..2b8fb10 100644 --- a/contrib/ipfilter/test/regress/i9 +++ b/contrib/ipfilter/test/regress/i9 @@ -1,5 +1,7 @@ -pass in from localhost to localhost with short +pass in from localhost to localhost with short,frags block in from any to any with ipopts pass in from any to any with opt nop,rr,zsu pass in from any to any with opt nop,rr,zsu not opt ssrr,lsrr pass in from localhost to localhost with not frag +pass in proto tcp all flags S with not oow keep state +pass in proto tcp all flags S with not bad,bad-src,bad-nat diff --git a/contrib/ipfilter/test/regress/in1 b/contrib/ipfilter/test/regress/in1 index 59c5754..145e3d0 100644 --- a/contrib/ipfilter/test/regress/in1 +++ b/contrib/ipfilter/test/regress/in1 @@ -23,3 +23,5 @@ map le0 0/0 -> 0/32 frag age 10 map le0 192.168.0.0/16 -> range 203.1.1.23-203.1.3.45 frag age 10/20 map ppp0 192.168.0.0/16 -> 0/32 portmap tcp 10000:19999 frag age 30 map fxp0 from 192.168.0.0/18 to 0/0 port = 21 -> 1.2.3.4/32 proxy port 21 ftp/tcp +map thisisalonginte 0/0 -> 0/32 mssclamp 1452 tag freddyliveshere +map bar0 0/0 -> 0/32 icmpidmap icmp 1000:2000 diff --git a/contrib/ipfilter/test/regress/in2 b/contrib/ipfilter/test/regress/in2 index 33151f0..222a28c 100644 --- a/contrib/ipfilter/test/regress/in2 +++ b/contrib/ipfilter/test/regress/in2 @@ -1,22 +1,67 @@ -rdr le0 0/0 port 0 -> 1.1.1.1 port 0 -rdr le0 0/0 port 0 -> 1.1.1.1 port 0 ip -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 ip -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 tcp -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 udp -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 tcp/udp -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 icmp -rdr le0 0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 tcp round-robin -rdr le0 0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin -rdr le0 0/0 port 0 -> 1.1.1.1 port 0 ip frag -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 icmp frag -rdr le0 0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 tcp round-robin frag -rdr le0 0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag -rdr le0 0/0 port 0 -> 1.1.1.1 port 0 ip frag age 10 -rdr le0 0/0 port 0 -> 1.1.1.1 port 0 ip frag age 10/20 -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 icmp frag age 10 -rdr le0 0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20 -rdr le0 0/0 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30 -rdr le0 0/0 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 tcp +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 udp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp/udp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag +rdr le0 9.8.7.6/32 -> 1.1.1.1 ip frag age 10 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag age 10/20 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag age 10 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip sticky +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag sticky +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag age 10 sticky +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag age 10/20 sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag age 10 sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20 sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30 sticky +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40 sticky +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip mssclamp 1000 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag age 10 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag age 10/20 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag age 10 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40 sticky mssclamp 1000 +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip tag nattagcacheline +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag age 10 sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 0 -> 1.1.1.1 port 0 ip frag age 10/20 sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 icmp frag age 10 sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp frag age 20 sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1 port 80 tcp round-robin frag age 30 sticky mssclamp 1000 tag nattagcacheline +rdr le0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp round-robin frag age 40 sticky mssclamp 1000 tag nattagcacheline +rdr ge0 9.8.7.6/32 -> 1.1.1.1 proxy port 21 ftp/tcp +rdr ge0 9.8.7.6/32 port 21 -> 1.1.1.1 port 21 tcp proxy ftp +rdr le0 9.8.7.6/32 port 1000-2000 -> 1.1.1.1 port 5555 tcp +rdr le0 9.8.7.6/32 port 1000-2000 -> 1.1.1.1 port = 5555 tcp +rdr le0 0/0 -> test.host.dots +rdr le0 0/0 -> test.host.dots,test.host.dots diff --git a/contrib/ipfilter/test/regress/in5 b/contrib/ipfilter/test/regress/in5 new file mode 100644 index 0000000..d0a115c --- /dev/null +++ b/contrib/ipfilter/test/regress/in5 @@ -0,0 +1,22 @@ +rdr le0 from any to 9.8.7.6/32 port = 0 -> 1.1.1.1 port 0 tcp +rdr le0 from any to 9.8.7.6/32 port = 0 -> 1.1.1.1 port 0 ip +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 ip +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 udp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp/udp +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 port 888 icmp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp round-robin +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp round-robin +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 port 0 ip frag +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 icmp frag +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp frag +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp round-robin frag +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp round-robin frag +rdr le0 from any to 9.8.7.6/32 -> 1.1.1.1 port 0 ip frag age 10 +rdr le0 from any to 9.8.7.6/32 port = 0 -> 1.1.1.1 port 0 ip frag age 10/20 +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 icmp frag age 10 +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp frag age 20 +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1 port 888 tcp round-robin frag age 30 +rdr le0 from any to 9.8.7.6/32 port = 8888 -> 1.1.1.1,1.1.1.2 port 888 tcp round-robin frag age 40 diff --git a/contrib/ipfilter/test/regress/in6 b/contrib/ipfilter/test/regress/in6 new file mode 100644 index 0000000..6948799 --- /dev/null +++ b/contrib/ipfilter/test/regress/in6 @@ -0,0 +1,3 @@ +map foo0 from any port = 1 to any port != 0 -> 0/32 udp +map foo0 from any port < 1 to any port > 0 -> 0/32 tcp +map foo0 from any port <= 1 to any port >= 0 -> 0/32 tcp/udp diff --git a/contrib/ipfilter/test/regress/ip1 b/contrib/ipfilter/test/regress/ip1 new file mode 100644 index 0000000..c31ba25 --- /dev/null +++ b/contrib/ipfilter/test/regress/ip1 @@ -0,0 +1,78 @@ +#:%s/ \(number = [0-9]*\) \(type = [a-z]*\)/ \2 \1/g + +table role = ipf type = tree number = 1 + {; }; +table role = ipf type = tree number = 100 + { 1.2.3.4/32; !2.2.0.0/16; 2.2.2.0/24; }; +table role = nat type = tree number = 110 + { 1.2.3.4/32; !2.2.0.0/16; 2.2.2.0/24; }; +table role = auth type = tree number = 120 + { 1.2.3.4/32; !2.2.0.0/16; 2.2.2.0/24; }; +table role = count type = tree number = 130 + { 1.2.3.4; !2.2.0.0/16; 2.2.2.0/24; }; + +table role = ipf type = hash number = 2 + {; }; +table role = ipf type = hash number = 200 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 210 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 220 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 230 + { 0/0; 4/32; 1.2.3.4/32; }; + +table role = ipf type = hash number = 240 seed = 101 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 250 seed = 101 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 260 seed = 101 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 270 seed = 101 + { 0/0; 4/32; 1.2.3.4/32; }; + +table role = ipf type = hash number = 2000 size = 1001 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 2000 size = 1001 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 2000 size = 1001 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 2000 size = 1001 + { 0/0; 4/32; 1.2.3.4/32; }; + +table role = ipf type = hash number = 100 size = 1001 seed = 101 + { 0/0; 1/32; 1.2.3.4/32; }; +table role = nat type = hash number = 100 size = 1001 seed = 101 + { 0/0; 2/32; 1.2.3.4/32; }; +table role = auth type = hash number = 100 size = 1001 seed = 101 + { 0/0; 3/32; 1.2.3.4/32; }; +table role = count type = hash number = 100 size = 1001 seed = 101 + { 0/0; 4/32; 1.2.3.4/32; }; + +group-map in role = ipf number = 300 group = 303 + { 0/0; 5/32; 1.2.3.4/32; }; +group-map in role = nat number = 300 group = 303 + { 0/0; 6/32; 1.2.3.4/32; }; +group-map in role = auth number = 300 group = 303 + { 0/0; 7/32; 1.2.3.4/32; }; +group-map in role = count number = 300 group = 303 + { 0/0; 8/32; 1.2.3.4/32; }; + +group-map out role = ipf number = 400 group = 303 + { 0/0; 5/32; 1.2.3.4/32, group = 606; }; +group-map out role = nat number = 400 group = 303 + { 0/0; 6/32; 1.2.3.4/32, group = 606; }; +group-map out role = auth number = 400 group = 303 + { 0/0; 7/32; 1.2.3.4/32, group = 606; }; +group-map out role = count number = 400 group = 303 + { 0/0; 8/32; 1.2.3.4/32, group = 606; }; + +group-map in role = ipf number = 500 + { 0/0, group = 10; 5/32, group = 800; 1.2.3.4/32, group = 606; }; +group-map in role = nat number = 500 + { 0/0, group = 10; 6/32, group = 800; 1.2.3.4/32, group = 606; }; +group-map in role = auth number = 500 + { 0/0, group = 10; 7/32, group = 800; 1.2.3.4/32, group = 606; }; +group-map in role = count number = 500 + { 0/0, group = 10; 8/32, group = 800; 1.2.3.4/32, group = 606; }; + diff --git a/contrib/ipfilter/test/regress/n10 b/contrib/ipfilter/test/regress/n10 new file mode 100644 index 0000000..0f48192 --- /dev/null +++ b/contrib/ipfilter/test/regress/n10 @@ -0,0 +1,3 @@ +map ppp0 0/0 -> 203.203.203.203/32 mssclamp 100 +map ppp0 0/0 -> 203.203.203.203/32 mssclamp 1000 +map ppp0 0/0 -> 203.203.203.203/32 mssclamp 10000 diff --git a/contrib/ipfilter/test/regress/n11 b/contrib/ipfilter/test/regress/n11 new file mode 100644 index 0000000..8cdf7fc --- /dev/null +++ b/contrib/ipfilter/test/regress/n11 @@ -0,0 +1,3 @@ +bimap zx0 10.1.1.1/32 -> 1.6.7.8/32 +bimap zx0 10.1.1.0/24 -> 10.2.2.2/32 +bimap zx0 10.1.1.0/24 -> 10.3.4.5/24 diff --git a/contrib/ipfilter/test/regress/n12 b/contrib/ipfilter/test/regress/n12 new file mode 100644 index 0000000..225675b --- /dev/null +++ b/contrib/ipfilter/test/regress/n12 @@ -0,0 +1 @@ +map le0 192.168.126.0/24 -> 0/32 portmap tcp/udp 10000:20000 diff --git a/contrib/ipfilter/test/regress/n4 b/contrib/ipfilter/test/regress/n4 index b066c7a..e7c0314 100644 --- a/contrib/ipfilter/test/regress/n4 +++ b/contrib/ipfilter/test/regress/n4 @@ -3,3 +3,4 @@ rdr zx0 10.1.1.0/24 port 23 -> 10.2.2.1 port 10023 tcp rdr zx0 0/0 port 23 -> 10.2.2.1 port 10023 tcp rdr zx0 10.1.1.0/24 port 53 -> 10.2.2.1 port 10053 udp rdr zx0 10.1.1.0/24 port 0 -> 10.2.2.1 port 0 tcp +rdr zx0 10.1.1.0/24 port 0 -> 10.2.2.1 port 0 ip diff --git a/contrib/ipfilter/test/regress/n7 b/contrib/ipfilter/test/regress/n7 index 4abde53..be995c2 100644 --- a/contrib/ipfilter/test/regress/n7 +++ b/contrib/ipfilter/test/regress/n7 @@ -1,2 +1,3 @@ rdr zx0 10.1.1.1/32 port 23-79 -> 10.2.2.1 port 10023 tcp +rdr zx0 10.1.1.1/32 port 23-79 -> 10.2.2.1 port = 10023 tcp rdr zx0 10.1.1.0/24 port 80 -> 10.2.2.1,1.2.2.129 port 3128 tcp diff --git a/contrib/ipfilter/test/regress/n8 b/contrib/ipfilter/test/regress/n8 new file mode 100644 index 0000000..bf0e94f --- /dev/null +++ b/contrib/ipfilter/test/regress/n8 @@ -0,0 +1 @@ +map icmp0 2.2.2.0/24 -> 10.10.10.0/24 diff --git a/contrib/ipfilter/test/regress/n9 b/contrib/ipfilter/test/regress/n9 new file mode 100644 index 0000000..81a7ccd --- /dev/null +++ b/contrib/ipfilter/test/regress/n9 @@ -0,0 +1 @@ +rdr icmp0 4.4.4.0/24 port 0 -> 10.10.10.1 port 0 ip diff --git a/contrib/ipfilter/test/regress/ni10.nat b/contrib/ipfilter/test/regress/ni10.nat index 5257818..2a04ef7 100644 --- a/contrib/ipfilter/test/regress/ni10.nat +++ b/contrib/ipfilter/test/regress/ni10.nat @@ -1 +1 @@ -rdr df0 2.2.2.2/32 port 0 -> 6.6.6.6 port 0 ip +rdr df0 2.2.2.2/32 -> 6.6.6.6 diff --git a/contrib/ipfilter/test/regress/ni11.nat b/contrib/ipfilter/test/regress/ni11.nat index 87e9673..1d0018c 100644 --- a/contrib/ipfilter/test/regress/ni11.nat +++ b/contrib/ipfilter/test/regress/ni11.nat @@ -1 +1 @@ -rdr df0 10.0.0.0/8 port 1000-2000 -> 1.1.1.1 port 40000 tcp/udp +rdr df0 10.0.0.0/8 port 1000:2000 -> 1.1.1.1 port 40000 tcp/udp diff --git a/contrib/ipfilter/test/regress/ni12.ipf b/contrib/ipfilter/test/regress/ni12.ipf new file mode 100644 index 0000000..4151b6e --- /dev/null +++ b/contrib/ipfilter/test/regress/ni12.ipf @@ -0,0 +1,4 @@ +block in all +block out all +pass in proto udp from any to any keep state +pass in proto tcp from any to any flags S keep state diff --git a/contrib/ipfilter/test/regress/ni12.nat b/contrib/ipfilter/test/regress/ni12.nat new file mode 100644 index 0000000..8c36bc8 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni12.nat @@ -0,0 +1 @@ +rdr df0 10.0.0.0/8 port 1000:2000 -> 1.1.1.1 port = 40000 tcp/udp diff --git a/contrib/ipfilter/test/regress/ni13.ipf b/contrib/ipfilter/test/regress/ni13.ipf new file mode 100644 index 0000000..04b6d13 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni13.ipf @@ -0,0 +1,3 @@ +pass in quick on pcn1 proto tcp from any to any port = 1723 keep state +block in all +block out all diff --git a/contrib/ipfilter/test/regress/ni13.nat b/contrib/ipfilter/test/regress/ni13.nat new file mode 100644 index 0000000..7a879d8 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni13.nat @@ -0,0 +1 @@ +rdr pcn1 192.168.113.3/32 port 1723 -> 0.0.0.0 port 1723 proxy pptp diff --git a/contrib/ipfilter/test/regress/ni14.ipf b/contrib/ipfilter/test/regress/ni14.ipf new file mode 100644 index 0000000..04b6d13 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni14.ipf @@ -0,0 +1,3 @@ +pass in quick on pcn1 proto tcp from any to any port = 1723 keep state +block in all +block out all diff --git a/contrib/ipfilter/test/regress/ni14.nat b/contrib/ipfilter/test/regress/ni14.nat new file mode 100644 index 0000000..c546e99 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni14.nat @@ -0,0 +1 @@ +rdr pcn1 192.168.113.3/32 port 1723 -> 127.0.0.1 port 1723 proxy pptp diff --git a/contrib/ipfilter/test/regress/ni15.ipf b/contrib/ipfilter/test/regress/ni15.ipf new file mode 100644 index 0000000..1b9a013 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni15.ipf @@ -0,0 +1,3 @@ +pass out quick on pcn1 proto tcp from any to any port = 1723 keep state +block in all +block out all diff --git a/contrib/ipfilter/test/regress/ni15.nat b/contrib/ipfilter/test/regress/ni15.nat new file mode 100644 index 0000000..420c7b7 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni15.nat @@ -0,0 +1 @@ +map pcn1 0/0 -> 0/0 proxy port 1723 pptp/tcp diff --git a/contrib/ipfilter/test/regress/ni16.ipf b/contrib/ipfilter/test/regress/ni16.ipf new file mode 100644 index 0000000..1b9a013 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni16.ipf @@ -0,0 +1,3 @@ +pass out quick on pcn1 proto tcp from any to any port = 1723 keep state +block in all +block out all diff --git a/contrib/ipfilter/test/regress/ni16.nat b/contrib/ipfilter/test/regress/ni16.nat new file mode 100644 index 0000000..5fad3cd --- /dev/null +++ b/contrib/ipfilter/test/regress/ni16.nat @@ -0,0 +1 @@ +map pcn1 10.2.2.2/32 -> 0/32 proxy port 1723 pptp/tcp diff --git a/contrib/ipfilter/test/regress/ni6.ipf b/contrib/ipfilter/test/regress/ni6.ipf new file mode 100644 index 0000000..f5b83b2 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni6.ipf @@ -0,0 +1,9 @@ +block out log quick on qfe0 from 192.168.7.0/24 to any +block out log quick on nf0 from 192.168.6.0/24 to any +pass in quick on nf0 proto tcp from any to any port = 111 flags S keep state +pass in quick on nf0 proto udp from any to any port = 111 keep state +block return-rst in log quick on nf0 proto tcp from any to any +block in log quick on nf0 from 192.168.7.0/24 to any +block return-rst in log quick on qfe0 proto tcp from any to any +block in log quick on qfe0 from 192.168.6.0/24 to any + diff --git a/contrib/ipfilter/test/regress/ni6.nat b/contrib/ipfilter/test/regress/ni6.nat new file mode 100644 index 0000000..00d57d0 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni6.nat @@ -0,0 +1,3 @@ +rdr nf0 192.168.6.2 port 111 -> 192.168.7.1 port 111 udp proxy rpcbu +rdr nf0 192.168.6.2 port 111 -> 192.168.7.1 port 111 tcp proxy rpcbt +map qfe0 192.168.6.0/24 -> 192.168.7.2/32 diff --git a/contrib/ipfilter/test/regress/ni7.nat b/contrib/ipfilter/test/regress/ni7.nat index 5257818..2a04ef7 100644 --- a/contrib/ipfilter/test/regress/ni7.nat +++ b/contrib/ipfilter/test/regress/ni7.nat @@ -1 +1 @@ -rdr df0 2.2.2.2/32 port 0 -> 6.6.6.6 port 0 ip +rdr df0 2.2.2.2/32 -> 6.6.6.6 diff --git a/contrib/ipfilter/test/regress/ni8.nat b/contrib/ipfilter/test/regress/ni8.nat index 87e9673..1d0018c 100644 --- a/contrib/ipfilter/test/regress/ni8.nat +++ b/contrib/ipfilter/test/regress/ni8.nat @@ -1 +1 @@ -rdr df0 10.0.0.0/8 port 1000-2000 -> 1.1.1.1 port 40000 tcp/udp +rdr df0 10.0.0.0/8 port 1000:2000 -> 1.1.1.1 port 40000 tcp/udp diff --git a/contrib/ipfilter/test/regress/ni9.ipf b/contrib/ipfilter/test/regress/ni9.ipf new file mode 100644 index 0000000..6666241 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni9.ipf @@ -0,0 +1 @@ +pass in quick proto tcp from any to any flags S/SAFR keep state diff --git a/contrib/ipfilter/test/regress/ni9.nat b/contrib/ipfilter/test/regress/ni9.nat new file mode 100644 index 0000000..8c36bc8 --- /dev/null +++ b/contrib/ipfilter/test/regress/ni9.nat @@ -0,0 +1 @@ +rdr df0 10.0.0.0/8 port 1000:2000 -> 1.1.1.1 port = 40000 tcp/udp diff --git a/contrib/ipfilter/test/regress/p1.ipf b/contrib/ipfilter/test/regress/p1.ipf new file mode 100644 index 0000000..acaf639 --- /dev/null +++ b/contrib/ipfilter/test/regress/p1.ipf @@ -0,0 +1 @@ +pass in from pool/100 to any diff --git a/contrib/ipfilter/test/regress/p1.pool b/contrib/ipfilter/test/regress/p1.pool new file mode 100644 index 0000000..14ae3a3 --- /dev/null +++ b/contrib/ipfilter/test/regress/p1.pool @@ -0,0 +1,2 @@ +table role = ipf type = tree number = 100 + { 1.1.1.1/32; !2.2.0.0/16; 2.2.2.0/24; }; diff --git a/contrib/ipfilter/test/regress/p2.ipf b/contrib/ipfilter/test/regress/p2.ipf new file mode 100644 index 0000000..5b58647 --- /dev/null +++ b/contrib/ipfilter/test/regress/p2.ipf @@ -0,0 +1 @@ +pass out from hash=(127.0.0.1,4.4.0.0/16) to any diff --git a/contrib/ipfilter/test/regress/p3.ipf b/contrib/ipfilter/test/regress/p3.ipf new file mode 100644 index 0000000..aad7cb3 --- /dev/null +++ b/contrib/ipfilter/test/regress/p3.ipf @@ -0,0 +1,6 @@ +call now fr_srcgrpmap/1010 in all +call now fr_dstgrpmap/2010 out all +pass in all group 1020 +block in all group 1030 +pass out all group 2020 +block out all group 2040 diff --git a/contrib/ipfilter/test/regress/p3.pool b/contrib/ipfilter/test/regress/p3.pool new file mode 100644 index 0000000..3fadd59 --- /dev/null +++ b/contrib/ipfilter/test/regress/p3.pool @@ -0,0 +1,4 @@ +group-map in role = ipf number = 1010 + { 1.1.1.1/32, group = 1020; 3.3.0.0/16, group = 1030; }; +group-map out role = ipf number = 2010 group = 2020 + { 2.2.2.2/32; 4.4.0.0/16; 5.0.0.0/8, group = 2040; }; diff --git a/contrib/ipfilter/test/test.format b/contrib/ipfilter/test/test.format new file mode 100644 index 0000000..090c8a9 --- /dev/null +++ b/contrib/ipfilter/test/test.format @@ -0,0 +1,77 @@ +#test input-format output-format +bpf-f1 text text +bpf1 text text +f1 text text +f2 text text +f3 text text +f4 text text +f5 text text +f6 text text +f7 text text +f8 text text +f9 text text +f10 text text +f11 text text +f12 hex hex +f13 hex hex +f14 text text +f15 text text +f16 text text +f17 hex hex +i1 text text +i2 text text +i3 text text +i4 text text +i5 text text +i6 text text +i7 text text +i8 text text +i9 text text +i10 text text +i11 text text +i12 text text +i13 text text +i14 text text +i15 text text +in1 text text +in2 text text +in3 text text +in4 text text +in5 text text +in6 text text +ip1 text text +ipv6.1 hex hex +ipv6.2 hex hex +ipv6.3 hex hex +l1 hex hex +n1 text text +n2 text text +n3 text text +n4 text text +n5 text text +n6 text text +n7 text text +n8 hex hex fr_update_ipid=0 +n9 hex hex fr_update_ipid=0 +n10 hex hex fr_update_ipid=0 +n11 text text +n12 hex hex fr_update_ipid=0 +ni1 hex hex fr_update_ipid=1 +ni2 hex hex fr_update_ipid=1 +ni3 hex hex fr_update_ipid=1 +ni4 hex hex fr_update_ipid=1 +ni5 hex hex fr_update_ipid=1 +ni6 hex hex fr_update_ipid=1 +ni7 hex hex fr_update_ipid=1 +ni8 hex hex fr_update_ipid=1 +ni9 hex hex fr_update_ipid=1 +ni10 hex hex fr_update_ipid=1 +ni11 hex hex fr_update_ipid=1 +ni12 hex hex fr_update_ipid=1 +ni13 hex hex fr_update_ipid=1 +ni14 hex hex fr_update_ipid=1 +ni15 hex hex fr_update_ipid=1 +ni16 hex hex fr_update_ipid=1 +p1 text text +p2 text text +p3 text text diff --git a/contrib/ipfilter/test/vfycksum.pl b/contrib/ipfilter/test/vfycksum.pl index b6a2076..9cb47f6 100755 --- a/contrib/ipfilter/test/vfycksum.pl +++ b/contrib/ipfilter/test/vfycksum.pl @@ -62,7 +62,7 @@ sub tcpcheck { local($base) = $_[0]; local($hl) = $bytes[$base] / 256; return if (($hl >> 4) != 4); - return if ($bytes[3] & 0x1fff); + return if ($bytes[$base + 3] & 0x1fff); $hl &= 0xf; $hl <<= 1; @@ -79,10 +79,27 @@ sub tcpcheck { local($thl) = $bytes[$base + $hl + 6] >> 8; $thl &= 0xf0; $thl >>= 2; - if (($bytes[$base + 1] > ($cnt - $base) * 2) || - (($cnt - $base) * 2 < $hl + 20) || - (($cnt - $base) * 2 < $hl + $thl)) { - print " TCP: missing data"; + + $x = $bytes[$base + 1]; + $y = ($cnt - $base) * 2; + $z = 0; + if ($bytes[$base + 1] > ($cnt - $base) * 2) { + print "[cnt=$cnt base=$base]"; + $x = $bytes[$base + 1]; + $y = ($cnt - $base) * 2; + $z = 1; + } elsif (($cnt - $base) * 2 < $hl + 20) { + $x = ($cnt - $base) * 2; + $y = $hl + 20; + $z = 2; + } elsif (($cnt - $base) * 2 < $hl + $thl) { + $x = ($cnt - $base) * 2; + $y = $hl + $thl; + $z = 3; + } + + if ($z) { + print " TCP: missing data($x $y $z)"; return; } @@ -95,7 +112,7 @@ sub tcpcheck { $bytes[$tcpat + 8] = $osum; printf " TCP: (%x) %x != %x", $hs, $osum, $hs2; } else { - print " TCP: ok"; + print " TCP: ok ($x $y)"; } } @@ -161,8 +178,15 @@ sub icmpcheck { local($len) = $bytes[$base + 1] - ($hl << 1); - if ($len > $cnt * 2) { - print "missing icmp data\n"; + if ($bytes[$base + 1] > ($cnt - $base) * 2) { + print " ICMP: missing data(1)"; + return; + } elsif ($bytes[$base + 1] < ($hl << 1) + 8) { + print " ICMP: missing data(2)"; + return; + } elsif (($cnt - $base) * 2 < ($hl << 1) + 8) { + print " ICMP: missing data(3)"; + return; } local($osum) = $bytes[$base + $hl + 1]; @@ -240,6 +264,7 @@ $b=$_; $y = hex $x; s/[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F] *(.*)/$1/; $bytes[$cnt] = $y; +#print "bytes[$cnt] = $x\n"; $cnt++; } diff --git a/contrib/ipfilter/todo b/contrib/ipfilter/todo index 4c2adf1..5b2c059 100644 --- a/contrib/ipfilter/todo +++ b/contrib/ipfilter/todo @@ -7,9 +7,14 @@ fastroute works GENERAL: -------- +* support redirection like "rdr tun0 0/32 port 80 ..." + * use fr_tcpstate() with NAT code for increased NAT usage security or even fr_checkstate() - suspect this is not possible. +* add another alias for <thishost> for interfaces <thisif>? as well as + all IP#'s associated with the box <myaddrs>? + time permitting: * load balancing across interfaces @@ -17,21 +22,13 @@ time permitting: * record buffering for TCP/UDP * modular application proxying -available +-done * 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 +* port IP Filter to Linux +Not in this century. -* ipfsync() should change IP#'s in current mappings as well as what's - in rules. -done - * document bimap * document NAT rule order processing @@ -43,22 +40,23 @@ in progress 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!!! +maybe for solaris, otherwise "ALTQ" * 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. +- done 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?) +-sort of done * intrusion detection detection of port scans @@ -76,23 +74,25 @@ the userland ipnat?) 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. -fixed. Solaris: * "to <if>:<ip>" is not supported, but "fastroute" is and "to <if>" are. +Tru64: +------ +* IPv6 checksum calculation for RST's and ICMP packets is not done (there + are routines in the Tru64 kernel to do this but what is the interface?) + +does bimap allow equal sized subnets? + +make return-icmp 'intelligent' if no type is given about what type to use? + +reply-to - enforce packets to pass through interfaces in particular +combinations - opposite to "to", set reverse path interface + diff --git a/contrib/ipfilter/tools/BNF.ipf b/contrib/ipfilter/tools/BNF.ipf new file mode 100644 index 0000000..0e84332 --- /dev/null +++ b/contrib/ipfilter/tools/BNF.ipf @@ -0,0 +1,80 @@ +filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] + [ proto ] [ ip ] [ group ] [ tag ] [ pps ] . + +insert = "@" decnumber . +action = block | "pass" | log | "count" | auth | call . +in-out = "in" | "out" . +options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] . +tos = "tos" decnumber | "tos" hexnumber . +ttl = "ttl" decnumber . +proto = "proto" protocol . +ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . +group = [ "head" decnumber ] [ "group" decnumber ] . +pps = "pps" decnumber . + +onif = "on" interface-name [ "out-via" interface-name ] . +block = "block" [ return-icmp[return-code] | "return-rst" ] . +auth = "auth" | "preauth" . +log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . +tag = "tag" tagid . +call = "call" [ "now" ] function-name . +dup = "dup-to" interface-name[":"ipaddr] . +froute = "fastroute" | "to" interface-name . +protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . +srcdst = "all" | fromto . +fromto = "from" object "to" object . + +return-icmp = "return-icmp" | "return-icmp-as-dest" . +loglevel = facility"."priority | priority . +object = addr [ port-comp | port-range ] . +addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +port-comp = "port" compare port-num . +port-range = "port" port-num range port-num . +flags = "flags" flag { flag } [ "/" flag { flag } ] . +with = "with" | "and" . +icmp = "icmp-type" icmp-type [ "code" decnumber ] . +return-code = "("icmp-code")" . +keep = "keep" "state" [ "limit" number ] | "keep" "frags" . + +nummask = host-name [ "/" decnumber ] . +host-name = ipaddr | hostname | "any" . +ipaddr = host-num "." host-num "." host-num "." host-num . +host-num = digit [ digit [ digit ] ] . +port-num = service-name | decnumber . + +withopt = [ "not" | "no" ] opttype [ withopt ] . +opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" | + "mbcast" | "opt" ipopts . +optname = ipopts [ "," optname ] . +ipopts = optlist | "sec-class" [ secname ] . +secname = seclvl [ "," secname ] . +seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" | + "reserv-4" | "secret" | "topsecret" . +icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" | + "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" | + "inforep" | "maskreq" | "maskrep" | "routerad" | + "routersol" | decnumber . +icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" | + "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | + "net-prohib" | "host-prohib" | "net-tos" | "host-tos" | + "filter-prohib" | "host-preced" | "cutoff-preced" . +optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" | + "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" | + "visa" | "imitd" | "eip" | "finn" . +facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" | + "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" | + "audit" | "logalert" | "local0" | "local1" | "local2" | + "local3" | "local4" | "local5" | "local6" | "local7" . +priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" | + "info" | "debug" . + +hexnumber = "0" "x" hexstring . +hexstring = hexdigit [ hexstring ] . +decnumber = digit [ decnumber ] . + +compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | + "le" | "ge" . +range = "<>" | "><" . +hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . +flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" . diff --git a/contrib/ipfilter/tools/BNF.ipnat b/contrib/ipfilter/tools/BNF.ipnat new file mode 100644 index 0000000..69ed8a2 --- /dev/null +++ b/contrib/ipfilter/tools/BNF.ipnat @@ -0,0 +1,28 @@ +ipmap :: = mapblock | redir | map . + +map ::= mapit ifname ipmask "->" ipmask [ mapport | mapicmpid ] . +map ::= mapit ifname fromto "->" ipmask [ mapport | mapicmpid ] . +mapblock ::= "map-block" ifname ipmask "->" ipmask [ ports ] . +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 . +mapicmpid ::= "icmpidmap" icmp idnumber ":" idnumber . +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 . + +rr ::= "round-robin" . +tcpudp ::= "tcp" | "udp" | "tcp/udp" . +portnumber ::= number { numbers } | "auto" . +idnumber ::= number { numbers } . +ifname ::= 'A' - 'Z' { 'A' - 'Z' } numbers . + +numbers ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' . diff --git a/contrib/ipfilter/tools/Makefile b/contrib/ipfilter/tools/Makefile new file mode 100644 index 0000000..49a869c --- /dev/null +++ b/contrib/ipfilter/tools/Makefile @@ -0,0 +1,103 @@ + +DEST=. + +all: $(DEST)/ipf_y.c $(DEST)/ipf_y.h $(DEST)/ipf_l.c \ + $(DEST)/ipmon_y.c $(DEST)/ipmon_y.h $(DEST)/ipmon_l.c \ + $(DEST)/ipnat_y.c $(DEST)/ipnat_y.h $(DEST)/ipnat_l.c \ + $(DEST)/ipscan_y.c $(DEST)/ipscan_y.h $(DEST)/ipscan_l.c \ + $(DEST)/ippool_y.c $(DEST)/ippool_y.h $(DEST)/ippool_l.c \ + $(DEST)/ipf_l.h $(DEST)/ipnat_l.h $(DEST)/ipscan_l.h \ + $(DEST)/ippool_l.h $(DEST)/ipmon_l.h + +$(DEST)/ipf_y.h: $(DEST)/ipf_y.c + +$(DEST)/ipf_y.c: ipf_y.y + yacc -d ipf_y.y + sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.c/' \ + -e 's/"ipf_y.y"/"..\/tools\/ipf_y.y"/' \ + y.tab.c > $(DEST)/ipf_y.c + sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' y.tab.h > $(DEST)/ipf_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipf_l.c: lexer.c + sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' \ + -e 's/lexer.h/ipf_l.h/' lexer.c > $@ + +$(DEST)/ipmon_y.n: $(DEST)/ipmon_y.c + +$(DEST)/ipmon_y.c $(DEST)/ipmon_y.h: ipmon_y.y + yacc -d ipmon_y.y + sed -e 's/yy/ipmon_yy/g' -e 's/"ipmon_y.y"/"..\/tools\/ipmon_y.y"/' \ + y.tab.c > $(DEST)/ipmon_y.c + sed -e 's/yy/ipmon_yy/g' y.tab.h > $(DEST)/ipmon_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipmon_l.c: lexer.c + sed -e 's/yy/ipmon_yy/g' -e 's/y.tab.h/ipmon_y.h/' \ + -e 's/lexer.h/ipmon_l.h/' lexer.c > $@ + +$(DEST)/ipscan_y.h: $(DEST)/ipscan_y.c + +$(DEST)/ipscan_y.c $(DEST)/ipscan_y.h: ipscan_y.y + yacc -d ipscan_y.y + sed -e 's/yy/ipscan_yy/g' \ + -e 's/"ipscan_y.y"/"..\/tools\/ipscan_y.y"/' \ + y.tab.c > $(DEST)/ipscan_y.c + sed -e 's/yy/ipscan_yy/g' y.tab.h > $(DEST)/ipscan_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipscan_l.c: lexer.c + sed -e 's/yy/ipscan_yy/g' -e 's/y.tab.h/ipscan_y.h/' \ + -e 's/lexer.h/ipscan_l.h/' lexer.c > $@ + +$(DEST)/ippool_y.h: $(DEST)/ippool_y.c + +$(DEST)/ippool_y.c $(DEST)/ippool_y.h: ippool_y.y + yacc -d ippool_y.y + sed -e 's/yy/ippool_yy/g' -e 's/"ippool_y.y"/"..\/tools\/ippool_y.y"/' \ + y.tab.c > $(DEST)/ippool_y.c + sed -e 's/yy/ippool_yy/g' y.tab.h > $(DEST)/ippool_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ippool_l.c: lexer.c + sed -e 's/yy/ippool_yy/g' -e 's/y.tab.h/ippool_y.h/' \ + -e 's/lexer.h/ippool_l.h/' lexer.c > $@ + +$(DEST)/ipnat_y.h: $(DEST)/ipnat_y.c + +$(DEST)/ipnat_y.c $(DEST)/ipnat_y.h: ipnat_y.y + yacc -d ipnat_y.y + sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.c/ipnat_y.c/' \ + -e s/\"ipnat_y.y\"/\"..\\/tools\\/ipnat_y.y\"/ \ + y.tab.c > $(DEST)/ipnat_y.c + sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ + y.tab.h > $(DEST)/ipnat_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipnat_l.c: lexer.c + sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ + -e 's/lexer.h/ipnat_l.h/' lexer.c > $@ + +$(DEST)/ipf_l.h: lexer.h + sed -e 's/yy/ipf_yy/g' lexer.h > $@ + +$(DEST)/ipmon_l.h: lexer.h + sed -e 's/yy/ipmon_yy/g' lexer.h > $@ + +$(DEST)/ipscan_l.h: lexer.h + sed -e 's/yy/ipscan_yy/g' lexer.h > $@ + +$(DEST)/ippool_l.h: lexer.h + sed -e 's/yy/ippool_yy/g' lexer.h > $@ + +$(DEST)/ipnat_l.h: lexer.h + sed -e 's/yy/ipnat_yy/g' lexer.h > $@ + +clean: + /bin/rm -f $(DEST)/ipf_y.c $(DEST)/ipf_y.h $(DEST)/ipf_l.c + /bin/rm -f $(DEST)/ipmon_y.c $(DEST)/ipmon_y.h $(DEST)/ipmon_l.c + /bin/rm -f $(DEST)/ipscan_y.c $(DEST)/ipscan_y.h $(DEST)/ipscan_l.c + /bin/rm -f $(DEST)/ippool_y.c $(DEST)/ippool_y.h $(DEST)/ippool_l.c + /bin/rm -f $(DEST)/ipnat_y.c $(DEST)/ipnat_y.h $(DEST)/ipnat_l.c + /bin/rm -f $(DEST)/ipf_l.h $(DEST)/ipmon_l.h $(DEST)/ippool_l.h + /bin/rm -f $(DEST)/ipscan_l.h $(DEST)/ipnat_l.h diff --git a/contrib/ipfilter/tools/ipf.c b/contrib/ipfilter/tools/ipf.c new file mode 100644 index 0000000..ea39780 --- /dev/null +++ b/contrib/ipfilter/tools/ipf.c @@ -0,0 +1,562 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#endif +#include "ipf.h" +#include <fcntl.h> +#include <sys/ioctl.h> +#include "netinet/ipl.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipf.c,v 1.35.2.3 2004/12/15 18:27:17 darrenr Exp"; +#endif + +#if !defined(__SVR4) && defined(__GNUC__) +extern char *index __P((const char *, int)); +#endif + +extern char *optarg; +extern int optind; +extern frentry_t *frtop; + + +void ipf_frsync __P((void)); +void zerostats __P((void)); +int main __P((int, char *[])); + +int opts = 0; +int outputc = 0; +int use_inet6 = 0; + +static void procfile __P((char *, char *)), flushfilter __P((char *)); +static void set_state __P((u_int)), showstats __P((friostat_t *)); +static void packetlogon __P((char *)), swapactive __P((void)); +static int opendevice __P((char *, int)); +static void closedevice __P((void)); +static char *ipfname = IPL_NAME; +static void usage __P((void)); +static int showversion __P((void)); +static int get_flags __P((void)); +static void ipf_interceptadd __P((int, ioctlfunc_t, void *)); + +static int fd = -1; +static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl, + ioctl, ioctl, ioctl, + ioctl, ioctl }; + + +static void usage() +{ + fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n", + "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]", + "[-f filename] [-T <tuneopts>]"); + exit(1); +} + + +int main(argc,argv) +int argc; +char *argv[]; +{ + int c; + + if (argc < 2) + usage(); + + while ((c = getopt(argc, argv, "6Ac:dDEf:F:Il:noPrRsT:vVyzZ")) != -1) { + switch (c) + { + case '?' : + usage(); + break; +#ifdef USE_INET6 + case '6' : + use_inet6 = 1; + break; +#endif + case 'A' : + opts &= ~OPT_INACTIVE; + break; + case 'c' : + if (strcmp(optarg, "c") == 0) + outputc = 1; + break; + case 'E' : + set_state((u_int)1); + break; + case 'D' : + set_state((u_int)0); + break; + case 'd' : + opts ^= OPT_DEBUG; + break; + case 'f' : + procfile(argv[0], optarg); + break; + case 'F' : + flushfilter(optarg); + break; + case 'I' : + opts ^= OPT_INACTIVE; + break; + case 'l' : + packetlogon(optarg); + break; + case 'n' : + opts ^= OPT_DONOTHING; + break; + case 'o' : + break; + case 'P' : + ipfname = IPAUTH_NAME; + break; + case 'R' : + opts ^= OPT_NORESOLVE; + break; + case 'r' : + opts ^= OPT_REMOVE; + break; + case 's' : + swapactive(); + break; + case 'T' : + if (opendevice(ipfname, 1) >= 0) + ipf_dotuning(fd, optarg, ioctl); + break; + case 'v' : + opts += OPT_VERBOSE; + break; + case 'V' : + if (showversion()) + exit(1); + break; + case 'y' : + ipf_frsync(); + break; + case 'z' : + opts ^= OPT_ZERORULEST; + break; + case 'Z' : + zerostats(); + break; + } + } + + if (optind < 2) + usage(); + + if (fd != -1) + (void) close(fd); + + return(0); + /* NOTREACHED */ +} + + +static int opendevice(ipfdev, check) +char *ipfdev; +int check; +{ + if (opts & OPT_DONOTHING) + return -2; + + if (check && checkrev(ipfname) == -1) { + fprintf(stderr, "User/kernel version check failed\n"); + return -2; + } + + if (!ipfdev) + ipfdev = ipfname; + + if (fd == -1) + if ((fd = open(ipfdev, O_RDWR)) == -1) + if ((fd = open(ipfdev, O_RDONLY)) == -1) + perror("open device"); + return fd; +} + + +static void closedevice() +{ + close(fd); + fd = -1; +} + + +static int get_flags() +{ + int i; + + if ((opendevice(ipfname, 1) != -2) && + (ioctl(fd, SIOCGETFF, &i) == -1)) { + perror("SIOCGETFF"); + return 0; + } + return i; +} + + +static void set_state(enable) +u_int enable; +{ + if (opendevice(ipfname, 0) != -2) + if (ioctl(fd, SIOCFRENB, &enable) == -1) { + if (errno == EBUSY) + fprintf(stderr, + "IP FIlter: already initialized\n"); + else + perror("SIOCFRENB"); + } + return; +} + + +static void procfile(name, file) +char *name, *file; +{ + (void) opendevice(ipfname, 1); + + initparse(); + + ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file); + + if (outputc) { + printC(0); + printC(1); + emit(-1, -1, NULL, NULL); + } +} + + +static void ipf_interceptadd(fd, ioctlfunc, ptr) +int fd; +ioctlfunc_t ioctlfunc; +void *ptr; +{ + if (outputc) + printc(ptr); + + ipf_addrule(fd, ioctlfunc, ptr); +} + + +static void packetlogon(opt) +char *opt; +{ + int flag, xfd, logopt, change = 0; + + flag = get_flags(); + if (flag != 0) { + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) + printf("log flag is currently %#x\n", flag); + } + + flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); + + if (strstr(opt, "pass")) { + flag |= FF_LOGPASS; + if (opts & OPT_VERBOSE) + printf("set log flag: pass\n"); + change = 1; + } + if (strstr(opt, "nomatch")) { + flag |= FF_LOGNOMATCH; + if (opts & OPT_VERBOSE) + printf("set log flag: nomatch\n"); + change = 1; + } + if (strstr(opt, "block") || index(opt, 'd')) { + flag |= FF_LOGBLOCK; + if (opts & OPT_VERBOSE) + printf("set log flag: block\n"); + change = 1; + } + if (strstr(opt, "none")) { + if (opts & OPT_VERBOSE) + printf("disable all log flags\n"); + change = 1; + } + + if (change == 1) { + if (opendevice(ipfname, 1) != -2 && + (ioctl(fd, SIOCSETFF, &flag) != 0)) + perror("ioctl(SIOCSETFF)"); + } + + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { + flag = get_flags(); + printf("log flags are now %#x\n", flag); + } + + if (strstr(opt, "state")) { + if (opts & OPT_VERBOSE) + printf("set state log flag\n"); + xfd = open(IPSTATE_NAME, O_RDWR); + if (xfd >= 0) { + logopt = 0; + if (ioctl(xfd, SIOCGETLG, &logopt)) + perror("ioctl(SIOCGETLG)"); + else { + logopt = 1 - logopt; + if (ioctl(xfd, SIOCSETLG, &logopt)) + perror("ioctl(SIOCSETLG)"); + } + close(xfd); + } + } + + if (strstr(opt, "nat")) { + if (opts & OPT_VERBOSE) + printf("set nat log flag\n"); + xfd = open(IPNAT_NAME, O_RDWR); + if (xfd >= 0) { + logopt = 0; + if (ioctl(xfd, SIOCGETLG, &logopt)) + perror("ioctl(SIOCGETLG)"); + else { + logopt = 1 - logopt; + if (ioctl(xfd, SIOCSETLG, &logopt)) + perror("ioctl(SIOCSETLG)"); + } + close(xfd); + } + } +} + + +static void flushfilter(arg) +char *arg; +{ + int fl = 0, rem; + + if (!arg || !*arg) + return; + if (!strcmp(arg, "s") || !strcmp(arg, "S")) { + if (*arg == 'S') + fl = 0; + else + fl = 1; + rem = fl; + + closedevice(); + if (opendevice(IPSTATE_NAME, 1) == -2) + exit(1); + + if (!(opts & OPT_DONOTHING)) { + if (use_inet6) { + if (ioctl(fd, SIOCIPFL6, &fl) == -1) { + perror("ioctl(SIOCIPFL6)"); + exit(1); + } + } else { + if (ioctl(fd, SIOCIPFFL, &fl) == -1) { + perror("ioctl(SIOCIPFFL)"); + exit(1); + } + } + } + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { + printf("remove flags %s (%d)\n", arg, rem); + printf("removed %d filter rules\n", fl); + } + closedevice(); + return; + } + +#ifdef SIOCIPFFA + if (!strcmp(arg, "u")) { + closedevice(); + /* + * Flush auth rules and packets + */ + if (opendevice(IPL_AUTH, 1) == -1) + perror("open(IPL_AUTH)"); + else { + if (ioctl(fd, SIOCIPFFA, &fl) == -1) + perror("ioctl(SIOCIPFFA)"); + } + closedevice(); + return; + } +#endif + + if (strchr(arg, 'i') || strchr(arg, 'I')) + fl = FR_INQUE; + if (strchr(arg, 'o') || strchr(arg, 'O')) + fl = FR_OUTQUE; + if (strchr(arg, 'a') || strchr(arg, 'A')) + fl = FR_OUTQUE|FR_INQUE; + if (opts & OPT_INACTIVE) + fl |= FR_INACTIVE; + rem = fl; + + if (opendevice(ipfname, 1) == -2) + exit(1); + + if (!(opts & OPT_DONOTHING)) { + if (use_inet6) { + if (ioctl(fd, SIOCIPFL6, &fl) == -1) { + perror("ioctl(SIOCIPFL6)"); + exit(1); + } + } else { + if (ioctl(fd, SIOCIPFFL, &fl) == -1) { + perror("ioctl(SIOCIPFFL)"); + exit(1); + } + } + } + + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { + printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", + (rem & FR_OUTQUE) ? "O" : "", rem); + printf("removed %d filter rules\n", fl); + } + return; +} + + +static void swapactive() +{ + int in = 2; + + if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) + perror("ioctl(SIOCSWAPA)"); + else + printf("Set %d now inactive\n", in); +} + + +void ipf_frsync() +{ + int frsyn = 0; + + if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1) + perror("SIOCFRSYN"); + else + printf("filter sync'd\n"); +} + + +void zerostats() +{ + friostat_t fio; + friostat_t *fiop = &fio; + + if (opendevice(ipfname, 1) != -2) { + if (ioctl(fd, SIOCFRZST, &fiop) == -1) { + perror("ioctl(SIOCFRZST)"); + exit(-1); + } + showstats(fiop); + } + +} + + +/* + * read the kernel stats for packets blocked and passed + */ +static void showstats(fp) +friostat_t *fp; +{ + printf("bad packets:\t\tin %lu\tout %lu\n", + fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); + printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", + fp->f_st[0].fr_block, fp->f_st[0].fr_pass, + fp->f_st[0].fr_nom); + printf(" counted %lu\n", fp->f_st[0].fr_acct); + printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", + fp->f_st[1].fr_block, fp->f_st[1].fr_pass, + fp->f_st[1].fr_nom); + printf(" counted %lu\n", fp->f_st[0].fr_acct); + printf(" input packets logged:\tblocked %lu passed %lu\n", + fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); + printf("output packets logged:\tblocked %lu passed %lu\n", + fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); + printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n", + fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip, + fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip); +} + + +static int showversion() +{ + struct friostat fio; + ipfobj_t ipfo; + u_32_t flags; + char *s; + int vfd; + + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(fio); + ipfo.ipfo_ptr = (void *)&fio; + ipfo.ipfo_type = IPFOBJ_IPFSTAT; + + printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); + + if ((vfd = open(ipfname, O_RDONLY)) == -1) { + perror("open device"); + return 1; + } + + if (ioctl(vfd, SIOCGETFS, &ipfo)) { + perror("ioctl(SIOCGETFS)"); + close(vfd); + return 1; + } + close(vfd); + flags = get_flags(); + + printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), + (int)sizeof(fio.f_version), fio.f_version); + printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no"); + printf("Log Flags: %#x = ", flags); + s = ""; + if (flags & FF_LOGPASS) { + printf("pass"); + s = ", "; + } + if (flags & FF_LOGBLOCK) { + printf("%sblock", s); + s = ", "; + } + if (flags & FF_LOGNOMATCH) { + printf("%snomatch", s); + s = ", "; + } + if (flags & FF_BLOCKNONIP) { + printf("%snonip", s); + s = ", "; + } + if (!*s) + printf("none set"); + putchar('\n'); + + printf("Default: "); + if (FR_ISPASS(fio.f_defpass)) + s = "pass"; + else if (FR_ISBLOCK(fio.f_defpass)) + s = "block"; + else + s = "nomatch -> block"; + printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); + printf("Active list: %d\n", fio.f_active); + printf("Feature mask: %#x\n", fio.f_features); + + return 0; +} diff --git a/contrib/ipfilter/tools/ipf_y.y b/contrib/ipfilter/tools/ipf_y.y new file mode 100644 index 0000000..0660d50 --- /dev/null +++ b/contrib/ipfilter/tools/ipf_y.y @@ -0,0 +1,2126 @@ +/* $NetBSD$ */ + +%{ +#include "ipf.h" +#include <sys/ioctl.h> +#include <syslog.h> +#ifdef IPFILTER_BPF +# include <pcap-bpf.h> +# include <pcap.h> +#endif +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "netinet/ipl.h" +#include "ipf_l.h" + +#define YYDEBUG 1 +#define DOALL(x) for (fr = frc; fr != NULL; fr = fr->fr_next) { x } +#define DOREM(x) for (; fr != NULL; fr = fr->fr_next) { x } + +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; + +static void newrule __P((void)); +static void setipftype __P((void)); +static u_32_t lookuphost __P((char *)); +static void dobpf __P((int, char *)); +static void resetaddr __P((void)); +static struct alist_s *newalist __P((struct alist_s *)); +static u_int makehash __P((struct alist_s *)); +static int makepool __P((struct alist_s *)); +static frentry_t *addrule __P((void)); +static void setsyslog __P((void)); +static void unsetsyslog __P((void)); +static void fillgroup __P((frentry_t *)); + +frentry_t *fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL; + +static int ifpflag = 0; +static int nowith = 0; +static int dynamic = -1; +static int pooled = 0; +static int hashed = 0; +static int nrules = 0; +static int newlist = 0; +static int added = 0; +static int ipffd = -1; +static int *yycont = 0; +static ioctlfunc_t ipfioctl[IPL_LOGSIZE]; +static addfunc_t ipfaddfunc = NULL; +static struct wordtab ipfwords[95]; +static struct wordtab addrwords[4]; +static struct wordtab maskwords[5]; +static struct wordtab icmpcodewords[17]; +static struct wordtab icmptypewords[16]; +static struct wordtab ipv4optwords[25]; +static struct wordtab ipv4secwords[9]; +static struct wordtab ipv6optwords[8]; +static struct wordtab logwords[33]; + +%} +%union { + char *str; + u_32_t num; + struct in_addr ipa; + frentry_t fr; + frtuc_t *frt; + struct alist_s *alist; + u_short port; + struct { + u_short p1; + u_short p2; + int pc; + } pc; + struct { + union i6addr a; + union i6addr m; + } ipp; + union i6addr ip6; +}; + +%type <port> portnum +%type <num> facility priority icmpcode seclevel secname icmptype +%type <num> opt compare range opttype flagset optlist ipv6hdrlist ipv6hdr +%type <num> portc porteq +%type <ipa> hostname ipv4 ipv4mask ipv4_16 ipv4_24 +%type <ip6> ipv6mask +%type <ipp> addr ipaddr +%type <str> servicename name interfacename +%type <pc> portrange portcomp +%type <alist> addrlist poollist + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token <ip6> YY_IPV6 + +%token IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL +%token IPFY_RETICMP IPFY_RETRST IPFY_RETICMPASDST +%token IPFY_IN IPFY_OUT +%token IPFY_QUICK IPFY_ON IPFY_OUTVIA IPFY_INVIA +%token IPFY_DUPTO IPFY_TO IPFY_FROUTE IPFY_REPLY_TO IPFY_ROUTETO +%token IPFY_TOS IPFY_TTL IPFY_PROTO +%token IPFY_HEAD IPFY_GROUP +%token IPFY_AUTH IPFY_PREAUTH +%token IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK +%token IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP +%token IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH +%token IPFY_PPS +%token IPFY_ESP IPFY_AH +%token IPFY_WITH IPFY_AND IPFY_NOT IPFY_NO IPFY_OPT +%token IPFY_TCPUDP IPFY_TCP IPFY_UDP +%token IPFY_FLAGS IPFY_MULTICAST +%token IPFY_MASK IPFY_BROADCAST IPFY_NETWORK IPFY_NETMASKED IPFY_PEER +%token IPFY_PORT +%token IPFY_NOW +%token IPFY_ICMP IPFY_ICMPTYPE IPFY_ICMPCODE +%token IPFY_IPOPTS IPFY_SHORT IPFY_NAT IPFY_BADSRC IPFY_LOWTTL IPFY_FRAG +%token IPFY_MBCAST IPFY_BAD IPFY_BADNAT IPFY_OOW IPFY_NEWISN IPFY_NOICMPERR +%token IPFY_KEEP IPFY_STATE IPFY_FRAGS IPFY_LIMIT IPFY_STRICT IPFY_AGE +%token IPFY_SYNC IPFY_FRAGBODY +%token IPFY_IPOPT_NOP IPFY_IPOPT_RR IPFY_IPOPT_ZSU IPFY_IPOPT_MTUP +%token IPFY_IPOPT_MTUR IPFY_IPOPT_ENCODE IPFY_IPOPT_TS IPFY_IPOPT_TR +%token IPFY_IPOPT_SEC IPFY_IPOPT_LSRR IPFY_IPOPT_ESEC IPFY_IPOPT_CIPSO +%token IPFY_IPOPT_SATID IPFY_IPOPT_SSRR IPFY_IPOPT_ADDEXT IPFY_IPOPT_VISA +%token IPFY_IPOPT_IMITD IPFY_IPOPT_EIP IPFY_IPOPT_FINN IPFY_IPOPT_DPS +%token IPFY_IPOPT_SDB IPFY_IPOPT_NSAPA IPFY_IPOPT_RTRALRT IPFY_IPOPT_UMP +%token IPFY_SECCLASS IPFY_SEC_UNC IPFY_SEC_CONF IPFY_SEC_RSV1 IPFY_SEC_RSV2 +%token IPFY_SEC_RSV4 IPFY_SEC_SEC IPFY_SEC_TS IPFY_SEC_RSV3 + +%token IPF6_V6HDRS IPFY_IPV6OPT IPFY_IPV6OPT_DSTOPTS IPFY_IPV6OPT_HOPOPTS +%token IPFY_IPV6OPT_IPV6 IPFY_IPV6OPT_NONE IPFY_IPV6OPT_ROUTING + +%token IPFY_ICMPT_UNR IPFY_ICMPT_ECHO IPFY_ICMPT_ECHOR IPFY_ICMPT_SQUENCH +%token IPFY_ICMPT_REDIR IPFY_ICMPT_TIMEX IPFY_ICMPT_PARAMP IPFY_ICMPT_TIMEST +%token IPFY_ICMPT_TIMESTREP IPFY_ICMPT_INFOREQ IPFY_ICMPT_INFOREP +%token IPFY_ICMPT_MASKREQ IPFY_ICMPT_MASKREP IPFY_ICMPT_ROUTERAD +%token IPFY_ICMPT_ROUTERSOL + +%token IPFY_ICMPC_NETUNR IPFY_ICMPC_HSTUNR IPFY_ICMPC_PROUNR IPFY_ICMPC_PORUNR +%token IPFY_ICMPC_NEEDF IPFY_ICMPC_SRCFAIL IPFY_ICMPC_NETUNK IPFY_ICMPC_HSTUNK +%token IPFY_ICMPC_ISOLATE IPFY_ICMPC_NETPRO IPFY_ICMPC_HSTPRO +%token IPFY_ICMPC_NETTOS IPFY_ICMPC_HSTTOS IPFY_ICMPC_FLTPRO IPFY_ICMPC_HSTPRE +%token IPFY_ICMPC_CUTPRE + +%token IPFY_FAC_KERN IPFY_FAC_USER IPFY_FAC_MAIL IPFY_FAC_DAEMON IPFY_FAC_AUTH +%token IPFY_FAC_SYSLOG IPFY_FAC_LPR IPFY_FAC_NEWS IPFY_FAC_UUCP IPFY_FAC_CRON +%token IPFY_FAC_LOCAL0 IPFY_FAC_LOCAL1 IPFY_FAC_LOCAL2 IPFY_FAC_LOCAL3 +%token IPFY_FAC_LOCAL4 IPFY_FAC_LOCAL5 IPFY_FAC_LOCAL6 IPFY_FAC_LOCAL7 +%token IPFY_FAC_SECURITY IPFY_FAC_FTP IPFY_FAC_AUTHPRIV IPFY_FAC_AUDIT +%token IPFY_FAC_LFMT IPFY_FAC_CONSOLE + +%token IPFY_PRI_EMERG IPFY_PRI_ALERT IPFY_PRI_CRIT IPFY_PRI_ERR IPFY_PRI_WARN +%token IPFY_PRI_NOTICE IPFY_PRI_INFO IPFY_PRI_DEBUG +%% +file: line + | assign + | file line + | file assign + ; + +line: xx rule { while ((fr = frtop) != NULL) { + frtop = fr->fr_next; + fr->fr_next = NULL; + (*ipfaddfunc)(ipffd, ipfioctl[IPL_LOGIPF], fr); + fr->fr_next = frold; + frold = fr; + } + resetlexer(); + } + | YY_COMMENT + ; + +xx: { newrule(); } + ; + +assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +rule: inrule eol + | outrule eol + ; + +eol: | ';' + ; + +inrule: + rulehead markin inopts rulemain ruletail intag ruletail2 + ; + +outrule: + rulehead markout outopts rulemain ruletail outtag ruletail2 + ; + +rulehead: + collection action + | insert collection action + ; + +markin: IPFY_IN { fr->fr_flags |= FR_INQUE; } + ; + +markout: + IPFY_OUT { fr->fr_flags |= FR_OUTQUE; } + ; + +rulemain: + ipfrule + | bpfrule + ; + +ipfrule: + tos ttl proto ip + ; + +bpfrule: + IPFY_BPFV4 '{' YY_STR '}' { dobpf(4, $3); free($3); } + | IPFY_BPFV6 '{' YY_STR '}' { dobpf(6, $3); free($3); } + ; + +ruletail: + with keep head group + ; + +ruletail2: + pps age new + ; + +intag: settagin matchtagin + ; + +outtag: settagout matchtagout + ; + +insert: + '@' YY_NUMBER { fr->fr_hits = (U_QUAD_T)$2 + 1; } + ; + +collection: + | YY_NUMBER { fr->fr_collect = $1; } + ; + +action: block + | IPFY_PASS { fr->fr_flags |= FR_PASS; } + | log + | IPFY_COUNT { fr->fr_flags |= FR_ACCOUNT; } + | auth + | IPFY_SKIP YY_NUMBER { fr->fr_flags |= FR_SKIP; + fr->fr_arg = $2; } + | IPFY_CALL func + | IPFY_CALL IPFY_NOW func { fr->fr_flags |= FR_CALLNOW; } + ; + +block: blocked + | blocked blockreturn + ; + +blocked: + IPFY_BLOCK { fr->fr_flags = FR_BLOCK; } + ; +blockreturn: + IPFY_RETICMP { fr->fr_flags |= FR_RETICMP; } + | IPFY_RETICMP returncode { fr->fr_flags |= FR_RETICMP; } + | IPFY_RETICMPASDST { fr->fr_flags |= FR_FAKEICMP; } + | IPFY_RETICMPASDST returncode { fr->fr_flags |= FR_FAKEICMP; } + | IPFY_RETRST { fr->fr_flags |= FR_RETRST; } + ; + +log: IPFY_LOG { fr->fr_flags |= FR_LOG; } + | IPFY_LOG logoptions { fr->fr_flags |= FR_LOG; } + ; + +auth: IPFY_AUTH { fr->fr_flags |= FR_AUTH; } + | IPFY_AUTH IPFY_RETRST { fr->fr_flags |= (FR_AUTH|FR_RETRST);} + | IPFY_PREAUTH { fr->fr_flags |= FR_PREAUTH; } + ; + +func: YY_STR '/' YY_NUMBER { fr->fr_func = nametokva($1, + ipfioctl[IPL_LOGIPF]); + fr->fr_arg = $3; + free($1); } + ; + +inopts: + | inopts inopt + ; + +inopt: + logopt + | quick + | on + | dup + | froute + | proute + | replyto + ; + +outopts: + | outopts outopt + ; + +outopt: + logopt + | quick + | on + | dup + | proute + | replyto + ; + +tos: | settos YY_NUMBER { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) } + | settos YY_HEX { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) } + | settos lstart toslist lend + ; + +settos: IPFY_TOS { setipftype(); } + ; + +toslist: + YY_NUMBER { DOALL(fr->fr_tos = $1; fr->fr_mtos = 0xff;) } + | YY_HEX { DOREM(fr->fr_tos = $1; fr->fr_mtos = 0xff;) } + | toslist lmore YY_NUMBER + { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) } + | toslist lmore YY_HEX + { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) } + ; + +ttl: | setttl YY_NUMBER + { DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) } + | setttl lstart ttllist lend + ; + +lstart: '(' { newlist = 1; fr = frc; added = 0; } + ; + +lend: ')' { nrules += added; } + ; + +lmore: lanother { if (newlist == 1) { + newlist = 0; + } + fr = addrule(); + if (yycont != NULL) + *yycont = 1; + } + ; + +lanother: + | ',' + ; + +setttl: IPFY_TTL { setipftype(); } + ; + +ttllist: + YY_NUMBER { DOREM(fr->fr_ttl = $1; fr->fr_mttl = 0xff;) } + | ttllist lmore YY_NUMBER + { DOREM(fr->fr_ttl = $3; fr->fr_mttl = 0xff;) } + ; + +proto: | protox protocol { yyresetdict(); } + ; + +protox: IPFY_PROTO { setipftype(); + fr = frc; + yysetdict(NULL); } + ; + +ip: srcdst flags icmp + ; + +group: | IPFY_GROUP YY_STR { DOALL(strncpy(fr->fr_group, $2, \ + FR_GROUPLEN); \ + fillgroup(fr);); + free($2); } + | IPFY_GROUP YY_NUMBER { DOALL(sprintf(fr->fr_group, "%d", \ + $2); \ + fillgroup(fr);) } + ; + +head: | IPFY_HEAD YY_STR { DOALL(strncpy(fr->fr_grhead, $2, \ + FR_GROUPLEN);); + free($2); } + | IPFY_HEAD YY_NUMBER { DOALL(sprintf(fr->fr_grhead, "%d", \ + $2);) } + ; + +settagin: + | IPFY_SETTAG '(' taginlist ')' + ; + +taginlist: + taginspec + | taginlist ',' taginspec + ; + +taginspec: + logtag + ; + +nattag: IPFY_NAT '=' YY_STR { DOALL(strncpy(fr->fr_nattag.ipt_tag,\ + $3, IPFTAG_LEN);); + free($3); } + | IPFY_NAT '=' YY_NUMBER { DOALL(sprintf(fr->fr_nattag.ipt_tag,\ + "%d", $3 & 0xffffffff);) } + ; + +logtag: IPFY_LOG '=' YY_NUMBER { DOALL(fr->fr_logtag = $3;) } + ; + +settagout: + | IPFY_SETTAG '(' tagoutlist ')' + ; + +tagoutlist: + tagoutspec + | tagoutlist ',' tagoutspec + ; + +tagoutspec: + logtag + | nattag + ; + +matchtagin: + | IPFY_MATCHTAG '(' tagoutlist ')' + ; + +matchtagout: + | IPFY_MATCHTAG '(' taginlist ')' + ; + +pps: | IPFY_PPS YY_NUMBER { DOALL(fr->fr_pps = $2;) } + ; + +new: | savegroup file restoregroup + ; + +savegroup: + '{' + ; + +restoregroup: + '}' + ; + +logopt: log + ; + +quick: + IPFY_QUICK { fr->fr_flags |= FR_QUICK; } + ; + +on: IPFY_ON onname + | IPFY_ON onname IPFY_INVIA vianame + | IPFY_ON onname IPFY_OUTVIA vianame + ; + +onname: interfacename + { strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0])); + free($1); + } + | interfacename ',' interfacename + { strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0])); + free($1); + strncpy(fr->fr_ifnames[1], $3, sizeof(fr->fr_ifnames[1])); + free($3); + } + ; + +vianame: + name + { strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2])); + free($1); + } + | name ',' name + { strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2])); + free($1); + strncpy(fr->fr_ifnames[3], $3, sizeof(fr->fr_ifnames[3])); + free($3); + } + ; + +dup: IPFY_DUPTO name + { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); + free($2); + } + | IPFY_DUPTO name duptoseparator hostname + { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); + fr->fr_dif.fd_ip = $4; + yyexpectaddr = 0; + free($2); + } + | IPFY_DUPTO name duptoseparator YY_IPV6 + { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); + bcopy(&$4, &fr->fr_dif.fd_ip6, sizeof(fr->fr_dif.fd_ip6)); + yyexpectaddr = 0; + free($2); + } + ; + +duptoseparator: + ':' { yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); } + ; + +froute: IPFY_FROUTE { fr->fr_flags |= FR_FASTROUTE; } + ; + +proute: routeto name + { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); + free($2); + } + | routeto name duptoseparator hostname + { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); + fr->fr_tif.fd_ip = $4; + yyexpectaddr = 0; + free($2); + } + | routeto name duptoseparator YY_IPV6 + { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); + bcopy(&$4, &fr->fr_tif.fd_ip6, sizeof(fr->fr_tif.fd_ip6)); + yyexpectaddr = 0; + free($2); + } + ; + +routeto: + IPFY_TO + | IPFY_ROUTETO + ; + +replyto: + IPFY_REPLY_TO name + { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); + free($2); + } + | IPFY_REPLY_TO name duptoseparator hostname + { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); + fr->fr_rif.fd_ip = $4; + free($2); + } + ; + +logoptions: + logoption + | logoptions logoption + ; + +logoption: + IPFY_BODY { fr->fr_flags |= FR_LOGBODY; } + | IPFY_FIRST { fr->fr_flags |= FR_LOGFIRST; } + | IPFY_ORBLOCK { fr->fr_flags |= FR_LOGORBLOCK; } + | level loglevel { unsetsyslog(); } + ; + +returncode: + starticmpcode icmpcode ')' { fr->fr_icode = $2; yyresetdict(); } + ; + +starticmpcode: + '(' { yysetdict(icmpcodewords); } + ; + +srcdst: | IPFY_ALL + | fromto + ; + +protocol: + YY_NUMBER { DOREM(fr->fr_proto = $1; \ + fr->fr_mproto = 0xff;) } + | YY_STR { if (!strcmp($1, "tcp-udp")) { + DOREM(fr->fr_flx |= FI_TCPUDP; \ + fr->fr_mflx |= FI_TCPUDP;) + } else { + int p = getproto($1); + if (p == -1) + yyerror("protocol unknown"); + DOREM(fr->fr_proto = p; \ + fr->fr_mproto = 0xff;) + } + free($1); + } + | YY_STR nextstring YY_STR + { if (!strcmp($1, "tcp") && + !strcmp($3, "udp")) { + DOREM(fr->fr_flx |= FI_TCPUDP; \ + fr->fr_mflx |= FI_TCPUDP;) + } else + YYERROR; + free($1); + free($3); + } + ; + +nextstring: + '/' { yysetdict(NULL); } + ; + +fromto: from srcobject to dstobject { yyexpectaddr = 0; yycont = NULL; } + | to dstobject { yyexpectaddr = 0; yycont = NULL; } + | from srcobject { yyexpectaddr = 0; yycont = NULL; } + ; + +from: IPFY_FROM { setipftype(); + if (fr == NULL) + fr = frc; + yyexpectaddr = 1; + if (yydebug) + printf("set yyexpectaddr\n"); + yycont = &yyexpectaddr; + yysetdict(addrwords); + resetaddr(); } + ; + +to: IPFY_TO { if (fr == NULL) + fr = frc; + yyexpectaddr = 1; + if (yydebug) + printf("set yyexpectaddr\n"); + yycont = &yyexpectaddr; + yysetdict(addrwords); + resetaddr(); } + ; + +with: | andwith withlist + ; + +andwith: + IPFY_WITH { nowith = 0; setipftype(); } + | IPFY_AND { nowith = 0; setipftype(); } + ; + +flags: | startflags flagset + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) } + | startflags flagset '/' flagset + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + | startflags '/' flagset + { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) } + | startflags YY_NUMBER + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) } + | startflags '/' YY_NUMBER + { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) } + | startflags YY_NUMBER '/' YY_NUMBER + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + | startflags flagset '/' YY_NUMBER + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + | startflags YY_NUMBER '/' flagset + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + ; + +startflags: + IPFY_FLAGS { if (frc->fr_type != FR_T_IPF) + yyerror("flags with non-ipf type rule"); + if (frc->fr_proto != IPPROTO_TCP) + yyerror("flags with non-TCP rule"); + } + ; + +flagset: + YY_STR { $$ = tcpflags($1); free($1); } + | YY_HEX { $$ = $1; } + ; + +srcobject: + { yyresetdict(); } fromport + | srcaddr srcport + | '!' srcaddr srcport + { DOALL(fr->fr_flags |= FR_NOTSRCIP;) } + ; + +srcaddr: + addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \ + bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \ + if (dynamic != -1) { \ + fr->fr_satype = ifpflag; \ + fr->fr_ipf->fri_sifpidx = dynamic; \ + } else if (pooled || hashed) \ + fr->fr_satype = FRI_LOOKUP;) + } + | lstart srcaddrlist lend + ; + +srcaddrlist: + addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \ + bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \ + if (dynamic != -1) { \ + fr->fr_satype = ifpflag; \ + fr->fr_ipf->fri_sifpidx = dynamic; \ + } else if (pooled || hashed) \ + fr->fr_satype = FRI_LOOKUP;) + } + | srcaddrlist lmore addr + { DOREM(bcopy(&($3.a), &fr->fr_ip.fi_src, sizeof($3.a)); \ + bcopy(&($3.m), &fr->fr_mip.fi_src, sizeof($3.m)); \ + if (dynamic != -1) { \ + fr->fr_satype = ifpflag; \ + fr->fr_ipf->fri_sifpidx = dynamic; \ + } else if (pooled || hashed) \ + fr->fr_satype = FRI_LOOKUP;) + } + ; + +srcport: + | portcomp + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) } + | portrange + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \ + fr->fr_stop = $1.p2;) } + | porteq lstart srcportlist lend + { yyresetdict(); } + ; + +fromport: + portcomp + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) } + | portrange + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \ + fr->fr_stop = $1.p2;) } + | porteq lstart srcportlist lend + { yyresetdict(); } + ; + +srcportlist: + portnum { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $1;) } + | srcportlist lmore portnum + { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $3;) } + ; + +dstobject: + { yyresetdict(); } toport + | dstaddr dstport + | '!' dstaddr dstport + { DOALL(fr->fr_flags |= FR_NOTDSTIP;) } + ; + +dstaddr: + addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \ + bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \ + if (dynamic != -1) { \ + fr->fr_datype = ifpflag; \ + fr->fr_ipf->fri_difpidx = dynamic; \ + } else if (pooled || hashed) \ + fr->fr_datype = FRI_LOOKUP;) + } + | lstart dstaddrlist lend + ; + +dstaddrlist: + addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \ + bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \ + if (dynamic != -1) { \ + fr->fr_datype = ifpflag; \ + fr->fr_ipf->fri_difpidx = dynamic; \ + } else if (pooled || hashed) \ + fr->fr_datype = FRI_LOOKUP;) + } + | dstaddrlist lmore addr + { DOREM(bcopy(&($3.a), &fr->fr_ip.fi_dst, sizeof($3.a)); \ + bcopy(&($3.m), &fr->fr_mip.fi_dst, sizeof($3.m)); \ + if (dynamic != -1) { \ + fr->fr_datype = ifpflag; \ + fr->fr_ipf->fri_difpidx = dynamic; \ + } else if (pooled || hashed) \ + fr->fr_datype = FRI_LOOKUP;) + } + ; + + +dstport: + | portcomp + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) } + | portrange + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \ + fr->fr_dtop = $1.p2;) } + | porteq lstart dstportlist lend + { yyresetdict(); } + ; + +toport: + portcomp + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) } + | portrange + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \ + fr->fr_dtop = $1.p2;) } + | porteq lstart dstportlist lend + { yyresetdict(); } + ; + +dstportlist: + portnum { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $1;) } + | dstportlist lmore portnum + { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $3;) } + ; + +addr: pool '/' YY_NUMBER { pooled = 1; + yyexpectaddr = 0; + $$.a.iplookuptype = IPLT_POOL; + $$.a.iplookupnum = $3; } + | pool '=' '(' poollist ')' { pooled = 1; + yyexpectaddr = 0; + $$.a.iplookuptype = IPLT_POOL; + $$.a.iplookupnum = makepool($4); } + | hash '/' YY_NUMBER { hashed = 1; + yyexpectaddr = 0; + $$.a.iplookuptype = IPLT_HASH; + $$.a.iplookupnum = $3; } + | hash '=' '(' addrlist ')' { hashed = 1; + yyexpectaddr = 0; + $$.a.iplookuptype = IPLT_HASH; + $$.a.iplookupnum = makehash($4); } + | ipaddr { bcopy(&$1, &$$, sizeof($$)); + yyexpectaddr = 0; } + ; + +ipaddr: IPFY_ANY { bzero(&($$), sizeof($$)); + yyresetdict(); + yyexpectaddr = 0; } + | hostname { $$.a.in4 = $1; + $$.m.in4_addr = 0xffffffff; + yyexpectaddr = 0; } + | hostname { yyresetdict(); + $$.a.in4_addr = $1.s_addr; } + maskspace { yysetdict(maskwords); } + ipv4mask { $$.m.in4_addr = $5.s_addr; + $$.a.in4_addr &= $5.s_addr; + yyresetdict(); + yyexpectaddr = 0; } + | YY_IPV6 { bcopy(&$1, &$$.a, sizeof($$.a)); + fill6bits(128, (u_32_t *)&$$.m); + yyresetdict(); + yyexpectaddr = 0; } + | YY_IPV6 { yyresetdict(); + bcopy(&$1, &$$.a, sizeof($$.a)); } + maskspace { yysetdict(maskwords); } + ipv6mask { bcopy(&$5, &$$.m, sizeof($$.m)); + yyresetdict(); + yyexpectaddr = 0; } + ; +maskspace: + '/' + | IPFY_MASK + ; + +ipv4mask: + ipv4 { $$ = $1; } + | YY_HEX { $$.s_addr = htonl($1); } + | YY_NUMBER { ntomask(4, $1, (u_32_t *)&$$); } + | IPFY_BROADCAST { if (ifpflag == FRI_DYNAMIC) { + $$.s_addr = 0; + ifpflag = FRI_BROADCAST; + } else + YYERROR; + } + | IPFY_NETWORK { if (ifpflag == FRI_DYNAMIC) { + $$.s_addr = 0; + ifpflag = FRI_NETWORK; + } else + YYERROR; + } + | IPFY_NETMASKED { if (ifpflag == FRI_DYNAMIC) { + $$.s_addr = 0; + ifpflag = FRI_NETMASKED; + } else + YYERROR; + } + | IPFY_PEER { if (ifpflag == FRI_DYNAMIC) { + $$.s_addr = 0; + ifpflag = FRI_PEERADDR; + } else + YYERROR; + } + ; + +ipv6mask: + YY_NUMBER { ntomask(6, $1, $$.i6); } + | IPFY_BROADCAST { if (ifpflag == FRI_DYNAMIC) { + bzero(&$$, sizeof($$)); + ifpflag = FRI_BROADCAST; + } else + YYERROR; + } + | IPFY_NETWORK { if (ifpflag == FRI_DYNAMIC) { + bzero(&$$, sizeof($$)); + ifpflag = FRI_BROADCAST; + } else + YYERROR; + } + | IPFY_NETMASKED { if (ifpflag == FRI_DYNAMIC) { + bzero(&$$, sizeof($$)); + ifpflag = FRI_BROADCAST; + } else + YYERROR; + } + | IPFY_PEER { if (ifpflag == FRI_DYNAMIC) { + bzero(&$$, sizeof($$)); + ifpflag = FRI_BROADCAST; + } else + YYERROR; + } + ; + +hostname: + ipv4 { $$ = $1; } + | YY_NUMBER { $$.s_addr = $1; } + | YY_HEX { $$.s_addr = $1; } + | YY_STR { $$.s_addr = lookuphost($1); + free($1); + } + ; + +addrlist: + ipaddr { $$ = newalist(NULL); + bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a)); + bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); } + | addrlist ',' ipaddr + { $$ = newalist($1); + bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a)); + bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); } + ; + +pool: IPFY_POOL { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } + ; + +hash: IPFY_HASH { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } + ; + +poollist: + ipaddr { $$ = newalist(NULL); + bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a)); + bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); } + | '!' ipaddr { $$ = newalist(NULL); + $$->al_not = 1; + bcopy(&($2.a), &($$->al_i6addr), sizeof($2.a)); + bcopy(&($2.m), &($$->al_i6mask), sizeof($2.m)); } + | poollist ',' ipaddr + { $$ = newalist($1); + bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a)); + bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); } + | poollist ',' '!' ipaddr + { $$ = newalist($1); + $$->al_not = 1; + bcopy(&($4.a), &($$->al_i6addr), sizeof($4.a)); + bcopy(&($4.m), &($$->al_i6mask), sizeof($4.m)); } + ; + +port: IPFY_PORT { yyexpectaddr = 0; + yycont = NULL; + } + ; + +portc: port compare { $$ = $2; + yysetdict(NULL); } + | porteq { $$ = $1; } + ; + +porteq: port '=' { $$ = FR_EQUAL; + yysetdict(NULL); } + ; + +portr: IPFY_PORT { yyexpectaddr = 0; + yycont = NULL; + yysetdict(NULL); } + ; + +portcomp: + portc portnum { $$.pc = $1; + $$.p1 = $2; + yyresetdict(); } + ; + +portrange: + portr portnum range portnum { $$.p1 = $2; + $$.pc = $3; + $$.p2 = $4; + yyresetdict(); } + ; + +icmp: | itype icode + ; + +itype: seticmptype icmptype + { DOALL(fr->fr_icmp = htons($2 << 8); fr->fr_icmpm = htons(0xff00);); + yyresetdict(); + } + | seticmptype lstart typelist lend { yyresetdict(); } + ; + +seticmptype: + IPFY_ICMPTYPE { setipftype(); + yysetdict(icmptypewords); } + ; + +icode: | seticmpcode icmpcode + { DOALL(fr->fr_icmp |= htons($2); fr->fr_icmpm |= htons(0xff);); + yyresetdict(); + } + | seticmpcode lstart codelist lend { yyresetdict(); } + ; + +seticmpcode: + IPFY_ICMPCODE { yysetdict(icmpcodewords); } + ; + +typelist: + icmptype + { DOREM(fr->fr_icmp = htons($1 << 8); fr->fr_icmpm = htons(0xff00);) } + | typelist lmore icmptype + { DOREM(fr->fr_icmp = htons($3 << 8); fr->fr_icmpm = htons(0xff00);) } + ; + +codelist: + icmpcode + { DOREM(fr->fr_icmp |= htons($1); fr->fr_icmpm |= htons(0xff);) } + | codelist lmore icmpcode + { DOREM(fr->fr_icmp |= htons($3); fr->fr_icmpm |= htons(0xff);) } + ; + +age: | IPFY_AGE YY_NUMBER { DOALL(fr->fr_age[0] = $2; \ + fr->fr_age[1] = $2;) } + | IPFY_AGE YY_NUMBER '/' YY_NUMBER + { DOALL(fr->fr_age[0] = $2; \ + fr->fr_age[1] = $4;) } + ; + +keep: | IPFY_KEEP keepstate keep + | IPFY_KEEP keepfrag keep + ; + +keepstate: + IPFY_STATE stateoptlist { DOALL(fr->fr_flags |= FR_KEEPSTATE;)} + ; + +keepfrag: + IPFY_FRAGS fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) } + | IPFY_FRAG fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) } + ; + +fragoptlist: + | '(' fragopts ')' + ; + +fragopts: + fragopt lanother fragopts + | fragopt + ; + +fragopt: + IPFY_STRICT { DOALL(fr->fr_flags |= FR_FRSTRICT;) } + ; + +stateoptlist: + | '(' stateopts ')' + ; + +stateopts: + stateopt lanother stateopts + | stateopt + ; + +stateopt: + IPFY_LIMIT YY_NUMBER { DOALL(fr->fr_statemax = $2;) } + | IPFY_STRICT { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \ + YYERROR; \ + } else \ + fr->fr_flags |= FR_STSTRICT;) + } + | IPFY_NEWISN { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \ + YYERROR; \ + } else \ + fr->fr_flags |= FR_NEWISN;) + } + | IPFY_NOICMPERR { DOALL(fr->fr_flags |= FR_NOICMPERR;) } + + | IPFY_SYNC { DOALL(fr->fr_flags |= FR_STATESYNC;) } + ; + +portnum: + servicename { if (getport(frc, $1, &($$)) == -1) + yyerror("service unknown"); + $$ = ntohs($$); + free($1); + } + | YY_NUMBER { if ($1 > 65535) /* Unsigned */ + yyerror("invalid port number"); + else + $$ = $1; + } + ; + +withlist: + withopt + | withlist withopt + | withlist ',' withopt + ; + +withopt: + opttype { DOALL(fr->fr_flx |= $1; fr->fr_mflx |= $1;) } + | notwith opttype + { DOALL(fr->fr_mflx |= $2;) } + | ipopt ipopts { yyresetdict(); } + | notwith ipopt ipopts { yyresetdict(); } + | startv6hdrs ipv6hdrs { yyresetdict(); } + ; + +ipopt: IPFY_OPT { yysetdict(ipv4optwords); } + ; + +startv6hdrs: + IPF6_V6HDRS { if (use_inet6 == 0) + yyerror("only available with IPv6"); + yysetdict(ipv6optwords); + } + ; + +notwith: + IPFY_NOT { nowith = 1; } + | IPFY_NO { nowith = 1; } + ; + +opttype: + IPFY_IPOPTS { $$ = FI_OPTIONS; } + | IPFY_SHORT { $$ = FI_SHORT; } + | IPFY_NAT { $$ = FI_NATED; } + | IPFY_BAD { $$ = FI_BAD; } + | IPFY_BADNAT { $$ = FI_BADNAT; } + | IPFY_BADSRC { $$ = FI_BADSRC; } + | IPFY_LOWTTL { $$ = FI_LOWTTL; } + | IPFY_FRAG { $$ = FI_FRAG; } + | IPFY_FRAGBODY { $$ = FI_FRAGBODY; } + | IPFY_FRAGS { $$ = FI_FRAG; } + | IPFY_MBCAST { $$ = FI_MBCAST; } + | IPFY_MULTICAST { $$ = FI_MULTICAST; } + | IPFY_BROADCAST { $$ = FI_BROADCAST; } + | IPFY_STATE { $$ = FI_STATE; } + | IPFY_OOW { $$ = FI_OOW; } + ; + +ipopts: optlist { DOALL(fr->fr_mip.fi_optmsk |= $1; + if (!nowith) + fr->fr_ip.fi_optmsk |= $1;) + } + ; + +optlist: + opt { $$ |= $1; } + | optlist ',' opt { $$ |= $1 | $3; } + ; + +ipv6hdrs: + ipv6hdrlist { DOALL(fr->fr_mip.fi_optmsk |= $1; + if (!nowith) + fr->fr_ip.fi_optmsk |= $1;) + } + ; + +ipv6hdrlist: + ipv6hdr { $$ |= $1; } + | ipv6hdrlist ',' ipv6hdr { $$ |= $1 | $3; } + ; + +secname: + seclevel { $$ |= $1; } + | secname ',' seclevel { $$ |= $1 | $3; } + ; + +seclevel: + IPFY_SEC_UNC { $$ = secbit(IPSO_CLASS_UNCL); } + | IPFY_SEC_CONF { $$ = secbit(IPSO_CLASS_CONF); } + | IPFY_SEC_RSV1 { $$ = secbit(IPSO_CLASS_RES1); } + | IPFY_SEC_RSV2 { $$ = secbit(IPSO_CLASS_RES2); } + | IPFY_SEC_RSV3 { $$ = secbit(IPSO_CLASS_RES3); } + | IPFY_SEC_RSV4 { $$ = secbit(IPSO_CLASS_RES4); } + | IPFY_SEC_SEC { $$ = secbit(IPSO_CLASS_SECR); } + | IPFY_SEC_TS { $$ = secbit(IPSO_CLASS_TOPS); } + ; + +icmptype: + YY_NUMBER { $$ = $1; } + | IPFY_ICMPT_UNR { $$ = ICMP_UNREACH; } + | IPFY_ICMPT_ECHO { $$ = ICMP_ECHO; } + | IPFY_ICMPT_ECHOR { $$ = ICMP_ECHOREPLY; } + | IPFY_ICMPT_SQUENCH { $$ = ICMP_SOURCEQUENCH; } + | IPFY_ICMPT_REDIR { $$ = ICMP_REDIRECT; } + | IPFY_ICMPT_TIMEX { $$ = ICMP_TIMXCEED; } + | IPFY_ICMPT_PARAMP { $$ = ICMP_PARAMPROB; } + | IPFY_ICMPT_TIMEST { $$ = ICMP_TSTAMP; } + | IPFY_ICMPT_TIMESTREP { $$ = ICMP_TSTAMPREPLY; } + | IPFY_ICMPT_INFOREQ { $$ = ICMP_IREQ; } + | IPFY_ICMPT_INFOREP { $$ = ICMP_IREQREPLY; } + | IPFY_ICMPT_MASKREQ { $$ = ICMP_MASKREQ; } + | IPFY_ICMPT_MASKREP { $$ = ICMP_MASKREPLY; } + | IPFY_ICMPT_ROUTERAD { $$ = ICMP_ROUTERADVERT; } + | IPFY_ICMPT_ROUTERSOL { $$ = ICMP_ROUTERSOLICIT; } + ; + +icmpcode: + YY_NUMBER { $$ = $1; } + | IPFY_ICMPC_NETUNR { $$ = ICMP_UNREACH_NET; } + | IPFY_ICMPC_HSTUNR { $$ = ICMP_UNREACH_HOST; } + | IPFY_ICMPC_PROUNR { $$ = ICMP_UNREACH_PROTOCOL; } + | IPFY_ICMPC_PORUNR { $$ = ICMP_UNREACH_PORT; } + | IPFY_ICMPC_NEEDF { $$ = ICMP_UNREACH_NEEDFRAG; } + | IPFY_ICMPC_SRCFAIL { $$ = ICMP_UNREACH_SRCFAIL; } + | IPFY_ICMPC_NETUNK { $$ = ICMP_UNREACH_NET_UNKNOWN; } + | IPFY_ICMPC_HSTUNK { $$ = ICMP_UNREACH_HOST_UNKNOWN; } + | IPFY_ICMPC_ISOLATE { $$ = ICMP_UNREACH_ISOLATED; } + | IPFY_ICMPC_NETPRO { $$ = ICMP_UNREACH_NET_PROHIB; } + | IPFY_ICMPC_HSTPRO { $$ = ICMP_UNREACH_HOST_PROHIB; } + | IPFY_ICMPC_NETTOS { $$ = ICMP_UNREACH_TOSNET; } + | IPFY_ICMPC_HSTTOS { $$ = ICMP_UNREACH_TOSHOST; } + | IPFY_ICMPC_FLTPRO { $$ = ICMP_UNREACH_ADMIN_PROHIBIT; } + | IPFY_ICMPC_HSTPRE { $$ = 14; } + | IPFY_ICMPC_CUTPRE { $$ = 15; } + ; + +opt: + IPFY_IPOPT_NOP { $$ = getoptbyvalue(IPOPT_NOP); } + | IPFY_IPOPT_RR { $$ = getoptbyvalue(IPOPT_RR); } + | IPFY_IPOPT_ZSU { $$ = getoptbyvalue(IPOPT_ZSU); } + | IPFY_IPOPT_MTUP { $$ = getoptbyvalue(IPOPT_MTUP); } + | IPFY_IPOPT_MTUR { $$ = getoptbyvalue(IPOPT_MTUR); } + | IPFY_IPOPT_ENCODE { $$ = getoptbyvalue(IPOPT_ENCODE); } + | IPFY_IPOPT_TS { $$ = getoptbyvalue(IPOPT_TS); } + | IPFY_IPOPT_TR { $$ = getoptbyvalue(IPOPT_TR); } + | IPFY_IPOPT_SEC { $$ = getoptbyvalue(IPOPT_SECURITY); } + | IPFY_IPOPT_LSRR { $$ = getoptbyvalue(IPOPT_LSRR); } + | IPFY_IPOPT_ESEC { $$ = getoptbyvalue(IPOPT_E_SEC); } + | IPFY_IPOPT_CIPSO { $$ = getoptbyvalue(IPOPT_CIPSO); } + | IPFY_IPOPT_SATID { $$ = getoptbyvalue(IPOPT_SATID); } + | IPFY_IPOPT_SSRR { $$ = getoptbyvalue(IPOPT_SSRR); } + | IPFY_IPOPT_ADDEXT { $$ = getoptbyvalue(IPOPT_ADDEXT); } + | IPFY_IPOPT_VISA { $$ = getoptbyvalue(IPOPT_VISA); } + | IPFY_IPOPT_IMITD { $$ = getoptbyvalue(IPOPT_IMITD); } + | IPFY_IPOPT_EIP { $$ = getoptbyvalue(IPOPT_EIP); } + | IPFY_IPOPT_FINN { $$ = getoptbyvalue(IPOPT_FINN); } + | IPFY_IPOPT_DPS { $$ = getoptbyvalue(IPOPT_DPS); } + | IPFY_IPOPT_SDB { $$ = getoptbyvalue(IPOPT_SDB); } + | IPFY_IPOPT_NSAPA { $$ = getoptbyvalue(IPOPT_NSAPA); } + | IPFY_IPOPT_RTRALRT { $$ = getoptbyvalue(IPOPT_RTRALRT); } + | IPFY_IPOPT_UMP { $$ = getoptbyvalue(IPOPT_UMP); } + | setsecclass secname + { DOALL(fr->fr_mip.fi_secmsk |= $2; + if (!nowith) + fr->fr_ip.fi_secmsk |= $2;) + $$ = 0; + yyresetdict(); + } + ; + +setsecclass: + IPFY_SECCLASS { yysetdict(ipv4secwords); } + ; + +ipv6hdr: + IPFY_AH { $$ = getv6optbyvalue(IPPROTO_AH); } + | IPFY_IPV6OPT_DSTOPTS { $$ = getv6optbyvalue(IPPROTO_DSTOPTS); } + | IPFY_ESP { $$ = getv6optbyvalue(IPPROTO_ESP); } + | IPFY_IPV6OPT_HOPOPTS { $$ = getv6optbyvalue(IPPROTO_HOPOPTS); } + | IPFY_IPV6OPT_IPV6 { $$ = getv6optbyvalue(IPPROTO_IPV6); } + | IPFY_IPV6OPT_NONE { $$ = getv6optbyvalue(IPPROTO_NONE); } + | IPFY_IPV6OPT_ROUTING { $$ = getv6optbyvalue(IPPROTO_ROUTING); } + | IPFY_FRAG { $$ = getv6optbyvalue(IPPROTO_FRAGMENT); } + ; + +level: IPFY_LEVEL { setsyslog(); } + ; + +loglevel: + priority { fr->fr_loglevel = LOG_LOCAL0|$1; } + | facility '.' priority { fr->fr_loglevel = $1 | $3; } + ; + +facility: + IPFY_FAC_KERN { $$ = LOG_KERN; } + | IPFY_FAC_USER { $$ = LOG_USER; } + | IPFY_FAC_MAIL { $$ = LOG_MAIL; } + | IPFY_FAC_DAEMON { $$ = LOG_DAEMON; } + | IPFY_FAC_AUTH { $$ = LOG_AUTH; } + | IPFY_FAC_SYSLOG { $$ = LOG_SYSLOG; } + | IPFY_FAC_LPR { $$ = LOG_LPR; } + | IPFY_FAC_NEWS { $$ = LOG_NEWS; } + | IPFY_FAC_UUCP { $$ = LOG_UUCP; } + | IPFY_FAC_CRON { $$ = LOG_CRON; } + | IPFY_FAC_FTP { $$ = LOG_FTP; } + | IPFY_FAC_AUTHPRIV { $$ = LOG_AUTHPRIV; } + | IPFY_FAC_AUDIT { $$ = LOG_AUDIT; } + | IPFY_FAC_LFMT { $$ = LOG_LFMT; } + | IPFY_FAC_LOCAL0 { $$ = LOG_LOCAL0; } + | IPFY_FAC_LOCAL1 { $$ = LOG_LOCAL1; } + | IPFY_FAC_LOCAL2 { $$ = LOG_LOCAL2; } + | IPFY_FAC_LOCAL3 { $$ = LOG_LOCAL3; } + | IPFY_FAC_LOCAL4 { $$ = LOG_LOCAL4; } + | IPFY_FAC_LOCAL5 { $$ = LOG_LOCAL5; } + | IPFY_FAC_LOCAL6 { $$ = LOG_LOCAL6; } + | IPFY_FAC_LOCAL7 { $$ = LOG_LOCAL7; } + | IPFY_FAC_SECURITY { $$ = LOG_SECURITY; } + ; + +priority: + IPFY_PRI_EMERG { $$ = LOG_EMERG; } + | IPFY_PRI_ALERT { $$ = LOG_ALERT; } + | IPFY_PRI_CRIT { $$ = LOG_CRIT; } + | IPFY_PRI_ERR { $$ = LOG_ERR; } + | IPFY_PRI_WARN { $$ = LOG_WARNING; } + | IPFY_PRI_NOTICE { $$ = LOG_NOTICE; } + | IPFY_PRI_INFO { $$ = LOG_INFO; } + | IPFY_PRI_DEBUG { $$ = LOG_DEBUG; } + ; + +compare: + YY_CMP_EQ { $$ = FR_EQUAL; } + | YY_CMP_NE { $$ = FR_NEQUAL; } + | YY_CMP_LT { $$ = FR_LESST; } + | YY_CMP_LE { $$ = FR_LESSTE; } + | YY_CMP_GT { $$ = FR_GREATERT; } + | YY_CMP_GE { $$ = FR_GREATERTE; } + ; + +range: YY_RANGE_IN { $$ = FR_INRANGE; } + | YY_RANGE_OUT { $$ = FR_OUTRANGE; } + | ':' { $$ = FR_INCRANGE; } + ; + +servicename: + YY_STR { $$ = $1; } + ; + +interfacename: YY_STR { $$ = $1; } + | YY_STR ':' YY_NUMBER + { $$ = $1; + fprintf(stderr, "%d: Logical interface %s:%d unsupported, " + "use the physical interface %s instead.\n", + yylineNum, $1, $3, $1); + } + ; + +name: YY_STR { $$ = $1; } + ; + +ipv4_16: + YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr = ($1 << 24) | ($3 << 16); + $$.s_addr = htonl($$.s_addr); + } + ; + +ipv4_24: + ipv4_16 '.' YY_NUMBER + { if ($3 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr |= htonl($3 << 8); + } + ; + +ipv4: ipv4_24 '.' YY_NUMBER + { if ($3 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr |= htonl($3); + } + | ipv4_24 + | ipv4_16 + ; + +%% + + +static struct wordtab ipfwords[95] = { + { "age", IPFY_AGE }, + { "ah", IPFY_AH }, + { "all", IPFY_ALL }, + { "and", IPFY_AND }, + { "auth", IPFY_AUTH }, + { "bad", IPFY_BAD }, + { "bad-nat", IPFY_BADNAT }, + { "bad-src", IPFY_BADSRC }, + { "bcast", IPFY_BROADCAST }, + { "block", IPFY_BLOCK }, + { "body", IPFY_BODY }, + { "bpf-v4", IPFY_BPFV4 }, +#ifdef USE_INET6 + { "bpf-v6", IPFY_BPFV6 }, +#endif + { "call", IPFY_CALL }, + { "code", IPFY_ICMPCODE }, + { "count", IPFY_COUNT }, + { "dup-to", IPFY_DUPTO }, + { "eq", YY_CMP_EQ }, + { "esp", IPFY_ESP }, + { "fastroute", IPFY_FROUTE }, + { "first", IPFY_FIRST }, + { "flags", IPFY_FLAGS }, + { "frag", IPFY_FRAG }, + { "frag-body", IPFY_FRAGBODY }, + { "frags", IPFY_FRAGS }, + { "from", IPFY_FROM }, + { "ge", YY_CMP_GE }, + { "group", IPFY_GROUP }, + { "gt", YY_CMP_GT }, + { "head", IPFY_HEAD }, + { "icmp", IPFY_ICMP }, + { "icmp-type", IPFY_ICMPTYPE }, + { "in", IPFY_IN }, + { "in-via", IPFY_INVIA }, + { "ipopt", IPFY_IPOPTS }, + { "ipopts", IPFY_IPOPTS }, + { "keep", IPFY_KEEP }, + { "le", YY_CMP_LE }, + { "level", IPFY_LEVEL }, + { "limit", IPFY_LIMIT }, + { "log", IPFY_LOG }, + { "lowttl", IPFY_LOWTTL }, + { "lt", YY_CMP_LT }, + { "mask", IPFY_MASK }, + { "match-tag", IPFY_MATCHTAG }, + { "mbcast", IPFY_MBCAST }, + { "multicast", IPFY_MULTICAST }, + { "nat", IPFY_NAT }, + { "ne", YY_CMP_NE }, + { "net", IPFY_NETWORK }, + { "newisn", IPFY_NEWISN }, + { "no", IPFY_NO }, + { "no-icmp-err", IPFY_NOICMPERR }, + { "now", IPFY_NOW }, + { "not", IPFY_NOT }, + { "oow", IPFY_OOW }, + { "on", IPFY_ON }, + { "opt", IPFY_OPT }, + { "or-block", IPFY_ORBLOCK }, + { "out", IPFY_OUT }, + { "out-via", IPFY_OUTVIA }, + { "pass", IPFY_PASS }, + { "port", IPFY_PORT }, + { "pps", IPFY_PPS }, + { "preauth", IPFY_PREAUTH }, + { "proto", IPFY_PROTO }, + { "quick", IPFY_QUICK }, + { "reply-to", IPFY_REPLY_TO }, + { "return-icmp", IPFY_RETICMP }, + { "return-icmp-as-dest", IPFY_RETICMPASDST }, + { "return-rst", IPFY_RETRST }, + { "route-to", IPFY_ROUTETO }, + { "sec-class", IPFY_SECCLASS }, + { "set-tag", IPFY_SETTAG }, + { "skip", IPFY_SKIP }, + { "short", IPFY_SHORT }, + { "state", IPFY_STATE }, + { "state-age", IPFY_AGE }, + { "strict", IPFY_STRICT }, + { "sync", IPFY_SYNC }, + { "tcp", IPFY_TCP }, + { "tcp-udp", IPFY_TCPUDP }, + { "tos", IPFY_TOS }, + { "to", IPFY_TO }, + { "ttl", IPFY_TTL }, + { "udp", IPFY_UDP }, + { "v6hdrs", IPF6_V6HDRS }, + { "with", IPFY_WITH }, + { NULL, 0 } +}; + +static struct wordtab addrwords[4] = { + { "any", IPFY_ANY }, + { "hash", IPFY_HASH }, + { "pool", IPFY_POOL }, + { NULL, 0 } +}; + +static struct wordtab maskwords[5] = { + { "broadcast", IPFY_BROADCAST }, + { "netmasked", IPFY_NETMASKED }, + { "network", IPFY_NETWORK }, + { "peer", IPFY_PEER }, + { NULL, 0 } +}; + +static struct wordtab icmptypewords[16] = { + { "echo", IPFY_ICMPT_ECHO }, + { "echorep", IPFY_ICMPT_ECHOR }, + { "inforeq", IPFY_ICMPT_INFOREQ }, + { "inforep", IPFY_ICMPT_INFOREP }, + { "maskrep", IPFY_ICMPT_MASKREP }, + { "maskreq", IPFY_ICMPT_MASKREQ }, + { "paramprob", IPFY_ICMPT_PARAMP }, + { "redir", IPFY_ICMPT_REDIR }, + { "unreach", IPFY_ICMPT_UNR }, + { "routerad", IPFY_ICMPT_ROUTERAD }, + { "routersol", IPFY_ICMPT_ROUTERSOL }, + { "squench", IPFY_ICMPT_SQUENCH }, + { "timest", IPFY_ICMPT_TIMEST }, + { "timestrep", IPFY_ICMPT_TIMESTREP }, + { "timex", IPFY_ICMPT_TIMEX }, + { NULL, 0 }, +}; + +static struct wordtab icmpcodewords[17] = { + { "cutoff-preced", IPFY_ICMPC_CUTPRE }, + { "filter-prohib", IPFY_ICMPC_FLTPRO }, + { "isolate", IPFY_ICMPC_ISOLATE }, + { "needfrag", IPFY_ICMPC_NEEDF }, + { "net-prohib", IPFY_ICMPC_NETPRO }, + { "net-tos", IPFY_ICMPC_NETTOS }, + { "host-preced", IPFY_ICMPC_HSTPRE }, + { "host-prohib", IPFY_ICMPC_HSTPRO }, + { "host-tos", IPFY_ICMPC_HSTTOS }, + { "host-unk", IPFY_ICMPC_HSTUNK }, + { "host-unr", IPFY_ICMPC_HSTUNR }, + { "net-unk", IPFY_ICMPC_NETUNK }, + { "net-unr", IPFY_ICMPC_NETUNR }, + { "port-unr", IPFY_ICMPC_PORUNR }, + { "proto-unr", IPFY_ICMPC_PROUNR }, + { "srcfail", IPFY_ICMPC_SRCFAIL }, + { NULL, 0 }, +}; + +static struct wordtab ipv4optwords[25] = { + { "addext", IPFY_IPOPT_ADDEXT }, + { "cipso", IPFY_IPOPT_CIPSO }, + { "dps", IPFY_IPOPT_DPS }, + { "e-sec", IPFY_IPOPT_ESEC }, + { "eip", IPFY_IPOPT_EIP }, + { "encode", IPFY_IPOPT_ENCODE }, + { "finn", IPFY_IPOPT_FINN }, + { "imitd", IPFY_IPOPT_IMITD }, + { "lsrr", IPFY_IPOPT_LSRR }, + { "mtup", IPFY_IPOPT_MTUP }, + { "mtur", IPFY_IPOPT_MTUR }, + { "nop", IPFY_IPOPT_NOP }, + { "nsapa", IPFY_IPOPT_NSAPA }, + { "rr", IPFY_IPOPT_RR }, + { "rtralrt", IPFY_IPOPT_RTRALRT }, + { "satid", IPFY_IPOPT_SATID }, + { "sdb", IPFY_IPOPT_SDB }, + { "sec", IPFY_IPOPT_SEC }, + { "ssrr", IPFY_IPOPT_SSRR }, + { "tr", IPFY_IPOPT_TR }, + { "ts", IPFY_IPOPT_TS }, + { "ump", IPFY_IPOPT_UMP }, + { "visa", IPFY_IPOPT_VISA }, + { "zsu", IPFY_IPOPT_ZSU }, + { NULL, 0 }, +}; + +static struct wordtab ipv4secwords[9] = { + { "confid", IPFY_SEC_CONF }, + { "reserv-1", IPFY_SEC_RSV1 }, + { "reserv-2", IPFY_SEC_RSV2 }, + { "reserv-3", IPFY_SEC_RSV3 }, + { "reserv-4", IPFY_SEC_RSV4 }, + { "secret", IPFY_SEC_SEC }, + { "topsecret", IPFY_SEC_TS }, + { "unclass", IPFY_SEC_UNC }, + { NULL, 0 }, +}; + +static struct wordtab ipv6optwords[8] = { + { "dstopts", IPFY_IPV6OPT_DSTOPTS }, + { "esp", IPFY_ESP }, + { "frag", IPFY_FRAG }, + { "hopopts", IPFY_IPV6OPT_HOPOPTS }, + { "ipv6", IPFY_IPV6OPT_IPV6 }, + { "none", IPFY_IPV6OPT_NONE }, + { "routing", IPFY_IPV6OPT_ROUTING }, + { NULL, 0 }, +}; + +static struct wordtab logwords[33] = { + { "kern", IPFY_FAC_KERN }, + { "user", IPFY_FAC_USER }, + { "mail", IPFY_FAC_MAIL }, + { "daemon", IPFY_FAC_DAEMON }, + { "auth", IPFY_FAC_AUTH }, + { "syslog", IPFY_FAC_SYSLOG }, + { "lpr", IPFY_FAC_LPR }, + { "news", IPFY_FAC_NEWS }, + { "uucp", IPFY_FAC_UUCP }, + { "cron", IPFY_FAC_CRON }, + { "ftp", IPFY_FAC_FTP }, + { "authpriv", IPFY_FAC_AUTHPRIV }, + { "audit", IPFY_FAC_AUDIT }, + { "logalert", IPFY_FAC_LFMT }, + { "console", IPFY_FAC_CONSOLE }, + { "security", IPFY_FAC_SECURITY }, + { "local0", IPFY_FAC_LOCAL0 }, + { "local1", IPFY_FAC_LOCAL1 }, + { "local2", IPFY_FAC_LOCAL2 }, + { "local3", IPFY_FAC_LOCAL3 }, + { "local4", IPFY_FAC_LOCAL4 }, + { "local5", IPFY_FAC_LOCAL5 }, + { "local6", IPFY_FAC_LOCAL6 }, + { "local7", IPFY_FAC_LOCAL7 }, + { "emerg", IPFY_PRI_EMERG }, + { "alert", IPFY_PRI_ALERT }, + { "crit", IPFY_PRI_CRIT }, + { "err", IPFY_PRI_ERR }, + { "warn", IPFY_PRI_WARN }, + { "notice", IPFY_PRI_NOTICE }, + { "info", IPFY_PRI_INFO }, + { "debug", IPFY_PRI_DEBUG }, + { NULL, 0 }, +}; + + + + +int ipf_parsefile(fd, addfunc, iocfuncs, filename) +int fd; +addfunc_t addfunc; +ioctlfunc_t *iocfuncs; +char *filename; +{ + FILE *fp = NULL; + char *s; + + yylineNum = 1; + yysettab(ipfwords); + + s = getenv("YYDEBUG"); + if (s != NULL) + yydebug = atoi(s); + else + yydebug = 0; + + if (strcmp(filename, "-")) { + fp = fopen(filename, "r"); + if (fp == NULL) { + fprintf(stderr, "fopen(%s) failed: %s\n", filename, + STRERROR(errno)); + return -1; + } + } else + fp = stdin; + + while (ipf_parsesome(fd, addfunc, iocfuncs, fp) == 1) + ; + if (fp != NULL) + fclose(fp); + return 0; +} + + +int ipf_parsesome(fd, addfunc, iocfuncs, fp) +int fd; +addfunc_t addfunc; +ioctlfunc_t *iocfuncs; +FILE *fp; +{ + char *s; + int i; + + ipffd = fd; + for (i = 0; i <= IPL_LOGMAX; i++) + ipfioctl[i] = iocfuncs[i]; + ipfaddfunc = addfunc; + + if (feof(fp)) + return 0; + i = fgetc(fp); + if (i == EOF) + return 0; + if (ungetc(i, fp) == 0) + return 0; + if (feof(fp)) + return 0; + s = getenv("YYDEBUG"); + if (s != NULL) + yydebug = atoi(s); + else + yydebug = 0; + + yyin = fp; + yyparse(); + return 1; +} + + +static void newrule() +{ + frentry_t *frn; + + frn = (frentry_t *)calloc(1, sizeof(frentry_t)); + for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next) + ; + if (fr != NULL) + fr->fr_next = frn; + if (frtop == NULL) + frtop = frn; + fr = frn; + frc = frn; + fr->fr_loglevel = 0xffff; + fr->fr_isc = (void *)-1; + fr->fr_logtag = FR_NOLOGTAG; + fr->fr_type = FR_T_NONE; + if (use_inet6 != 0) + fr->fr_v = 6; + else + fr->fr_v = 4; + + nrules = 1; +} + + +static void setipftype() +{ + for (fr = frc; fr != NULL; fr = fr->fr_next) { + if (fr->fr_type == FR_T_NONE) { + fr->fr_type = FR_T_IPF; + fr->fr_data = (void *)calloc(sizeof(fripf_t), 1); + fr->fr_dsize = sizeof(fripf_t); + fr->fr_ip.fi_v = frc->fr_v; + fr->fr_mip.fi_v = 0xf; + fr->fr_ipf->fri_sifpidx = -1; + fr->fr_ipf->fri_difpidx = -1; + } + if (fr->fr_type != FR_T_IPF) { + fprintf(stderr, "IPF Type not set\n"); + } + } +} + + +static frentry_t *addrule() +{ + frentry_t *f, *f1, *f2; + int count; + + for (f2 = frc; f2->fr_next != NULL; f2 = f2->fr_next) + ; + + count = nrules; + if (count == 0) { + f = (frentry_t *)calloc(sizeof(*f), 1); + added++; + f2->fr_next = f; + bcopy(f2, f, sizeof(*f)); + if (f2->fr_caddr != NULL) { + f->fr_caddr = malloc(f->fr_dsize); + bcopy(f2->fr_caddr, f->fr_caddr, f->fr_dsize); + } + f->fr_next = NULL; + return f; + } + f = f2; + for (f1 = frc; count > 0; count--, f1 = f1->fr_next) { + f->fr_next = (frentry_t *)calloc(sizeof(*f), 1); + added++; + f = f->fr_next; + bcopy(f1, f, sizeof(*f)); + f->fr_next = NULL; + if (f->fr_caddr != NULL) { + f->fr_caddr = malloc(f->fr_dsize); + bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize); + } + } + + return f2->fr_next; +} + + +static u_32_t lookuphost(name) +char *name; +{ + u_32_t addr; + int i; + + hashed = 0; + pooled = 0; + dynamic = -1; + + for (i = 0; i < 4; i++) { + if (strncmp(name, frc->fr_ifnames[i], + sizeof(frc->fr_ifnames[i])) == 0) { + ifpflag = FRI_DYNAMIC; + dynamic = i; + return 0; + } + } + + if (gethost(name, &addr) == -1) { + fprintf(stderr, "unknown name \"%s\"\n", name); + return 0; + } + return addr; +} + + +static void dobpf(v, phrase) +int v; +char *phrase; +{ +#ifdef IPFILTER_BPF + struct bpf_program bpf; + struct pcap *p; +#endif + fakebpf_t *fb; + u_32_t l; + char *s; + int i; + + for (fr = frc; fr != NULL; fr = fr->fr_next) { + if (fr->fr_type != FR_T_NONE) { + fprintf(stderr, "cannot mix IPF and BPF matching\n"); + return; + } + fr->fr_v = v; + fr->fr_type = FR_T_BPFOPC; + + if (!strncmp(phrase, "\"0x", 2)) { + phrase++; + fb = malloc(sizeof(fakebpf_t)); + + for (i = 0, s = strtok(phrase, " \r\n\t"); s != NULL; + s = strtok(NULL, " \r\n\t"), i++) { + fb = realloc(fb, (i / 4 + 1) * sizeof(*fb)); + l = (u_32_t)strtol(s, NULL, 0); + switch (i & 3) + { + case 0 : + fb[i / 4].fb_c = l & 0xffff; + break; + case 1 : + fb[i / 4].fb_t = l & 0xff; + break; + case 2 : + fb[i / 4].fb_f = l & 0xff; + break; + case 3 : + fb[i / 4].fb_k = l; + break; + } + } + if ((i & 3) != 0) { + fprintf(stderr, + "Odd number of bytes in BPF code\n"); + exit(1); + } + i--; + fr->fr_dsize = (i / 4 + 1) * sizeof(*fb); + fr->fr_data = fb; + return; + } + +#ifdef IPFILTER_BPF + bzero((char *)&bpf, sizeof(bpf)); + p = pcap_open_dead(DLT_RAW, 1); + if (!p) { + fprintf(stderr, "pcap_open_dead failed\n"); + return; + } + + if (pcap_compile(p, &bpf, phrase, 1, 0xffffffff)) { + pcap_perror(p, "ipf"); + pcap_close(p); + fprintf(stderr, "pcap parsing failed (%s)\n", phrase); + return; + } + pcap_close(p); + + fr->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn); + fr->fr_data = malloc(fr->fr_dsize); + bcopy((char *)bpf.bf_insns, fr->fr_data, fr->fr_dsize); + if (!bpf_validate(fr->fr_data, bpf.bf_len)) { + fprintf(stderr, "BPF validation failed\n"); + return; + } +#endif + } + +#ifdef IPFILTER_BPF + if (opts & OPT_DEBUG) + bpf_dump(&bpf, 0); +#else + fprintf(stderr, "BPF filter expressions not supported\n"); + exit(1); +#endif +} + + +static void resetaddr() +{ + hashed = 0; + pooled = 0; + dynamic = -1; +} + + +static alist_t *newalist(ptr) +alist_t *ptr; +{ + alist_t *al; + + al = malloc(sizeof(*al)); + if (al == NULL) + return NULL; + al->al_not = 0; + al->al_next = ptr; + return al; +} + + +static int makepool(list) +alist_t *list; +{ + ip_pool_node_t *n, *top; + ip_pool_t pool; + alist_t *a; + int num; + + if (list == NULL) + return 0; + top = calloc(1, sizeof(*top)); + if (top == NULL) + return 0; + + for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) { + n->ipn_addr.adf_addr.in4.s_addr = a->al_1; + n->ipn_mask.adf_addr.in4.s_addr = a->al_2; + n->ipn_info = a->al_not; + if (a->al_next != NULL) { + n->ipn_next = calloc(1, sizeof(*n)); + n = n->ipn_next; + } + } + + bzero((char *)&pool, sizeof(pool)); + pool.ipo_unit = IPL_LOGIPF; + pool.ipo_list = top; + num = load_pool(&pool, ipfioctl[IPL_LOGLOOKUP]); + + while ((n = top) != NULL) { + top = n->ipn_next; + free(n); + } + return num; +} + + +static u_int makehash(list) +alist_t *list; +{ + iphtent_t *n, *top; + iphtable_t iph; + alist_t *a; + int num; + + if (list == NULL) + return 0; + top = calloc(1, sizeof(*top)); + if (top == NULL) + return 0; + + for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) { + n->ipe_addr.in4_addr = a->al_1; + n->ipe_mask.in4_addr = a->al_2; + n->ipe_value = 0; + if (a->al_next != NULL) { + n->ipe_next = calloc(1, sizeof(*n)); + n = n->ipe_next; + } + } + + bzero((char *)&iph, sizeof(iph)); + iph.iph_unit = IPL_LOGIPF; + iph.iph_type = IPHASH_LOOKUP; + *iph.iph_name = '\0'; + + if (load_hash(&iph, top, ipfioctl[IPL_LOGLOOKUP]) == 0) + sscanf(iph.iph_name, "%u", &num); + else + num = 0; + + while ((n = top) != NULL) { + top = n->ipe_next; + free(n); + } + return num; +} + + +void ipf_addrule(fd, ioctlfunc, ptr) +int fd; +ioctlfunc_t ioctlfunc; +void *ptr; +{ + ioctlcmd_t add, del; + frentry_t *fr; + ipfobj_t obj; + + fr = ptr; + add = 0; + del = 0; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*fr); + obj.ipfo_type = IPFOBJ_FRENTRY; + obj.ipfo_ptr = ptr; + + if ((opts & OPT_DONOTHING) != 0) + fd = -1; + + if (opts & OPT_ZERORULEST) { + add = SIOCZRLST; + } else if (opts & OPT_INACTIVE) { + add = (u_int)fr->fr_hits ? SIOCINIFR : + SIOCADIFR; + del = SIOCRMIFR; + } else { + add = (u_int)fr->fr_hits ? SIOCINAFR : + SIOCADAFR; + del = SIOCRMAFR; + } + + if (fr && (opts & OPT_OUTQUE)) + fr->fr_flags |= FR_OUTQUE; + if (fr->fr_hits) + fr->fr_hits--; + if (fr && (opts & OPT_VERBOSE)) + printfr(fr, ioctlfunc); + + if (opts & OPT_DEBUG) { + binprint(fr, sizeof(*fr)); + if (fr->fr_data != NULL) + binprint(fr->fr_data, fr->fr_dsize); + } + + if ((opts & OPT_ZERORULEST) != 0) { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + fprintf(stderr, "%d:", yylineNum); + 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 ", + fr->fr_hits, fr->fr_bytes); +#endif + printfr(fr, ioctlfunc); + } + } else if ((opts & OPT_REMOVE) != 0) { + if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) != 0) { + fprintf(stderr, "%d:", yylineNum); + perror("ioctl(delete rule)"); + } + } + } else { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if (!(opts & OPT_DONOTHING)) { + fprintf(stderr, "%d:", yylineNum); + perror("ioctl(add/insert rule)"); + } + } + } +} + +static void setsyslog() +{ + yysetdict(logwords); + yybreakondot = 1; +} + + +static void unsetsyslog() +{ + yyresetdict(); + yybreakondot = 0; +} + + +static void fillgroup(fr) +frentry_t *fr; +{ + frentry_t *f; + + for (f = frold; f != NULL; f = f->fr_next) + if (strncmp(f->fr_grhead, fr->fr_group, FR_GROUPLEN) == 0) + break; + if (f == NULL) + return; + + /* + * Only copy down matching fields if the rules are of the same type + * and are of ipf type. The only fields that are copied are those + * that impact the rule parsing itself, eg. need for knowing what the + * protocol should be for rules with port comparisons in them. + */ + if (f->fr_type != fr->fr_type || f->fr_type != FR_T_IPF) + return; + + if (fr->fr_v == 0 && f->fr_v != 0) + fr->fr_v = f->fr_v; + + if (fr->fr_mproto == 0 && f->fr_mproto != 0) + fr->fr_mproto = f->fr_mproto; + if (fr->fr_proto == 0 && f->fr_proto != 0) + fr->fr_proto = f->fr_proto; + + if ((fr->fr_mproto == 0) && ((fr->fr_flx & FI_TCPUDP) == 0) && + ((f->fr_flx & FI_TCPUDP) != 0)) + fr->fr_flx |= FI_TCPUDP; +} diff --git a/contrib/ipfilter/tools/ipfcomp.c b/contrib/ipfilter/tools/ipfcomp.c new file mode 100644 index 0000000..262e909 --- /dev/null +++ b/contrib/ipfilter/tools/ipfcomp.c @@ -0,0 +1,1347 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipfcomp.c,v 1.24.2.2 2004/04/28 10:34:44 darrenr Exp"; +#endif + +#include "ipf.h" + + +typedef struct { + int c; + int e; + int n; + int p; + int s; +} mc_t; + + +static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" }; +static int count = 0; + +int intcmp __P((const void *, const void *)); +static void indent __P((FILE *, int)); +static void printeq __P((FILE *, char *, int, int, int)); +static void printipeq __P((FILE *, char *, int, int, int)); +static void addrule __P((FILE *, frentry_t *)); +static void printhooks __P((FILE *, int, int, frgroup_t *)); +static void emitheader __P((frgroup_t *, u_int, u_int)); +static void emitGroup __P((int, int, void *, frentry_t *, char *, + u_int, u_int)); +static void emittail __P((void)); +static void printCgroup __P((int, frentry_t *, mc_t *, char *)); + +#define FRC_IFN 0 +#define FRC_V 1 +#define FRC_P 2 +#define FRC_FL 3 +#define FRC_TOS 4 +#define FRC_TTL 5 +#define FRC_SRC 6 +#define FRC_DST 7 +#define FRC_TCP 8 +#define FRC_SP 9 +#define FRC_DP 10 +#define FRC_OPT 11 +#define FRC_SEC 12 +#define FRC_ATH 13 +#define FRC_ICT 14 +#define FRC_ICC 15 +#define FRC_MAX 16 + + +static FILE *cfile = NULL; + +/* + * This is called once per filter rule being loaded to emit data structures + * required. + */ +void printc(fr) +frentry_t *fr; +{ + fripf_t *ipf; + u_long *ulp; + char *and; + FILE *fp; + int i; + + if (fr->fr_v != 4) + return; + if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE)) + return; + if ((fr->fr_type == FR_T_IPF) && + ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL))) + return; + ipf = fr->fr_ipf; + + if (cfile == NULL) + cfile = fopen("ip_rules.c", "w"); + if (cfile == NULL) + return; + fp = cfile; + if (count == 0) { + fprintf(fp, "/*\n"); + fprintf(fp, "* Copyright (C) 1993-2000 by Darren Reed.\n"); + fprintf(fp, "*\n"); + fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n"); + fprintf(fp, "* provided that this notice is preserved and due credit is given\n"); + fprintf(fp, "* to the original author and the contributors.\n"); + fprintf(fp, "*/\n\n"); + + fprintf(fp, "#include <sys/types.h>\n"); + fprintf(fp, "#include <sys/time.h>\n"); + fprintf(fp, "#include <sys/socket.h>\n"); + fprintf(fp, "#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n"); + fprintf(fp, "# include <sys/systm.h>\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "#include <sys/errno.h>\n"); + fprintf(fp, "#include <sys/param.h>\n"); + fprintf(fp, +"#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n"); + fprintf(fp, "# include <sys/mbuf.h>\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, +"#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n"); + fprintf(fp, "# include <sys/sockio.h>\n"); + fprintf(fp, "#else\n"); + fprintf(fp, "# include <sys/ioctl.h>\n"); + fprintf(fp, "#endif /* FreeBSD */\n"); + fprintf(fp, "#include <net/if.h>\n"); + fprintf(fp, "#include <netinet/in.h>\n"); + fprintf(fp, "#include <netinet/in_systm.h>\n"); + fprintf(fp, "#include <netinet/ip.h>\n"); + fprintf(fp, "#include <netinet/tcp.h>\n"); + fprintf(fp, "#include \"netinet/ip_compat.h\"\n"); + fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n"); + fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n"); + fprintf(fp, "#ifndef _KERNEL\n"); + fprintf(fp, "# include <string.h>\n"); + fprintf(fp, "#endif /* _KERNEL */\n"); + fprintf(fp, "\n"); + fprintf(fp, "#ifdef IPFILTER_COMPILED\n"); + } + + addrule(fp, fr); + fr->fr_type |= FR_T_BUILTIN; + and = ""; + fr->fr_ref = 1; + i = sizeof(*fr); + if (i & -(1 - sizeof(*ulp))) + i += sizeof(u_long); + for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) { + fprintf(fp, "%s%#lx", and, *ulp++); + and = ", "; + } + fprintf(fp, "\n};\n"); + fr->fr_type &= ~FR_T_BUILTIN; + + count++; + + fflush(fp); +} + + +static frgroup_t *groups = NULL; + + +static void addrule(fp, fr) +FILE *fp; +frentry_t *fr; +{ + frentry_t *f, **fpp; + frgroup_t *g; + u_long *ulp; + char *and; + int i; + + f = (frentry_t *)malloc(sizeof(*f)); + bcopy((char *)fr, (char *)f, sizeof(*fr)); + if (fr->fr_ipf) { + f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf)); + bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf, + sizeof(*fr->fr_ipf)); + } + + f->fr_next = NULL; + for (g = groups; g != NULL; g = g->fg_next) + if ((strncmp(g->fg_name, f->fr_group, FR_GROUPLEN) == 0) && + (g->fg_flags == (f->fr_flags & FR_INOUT))) + break; + + if (g == NULL) { + g = (frgroup_t *)calloc(1, sizeof(*g)); + g->fg_next = groups; + groups = g; + g->fg_head = f; + bcopy(f->fr_group, g->fg_name, FR_GROUPLEN); + g->fg_ref = 0; + g->fg_flags = f->fr_flags & FR_INOUT; + } + + for (fpp = &g->fg_start; *fpp != NULL; ) + fpp = &((*fpp)->fr_next); + *fpp = f; + + if (fr->fr_dsize > 0) { + fprintf(fp, "\ +static u_long ipf%s_rule_data_%s_%u[] = {\n", + f->fr_flags & FR_INQUE ? "in" : "out", + g->fg_name, g->fg_ref); + and = ""; + i = fr->fr_dsize; + ulp = fr->fr_data; + for (i /= sizeof(u_long); i > 0; i--) { + fprintf(fp, "%s%#lx", and, *ulp++); + and = ", "; + } + fprintf(fp, "\n};\n"); + } + + fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n", + f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref); + + g->fg_ref++; + + if (f->fr_grhead != 0) { + for (g = groups; g != NULL; g = g->fg_next) + if ((strncmp(g->fg_name, f->fr_grhead, + FR_GROUPLEN) == 0) && + g->fg_flags == (f->fr_flags & FR_INOUT)) + break; + if (g == NULL) { + g = (frgroup_t *)calloc(1, sizeof(*g)); + g->fg_next = groups; + groups = g; + g->fg_head = f; + bcopy(f->fr_grhead, g->fg_name, FR_GROUPLEN); + g->fg_ref = 0; + g->fg_flags = f->fr_flags & FR_INOUT; + } + } +} + + +int intcmp(c1, c2) +const void *c1, *c2; +{ + const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2; + + if (i1->n == i2->n) { + return i1->c - i2->c; + } + return i2->n - i1->n; +} + + +static void indent(fp, in) +FILE *fp; +int in; +{ + for (; in; in--) + fputc('\t', fp); +} + +static void printeq(fp, var, m, max, v) +FILE *fp; +char *var; +int m, max, v; +{ + if (m == max) + fprintf(fp, "%s == %#x) {\n", var, v); + else + fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v); +} + +/* + * Parameters: var - IP# being compared + * fl - 0 for positive match, 1 for negative match + * m - netmask + * v - required address + */ +static void printipeq(fp, var, fl, m, v) +FILE *fp; +char *var; +int fl, m, v; +{ + if (m == 0xffffffff) + fprintf(fp, "%s ", var); + else + fprintf(fp, "(%s & %#x) ", var, m); + fprintf(fp, "%c", fl ? '!' : '='); + fprintf(fp, "= %#x) {\n", v); +} + + +void emit(num, dir, v, fr) +int num, dir; +void *v; +frentry_t *fr; +{ + u_int incnt, outcnt; + frgroup_t *g; + frentry_t *f; + + for (g = groups; g != NULL; g = g->fg_next) { + if (dir == 0 || dir == -1) { + if ((g->fg_flags & FR_INQUE) == 0) + continue; + for (incnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + incnt++; + emitGroup(num, dir, v, fr, g->fg_name, incnt, 0); + } + if (dir == 1 || dir == -1) { + if ((g->fg_flags & FR_OUTQUE) == 0) + continue; + for (outcnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + outcnt++; + emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt); + } + } + + if (num == -1 && dir == -1) { + for (g = groups; g != NULL; g = g->fg_next) { + if ((g->fg_flags & FR_INQUE) != 0) { + for (incnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + incnt++; + if (incnt > 0) + emitheader(g, incnt, 0); + } + if ((g->fg_flags & FR_OUTQUE) != 0) { + for (outcnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + outcnt++; + if (outcnt > 0) + emitheader(g, 0, outcnt); + } + } + emittail(); + fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n"); + } + +} + + +static void emitheader(grp, incount, outcount) +frgroup_t *grp; +u_int incount, outcount; +{ + static FILE *fph = NULL; + frgroup_t *g; + + if (fph == NULL) { + fph = fopen("ip_rules.h", "w"); + if (fph == NULL) + return; + + fprintf(fph, "extern int ipfrule_add __P((void));\n"); + fprintf(fph, "extern int ipfrule_remove __P((void));\n"); + } + + printhooks(cfile, incount, outcount, grp); + + if (incount) { + fprintf(fph, "\n\ +extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\ +extern frentry_t *ipf_rules_in_%s[%d];\n", + grp->fg_name, grp->fg_name, incount); + + for (g = groups; g != grp; g = g->fg_next) + if ((strncmp(g->fg_name, grp->fg_name, + FR_GROUPLEN) == 0) && + g->fg_flags == grp->fg_flags) + break; + if (g == grp) { + fprintf(fph, "\n\ +extern int ipfrule_add_in_%s __P((void));\n\ +extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name); + } + } + if (outcount) { + fprintf(fph, "\n\ +extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\ +extern frentry_t *ipf_rules_out_%s[%d];\n", + grp->fg_name, grp->fg_name, outcount); + + for (g = groups; g != g; g = g->fg_next) + if ((strncmp(g->fg_name, grp->fg_name, + FR_GROUPLEN) == 0) && + g->fg_flags == grp->fg_flags) + break; + if (g == grp) { + fprintf(fph, "\n\ +extern int ipfrule_add_out_%s __P((void));\n\ +extern int ipfrule_remove_out_%s __P((void));\n", + grp->fg_name, grp->fg_name); + } + } +} + +static void emittail() +{ + frgroup_t *g; + + fprintf(cfile, "\n\ +int ipfrule_add()\n\ +{\n\ + int err;\n\ +\n"); + for (g = groups; g != NULL; g = g->fg_next) + fprintf(cfile, "\ + err = ipfrule_add_%s_%s();\n\ + if (err != 0)\n\ + return err;\n", + (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); + fprintf(cfile, "\ + return 0;\n"); + fprintf(cfile, "}\n\ +\n"); + + fprintf(cfile, "\n\ +int ipfrule_remove()\n\ +{\n\ + int err;\n\ +\n"); + for (g = groups; g != NULL; g = g->fg_next) + fprintf(cfile, "\ + err = ipfrule_remove_%s_%s();\n\ + if (err != 0)\n\ + return err;\n", + (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); + fprintf(cfile, "\ + return 0;\n"); + fprintf(cfile, "}\n"); +} + + +static void emitGroup(num, dir, v, fr, group, incount, outcount) +int num, dir; +void *v; +frentry_t *fr; +char *group; +u_int incount, outcount; +{ + static FILE *fp = NULL; + static int header[2] = { 0, 0 }; + static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static int openfunc = 0; + static mc_t *n = NULL; + static int sin = 0; + frentry_t *f; + frgroup_t *g; + fripf_t *ipf; + int i, in, j; + mc_t *m = v; + + if (fp == NULL) + fp = cfile; + if (fp == NULL) + return; + if (strncmp(egroup, group, FR_GROUPLEN)) { + for (sin--; sin > 0; sin--) { + indent(fp, sin); + fprintf(fp, "}\n"); + } + if (openfunc == 1) { + fprintf(fp, "\treturn fr;\n}\n"); + openfunc = 0; + if (n != NULL) { + free(n); + n = NULL; + } + } + sin = 0; + header[0] = 0; + header[1] = 0; + strncpy(egroup, group, FR_GROUPLEN); + } else if (openfunc == 1 && num < 0) { + if (n != NULL) { + free(n); + n = NULL; + } + for (sin--; sin > 0; sin--) { + indent(fp, sin); + fprintf(fp, "}\n"); + } + if (openfunc == 1) { + fprintf(fp, "\treturn fr;\n}\n"); + openfunc = 0; + } + } + + if (dir == -1) + return; + + for (g = groups; g != NULL; g = g->fg_next) { + if (dir == 0 && (g->fg_flags & FR_INQUE) == 0) + continue; + else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0) + continue; + if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0) + continue; + break; + } + + /* + * Output the array of pointers to rules for this group. + */ + if (num == -2 && dir == 0 && header[0] == 0 && incount != 0) { + fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {", + group, incount); + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if ((f->fr_flags & FR_INQUE) == 0) + continue; + if ((i & 1) == 0) { + fprintf(fp, "\n\t"); + } + fprintf(fp, + "(frentry_t *)&in_rule_%s_%d", + f->fr_group, i); + if (i + 1 < incount) + fprintf(fp, ", "); + i++; + } + fprintf(fp, "\n};\n"); + } + + if (num == -2 && dir == 1 && header[1] == 0 && outcount != 0) { + fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {", + group, outcount); + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if ((f->fr_flags & FR_OUTQUE) == 0) + continue; + if ((i & 1) == 0) { + fprintf(fp, "\n\t"); + } + fprintf(fp, + "(frentry_t *)&out_rule_%s_%d", + f->fr_group, i); + if (i + 1 < outcount) + fprintf(fp, ", "); + i++; + } + fprintf(fp, "\n};\n"); + fp = NULL; + } + + if (num < 0) + return; + + in = 0; + ipf = fr->fr_ipf; + + /* + * If the function header has not been printed then print it now. + */ + if (header[dir] == 0) { + int pdst = 0, psrc = 0; + + openfunc = 1; + fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n", + (dir == 0) ? "in" : "out", group); + fprintf(fp, "fr_info_t *fin;\n"); + fprintf(fp, "u_32_t *passp;\n"); + fprintf(fp, "{\n"); + fprintf(fp, "\tfrentry_t *fr = NULL;\n"); + + /* + * Print out any variables that need to be declared. + */ + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if (incount + outcount > m[FRC_SRC].e + 1) + psrc = 1; + if (incount + outcount > m[FRC_DST].e + 1) + pdst = 1; + } + if (psrc == 1) + fprintf(fp, "\tu_32_t src = ntohl(%s);\n", + "fin->fin_fi.fi_saddr"); + if (pdst == 1) + fprintf(fp, "\tu_32_t dst = ntohl(%s);\n", + "fin->fin_fi.fi_daddr"); + } + + for (i = 0; i < FRC_MAX; i++) { + switch(m[i].c) + { + case FRC_IFN : + if (*fr->fr_ifname) + m[i].s = 1; + break; + case FRC_V : + if (ipf != NULL && ipf->fri_mip.fi_v != 0) + m[i].s = 1; + break; + case FRC_FL : + if (ipf != NULL && ipf->fri_mip.fi_flx != 0) + m[i].s = 1; + break; + case FRC_P : + if (ipf != NULL && ipf->fri_mip.fi_p != 0) + m[i].s = 1; + break; + case FRC_TTL : + if (ipf != NULL && ipf->fri_mip.fi_ttl != 0) + m[i].s = 1; + break; + case FRC_TOS : + if (ipf != NULL && ipf->fri_mip.fi_tos != 0) + m[i].s = 1; + break; + case FRC_TCP : + if (ipf == NULL) + break; + if ((ipf->fri_ip.fi_p == IPPROTO_TCP) && + fr->fr_tcpfm != 0) + m[i].s = 1; + break; + case FRC_SP : + if (ipf == NULL) + break; + if (fr->fr_scmp == FR_INRANGE) + m[i].s = 1; + else if (fr->fr_scmp == FR_OUTRANGE) + m[i].s = 1; + else if (fr->fr_scmp != 0) + m[i].s = 1; + break; + case FRC_DP : + if (ipf == NULL) + break; + if (fr->fr_dcmp == FR_INRANGE) + m[i].s = 1; + else if (fr->fr_dcmp == FR_OUTRANGE) + m[i].s = 1; + else if (fr->fr_dcmp != 0) + m[i].s = 1; + break; + case FRC_SRC : + if (ipf == NULL) + break; + if (fr->fr_satype == FRI_LOOKUP) { + ; + } else if ((fr->fr_smask != 0) || + (fr->fr_flags & FR_NOTSRCIP) != 0) + m[i].s = 1; + break; + case FRC_DST : + if (ipf == NULL) + break; + if (fr->fr_datype == FRI_LOOKUP) { + ; + } else if ((fr->fr_dmask != 0) || + (fr->fr_flags & FR_NOTDSTIP) != 0) + m[i].s = 1; + break; + case FRC_OPT : + if (ipf == NULL) + break; + if (fr->fr_optmask != 0) + m[i].s = 1; + break; + case FRC_SEC : + if (ipf == NULL) + break; + if (fr->fr_secmask != 0) + m[i].s = 1; + break; + case FRC_ATH : + if (ipf == NULL) + break; + if (fr->fr_authmask != 0) + m[i].s = 1; + break; + case FRC_ICT : + if (ipf == NULL) + break; + if ((fr->fr_icmpm & 0xff00) != 0) + m[i].s = 1; + break; + case FRC_ICC : + if (ipf == NULL) + break; + if ((fr->fr_icmpm & 0xff) != 0) + m[i].s = 1; + break; + } + } + + if (!header[dir]) { + fprintf(fp, "\n"); + header[dir] = 1; + sin = 0; + } + + qsort(m, FRC_MAX, sizeof(mc_t), intcmp); + + if (n) { + /* + * Calculate the indentation interval upto the last common + * common comparison being made. + */ + for (i = 0, in = 1; i < FRC_MAX; i++) { + if (n[i].c != m[i].c) + break; + if (n[i].s != m[i].s) + break; + if (n[i].s) { + if (n[i].n && (n[i].n > n[i].e)) { + m[i].p++; + in += m[i].p; + break; + } + if (n[i].e > 0) { + in++; + } else + break; + } + } + if (sin != in) { + for (j = sin - 1; j >= in; j--) { + indent(fp, j); + fprintf(fp, "}\n"); + } + } + } else { + in = 1; + i = 0; + } + + /* + * print out C code that implements a filter rule. + */ + for (; i < FRC_MAX; i++) { + switch(m[i].c) + { + case FRC_IFN : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_ifp == "); + fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n", + dir ? "out" : "in", group, num); + in++; + } + break; + case FRC_V : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_v == %d) {\n", + ipf->fri_ip.fi_v); + in++; + } + break; + case FRC_FL : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_flx", + ipf->fri_mip.fi_flx, 0xf, + ipf->fri_ip.fi_flx); + in++; + } + break; + case FRC_P : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_p == %d) {\n", + ipf->fri_ip.fi_p); + in++; + } + break; + case FRC_TTL : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_ttl", + ipf->fri_mip.fi_ttl, 0xff, + ipf->fri_ip.fi_ttl); + in++; + } + break; + case FRC_TOS : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_tos"); + printeq(fp, "fin->fin_tos", + ipf->fri_mip.fi_tos, 0xff, + ipf->fri_ip.fi_tos); + in++; + } + break; + case FRC_TCP : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm, + 0xff, fr->fr_tcpf); + in++; + } + break; + case FRC_SP : + if (!m[i].s) + break; + if (fr->fr_scmp == FR_INRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[0] > %d) && ", + fr->fr_sport); + fprintf(fp, "(fin->fin_data[0] < %d)", + fr->fr_stop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_scmp == FR_OUTRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[0] < %d) || ", + fr->fr_sport); + fprintf(fp, "(fin->fin_data[0] > %d)", + fr->fr_stop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_scmp) { + indent(fp, in); + fprintf(fp, "if (fin->fin_data[0] %s %d)", + portcmp[fr->fr_scmp], fr->fr_sport); + fprintf(fp, " {\n"); + in++; + } + break; + case FRC_DP : + if (!m[i].s) + break; + if (fr->fr_dcmp == FR_INRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[1] > %d) && ", + fr->fr_dport); + fprintf(fp, "(fin->fin_data[1] < %d)", + fr->fr_dtop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_dcmp == FR_OUTRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[1] < %d) || ", + fr->fr_dport); + fprintf(fp, "(fin->fin_data[1] > %d)", + fr->fr_dtop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_dcmp) { + indent(fp, in); + fprintf(fp, "if (fin->fin_data[1] %s %d)", + portcmp[fr->fr_dcmp], fr->fr_dport); + fprintf(fp, " {\n"); + in++; + } + break; + case FRC_SRC : + if (!m[i].s) + break; + if (fr->fr_satype == FRI_LOOKUP) { + ; + } else if ((fr->fr_smask != 0) || + (fr->fr_flags & FR_NOTSRCIP) != 0) { + indent(fp, in); + fprintf(fp, "if ("); + printipeq(fp, "src", + fr->fr_flags & FR_NOTSRCIP, + fr->fr_smask, fr->fr_saddr); + in++; + } + break; + case FRC_DST : + if (!m[i].s) + break; + if (fr->fr_datype == FRI_LOOKUP) { + ; + } else if ((fr->fr_dmask != 0) || + (fr->fr_flags & FR_NOTDSTIP) != 0) { + indent(fp, in); + fprintf(fp, "if ("); + printipeq(fp, "dst", + fr->fr_flags & FR_NOTDSTIP, + fr->fr_dmask, fr->fr_daddr); + in++; + } + break; + case FRC_OPT : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_optmsk", + fr->fr_optmask, 0xffffffff, + fr->fr_optbits); + in++; + } + break; + case FRC_SEC : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_secmsk", + fr->fr_secmask, 0xffff, + fr->fr_secbits); + in++; + } + break; + case FRC_ATH : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_authmsk", + fr->fr_authmask, 0xffff, + fr->fr_authbits); + in++; + } + break; + case FRC_ICT : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_data[0]", + fr->fr_icmpm & 0xff00, 0xffff, + fr->fr_icmp & 0xff00); + in++; + } + break; + case FRC_ICC : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_data[0]", + fr->fr_icmpm & 0xff, 0xffff, + fr->fr_icmp & 0xff); + in++; + } + break; + } + + } + + indent(fp, in); + if (fr->fr_flags & FR_QUICK) { + fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n", + fr->fr_flags & FR_INQUE ? "in" : "out", + fr->fr_group, num); + } else { + fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n", + fr->fr_flags & FR_INQUE ? "in" : "out", + fr->fr_group, num); + } + if (n == NULL) + n = (mc_t *)malloc(sizeof(*n) * FRC_MAX); + bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX); + sin = in; +} + + +void printC(dir) +int dir; +{ + static mc_t *m = NULL; + frgroup_t *g; + + if (m == NULL) + m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX); + + for (g = groups; g != NULL; g = g->fg_next) { + if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0)) + printCgroup(dir, g->fg_start, m, g->fg_name); + if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0)) + printCgroup(dir, g->fg_start, m, g->fg_name); + } + + emit(-1, dir, m, NULL); +} + + +/* + * Now print out code to implement all of the rules. + */ +static void printCgroup(dir, top, m, group) +int dir; +frentry_t *top; +mc_t *m; +char *group; +{ + frentry_t *fr, *fr1; + int i, n, rn; + u_int count; + + for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) { + if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0)) + count++; + else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0)) + count++; + } + + if (dir == 0) + emitGroup(-2, dir, m, fr1, group, count, 0); + else if (dir == 1) + emitGroup(-2, dir, m, fr1, group, 0, count); + + /* + * Before printing each rule, check to see how many of its fields are + * matched by subsequent rules. + */ + for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) { + if (!dir && !(fr1->fr_flags & FR_INQUE)) + continue; + if (dir && !(fr1->fr_flags & FR_OUTQUE)) + continue; + n = 0xfffffff; + + for (i = 0; i < FRC_MAX; i++) + m[i].e = 0; + qsort(m, FRC_MAX, sizeof(mc_t), intcmp); + + for (i = 0; i < FRC_MAX; i++) { + m[i].c = i; + m[i].e = 0; + m[i].n = 0; + m[i].s = 0; + } + + for (fr = fr1->fr_next; fr; fr = fr->fr_next) { + if (!dir && !(fr->fr_flags & FR_INQUE)) + continue; + if (dir && !(fr->fr_flags & FR_OUTQUE)) + continue; + + if ((n & 0x0001) && + !strcmp(fr1->fr_ifname, fr->fr_ifname)) { + m[FRC_IFN].e++; + m[FRC_IFN].n++; + } else + n &= ~0x0001; + + if ((n & 0x0002) && (fr1->fr_v == fr->fr_v)) { + m[FRC_V].e++; + m[FRC_V].n++; + } else + n &= ~0x0002; + + if ((n & 0x0004) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) && + (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) { + m[FRC_FL].e++; + m[FRC_FL].n++; + } else + n &= ~0x0004; + + if ((n & 0x0008) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_proto == fr->fr_proto)) { + m[FRC_P].e++; + m[FRC_P].n++; + } else + n &= ~0x0008; + + if ((n & 0x0010) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_ttl == fr->fr_ttl)) { + m[FRC_TTL].e++; + m[FRC_TTL].n++; + } else + n &= ~0x0010; + + if ((n & 0x0020) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_tos == fr->fr_tos)) { + m[FRC_TOS].e++; + m[FRC_TOS].n++; + } else + n &= ~0x0020; + + if ((n & 0x0040) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_tcpfm == fr->fr_tcpfm) && + (fr1->fr_tcpf == fr->fr_tcpf))) { + m[FRC_TCP].e++; + m[FRC_TCP].n++; + } else + n &= ~0x0040; + + if ((n & 0x0080) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_scmp == fr->fr_scmp) && + (fr1->fr_stop == fr->fr_stop) && + (fr1->fr_sport == fr->fr_sport))) { + m[FRC_SP].e++; + m[FRC_SP].n++; + } else + n &= ~0x0080; + + if ((n & 0x0100) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_dcmp == fr->fr_dcmp) && + (fr1->fr_dtop == fr->fr_dtop) && + (fr1->fr_dport == fr->fr_dport))) { + m[FRC_DP].e++; + m[FRC_DP].n++; + } else + n &= ~0x0100; + + if ((n & 0x0200) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_satype == FRI_LOOKUP) && + (fr->fr_satype == FRI_LOOKUP) && + (fr1->fr_srcnum == fr->fr_srcnum))) { + m[FRC_SRC].e++; + m[FRC_SRC].n++; + } else if ((n & 0x0200) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (((fr1->fr_flags & FR_NOTSRCIP) == + (fr->fr_flags & FR_NOTSRCIP)))) { + if ((fr1->fr_smask == fr->fr_smask) && + (fr1->fr_saddr == fr->fr_saddr)) + m[FRC_SRC].e++; + else + n &= ~0x0200; + if (fr1->fr_smask && + (fr1->fr_saddr & fr1->fr_smask) == + (fr->fr_saddr & fr1->fr_smask)) { + m[FRC_SRC].n++; + n |= 0x0200; + } + } else { + n &= ~0x0200; + } + + if ((n & 0x0400) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_datype == FRI_LOOKUP) && + (fr->fr_datype == FRI_LOOKUP) && + (fr1->fr_dstnum == fr->fr_dstnum))) { + m[FRC_DST].e++; + m[FRC_DST].n++; + } else if ((n & 0x0400) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (((fr1->fr_flags & FR_NOTDSTIP) == + (fr->fr_flags & FR_NOTDSTIP)))) { + if ((fr1->fr_dmask == fr->fr_dmask) && + (fr1->fr_daddr == fr->fr_daddr)) + m[FRC_DST].e++; + else + n &= ~0x0400; + if (fr1->fr_dmask && + (fr1->fr_daddr & fr1->fr_dmask) == + (fr->fr_daddr & fr1->fr_dmask)) { + m[FRC_DST].n++; + n |= 0x0400; + } + } else { + n &= ~0x0400; + } + + if ((n & 0x0800) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_optmask == fr->fr_optmask) && + (fr1->fr_optbits == fr->fr_optbits)) { + m[FRC_OPT].e++; + m[FRC_OPT].n++; + } else + n &= ~0x0800; + + if ((n & 0x1000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_secmask == fr->fr_secmask) && + (fr1->fr_secbits == fr->fr_secbits)) { + m[FRC_SEC].e++; + m[FRC_SEC].n++; + } else + n &= ~0x1000; + + if ((n & 0x10000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_authmask == fr->fr_authmask) && + (fr1->fr_authbits == fr->fr_authbits)) { + m[FRC_ATH].e++; + m[FRC_ATH].n++; + } else + n &= ~0x10000; + + if ((n & 0x20000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_icmpm & 0xff00) == + (fr->fr_icmpm & 0xff00)) && + ((fr1->fr_icmp & 0xff00) == + (fr->fr_icmp & 0xff00))) { + m[FRC_ICT].e++; + m[FRC_ICT].n++; + } else + n &= ~0x20000; + + if ((n & 0x40000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) && + ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) { + m[FRC_ICC].e++; + m[FRC_ICC].n++; + } else + n &= ~0x40000; + } + /*msort(m);*/ + + if (dir == 0) + emitGroup(rn, dir, m, fr1, group, count, 0); + else if (dir == 1) + emitGroup(rn, dir, m, fr1, group, 0, count); + } +} + +static void printhooks(fp, in, out, grp) +FILE *fp; +int in; +int out; +frgroup_t *grp; +{ + frentry_t *fr; + char *group; + int dogrp, i; + char *instr; + + group = grp->fg_name; + dogrp = 0; + + if (in && out) { + fprintf(stderr, + "printhooks called with both in and out set\n"); + exit(1); + } + + if (in) { + instr = "in"; + } else if (out) { + instr = "out"; + } else { + instr = "???"; + } + fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group); + + fprintf(fp, "\ +\n\ +int ipfrule_add_%s_%s()\n", instr, group); + fprintf(fp, "\ +{\n\ + int i, j, err = 0, max;\n\ + frentry_t *fp;\n"); + + if (dogrp) + fprintf(fp, "\ + frgroup_t *fg;\n"); + + fprintf(fp, "\n"); + + for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next) + if (fr->fr_dsize > 0) { + fprintf(fp, "\ + ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n", + instr, grp->fg_name, i, + instr, grp->fg_name, i); + } + fprintf(fp, "\ + max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\ + for (i = 0; i < max; i++) {\n\ + fp = ipf_rules_%s_%s[i];\n\ + fp->fr_next = NULL;\n", instr, group, instr, group); + + fprintf(fp, "\ + for (j = i + 1; j < max; j++)\n\ + if (strncmp(fp->fr_group,\n\ + ipf_rules_%s_%s[j]->fr_group,\n\ + FR_GROUPLEN) == 0) {\n\ + fp->fr_next = ipf_rules_%s_%s[j];\n\ + break;\n\ + }\n", instr, group, instr, group); + if (dogrp) + fprintf(fp, "\ +\n\ + if (fp->fr_grhead != 0) {\n\ + fg = fr_addgroup(fp->fr_grhead, fp, FR_INQUE,\n\ + IPL_LOGIPF, 0);\n\ + if (fg != NULL)\n\ + fp->fr_grp = &fg->fg_start;\n\ + }\n"); + fprintf(fp, "\ + }\n\ +\n\ + fp = &ipfrule_%s_%s;\n", instr, group); + fprintf(fp, "\ + bzero((char *)fp, sizeof(*fp));\n\ + fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;\n\ + fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\ + fp->fr_data = (void *)ipf_rules_%s_%s[0];\n", + (in != 0) ? "IN" : "OUT", instr, group); + fprintf(fp, "\ + fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n", + instr, group); + + fprintf(fp, "\ + fp->fr_v = 4;\n\ + fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\ + err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);\n", + instr, group); + fprintf(fp, "\treturn err;\n}\n"); + + fprintf(fp, "\n\n\ +int ipfrule_remove_%s_%s()\n", instr, group); + fprintf(fp, "\ +{\n\ + int err = 0, i;\n\ + frentry_t *fp;\n\ +\n\ + /*\n\ + * Try to remove the %sbound rule.\n", instr); + + fprintf(fp, "\ + */\n\ + if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group); + + fprintf(fp, "\ + err = EBUSY;\n\ + } else {\n"); + + fprintf(fp, "\ + i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\ + for (; i >= 0; i--) {\n\ + fp = ipf_rules_%s_%s[i];\n\ + if (fp->fr_ref > 1) {\n\ + err = EBUSY;\n\ + break;\n\ + }\n\ + }\n\ + }\n\ + if (err == 0)\n\ + err = frrequest(IPL_LOGIPF, SIOCDELFR,\n\ + (caddr_t)&ipfrule_%s_%s, fr_active, 0);\n", + instr, group, instr, group, instr, group); + fprintf(fp, "\ + if (err)\n\ + return err;\n\ +\n\n"); + + fprintf(fp, "\treturn err;\n}\n"); +} diff --git a/contrib/ipfilter/tools/ipfs.c b/contrib/ipfilter/tools/ipfs.c new file mode 100644 index 0000000..49e7e52 --- /dev/null +++ b/contrib/ipfilter/tools/ipfs.c @@ -0,0 +1,855 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1999-2001, 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#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 "ipf.h" +#include "ipl.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp"; +#endif + +#ifndef IPF_SAVEDIR +# define IPF_SAVEDIR "/var/db/ipf" +#endif +#ifndef IPF_NATFILE +# define IPF_NATFILE "ipnat.ipf" +#endif +#ifndef IPF_STATEFILE +# define IPF_STATEFILE "ipstate.ipf" +#endif + +#if !defined(__SVR4) && defined(__GNUC__) +extern char *index __P((const char *, int)); +#endif + +extern char *optarg; +extern int optind; + +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; +char *progname; + + +void usage() +{ + fprintf(stderr, "usage: %s [-nv] -l\n", progname); + fprintf(stderr, "usage: %s [-nv] -u\n", progname); + fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname); + fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname); + fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname); + fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname); + fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n", + progname); + 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_ifnames[0]) || + olen >= sizeof(nat->nat_ifnames[0])) + 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_ifnames[0], ifs, olen + 1)) { + strcpy(nat->nat_ifnames[0], s); + rw = 1; + } + if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { + strcpy(nat->nat_ifnames[1], 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; + + progname = argv[0]; + 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 (dirname || (rw != -1) || (ns == -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 (dirname || (rw != -1) || (ns == -1)) + usage(); + rw = 1; + set = 1; + break; + case 'W' : + rw = 3; + set = 1; + break; + case '?' : + default : + usage(); + } + + if (ifs) { + if (!filename || ns < 0) + usage(); + if (ns == 0) + return changenatif(ifs, filename); + else + return changestateif(ifs, filename); + } + + if ((ns >= 0) || (lock >= 0)) { + if (lock >= 0) + devfd = opendevice(NULL); + else if (ns >= 0) { + if (ns == 1) + devfd = opendevice(IPSTATE_NAME); + else if (ns == 0) + devfd = opendevice(IPNAT_NAME); + } + 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; + ipfobj_t obj; + int wfd = -1; + + if (!file) + file = IPF_STATEFILE; + + 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 *)&obj, sizeof(obj)); + bzero((char *)ipsp, sizeof(ips)); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*ipsp); + obj.ipfo_type = IPFOBJ_STATESAVE; + obj.ipfo_ptr = ipsp; + + do { + + if (opts & OPT_VERBOSE) + printf("Getting state from addr %p\n", ips.ips_next); + if (ioctl(fd, SIOCSTGET, &obj)) { + 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; + ipfobj_t obj; + + if (!file) + file = IPF_STATEFILE; + + 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, "state:incomplete read: %d != %d\n", + i, (int)sizeof(ips)); + close(sfd); + return 1; + } + is = (ipstate_save_t *)malloc(sizeof(*is)); + if(!is) { + fprintf(stderr, "malloc failed\n"); + return 1; + } + + 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 |= SI_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); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*is); + obj.ipfo_type = IPFOBJ_STATESAVE; + + 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 & SI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Loading new filter rule\n"); + } + + obj.ipfo_ptr = is; + if (!(opts & OPT_DONOTHING)) + if (ioctl(fd, SIOCSTPUT, &obj)) { + perror("SIOCSTPUT"); + return 1; + } + + if (is->ips_is.is_flags & SI_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; + ipfobj_t obj; + int nfd, i; + nat_t *nat; + char *s; + int n; + + nfd = -1; + in = NULL; + ipnhead = NULL; + ipntail = NULL; + + if (!file) + file = IPF_NATFILE; + + 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, "nat:incomplete read: %d != %d\n", + i, (int)sizeof(ipn)); + close(nfd); + return 1; + } + + in = (nat_save_t *)malloc(ipn.ipn_dsize); + if (!in) + break; + + if (ipn.ipn_dsize > sizeof(ipn)) { + n = ipn.ipn_dsize - sizeof(ipn); + if (n > 0) { + s = in->ipn_data + sizeof(in->ipn_data); + i = read(nfd, s, n); + if (i == 0) + break; + if (i != n) { + fprintf(stderr, + "nat:incomplete read: %d != %d\n", + i, n); + close(nfd); + return 1; + } + } + } + bcopy((char *)&ipn, (char *)in, sizeof(ipn)); + + /* + * Check to see if this is the first NAT 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 |= SI_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); + nfd = -1; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_NATSAVE; + + 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 & SI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Loading new filter rule\n"); + } + + obj.ipfo_ptr = in; + obj.ipfo_size = in->ipn_dsize; + if (!(opts & OPT_DONOTHING)) + if (ioctl(fd, SIOCSTPUT, &obj)) { + fprintf(stderr, "in=%p:", in); + perror("SIOCSTPUT"); + return 1; + } + + if (nat->nat_flags & SI_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; + ipfobj_t obj; + int nfd = -1; + natget_t ng; + + if (!file) + file = IPF_NATFILE; + + nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); + if (nfd == -1) { + fprintf(stderr, "%s ", file); + perror("nat:open"); + return 1; + } + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_NATSAVE; + + 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); + if (ipnp != NULL) + free(ipnp); + 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); + obj.ipfo_size = ng.ng_sz; + obj.ipfo_ptr = ipnp; + ipnp->ipn_dsize = ng.ng_sz; + ipnp->ipn_next = next; + if (ioctl(fd, SIOCSTGET, &obj)) { + if (errno == ENOENT) + break; + perror("nat:SIOCSTGET"); + close(nfd); + free(ipnp); + return 1; + } + + if (opts & OPT_VERBOSE) + printf("Got nat next %p ipn_dsize %d ng_sz %d\n", + ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); + if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { + perror("nat:write"); + close(nfd); + free(ipnp); + return 1; + } + next = ipnp->ipn_next; + } while (ipnp && next); + if (ipnp != NULL) + free(ipnp); + close(nfd); + + return 0; +} + + +int writeall(dirname) +char *dirname; +{ + int fd, devfd; + + if (!dirname) + dirname = IPF_SAVEDIR; + + if (chdir(dirname)) { + fprintf(stderr, "IPF_SAVEDIR=%s: ", 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(IPSTATE_NAME); + if (devfd == -1) + goto bad; + if (writestate(devfd, NULL)) + goto bad; + close(devfd); + + devfd = opendevice(IPNAT_NAME); + if (devfd == -1) + goto bad; + if (writenat(devfd, NULL)) + goto bad; + close(devfd); + + if (setlock(fd, 0)) { + close(fd); + return 1; + } + + close(fd); + return 0; + +bad: + setlock(fd, 0); + close(fd); + return 1; +} + + +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(IPSTATE_NAME); + if (devfd == -1) + return 1; + if (readstate(devfd, NULL)) + return 1; + close(devfd); + + devfd = opendevice(IPNAT_NAME); + if (devfd == -1) + return 1; + if (readnat(devfd, NULL)) + return 1; + close(devfd); + + if (setlock(fd, 0)) { + close(fd); + return 1; + } + + return 0; +} diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c new file mode 100644 index 0000000..fbd6c35 --- /dev/null +++ b/contrib/ipfilter/tools/ipfstat.c @@ -0,0 +1,1792 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001, 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#endif +#include <sys/ioctl.h> +#include <fcntl.h> +#ifdef linux +# include <linux/a.out.h> +#else +# include <nlist.h> +#endif +#include <ctype.h> +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include <stddef.h> +#endif +#include "ipf.h" +#include "netinet/ipl.h" +#if defined(STATETOP) +# if defined(_BSDI_VERSION) +# undef STATETOP +# endif +# if defined(__FreeBSD__) && \ + (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000)) +# undef STATETOP +# endif +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000) +# undef STATETOP +# endif +# if defined(sun) +# if defined(__svr4__) || defined(__SVR4) +# include <sys/select.h> +# else +# undef STATETOP /* NOT supported on SunOS4 */ +# endif +# endif +#endif +#if defined(STATETOP) && !defined(linux) +# include <netinet/ip_var.h> +# include <netinet/tcp_fsm.h> +#endif +#ifdef STATETOP +# include <ctype.h> +# include <signal.h> +# if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \ + defined(__sgi) +# ifdef ERR +# undef ERR +# endif +# include <curses.h> +# else /* SOLARIS */ +# include <ncurses.h> +# endif /* SOLARIS */ +#endif /* STATETOP */ +#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-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipfstat.c,v 1.44.2.11 2005/03/30 14:09:57 darrenr Exp"; +#endif + +#ifdef __hpux +# define nlist nlist64 +#endif + +extern char *optarg; +extern int optind; +extern int opterr; + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf +#define F_IN 0 +#define F_OUT 1 +#define F_ACIN 2 +#define F_ACOUT 3 +static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", + "ipacct(in)", "ipacct(out)" }; +static int state_logging = -1; + +int opts = 0; +int use_inet6 = 0; +int live_kernel = 1; +int state_fd = -1; +int ipf_fd = -1; + +#ifdef STATETOP +#define STSTRSIZE 80 +#define STGROWSIZE 16 +#define HOSTNMLEN 40 + +#define STSORT_PR 0 +#define STSORT_PKTS 1 +#define STSORT_BYTES 2 +#define STSORT_TTL 3 +#define STSORT_SRCIP 4 +#define STSORT_SRCPT 5 +#define STSORT_DSTIP 6 +#define STSORT_DSTPT 7 +#define STSORT_MAX STSORT_DSTPT +#define STSORT_DEFAULT STSORT_BYTES + + +typedef struct statetop { + i6addr_t st_src; + i6addr_t st_dst; + u_short st_sport; + u_short st_dport; + u_char st_p; + u_char st_v; + u_char st_state[2]; + U_QUAD_T st_pkts; + U_QUAD_T st_bytes; + u_long st_age; +} statetop_t; +#endif + +int main __P((int, char *[])); + +static void showstats __P((friostat_t *, u_32_t)); +static void showfrstates __P((ipfrstat_t *)); +static void showlist __P((friostat_t *)); +static void showipstates __P((ips_stat_t *)); +static void showauthstates __P((fr_authstat_t *)); +static void showgroups __P((friostat_t *)); +static void usage __P((char *)); +static void printlist __P((frentry_t *, char *)); +static void parse_ipportstr __P((const char *, i6addr_t *, int *)); +static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **, + ipfrstat_t **, fr_authstat_t **, u_32_t *)); +static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **, + ipfrstat_t **, fr_authstat_t **, u_32_t *)); +#ifdef STATETOP +static void topipstates __P((i6addr_t, i6addr_t, int, int, int, + int, int, int)); +static void sig_break __P((int)); +static void sig_resize __P((int)); +static char *getip __P((int, i6addr_t *)); +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 *)); +static int sort_srcip __P((const void *, const void *)); +static int sort_srcpt __P((const void *, const void *)); +static int sort_dstip __P((const void *, const void *)); +static int sort_dstpt __P((const void *, const void *)); +#endif + + +static void usage(name) +char *name; +{ +#ifdef USE_INET6 + fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name); +#else + fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name); +#endif + fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); +#ifdef USE_INET6 + fprintf(stderr, " %s -t [-6C] ", name); +#else + fprintf(stderr, " %s -t [-C] ", name); +#endif + fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); + exit(1); +} + + +int main(argc,argv) +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 *device = IPL_NAME, *memf = NULL; + char *options, *kern = NULL; + int c, myoptind; + + 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 */ + i6addr_t saddr, daddr; + u_32_t frf; + +#ifdef USE_INET6 + options = "6aACdfghIilnostvD:M:N:P:RS:T:"; +#else + options = "aACdfghIilnostvD:M:N:P:RS:T:"; +#endif + + saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */ + daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */ +#ifdef USE_INET6 + saddr.in6 = in6addr_any; /* default any v6 source addr */ + daddr.in6 = in6addr_any; /* default any v6 dest addr */ +#endif + + /* Don't warn about invalid flags when we run getopt for the 1st time */ + opterr = 0; + + /* + * Parse these two arguments now lest there be any buffer overflows + * in the parsing of the rest. + */ + myoptind = optind; + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) + { + case 'M' : + memf = optarg; + live_kernel = 0; + break; + case 'N' : + kern = optarg; + live_kernel = 0; + break; + } + } + optind = myoptind; + + if (live_kernel == 1) { + if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) { + perror("open(IPSTATE_NAME)"); + exit(-1); + } + if ((ipf_fd = open(device, O_RDONLY)) == -1) { + fprintf(stderr, "open(%s)", device); + perror(""); + exit(-1); + } + } + + if (kern != NULL || memf != NULL) { + (void)setgid(getgid()); + (void)setuid(getuid()); + } + + if (live_kernel == 1) + (void) checkrev(device); + if (openkmem(kern, memf) == -1) + exit(-1); + + (void)setgid(getgid()); + (void)setuid(getuid()); + + opterr = 1; + + while ((c = getopt(argc, argv, options)) != -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' : + opts |= OPT_DEBUG; + break; + case 'D' : + parse_ipportstr(optarg, &daddr, &dport); + break; + case 'f' : + opts |= OPT_FRSTATES; + break; + case 'g' : + opts |= OPT_GROUPS; + break; + case 'h' : + opts |= OPT_HITS; + break; + case 'i' : + opts |= OPT_INQUE|OPT_SHOWLIST; + break; + case 'I' : + opts |= OPT_INACTIVE; + break; + case 'l' : + opts |= OPT_SHOWLIST; + break; + case 'M' : + break; + case 'N' : + break; + case 'n' : + opts |= OPT_SHOWLINENO; + break; + case 'o' : + opts |= OPT_OUTQUE|OPT_SHOWLIST; + break; + case 'P' : + protocol = getproto(optarg); + if (protocol == -1) { + fprintf(stderr, "%s: Invalid protocol: %s\n", + argv[0], optarg); + exit(-2); + } + break; + case 'R' : + opts |= OPT_NORESOLVE; + 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; + default : + usage(argv[0]); + break; + } + } + + if (live_kernel == 1) { + bzero((char *)&fio, sizeof(fio)); + bzero((char *)&ipsst, sizeof(ipsst)); + bzero((char *)&ifrst, sizeof(ifrst)); + + ipfstate_live(device, &fiop, &ipsstp, &ifrstp, + &frauthstp, &frf); + } else + ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); + + if (opts & OPT_IPSTATES) { + showipstates(ipsstp); + } else if (opts & OPT_SHOWLIST) { + showlist(fiop); + if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ + opts &= ~OPT_OUTQUE; + showlist(fiop); + } + } else if (opts & OPT_FRSTATES) + showfrstates(ifrstp); +#ifdef STATETOP + else if (opts & OPT_STATETOP) + topipstates(saddr, daddr, sport, dport, protocol, + use_inet6 ? 6 : 4, refreshtime, topclosed); +#endif + else if (opts & OPT_AUTHSTATS) + showauthstates(frauthstp); + else if (opts & OPT_GROUPS) + showgroups(fiop); + else + showstats(fiop, frf); + + return 0; +} + + +/* + * Fill in the stats structures from the live kernel, using a combination + * of ioctl's and copying directly from kernel memory. + */ +static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) +char *device; +friostat_t **fiopp; +ips_stat_t **ipsstpp; +ipfrstat_t **ifrstpp; +fr_authstat_t **frauthstpp; +u_32_t *frfp; +{ + ipfobj_t ipfo; + + if (checkrev(device) == -1) { + fprintf(stderr, "User/kernel version check failed\n"); + exit(1); + } + + if ((opts & OPT_AUTHSTATS) == 0) { + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(friostat_t); + ipfo.ipfo_ptr = (void *)*fiopp; + ipfo.ipfo_type = IPFOBJ_IPFSTAT; + + if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) { + perror("ioctl(ipf:SIOCGETFS)"); + exit(-1); + } + + if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1) + perror("ioctl(SIOCGETFF)"); + } + + if ((opts & OPT_IPSTATES) != 0) { + + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(ips_stat_t); + ipfo.ipfo_ptr = (void *)*ipsstpp; + ipfo.ipfo_type = IPFOBJ_STATESTAT; + + if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { + perror("ioctl(state:SIOCGETFS)"); + exit(-1); + } + if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) { + perror("ioctl(state:SIOCGETLG)"); + exit(-1); + } + } + + if ((opts & OPT_FRSTATES) != 0) { + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(ipfrstat_t); + ipfo.ipfo_ptr = (void *)*ifrstpp; + ipfo.ipfo_type = IPFOBJ_FRAGSTAT; + + if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) { + perror("ioctl(SIOCGFRST)"); + exit(-1); + } + } + + if (opts & OPT_VERBOSE) + PRINTF("opts %#x name %s\n", opts, device); + + if ((opts & OPT_AUTHSTATS) != 0) { + if (ipf_fd >= 0) { + close(ipf_fd); + ipf_fd = -1; + } + device = IPAUTH_NAME; + if ((ipf_fd = open(device, O_RDONLY)) == -1) { + perror("open"); + exit(-1); + } + + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(fr_authstat_t); + ipfo.ipfo_ptr = (void *)*frauthstpp; + ipfo.ipfo_type = IPFOBJ_AUTHSTAT; + + if (ioctl(ipf_fd, SIOCATHST, &ipfo) == -1) { + perror("ioctl(SIOCATHST)"); + exit(-1); + } + } +} + + +/* + * Build up the stats structures from data held in the "core" memory. + * This is mainly useful when looking at data in crash dumps and ioctl's + * just won't work any more. + */ +static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) +char *kernel; +friostat_t **fiopp; +ips_stat_t **ipsstpp; +ipfrstat_t **ifrstpp; +fr_authstat_t **frauthstpp; +u_32_t *frfp; +{ + static fr_authstat_t frauthst, *frauthstp; + static ips_stat_t ipsst, *ipsstp; + static ipfrstat_t ifrst, *ifrstp; + static friostat_t fio, *fiop; + int temp; + + void *rules[2][2]; + struct nlist deadlist[43] = { + { "fr_authstats" }, /* 0 */ + { "fae_list" }, + { "ipauth" }, + { "fr_authlist" }, + { "fr_authstart" }, + { "fr_authend" }, /* 5 */ + { "fr_authnext" }, + { "fr_auth" }, + { "fr_authused" }, + { "fr_authsize" }, + { "fr_defaultauthage" }, /* 10 */ + { "fr_authpkts" }, + { "fr_auth_lock" }, + { "frstats" }, + { "ips_stats" }, + { "ips_num" }, /* 15 */ + { "ips_wild" }, + { "ips_list" }, + { "ips_table" }, + { "fr_statemax" }, + { "fr_statesize" }, /* 20 */ + { "fr_state_doflush" }, + { "fr_state_lock" }, + { "ipfr_heads" }, + { "ipfr_nattab" }, + { "ipfr_stats" }, /* 25 */ + { "ipfr_inuse" }, + { "fr_ipfrttl" }, + { "fr_frag_lock" }, + { "ipfr_timer_id" }, + { "fr_nat_lock" }, /* 30 */ + { "ipfilter" }, + { "ipfilter6" }, + { "ipacct" }, + { "ipacct6" }, + { "ipl_frouteok" }, /* 35 */ + { "fr_running" }, + { "ipfgroups" }, + { "fr_active" }, + { "fr_pass" }, + { "fr_flags" }, /* 40 */ + { "ipstate_logging" }, + { NULL } + }; + + + frauthstp = &frauthst; + ipsstp = &ipsst; + ifrstp = &ifrst; + fiop = &fio; + + *frfp = 0; + *fiopp = fiop; + *ipsstpp = ipsstp; + *ifrstpp = ifrstp; + *frauthstpp = frauthstp; + + bzero((char *)fiop, sizeof(*fiop)); + bzero((char *)ipsstp, sizeof(*ipsstp)); + bzero((char *)ifrstp, sizeof(*ifrstp)); + bzero((char *)frauthstp, sizeof(*frauthstp)); + + if (nlist(kernel, deadlist) == -1) { + fprintf(stderr, "nlist error\n"); + return; + } + + /* + * This is for SIOCGETFF. + */ + kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp)); + + /* + * f_locks is a combination of the lock variable from each part of + * ipfilter (state, auth, nat, fragments). + */ + kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop)); + kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value, + sizeof(fiop->f_locks[0])); + kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value, + sizeof(fiop->f_locks[1])); + kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value, + sizeof(fiop->f_locks[2])); + kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value, + sizeof(fiop->f_locks[3])); + + /* + * Get pointers to each list of rules (active, inactive, in, out) + */ + kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules)); + fiop->f_fin[0] = rules[0][0]; + fiop->f_fin[1] = rules[0][1]; + fiop->f_fout[0] = rules[1][0]; + fiop->f_fout[1] = rules[1][1]; + + /* + * Same for IPv6, except make them null if support for it is not + * being compiled in. + */ +#ifdef USE_INET6 + kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules)); + fiop->f_fin6[0] = rules[0][0]; + fiop->f_fin6[1] = rules[0][1]; + fiop->f_fout6[0] = rules[1][0]; + fiop->f_fout6[1] = rules[1][1]; +#else + fiop->f_fin6[0] = NULL; + fiop->f_fin6[1] = NULL; + fiop->f_fout6[0] = NULL; + fiop->f_fout6[1] = NULL; +#endif + + /* + * Now get accounting rules pointers. + */ + kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules)); + fiop->f_acctin[0] = rules[0][0]; + fiop->f_acctin[1] = rules[0][1]; + fiop->f_acctout[0] = rules[1][0]; + fiop->f_acctout[1] = rules[1][1]; + +#ifdef USE_INET6 + kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules)); + fiop->f_acctin6[0] = rules[0][0]; + fiop->f_acctin6[1] = rules[0][1]; + fiop->f_acctout6[0] = rules[1][0]; + fiop->f_acctout6[1] = rules[1][1]; +#else + fiop->f_acctin6[0] = NULL; + fiop->f_acctin6[1] = NULL; + fiop->f_acctout6[0] = NULL; + fiop->f_acctout6[1] = NULL; +#endif + + /* + * A collection of "global" variables used inside the kernel which + * are all collected in friostat_t via ioctl. + */ + kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value, + sizeof(fiop->f_froute)); + kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value, + sizeof(fiop->f_running)); + kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value, + sizeof(fiop->f_groups)); + kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value, + sizeof(fiop->f_active)); + kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value, + sizeof(fiop->f_defpass)); + + /* + * Build up the state information stats structure. + */ + kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp)); + kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp)); + ipsstp->iss_active = temp; + ipsstp->iss_table = (void *)deadlist[18].n_value; + ipsstp->iss_list = (void *)deadlist[17].n_value; + + /* + * Build up the authentiation information stats structure. + */ + kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value, + sizeof(*frauthstp)); + frauthstp->fas_faelist = (void *)deadlist[1].n_value; + + /* + * Build up the fragment information stats structure. + */ + kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value, + sizeof(*ifrstp)); + ifrstp->ifs_table = (void *)deadlist[23].n_value; + ifrstp->ifs_nattab = (void *)deadlist[24].n_value; + kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value, + sizeof(ifrstp->ifs_inuse)); + + /* + * Get logging on/off switches + */ + kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value, + sizeof(state_logging)); +} + + +/* + * Display the kernel stats for packets blocked and passed and other + * associated running totals which are kept. + */ +static void showstats(fp, frf) +struct friostat *fp; +u_32_t frf; +{ + + PRINTF("bad packets:\t\tin %lu\tout %lu\n", + fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); +#ifdef USE_INET6 + PRINTF(" IPv6 packets:\t\tin %lu out %lu\n", + fp->f_st[0].fr_ipv6, fp->f_st[1].fr_ipv6); +#endif + PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu", + fp->f_st[0].fr_block, fp->f_st[0].fr_pass, + fp->f_st[0].fr_nom); + PRINTF(" counted %lu short %lu\n", + fp->f_st[0].fr_acct, fp->f_st[0].fr_short); + PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu", + fp->f_st[1].fr_block, fp->f_st[1].fr_pass, + fp->f_st[1].fr_nom); + PRINTF(" counted %lu short %lu\n", + fp->f_st[1].fr_acct, fp->f_st[1].fr_short); + PRINTF(" input packets logged:\tblocked %lu passed %lu\n", + fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); + PRINTF("output packets logged:\tblocked %lu passed %lu\n", + fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); + PRINTF(" packets logged:\tinput %lu output %lu\n", + fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl); + PRINTF(" log failures:\t\tinput %lu output %lu\n", + fp->f_st[0].fr_skip, fp->f_st[1].fr_skip); + PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n", + fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr, + fp->f_st[0].fr_cfr); + PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n", + fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr, + fp->f_st[0].fr_cfr); + PRINTF("packet state(in):\tkept %lu\tlost %lu\n", + fp->f_st[0].fr_ads, fp->f_st[0].fr_bads); + PRINTF("packet state(out):\tkept %lu\tlost %lu\n", + 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", + fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]); + PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n", + fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]); + PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n", + fp->f_froute[0], fp->f_froute[1]); + PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n", + fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad); + PRINTF("IPF Ticks:\t%lu\n", fp->f_ticks); + + PRINTF("Packet log flags set: (%#x)\n", frf); + if (frf & FF_LOGPASS) + PRINTF("\tpackets passed through filter\n"); + if (frf & FF_LOGBLOCK) + PRINTF("\tpackets blocked by filter\n"); + if (frf & FF_LOGNOMATCH) + PRINTF("\tpackets not matched by filter\n"); + if (!frf) + PRINTF("\tnone\n"); +} + + +/* + * Print out a list of rules from the kernel, starting at the one passed. + */ +static void printlist(fp, comment) +frentry_t *fp; +char *comment; +{ + struct frentry fb, *fg; + char *data; + u_32_t type; + int n; + + for (n = 1; fp; n++) { + if (kmemcpy((char *)&fb, (u_long)fp, sizeof(fb)) == -1) { + perror("kmemcpy"); + return; + } + fp = &fb; + if (opts & (OPT_HITS|OPT_VERBOSE)) +#ifdef USE_QUAD_T + PRINTF("%qu ", (unsigned long long) fp->fr_hits); +#else + PRINTF("%lu ", fp->fr_hits); +#endif + if (opts & (OPT_ACCNT|OPT_VERBOSE)) +#ifdef USE_QUAD_T + PRINTF("%qu ", (unsigned long long) fp->fr_bytes); +#else + PRINTF("%lu ", fp->fr_bytes); +#endif + if (opts & OPT_SHOWLINENO) + PRINTF("@%d ", n); + data = NULL; + type = fp->fr_type & ~FR_T_BUILTIN; + if (type == FR_T_IPF || type == FR_T_BPFOPC) { + if (fp->fr_dsize) { + data = malloc(fp->fr_dsize); + + if (kmemcpy(data, (u_long)fp->fr_data, + fp->fr_dsize) == -1) { + perror("kmemcpy"); + return; + } + fp->fr_data = data; + } + } + + printfr(fp, ioctl); + if (opts & OPT_DEBUG) { + binprint(fp, sizeof(*fp)); + if (fp->fr_data != NULL && fp->fr_dsize > 0) + binprint(fp->fr_data, fp->fr_dsize); + } + if (data != NULL) + free(data); + if (fp->fr_grp != NULL) { + if (!kmemcpy((char *)&fg, (u_long)fp->fr_grp, + sizeof(fg))) + printlist(fg, comment); + } + if (type == FR_T_CALLFUNC) { + printlist(fp->fr_data, "# callfunc: "); + } + fp = fp->fr_next; + } +} + +/* + * print out all of the asked for rule sets, using the stats struct as + * the base from which to get the pointers. + */ +static void showlist(fiop) +struct friostat *fiop; +{ + struct frentry *fp = NULL; + int i, set; + + set = fiop->f_active; + if (opts & OPT_INACTIVE) + set = 1 - set; + if (opts & OPT_ACCNT) { +#ifdef USE_INET6 + if ((use_inet6) && (opts & OPT_OUTQUE)) { + i = F_ACOUT; + fp = (struct frentry *)fiop->f_acctout6[set]; + } else if ((use_inet6) && (opts & OPT_INQUE)) { + i = F_ACIN; + fp = (struct frentry *)fiop->f_acctin6[set]; + } else +#endif + if (opts & OPT_OUTQUE) { + i = F_ACOUT; + fp = (struct frentry *)fiop->f_acctout[set]; + } else if (opts & OPT_INQUE) { + i = F_ACIN; + fp = (struct frentry *)fiop->f_acctin[set]; + } else { + FPRINTF(stderr, "No -i or -o given with -a\n"); + 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); + + if (opts & OPT_VERBOSE) + PRINTF("fp %p set %d\n", fp, set); + if (!fp) { + FPRINTF(stderr, "empty list for %s%s\n", + (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); + return; + } + printlist(fp, NULL); +} + + +/* + * Display ipfilter stateful filtering information + */ +static void showipstates(ipsp) +ips_stat_t *ipsp; +{ + u_long minlen, maxlen, totallen, *buckets; + int i, sz; + + sz = sizeof(*buckets) * ipsp->iss_statesize; + buckets = (u_long *)malloc(sz); + if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) { + free(buckets); + return; + } + + /* + * If a list of states hasn't been asked for, only print out stats + */ + 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 max bucket\n", + ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_bucketfull); + 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); + + PRINTF("State logging %sabled\n", + state_logging ? "en" : "dis"); + + PRINTF("\nState table bucket statistics:\n"); + PRINTF("\t%lu in use\t\n", ipsp->iss_inuse); + + minlen = ipsp->iss_max; + totallen = 0; + maxlen = 0; + + for (i = 0; i < ipsp->iss_statesize; i++) { + if (buckets[i] > maxlen) + maxlen = buckets[i]; + if (buckets[i] < minlen) + minlen = buckets[i]; + totallen += buckets[i]; + } + + PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n", + ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0, + minlen); + PRINTF("\t%lu maximal length\n\t%.3f average length\n", + maxlen, + ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse : + 0.0); + +#define ENTRIES_PER_LINE 5 + + if (opts & OPT_VERBOSE) { + PRINTF("\nCurrent bucket sizes :\n"); + for (i = 0; i < ipsp->iss_statesize; i++) { + if ((i % ENTRIES_PER_LINE) == 0) + PRINTF("\t"); + PRINTF("%4d -> %4lu", i, buckets[i]); + if ((i % ENTRIES_PER_LINE) == + (ENTRIES_PER_LINE - 1)) + PRINTF("\n"); + else + PRINTF(" "); + } + PRINTF("\n"); + } + PRINTF("\n"); + + free(buckets); + return; + } + + /* + * Print out all the state information currently held in the kernel. + */ + while (ipsp->iss_list != NULL) { + ipsp->iss_list = printstate(ipsp->iss_list, opts, + ipsp->iss_ticks); + } + + free(buckets); +} + + +#ifdef STATETOP +static int handle_resize = 0, handle_break = 0; + +static void topipstates(saddr, daddr, sport, dport, protocol, ver, + refreshtime, topclosed) +i6addr_t saddr; +i6addr_t daddr; +int sport; +int dport; +int protocol; +int ver; +int refreshtime; +int topclosed; +{ + char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; + int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; + int i, j, winy, tsentry, maxx, maxy, redraw = 0; + int len, srclen, dstlen, forward = 1, c = 0; + ips_stat_t ipsst, *ipsstp = &ipsst; + statetop_t *tstable = NULL, *tp; + ipstate_t ips; + ipfobj_t ipfo; + struct timeval selecttimeout; + char hostnm[HOSTNMLEN]; + struct protoent *proto; + fd_set readfd; + time_t t; + + /* install signal handlers */ + signal(SIGINT, sig_break); + signal(SIGQUIT, sig_break); + signal(SIGTERM, sig_break); + signal(SIGWINCH, sig_resize); + + /* init ncurses stuff */ + initscr(); + cbreak(); + noecho(); + curs_set(0); + timeout(0); + getmaxyx(stdscr, maxy, maxx); + + /* init hostname */ + gethostname(hostnm, sizeof(hostnm) - 1); + hostnm[sizeof(hostnm) - 1] = '\0'; + + /* init ipfobj_t stuff */ + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(*ipsstp); + ipfo.ipfo_ptr = (void *)ipsstp; + ipfo.ipfo_type = IPFOBJ_STATESTAT; + + /* repeat until user aborts */ + while ( 1 ) { + + /* get state table */ + bzero((char *)&ipsst, sizeof(ipsst)); + if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { + perror("ioctl(SIOCGETFS)"); + exit(-1); + } + + /* clear the history */ + tsentry = -1; + + /* reset max str len */ + srclen = dstlen = 0; + + /* read the state table and store in tstable */ + for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) { + + if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, + sizeof(ips))) + break; + + if (ips.is_v != ver) + continue; + + /* check v4 src/dest addresses */ + if (ips.is_v == 4) { + if ((saddr.in4.s_addr != INADDR_ANY && + saddr.in4.s_addr != ips.is_saddr) || + (daddr.in4.s_addr != INADDR_ANY && + daddr.in4.s_addr != ips.is_daddr)) + continue; + } +#ifdef USE_INET6 + /* check v6 src/dest addresses */ + if (ips.is_v == 6) { + if ((IP6_NEQ(&saddr, &in6addr_any) && + IP6_NEQ(&saddr, &ips.is_src)) || + (IP6_NEQ(&daddr, &in6addr_any) && + IP6_NEQ(&daddr, &ips.is_dst))) + continue; + } +#endif + /* check protocol */ + if (protocol > 0 && protocol != ips.is_p) + continue; + + /* check ports if protocol is TCP or UDP */ + if (((ips.is_p == IPPROTO_TCP) || + (ips.is_p == IPPROTO_UDP)) && + (((sport > 0) && (htons(sport) != ips.is_sport)) || + ((dport > 0) && (htons(dport) != ips.is_dport)))) + continue; + + /* show closed TCP sessions ? */ + if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) && + (ips.is_state[0] >= IPF_TCPS_LAST_ACK) && + (ips.is_state[1] >= IPF_TCPS_LAST_ACK)) + continue; + + /* + * if necessary make room for this state + * entry + */ + tsentry++; + if (!maxtsentries || tsentry == maxtsentries) { + maxtsentries += STGROWSIZE; + tstable = realloc(tstable, + maxtsentries * sizeof(statetop_t)); + if (tstable == NULL) { + perror("realloc"); + exit(-1); + } + } + + /* get max src/dest address string length */ + len = strlen(getip(ips.is_v, &ips.is_src)); + if (srclen < len) + srclen = len; + len = strlen(getip(ips.is_v, &ips.is_dst)); + if (dstlen < len) + dstlen = len; + + /* 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_v = ips.is_v; + tp->st_state[0] = ips.is_state[0]; + tp->st_state[1] = ips.is_state[1]; + if (forward) { + tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1]; + tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1]; + } else { + tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3]; + tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3]; + } + tp->st_age = ips.is_die - ipsstp->iss_ticks; + 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; + case STSORT_SRCIP: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_srcip); + break; + case STSORT_SRCPT: + qsort(tstable, tsentry +1, + sizeof(statetop_t), sort_srcpt); + break; + case STSORT_DSTIP: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_dstip); + break; + case STSORT_DSTPT: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_dstpt); + break; + default: + break; + } + } + + /* handle window resizes */ + if (handle_resize) { + endwin(); + initscr(); + cbreak(); + noecho(); + curs_set(0); + timeout(0); + getmaxyx(stdscr, maxy, maxx); + redraw = 1; + handle_resize = 0; + } + + /* stop program? */ + if (handle_break) + break; + + /* print title */ + erase(); + attron(A_BOLD); + winy = 0; + move(winy,0); + sprintf(str1, "%s - %s - state top", hostnm, 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(winy, 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", getip(ver, &saddr), sport); + else + sprintf(str1, "%s", getip(ver, &saddr)); + + if (dport >= 0) + sprintf(str2, "%s,%d", getip(ver, &daddr), dport); + else + sprintf(str2, "%s", getip(ver, &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; + case STSORT_SRCIP: + sprintf(str4, "src ip"); + break; + case STSORT_SRCPT: + sprintf(str4, "src port"); + break; + case STSORT_DSTIP: + sprintf(str4, "dest ip"); + break; + case STSORT_DSTPT: + sprintf(str4, "dest port"); + break; + default: + sprintf(str4, "unknown"); + break; + } + + if (reverse) + strcat(str4, " (reverse)"); + + winy += 2; + move(winy,0); + printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n", + str1, str2, str3, str4); + + /* + * For an IPv4 IP address we need at most 15 characters, + * 4 tuples of 3 digits, separated by 3 dots. Enforce this + * length, so the colums do not change positions based + * on the size of the IP address. This length makes the + * output fit in a 80 column terminal. + * We are lacking a good solution for IPv6 addresses (that + * can be longer that 15 characters), so we do not enforce + * a maximum on the IP field size. + */ + if (srclen < 15) + srclen = 15; + if (dstlen < 15) + dstlen = 15; + + /* print column description */ + winy += 2; + move(winy,0); + attron(A_BOLD); + printw("%-*s %-*s %3s %4s %7s %9s %9s\n", + srclen + 6, "Source IP", dstlen + 6, "Destination IP", + "ST", "PR", "#pkts", "#bytes", "ttl"); + attroff(A_BOLD); + + /* print all the entries */ + tp = tstable; + if (reverse) + tp += tsentry; + + if (tsentry > maxy - 6) + tsentry = maxy - 6; + 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", + getip(tp->st_v, &tp->st_src), + ntohs(tp->st_sport)); + sprintf(str2, "%s,%hu", + getip(tp->st_v, &tp->st_dst), + ntohs(tp->st_dport)); + } else { + sprintf(str1, "%s", getip(tp->st_v, + &tp->st_src)); + sprintf(str2, "%s", getip(tp->st_v, + &tp->st_dst)); + } + winy++; + move(winy, 0); + printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2); + + /* print state */ + sprintf(str1, "%X/%X", tp->st_state[0], + tp->st_state[1]); + printw(" %3s", str1); + + /* print protocol */ + proto = getprotobynumber(tp->st_p); + if (proto) { + strncpy(str1, proto->p_name, 4); + str1[4] = '\0'; + } else { + sprintf(str1, "%d", tp->st_p); + } + /* just print icmp for IPv6-ICMP */ + if (tp->st_p == IPPROTO_ICMPV6) + strcpy(str1, "icmp"); + 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); + + if (refresh() == ERR) + break; + 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)) { + c = wgetch(stdscr); + if (c == ERR) + continue; + + if (ISALPHA(c) && ISUPPER(c)) + c = TOLOWER(c); + if (c == 'l') { + redraw = 1; + } else if (c == 'q') { + break; + } else if (c == 'r') { + reverse = !reverse; + } else if (c == 'b') { + forward = 0; + } else if (c == 'f') { + forward = 1; + } else if (c == 's') { + if (++sorting > STSORT_MAX) + sorting = 0; + } + } + } /* while */ + + printw("\n"); + curs_set(1); + nocbreak(); + endwin(); + + free(tstable); +} +#endif + + +/* + * Show fragment cache information that's held in the kernel. + */ +static void showfrstates(ifsp) +ipfrstat_t *ifsp; +{ + struct ipfr *ipfrtab[IPFT_SIZE], ifr; + int i; + + /* + * print out the numeric statistics + */ + PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n", + ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits); + PRINTF("\t%lu retrans\n\t%lu too short\n", + ifsp->ifs_retrans0, ifsp->ifs_short); + PRINTF("\t%lu no memory\n\t%lu already exist\n", + ifsp->ifs_nomem, ifsp->ifs_exists); + PRINTF("\t%lu inuse\n", ifsp->ifs_inuse); + if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab))) + return; + + /* + * Print out the contents (if any) of the fragment cache table. + */ + PRINTF("\n"); + for (i = 0; i < IPFT_SIZE; i++) + while (ipfrtab[i] != NULL) { + if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], + sizeof(ifr)) == -1) + break; + printfraginfo("", &ifr); + ipfrtab[i] = ifr.ipfr_next; + } + /* + * Print out the contents (if any) of the NAT fragment cache table. + */ + if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab))) + return; + for (i = 0; i < IPFT_SIZE; i++) + while (ipfrtab[i] != NULL) { + if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], + sizeof(ifr)) == -1) + break; + printfraginfo("NAT: ", &ifr); + ipfrtab[i] = ifr.ipfr_next; + } +} + + +/* + * Show stats on how auth within IPFilter has been used + */ +static void showauthstates(asp) +fr_authstat_t *asp; +{ + frauthent_t *frap, fra; + +#ifdef USE_QUAD_T + 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); +#endif + printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n", + asp->fas_nospace, asp->fas_added, asp->fas_sendfail, + asp->fas_sendok); + printf("queok %ld\nquefail %ld\nexpire %ld\n", + asp->fas_queok, asp->fas_quefail, asp->fas_expire); + + frap = asp->fas_faelist; + while (frap) { + if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1) + break; + + printf("age %ld\t", fra.fae_age); + printfr(&fra.fae_fr, ioctl); + frap = fra.fae_next; + } +} + + +/* + * Display groups used for each of filter rules, accounting rules and + * authentication, separately. + */ +static void showgroups(fiop) +struct friostat *fiop; +{ + static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; + static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH }; + frgroup_t *fp, grp; + int on, off, i; + + on = fiop->f_active; + off = 1 - on; + + for (i = 0; i < 3; i++) { + printf("%s groups (active):\n", gnames[i]); + for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL; + fp = grp.fg_next) + if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) + break; + else + printf("%s\n", grp.fg_name); + printf("%s groups (inactive):\n", gnames[i]); + for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL; + fp = grp.fg_next) + if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) + break; + else + printf("%s\n", grp.fg_name); + } +} + +static void parse_ipportstr(argument, ip, port) +const char *argument; +i6addr_t *ip; +int *port; +{ + char *s, *comma; + int ok = 0; + + /* make working copy of argument, Theoretically you must be able + * to write to optarg, but that seems very ugly to me.... + */ + s = strdup(argument); + if (s == NULL) + return; + + /* get port */ + if ((comma = strchr(s, ',')) != NULL) { + if (!strcasecmp(comma + 1, "any")) { + *port = -1; + } else if (!sscanf(comma + 1, "%d", port) || + (*port < 0) || (*port > 65535)) { + fprintf(stderr, "Invalid port specfication in %s\n", + argument); + free(s); + exit(-2); + } + *comma = '\0'; + } + + + /* get ip address */ + if (!strcasecmp(s, "any")) { + ip->in4.s_addr = INADDR_ANY; +#ifdef USE_INET6 + ip->in6 = in6addr_any; + } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) { + ok = 1; +#endif + } else if (inet_aton(s, &ip->in4)) + ok = 1; + + if (ok == 0) { + fprintf(stderr, "Invalid IP address: %s\n", s); + free(s); + exit(-2); + } + + /* free allocated memory */ + free(s); +} + + +#ifdef STATETOP +static void sig_resize(s) +int s; +{ + handle_resize = 1; +} + +static void sig_break(s) +int s; +{ + handle_break = 1; +} + +static char *getip(v, addr) +int v; +i6addr_t *addr; +{ + static char hostbuf[MAXHOSTNAMELEN+1]; + + if (v == 4) + return inet_ntoa(addr->in4); + +#ifdef USE_INET6 + (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1); + hostbuf[MAXHOSTNAMELEN] = '\0'; + return hostbuf; +#else + return "IPv6"; +#endif +} + + +static char *ttl_to_string(ttl) +long int ttl; +{ + static char ttlbuf[STSTRSIZE]; + 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; +} + +static int sort_srcip(a, b) +const void *a; +const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + +#ifdef USE_INET6 + if (use_inet6) { + if (IP6_EQ(&ap->st_src, &bp->st_src)) + return 0; + else if (IP6_GT(&ap->st_src, &bp->st_src)) + return 1; + } else +#endif + { + if (ntohl(ap->st_src.in4.s_addr) == + ntohl(bp->st_src.in4.s_addr)) + return 0; + else if (ntohl(ap->st_src.in4.s_addr) > + ntohl(bp->st_src.in4.s_addr)) + return 1; + } + return -1; +} + +static int sort_srcpt(a, b) +const void *a; +const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (htons(ap->st_sport) == htons(bp->st_sport)) + return 0; + else if (htons(ap->st_sport) > htons(bp->st_sport)) + return 1; + return -1; +} + +static int sort_dstip(a, b) +const void *a; +const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + +#ifdef USE_INET6 + if (use_inet6) { + if (IP6_EQ(&ap->st_dst, &bp->st_dst)) + return 0; + else if (IP6_GT(&ap->st_dst, &bp->st_dst)) + return 1; + } else +#endif + { + if (ntohl(ap->st_dst.in4.s_addr) == + ntohl(bp->st_dst.in4.s_addr)) + return 0; + else if (ntohl(ap->st_dst.in4.s_addr) > + ntohl(bp->st_dst.in4.s_addr)) + return 1; + } + return -1; +} + +static int sort_dstpt(a, b) +const void *a; +const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (htons(ap->st_dport) == htons(bp->st_dport)) + return 0; + else if (htons(ap->st_dport) > htons(bp->st_dport)) + return 1; + return -1; +} + +#endif diff --git a/contrib/ipfilter/tools/ipftest.c b/contrib/ipfilter/tools/ipftest.c new file mode 100644 index 0000000..fbc91e5 --- /dev/null +++ b/contrib/ipfilter/tools/ipftest.c @@ -0,0 +1,776 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include "ipf.h" +#include "ipt.h" +#include <sys/ioctl.h> +#include <sys/file.h> + +#if !defined(lint) +static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipftest.c,v 1.44.2.3 2005/02/01 02:41:24 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 *, int)); +extern void init_ifp __P((void)); +extern ipnat_t *natparse __P((char *, int)); +extern int fr_running; + +ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; +ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; +ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ip_poolrw; +ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; +int opts = OPT_DONOTHING; +int use_inet6 = 0; +int pfil_delayed_copy = 0; +int main __P((int, char *[])); +int loadrules __P((char *, int)); +int kmemcpy __P((char *, long, int)); +int kstrncpy __P((char *, long, int n)); +void dumpnat __P((void)); +void dumpstate __P((void)); +void dumplookups __P((void)); +void dumpgroups __P((void)); +void drain_log __P((char *)); +void fixv4sums __P((mb_t *, ip_t *)); + +#if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ + defined(__osf__) || defined(linux) +int ipftestioctl __P((int, ioctlcmd_t, ...)); +int ipnattestioctl __P((int, ioctlcmd_t, ...)); +int ipstatetestioctl __P((int, ioctlcmd_t, ...)); +int ipauthtestioctl __P((int, ioctlcmd_t, ...)); +int ipscantestioctl __P((int, ioctlcmd_t, ...)); +int ipsynctestioctl __P((int, ioctlcmd_t, ...)); +int ipooltestioctl __P((int, ioctlcmd_t, ...)); +#else +int ipftestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipnattestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipstatetestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipauthtestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipsynctestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipscantestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipooltestioctl __P((dev_t, ioctlcmd_t, void *)); +#endif + +static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ipftestioctl, + ipnattestioctl, + ipstatetestioctl, + ipauthtestioctl, + ipsynctestioctl, + ipscantestioctl, + ipooltestioctl, + NULL }; + + +int main(argc,argv) +int argc; +char *argv[]; +{ + char *datain, *iface, *ifname, *logout; + int fd, i, dir, c, loaded, dump, hlen; + struct ifnet *ifp; + struct ipread *r; + mb_t mb, *m; + ip_t *ip; + + m = &mb; + dir = 0; + dump = 0; + hlen = 0; + loaded = 0; + r = &iptext; + iface = NULL; + logout = NULL; + ifname = "anon0"; + datain = NULL; + + MUTEX_INIT(&ipf_rw, "ipf rw mutex"); + MUTEX_INIT(&ipf_timeoutlock, "ipf timeout lock"); + RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); + RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); + RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); + + initparse(); + if (fr_initialise() == -1) + abort(); + fr_running = 1; + + while ((c = getopt(argc, argv, "6bdDF:i:I:l:N:P:or:RT:vxX")) != -1) + switch (c) + { + case '6' : +#ifdef USE_INET6 + use_inet6 = 1; +#else + fprintf(stderr, "IPv6 not supported\n"); + exit(1); +#endif + break; + case 'b' : + opts |= OPT_BRIEF; + break; + case 'd' : + opts |= OPT_DEBUG; + break; + case 'D' : + dump = 1; + break; + case 'F' : + if (strcasecmp(optarg, "pcap") == 0) + r = &pcap; + else if (strcasecmp(optarg, "etherfind") == 0) + r = ðerf; + else if (strcasecmp(optarg, "snoop") == 0) + r = &snoop; + else if (strcasecmp(optarg, "tcpdump") == 0) + r = &tcpd; + else if (strcasecmp(optarg, "hex") == 0) + r = &iphex; + else if (strcasecmp(optarg, "text") == 0) + r = &iptext; + break; + case 'i' : + datain = optarg; + break; + case 'I' : + ifname = optarg; + break; + case 'l' : + logout = optarg; + break; + case 'o' : + opts |= OPT_SAVEOUT; + break; + case 'r' : + if (ipf_parsefile(-1, ipf_addrule, iocfunctions, + optarg) == -1) + return -1; + loaded = 1; + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + case 'N' : + if (ipnat_parsefile(-1, ipnat_addrule, ipnattestioctl, + optarg) == -1) + return -1; + loaded = 1; + opts |= OPT_NAT; + break; + case 'P' : + if (ippool_parsefile(-1, optarg, ipooltestioctl) == -1) + return -1; + loaded = 1; + break; + case 'T' : + ipf_dotuning(-1, optarg, ipftestioctl); + break; + case 'x' : + opts |= OPT_HEX; + break; + } + + if (loaded == 0) { + (void)fprintf(stderr,"no rules loaded\n"); + exit(-1); + } + + if (opts & OPT_SAVEOUT) + init_ifp(); + + if (datain) + fd = (*r->r_open)(datain); + else + fd = (*r->r_open)("-"); + + if (fd < 0) + exit(-1); + + ip = MTOD(m, ip_t *); + while ((i = (*r->r_readip)(MTOD(m, char *), sizeof(m->mb_buf), + &iface, &dir)) > 0) { + if (iface == NULL || *iface == '\0') + iface = ifname; + ifp = get_unit(iface, IP_V(ip)); + if (!use_inet6) { + ip->ip_off = ntohs(ip->ip_off); + ip->ip_len = ntohs(ip->ip_len); + if (r->r_flags & R_DO_CKSUM) + fixv4sums(m, ip); + hlen = IP_HL(ip) << 2; + } +#ifdef USE_INET6 + else + hlen = sizeof(ip6_t); +#endif + /* ipfr_slowtimer(); */ + m = &mb; + m->mb_len = i; + i = fr_check(ip, hlen, ifp, dir, &m); + if ((opts & OPT_NAT) == 0) + switch (i) + { + case -4 : + (void)printf("preauth"); + break; + case -3 : + (void)printf("account"); + break; + case -2 : + (void)printf("auth"); + break; + case -1 : + (void)printf("block"); + break; + case 0 : + (void)printf("pass"); + break; + case 1 : + (void)printf("nomatch"); + break; + case 3 : + (void)printf("block return-rst"); + break; + case 4 : + (void)printf("block return-icmp"); + break; + case 5 : + (void)printf("block return-icmp-as-dest"); + break; + default : + (void)printf("recognised return %#x\n", i); + break; + } + if (!use_inet6) { + ip->ip_off = htons(ip->ip_off); + ip->ip_len = htons(ip->ip_len); + } + + if (!(opts & OPT_BRIEF)) { + putchar(' '); + printpacket(ip); + printf("--------------"); + } else if ((opts & (OPT_BRIEF|OPT_NAT)) == (OPT_NAT|OPT_BRIEF)) + printpacket(ip); + if (dir && (ifp != NULL) && IP_V(ip) && (m != NULL)) +#if defined(__sgi) && (IRIX < 60500) + (*ifp->if_output)(ifp, (void *)m, NULL); +#else +# if TRU64 >= 1885 + (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0); +# else + (*ifp->if_output)(ifp, (void *)m, NULL, 0); +# endif +#endif + if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF)) + putchar('\n'); + dir = 0; + if (iface != ifname) { + free(iface); + iface = ifname; + } + m = &mb; + } + (*r->r_close)(); + + if (logout != NULL) { + drain_log(logout); + } + + if (dump == 1) { + dumpnat(); + dumpstate(); + dumplookups(); + dumpgroups(); + } + + fr_deinitialise(); + + return 0; +} + + +#if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ + defined(__osf__) || defined(linux) +int ipftestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = iplioctl(IPL_LOGIPF, cmd, data, FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, "iplioctl(IPF,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipnattestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = iplioctl(IPL_LOGNAT, cmd, data, FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, "iplioctl(NAT,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipstatetestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = iplioctl(IPL_LOGSTATE, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(STATE,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipauthtestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = iplioctl(IPL_LOGAUTH, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(AUTH,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipscantestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = iplioctl(IPL_LOGSCAN, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(SCAN,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipsynctestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = iplioctl(IPL_LOGSYNC, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(SYNC,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipooltestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = iplioctl(IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(POOL,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} +#else +int ipftestioctl(dev, cmd, data) +dev_t dev; +ioctlcmd_t cmd; +void *data; +{ + int i; + + i = iplioctl(IPL_LOGIPF, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(IPF,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipnattestioctl(dev, cmd, data) +dev_t dev; +ioctlcmd_t cmd; +void *data; +{ + int i; + + i = iplioctl(IPL_LOGNAT, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(NAT,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipstatetestioctl(dev, cmd, data) +dev_t dev; +ioctlcmd_t cmd; +void *data; +{ + int i; + + i = iplioctl(IPL_LOGSTATE, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(STATE,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipauthtestioctl(dev, cmd, data) +dev_t dev; +ioctlcmd_t cmd; +void *data; +{ + int i; + + i = iplioctl(IPL_LOGAUTH, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(AUTH,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipsynctestioctl(dev, cmd, data) +dev_t dev; +ioctlcmd_t cmd; +void *data; +{ + int i; + + i = iplioctl(IPL_LOGSYNC, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(SYNC,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipscantestioctl(dev, cmd, data) +dev_t dev; +ioctlcmd_t cmd; +void *data; +{ + int i; + + i = iplioctl(IPL_LOGSCAN, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "iplioctl(SCAN,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipooltestioctl(dev, cmd, data) +dev_t dev; +ioctlcmd_t cmd; +void *data; +{ + int i; + + i = iplioctl(IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, "iplioctl(POOL,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} +#endif + + +int kmemcpy(addr, offset, size) +char *addr; +long offset; +int size; +{ + bcopy((char *)offset, addr, size); + return 0; +} + + +int kstrncpy(buf, pos, n) +char *buf; +long pos; +int n; +{ + char *ptr; + + ptr = (char *)pos; + + while ((n > 0) && (*buf++ = *ptr++)) + ; + return 0; +} + + +/* + * Display the built up NAT table rules and mapping entries. + */ +void dumpnat() +{ + ipnat_t *ipn; + nat_t *nat; + + printf("List of active MAP/Redirect filters:\n"); + for (ipn = nat_list; ipn != NULL; ipn = ipn->in_next) + printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); + printf("\nList of active sessions:\n"); + for (nat = nat_instances; nat; nat = nat->nat_next) { + printactivenat(nat, opts); + if (nat->nat_aps) + printaps(nat->nat_aps, opts); + } +} + + +/* + * Display the built up state table rules and mapping entries. + */ +void dumpstate() +{ + ipstate_t *ips; + + printf("List of active state sessions:\n"); + for (ips = ips_list; ips != NULL; ) + ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE), + fr_ticks); +} + + +void dumplookups() +{ + iphtable_t *iph; + ip_pool_t *ipl; + int i; + + printf("List of configured pools\n"); + for (i = 0; i < IPL_LOGSIZE; i++) + for (ipl = ip_pool_list[i]; ipl != NULL; ipl = ipl->ipo_next) + printpool(ipl, bcopywrap, NULL, opts); + + printf("List of configured hash tables\n"); + for (i = 0; i < IPL_LOGSIZE; i++) + for (iph = ipf_htables[i]; iph != NULL; iph = iph->iph_next) + printhash(iph, bcopywrap, NULL, opts); +} + + +void dumpgroups() +{ + frgroup_t *fg; + frentry_t *fr; + int i; + + printf("List of groups configured (set 0)\n"); + for (i = 0; i < IPL_LOGSIZE; i++) + for (fg = ipfgroups[i][0]; fg != NULL; fg = fg->fg_next) { + printf("Dev.%d. Group %s Ref %d Flags %#x\n", + i, fg->fg_name, fg->fg_ref, fg->fg_flags); + for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) { +#ifdef USE_QUAD_T + printf("%qu ",(unsigned long long)fr->fr_hits); +#else + printf("%ld ", fr->fr_hits); +#endif + printfr(fr, ipftestioctl); + } + } + + printf("List of groups configured (set 1)\n"); + for (i = 0; i < IPL_LOGSIZE; i++) + for (fg = ipfgroups[i][1]; fg != NULL; fg = fg->fg_next) { + printf("Dev.%d. Group %s Ref %d Flags %#x\n", + i, fg->fg_name, fg->fg_ref, fg->fg_flags); + for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) { +#ifdef USE_QUAD_T + printf("%qu ",(unsigned long long)fr->fr_hits); +#else + printf("%ld ", fr->fr_hits); +#endif + printfr(fr, ipftestioctl); + } + } +} + + +void drain_log(filename) +char *filename; +{ + char buffer[DEFAULT_IPFLOGSIZE]; + struct iovec iov; + struct uio uio; + size_t resid; + int fd, i; + + fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644); + if (fd == -1) { + perror("drain_log:open"); + return; + } + + for (i = 0; i <= IPL_LOGMAX; i++) + while (1) { + bzero((char *)&iov, sizeof(iov)); + iov.iov_base = buffer; + iov.iov_len = sizeof(buffer); + + bzero((char *)&uio, sizeof(uio)); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_resid = iov.iov_len; + resid = uio.uio_resid; + + if (ipflog_read(i, &uio) == 0) { + /* + * If nothing was read then break out. + */ + if (uio.uio_resid == resid) + break; + write(fd, buffer, resid - uio.uio_resid); + } else + break; + } + + close(fd); +} + + +void fixv4sums(m, ip) +mb_t *m; +ip_t *ip; +{ + u_char *csump, *hdr; + + ip->ip_sum = 0; + ip->ip_sum = ipf_cksum((u_short *)ip, IP_HL(ip) << 2); + + csump = (u_char *)ip; + csump += IP_HL(ip) << 2; + + switch (ip->ip_p) + { + case IPPROTO_TCP : + hdr = csump; + csump += offsetof(tcphdr_t, th_sum); + break; + case IPPROTO_UDP : + hdr = csump; + csump += offsetof(udphdr_t, uh_sum); + break; + default : + csump = NULL; + hdr = NULL; + break; + } + if (hdr != NULL) { + *csump = 0; + *(u_short *)csump = fr_cksum(m, ip, ip->ip_p, hdr); + } +} diff --git a/contrib/ipfilter/tools/ipmon.c b/contrib/ipfilter/tools/ipmon.c new file mode 100644 index 0000000..a91eee4 --- /dev/null +++ b/contrib/ipfilter/tools/ipmon.c @@ -0,0 +1,1663 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001, 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifndef SOLARIS +#define SOLARIS (defined(__SVR4) || defined(__svr4__)) && defined(sun) +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/file.h> +#include <sys/time.h> +#define _KERNEL +#include <sys/uio.h> +#undef _KERNEL +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> +#if !defined(__SVR4) && !defined(__svr4__) +# if (__FreeBSD_version >= 300000) +# include <sys/dirent.h> +# else +# include <sys/dir.h> +# endif +#else +# include <sys/filio.h> +# include <sys/byteorder.h> +#endif +#if !defined(__hpux) && (!defined(__SVR4) && !defined(__GNUC__)) +# include <strings.h> +#endif +#include <signal.h> +#include <stdlib.h> +#include <stddef.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <net/if.h> +#include <netinet/ip.h> +#if !defined(__hpux) && !defined(linux) +# include <netinet/tcp_fsm.h> +#endif +#include <netdb.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#ifdef __hpux +# undef NOERROR +#endif +#include <resolv.h> + +#if !defined(linux) +# include <sys/protosw.h> +# include <netinet/ip_var.h> +#endif + +#include <netinet/tcp.h> +#include <netinet/ip_icmp.h> + +#include <ctype.h> +#include <syslog.h> + +#include "netinet/ip_compat.h" +#include <netinet/tcpip.h> +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "ipmon.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipmon.c,v 1.33.2.8 2004/12/09 19:41:26 darrenr Exp"; +#endif + + +#if defined(sun) && !defined(SOLARIS2) +#define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +#define STRERROR(x) strerror(x) +#endif + + +struct flags { + int value; + char flag; +}; + + +typedef struct icmp_subtype { + int ist_val; + char *ist_name; +} icmp_subtype_t; + +typedef struct icmp_type { + int it_val; + struct icmp_subtype *it_subtable; + size_t it_stsize; + char *it_name; +} icmp_type_t; + + +#define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t)) + + +struct flags tcpfl[] = { + { TH_ACK, 'A' }, + { TH_RST, 'R' }, + { TH_SYN, 'S' }, + { TH_FIN, 'F' }, + { TH_URG, 'U' }, + { TH_PUSH,'P' }, + { TH_ECN, 'E' }, + { TH_CWR, 'C' }, + { 0, '\0' } +}; + +#ifdef MENTAT +static char *pidfile = "/etc/opt/ipf/ipmon.pid"; +#else +# if BSD >= 199306 +static char *pidfile = "/var/run/ipmon.pid"; +# else +static char *pidfile = "/etc/ipmon.pid"; +# endif +#endif + +static char line[2048]; +static int opts = 0; +static char *logfile = NULL; +static FILE *binarylog = NULL; +static char *binarylogfile = NULL; +static int donehup = 0; +static void usage __P((char *)); +static void handlehup __P((int)); +static void flushlogs __P((char *, FILE *)); +static void print_log __P((int, FILE *, char *, int)); +static void print_ipflog __P((FILE *, char *, int)); +static void print_natlog __P((FILE *, char *, int)); +static void print_statelog __P((FILE *, char *, int)); +static int read_log __P((int, int *, char *, int)); +static void write_pid __P((char *)); +static char *icmpname __P((u_int, u_int)); +static char *icmpname6 __P((u_int, u_int)); +static icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t)); +static icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t)); +#ifdef __hpux +static struct tm *get_tm __P((u_32_t)); +#else +static struct tm *get_tm __P((time_t)); +#endif + +char *hostname __P((int, int, u_32_t *)); +char *portname __P((int, char *, u_int)); +int main __P((int, char *[])); + +static void logopts __P((int, char *)); +static void init_tabs __P((void)); +static char *getproto __P((u_int)); + +static char **protocols = NULL; +static char **udp_ports = NULL; +static char **tcp_ports = NULL; +static char *conf_file = NULL; + + +#define OPT_SYSLOG 0x001 +#define OPT_RESOLVE 0x002 +#define OPT_HEXBODY 0x004 +#define OPT_VERBOSE 0x008 +#define OPT_HEXHDR 0x010 +#define OPT_TAIL 0x020 +#define OPT_NAT 0x080 +#define OPT_STATE 0x100 +#define OPT_FILTER 0x200 +#define OPT_PORTNUM 0x400 +#define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) +#define OPT_LOGBODY 0x800 + +#define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) + +#ifndef LOGFAC +#define LOGFAC LOG_LOCAL0 +#endif + + +static icmp_subtype_t icmpunreachnames[] = { + { ICMP_UNREACH_NET, "net" }, + { ICMP_UNREACH_HOST, "host" }, + { ICMP_UNREACH_PROTOCOL, "protocol" }, + { ICMP_UNREACH_PORT, "port" }, + { ICMP_UNREACH_NEEDFRAG, "needfrag" }, + { ICMP_UNREACH_SRCFAIL, "srcfail" }, + { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" }, + { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" }, + { ICMP_UNREACH_NET, "isolated" }, + { ICMP_UNREACH_NET_PROHIB, "net_prohib" }, + { ICMP_UNREACH_NET_PROHIB, "host_prohib" }, + { ICMP_UNREACH_TOSNET, "tosnet" }, + { ICMP_UNREACH_TOSHOST, "toshost" }, + { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" }, + { -2, NULL } +}; + +static icmp_subtype_t redirectnames[] = { + { ICMP_REDIRECT_NET, "net" }, + { ICMP_REDIRECT_HOST, "host" }, + { ICMP_REDIRECT_TOSNET, "tosnet" }, + { ICMP_REDIRECT_TOSHOST, "toshost" }, + { -2, NULL } +}; + +static icmp_subtype_t timxceednames[] = { + { ICMP_TIMXCEED_INTRANS, "transit" }, + { ICMP_TIMXCEED_REASS, "reassem" }, + { -2, NULL } +}; + +static icmp_subtype_t paramnames[] = { + { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" }, + { ICMP_PARAMPROB_OPTABSENT, "optmissing" }, + { ICMP_PARAMPROB_LENGTH, "length" }, + { -2, NULL } +}; + +static icmp_type_t icmptypes[] = { + { ICMP_ECHOREPLY, NULL, 0, "echoreply" }, + { -1, NULL, 0, NULL }, + { -1, NULL, 0, NULL }, + { ICMP_UNREACH, icmpunreachnames, + IST_SZ(icmpunreachnames),"unreach" }, + { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" }, + { ICMP_REDIRECT, redirectnames, + IST_SZ(redirectnames), "redirect" }, + { -1, NULL, 0, NULL }, + { -1, NULL, 0, NULL }, + { ICMP_ECHO, NULL, 0, "echo" }, + { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" }, + { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" }, + { ICMP_TIMXCEED, timxceednames, + IST_SZ(timxceednames), "timxceed" }, + { ICMP_PARAMPROB, paramnames, + IST_SZ(paramnames), "paramprob" }, + { ICMP_TSTAMP, NULL, 0, "timestamp" }, + { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" }, + { ICMP_IREQ, NULL, 0, "inforeq" }, + { ICMP_IREQREPLY, NULL, 0, "inforeply" }, + { ICMP_MASKREQ, NULL, 0, "maskreq" }, + { ICMP_MASKREPLY, NULL, 0, "maskreply" }, + { -2, NULL, 0, NULL } +}; + +static icmp_subtype_t icmpredirect6[] = { + { ICMP6_DST_UNREACH_NOROUTE, "noroute" }, + { ICMP6_DST_UNREACH_ADMIN, "admin" }, + { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" }, + { ICMP6_DST_UNREACH_ADDR, "address" }, + { ICMP6_DST_UNREACH_NOPORT, "noport" }, + { -2, NULL } +}; + +static icmp_subtype_t icmptimexceed6[] = { + { ICMP6_TIME_EXCEED_TRANSIT, "intransit" }, + { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" }, + { -2, NULL } +}; + +static icmp_subtype_t icmpparamprob6[] = { + { ICMP6_PARAMPROB_HEADER, "header" }, + { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" }, + { ICMP6_PARAMPROB_OPTION, "option" }, + { -2, NULL } +}; + +static icmp_subtype_t icmpquerysubject6[] = { + { ICMP6_NI_SUBJ_IPV6, "ipv6" }, + { ICMP6_NI_SUBJ_FQDN, "fqdn" }, + { ICMP6_NI_SUBJ_IPV4, "ipv4" }, + { -2, NULL }, +}; + +static icmp_subtype_t icmpnodeinfo6[] = { + { ICMP6_NI_SUCCESS, "success" }, + { ICMP6_NI_REFUSED, "refused" }, + { ICMP6_NI_UNKNOWN, "unknown" }, + { -2, NULL } +}; + +static icmp_subtype_t icmprenumber6[] = { + { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" }, + { ICMP6_ROUTER_RENUMBERING_RESULT, "result" }, + { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" }, + { -2, NULL } +}; + +static icmp_type_t icmptypes6[] = { + { 0, NULL, 0, NULL }, + { ICMP6_DST_UNREACH, icmpredirect6, + IST_SZ(icmpredirect6), "unreach" }, + { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" }, + { ICMP6_TIME_EXCEEDED, icmptimexceed6, + IST_SZ(icmptimexceed6), "timxceed" }, + { ICMP6_PARAM_PROB, icmpparamprob6, + IST_SZ(icmpparamprob6), "paramprob" }, + { ICMP6_ECHO_REQUEST, NULL, 0, "echo" }, + { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" }, + { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6, + IST_SZ(icmpquerysubject6), "groupmemberquery" }, + { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" }, + { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" }, + { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" }, + { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" }, + { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" }, + { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" }, + { ND_REDIRECT, NULL, 0, "redirect" }, + { ICMP6_ROUTER_RENUMBERING, icmprenumber6, + IST_SZ(icmprenumber6), "routerrenumber" }, + { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" }, + { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" }, + { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" }, + { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" }, + { ICMP6_NI_QUERY, icmpnodeinfo6, + IST_SZ(icmpnodeinfo6), "nodeinforequest" }, + { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" }, + { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" }, + { MLD6_MTRACE, NULL, 0, "mtracerequest" }, + { -2, NULL, 0, NULL } +}; + +static icmp_subtype_t *find_icmpsubtype(type, table, tablesz) +int type; +icmp_subtype_t *table; +size_t tablesz; +{ + icmp_subtype_t *ist; + int i; + + if (tablesz < 2) + return NULL; + + if ((type < 0) || (type > table[tablesz - 2].ist_val)) + return NULL; + + i = type; + if (table[type].ist_val == type) + return table + type; + + for (i = 0, ist = table; ist->ist_val != -2; i++, ist++) + if (ist->ist_val == type) + return ist; + return NULL; +} + + +static icmp_type_t *find_icmptype(type, table, tablesz) +int type; +icmp_type_t *table; +size_t tablesz; +{ + icmp_type_t *it; + int i; + + if (tablesz < 2) + return NULL; + + if ((type < 0) || (type > table[tablesz - 2].it_val)) + return NULL; + + i = type; + if (table[type].it_val == type) + return table + type; + + for (i = 0, it = table; it->it_val != -2; i++, it++) + if (it->it_val == type) + return it; + return NULL; +} + + +static void handlehup(sig) +int sig; +{ + signal(SIGHUP, handlehup); + donehup = 1; +} + + +static void init_tabs() +{ + struct protoent *p; + struct servent *s; + char *name, **tab; + int port, i; + + if (protocols != NULL) { + for (i = 0; i < 256; i++) + if (protocols[i] != NULL) { + free(protocols[i]); + protocols[i] = NULL; + } + free(protocols); + protocols = NULL; + } + protocols = (char **)malloc(256 * sizeof(*protocols)); + if (protocols != NULL) { + bzero((char *)protocols, 256 * sizeof(*protocols)); + + setprotoent(1); + while ((p = getprotoent()) != NULL) + if (p->p_proto >= 0 && p->p_proto <= 255 && + p->p_name != NULL && protocols[p->p_proto] == NULL) + protocols[p->p_proto] = strdup(p->p_name); + endprotoent(); + } + + if (udp_ports != NULL) { + for (i = 0; i < 65536; i++) + if (udp_ports[i] != NULL) { + free(udp_ports[i]); + udp_ports[i] = NULL; + } + free(udp_ports); + udp_ports = NULL; + } + udp_ports = (char **)malloc(65536 * sizeof(*udp_ports)); + if (udp_ports != NULL) + bzero((char *)udp_ports, 65536 * sizeof(*udp_ports)); + + if (tcp_ports != NULL) { + for (i = 0; i < 65536; i++) + if (tcp_ports[i] != NULL) { + free(tcp_ports[i]); + tcp_ports[i] = NULL; + } + free(tcp_ports); + tcp_ports = NULL; + } + tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports)); + if (tcp_ports != NULL) + bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports)); + + setservent(1); + while ((s = getservent()) != NULL) { + if (s->s_proto == NULL) + continue; + else if (!strcmp(s->s_proto, "tcp")) { + port = ntohs(s->s_port); + name = s->s_name; + tab = tcp_ports; + } else if (!strcmp(s->s_proto, "udp")) { + port = ntohs(s->s_port); + name = s->s_name; + tab = udp_ports; + } else + continue; + if ((port < 0 || port > 65535) || (name == NULL)) + continue; + if (tab != NULL) + tab[port] = strdup(name); + } + endservent(); +} + + +static char *getproto(p) +u_int p; +{ + static char pnum[4]; + char *s; + + p &= 0xff; + s = protocols ? protocols[p] : NULL; + if (s == NULL) { + sprintf(pnum, "%u", p); + s = pnum; + } + return s; +} + + +static int read_log(fd, lenp, buf, bufsize) +int fd, bufsize, *lenp; +char *buf; +{ + int nr; + + nr = read(fd, buf, bufsize); + if (!nr) + return 2; + if ((nr < 0) && (errno != EINTR)) + return -1; + *lenp = nr; + return 0; +} + + +char *hostname(res, v, ip) +int res, v; +u_32_t *ip; +{ +# define MAX_INETA 16 + static char hname[MAXHOSTNAMELEN + MAX_INETA + 3]; +#ifdef USE_INET6 + static char hostbuf[MAXHOSTNAMELEN+1]; +#endif + struct hostent *hp; + struct in_addr ipa; + + if (v == 4) { + ipa.s_addr = *ip; + if (!res) + return inet_ntoa(ipa); + hp = gethostbyaddr((char *)ip, sizeof(*ip), AF_INET); + if (!hp) + return inet_ntoa(ipa); + sprintf(hname, "%.*s[%s]", MAXHOSTNAMELEN, hp->h_name, + inet_ntoa(ipa)); + return hname; + } +#ifdef USE_INET6 + (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); + hostbuf[MAXHOSTNAMELEN] = '\0'; + return hostbuf; +#else + return "IPv6"; +#endif +} + + +char *portname(res, proto, port) +int res; +char *proto; +u_int port; +{ + static char pname[8]; + char *s; + + port = ntohs(port); + port &= 0xffff; + (void) sprintf(pname, "%u", port); + if (!res || (opts & OPT_PORTNUM)) + return pname; + s = NULL; + if (!strcmp(proto, "tcp")) + s = tcp_ports[port]; + else if (!strcmp(proto, "udp")) + s = udp_ports[port]; + if (s == NULL) + s = pname; + return s; +} + + +static char *icmpname(type, code) +u_int type; +u_int code; +{ + static char name[80]; + icmp_subtype_t *ist; + icmp_type_t *it; + char *s; + + s = NULL; + it = find_icmptype(type, icmptypes, sizeof(icmptypes) / sizeof(*it)); + if (it != NULL) + s = it->it_name; + + if (s == NULL) + sprintf(name, "icmptype(%d)/", type); + else + sprintf(name, "%s/", s); + + ist = NULL; + if (it != NULL && it->it_subtable != NULL) + ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); + + if (ist != NULL && ist->ist_name != NULL) + strcat(name, ist->ist_name); + else + sprintf(name + strlen(name), "%d", code); + + return name; +} + +static char *icmpname6(type, code) +u_int type; +u_int code; +{ + static char name[80]; + icmp_subtype_t *ist; + icmp_type_t *it; + char *s; + + s = NULL; + it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it)); + if (it != NULL) + s = it->it_name; + + if (s == NULL) + sprintf(name, "icmpv6type(%d)/", type); + else + sprintf(name, "%s/", s); + + ist = NULL; + if (it != NULL && it->it_subtable != NULL) + ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); + + if (ist != NULL && ist->ist_name != NULL) + strcat(name, ist->ist_name); + else + sprintf(name + strlen(name), "%d", code); + + return name; +} + + +void dumphex(log, dopts, buf, len) +FILE *log; +int dopts; +char *buf; +int len; +{ + char hline[80]; + int i, j, k; + u_char *s = (u_char *)buf, *t = (u_char *)hline; + + if (buf == NULL || len == 0) + return; + + *hline = '\0'; + + for (i = len, j = 0; i; i--, j++, s++) { + if (j && !(j & 0xf)) { + *t++ = '\n'; + *t = '\0'; + if (!(dopts & OPT_SYSLOG)) + fputs(hline, log); + else + syslog(LOG_INFO, "%s", hline); + t = (u_char *)hline; + *t = '\0'; + } + sprintf((char *)t, "%02x", *s & 0xff); + t += 2; + if (!((j + 1) & 0xf)) { + s -= 15; + sprintf((char *)t, " "); + t += 8; + for (k = 16; k; k--, s++) + *t++ = (ISPRINT(*s) ? *s : '.'); + s--; + } + + if ((j + 1) & 0xf) + *t++ = ' ';; + } + + if (j & 0xf) { + for (k = 16 - (j & 0xf); k; k--) { + *t++ = ' '; + *t++ = ' '; + *t++ = ' '; + } + sprintf((char *)t, " "); + t += 7; + s -= j & 0xf; + for (k = j & 0xf; k; k--, s++) + *t++ = (ISPRINT(*s) ? *s : '.'); + *t++ = '\n'; + *t = '\0'; + } + if (!(dopts & OPT_SYSLOG)) { + fputs(hline, log); + fflush(log); + } else + syslog(LOG_INFO, "%s", hline); +} + + +static struct tm *get_tm(sec) +#ifdef __hpux +u_32_t sec; +#else +time_t sec; +#endif +{ + struct tm *tm; + time_t t; + + t = sec; + tm = localtime(&t); + return tm; +} + +static void print_natlog(log, buf, blen) +FILE *log; +char *buf; +int blen; +{ + struct natlog *nl; + iplog_t *ipl = (iplog_t *)buf; + char *t = line; + struct tm *tm; + int res, i, len; + char *proto; + + nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); + res = (opts & OPT_RESOLVE) ? 1 : 0; + tm = get_tm(ipl->ipl_sec); + len = sizeof(line); + if (!(opts & OPT_SYSLOG)) { + (void) strftime(t, len, "%d/%m/%Y ", tm); + i = strlen(t); + len -= i; + t += i; + } + (void) strftime(t, len, "%T", tm); + t += strlen(t); + (void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_usec, nl->nl_rule + 1); + t += strlen(t); + + if (nl->nl_type == NL_NEWMAP) + strcpy(t, "NAT:MAP "); + else if (nl->nl_type == NL_NEWRDR) + strcpy(t, "NAT:RDR "); + else if (nl->nl_type == NL_FLUSH) + strcpy(t, "NAT:FLUSH "); + else if (nl->nl_type == NL_EXPIRE) + strcpy(t, "NAT:EXPIRE "); + else if (nl->nl_type == NL_NEWBIMAP) + strcpy(t, "NAT:BIMAP "); + else if (nl->nl_type == NL_NEWBLOCK) + strcpy(t, "NAT:MAPBLOCK "); + else if (nl->nl_type == NL_CLONE) + strcpy(t, "NAT:CLONE "); + else + sprintf(t, "Type: %d ", nl->nl_type); + t += strlen(t); + + proto = getproto(nl->nl_p); + + (void) sprintf(t, "%s,%s <- -> ", HOSTNAME_V4(res, nl->nl_inip), + portname(res, proto, (u_int)nl->nl_inport)); + t += strlen(t); + (void) sprintf(t, "%s,%s ", HOSTNAME_V4(res, nl->nl_outip), + portname(res, proto, (u_int)nl->nl_outport)); + t += strlen(t); + (void) sprintf(t, "[%s,%s]", HOSTNAME_V4(res, nl->nl_origip), + portname(res, proto, (u_int)nl->nl_origport)); + t += strlen(t); + if (nl->nl_type == NL_EXPIRE) { +#ifdef USE_QUAD_T + (void) sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd", + (long long)nl->nl_pkts[0], + (long long)nl->nl_pkts[1], + (long long)nl->nl_bytes[0], + (long long)nl->nl_bytes[1]); +#else + (void) sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld", + nl->nl_pkts[0], nl->nl_pkts[1], + nl->nl_bytes[0], nl->nl_bytes[1]); +#endif + t += strlen(t); + } + + *t++ = '\n'; + *t++ = '\0'; + if (opts & OPT_SYSLOG) + syslog(LOG_INFO, "%s", line); + else + (void) fprintf(log, "%s", line); +} + + +static void print_statelog(log, buf, blen) +FILE *log; +char *buf; +int blen; +{ + struct ipslog *sl; + iplog_t *ipl = (iplog_t *)buf; + char *t = line, *proto; + struct tm *tm; + int res, i, len; + + sl = (struct ipslog *)((char *)ipl + sizeof(*ipl)); + res = (opts & OPT_RESOLVE) ? 1 : 0; + tm = get_tm(ipl->ipl_sec); + len = sizeof(line); + if (!(opts & OPT_SYSLOG)) { + (void) strftime(t, len, "%d/%m/%Y ", tm); + i = strlen(t); + len -= i; + t += i; + } + (void) strftime(t, len, "%T", tm); + t += strlen(t); + (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); + t += strlen(t); + + if (sl->isl_type == ISL_NEW) + strcpy(t, "STATE:NEW "); + else if (sl->isl_type == ISL_CLONE) + strcpy(t, "STATE:CLONED "); + else if (sl->isl_type == ISL_EXPIRE) { + if ((sl->isl_p == IPPROTO_TCP) && + (sl->isl_state[0] > IPF_TCPS_ESTABLISHED || + sl->isl_state[1] > IPF_TCPS_ESTABLISHED)) + strcpy(t, "STATE:CLOSE "); + else + strcpy(t, "STATE:EXPIRE "); + } else if (sl->isl_type == ISL_FLUSH) + strcpy(t, "STATE:FLUSH "); + else if (sl->isl_type == ISL_INTERMEDIATE) + strcpy(t, "STATE:INTERMEDIATE "); + else if (sl->isl_type == ISL_REMOVE) + strcpy(t, "STATE:REMOVE "); + else if (sl->isl_type == ISL_KILLED) + strcpy(t, "STATE:KILLED "); + else + sprintf(t, "Type: %d ", sl->isl_type); + t += strlen(t); + + proto = getproto(sl->isl_p); + + if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { + (void) sprintf(t, "%s,%s -> ", + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src), + portname(res, proto, (u_int)sl->isl_sport)); + t += strlen(t); + (void) sprintf(t, "%s,%s PR %s", + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), + portname(res, proto, (u_int)sl->isl_dport), proto); + } else if (sl->isl_p == IPPROTO_ICMP) { + (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, + (u_32_t *)&sl->isl_src)); + t += strlen(t); + (void) sprintf(t, "%s PR icmp %d", + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), + sl->isl_itype); + } else if (sl->isl_p == IPPROTO_ICMPV6) { + (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, + (u_32_t *)&sl->isl_src)); + t += strlen(t); + (void) sprintf(t, "%s PR icmpv6 %d", + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), + sl->isl_itype); + } else { + (void) sprintf(t, "%s -> ", + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src)); + t += strlen(t); + (void) sprintf(t, "%s PR %s", + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), + proto); + } + t += strlen(t); + if (sl->isl_tag != FR_NOLOGTAG) { + (void) sprintf(t, " tag %u", sl->isl_tag); + t += strlen(t); + } + if (sl->isl_type != ISL_NEW) { + sprintf(t, +#ifdef USE_QUAD_T +#ifdef PRId64 + " Forward: Pkts in %" PRId64 " Bytes in %" PRId64 + " Pkts out %" PRId64 " Bytes out %" PRId64 + " Backward: Pkts in %" PRId64 " Bytes in %" PRId64 + " Pkts out %" PRId64 " Bytes out %" PRId64, +#else + " Forward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd Backward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd", +#endif /* PRId64 */ +#else + " Forward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld Backward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld", +#endif + sl->isl_pkts[0], sl->isl_bytes[0], + sl->isl_pkts[1], sl->isl_bytes[1], + sl->isl_pkts[2], sl->isl_bytes[2], + sl->isl_pkts[3], sl->isl_bytes[3]); + + t += strlen(t); + } + + *t++ = '\n'; + *t++ = '\0'; + if (opts & OPT_SYSLOG) + syslog(LOG_INFO, "%s", line); + else + (void) fprintf(log, "%s", line); +} + + +static void print_log(logtype, log, buf, blen) +FILE *log; +char *buf; +int logtype, blen; +{ + iplog_t *ipl; + char *bp = NULL, *bpo = NULL; + int psize; + + while (blen > 0) { + ipl = (iplog_t *)buf; + if ((u_long)ipl & (sizeof(long)-1)) { + if (bp) + bpo = bp; + bp = (char *)malloc(blen); + bcopy((char *)ipl, bp, blen); + if (bpo) { + free(bpo); + bpo = NULL; + } + buf = bp; + continue; + } + + psize = ipl->ipl_dsize; + if (psize > blen) + break; + + if (binarylog) { + fwrite(buf, psize, 1, binarylog); + fflush(binarylog); + } + + if (logtype == IPL_LOGIPF) { + if (ipl->ipl_magic == IPL_MAGIC) + print_ipflog(log, buf, psize); + + } else if (logtype == IPL_LOGNAT) { + if (ipl->ipl_magic == IPL_MAGIC_NAT) + print_natlog(log, buf, psize); + + } else if (logtype == IPL_LOGSTATE) { + if (ipl->ipl_magic == IPL_MAGIC_STATE) + print_statelog(log, buf, psize); + } + + blen -= psize; + buf += psize; + } + if (bp) + free(bp); + return; +} + + +static void print_ipflog(log, buf, blen) +FILE *log; +char *buf; +int blen; +{ + tcphdr_t *tp; + struct icmp *ic; + struct icmp *icmp; + struct tm *tm; + char *t, *proto; + int i, v, lvl, res, len, off, plen, ipoff, defaction; + ip_t *ipc, *ip; + u_32_t *s, *d; + u_short hl, p; + ipflog_t *ipf; + iplog_t *ipl; +#ifdef USE_INET6 + ip6_t *ip6; +#endif + + ipl = (iplog_t *)buf; + ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); + ip = (ip_t *)((char *)ipf + sizeof(*ipf)); + v = IP_V(ip); + res = (opts & OPT_RESOLVE) ? 1 : 0; + t = line; + *t = '\0'; + tm = get_tm(ipl->ipl_sec); + + len = sizeof(line); + if (!(opts & OPT_SYSLOG)) { + (void) strftime(t, len, "%d/%m/%Y ", tm); + i = strlen(t); + len -= i; + t += i; + } + (void) strftime(t, len, "%T", tm); + t += strlen(t); + (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); + t += strlen(t); + if (ipl->ipl_count > 1) { + (void) sprintf(t, "%dx ", ipl->ipl_count); + t += strlen(t); + } +#if (defined(MENTAT) || \ + (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) + { + char ifname[sizeof(ipf->fl_ifname) + 1]; + + strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname)); + ifname[sizeof(ipf->fl_ifname)] = '\0'; + (void) sprintf(t, "%s", ifname); + t += strlen(t); +# if defined(MENTAT) || defined(linux) + if (ISALPHA(*(t - 1))) { + sprintf(t, "%d", ipf->fl_unit); + t += strlen(t); + } +# endif + } +#else + for (len = 0; len < 3; len++) + if (ipf->fl_ifname[len] == '\0') + break; + if (ipf->fl_ifname[len]) + len++; + (void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); + t += strlen(t); +#endif +#ifdef __sgi + if ((ipf->fl_group[0] == 255) && (ipf->fl_group[1] == '\0')) +#else + if ((ipf->fl_group[0] == -1) && (ipf->fl_group[1] == '\0')) +#endif + strcat(t, " @-1:"); + else if (ipf->fl_group[0] == '\0') + (void) strcpy(t, " @0:"); + else + (void) sprintf(t, " @%s:", ipf->fl_group); + t += strlen(t); + if (ipf->fl_rule == 0xffffffff) + strcat(t, "-1 "); + else + (void) sprintf(t, "%u ", ipf->fl_rule + 1); + t += strlen(t); + + lvl = LOG_NOTICE; + + if (ipf->fl_lflags & FI_SHORT) { + *t++ = 'S'; + lvl = LOG_ERR; + } + + if (FR_ISPASS(ipf->fl_flags)) { + if (ipf->fl_flags & FR_LOGP) + *t++ = 'p'; + else + *t++ = 'P'; + } else if (FR_ISBLOCK(ipf->fl_flags)) { + if (ipf->fl_flags & FR_LOGB) + *t++ = 'b'; + else + *t++ = 'B'; + lvl = LOG_WARNING; + } else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) { + *t++ = 'L'; + lvl = LOG_INFO; + } else if (ipf->fl_flags & FF_LOGNOMATCH) { + *t++ = 'n'; + } else { + *t++ = '?'; + lvl = LOG_EMERG; + } + if (ipf->fl_loglevel != 0xffff) + lvl = ipf->fl_loglevel; + *t++ = ' '; + *t = '\0'; + + if (v == 6) { +#ifdef USE_INET6 + off = 0; + ipoff = 0; + hl = sizeof(ip6_t); + ip6 = (ip6_t *)ip; + p = (u_short)ip6->ip6_nxt; + s = (u_32_t *)&ip6->ip6_src; + d = (u_32_t *)&ip6->ip6_dst; + plen = hl + ntohs(ip6->ip6_plen); +#else + sprintf(t, "ipv6"); + goto printipflog; +#endif + } else if (v == 4) { + hl = IP_HL(ip) << 2; + ipoff = ip->ip_off; + off = ipoff & IP_OFFMASK; + p = (u_short)ip->ip_p; + s = (u_32_t *)&ip->ip_src; + d = (u_32_t *)&ip->ip_dst; + plen = ip->ip_len; + } else { + goto printipflog; + } + proto = getproto(p); + + if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { + tp = (tcphdr_t *)((char *)ip + hl); + if (!(ipf->fl_lflags & FI_SHORT)) { + (void) sprintf(t, "%s,%s -> ", hostname(res, v, s), + portname(res, proto, (u_int)tp->th_sport)); + t += strlen(t); + (void) sprintf(t, "%s,%s PR %s len %hu %hu", + hostname(res, v, d), + portname(res, proto, (u_int)tp->th_dport), + proto, hl, plen); + t += strlen(t); + + if (p == IPPROTO_TCP) { + *t++ = ' '; + *t++ = '-'; + for (i = 0; tcpfl[i].value; i++) + if (tp->th_flags & tcpfl[i].value) + *t++ = tcpfl[i].flag; + if (opts & OPT_VERBOSE) { + (void) sprintf(t, " %lu %lu %hu", + (u_long)(ntohl(tp->th_seq)), + (u_long)(ntohl(tp->th_ack)), + ntohs(tp->th_win)); + t += strlen(t); + } + } + *t = '\0'; + } else { + (void) sprintf(t, "%s -> ", hostname(res, v, s)); + t += strlen(t); + (void) sprintf(t, "%s PR %s len %hu %hu", + hostname(res, v, d), proto, hl, plen); + } + } else if ((p == IPPROTO_ICMPV6) && !off && (v == 6)) { + ic = (struct icmp *)((char *)ip + hl); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); + t += strlen(t); + (void) sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", + hostname(res, v, d), hl, plen, + icmpname6(ic->icmp_type, ic->icmp_code)); + } else if ((p == IPPROTO_ICMP) && !off && (v == 4)) { + ic = (struct icmp *)((char *)ip + hl); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); + t += strlen(t); + (void) sprintf(t, "%s PR icmp len %hu %hu icmp %s", + hostname(res, v, d), hl, plen, + icmpname(ic->icmp_type, ic->icmp_code)); + if (ic->icmp_type == ICMP_UNREACH || + ic->icmp_type == ICMP_SOURCEQUENCH || + ic->icmp_type == ICMP_PARAMPROB || + ic->icmp_type == ICMP_REDIRECT || + ic->icmp_type == ICMP_TIMXCEED) { + ipc = &ic->icmp_ip; + i = ntohs(ipc->ip_len); + /* + * XXX - try to guess endian of ip_len in ICMP + * returned data. + */ + if (i > 1500) + i = ipc->ip_len; + ipoff = ntohs(ipc->ip_off); + proto = getproto(ipc->ip_p); + + if (!(ipoff & IP_OFFMASK) && + ((ipc->ip_p == IPPROTO_TCP) || + (ipc->ip_p == IPPROTO_UDP))) { + tp = (tcphdr_t *)((char *)ipc + hl); + t += strlen(t); + (void) sprintf(t, " for %s,%s -", + HOSTNAME_V4(res, ipc->ip_src), + portname(res, proto, + (u_int)tp->th_sport)); + t += strlen(t); + (void) sprintf(t, " %s,%s PR %s len %hu %hu", + HOSTNAME_V4(res, ipc->ip_dst), + portname(res, proto, + (u_int)tp->th_dport), + proto, IP_HL(ipc) << 2, i); + } else if (!(ipoff & IP_OFFMASK) && + (ipc->ip_p == IPPROTO_ICMP)) { + icmp = (icmphdr_t *)((char *)ipc + hl); + + t += strlen(t); + (void) sprintf(t, " for %s -", + HOSTNAME_V4(res, ipc->ip_src)); + t += strlen(t); + (void) sprintf(t, + " %s PR icmp len %hu %hu icmp %d/%d", + HOSTNAME_V4(res, ipc->ip_dst), + IP_HL(ipc) << 2, i, + icmp->icmp_type, icmp->icmp_code); + } else { + t += strlen(t); + (void) sprintf(t, " for %s -", + HOSTNAME_V4(res, ipc->ip_src)); + t += strlen(t); + (void) sprintf(t, " %s PR %s len %hu (%hu)", + HOSTNAME_V4(res, ipc->ip_dst), proto, + IP_HL(ipc) << 2, i); + t += strlen(t); + if (ipoff & IP_OFFMASK) { + (void) sprintf(t, + "(frag %d:%hu@%hu%s%s)", + ntohs(ipc->ip_id), + i - (IP_HL(ipc) << 2), + (ipoff & IP_OFFMASK) << 3, + ipoff & IP_MF ? "+" : "", + ipoff & IP_DF ? "-" : ""); + } + } + + } + } else { + (void) sprintf(t, "%s -> ", hostname(res, v, s)); + t += strlen(t); + (void) sprintf(t, "%s PR %s len %hu (%hu)", + hostname(res, v, d), proto, hl, plen); + t += strlen(t); + if (off & IP_OFFMASK) + (void) sprintf(t, " (frag %d:%hu@%hu%s%s)", + ntohs(ip->ip_id), + plen - hl, (off & IP_OFFMASK) << 3, + ipoff & IP_MF ? "+" : "", + ipoff & IP_DF ? "-" : ""); + } + t += strlen(t); + +printipflog: + if (ipf->fl_flags & FR_KEEPSTATE) { + (void) strcpy(t, " K-S"); + t += strlen(t); + } + + if (ipf->fl_flags & FR_KEEPFRAG) { + (void) strcpy(t, " K-F"); + t += strlen(t); + } + + if (ipf->fl_dir == 0) + strcpy(t, " IN"); + else if (ipf->fl_dir == 1) + strcpy(t, " OUT"); + t += strlen(t); + if (ipf->fl_logtag != 0) { + sprintf(t, " log-tag %d", ipf->fl_logtag); + t += strlen(t); + } + if (ipf->fl_nattag.ipt_num[0] != 0) { + strcpy(t, " nat-tag "); + t += strlen(t); + strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag)); + t += strlen(t); + } + if ((ipf->fl_lflags & FI_LOWTTL) != 0) { + strcpy(t, " low-ttl"); + t += 8; + } + if ((ipf->fl_lflags & FI_OOW) != 0) { + strcpy(t, " OOW"); + t += 4; + } + if ((ipf->fl_lflags & FI_BAD) != 0) { + strcpy(t, " bad"); + t += 4; + } + if ((ipf->fl_lflags & FI_NATED) != 0) { + strcpy(t, " NAT"); + t += 4; + } + if ((ipf->fl_lflags & FI_BADNAT) != 0) { + strcpy(t, " bad-NAT"); + t += 8; + } + if ((ipf->fl_lflags & FI_BADSRC) != 0) { + strcpy(t, " bad-src"); + t += 8; + } + if ((ipf->fl_lflags & FI_MULTICAST) != 0) { + strcpy(t, " multicast"); + t += 10; + } + if ((ipf->fl_lflags & FI_BROADCAST) != 0) { + strcpy(t, " broadcast"); + t += 10; + } + if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) == + FI_MBCAST) { + strcpy(t, " mbcast"); + t += 7; + } + *t++ = '\n'; + *t++ = '\0'; + defaction = 0; + if (conf_file != NULL) + defaction = check_action(buf, line, opts, lvl); + if (defaction == 0) { + if (opts & OPT_SYSLOG) + syslog(lvl, "%s", line); + else + (void) fprintf(log, "%s", line); + if (opts & OPT_HEXHDR) + dumphex(log, opts, buf, + sizeof(iplog_t) + sizeof(*ipf)); + if (opts & OPT_HEXBODY) + dumphex(log, opts, (char *)ip, + ipf->fl_plen + ipf->fl_hlen); + else if ((opts & OPT_LOGBODY) && (ipf->fl_flags & FR_LOGBODY)) + dumphex(log, opts, (char *)ip + ipf->fl_hlen, + ipf->fl_plen); + } +} + + +static void usage(prog) +char *prog; +{ + fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog); + exit(1); +} + + +static void write_pid(file) +char *file; +{ + FILE *fp = NULL; + int fd; + + if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) { + fp = fdopen(fd, "w"); + if (fp == NULL) { + close(fd); + fprintf(stderr, + "unable to open/create pid file: %s\n", file); + return; + } + fprintf(fp, "%d", getpid()); + fclose(fp); + } +} + + +static void flushlogs(file, log) +char *file; +FILE *log; +{ + int fd, flushed = 0; + + if ((fd = open(file, O_RDWR)) == -1) { + (void) fprintf(stderr, "%s: open: %s\n", + file, STRERROR(errno)); + exit(1); + } + + if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { + printf("%d bytes flushed from log buffer\n", + flushed); + fflush(stdout); + } else + perror("SIOCIPFFB"); + (void) close(fd); + + if (flushed) { + if (opts & OPT_SYSLOG) + syslog(LOG_INFO, "%d bytes flushed from log\n", + flushed); + else if (log != stdout) + fprintf(log, "%d bytes flushed from log\n", flushed); + } +} + + +static void logopts(turnon, options) +int turnon; +char *options; +{ + int flags = 0; + char *s; + + for (s = options; *s; s++) + { + switch (*s) + { + case 'N' : + flags |= OPT_NAT; + break; + case 'S' : + flags |= OPT_STATE; + break; + case 'I' : + flags |= OPT_FILTER; + break; + default : + fprintf(stderr, "Unknown log option %c\n", *s); + exit(1); + } + } + + if (turnon) + opts |= flags; + else + opts &= ~(flags); +} + + +int main(argc, argv) +int argc; +char *argv[]; +{ + struct stat sb; + FILE *log = stdout; + FILE *fp; + int fd[3], doread, n, i; + int tr, nr, regular[3], c; + int fdt[3], devices = 0, make_daemon = 0; + char buf[DEFAULT_IPFLOGSIZE], *iplfile[3], *s; + extern int optind; + extern char *optarg; + + fd[0] = fd[1] = fd[2] = -1; + fdt[0] = fdt[1] = fdt[2] = -1; + iplfile[0] = IPL_NAME; + iplfile[1] = IPNAT_NAME; + iplfile[2] = IPSTATE_NAME; + + while ((c = getopt(argc, argv, "?abB:C:Df:FhnN:o:O:pP:sS:tvxX")) != -1) + switch (c) + { + case 'a' : + opts |= OPT_LOGALL; + fdt[0] = IPL_LOGIPF; + fdt[1] = IPL_LOGNAT; + fdt[2] = IPL_LOGSTATE; + break; + case 'b' : + opts |= OPT_LOGBODY; + break; + case 'B' : + binarylogfile = optarg; + binarylog = fopen(optarg, "a"); + break; + case 'C' : + conf_file = optarg; + break; + case 'D' : + make_daemon = 1; + break; + case 'f' : case 'I' : + opts |= OPT_FILTER; + fdt[0] = IPL_LOGIPF; + iplfile[0] = optarg; + break; + case 'F' : + flushlogs(iplfile[0], log); + flushlogs(iplfile[1], log); + flushlogs(iplfile[2], log); + break; + case 'n' : + opts |= OPT_RESOLVE; + break; + case 'N' : + opts |= OPT_NAT; + fdt[1] = IPL_LOGNAT; + iplfile[1] = optarg; + break; + case 'o' : case 'O' : + logopts(c == 'o', optarg); + fdt[0] = fdt[1] = fdt[2] = -1; + if (opts & OPT_FILTER) + fdt[0] = IPL_LOGIPF; + if (opts & OPT_NAT) + fdt[1] = IPL_LOGNAT; + if (opts & OPT_STATE) + fdt[2] = IPL_LOGSTATE; + break; + case 'p' : + opts |= OPT_PORTNUM; + break; + case 'P' : + pidfile = optarg; + break; + case 's' : + s = strrchr(argv[0], '/'); + if (s == NULL) + s = argv[0]; + else + s++; + openlog(s, LOG_NDELAY|LOG_PID, LOGFAC); + s = NULL; + opts |= OPT_SYSLOG; + log = NULL; + break; + case 'S' : + opts |= OPT_STATE; + fdt[2] = IPL_LOGSTATE; + iplfile[2] = optarg; + break; + case 't' : + opts |= OPT_TAIL; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + case 'x' : + opts |= OPT_HEXBODY; + break; + case 'X' : + opts |= OPT_HEXHDR; + break; + default : + case 'h' : + case '?' : + usage(argv[0]); + } + + init_tabs(); + if (conf_file) + if (load_config(conf_file) == -1) + exit(1); + + /* + * Default action is to only open the filter log file. + */ + if ((fdt[0] == -1) && (fdt[1] == -1) && (fdt[2] == -1)) + fdt[0] = IPL_LOGIPF; + + for (i = 0; i < 3; i++) { + if (fdt[i] == -1) + continue; + if (!strcmp(iplfile[i], "-")) + fd[i] = 0; + else { + if ((fd[i] = open(iplfile[i], O_RDONLY)) == -1) { + (void) fprintf(stderr, + "%s: open: %s\n", iplfile[i], + STRERROR(errno)); + exit(1); + /* NOTREACHED */ + } + if (fstat(fd[i], &sb) == -1) { + (void) fprintf(stderr, "%d: fstat: %s\n", + fd[i], STRERROR(errno)); + exit(1); + /* NOTREACHED */ + } + if (!(regular[i] = !S_ISCHR(sb.st_mode))) + devices++; + } + } + + if (!(opts & OPT_SYSLOG)) { + logfile = argv[optind]; + log = logfile ? fopen(logfile, "a") : stdout; + if (log == NULL) { + (void) fprintf(stderr, "%s: fopen: %s\n", + argv[optind], STRERROR(errno)); + exit(1); + /* NOTREACHED */ + } + setvbuf(log, NULL, _IONBF, 0); + } else + log = NULL; + + if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) { +#if BSD >= 199306 + daemon(0, !(opts & OPT_SYSLOG)); +#else + int pid; + if ((pid = fork()) > 0) + exit(0); + if (pid < 0) { + (void) fprintf(stderr, "%s: fork() failed: %s\n", + argv[0], STRERROR(errno)); + exit(1); + /* NOTREACHED */ + } + setsid(); + if ((opts & OPT_SYSLOG)) + close(2); +#endif /* !BSD */ + close(0); + close(1); + } + write_pid(pidfile); + + signal(SIGHUP, handlehup); + + for (doread = 1; doread; ) { + nr = 0; + + for (i = 0; i < 3; i++) { + tr = 0; + if (fdt[i] == -1) + continue; + if (!regular[i]) { + if (ioctl(fd[i], FIONREAD, &tr) == -1) { + if (opts & OPT_SYSLOG) + syslog(LOG_CRIT, + "ioctl(FIONREAD): %m"); + else + perror("ioctl(FIONREAD)"); + exit(1); + /* NOTREACHED */ + } + } else { + tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size); + if (!tr && !(opts & OPT_TAIL)) + doread = 0; + } + if (!tr) + continue; + nr += tr; + + tr = read_log(fd[i], &n, buf, sizeof(buf)); + if (donehup) { + if (logfile && (fp = fopen(logfile, "a"))) { + fclose(log); + log = fp; + } + if (binarylogfile && (fp = fopen(binarylogfile, "a"))) { + fclose(binarylog); + binarylog = fp; + } + init_tabs(); + if (conf_file != NULL) + load_config(conf_file); + donehup = 0; + } + + switch (tr) + { + case -1 : + if (opts & OPT_SYSLOG) + syslog(LOG_CRIT, "read: %m\n"); + else + perror("read"); + doread = 0; + break; + case 1 : + if (opts & OPT_SYSLOG) + syslog(LOG_CRIT, "aborting logging\n"); + else + fprintf(log, "aborting logging\n"); + doread = 0; + break; + case 2 : + break; + case 0 : + if (n > 0) { + print_log(fdt[i], log, buf, n); + if (!(opts & OPT_SYSLOG)) + fflush(log); + } + break; + } + } + if (!nr && ((opts & OPT_TAIL) || devices)) + sleep(1); + } + return(0); + /* NOTREACHED */ +} diff --git a/contrib/ipfilter/tools/ipmon_y.y b/contrib/ipfilter/tools/ipmon_y.y new file mode 100644 index 0000000..8b30028 --- /dev/null +++ b/contrib/ipfilter/tools/ipmon_y.y @@ -0,0 +1,694 @@ +/* $NetBSD$ */ + +%{ +#include "ipf.h" +#include <syslog.h> +#undef OPT_NAT +#undef OPT_VERBOSE +#include "ipmon_l.h" +#include "ipmon.h" + +#define YYDEBUG 1 + +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; + +typedef struct opt { + struct opt *o_next; + int o_line; + int o_type; + int o_num; + char *o_str; + struct in_addr o_ip; +} opt_t; + +static void build_action __P((struct opt *)); +static opt_t *new_opt __P((int)); +static void free_action __P((ipmon_action_t *)); + +static ipmon_action_t *alist = NULL; +%} + +%union { + char *str; + u_32_t num; + struct in_addr addr; + struct opt *opt; + union i6addr ip6; +} + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token <ip6> YY_IPV6 +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN + +%token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT +%token IPM_EVERY IPM_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT +%token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE +%token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH +%token IPM_DO IPM_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT +%token IPM_STATE IPM_NATTAG IPM_IPF +%type <addr> ipv4 +%type <opt> direction dstip dstport every execute group interface +%type <opt> protocol result rule srcip srcport logtag matching +%type <opt> matchopt nattag type doopt doing save syslog nothing +%type <num> saveopts saveopt typeopt + +%% +file: line + | assign + | file line + | file assign + ; + +line: IPM_MATCH '{' matching '}' IPM_DO '{' doing '}' ';' + { build_action($3); resetlexer(); } + | IPM_COMMENT + | YY_COMMENT + ; + +assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +matching: + matchopt { $$ = $1; } + | matchopt ',' matching { $1->o_next = $3; $$ = $1; } + ; + +matchopt: + direction { $$ = $1; } + | dstip { $$ = $1; } + | dstport { $$ = $1; } + | every { $$ = $1; } + | group { $$ = $1; } + | interface { $$ = $1; } + | protocol { $$ = $1; } + | result { $$ = $1; } + | rule { $$ = $1; } + | srcip { $$ = $1; } + | srcport { $$ = $1; } + | logtag { $$ = $1; } + | nattag { $$ = $1; } + | type { $$ = $1; } + ; + +doing: + doopt { $$ = $1; } + | doopt ',' doing { $1->o_next = $3; $$ = $1; } + ; + +doopt: + execute { $$ = $1; } + | save { $$ = $1; } + | syslog { $$ = $1; } + | nothing { $$ = $1; } + ; + +direction: + IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION); + $$->o_num = IPM_IN; } + | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION); + $$->o_num = IPM_OUT; } + ; + +dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP); + $$->o_ip = $3; + $$->o_num = $5; } + ; + +dstport: + IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT); + $$->o_num = $3; } + | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT); + $$->o_str = $3; } + ; + +every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND); + $$->o_num = 1; } + | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND); + $$->o_num = $2; } + | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET); + $$->o_num = 1; } + | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET); + $$->o_num = $2; } + ; + +group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP); + $$->o_num = $3; } + | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP); + $$->o_str = $3; } + ; + +interface: + IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE); + $$->o_str = $3; } + ; + +logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG); + $$->o_num = $3; } + ; + +nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG); + $$->o_str = $3; } + ; + +protocol: + IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL); + $$->o_num = $3; } + | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL); + $$->o_num = getproto($3); + free($3); + } + ; + +result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT); + $$->o_str = $3; } + ; + +rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE); + $$->o_num = YY_NUMBER; } + ; + +srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP); + $$->o_ip = $3; + $$->o_num = $5; } + ; + +srcport: + IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT); + $$->o_num = $3; } + | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT); + $$->o_str = $3; } + ; + +type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE); + $$->o_num = $3; } + ; + +typeopt: + IPM_IPF { $$ = IPL_MAGIC; } + | IPM_NAT { $$ = IPL_MAGIC_NAT; } + | IPM_STATE { $$ = IPL_MAGIC_STATE; } + ; + +execute: + IPM_EXECUTE YY_STR { $$ = new_opt(IPM_EXECUTE); + $$->o_str = $2; } + ; + +save: IPM_SAVE saveopts YY_STR { $$ = new_opt(IPM_SAVE); + $$->o_num = $2; + $$->o_str = $3; } + ; + +saveopts: { $$ = 0; } + | saveopt { $$ = $1; } + | saveopt ',' saveopts { $$ = $1 | $3; } + ; + +saveopt: + IPM_RAW { $$ = IPMDO_SAVERAW; } + ; + +syslog: IPM_SYSLOG { $$ = new_opt(IPM_SYSLOG); } + ; + +nothing: + IPM_NOTHING { $$ = 0; } + ; + +ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; + $$.s_addr = htonl($$.s_addr); + } +%% +static struct wordtab yywords[] = { + { "body", IPM_BODY }, + { "direction", IPM_DIRECTION }, + { "do", IPM_DO }, + { "dstip", IPM_DSTIP }, + { "dstport", IPM_DSTPORT }, + { "every", IPM_EVERY }, + { "execute", IPM_EXECUTE }, + { "group", IPM_GROUP }, + { "in", IPM_IN }, + { "interface", IPM_INTERFACE }, + { "ipf", IPM_IPF }, + { "logtag", IPM_LOGTAG }, + { "match", IPM_MATCH }, + { "nat", IPM_NAT }, + { "nattag", IPM_NATTAG }, + { "no", IPM_NO }, + { "nothing", IPM_NOTHING }, + { "out", IPM_OUT }, + { "packet", IPM_PACKET }, + { "packets", IPM_PACKETS }, + { "protocol", IPM_PROTOCOL }, + { "result", IPM_RESULT }, + { "rule", IPM_RULE }, + { "save", IPM_SAVE }, + { "second", IPM_SECOND }, + { "seconds", IPM_SECONDS }, + { "srcip", IPM_SRCIP }, + { "srcport", IPM_SRCPORT }, + { "state", IPM_STATE }, + { "syslog", IPM_SYSLOG }, + { "with", IPM_WITH }, + { NULL, 0 } +}; + +static int macflags[17][2] = { + { IPM_DIRECTION, IPMAC_DIRECTION }, + { IPM_DSTIP, IPMAC_DSTIP }, + { IPM_DSTPORT, IPMAC_DSTPORT }, + { IPM_GROUP, IPMAC_GROUP }, + { IPM_INTERFACE, IPMAC_INTERFACE }, + { IPM_LOGTAG, IPMAC_LOGTAG }, + { IPM_NATTAG, IPMAC_NATTAG }, + { IPM_PACKET, IPMAC_EVERY }, + { IPM_PROTOCOL, IPMAC_PROTOCOL }, + { IPM_RESULT, IPMAC_RESULT }, + { IPM_RULE, IPMAC_RULE }, + { IPM_SECOND, IPMAC_EVERY }, + { IPM_SRCIP, IPMAC_SRCIP }, + { IPM_SRCPORT, IPMAC_SRCPORT }, + { IPM_TYPE, IPMAC_TYPE }, + { IPM_WITH, IPMAC_WITH }, + { 0, 0 } +}; + +static opt_t *new_opt(type) +int type; +{ + opt_t *o; + + o = (opt_t *)malloc(sizeof(*o)); + o->o_type = type; + o->o_line = yylineNum; + o->o_num = 0; + o->o_str = (char *)0; + o->o_next = NULL; + return o; +} + +static void build_action(olist) +opt_t *olist; +{ + ipmon_action_t *a; + opt_t *o; + char c; + int i; + + a = (ipmon_action_t *)calloc(1, sizeof(*a)); + if (a == NULL) + return; + while ((o = olist) != NULL) { + /* + * Check to see if the same comparator is being used more than + * once per matching statement. + */ + for (i = 0; macflags[i][0]; i++) + if (macflags[i][0] == o->o_type) + break; + if (macflags[i][1] & a->ac_mflag) { + fprintf(stderr, "%s redfined on line %d\n", + yykeytostr(o->o_type), yylineNum); + if (o->o_str != NULL) + free(o->o_str); + olist = o->o_next; + free(o); + continue; + } + + a->ac_mflag |= macflags[i][1]; + + switch (o->o_type) + { + case IPM_DIRECTION : + a->ac_direction = o->o_num; + break; + case IPM_DSTIP : + a->ac_dip = o->o_ip.s_addr; + a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num)); + break; + case IPM_DSTPORT : + a->ac_dport = htons(o->o_num); + break; + case IPM_EXECUTE : + a->ac_exec = o->o_str; + c = *o->o_str; + if (c== '"'|| c == '\'') { + if (o->o_str[strlen(o->o_str) - 1] == c) { + a->ac_run = strdup(o->o_str + 1); + a->ac_run[strlen(a->ac_run) - 1] ='\0'; + } else + a->ac_run = o->o_str; + } else + a->ac_run = o->o_str; + o->o_str = NULL; + break; + case IPM_INTERFACE : + a->ac_iface = o->o_str; + o->o_str = NULL; + break; + case IPM_GROUP : + if (o->o_str != NULL) + strncpy(a->ac_group, o->o_str, FR_GROUPLEN); + else + sprintf(a->ac_group, "%d", o->o_num); + break; + case IPM_LOGTAG : + a->ac_logtag = o->o_num; + break; + case IPM_NATTAG : + strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag)); + break; + case IPM_PACKET : + a->ac_packet = o->o_num; + break; + case IPM_PROTOCOL : + a->ac_proto = o->o_num; + break; + case IPM_RULE : + a->ac_rule = o->o_num; + break; + case IPM_RESULT : + if (!strcasecmp(o->o_str, "pass")) + a->ac_result = IPMR_PASS; + else if (!strcasecmp(o->o_str, "block")) + a->ac_result = IPMR_BLOCK; + else if (!strcasecmp(o->o_str, "nomatch")) + a->ac_result = IPMR_NOMATCH; + else if (!strcasecmp(o->o_str, "log")) + a->ac_result = IPMR_LOG; + break; + case IPM_SECOND : + a->ac_second = o->o_num; + break; + case IPM_SRCIP : + a->ac_sip = o->o_ip.s_addr; + a->ac_smsk = htonl(0xffffffff << (32 - o->o_num)); + break; + case IPM_SRCPORT : + a->ac_sport = htons(o->o_num); + break; + case IPM_SAVE : + if (a->ac_savefile != NULL) { + fprintf(stderr, "%s redfined on line %d\n", + yykeytostr(o->o_type), yylineNum); + break; + } + a->ac_savefile = strdup(o->o_str); + a->ac_savefp = fopen(o->o_str, "a"); + a->ac_dflag |= o->o_num & IPMDO_SAVERAW; + break; + case IPM_SYSLOG : + if (a->ac_syslog != 0) { + fprintf(stderr, "%s redfined on line %d\n", + yykeytostr(o->o_type), yylineNum); + break; + } + a->ac_syslog = 1; + break; + case IPM_TYPE : + a->ac_type = o->o_num; + break; + case IPM_WITH : + break; + default : + break; + } + + olist = o->o_next; + if (o->o_str != NULL) + free(o->o_str); + free(o); + } + a->ac_next = alist; + alist = a; +} + + +int check_action(buf, log, opts, lvl) +char *buf, *log; +int opts, lvl; +{ + ipmon_action_t *a; + struct timeval tv; + ipflog_t *ipf; + tcphdr_t *tcp; + iplog_t *ipl; + int matched; + u_long t1; + ip_t *ip; + + matched = 0; + ipl = (iplog_t *)buf; + ipf = (ipflog_t *)(ipl +1); + ip = (ip_t *)(ipf + 1); + tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); + + for (a = alist; a != NULL; a = a->ac_next) { + if ((a->ac_mflag & IPMAC_DIRECTION) != 0) { + if (a->ac_direction == IPM_IN) { + if ((ipf->fl_flags & FR_INQUE) == 0) + continue; + } else if (a->ac_direction == IPM_OUT) { + if ((ipf->fl_flags & FR_OUTQUE) == 0) + continue; + } + } + + if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) + continue; + + if ((a->ac_mflag & IPMAC_EVERY) != 0) { + gettimeofday(&tv, NULL); + t1 = tv.tv_sec - a->ac_lastsec; + if (tv.tv_usec <= a->ac_lastusec) + t1--; + if (a->ac_second != 0) { + if (t1 < a->ac_second) + continue; + a->ac_lastsec = tv.tv_sec; + a->ac_lastusec = tv.tv_usec; + } + + if (a->ac_packet != 0) { + if (a->ac_pktcnt == 0) + a->ac_pktcnt++; + else if (a->ac_pktcnt == a->ac_packet) { + a->ac_pktcnt = 0; + continue; + } else { + a->ac_pktcnt++; + continue; + } + } + } + + if ((a->ac_mflag & IPMAC_DSTIP) != 0) { + if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) + continue; + } + + if ((a->ac_mflag & IPMAC_DSTPORT) != 0) { + if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) + continue; + if (tcp->th_dport != a->ac_dport) + continue; + } + + if ((a->ac_mflag & IPMAC_GROUP) != 0) { + if (strncmp(a->ac_group, ipf->fl_group, + FR_GROUPLEN) != 0) + continue; + } + + if ((a->ac_mflag & IPMAC_INTERFACE) != 0) { + if (strcmp(a->ac_iface, ipf->fl_ifname)) + continue; + } + + if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) { + if (a->ac_proto != ip->ip_p) + continue; + } + + if ((a->ac_mflag & IPMAC_RESULT) != 0) { + if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) { + if (a->ac_result != IPMR_NOMATCH) + continue; + } else if (FR_ISPASS(ipf->fl_flags)) { + if (a->ac_result != IPMR_PASS) + continue; + } else if (FR_ISBLOCK(ipf->fl_flags)) { + if (a->ac_result != IPMR_BLOCK) + continue; + } else { /* Log only */ + if (a->ac_result != IPMR_LOG) + continue; + } + } + + if ((a->ac_mflag & IPMAC_RULE) != 0) { + if (a->ac_rule != ipf->fl_rule) + continue; + } + + if ((a->ac_mflag & IPMAC_SRCIP) != 0) { + if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) + continue; + } + + if ((a->ac_mflag & IPMAC_SRCPORT) != 0) { + if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) + continue; + if (tcp->th_sport != a->ac_sport) + continue; + } + + if ((a->ac_mflag & IPMAC_LOGTAG) != 0) { + if (a->ac_logtag != ipf->fl_logtag) + continue; + } + + if ((a->ac_mflag & IPMAC_NATTAG) != 0) { + if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag, + IPFTAG_LEN) != 0) + continue; + } + + matched = 1; + + /* + * It matched so now execute the command + */ + if (a->ac_syslog != 0) { + syslog(lvl, "%s", log); + } + + if (a->ac_savefp != NULL) { + if (a->ac_dflag & IPMDO_SAVERAW) + fwrite(ipl, 1, ipl->ipl_dsize, a->ac_savefp); + else + fputs(log, a->ac_savefp); + } + + if (a->ac_exec != NULL) { + switch (fork()) + { + case 0 : + { + FILE *pi; + + pi = popen(a->ac_run, "w"); + if (pi != NULL) { + fprintf(pi, "%s\n", log); + if ((opts & OPT_HEXHDR) != 0) { + dumphex(pi, 0, buf, + sizeof(*ipl) + + sizeof(*ipf)); + } + if ((opts & OPT_HEXBODY) != 0) { + dumphex(pi, 0, (char *)ip, + ipf->fl_hlen + + ipf->fl_plen); + } + pclose(pi); + } + exit(1); + } + case -1 : + break; + default : + break; + } + } + } + + return matched; +} + + +static void free_action(a) +ipmon_action_t *a; +{ + if (a->ac_savefile != NULL) { + free(a->ac_savefile); + a->ac_savefile = NULL; + } + if (a->ac_savefp != NULL) { + fclose(a->ac_savefp); + a->ac_savefp = NULL; + } + if (a->ac_exec != NULL) { + free(a->ac_exec); + if (a->ac_run == a->ac_exec) + a->ac_run = NULL; + a->ac_exec = NULL; + } + if (a->ac_run != NULL) { + free(a->ac_run); + a->ac_run = NULL; + } + if (a->ac_iface != NULL) { + free(a->ac_iface); + a->ac_iface = NULL; + } + a->ac_next = NULL; + free(a); +} + + +int load_config(file) +char *file; +{ + ipmon_action_t *a; + FILE *fp; + char *s; + + s = getenv("YYDEBUG"); + if (s != NULL) + yydebug = atoi(s); + else + yydebug = 0; + + while ((a = alist) != NULL) { + alist = a->ac_next; + free_action(a); + } + + yylineNum = 1; + + (void) yysettab(yywords); + + fp = fopen(file, "r"); + if (!fp) { + perror("load_config:fopen:"); + return -1; + } + yyin = fp; + while (!feof(fp)) + yyparse(); + fclose(fp); + return 0; +} diff --git a/contrib/ipfilter/tools/ipnat.c b/contrib/ipfilter/tools/ipnat.c new file mode 100644 index 0000000..fc17cea --- /dev/null +++ b/contrib/ipfilter/tools/ipnat.c @@ -0,0 +1,400 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#else +#include <sys/byteorder.h> +#endif +#include <sys/time.h> +#include <sys/param.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/file.h> +#define _KERNEL +#include <sys/uio.h> +#undef _KERNEL +#include <sys/socket.h> +#include <sys/ioctl.h> +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include <sys/ioccom.h> +# include <sys/sysmacros.h> +#endif +#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 <netdb.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <ctype.h> +#if defined(linux) +# include <linux/a.out.h> +#else +# include <nlist.h> +#endif +#include "ipf.h" +#include "ipl.h" +#include "kmem.h" + +#ifdef __hpux +# define nlist nlist64 +#endif + +#if defined(sun) && !SOLARIS2 +# define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +# define STRERROR(x) strerror(x) +#endif + +#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 1.24.2.1 2004/04/28 17:56:22 darrenr Exp"; +#endif + + +#if SOLARIS +#define bzero(a,b) memset(a,0,b) +#endif +int use_inet6 = 0; +char thishost[MAXHOSTNAMELEN]; + +extern char *optarg; + +void dostats __P((natstat_t *, int)), flushtable __P((int, int)); +void usage __P((char *)); +int main __P((int, char*[])); +void showhostmap __P((natstat_t *nsp)); +void natstat_dead __P((natstat_t *, char *)); + +int opts; + +void usage(name) +char *name; +{ + fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name); + exit(1); +} + + +int main(argc, argv) +int argc; +char *argv[]; +{ + char *file, *core, *kernel; + natstat_t ns, *nsp; + int fd, c, mode; + ipfobj_t obj; + + fd = -1; + opts = 0; + nsp = &ns; + file = NULL; + core = NULL; + kernel = NULL; + mode = O_RDWR; + + while ((c = getopt(argc, argv, "CdFf:hlM:N:nrRsv")) != -1) + switch (c) + { + case 'C' : + opts |= OPT_CLEAR; + break; + case 'd' : + opts |= OPT_DEBUG; + break; + case 'f' : + file = optarg; + break; + case 'F' : + opts |= OPT_FLUSH; + break; + case 'h' : + opts |=OPT_HITS; + break; + case 'l' : + opts |= OPT_LIST; + mode = O_RDONLY; + break; + case 'M' : + core = optarg; + break; + case 'N' : + kernel = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING; + mode = O_RDONLY; + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'r' : + opts |= OPT_REMOVE; + break; + case 's' : + opts |= OPT_STAT; + mode = O_RDONLY; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + default : + usage(argv[0]); + } + + initparse(); + + if ((kernel != NULL) || (core != NULL)) { + (void) setgid(getgid()); + (void) setuid(getuid()); + } + + bzero((char *)&ns, sizeof(ns)); + + if ((opts & OPT_DONOTHING) == 0) { + if (checkrev(IPL_NAME) == -1) { + fprintf(stderr, "User/kernel version check failed\n"); + exit(1); + } + } + + + if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) { + if (openkmem(kernel, core) == -1) + exit(1); + + if (((fd = open(IPNAT_NAME, mode)) == -1) && + ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { + (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, + STRERROR(errno)); + exit(1); + } + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*nsp); + obj.ipfo_type = IPFOBJ_NATSTAT; + obj.ipfo_ptr = (void *)nsp; + if (ioctl(fd, SIOCGNATS, &obj) == -1) { + perror("ioctl(SIOCGNATS)"); + exit(1); + } + (void) setgid(getgid()); + (void) setuid(getuid()); + } else if ((kernel != NULL) || (core != NULL)) { + if (openkmem(kernel, core) == -1) + exit(1); + + natstat_dead(nsp, kernel); + if (opts & (OPT_LIST|OPT_STAT)) + dostats(nsp, opts); + exit(0); + } + + if (opts & (OPT_FLUSH|OPT_CLEAR)) + flushtable(fd, opts); + if (file) { + ipnat_parsefile(fd, ipnat_addrule, ioctl, file); + } + if (opts & (OPT_LIST|OPT_STAT)) + dostats(nsp, opts); + return 0; +} + + +/* + * Read NAT statistic information in using a symbol table and memory file + * rather than doing ioctl's. + */ +void natstat_dead(nsp, kernel) +natstat_t *nsp; +char *kernel; +{ + struct nlist nat_nlist[10] = { + { "nat_table" }, /* 0 */ + { "nat_list" }, + { "maptable" }, + { "ipf_nattable_sz" }, + { "ipf_natrules_sz" }, + { "ipf_rdrrules_sz" }, /* 5 */ + { "ipf_hostmap_sz" }, + { "nat_instances" }, + { "ap_sess_list" }, + { NULL } + }; + void *tables[2]; + + if (nlist(kernel, nat_nlist) == -1) { + fprintf(stderr, "nlist error\n"); + return; + } + + /* + * Normally the ioctl copies all of these values into the structure + * for us, before returning it to userland, so here we must copy each + * one in individually. + */ + kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables)); + nsp->ns_table[0] = tables[0]; + nsp->ns_table[1] = tables[1]; + + kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, + sizeof(nsp->ns_list)); + kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, + sizeof(nsp->ns_maptable)); + kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, + sizeof(nsp->ns_nattab_sz)); + kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, + sizeof(nsp->ns_rultab_sz)); + kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, + sizeof(nsp->ns_rdrtab_sz)); + kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, + sizeof(nsp->ns_hostmap_sz)); + kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, + sizeof(nsp->ns_instances)); + kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, + sizeof(nsp->ns_apslist)); +} + + +/* + * Display NAT statistics. + */ +void dostats(nsp, opts) +natstat_t *nsp; +int opts; +{ + nat_t *np, nat; + ipnat_t ipn; + + /* + * Show statistics ? + */ + if (opts & OPT_STAT) { + printf("mapped\tin\t%lu\tout\t%lu\n", + nsp->ns_mapped[0], nsp->ns_mapped[1]); + printf("added\t%lu\texpired\t%lu\n", + nsp->ns_added, nsp->ns_expire); + printf("no memory\t%lu\tbad nat\t%lu\n", + nsp->ns_memfail, nsp->ns_badnat); + printf("inuse\t%lu\nrules\t%lu\n", + nsp->ns_inuse, nsp->ns_rules); + printf("wilds\t%u\n", nsp->ns_wilds); + if (opts & OPT_VERBOSE) + printf("table %p list %p\n", + nsp->ns_table, nsp->ns_list); + } + + /* + * Show list of NAT rules and NAT sessions ? + */ + if (opts & OPT_LIST) { + printf("List of active MAP/Redirect filters:\n"); + while (nsp->ns_list) { + if (kmemcpy((char *)&ipn, (long)nsp->ns_list, + sizeof(ipn))) { + perror("kmemcpy"); + break; + } + if (opts & OPT_HITS) + printf("%lu ", ipn.in_hits); + printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); + nsp->ns_list = ipn.in_next; + } + + printf("\nList of active sessions:\n"); + + for (np = nsp->ns_instances; np; np = nat.nat_next) { + if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) + break; + printactivenat(&nat, opts); + if (nat.nat_aps) + printaps(nat.nat_aps, opts); + } + + if (opts & OPT_VERBOSE) + showhostmap(nsp); + } +} + + +/* + * Display the active host mapping table. + */ +void showhostmap(nsp) +natstat_t *nsp; +{ + hostmap_t hm, *hmp, **maptable; + u_int hv; + + printf("\nList of active host mappings:\n"); + + maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) * + nsp->ns_hostmap_sz); + if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable, + sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) { + perror("kmemcpy (maptable)"); + return; + } + + for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { + hmp = maptable[hv]; + + while (hmp) { + if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) { + perror("kmemcpy (hostmap)"); + return; + } + + printhostmap(&hm, hv); + hmp = hm.hm_next; + } + } + free(maptable); +} + + +/* + * Issue an ioctl to flush either the NAT rules table or the active mapping + * table or both. + */ +void flushtable(fd, opts) +int fd, opts; +{ + int n = 0; + + if (opts & OPT_FLUSH) { + n = 0; + if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) + perror("ioctl(SIOCFLNAT)"); + else + printf("%d entries flushed from NAT table\n", n); + } + + if (opts & OPT_CLEAR) { + n = 1; + if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) + perror("ioctl(SIOCCNATL)"); + else + printf("%d entries flushed from NAT list\n", n); + } +} diff --git a/contrib/ipfilter/tools/ipnat_y.y b/contrib/ipfilter/tools/ipnat_y.y new file mode 100644 index 0000000..d3f18c6 --- /dev/null +++ b/contrib/ipfilter/tools/ipnat_y.y @@ -0,0 +1,828 @@ +/* $NetBSD$ */ + +%{ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#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 <syslog.h> +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#include <netdb.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include "ipf.h" +#include "netinet/ipl.h" +#include "ipnat_l.h" + +#define YYDEBUG 1 + +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; + +static ipnat_t *nattop = NULL; +static ipnat_t *nat = NULL; +static int natfd = -1; +static ioctlfunc_t natioctlfunc = NULL; +static addfunc_t nataddfunc = NULL; + +static void newnatrule __P((void)); +static void setnatproto __P((int)); + +%} +%union { + char *str; + u_32_t num; + struct in_addr ipa; + frentry_t fr; + frtuc_t *frt; + u_short port; + struct { + u_short p1; + u_short p2; + int pc; + } pc; + struct { + struct in_addr a; + struct in_addr m; + } ipp; + union i6addr ip6; +}; + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token <ip6> YY_IPV6 + +%token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE +%token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY +%token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY +%token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG +%token IPNY_TLATE +%type <port> portspec +%type <num> hexnumber compare range proto +%type <ipa> hostname ipv4 +%type <ipp> addr nummask rhaddr +%type <pc> portstuff +%% +file: line + | assign + | file line + | file assign + ; + +line: xx rule { while ((nat = nattop) != NULL) { + nattop = nat->in_next; + (*nataddfunc)(natfd, natioctlfunc, nat); + free(nat); + } + resetlexer(); + } + | YY_COMMENT + ; + +assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +xx: { newnatrule(); } + ; + +rule: map eol + | mapblock eol + | redir eol + ; + +eol: | ';' + ; + +map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions + { nat->in_v = 4; + nat->in_inip = $3.a.s_addr; + nat->in_inmsk = $3.m.s_addr; + nat->in_outip = $5.a.s_addr; + nat->in_outmsk = $5.m.s_addr; + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + if ((nat->in_flags & IPN_TCPUDP) == 0) + setnatproto(nat->in_p); + if (((nat->in_redir & NAT_MAPBLK) != 0) || + ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) + nat_setgroupmap(nat); + } + | mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions + { nat->in_v = 4; + nat->in_inip = $3.a.s_addr; + nat->in_inmsk = $3.m.s_addr; + nat->in_outip = $5.a.s_addr; + nat->in_outmsk = $5.m.s_addr; + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0) + setnatproto(nat->in_p); + if (((nat->in_redir & NAT_MAPBLK) != 0) || + ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) + nat_setgroupmap(nat); + } + | mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions + { nat->in_v = 4; + nat->in_outip = $5.a.s_addr; + nat->in_outmsk = $5.m.s_addr; + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + if ((nat->in_flags & IPN_TCPUDP) == 0) + setnatproto(nat->in_p); + if (((nat->in_redir & NAT_MAPBLK) != 0) || + ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) + nat_setgroupmap(nat); + } + | mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions + { nat->in_v = 4; + nat->in_outip = $5.a.s_addr; + nat->in_outmsk = $5.m.s_addr; + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0) + setnatproto(nat->in_p); + if (((nat->in_redir & NAT_MAPBLK) != 0) || + ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) + nat_setgroupmap(nat); + } + ; + +mapblock: + mapblockit ifnames addr IPNY_TLATE addr ports mapoptions + { nat->in_v = 4; + nat->in_inip = $3.a.s_addr; + nat->in_inmsk = $3.m.s_addr; + nat->in_outip = $5.a.s_addr; + nat->in_outmsk = $5.m.s_addr; + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + if ((nat->in_flags & IPN_TCPUDP) == 0) + setnatproto(nat->in_p); + if (((nat->in_redir & NAT_MAPBLK) != 0) || + ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) + nat_setgroupmap(nat); + } + ; + +redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions + { nat->in_v = 4; + nat->in_outip = $3.a.s_addr; + nat->in_outmsk = $3.m.s_addr; + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + if ((nat->in_p == 0) && + ((nat->in_flags & IPN_TCPUDP) == 0) && + (nat->in_pmin != 0 || + nat->in_pmax != 0 || + nat->in_pnext != 0)) + setnatproto(IPPROTO_TCP); + } + | rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions + { nat->in_v = 4; + if ((nat->in_p == 0) && + ((nat->in_flags & IPN_TCPUDP) == 0) && + (nat->in_pmin != 0 || + nat->in_pmax != 0 || + nat->in_pnext != 0)) + setnatproto(IPPROTO_TCP); + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + } + | rdrit ifnames addr IPNY_TLATE dip setproto rdroptions + { nat->in_v = 4; + nat->in_outip = $3.a.s_addr; + nat->in_outmsk = $3.m.s_addr; + if (nat->in_ifnames[1][0] == '\0') + strncpy(nat->in_ifnames[1], + nat->in_ifnames[0], + sizeof(nat->in_ifnames[0])); + } + ; + +proxy: | IPNY_PROXY IPNY_PORT portspec YY_STR '/' proto + { strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); + if (nat->in_dcmp == 0) { + nat->in_dport = htons($3); + } else if ($3 != nat->in_dport) { + yyerror("proxy port numbers not consistant"); + } + setnatproto($6); + free($4); + } + | IPNY_PROXY IPNY_PORT YY_STR YY_STR '/' proto + { int pnum; + strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); + pnum = getportproto($3, $6); + if (pnum == -1) + yyerror("invalid port number"); + nat->in_dport = pnum; + setnatproto($6); + free($3); + free($4); + } + ; + +setproto: + | proto { if (nat->in_p != 0 || + nat->in_flags & IPN_TCPUDP) + yyerror("protocol set twice"); + setnatproto($1); + } + | IPNY_TCPUDP { if (nat->in_p != 0 || + nat->in_flags & IPN_TCPUDP) + yyerror("protocol set twice"); + nat->in_flags |= IPN_TCPUDP; + nat->in_p = 0; + } + | IPNY_TCP '/' IPNY_UDP { if (nat->in_p != 0 || + nat->in_flags & IPN_TCPUDP) + yyerror("protocol set twice"); + nat->in_flags |= IPN_TCPUDP; + nat->in_p = 0; + } + ; + +rhaddr: addr { $$.a = $1.a; $$.m = $1.m; } + | IPNY_RANGE ipv4 '-' ipv4 + { $$.a = $2; $$.m = $4; + nat->in_flags |= IPN_IPRANGE; } + ; + +dip: + hostname { nat->in_inip = $1.s_addr; + nat->in_inmsk = 0xffffffff; } + | hostname ',' hostname { nat->in_flags |= IPN_SPLIT; + nat->in_inip = $1.s_addr; + nat->in_inmsk = $3.s_addr; } + ; + +portspec: + YY_NUMBER { if ($1 > 65535) /* Unsigned */ + yyerror("invalid port number"); + else + $$ = $1; + } + | YY_STR { if (getport(NULL, $1, &($$)) == -1) + yyerror("invalid port number"); + $$ = ntohs($$); + } + ; + +dport: | IPNY_PORT portspec { nat->in_pmin = htons($2); + nat->in_pmax = htons($2); } + | IPNY_PORT portspec '-' portspec { nat->in_pmin = htons($2); + nat->in_pmax = htons($4); } + | IPNY_PORT portspec ':' portspec { nat->in_pmin = htons($2); + nat->in_pmax = htons($4); } + ; + +nport: IPNY_PORT portspec { nat->in_pnext = htons($2); } + | IPNY_PORT '=' portspec { nat->in_pnext = htons($3); + nat->in_flags |= IPN_FIXEDDPORT; + } + ; + +ports: | IPNY_PORTS YY_NUMBER { nat->in_pmin = $2; } + | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; } + ; + +mapit: IPNY_MAP { nat->in_redir = NAT_MAP; } + | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; } + ; + +rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; } + ; + +mapblockit: + IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; } + ; + +mapfrom: + from sobject IPNY_TO dobject + | from sobject '!' IPNY_TO dobject + { nat->in_flags |= IPN_NOTDST; } + ; + +rdrfrom: + from sobject IPNY_TO dobject + | '!' from sobject IPNY_TO dobject + { nat->in_flags |= IPN_NOTSRC; } + ; + +from: IPNY_FROM { nat->in_flags |= IPN_FILTER; } + ; + +ifnames: + ifname + | ifname ',' otherifname + ; + +ifname: YY_STR { strncpy(nat->in_ifnames[0], $1, + sizeof(nat->in_ifnames[0])); + nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; + free($1); + } + ; + +otherifname: + YY_STR { strncpy(nat->in_ifnames[1], $1, + sizeof(nat->in_ifnames[1])); + nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; + free($1); + } + ; + +mapport: + IPNY_PORTMAP tcpudp portspec ':' portspec + { nat->in_pmin = htons($3); + nat->in_pmax = htons($5); + } + | IPNY_PORTMAP tcpudp IPNY_AUTO + { nat->in_flags |= IPN_AUTOPORTMAP; + nat->in_pmin = htons(1024); + nat->in_pmax = htons(65535); + } + | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER + { if (strcmp($2, "icmp") != 0) { + yyerror("icmpidmap not followed by icmp"); + } + free($2); + if ($3 < 0 || $3 > 65535) + yyerror("invalid ICMP Id number"); + if ($5 < 0 || $5 > 65535) + yyerror("invalid ICMP Id number"); + nat->in_flags = IPN_ICMPQUERY; + nat->in_pmin = htons($3); + nat->in_pmax = htons($5); + } + ; + +sobject: + saddr + | saddr IPNY_PORT portstuff { nat->in_sport = $3.p1; + nat->in_stop = $3.p2; + nat->in_scmp = $3.pc; } + ; + +saddr: addr { if (nat->in_redir == NAT_REDIRECT) { + nat->in_srcip = $1.a.s_addr; + nat->in_srcmsk = $1.m.s_addr; + } else { + nat->in_inip = $1.a.s_addr; + nat->in_inmsk = $1.m.s_addr; + } + } + ; + +dobject: + daddr + | daddr IPNY_PORT portstuff { nat->in_dport = $3.p1; + nat->in_dtop = $3.p2; + nat->in_dcmp = $3.pc; + if (nat->in_redir == NAT_REDIRECT) + nat->in_pmin = htons($3.p1); + } + ; + +daddr: addr { if (nat->in_redir == NAT_REDIRECT) { + nat->in_outip = $1.a.s_addr; + nat->in_outmsk = $1.m.s_addr; + } else { + nat->in_srcip = $1.a.s_addr; + nat->in_srcmsk = $1.m.s_addr; + } + } + ; + +addr: IPNY_ANY { $$.a.s_addr = 0; $$.m.s_addr = 0; } + | nummask { $$.a = $1.a; $$.m = $1.m; + $$.a.s_addr &= $$.m.s_addr; } + | hostname '/' ipv4 { $$.a = $1; $$.m = $3; + $$.a.s_addr &= $$.m.s_addr; } + | hostname '/' hexnumber { $$.a = $1; $$.m.s_addr = $3; + $$.a.s_addr &= $$.m.s_addr; } + | hostname IPNY_MASK ipv4 { $$.a = $1; $$.m = $3; + $$.a.s_addr &= $$.m.s_addr; } + | hostname IPNY_MASK hexnumber { $$.a = $1; $$.m.s_addr = $3; + $$.a.s_addr &= $$.m.s_addr; } + ; + +nummask: + hostname { $$.a = $1; + $$.m.s_addr = 0xffffffff; } + | hostname '/' YY_NUMBER { $$.a = $1; + ntomask(4, $3, &$$.m.s_addr); } + ; + +portstuff: + compare portspec { $$.pc = $1; $$.p1 = $2; } + | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p1 = $3; } + ; + +mapoptions: + rr frag age mssclamp nattag setproto + ; + +rdroptions: + rr frag age sticky mssclamp rdrproxy nattag + ; + +nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2, + sizeof(nat->in_tag.ipt_tag)); + } +rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; } + ; + +frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; } + ; + +age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2; + nat->in_age[1] = $2; } + | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2; + nat->in_age[1] = $4; } + ; + +sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) && + !(nat->in_flags & IPN_SPLIT)) { + fprintf(stderr, + "'sticky' for use with round-robin/IP splitting only\n"); + } else + nat->in_flags |= IPN_STICKY; + } + ; + +mssclamp: + | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; } + ; + +tcpudp: | IPNY_TCP { setnatproto(IPPROTO_TCP); } + | IPNY_UDP { setnatproto(IPPROTO_UDP); } + | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP; + nat->in_p = 0; + } + | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP; + nat->in_p = 0; + } + ; + +rdrproxy: + IPNY_PROXY YY_STR + { strncpy(nat->in_plabel, $2, + sizeof(nat->in_plabel)); + nat->in_dport = nat->in_pnext; + nat->in_dport = htons(nat->in_dport); + free($2); + } + | proxy { if (nat->in_plabel[0] != '\0') { + nat->in_pmin = nat->in_dport; + nat->in_pmax = nat->in_pmin; + nat->in_pnext = nat->in_pmin; + } + } + ; + +proto: YY_NUMBER { $$ = $1; } + | IPNY_TCP { $$ = IPPROTO_TCP; } + | IPNY_UDP { $$ = IPPROTO_UDP; } + | YY_STR { $$ = getproto($1); free($1); } + ; + +hexnumber: + YY_HEX { $$ = $1; } + ; + +hostname: + YY_STR { if (gethost($1, &$$.s_addr) == -1) + fprintf(stderr, + "Unknown host '%s'\n", + $1); + free($1); + } + | YY_NUMBER { $$.s_addr = htonl($1); } + | ipv4 { $$.s_addr = $1.s_addr; } + ; + +compare: + '=' { $$ = FR_EQUAL; } + | YY_CMP_EQ { $$ = FR_EQUAL; } + | YY_CMP_NE { $$ = FR_NEQUAL; } + | YY_CMP_LT { $$ = FR_LESST; } + | YY_CMP_LE { $$ = FR_LESSTE; } + | YY_CMP_GT { $$ = FR_GREATERT; } + | YY_CMP_GE { $$ = FR_GREATERTE; } + +range: + YY_RANGE_OUT { $$ = FR_OUTRANGE; } + | YY_RANGE_IN { $$ = FR_INRANGE; } + ; + +ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; + $$.s_addr = htonl($$.s_addr); + } + ; + +%% + + +static wordtab_t yywords[] = { + { "age", IPNY_AGE }, + { "any", IPNY_ANY }, + { "auto", IPNY_AUTO }, + { "bimap", IPNY_BIMAP }, + { "frag", IPNY_FRAG }, + { "from", IPNY_FROM }, + { "icmpidmap", IPNY_ICMPIDMAP }, + { "mask", IPNY_MASK }, + { "map", IPNY_MAP }, + { "map-block", IPNY_MAPBLOCK }, + { "mssclamp", IPNY_MSSCLAMP }, + { "netmask", IPNY_MASK }, + { "port", IPNY_PORT }, + { "portmap", IPNY_PORTMAP }, + { "ports", IPNY_PORTS }, + { "proxy", IPNY_PROXY }, + { "range", IPNY_RANGE }, + { "rdr", IPNY_RDR }, + { "round-robin",IPNY_ROUNDROBIN }, + { "sticky", IPNY_STICKY }, + { "tag", IPNY_TAG }, + { "tcp", IPNY_TCP }, + { "tcpudp", IPNY_TCPUDP }, + { "to", IPNY_TO }, + { "udp", IPNY_UDP }, + { "-", '-' }, + { "->", IPNY_TLATE }, + { "eq", YY_CMP_EQ }, + { "ne", YY_CMP_NE }, + { "lt", YY_CMP_LT }, + { "gt", YY_CMP_GT }, + { "le", YY_CMP_LE }, + { "ge", YY_CMP_GE }, + { NULL, 0 } +}; + + +int ipnat_parsefile(fd, addfunc, ioctlfunc, filename) +int fd; +addfunc_t addfunc; +ioctlfunc_t ioctlfunc; +char *filename; +{ + FILE *fp = NULL; + char *s; + + (void) yysettab(yywords); + + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + if (strcmp(filename, "-")) { + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "fopen(%s) failed: %s\n", filename, + STRERROR(errno)); + return -1; + } + } else + fp = stdin; + + while (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1) + ; + if (fp != NULL) + fclose(fp); + return 0; +} + + +int ipnat_parsesome(fd, addfunc, ioctlfunc, fp) +int fd; +addfunc_t addfunc; +ioctlfunc_t ioctlfunc; +FILE *fp; +{ + char *s; + int i; + + yylineNum = 1; + + natfd = fd; + nataddfunc = addfunc; + natioctlfunc = ioctlfunc; + + if (feof(fp)) + return 0; + i = fgetc(fp); + if (i == EOF) + return 0; + if (ungetc(i, fp) == EOF) + return 0; + if (feof(fp)) + return 0; + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + yyin = fp; + yyparse(); + return 1; +} + + +static void newnatrule() +{ + ipnat_t *n; + + n = calloc(1, sizeof(*n)); + if (n == NULL) + return; + + if (nat == NULL) + nattop = nat = n; + else { + nat->in_next = n; + nat = n; + } +} + + +static void setnatproto(p) +int p; +{ + nat->in_p = p; + + switch (p) + { + case IPPROTO_TCP : + nat->in_flags |= IPN_TCP; + nat->in_flags &= ~IPN_UDP; + break; + case IPPROTO_UDP : + nat->in_flags |= IPN_UDP; + nat->in_flags &= ~IPN_TCP; + break; + case IPPROTO_ICMP : + nat->in_flags &= ~IPN_TCPUDP; + if (!(nat->in_flags & IPN_ICMPQUERY)) { + nat->in_dcmp = 0; + nat->in_scmp = 0; + nat->in_pmin = 0; + nat->in_pmax = 0; + nat->in_pnext = 0; + } + break; + default : + if ((nat->in_redir & NAT_MAPBLK) == 0) { + nat->in_flags &= ~IPN_TCPUDP; + nat->in_dcmp = 0; + nat->in_scmp = 0; + nat->in_pmin = 0; + nat->in_pmax = 0; + nat->in_pnext = 0; + } + break; + } + + if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) + nat->in_flags &= ~IPN_FIXEDDPORT; +} + + +void ipnat_addrule(fd, ioctlfunc, ptr) +int fd; +ioctlfunc_t ioctlfunc; +void *ptr; +{ + ioctlcmd_t add, del; + ipfobj_t obj; + ipnat_t *ipn; + + ipn = ptr; + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(ipnat_t); + obj.ipfo_type = IPFOBJ_IPNAT; + obj.ipfo_ptr = ptr; + add = 0; + del = 0; + + if ((opts & OPT_DONOTHING) != 0) + fd = -1; + + if (opts & OPT_ZERORULEST) { + add = SIOCZRLST; + } else if (opts & OPT_INACTIVE) { + add = SIOCADNAT; + del = SIOCRMNAT; + } else { + add = SIOCADNAT; + del = SIOCRMNAT; + } + + if (ipn && (opts & OPT_VERBOSE)) + printnat(ipn, opts); + + if (opts & OPT_DEBUG) + binprint(ipn, sizeof(*ipn)); + + if ((opts & OPT_ZERORULEST) != 0) { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + fprintf(stderr, "%d:", yylineNum); + 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 ", + fr->fr_hits, fr->fr_bytes); +*/ +#endif + printnat(ipn, opts); + } + } else if ((opts & OPT_REMOVE) != 0) { + if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + fprintf(stderr, "%d:", yylineNum); + perror("ioctl(delete nat rule)"); + } + } + } else { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + fprintf(stderr, "%d:", yylineNum); + perror("ioctl(add/insert nat rule)"); + } + } + } +} diff --git a/contrib/ipfilter/tools/ippool.c b/contrib/ipfilter/tools/ippool.c new file mode 100644 index 0000000..7122c94 --- /dev/null +++ b/contrib/ipfilter/tools/ippool.c @@ -0,0 +1,700 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <sys/socket.h> +#if defined(BSD) && (BSD >= 199306) +# include <sys/cdefs.h> +#endif +#include <sys/ioctl.h> + +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#include <netinet/in.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <ctype.h> +#include <unistd.h> + +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "kmem.h" + + +extern int ippool_yyparse __P((void)); +extern int ippool_yydebug; +extern FILE *ippool_yyin; +extern char *optarg; +extern int lineNum; + +void showpools __P((ip_pool_stat_t *)); +void usage __P((char *)); +int main __P((int, char **)); +int poolcommand __P((int, int, char *[])); +int poolnodecommand __P((int, int, char *[])); +int loadpoolfile __P((int, char *[], char *)); +int poollist __P((int, char *[])); +int poolflush __P((int, char *[])); +int poolstats __P((int, char *[])); +int gettype __P((char *, u_int *)); +int getrole __P((char *)); + +int opts = 0; +int fd = -1; +int use_inet6 = 0; + + +void usage(prog) +char *prog; +{ + fprintf(stderr, "Usage:\t%s\n", prog); + fprintf(stderr, "\t\t\t-a [-dnv] [-m <name>] [-o <role>] -i <ipaddr>[/netmask]\n"); + fprintf(stderr, "\t\t\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n"); + fprintf(stderr, "\t\t\t-f <file> [-dnuv]\n"); + fprintf(stderr, "\t\t\t-F [-dv] [-o <role>] [-t <type>]\n"); + fprintf(stderr, "\t\t\t-l [-dv] [-m <name>] [-t <type>]\n"); + fprintf(stderr, "\t\t\t-r [-dnv] [-m <name>] [-o <role>] -i <ipaddr>[/netmask]\n"); + fprintf(stderr, "\t\t\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n"); + fprintf(stderr, "\t\t\t-s [-dtv] [-M <core>] [-N <namelist>]\n"); + exit(1); +} + + +int main(argc, argv) +int argc; +char *argv[]; +{ + int err; + + if (argc < 2) + usage(argv[0]); + + switch (getopt(argc, argv, "aAf:FlrRs")) + { + case 'a' : + err = poolnodecommand(0, argc, argv); + break; + case 'A' : + err = poolcommand(0, argc, argv); + break; + case 'f' : + err = loadpoolfile(argc, argv, optarg); + break; + case 'F' : + err = poolflush(argc, argv); + break; + case 'l' : + err = poollist(argc, argv); + break; + case 'r' : + err = poolnodecommand(1, argc, argv); + break; + case 'R' : + err = poolcommand(1, argc, argv); + break; + case 's' : + err = poolstats(argc, argv); + break; + default : + exit(1); + } + + return err; +} + + +int poolnodecommand(remove, argc, argv) +int remove, argc; +char *argv[]; +{ + char *poolname = NULL, *s; + int err, c, ipset, role; + ip_pool_node_t node; + struct in_addr mask; + + ipset = 0; + role = IPL_LOGIPF; + bzero((char *)&node, sizeof(node)); + + while ((c = getopt(argc, argv, "di:m:no:Rv")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + ippool_yydebug++; + break; + case 'i' : + s = strchr(optarg, '/'); + if (s == NULL) + mask.s_addr = 0xffffffff; + else if (strchr(s, '.') == NULL) { + if (ntomask(4, atoi(s + 1), &mask.s_addr) != 0) + return -1; + } else { + mask.s_addr = inet_addr(s + 1); + } + if (s != NULL) + *s = '\0'; + ipset = 1; + node.ipn_addr.adf_len = sizeof(node.ipn_addr); + node.ipn_addr.adf_addr.in4.s_addr = inet_addr(optarg); + node.ipn_mask.adf_len = sizeof(node.ipn_mask); + node.ipn_mask.adf_addr.in4.s_addr = mask.s_addr; + break; + case 'm' : + poolname = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) + return -1; + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolnodecommand: opts = %#x\n", opts); + + if (ipset == 0) + return -1; + if (poolname == NULL) { + fprintf(stderr, "poolname not given with add/remove node\n"); + return -1; + } + + if (remove == 0) + err = load_poolnode(0, poolname, &node, ioctl); + else + err = remove_poolnode(0, poolname, &node, ioctl); + return err; +} + + +int poolcommand(remove, argc, argv) +int remove, argc; +char *argv[]; +{ + int type, role, c, err; + char *poolname; + iphtable_t iph; + ip_pool_t pool; + + err = 1; + role = 0; + type = 0; + poolname = NULL; + role = IPL_LOGIPF; + bzero((char *)&iph, sizeof(iph)); + bzero((char *)&pool, sizeof(pool)); + + while ((c = getopt(argc, argv, "dm:no:RSt:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + ippool_yydebug++; + break; + case 'm' : + poolname = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'S' : + iph.iph_seed = atoi(optarg); + break; + case 't' : + type = gettype(optarg, &iph.iph_type); + if (type == IPLT_NONE) { + fprintf(stderr, "unknown type '%s'\n", optarg); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolcommand: opts = %#x\n", opts); + + if (poolname == NULL) { + fprintf(stderr, "poolname not given with add/remove pool\n"); + return -1; + } + + if (type == IPLT_HASH) { + strncpy(iph.iph_name, poolname, sizeof(iph.iph_name)); + iph.iph_name[sizeof(iph.iph_name) - 1] = '\0'; + iph.iph_unit = role; + } else if (type == IPLT_POOL) { + strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name)); + pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0'; + pool.ipo_unit = role; + } + + if (remove == 0) { + switch (type) + { + case IPLT_HASH : + err = load_hash(&iph, NULL, ioctl); + break; + case IPLT_POOL : + err = load_pool(&pool, ioctl); + break; + } + } else { + switch (type) + { + case IPLT_HASH : + err = remove_hash(&iph, ioctl); + break; + case IPLT_POOL : + err = remove_pool(&pool, ioctl); + break; + } + } + return err; +} + + +int loadpoolfile(argc, argv, infile) +int argc; +char *argv[], *infile; +{ + int c; + + infile = optarg; + + while ((c = getopt(argc, argv, "dnRuv")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + ippool_yydebug++; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'u' : + opts |= OPT_REMOVE; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "loadpoolfile: opts = %#x\n", opts); + + if (!(opts & OPT_DONOTHING) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + if (ippool_parsefile(fd, infile, ioctl) != 0) + return -1; + return 0; +} + + +int poollist(argc, argv) +int argc; +char *argv[]; +{ + char *kernel, *core, *poolname; + int c, role, type, live_kernel; + ip_pool_stat_t *plstp, plstat; + iphtstat_t *htstp, htstat; + iphtable_t *hptr; + iplookupop_t op; + ip_pool_t *ptr; + + core = NULL; + kernel = NULL; + live_kernel = 1; + type = IPLT_ALL; + poolname = NULL; + role = IPL_LOGALL; + + while ((c = getopt(argc, argv, "dm:M:N:o:Rt:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + break; + case 'm' : + poolname = optarg; + break; + case 'M' : + live_kernel = 0; + core = optarg; + break; + case 'N' : + live_kernel = 0; + kernel = optarg; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 't' : + type = gettype(optarg, NULL); + if (type == IPLT_NONE) { + fprintf(stderr, "unknown type '%s'\n", optarg); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poollist: opts = %#x\n", opts); + + if (!(opts & OPT_DONOTHING) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + bzero((char *)&op, sizeof(op)); + if (poolname != NULL) { + strncpy(op.iplo_name, poolname, sizeof(op.iplo_name)); + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; + } + op.iplo_unit = role; + + if (openkmem(kernel, core) == -1) + exit(-1); + + if (type == IPLT_ALL || type == IPLT_POOL) { + plstp = &plstat; + op.iplo_type = IPLT_POOL; + op.iplo_size = sizeof(plstat); + op.iplo_struct = &plstat; + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + perror("ioctl(SIOCLOOKUPSTAT)"); + return -1; + } + + if (role != IPL_LOGALL) { + ptr = plstp->ipls_list[role]; + while (ptr != NULL) { + ptr = printpool(ptr, kmemcpywrap, poolname, + opts); + } + } else { + for (role = 0; role <= IPL_LOGMAX; role++) { + ptr = plstp->ipls_list[role]; + while (ptr != NULL) { + ptr = printpool(ptr, kmemcpywrap, + poolname, opts); + } + } + role = IPL_LOGALL; + } + } + if (type == IPLT_ALL || type == IPLT_HASH) { + htstp = &htstat; + op.iplo_type = IPLT_HASH; + op.iplo_size = sizeof(htstat); + op.iplo_struct = &htstat; + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + perror("ioctl(SIOCLOOKUPSTAT)"); + return -1; + } + + if (role != IPL_LOGALL) { + hptr = htstp->iphs_tables; + while (hptr != NULL) { + hptr = printhash(hptr, kmemcpywrap, + poolname, opts); + } + } else { + for (role = 0; role <= IPL_LOGMAX; role++) { + hptr = htstp->iphs_tables; + while (hptr != NULL) { + hptr = printhash(hptr, kmemcpywrap, + poolname, opts); + } + + op.iplo_unit = role; + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + perror("ioctl(SIOCLOOKUPSTAT)"); + return -1; + } + } + } + } + return 0; +} + + +int poolstats(argc, argv) +int argc; +char *argv[]; +{ + int c, type, role, live_kernel; + ip_pool_stat_t plstat; + char *kernel, *core; + iphtstat_t htstat; + iplookupop_t op; + + core = NULL; + kernel = NULL; + live_kernel = 1; + type = IPLT_ALL; + role = IPL_LOGALL; + + bzero((char *)&op, sizeof(op)); + + while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + break; + case 'M' : + live_kernel = 0; + core = optarg; + break; + case 'N' : + live_kernel = 0; + kernel = optarg; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 't' : + type = gettype(optarg, NULL); + if (type != IPLT_POOL) { + fprintf(stderr, + "-s not supported for this type yet\n"); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolstats: opts = %#x\n", opts); + + if (!(opts & OPT_DONOTHING) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + if (type == IPLT_ALL || type == IPLT_POOL) { + op.iplo_type = IPLT_POOL; + op.iplo_struct = &plstat; + op.iplo_size = sizeof(plstat); + if (!(opts & OPT_DONOTHING)) { + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + perror("ioctl(SIOCLOOKUPSTAT)"); + return -1; + } + printf("Pools:\t%lu\n", plstat.ipls_pools); + printf("Nodes:\t%lu\n", plstat.ipls_nodes); + } + } + + if (type == IPLT_ALL || type == IPLT_HASH) { + op.iplo_type = IPLT_HASH; + op.iplo_struct = &htstat; + op.iplo_size = sizeof(htstat); + if (!(opts & OPT_DONOTHING)) { + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + perror("ioctl(SIOCLOOKUPSTAT)"); + return -1; + } + printf("Hash Tables:\t%lu\n", htstat.iphs_numtables); + printf("Nodes:\t%lu\n", htstat.iphs_numnodes); + printf("Out of Memory:\t%lu\n", htstat.iphs_nomem); + } + } + return 0; +} + + +int poolflush(argc, argv) +int argc; +char *argv[]; +{ + int c, role, type, arg; + iplookupflush_t flush; + + arg = IPLT_ALL; + type = IPLT_ALL; + role = IPL_LOGALL; + + while ((c = getopt(argc, argv, "do:t:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 't' : + type = gettype(optarg, NULL); + if (type == IPLT_NONE) { + fprintf(stderr, "unknown type '%s'\n", optarg); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolflush: opts = %#x\n", opts); + + if (!(opts & OPT_DONOTHING) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + bzero((char *)&flush, sizeof(flush)); + flush.iplf_type = type; + flush.iplf_unit = role; + flush.iplf_arg = arg; + + if (!(opts & OPT_DONOTHING)) { + if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) { + perror("ioctl(SIOCLOOKUPFLUSH)"); + exit(1); + } + + } + printf("%u object%s flushed\n", flush.iplf_count, + (flush.iplf_count == 1) ? "" : "s"); + + return 0; +} + + +int getrole(rolename) +char *rolename; +{ + int role; + + if (!strcasecmp(rolename, "ipf")) { + role = IPL_LOGIPF; +#if 0 + } else if (!strcasecmp(rolename, "nat")) { + role = IPL_LOGNAT; + } else if (!strcasecmp(rolename, "state")) { + role = IPL_LOGSTATE; + } else if (!strcasecmp(rolename, "auth")) { + role = IPL_LOGAUTH; + } else if (!strcasecmp(rolename, "sync")) { + role = IPL_LOGSYNC; + } else if (!strcasecmp(rolename, "scan")) { + role = IPL_LOGSCAN; + } else if (!strcasecmp(rolename, "pool")) { + role = IPL_LOGLOOKUP; + } else if (!strcasecmp(rolename, "count")) { + role = IPL_LOGCOUNT; +#endif + } else { + role = IPL_LOGNONE; + } + + return role; +} + + +int gettype(typename, minor) +char *typename; +u_int *minor; +{ + int type; + + if (!strcasecmp(optarg, "tree")) { + type = IPLT_POOL; + } else if (!strcasecmp(optarg, "hash")) { + type = IPLT_HASH; + if (minor != NULL) + *minor = IPHASH_LOOKUP; + } else if (!strcasecmp(optarg, "group-map")) { + type = IPLT_HASH; + if (minor != NULL) + *minor = IPHASH_GROUPMAP; + } else { + type = IPLT_NONE; + } + return type; +} diff --git a/contrib/ipfilter/tools/ippool_y.y b/contrib/ipfilter/tools/ippool_y.y new file mode 100644 index 0000000..357745d --- /dev/null +++ b/contrib/ipfilter/tools/ippool_y.y @@ -0,0 +1,415 @@ +/* $NetBSD$ */ + +%{ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <sys/socket.h> +#if defined(BSD) && (BSD >= 199306) +# include <sys/cdefs.h> +#endif +#include <sys/ioctl.h> + +#include <net/if.h> +#if __FreeBSD_version >= 300000 +# include <net/if_var.h> +#endif +#include <netinet/in.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <ctype.h> +#include <unistd.h> + +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "ippool_l.h" +#include "kmem.h" + +#define YYDEBUG 1 + +extern int yyparse __P((void)); +extern int yydebug; +extern FILE *yyin; + +static iphtable_t ipht; +static iphtent_t iphte; +static ip_pool_t iplo; +static ioctlfunc_t poolioctl = NULL; +static char poolname[FR_GROUPLEN]; + +%} + +%union { + char *str; + u_32_t num; + struct in_addr addr; + struct alist_s *alist; + struct in_addr adrmsk[2]; + iphtent_t *ipe; + ip_pool_node_t *ipp; + union i6addr ip6; +} + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token <ip6> YY_IPV6 + +%token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT +%token IPT_TABLE IPT_GROUPMAP IPT_HASH +%token IPT_ROLE IPT_TYPE IPT_TREE +%token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME +%type <num> role table inout +%type <ipp> ipftree range addrlist +%type <adrmsk> addrmask +%type <ipe> ipfgroup ipfhash hashlist hashentry +%type <ipe> groupentry setgrouplist grouplist +%type <addr> ipaddr mask ipv4 +%type <str> number setgroup + +%% +file: line + | assign + | file line + | file assign + ; + +line: table role ipftree eol { iplo.ipo_unit = $2; + iplo.ipo_list = $3; + load_pool(&iplo, poolioctl); + resetlexer(); + } + | table role ipfhash eol { ipht.iph_unit = $2; + ipht.iph_type = IPHASH_LOOKUP; + load_hash(&ipht, $3, poolioctl); + resetlexer(); + } + | groupmap role number ipfgroup eol + { ipht.iph_unit = $2; + strncpy(ipht.iph_name, $3, + sizeof(ipht.iph_name)); + ipht.iph_type = IPHASH_GROUPMAP; + load_hash(&ipht, $4, poolioctl); + resetlexer(); + } + | YY_COMMENT + ; + +eol: ';' + ; + +assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht)); + bzero((char *)&iphte, sizeof(iphte)); + bzero((char *)&iplo, sizeof(iplo)); + *ipht.iph_name = '\0'; + iplo.ipo_flags = IPHASH_ANON; + iplo.ipo_name[0] = '\0'; + } + ; + +groupmap: + IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht)); + bzero((char *)&iphte, sizeof(iphte)); + *ipht.iph_name = '\0'; + ipht.iph_unit = IPHASH_GROUPMAP; + ipht.iph_flags = $2; + } + ; + +inout: IPT_IN { $$ = FR_INQUE; } + | IPT_OUT { $$ = FR_OUTQUE; } + ; +role: + IPT_ROLE '=' IPT_IPF { $$ = IPL_LOGIPF; } + | IPT_ROLE '=' IPT_NAT { $$ = IPL_LOGNAT; } + | IPT_ROLE '=' IPT_AUTH { $$ = IPL_LOGAUTH; } + | IPT_ROLE '=' IPT_COUNT { $$ = IPL_LOGCOUNT; } + ; + +ipftree: + IPT_TYPE '=' IPT_TREE number start addrlist end + { strncpy(iplo.ipo_name, $4, + sizeof(iplo.ipo_name)); + $$ = $6; + } + ; + +ipfhash: + IPT_TYPE '=' IPT_HASH number hashopts start hashlist end + { strncpy(ipht.iph_name, $4, + sizeof(ipht.iph_name)); + $$ = $7; + } + ; + +ipfgroup: + setgroup hashopts start grouplist end + { iphtent_t *e; + for (e = $4; e != NULL; + e = e->ipe_next) + if (e->ipe_group[0] == '\0') + strncpy(e->ipe_group, + $1, + FR_GROUPLEN); + $$ = $4; + } + | hashopts start setgrouplist end { $$ = $3; } + ; + +number: IPT_NUM '=' YY_NUMBER { sprintf(poolname, "%u", $3); + $$ = poolname; + } + | IPT_NAME '=' YY_STR { $$ = $3; } + | { $$ = ""; } + ; + +setgroup: + IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1]; + strncpy(tmp, $3, FR_GROUPLEN); + $$ = strdup(tmp); + } + | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1]; + sprintf(tmp, "%u", $3); + $$ = strdup(tmp); + } + ; + +hashopts: + | size + | seed + | size seed + ; + +addrlist: + next { $$ = NULL; } + | range next addrlist { $1->ipn_next = $3; $$ = $1; } + | range next { $$ = $1; } + ; + +grouplist: + next { $$ = NULL; } + | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; } + | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t)); + bcopy((char *)&($1[0]), + (char *)&($$->ipe_addr), + sizeof($$->ipe_addr)); + bcopy((char *)&($1[1]), + (char *)&($$->ipe_mask), + sizeof($$->ipe_mask)); + $$->ipe_next = $3; + } + | groupentry next { $$ = $1; } + | addrmask next { $$ = calloc(1, sizeof(iphtent_t)); + bcopy((char *)&($1[0]), + (char *)&($$->ipe_addr), + sizeof($$->ipe_addr)); + bcopy((char *)&($1[1]), + (char *)&($$->ipe_mask), + sizeof($$->ipe_mask)); + } + ; + +setgrouplist: + next { $$ = NULL; } + | groupentry next { $$ = $1; } + | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; } + ; + +groupentry: + addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t)); + bcopy((char *)&($1[0]), + (char *)&($$->ipe_addr), + sizeof($$->ipe_addr)); + bcopy((char *)&($1[1]), + (char *)&($$->ipe_mask), + sizeof($$->ipe_mask)); + strncpy($$->ipe_group, $3, + FR_GROUPLEN); + free($3); + } + ; + +range: addrmask { $$ = calloc(1, sizeof(*$$)); + $$->ipn_info = 0; + $$->ipn_addr.adf_len = sizeof($$->ipn_addr); + $$->ipn_addr.adf_addr.in4.s_addr = $1[0].s_addr; + $$->ipn_mask.adf_len = sizeof($$->ipn_mask); + $$->ipn_mask.adf_addr.in4.s_addr = $1[1].s_addr; + } + | '!' addrmask { $$ = calloc(1, sizeof(*$$)); + $$->ipn_info = 1; + $$->ipn_addr.adf_len = sizeof($$->ipn_addr); + $$->ipn_addr.adf_addr.in4.s_addr = $2[0].s_addr; + $$->ipn_mask.adf_len = sizeof($$->ipn_mask); + $$->ipn_mask.adf_addr.in4.s_addr = $2[1].s_addr; + } + +hashlist: + next { $$ = NULL; } + | hashentry next { $$ = $1; } + | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; } + ; + +hashentry: + addrmask { $$ = calloc(1, sizeof(iphtent_t)); + bcopy((char *)&($1[0]), + (char *)&($$->ipe_addr), + sizeof($$->ipe_addr)); + bcopy((char *)&($1[1]), + (char *)&($$->ipe_mask), + sizeof($$->ipe_mask)); + } + ; + +addrmask: + ipaddr '/' mask { $$[0] = $1; $$[1].s_addr = $3.s_addr; + yyexpectaddr = 0; + } + | ipaddr { $$[0] = $1; $$[1].s_addr = 0xffffffff; + yyexpectaddr = 0; + } + ; + +ipaddr: ipv4 { $$ = $1; } + | YY_NUMBER { $$.s_addr = htonl($1); } + | YY_STR { if (gethost($1, &($$.s_addr)) == -1) + yyerror("Unknown hostname"); + } + ; + +mask: YY_NUMBER { ntomask(4, $1, (u_32_t *)&$$.s_addr); } + | ipv4 { $$ = $1; } + ; + +start: '{' { yyexpectaddr = 1; } + ; + +end: '}' { yyexpectaddr = 0; } + ; + +next: ';' { yyexpectaddr = 1; } + ; + +size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; } + ; + +seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; } + ; + +ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; + $$.s_addr = htonl($$.s_addr); + } + ; +%% +static wordtab_t yywords[] = { + { "auth", IPT_AUTH }, + { "count", IPT_COUNT }, + { "group", IPT_GROUP }, + { "group-map", IPT_GROUPMAP }, + { "hash", IPT_HASH }, + { "in", IPT_IN }, + { "ipf", IPT_IPF }, + { "name", IPT_NAME }, + { "nat", IPT_NAT }, + { "number", IPT_NUM }, + { "out", IPT_OUT }, + { "role", IPT_ROLE }, + { "seed", IPT_SEED }, + { "size", IPT_SIZE }, + { "table", IPT_TABLE }, + { "tree", IPT_TREE }, + { "type", IPT_TYPE }, + { NULL, 0 } +}; + + +int ippool_parsefile(fd, filename, iocfunc) +int fd; +char *filename; +ioctlfunc_t iocfunc; +{ + FILE *fp = NULL; + char *s; + + yylineNum = 1; + (void) yysettab(yywords); + + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + if (strcmp(filename, "-")) { + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "fopen(%s) failed: %s\n", filename, + STRERROR(errno)); + return -1; + } + } else + fp = stdin; + + while (ippool_parsesome(fd, fp, iocfunc) == 1) + ; + if (fp != NULL) + fclose(fp); + return 0; +} + + +int ippool_parsesome(fd, fp, iocfunc) +int fd; +FILE *fp; +ioctlfunc_t iocfunc; +{ + char *s; + int i; + + poolioctl = iocfunc; + + if (feof(fp)) + return 0; + i = fgetc(fp); + if (i == EOF) + return 0; + if (ungetc(i, fp) == EOF) + return 0; + if (feof(fp)) + return 0; + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + yyin = fp; + yyparse(); + return 1; +} diff --git a/contrib/ipfilter/tools/ipscan_y.y b/contrib/ipfilter/tools/ipscan_y.y new file mode 100644 index 0000000..64cbb6d --- /dev/null +++ b/contrib/ipfilter/tools/ipscan_y.y @@ -0,0 +1,565 @@ +/* $NetBSD$ */ + +%{ +#include <sys/types.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "opts.h" +#include "kmem.h" +#include "ipscan_l.h" +#include "netinet/ip_scan.h" + +#define YYDEBUG 1 + +extern char *optarg; +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; +extern void printbuf __P((char *, int, int)); + + +void printent __P((ipscan_t *)); +void showlist __P((void)); +int getportnum __P((char *)); +struct in_addr gethostip __P((char *)); +struct in_addr combine __P((int, int, int, int)); +char **makepair __P((char *, char *)); +void addtag __P((char *, char **, char **, struct action *)); +int cram __P((char *, char *)); +void usage __P((char *)); +int main __P((int, char **)); + +int opts = 0; +int fd = -1; + + +%} + +%union { + char *str; + char **astr; + u_32_t num; + struct in_addr ipa; + struct action act; + union i6addr ip6; +} + +%type <str> tag +%type <act> action redirect result +%type <ipa> ipaddr +%type <num> portnum +%type <astr> matchup onehalf twohalves + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token <ip6> YY_IPV6 +%token IPSL_START IPSL_STARTGROUP IPSL_CONTENT + +%token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE + +%% +file: line ';' + | assign ';' + | file line ';' + | file assign ';' + | YY_COMMENT + ; + +line: IPSL_START dline + | IPSL_STARTGROUP gline + | IPSL_CONTENT oline + ; + +dline: cline { resetlexer(); } + | sline { resetlexer(); } + | csline { resetlexer(); } + ; + +gline: YY_STR ':' glist '=' action + ; + +oline: cline + | sline + | csline + ; + +assign: YY_STR assigning YY_STR + { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); } + ; + +sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); } + ; + +csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); } + ; + +glist: YY_STR + | glist ',' YY_STR + ; + +tag: YY_STR { $$ = $1; } + ; + +matchup: + onehalf { $$ = $1; } + | twohalves { $$ = $1; } + ; + +action: result { $$.act_val = $1.act_val; + $$.act_ip = $1.act_ip; + $$.act_port = $1.act_port; } + | result IPSL_ELSE result { $$.act_val = $1.act_val; + $$.act_else = $3.act_val; + if ($1.act_val == IPSL_REDIRECT) { + $$.act_ip = $1.act_ip; + $$.act_port = $1.act_port; + } + if ($3.act_val == IPSL_REDIRECT) { + $$.act_eip = $3.act_eip; + $$.act_eport = $3.act_eport; + } + } + +result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; } + | IPSL_TRACK { $$.act_val = IPSL_TRACK; } + | redirect { $$.act_val = IPSL_REDIRECT; + $$.act_ip = $1.act_ip; + $$.act_port = $1.act_port; } + ; + +onehalf: + '(' YY_STR ')' { $$ = makepair($2, NULL); } + ; + +twohalves: + '(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); } + ; + +redirect: + IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3; + $$.act_port = 0; } + | IPSL_REDIRECT '(' ipaddr ',' portnum ')' + { $$.act_ip = $3; + $$.act_port = $5; } + ; + + +ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { $$ = combine($1,$3,$5,$7); } + | YY_STR { $$ = gethostip($1); + free($1); + } + ; + +portnum: + YY_NUMBER { $$ = htons($1); } + | YY_STR { $$ = getportnum($1); + free($1); + } + ; + +%% + + +static struct wordtab yywords[] = { + { "close", IPSL_CLOSE }, + { "content", IPSL_CONTENT }, + { "else", IPSL_ELSE }, + { "start-group", IPSL_STARTGROUP }, + { "redirect", IPSL_REDIRECT }, + { "start", IPSL_START }, + { "track", IPSL_TRACK }, + { NULL, 0 } +}; + + +int cram(dst, src) +char *dst; +char *src; +{ + char c, *s, *t, *u; + int i, j, k; + + c = *src; + s = src + 1; + t = strchr(s, c); + *t = '\0'; + for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) { + c = *s++; + if (c == '\\') { + if (s >= t) + break; + j = k = 0; + do { + c = *s++; + if (j && (!ISDIGIT(c) || (c > '7') || + (k >= 248))) { + *u++ = k, i++; + j = k = 0; + s--; + break; + } + i++; + + if (ISALPHA(c) || (c > '7')) { + switch (c) + { + case 'n' : + *u++ = '\n'; + break; + case 'r' : + *u++ = '\r'; + break; + case 't' : + *u++ = '\t'; + break; + default : + *u++ = c; + break; + } + } else if (ISDIGIT(c)) { + j = 1; + k <<= 3; + k |= (c - '0'); + i--; + } else + *u++ = c; + } while ((i <= ISC_TLEN) && (s <= t) && (j > 0)); + } else + *u++ = c, i++; + } + return i; +} + + +void printent(isc) +ipscan_t *isc; +{ + char buf[ISC_TLEN+1]; + u_char *u; + int i, j; + + buf[ISC_TLEN] = '\0'; + bcopy(isc->ipsc_ctxt, buf, ISC_TLEN); + printf("%s : (\"", isc->ipsc_tag); + printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0); + + bcopy(isc->ipsc_cmsk, buf, ISC_TLEN); + printf("\", \"%s\"), (\"", buf); + + printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0); + + bcopy(isc->ipsc_smsk, buf, ISC_TLEN); + printf("\", \"%s\") = ", buf); + + switch (isc->ipsc_action) + { + case ISC_A_TRACK : + printf("track"); + break; + case ISC_A_REDIRECT : + printf("redirect"); + printf("(%s", inet_ntoa(isc->ipsc_ip)); + if (isc->ipsc_port) + printf(",%d", isc->ipsc_port); + printf(")"); + break; + case ISC_A_CLOSE : + printf("close"); + break; + default : + break; + } + + if (isc->ipsc_else != ISC_A_NONE) { + printf(" else "); + switch (isc->ipsc_else) + { + case ISC_A_TRACK : + printf("track"); + break; + case ISC_A_REDIRECT : + printf("redirect"); + printf("(%s", inet_ntoa(isc->ipsc_eip)); + if (isc->ipsc_eport) + printf(",%d", isc->ipsc_eport); + printf(")"); + break; + case ISC_A_CLOSE : + printf("close"); + break; + default : + break; + } + } + printf("\n"); + + if (opts & OPT_DEBUG) { + for (u = (u_char *)isc, i = sizeof(*isc); i; ) { + printf("#"); + for (j = 32; (j > 0) && (i > 0); j--, i--) + printf("%s%02x", (j & 7) ? "" : " ", *u++); + printf("\n"); + } + } + if (opts & OPT_VERBOSE) { + printf("# hits %d active %d fref %d sref %d\n", + isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref, + isc->ipsc_sref); + } +} + + +void addtag(tstr, cp, sp, act) +char *tstr; +char **cp, **sp; +struct action *act; +{ + ipscan_t isc, *iscp; + + bzero((char *)&isc, sizeof(isc)); + + strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag)); + isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0'; + + if (cp) { + isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]); + if (cp[1]) { + if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) { + fprintf(stderr, + "client text/mask strings different length\n"); + return; + } + } + } + + if (sp) { + isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]); + if (sp[1]) { + if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) { + fprintf(stderr, + "server text/mask strings different length\n"); + return; + } + } + } + + if (act->act_val == IPSL_CLOSE) { + isc.ipsc_action = ISC_A_CLOSE; + } else if (act->act_val == IPSL_TRACK) { + isc.ipsc_action = ISC_A_TRACK; + } else if (act->act_val == IPSL_REDIRECT) { + isc.ipsc_action = ISC_A_REDIRECT; + isc.ipsc_ip = act->act_ip; + isc.ipsc_port = act->act_port; + fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); + } + + if (act->act_else == IPSL_CLOSE) { + isc.ipsc_else = ISC_A_CLOSE; + } else if (act->act_else == IPSL_TRACK) { + isc.ipsc_else = ISC_A_TRACK; + } else if (act->act_else == IPSL_REDIRECT) { + isc.ipsc_else = ISC_A_REDIRECT; + isc.ipsc_eip = act->act_eip; + isc.ipsc_eport = act->act_eport; + fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); + } + + if (!(opts & OPT_DONOTHING)) { + iscp = &isc; + if (opts & OPT_REMOVE) { + if (ioctl(fd, SIOCRMSCA, &iscp) == -1) + perror("SIOCADSCA"); + } else { + if (ioctl(fd, SIOCADSCA, &iscp) == -1) + perror("SIOCADSCA"); + } + } + + if (opts & OPT_VERBOSE) + printent(&isc); +} + + +char **makepair(s1, s2) +char *s1, *s2; +{ + char **a; + + a = malloc(sizeof(char *) * 2); + a[0] = s1; + a[1] = s2; + return a; +} + + +struct in_addr combine(a1, a2, a3, a4) +int a1, a2, a3, a4; +{ + struct in_addr in; + + a1 &= 0xff; + in.s_addr = a1 << 24; + a2 &= 0xff; + in.s_addr |= (a2 << 16); + a3 &= 0xff; + in.s_addr |= (a3 << 8); + a4 &= 0xff; + in.s_addr |= a4; + in.s_addr = htonl(in.s_addr); + return in; +} + + +struct in_addr gethostip(host) +char *host; +{ + struct hostent *hp; + struct in_addr in; + + in.s_addr = 0; + + hp = gethostbyname(host); + if (!hp) + return in; + bcopy(hp->h_addr, (char *)&in, sizeof(in)); + return in; +} + + +int getportnum(port) +char *port; +{ + struct servent *s; + + s = getservbyname(port, "tcp"); + if (s == NULL) + return -1; + return s->s_port; +} + + +void showlist() +{ + ipscanstat_t ipsc, *ipscp = &ipsc; + ipscan_t isc; + + if (ioctl(fd, SIOCGSCST, &ipscp) == -1) + perror("ioctl(SIOCGSCST)"); + else if (opts & OPT_SHOWLIST) { + while (ipsc.iscs_list != NULL) { + if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list, + sizeof(isc)) == -1) { + perror("kmemcpy"); + break; + } else { + printent(&isc); + ipsc.iscs_list = isc.ipsc_next; + } + } + } else { + printf("scan entries loaded\t%d\n", ipsc.iscs_entries); + printf("scan entries matches\t%ld\n", ipsc.iscs_acted); + printf("negative matches\t%ld\n", ipsc.iscs_else); + } +} + + +void usage(prog) +char *prog; +{ + fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog); + fprintf(stderr, "\t%s [-dlv]\n", prog); + exit(1); +} + + +int main(argc, argv) +int argc; +char *argv[]; +{ + FILE *fp = NULL; + int c; + + (void) yysettab(yywords); + + if (argc < 2) + usage(argv[0]); + + while ((c = getopt(argc, argv, "df:lnrsv")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + yydebug++; + break; + case 'f' : + if (!strcmp(optarg, "-")) + fp = stdin; + else { + fp = fopen(optarg, "r"); + if (!fp) { + perror("open"); + exit(1); + } + } + yyin = fp; + break; + case 'l' : + opts |= OPT_SHOWLIST; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'r' : + opts |= OPT_REMOVE; + break; + case 's' : + opts |= OPT_STAT; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (!(opts & OPT_DONOTHING)) { + fd = open(IPL_SCAN, O_RDWR); + if (fd == -1) { + perror("open(IPL_SCAN)"); + exit(1); + } + } + + if (fp != NULL) { + yylineNum = 1; + + while (!feof(fp)) + yyparse(); + fclose(fp); + exit(0); + } + + if (opts & (OPT_SHOWLIST|OPT_STAT)) { + showlist(); + exit(0); + } + exit(1); +} diff --git a/contrib/ipfilter/tools/ipsyncm.c b/contrib/ipfilter/tools/ipsyncm.c new file mode 100644 index 0000000..20cc25e --- /dev/null +++ b/contrib/ipfilter/tools/ipsyncm.c @@ -0,0 +1,253 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipsyncm.c,v 1.4.2.2 2005/01/08 14:31:46 darrenr Exp"; +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <strings.h> +#include <syslog.h> +#include <signal.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#include "netinet/ip_sync.h" + + +int main __P((int, char *[])); + +int terminate = 0; + +void usage(const char *progname) { + fprintf(stderr, "Usage: %s <destination IP> <destination port>\n", progname); +} + +static void handleterm(int sig) +{ + terminate = sig; +} + + +/* should be large enough to hold header + any datatype */ +#define BUFFERLEN 1400 + +int main(argc, argv) +int argc; +char *argv[]; +{ + struct sockaddr_in sin; + char buff[BUFFERLEN]; + synclogent_t *sl; + syncupdent_t *su; + int nfd = -1, lfd = -1, n1, n2, n3, len; + int inbuf; + u_32_t magic; + synchdr_t *sh; + char *progname; + + progname = strrchr(argv[0], '/'); + if (progname) { + progname++; + } else { + progname = argv[0]; + } + + + if (argc < 2) { + usage(progname); + exit(1); + } + +#if 0 + signal(SIGHUP, handleterm); + signal(SIGINT, handleterm); + signal(SIGTERM, handleterm); +#endif + + openlog(progname, LOG_PID, LOG_SECURITY); + + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(argv[1]); + if (argc > 2) + sin.sin_port = htons(atoi(argv[2])); + else + sin.sin_port = htons(43434); + + while (1) { + + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + lfd = open(IPSYNC_NAME, O_RDONLY); + if (lfd == -1) { + syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); + goto tryagain; + } + + nfd = socket(AF_INET, SOCK_DGRAM, 0); + if (nfd == -1) { + syslog(LOG_ERR, "Socket :%m"); + goto tryagain; + } + + if (connect(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + syslog(LOG_ERR, "Connect: %m"); + goto tryagain; + } + + syslog(LOG_INFO, "Established connection to %s", + inet_ntoa(sin.sin_addr)); + + inbuf = 0; + while (1) { + + n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf); + + printf("header : %d bytes read (header = %d bytes)\n", + n1, sizeof(*sh)); + + if (n1 < 0) { + syslog(LOG_ERR, "Read error (header): %m"); + goto tryagain; + } + + if (n1 == 0) { + /* XXX can this happen??? */ + syslog(LOG_ERR, + "Read error (header) : No data"); + sleep(1); + continue; + } + + inbuf += n1; + +moreinbuf: + if (inbuf < sizeof(*sh)) { + continue; /* need more data */ + } + + sh = (synchdr_t *)buff; + len = ntohl(sh->sm_len); + magic = ntohl(sh->sm_magic); + + if (magic != SYNHDRMAGIC) { + syslog(LOG_ERR, + "Invalid header magic %x", magic); + goto tryagain; + } + +#define IPSYNC_DEBUG +#ifdef IPSYNC_DEBUG + printf("v:%d p:%d len:%d magic:%x", sh->sm_v, + sh->sm_p, len, magic); + + if (sh->sm_cmd == SMC_CREATE) + printf(" cmd:CREATE"); + else if (sh->sm_cmd == SMC_UPDATE) + printf(" cmd:UPDATE"); + else + printf(" cmd:Unknown(%d)", sh->sm_cmd); + + if (sh->sm_table == SMC_NAT) + printf(" table:NAT"); + else if (sh->sm_table == SMC_STATE) + printf(" table:STATE"); + else + printf(" table:Unknown(%d)", sh->sm_table); + + printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num)); +#endif + + if (inbuf < sizeof(*sh) + len) { + continue; /* need more data */ + goto tryagain; + } + +#ifdef IPSYNC_DEBUG + if (sh->sm_cmd == SMC_CREATE) { + sl = (synclogent_t *)buff; + + } else if (sh->sm_cmd == SMC_UPDATE) { + su = (syncupdent_t *)buff; + if (sh->sm_p == IPPROTO_TCP) { + printf(" TCP Update: age %lu state %d/%d\n", + su->sup_tcp.stu_age, + su->sup_tcp.stu_state[0], + su->sup_tcp.stu_state[1]); + } + } else { + printf("Unknown command\n"); + } +#endif + + n2 = sizeof(*sh) + len; + n3 = write(nfd, buff, n2); + if (n3 <= 0) { + syslog(LOG_ERR, "Write error: %m"); + goto tryagain; + } + + + if (n3 != n2) { + syslog(LOG_ERR, "Incomplete write (%d/%d)", + n3, n2); + goto tryagain; + } + + /* signal received? */ + if (terminate) + break; + + /* move buffer to the front,we might need to make + * this more efficient, by using a rolling pointer + * over the buffer and only copying it, when + * we are reaching the end + */ + inbuf -= n2; + if (inbuf) { + bcopy(buff+n2, buff, inbuf); + printf("More data in buffer\n"); + goto moreinbuf; + } + } + + if (terminate) + break; +tryagain: + sleep(1); + } + + + /* terminate */ + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + syslog(LOG_ERR, "signal %d received, exiting...", terminate); + + exit(1); +} + diff --git a/contrib/ipfilter/tools/ipsyncs.c b/contrib/ipfilter/tools/ipsyncs.c new file mode 100644 index 0000000..a189a9b --- /dev/null +++ b/contrib/ipfilter/tools/ipsyncs.c @@ -0,0 +1,272 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipsyncs.c,v 1.5.2.1 2004/10/31 18:46:44 darrenr Exp"; +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <syslog.h> +#include <errno.h> +#include <signal.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_state.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_sync.h" + +int main __P((int, char *[])); + +int terminate = 0; + +void usage(const char *progname) { + fprintf(stderr, + "Usage: %s <destination IP> <destination port> [remote IP]\n", + progname); +} + +static void handleterm(int sig) +{ + terminate = sig; + +} + +#define BUFFERLEN 1400 + +int main(argc, argv) +int argc; +char *argv[]; +{ + int nfd = -1 , lfd = -1; + int n1, n2, n3, magic, len, inbuf; + struct sockaddr_in sin; + struct sockaddr_in in; + char buff[BUFFERLEN]; + synclogent_t *sl; + syncupdent_t *su; + synchdr_t *sh; + char *progname; + + progname = strrchr(argv[0], '/'); + if (progname) { + progname++; + } else { + progname = argv[0]; + } + + if (argc < 2) { + usage(progname); + exit(1); + } + +#if 0 + signal(SIGHUP, handleterm); + signal(SIGINT, handleterm); + signal(SIGTERM, handleterm); +#endif + + openlog(progname, LOG_PID, LOG_SECURITY); + + lfd = open(IPSYNC_NAME, O_WRONLY); + if (lfd == -1) { + syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); + exit(1); + } + + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + if (argc > 1) + sin.sin_addr.s_addr = inet_addr(argv[1]); + if (argc > 2) + sin.sin_port = htons(atoi(argv[2])); + else + sin.sin_port = htons(43434); + if (argc > 3) + in.sin_addr.s_addr = inet_addr(argv[3]); + else + in.sin_addr.s_addr = 0; + in.sin_port = 0; + + while(1) { + + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + lfd = open(IPSYNC_NAME, O_WRONLY); + if (lfd == -1) { + syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); + goto tryagain; + } + + nfd = socket(AF_INET, SOCK_DGRAM, 0); + if (nfd == -1) { + syslog(LOG_ERR, "Socket :%m"); + goto tryagain; + } + + n1 = 1; + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1)); + + if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + syslog(LOG_ERR, "Bind: %m"); + goto tryagain; + } + + syslog(LOG_INFO, "Established connection to %s", + inet_ntoa(sin.sin_addr)); + + inbuf = 0; + while (1) { + + + /* + * XXX currently we do not check the source address + * of a datagram, this can be a security risk + */ + n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf); + + printf("header : %d bytes read (header = %d bytes)\n", + n1, sizeof(*sh)); + + if (n1 < 0) { + syslog(LOG_ERR, "Read error (header): %m"); + goto tryagain; + } + + if (n1 == 0) { + /* XXX can this happen??? */ + syslog(LOG_ERR, + "Read error (header) : No data"); + sleep(1); + continue; + } + + inbuf += n1; + +moreinbuf: + if (inbuf < sizeof(*sh)) { + continue; /* need more data */ + } + + sh = (synchdr_t *)buff; + len = ntohl(sh->sm_len); + magic = ntohl(sh->sm_magic); + + if (magic != SYNHDRMAGIC) { + syslog(LOG_ERR, "Invalid header magic %x", + magic); + goto tryagain; + } + +#define IPSYNC_DEBUG +#ifdef IPSYNC_DEBUG + printf("v:%d p:%d len:%d magic:%x", sh->sm_v, + sh->sm_p, len, magic); + + if (sh->sm_cmd == SMC_CREATE) + printf(" cmd:CREATE"); + else if (sh->sm_cmd == SMC_UPDATE) + printf(" cmd:UPDATE"); + else + printf(" cmd:Unknown(%d)", sh->sm_cmd); + + if (sh->sm_table == SMC_NAT) + printf(" table:NAT"); + else if (sh->sm_table == SMC_STATE) + printf(" table:STATE"); + else + printf(" table:Unknown(%d)", sh->sm_table); + + printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num)); +#endif + + if (inbuf < sizeof(*sh) + len) { + continue; /* need more data */ + goto tryagain; + } + +#ifdef IPSYNC_DEBUG + if (sh->sm_cmd == SMC_CREATE) { + sl = (synclogent_t *)buff; + + } else if (sh->sm_cmd == SMC_UPDATE) { + su = (syncupdent_t *)buff; + if (sh->sm_p == IPPROTO_TCP) { + printf(" TCP Update: age %lu state %d/%d\n", + su->sup_tcp.stu_age, + su->sup_tcp.stu_state[0], + su->sup_tcp.stu_state[1]); + } + } else { + printf("Unknown command\n"); + } +#endif + + n2 = sizeof(*sh) + len; + n3 = write(lfd, buff, n2); + if (n3 <= 0) { + syslog(LOG_ERR, "Write error: %m"); + goto tryagain; + } + + + if (n3 != n2) { + syslog(LOG_ERR, "Incomplete write (%d/%d)", + n3, n2); + goto tryagain; + } + + /* signal received? */ + if (terminate) + break; + + /* move buffer to the front,we might need to make + * this more efficient, by using a rolling pointer + * over the buffer and only copying it, when + * we are reaching the end + */ + inbuf -= n2; + if (inbuf) { + bcopy(buff+n2, buff, inbuf); + printf("More data in buffer\n"); + goto moreinbuf; + } + } + + if (terminate) + break; +tryagain: + sleep(1); + } + + + /* terminate */ + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + syslog(LOG_ERR, "signal %d received, exiting...", terminate); + + exit(1); +} diff --git a/contrib/ipfilter/tools/lex_var.h b/contrib/ipfilter/tools/lex_var.h new file mode 100644 index 0000000..33fba25 --- /dev/null +++ b/contrib/ipfilter/tools/lex_var.h @@ -0,0 +1,55 @@ +/* $NetBSD$ */ + + +extern long string_start; +extern long string_end; +extern char *string_val; +extern long pos; + +#define YY_INPUT(buf, result, max_size) \ + if (pos >= string_start && pos <= string_end) { \ + buf[0] = string_val[pos - string_start]; \ + pos++; \ + result = 1; \ + } else if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < 1 && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + pos++; \ + } \ + else if ( ((result = fread( buf, 1, 1, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); + +#ifdef input +# undef input +# define input() (((pos >= string_start) && (pos < string_end)) ? \ + yysptr = yysbuf, string_val[pos++ - string_start] : \ + ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \ + getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \ + yytchar) == EOF ? (pos++, 0) : (pos++, yytchar)) +#endif + +#ifdef lex_input +# undef lex_input +# define lex_input() (((pos >= string_start) && (pos < string_end)) ? \ + yysptr = yysbuf, string_val[pos++ - string_start] : \ + ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \ + getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \ + yytchar) == EOF ? (pos++, 0) : (pos++, yytchar)) +#endif + +#ifdef unput +# undef unput +# define unput(c) { if (pos > 0) pos--; \ + yytchar = (c); if (yytchar == '\n') yylineno--; \ + *yysptr++ = yytchar; } +#endif + diff --git a/contrib/ipfilter/tools/lexer.c b/contrib/ipfilter/tools/lexer.c new file mode 100644 index 0000000..f6fccfb --- /dev/null +++ b/contrib/ipfilter/tools/lexer.c @@ -0,0 +1,632 @@ +/* $NetBSD$ */ + +/* + * Copyright (C) 2003 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include <ctype.h> +#include "ipf.h" +#ifdef IPFILTER_SCAN +# include "netinet/ip_scan.h" +#endif +#include <sys/ioctl.h> +#include <syslog.h> +#ifdef TEST_LEXER +# define NO_YACC +union { + int num; + char *str; + struct in_addr ipa; + i6addr_t ip6; +} yylval; +#endif +#include "lexer.h" +#include "y.tab.h" + +FILE *yyin; + +#define ishex(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \ + ((c) >= 'A' && (c) <= 'F')) +#define TOOLONG -3 + +extern int string_start; +extern int string_end; +extern char *string_val; +extern int pos; +extern int yydebug; + +char *yystr = NULL; +int yytext[YYBUFSIZ+1]; +int yylineNum = 1; +int yypos = 0; +int yylast = -1; +int yyexpectaddr = 0; +int yybreakondot = 0; +int yyvarnext = 0; +int yytokentype = 0; +wordtab_t *yywordtab = NULL; +int yysavedepth = 0; +wordtab_t *yysavewords[30]; + + +static wordtab_t *yyfindkey __P((char *)); +static int yygetc __P((void)); +static void yyunputc __P((int)); +static int yyswallow __P((int)); +static char *yytexttostr __P((int, int)); +static void yystrtotext __P((char *)); + +static int yygetc() +{ + int c; + + if (yypos < yylast) { + c = yytext[yypos++]; + if (c == '\n') + yylineNum++; + return c; + } + + if (yypos == YYBUFSIZ) + return TOOLONG; + + if (pos >= string_start && pos <= string_end) { + c = string_val[pos - string_start]; + yypos++; + } else { + c = fgetc(yyin); + } + if (c == '\n') + yylineNum++; + yytext[yypos++] = c; + yylast = yypos; + yytext[yypos] = '\0'; + + return c; +} + + +static void yyunputc(c) +int c; +{ + if (c == '\n') + yylineNum--; + yytext[--yypos] = c; +} + + +static int yyswallow(last) +int last; +{ + int c; + + while (((c = yygetc()) > '\0') && (c != last)) + ; + + if (c != EOF) + yyunputc(c); + if (c == last) + return 0; + return -1; +} + + +static void yystrtotext(str) +char *str; +{ + int len; + char *s; + + len = strlen(str); + if (len > YYBUFSIZ) + len = YYBUFSIZ; + + for (s = str; *s != '\0' && len > 0; s++, len--) + yytext[yylast++] = *s; + yytext[yylast] = '\0'; +} + + +static char *yytexttostr(offset, max) +int offset, max; +{ + char *str; + int i; + + if ((yytext[offset] == '\'' || yytext[offset] == '"') && + (yytext[offset] == yytext[offset + max - 1])) { + offset++; + max--; + } + + if (max > yylast) + max = yylast; + str = malloc(max + 1); + if (str != NULL) { + for (i = offset; i < max; i++) + str[i - offset] = (char)(yytext[i] & 0xff); + str[i - offset] = '\0'; + } + return str; +} + + +int yylex() +{ + int c, n, isbuilding, rval, lnext, nokey = 0; + char *name; + + isbuilding = 0; + lnext = 0; + rval = 0; + + if (yystr != NULL) { + free(yystr); + yystr = NULL; + } + +nextchar: + c = yygetc(); + + switch (c) + { + case '\n' : + case '\t' : + case '\r' : + case ' ' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + if (yylast > yypos) { + bcopy(yytext + yypos, yytext, + sizeof(yytext[0]) * (yylast - yypos + 1)); + } + yylast -= yypos; + yypos = 0; + lnext = 0; + nokey = 0; + goto nextchar; + + case '\\' : + if (lnext == 0) { + lnext = 1; + if (yylast == yypos) { + yylast--; + yypos--; + } else + yypos--; + if (yypos == 0) + nokey = 1; + goto nextchar; + } + break; + } + + if (lnext == 1) { + lnext = 0; + if ((isbuilding == 0) && !ISALNUM(c)) { + return c; + } + goto nextchar; + } + + switch (c) + { + case '#' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + yyswallow('\n'); + rval = YY_COMMENT; + goto nextchar; + + case '$' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(); + if (n == '{') { + if (yyswallow('}') == -1) { + rval = -2; + goto done; + } + (void) yygetc(); + } else { + if (!ISALPHA(n)) { + yyunputc(n); + break; + } + do { + n = yygetc(); + } while (ISALPHA(n) || ISDIGIT(n) || n == '_'); + yyunputc(n); + } + + name = yytexttostr(1, yypos); /* skip $ */ + + if (name != NULL) { + string_val = get_variable(name, NULL, yylineNum); + free(name); + if (string_val != NULL) { + name = yytexttostr(yypos, yylast); + if (name != NULL) { + yypos = 0; + yylast = 0; + yystrtotext(string_val); + yystrtotext(name); + free(string_val); + free(name); + goto nextchar; + } + free(string_val); + } + } + break; + + case '\'': + case '"' : + if (isbuilding == 1) { + goto done; + } + do { + n = yygetc(); + if (n == EOF || n == TOOLONG) { + rval = -2; + goto done; + } + if (n == '\n') { + yyunputc(' '); + yypos++; + } + } while (n != c); + yyunputc(n); + break; + + case EOF : + yylineNum = 1; + yypos = 0; + yylast = -1; + yyexpectaddr = 0; + yybreakondot = 0; + yyvarnext = 0; + yytokentype = 0; + return 0; + } + + if (strchr("=,/;{}()@", c) != NULL) { + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + rval = c; + goto done; + } else if (c == '.') { + if (isbuilding == 0) { + rval = c; + goto done; + } + if (yybreakondot != 0) { + yyunputc(c); + goto done; + } + } + + switch (c) + { + case '-' : + if (yyexpectaddr) + break; + if (isbuilding == 1) + break; + n = yygetc(); + if (n == '>') { + isbuilding = 1; + goto done; + } + yyunputc(n); + rval = '-'; + goto done; + + case '!' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(); + if (n == '=') { + rval = YY_CMP_NE; + goto done; + } + yyunputc(n); + rval = '!'; + goto done; + + case '<' : + if (yyexpectaddr) + break; + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(); + if (n == '=') { + rval = YY_CMP_LE; + goto done; + } + if (n == '>') { + rval = YY_RANGE_OUT; + goto done; + } + yyunputc(n); + rval = YY_CMP_LT; + goto done; + + case '>' : + if (yyexpectaddr) + break; + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(); + if (n == '=') { + rval = YY_CMP_GE; + goto done; + } + if (n == '<') { + rval = YY_RANGE_IN; + goto done; + } + yyunputc(n); + rval = YY_CMP_GT; + goto done; + } + + /* + * Now for the reason this is here...IPv6 address parsing. + * The longest string we can expect is of this form: + * 0000:0000:0000:0000:0000:0000:000.000.000.000 + * not: + * 0000:0000:0000:0000:0000:0000:0000:0000 + */ +#ifdef USE_INET6 + if (yyexpectaddr == 1 && isbuilding == 0 && (ishex(c) || c == ':')) { + char ipv6buf[45 + 1], *s, oc; + int start; + + start = yypos; + s = ipv6buf; + oc = c; + + /* + * Perhaps we should implement stricter controls on what we + * swallow up here, but surely it would just be duplicating + * the code in inet_pton() anyway. + */ + do { + *s++ = c; + c = yygetc(); + } while ((ishex(c) || c == ':' || c == '.') && + (s - ipv6buf < 46)); + yyunputc(c); + *s = '\0'; + + if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) { + rval = YY_IPV6; + yyexpectaddr = 0; + goto done; + } + yypos = start; + c = oc; + } +#endif + + if (c == ':') { + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + rval = ':'; + goto done; + } + + if (isbuilding == 0 && c == '0') { + n = yygetc(); + if (n == 'x') { + do { + n = yygetc(); + } while (ishex(n)); + yyunputc(n); + rval = YY_HEX; + goto done; + } + yyunputc(n); + } + + /* + * No negative numbers with leading - sign.. + */ + if (isbuilding == 0 && ISDIGIT(c)) { + do { + n = yygetc(); + } while (ISDIGIT(n)); + yyunputc(n); + rval = YY_NUMBER; + goto done; + } + + isbuilding = 1; + goto nextchar; + +done: + yystr = yytexttostr(0, yypos); + + if (isbuilding == 1) { + wordtab_t *w; + + w = NULL; + isbuilding = 0; + + if ((yyvarnext == 0) && (nokey == 0)) { + w = yyfindkey(yystr); + if (w == NULL && yywordtab != NULL) { + yyresetdict(); + w = yyfindkey(yystr); + } + } else + yyvarnext = 0; + if (w != NULL) + rval = w->w_value; + else + rval = YY_STR; + } + + if (rval == YY_STR && yysavedepth > 0) + yyresetdict(); + + yytokentype = rval; + + if (yydebug) + printf("lexed(%s) [%d,%d,%d] => %d\n", yystr, string_start, + string_end, pos, rval); + + switch (rval) + { + case YY_NUMBER : + sscanf(yystr, "%u", &yylval.num); + break; + + case YY_HEX : + sscanf(yystr, "0x%x", (u_int *)&yylval.num); + break; + + case YY_STR : + yylval.str = strdup(yystr); + break; + + default : + break; + } + + if (yylast > 0) { + bcopy(yytext + yypos, yytext, + sizeof(yytext[0]) * (yylast - yypos + 1)); + yylast -= yypos; + yypos = 0; + } + + return rval; +} + + +static wordtab_t *yyfindkey(key) +char *key; +{ + wordtab_t *w; + + if (yywordtab == NULL) + return NULL; + + for (w = yywordtab; w->w_word != 0; w++) + if (strcasecmp(key, w->w_word) == 0) + return w; + return NULL; +} + + +char *yykeytostr(num) +int num; +{ + wordtab_t *w; + + if (yywordtab == NULL) + return "<unknown>"; + + for (w = yywordtab; w->w_word; w++) + if (w->w_value == num) + return w->w_word; + return "<unknown>"; +} + + +wordtab_t *yysettab(words) +wordtab_t *words; +{ + wordtab_t *save; + + save = yywordtab; + yywordtab = words; + return save; +} + + +void yyerror(msg) +char *msg; +{ + char *txt, letter[2]; + int freetxt = 0; + + if (yytokentype < 256) { + letter[0] = yytokentype; + letter[1] = '\0'; + txt = letter; + } else if (yytokentype == YY_STR || yytokentype == YY_HEX || + yytokentype == YY_NUMBER) { + if (yystr == NULL) { + txt = yytexttostr(yypos, YYBUFSIZ); + freetxt = 1; + } else + txt = yystr; + } else { + txt = yykeytostr(yytokentype); + } + fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); + if (freetxt == 1) + free(txt); + exit(1); +} + + +void yysetdict(newdict) +wordtab_t *newdict; +{ + if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { + fprintf(stderr, "%d: at maximum dictionary depth\n", + yylineNum); + return; + } + + yysavewords[yysavedepth++] = yysettab(newdict); + if (yydebug) + printf("yysavedepth++ => %d\n", yysavedepth); +} + +void yyresetdict() +{ + if (yysavedepth > 0) { + yysettab(yysavewords[--yysavedepth]); + if (yydebug) + printf("yysavedepth-- => %d\n", yysavedepth); + } +} + + + +#ifdef TEST_LEXER +int main(argc, argv) +int argc; +char *argv[]; +{ + int n; + + yyin = stdin; + + while ((n = yylex()) != 0) + printf("%d.n = %d [%s] %d %d\n", + yylineNum, n, yystr, yypos, yylast); +} +#endif diff --git a/contrib/ipfilter/tools/lexer.h b/contrib/ipfilter/tools/lexer.h new file mode 100644 index 0000000..4950aa8 --- /dev/null +++ b/contrib/ipfilter/tools/lexer.h @@ -0,0 +1,37 @@ +/* $NetBSD$ */ + + +typedef struct wordtab { + char *w_word; + int w_value; +} wordtab_t; + +#ifdef NO_YACC +#define YY_COMMENT 1000 +#define YY_CMP_NE 1001 +#define YY_CMP_LE 1002 +#define YY_RANGE_OUT 1003 +#define YY_CMP_GE 1004 +#define YY_RANGE_IN 1005 +#define YY_HEX 1006 +#define YY_NUMBER 1007 +#define YY_IPV6 1008 +#define YY_STR 1009 +#define YY_IPADDR 1010 +#endif + +#define YYBUFSIZ 8192 + +extern wordtab_t *yysettab __P((wordtab_t *)); +extern void yysetdict __P((wordtab_t *)); +extern int yylex __P((void)); +extern void yyerror __P((char *)); +extern char *yykeytostr __P((int)); +extern void yyresetdict __P((void)); + +extern FILE *yyin; +extern int yylineNum; +extern int yyexpectaddr; +extern int yybreakondot; +extern int yyvarnext; + diff --git a/contrib/ipfilter/typescript b/contrib/ipfilter/typescript new file mode 100644 index 0000000..1446ac4 --- /dev/null +++ b/contrib/ipfilter/typescript @@ -0,0 +1,121 @@ +Script started on Mon Apr 25 17:24:29 2005 +/sbin /usr/sbin /bin /usr/bin /etc /usr/sbin
+FreeBSD FreeBSD/i386.6.0 on /dev/ttyp0
+tcsh
+.cshrc
+(.cshrc)
+-done.
+/bin /sbin /etc /usr/bin /usr/sbin /usr/games
+.cshrc done
+TERM = vt100
+/usr/X11R6/man /usr/share/man
+(freebsd6:~) cd /usr/src/sy[K[Kcontrib/ipfilter
+(freebsd6:/usr/src/contrib/ipfilter) l
+./ ip_compat.h ipf.h
+../ ip_fil.c ipl.h
+.cvsignore ip_fil.h iplang/
+BNF ip_fil_freebsd.c ipmon.h
+BSD/ ip_frag.c ipsd/
+BugReport ip_frag.h ipsend/
+CVS/ ip_ftp_pxy.c ipt.h
+FAQ.FreeBSD ip_h323_pxy.c kmem.h
+FWTK/ ip_htable.c l4check/
+FreeBSD/ ip_htable.h lib/
+FreeBSD-2.2/ ip_ipsec_pxy.c man/
+FreeBSD-3/ ip_irc_pxy.c md5.c
+FreeBSD-4.0/ ip_log.c md5.h
+HISTORY ip_lookup.c mkfilters
+IMPORTANT ip_lookup.h mlf_ipl.c
+INST.FreeBSD-2.2 ip_msnrpc_pxy.c mlf_rule.c
+INSTALL.FreeBSD ip_nat.c mlfk_ipl.c
+INSTALL.xBSD ip_nat.h mlfk_rule.c
+IPF.KANJI ip_netbios_pxy.c mlh_rule.c
+IPFILTER.LICENCE ip_pool.c net/
+Makefile ip_pool.h netinet/
+NAT.FreeBSD ip_pptp_pxy.c opts.h
+QNX_OCL.txt ip_proxy.c pcap-ipf.h
+README ip_proxy.h perl/
+STYLE.TXT ip_raudio_pxy.c radix.c
+WhatsNew40.txt ip_rcmd_pxy.c radix_ipf.h
+Y2K ip_rpcb_pxy.c rules/
+bpf-ipf.h ip_rules.c samples/
+bpf_filter.c ip_rules.h snoop.h
+bsdinstall ip_scan.c test/
+buildsunos ip_scan.h todo
+etc/ ip_state.c tools/
+fil.c ip_state.h typescript
+ip_auth.c ip_sync.c
+ip_auth.h ip_sync.h
+(freebsd6:/usr/src/contrib/ipfilter) l CVS
+./ Entries Repository
+../ Entries.Log Root
+(freebsd6:/usr/src/contrib/ipfilter) \rm -rf CVS
+(freebsd6:/usr/src/contrib/ipfilter) l
+./ ip_compat.h ip_sync.h
+../ ip_fil.c ipf.h
+.cvsignore ip_fil.h ipl.h
+BNF ip_fil_freebsd.c iplang/
+BSD/ ip_frag.c ipmon.h
+BugReport ip_frag.h ipsd/
+FAQ.FreeBSD ip_ftp_pxy.c ipsend/
+FWTK/ ip_h323_pxy.c ipt.h
+FreeBSD/ ip_htable.c kmem.h
+FreeBSD-2.2/ ip_htable.h l4check/
+FreeBSD-3/ ip_ipsec_pxy.c lib/
+FreeBSD-4.0/ ip_irc_pxy.c man/
+HISTORY ip_log.c md5.c
+IMPORTANT ip_lookup.c md5.h
+INST.FreeBSD-2.2 ip_lookup.h mkfilters
+INSTALL.FreeBSD ip_msnrpc_pxy.c mlf_ipl.c
+INSTALL.xBSD ip_nat.c mlf_rule.c
+IPF.KANJI ip_nat.h mlfk_ipl.c
+IPFILTER.LICENCE ip_netbios_pxy.c mlfk_rule.c
+Makefile ip_pool.c mlh_rule.c
+NAT.FreeBSD ip_pool.h net/
+QNX_OCL.txt ip_pptp_pxy.c netinet/
+README ip_proxy.c opts.h
+STYLE.TXT ip_proxy.h pcap-ipf.h
+WhatsNew40.txt ip_raudio_pxy.c perl/
+Y2K ip_rcmd_pxy.c radix.c
+bpf-ipf.h ip_rpcb_pxy.c radix_ipf.h
+bpf_filter.c ip_rules.c rules/
+bsdinstall ip_rules.h samples/
+buildsunos ip_scan.c snoop.h
+etc/ ip_scan.h test/
+fil.c ip_state.c todo
+ip_auth.c ip_state.h tools/
+ip_auth.h ip_sync.c typescript
+(freebsd6:/usr/src/contrib/ipfilter) cd ..
+(freebsd6:/usr/src/contrib) mv ipfilter ipfilter.i
+(freebsd6:/usr/src/contrib) cd !$ipfilter.i
+(freebsd6:/usr/src/contrib/ipfilter.i) l */CVS
+/bin/ls: No match.
+(freebsd6:/usr/src/contrib/ipfilter.i) cvs m[K[K
+(freebsd6:/usr/src/contrib/ipfilter.i) cvs import[10D[K
+(freebsd6:/usr/src/contrib/ipfilter.i) ~
+/home/darrenr: Permission denied.
+(freebsd6:/usr/src/contrib/ipfilter.i) ~[K
+(freebsd6:/usr/src/contrib/ipfilter.i) suspend
+(freebsd6:/usr/src/contrib/ipfilter.i) history
+ 1 17:24 cd /usr/src/contrib/ipfilter
+ 2 17:24 l
+ 3 17:24 l CVS
+ 4 17:24 \rm -rf CVS
+ 5 17:24 l
+ 6 17:24 cd ..
+ 7 17:24 mv ipfilter ipfilter.i
+ 8 17:24 cd ipfilter.i
+ 9 17:24 l */CVS
+ 10 17:25 ~
+ 11 17:25 suspend
+ 12 17:25 history
+(freebsd6:/usr/src/contrib/ipfilter.i)
+(freebsd6:/usr/src/contrib/ipfilter.i) kill -STOP $$
+
+^C
+c
+
+
+[K(freebsd6:/usr/src/contrib/ipfilter.i)
+(freebsd6:/usr/src/contrib/ipfilter.i) c
+
|