summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authordarrenr <darrenr@FreeBSD.org>1997-02-09 22:50:16 +0000
committerdarrenr <darrenr@FreeBSD.org>1997-02-09 22:50:16 +0000
commit0ca5211690784ffe0b60716c46a65a19f7cbc591 (patch)
tree30adc56baae241f29bfd9459d068c8f0d1aeeaa6 /contrib
parentc02c6e248f4ea2eb160b89d383501080e7d0a2f7 (diff)
parentcb8d46a179f2d30ac1cd0a01eb156e1a4c08d717 (diff)
downloadFreeBSD-src-0ca5211690784ffe0b60716c46a65a19f7cbc591.zip
FreeBSD-src-0ca5211690784ffe0b60716c46a65a19f7cbc591.tar.gz
This commit was generated by cvs2svn to compensate for changes in r22514,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/ipfilter/BNF64
-rw-r--r--contrib/ipfilter/COMPILE.2.511
-rw-r--r--contrib/ipfilter/FWTK/README16
-rw-r--r--contrib/ipfilter/FWTK/ftp-gw.diff237
-rw-r--r--contrib/ipfilter/FWTK/fwtkp812
-rw-r--r--contrib/ipfilter/HISTORY567
-rw-r--r--contrib/ipfilter/IMPORTANT41
-rw-r--r--contrib/ipfilter/INSTALL.FreeBSD41
-rw-r--r--contrib/ipfilter/INSTALL.NetBSD48
-rw-r--r--contrib/ipfilter/INSTALL.Sol227
-rw-r--r--contrib/ipfilter/INSTALL.SunOS36
-rw-r--r--contrib/ipfilter/INSTALL.xBSD39
-rw-r--r--contrib/ipfilter/LICENCE16
-rw-r--r--contrib/ipfilter/Makefile158
-rw-r--r--contrib/ipfilter/README93
-rwxr-xr-xcontrib/ipfilter/bsdinstall83
-rwxr-xr-xcontrib/ipfilter/buildsunos23
-rw-r--r--contrib/ipfilter/etc/protocols95
-rw-r--r--contrib/ipfilter/etc/services731
-rw-r--r--contrib/ipfilter/fil.c762
-rw-r--r--contrib/ipfilter/fils.c366
-rw-r--r--contrib/ipfilter/inet_addr.c182
-rw-r--r--contrib/ipfilter/ip_compat.h342
-rw-r--r--contrib/ipfilter/ip_fil.c885
-rw-r--r--contrib/ipfilter/ip_fil.h293
-rw-r--r--contrib/ipfilter/ip_frag.c278
-rw-r--r--contrib/ipfilter/ip_frag.h47
-rw-r--r--contrib/ipfilter/ip_nat.c886
-rw-r--r--contrib/ipfilter/ip_nat.h118
-rw-r--r--contrib/ipfilter/ip_sfil.c731
-rw-r--r--contrib/ipfilter/ip_state.c536
-rw-r--r--contrib/ipfilter/ip_state.h86
-rw-r--r--contrib/ipfilter/ipf.c434
-rw-r--r--contrib/ipfilter/ipf.h67
-rw-r--r--contrib/ipfilter/ipft_ef.c148
-rw-r--r--contrib/ipfilter/ipft_hx.c140
-rw-r--r--contrib/ipfilter/ipft_pc.c224
-rw-r--r--contrib/ipfilter/ipft_sn.c206
-rw-r--r--contrib/ipfilter/ipft_td.c184
-rw-r--r--contrib/ipfilter/ipft_tx.c338
-rw-r--r--contrib/ipfilter/ipl.h16
-rw-r--r--contrib/ipfilter/ipl_ldev.c83
-rw-r--r--contrib/ipfilter/ipmon.c582
-rw-r--r--contrib/ipfilter/ipnat.c692
-rw-r--r--contrib/ipfilter/ipsd/Makefile63
-rw-r--r--contrib/ipfilter/ipsd/README32
-rw-r--r--contrib/ipfilter/ipsd/ip_compat.h201
-rw-r--r--contrib/ipfilter/ipsd/ipsd.c297
-rw-r--r--contrib/ipfilter/ipsd/ipsd.h30
-rw-r--r--contrib/ipfilter/ipsd/ipsdr.c315
-rw-r--r--contrib/ipfilter/ipsd/linux.h17
-rw-r--r--contrib/ipfilter/ipsd/sbpf.c195
-rw-r--r--contrib/ipfilter/ipsd/sdlpi.c263
-rw-r--r--contrib/ipfilter/ipsd/slinux.c120
-rw-r--r--contrib/ipfilter/ipsd/snit.c230
-rw-r--r--contrib/ipfilter/ipsend/44arp.c95
-rw-r--r--contrib/ipfilter/ipsend/Crashable20
-rw-r--r--contrib/ipfilter/ipsend/Makefile91
-rw-r--r--contrib/ipfilter/ipsend/arp.c119
-rw-r--r--contrib/ipfilter/ipsend/dlcommon.c1359
-rw-r--r--contrib/ipfilter/ipsend/dltest.h32
-rw-r--r--contrib/ipfilter/ipsend/in_var.h177
-rw-r--r--contrib/ipfilter/ipsend/ip.c346
-rw-r--r--contrib/ipfilter/ipsend/ip_compat.h242
-rw-r--r--contrib/ipfilter/ipsend/ip_var.h123
-rw-r--r--contrib/ipfilter/ipsend/ipresend.c165
-rw-r--r--contrib/ipfilter/ipsend/ipsend.c350
-rw-r--r--contrib/ipfilter/ipsend/ipsopt.c111
-rw-r--r--contrib/ipfilter/ipsend/iptest.c211
-rw-r--r--contrib/ipfilter/ipsend/iptests.c1296
-rw-r--r--contrib/ipfilter/ipsend/larp.c85
-rw-r--r--contrib/ipfilter/ipsend/linux.h17
-rw-r--r--contrib/ipfilter/ipsend/lsock.c261
-rw-r--r--contrib/ipfilter/ipsend/resend.c130
-rw-r--r--contrib/ipfilter/ipsend/sbpf.c136
-rw-r--r--contrib/ipfilter/ipsend/sdlpi.c130
-rw-r--r--contrib/ipfilter/ipsend/slinux.c94
-rw-r--r--contrib/ipfilter/ipsend/snit.c160
-rw-r--r--contrib/ipfilter/ipsend/sock.c370
-rw-r--r--contrib/ipfilter/ipsend/tcpip.h38
-rw-r--r--contrib/ipfilter/ipt.c199
-rw-r--r--contrib/ipfilter/ipt.h16
-rw-r--r--contrib/ipfilter/kmem.c68
-rw-r--r--contrib/ipfilter/kmem.h12
-rw-r--r--contrib/ipfilter/linux.h19
-rw-r--r--contrib/ipfilter/man/Makefile21
-rw-r--r--contrib/ipfilter/man/ipf.1109
-rw-r--r--contrib/ipfilter/man/ipf.4184
-rw-r--r--contrib/ipfilter/man/ipf.5433
-rw-r--r--contrib/ipfilter/man/ipfstat.873
-rw-r--r--contrib/ipfilter/man/ipftest.1127
-rw-r--r--contrib/ipfilter/man/ipl.462
-rw-r--r--contrib/ipfilter/man/ipmon.856
-rw-r--r--contrib/ipfilter/man/ipnat.145
-rw-r--r--contrib/ipfilter/man/ipnat.488
-rw-r--r--contrib/ipfilter/man/ipnat.570
-rw-r--r--contrib/ipfilter/misc.c85
-rw-r--r--contrib/ipfilter/mkfilters65
-rw-r--r--contrib/ipfilter/ml_ipl.c167
-rw-r--r--contrib/ipfilter/mln_ipl.c237
-rw-r--r--contrib/ipfilter/mls_ipl.c174
-rw-r--r--contrib/ipfilter/opt.c134
-rw-r--r--contrib/ipfilter/parse.c1249
-rw-r--r--contrib/ipfilter/pcap.h35
-rw-r--r--contrib/ipfilter/relay.c179
-rw-r--r--contrib/ipfilter/rules/example.14
-rw-r--r--contrib/ipfilter/rules/example.1012
-rw-r--r--contrib/ipfilter/rules/example.1126
-rw-r--r--contrib/ipfilter/rules/example.1217
-rw-r--r--contrib/ipfilter/rules/example.1317
-rw-r--r--contrib/ipfilter/rules/example.24
-rw-r--r--contrib/ipfilter/rules/example.340
-rw-r--r--contrib/ipfilter/rules/example.44
-rw-r--r--contrib/ipfilter/rules/example.525
-rw-r--r--contrib/ipfilter/rules/example.65
-rw-r--r--contrib/ipfilter/rules/example.712
-rw-r--r--contrib/ipfilter/rules/example.810
-rw-r--r--contrib/ipfilter/rules/example.912
-rw-r--r--contrib/ipfilter/rules/example.sr61
-rw-r--r--contrib/ipfilter/rules/nat.eg14
-rw-r--r--contrib/ipfilter/rules/server11
-rw-r--r--contrib/ipfilter/rules/tcpstate13
-rw-r--r--contrib/ipfilter/snoop.h42
-rw-r--r--contrib/ipfilter/solaris.c1018
-rw-r--r--contrib/ipfilter/test/Makefile39
-rw-r--r--contrib/ipfilter/test/dotest26
-rw-r--r--contrib/ipfilter/test/expected/116
-rw-r--r--contrib/ipfilter/test/expected/10108
-rw-r--r--contrib/ipfilter/test/expected/1166
-rw-r--r--contrib/ipfilter/test/expected/1254
-rw-r--r--contrib/ipfilter/test/expected/236
-rw-r--r--contrib/ipfilter/test/expected/340
-rw-r--r--contrib/ipfilter/test/expected/440
-rw-r--r--contrib/ipfilter/test/expected/51344
-rw-r--r--contrib/ipfilter/test/expected/61344
-rw-r--r--contrib/ipfilter/test/expected/754
-rw-r--r--contrib/ipfilter/test/expected/836
-rw-r--r--contrib/ipfilter/test/expected/9108
-rw-r--r--contrib/ipfilter/test/expected/i111
-rw-r--r--contrib/ipfilter/test/expected/i104
-rw-r--r--contrib/ipfilter/test/expected/i114
-rw-r--r--contrib/ipfilter/test/expected/i26
-rw-r--r--contrib/ipfilter/test/expected/i38
-rw-r--r--contrib/ipfilter/test/expected/i47
-rw-r--r--contrib/ipfilter/test/expected/i55
-rw-r--r--contrib/ipfilter/test/expected/i64
-rw-r--r--contrib/ipfilter/test/expected/i73
-rw-r--r--contrib/ipfilter/test/expected/i82
-rw-r--r--contrib/ipfilter/test/expected/i95
-rw-r--r--contrib/ipfilter/test/hextest23
-rw-r--r--contrib/ipfilter/test/input/14
-rw-r--r--contrib/ipfilter/test/input/106
-rw-r--r--contrib/ipfilter/test/input/1111
-rw-r--r--contrib/ipfilter/test/input/1235
-rw-r--r--contrib/ipfilter/test/input/1339
-rw-r--r--contrib/ipfilter/test/input/26
-rw-r--r--contrib/ipfilter/test/input/35
-rw-r--r--contrib/ipfilter/test/input/45
-rw-r--r--contrib/ipfilter/test/input/528
-rw-r--r--contrib/ipfilter/test/input/628
-rw-r--r--contrib/ipfilter/test/input/79
-rw-r--r--contrib/ipfilter/test/input/86
-rw-r--r--contrib/ipfilter/test/input/96
-rw-r--r--contrib/ipfilter/test/itest21
-rw-r--r--contrib/ipfilter/test/regress/14
-rw-r--r--contrib/ipfilter/test/regress/1018
-rw-r--r--contrib/ipfilter/test/regress/116
-rw-r--r--contrib/ipfilter/test/regress/126
-rw-r--r--contrib/ipfilter/test/regress/136
-rw-r--r--contrib/ipfilter/test/regress/26
-rw-r--r--contrib/ipfilter/test/regress/38
-rw-r--r--contrib/ipfilter/test/regress/48
-rw-r--r--contrib/ipfilter/test/regress/548
-rw-r--r--contrib/ipfilter/test/regress/648
-rw-r--r--contrib/ipfilter/test/regress/76
-rw-r--r--contrib/ipfilter/test/regress/86
-rw-r--r--contrib/ipfilter/test/regress/918
-rw-r--r--contrib/ipfilter/test/regress/i111
-rw-r--r--contrib/ipfilter/test/regress/i104
-rw-r--r--contrib/ipfilter/test/regress/i114
-rw-r--r--contrib/ipfilter/test/regress/i26
-rw-r--r--contrib/ipfilter/test/regress/i38
-rw-r--r--contrib/ipfilter/test/regress/i47
-rw-r--r--contrib/ipfilter/test/regress/i55
-rw-r--r--contrib/ipfilter/test/regress/i64
-rw-r--r--contrib/ipfilter/test/regress/i73
-rw-r--r--contrib/ipfilter/test/regress/i82
-rw-r--r--contrib/ipfilter/test/regress/i95
-rw-r--r--contrib/ipfilter/todo19
189 files changed, 28807 insertions, 0 deletions
diff --git a/contrib/ipfilter/BNF b/contrib/ipfilter/BNF
new file mode 100644
index 0000000..7cb556e
--- /dev/null
+++ b/contrib/ipfilter/BNF
@@ -0,0 +1,64 @@
+filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ]
+ [ proto ] [ ip ] .
+
+insert = "@" decnumber .
+action = block | "pass" | log | "count" | call .
+in-out = "in" | "out" .
+options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] ] .
+tos = "tos" decnumber | "tos" hexnumber .
+ttl = "ttl" decnumber .
+proto = "proto" protocol .
+ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
+
+block = "block" [ "return-icmp"[return-code] | "return-rst" ] .
+log = "log" [ "body" ] [ "first" ] [ "or-block" ] .
+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 .
+
+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" | "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" | "frag" | "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" | 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" .
+optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" |
+ "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" |
+ "visa" | "imitd" | "eip" | "finn" .
+
+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" .
diff --git a/contrib/ipfilter/COMPILE.2.5 b/contrib/ipfilter/COMPILE.2.5
new file mode 100644
index 0000000..ae550f8
--- /dev/null
+++ b/contrib/ipfilter/COMPILE.2.5
@@ -0,0 +1,11 @@
+
+If you get the following error whilst compiling:
+
+In file included from /usr/local/lib/gcc-lib/sparc-sun-solaris2.3/2.6.3/include/sys/user.h:48,
+ from /usr/include/sys/file.h:15,
+ from ../ip_nat.c:15:
+/usr/include/sys/psw.h:19: #error Kernel include of psw.h
+
+Remove (comment out) the line in
+/usr/local/lib/gcc-lib/sparc-sun-solaris2.3/2.6.3include/sys/user.h
+which includes psw.h
diff --git a/contrib/ipfilter/FWTK/README b/contrib/ipfilter/FWTK/README
new file mode 100644
index 0000000..216d205
--- /dev/null
+++ b/contrib/ipfilter/FWTK/README
@@ -0,0 +1,16 @@
+
+There are two patch files in this directory, each allowing for the Firewall
+Toolkit to be used in a transparent proxy configuration.
+
+ftp-gw.diff - A patch written by myself for use only with IP Filter and
+ ftp-gw from the Firewall Toolkit.
+
+fwtkp - A set of patches written by James B. Croall (jcroall@foo.org)
+ for use with both IP Filter and ipfwadm (for Linux) and more
+ of the various FWTK gateway plugins, including:
+ ftp-gw http-gw plug-gw rlogin-gw tn-gw
+
+Both patches when applied to the Firewall toolkit require the same
+configuration for IP Filter.
+
+Darren
diff --git a/contrib/ipfilter/FWTK/ftp-gw.diff b/contrib/ipfilter/FWTK/ftp-gw.diff
new file mode 100644
index 0000000..075e6eb
--- /dev/null
+++ b/contrib/ipfilter/FWTK/ftp-gw.diff
@@ -0,0 +1,237 @@
+*** ftp-gw.c.orig Sat Nov 5 10:30:16 1994
+--- ftp-gw.c Sun Jul 7 12:25:15 1996
+***************
+*** 11,31 ****
+ */
+ static char RcsId[] = "$Header: /devel/CVS/IP-Filter/FWTK/ftp-gw.diff,v 2.0.1.1 1997/01/09 15:14:46 darrenr Exp $";
+
+
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <syslog.h>
+ #include <sys/signal.h>
+ #include <sys/ioctl.h>
+ #include <sys/errno.h>
+- extern int errno;
+- extern char *sys_errlist[];
+ #include <arpa/ftp.h>
+ #include <arpa/telnet.h>
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+
+ extern char *rindex();
+ extern char *index();
+--- 11,37 ----
+ */
+ static char RcsId[] = "$Header: /devel/CVS/IP-Filter/FWTK/ftp-gw.diff,v 2.0.1.1 1997/01/09 15:14:46 darrenr Exp $";
+
++ /*
++ * Patches for IP Filter NAT extensions written by Darren Reed, 7/7/96
++ * darrenr@cyber.com.au
++ */
++ static char vIpFilter[] = "v3.1.0";
+
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <syslog.h>
++ #include <unistd.h>
++ #include <fcntl.h>
+ #include <sys/signal.h>
+ #include <sys/ioctl.h>
+ #include <sys/errno.h>
+ #include <arpa/ftp.h>
+ #include <arpa/telnet.h>
+ #include <sys/time.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
++ #include <net/if.h>
+
+ extern char *rindex();
+ extern char *index();
+***************
+*** 36,41 ****
+--- 42,48 ----
+
+ #include "firewall.h"
+
++ #include "ip_nat.h"
+
+ #ifndef BSIZ
+ #define BSIZ 2048
+***************
+*** 83,88 ****
+--- 90,97 ----
+ static int cmd_noop();
+ static int cmd_abor();
+ static int cmd_passthru();
++ static int nat_destination();
++ static int connectdest();
+ static void saveline();
+ static void flushsaved();
+ static void trap_sigurg();
+***************
+*** 317,323 ****
+ if(authallflg)
+ if(say(0,"220-Proxy first requires authentication"))
+ exit(1);
+! sprintf(xuf,"220 %s FTP proxy (Version %s) ready.",huf,FWTK_VERSION_MINOR);
+ if(say(0,xuf))
+ exit(1);
+ }
+--- 326,335 ----
+ if(authallflg)
+ if(say(0,"220-Proxy first requires authentication"))
+ exit(1);
+! sprintf(xuf,"220-%s FTP proxy (Version %s) ready.",huf,FWTK_VERSION_MINOR);
+! if(say(0,xuf))
+! exit(1);
+! sprintf(xuf,"220-%s TIS ftp-gw with IP Filter %s NAT extensions",huf,vIpFilter);
+ if(say(0,xuf))
+ exit(1);
+ }
+***************
+*** 338,343 ****
+--- 350,357 ----
+ exit(1);
+ }
+
++ nat_destination(0);
++
+ /* main loop */
+ while(1) {
+ FD_ZERO(&rdy);
+***************
+*** 608,619 ****
+ static char narg[] = "501 Missing or extra username";
+ static char noad[] = "501 Use user@site to connect via proxy";
+ char buf[1024];
+- char mbuf[512];
+ char *p;
+ char *dest;
+ char *user;
+ int x;
+- int msg_int;
+ short port = FTPPORT;
+
+ /* kludgy but effective. if authorizing everything call auth instead */
+--- 622,631 ----
+***************
+*** 643,648 ****
+--- 655,681 ----
+ return(sayn(0,noad,sizeof(noad)));
+ }
+
++ if((rfd == -1) && (x = connectdest(dest,port)))
++ return x;
++ sprintf(buf,"USER %s",user);
++ if(say(rfd,buf))
++ return(1);
++ x = getresp(rfd,buf,sizeof(buf),1);
++ if(sendsaved(0,x))
++ return(1);
++ return(say(0,buf));
++ }
++
++ static int
++ connectdest(dest,port)
++ char *dest;
++ short port;
++ {
++ char buf[1024];
++ char mbuf[512];
++ int msg_int;
++ int x;
++
+ if(*dest == '\0')
+ dest = "localhost";
+
+***************
+*** 685,691 ****
+ char ebuf[512];
+
+ strcpy(ebuf,buf);
+! sprintf(buf,"521 %s: %s",dest,ebuf);
+ return(say(0,buf));
+ }
+ sprintf(buf,"----GATEWAY CONNECTED TO %s----",dest);
+--- 718,724 ----
+ char ebuf[512];
+
+ strcpy(ebuf,buf);
+! sprintf(buf,"521 %s,%d: %s",dest,ntohs(port),ebuf);
+ return(say(0,buf));
+ }
+ sprintf(buf,"----GATEWAY CONNECTED TO %s----",dest);
+***************
+*** 698,711 ****
+ return(say(0,buf));
+ }
+ saveline(buf);
+!
+! sprintf(buf,"USER %s",user);
+! if(say(rfd,buf))
+! return(1);
+! x = getresp(rfd,buf,sizeof(buf),1);
+! if(sendsaved(0,x))
+! return(1);
+! return(say(0,buf));
+ }
+
+
+--- 731,738 ----
+ return(say(0,buf));
+ }
+ saveline(buf);
+! sendsaved(0,-1);
+! return 0;
+ }
+
+
+***************
+*** 1591,1593 ****
+--- 1618,1659 ----
+ dup(nread);
+ }
+ #endif
++
++
++ static int
++ nat_destination(fd)
++ int fd;
++ {
++ struct sockaddr_in laddr, faddr;
++ struct natlookup natlookup;
++ char *dest;
++ int slen, natfd;
++
++ bzero((char *)&laddr, sizeof(laddr));
++ bzero((char *)&faddr, sizeof(faddr));
++ slen = sizeof(laddr);
++ if(getsockname(fd,(struct sockaddr *)&laddr,&slen) < 0) {
++ perror("getsockname");
++ exit(1);
++ }
++ slen = sizeof(faddr);
++ if(getpeername(fd,(struct sockaddr *)&faddr,&slen) < 0) {
++ perror("getsockname");
++ exit(1);
++ }
++
++ natlookup.nl_inport = laddr.sin_port;
++ natlookup.nl_outport = faddr.sin_port;
++ natlookup.nl_inip = laddr.sin_addr;
++ natlookup.nl_outip = faddr.sin_addr;
++ if((natfd = open("/dev/ipl", O_RDONLY)) < 0) {
++ perror("open");
++ exit(1);
++ }
++ if(ioctl(natfd, SIOCGNATL, &natlookup) == -1) {
++ perror("ioctl");
++ exit(1);
++ }
++ close(natfd);
++ return connectdest(inet_ntoa(natlookup.nl_inip),ntohs(natlookup.nl_inport));
++ }
diff --git a/contrib/ipfilter/FWTK/fwtkp b/contrib/ipfilter/FWTK/fwtkp
new file mode 100644
index 0000000..8f4819a
--- /dev/null
+++ b/contrib/ipfilter/FWTK/fwtkp
@@ -0,0 +1,812 @@
+diff -c -r ./ftp-gw/ftp-gw.c ../../NEW/fwtk/ftp-gw/ftp-gw.c
+*** ./ftp-gw/ftp-gw.c Fri Sep 6 12:55:05 1996
+--- ../../NEW/fwtk/ftp-gw/ftp-gw.c Wed Oct 9 02:51:35 1996
+***************
+*** 40,47 ****
+
+ extern char *optarg;
+
+! #include "firewall.h"
+
+
+ #ifndef BSIZ
+ #define BSIZ 2048
+--- 40,48 ----
+
+ extern char *optarg;
+
+! char *getdsthost();
+
++ #include "firewall.h"
+
+ #ifndef BSIZ
+ #define BSIZ 2048
+***************
+*** 84,89 ****
+--- 85,92 ----
+ static int cmdcnt = 0;
+ static int timeout = PROXY_TIMEOUT;
+
++ static int do_transparent=0;
++
+
+ static int cmd_user();
+ static int cmd_authorize();
+***************
+*** 98,103 ****
+--- 101,107 ----
+ static void saveline();
+ static void flushsaved();
+ static void trap_sigurg();
++ static int connectdest();
+
+ #define OP_CONN 001 /* only valid if connected */
+ #define OP_WCON 002 /* writethrough if connected */
+***************
+*** 170,175 ****
+--- 174,180 ----
+ char xuf[1024];
+ char huf[128];
+ char *passuser = (char *)0; /* passed user as av */
++ char *psychic, *hotline;
+
+ #ifndef LOG_DAEMON
+ openlog("ftp-gw",LOG_PID);
+***************
+*** 314,319 ****
+--- 319,326 ----
+ } else
+ timeout = 60*60;
+
++ psychic=getdsthost(0,NULL);
++ if(psychic) { do_transparent++; }
+
+ /* display a welcome file or message */
+ if(passuser == (char *)0) {
+***************
+*** 322,327 ****
+--- 329,340 ----
+ syslog(LLEV,"fwtkcfgerr: welcome-msg must have one parameter, line %d",cf->ln);
+ exit(1);
+ }
++ if(do_transparent) {
++ if(sayfile2(0,cf->argv[0],220)) {
++ syslog(LLEV,"fwtksyserr: cannot display welcome %s: %m",cf->argv[0]);
++ exit(1);
++ }
++ } else
+ if(sayfile(0,cf->argv[0],220)) {
+ syslog(LLEV,"fwtksyserr: cannot display welcome %s: %m",cf->argv[0]);
+ exit(1);
+***************
+*** 332,338 ****
+ if(authallflg)
+ if(say(0,"220-Proxy first requires authentication"))
+ exit(1);
+! sprintf(xuf,"220 %s FTP proxy (Version %s) ready.",huf,FWTK_VERSION_MINOR);
+ if(say(0,xuf))
+ exit(1);
+ }
+--- 345,357 ----
+ if(authallflg)
+ if(say(0,"220-Proxy first requires authentication"))
+ exit(1);
+! /* foo */
+! if(do_transparent)
+! sprintf(xuf,"220-%s FTP proxy (Version %s) ready.",huf,FWTK_VERSION_MINOR);
+! else
+! sprintf(xuf,"220 %s FTP Proxy (Version %s) ready.",huf,FWTK_VERSION_MINOR);
+! /* foo */
+!
+ if(say(0,xuf))
+ exit(1);
+ }
+***************
+*** 353,358 ****
+--- 372,381 ----
+ exit(1);
+ }
+
++ if(do_transparent) {
++ connectdest(psychic,21);
++ }
++
+ /* main loop */
+ while(1) {
+ FD_ZERO(&rdy);
+***************
+*** 676,681 ****
+--- 699,713 ----
+ return(sayn(0,noad,sizeof(noad)-1));
+ }
+
++ if(do_transparent) {
++ if((rfd==(-1)) && (x=connectdest(dest,port))) return x;
++ sprintf(buf,"USER %s",user);
++ if(say(rfd,buf)) return(1);
++ x=getresp(rfd,buf,sizeof(buf),1);
++ if(sendsaved(0,x)) return(1);
++ return(say(0,buf));
++ }
++
+ if(*dest == '\0')
+ dest = "localhost";
+
+***************
+*** 701,708 ****
+ if(msg_int == 1) {
+ sprintf(mbuf,"Permission denied for user %s to connect to %s",authuser,dest);
+ syslog(LLEV,"deny host=%s/%s connect to %s user=%s",rladdr,riaddr,dest,authuser);
+! say(0,mbuf);
+! return(1);
+ } else {
+ if(msg_int == -1) {
+ sprintf(mbuf,"No match in netperm-table for %s to ftp to %s",authuser,dest);
+--- 733,740 ----
+ if(msg_int == 1) {
+ sprintf(mbuf,"Permission denied for user %s to connect to %s",authuser,dest);
+ syslog(LLEV,"deny host=%s/%s connect to %s user=%s",rladdr,riaddr,dest,authuser);
+! say(0,mbuf);
+! return(1);
+ } else {
+ if(msg_int == -1) {
+ sprintf(mbuf,"No match in netperm-table for %s to ftp to %s",authuser,dest);
+***************
+*** 717,723 ****
+ char ebuf[512];
+
+ strcpy(ebuf,buf);
+! sprintf(buf,"521 %s: %s",dest,ebuf);
+ rfd = -1;
+ return(say(0,buf));
+ }
+--- 749,759 ----
+ char ebuf[512];
+
+ strcpy(ebuf,buf);
+! if(do_transparent) {
+! sprintf(buf,"521 %s,%d: %s",dest,ntohs(port),ebuf);
+! } else {
+! sprintf(buf,"521 %s: %s",dest,ebuf);
+! }
+ rfd = -1;
+ return(say(0,buf));
+ }
+***************
+*** 732,737 ****
+--- 768,778 ----
+ }
+ saveline(buf);
+
++ /* if(do_transparent) {
++ sendsaved(0,-1);
++ return(0);
++ } /* EEEk. I can't remember what this does. */
++
+ sprintf(buf,"USER %s",user);
+ if(say(rfd,buf))
+ return(1);
+***************
+*** 744,749 ****
+--- 785,860 ----
+ return 0;
+ }
+
++ static int connectdest(dest, port)
++ char *dest;
++ short port;
++ {
++ char buf[1024], mbuf[512];
++ int msg_int, x;
++
++ if(*dest == '\0')
++ dest = "localhost";
++
++ if(validests != (char **)0) {
++ char **xp;
++ int x;
++
++ for(xp = validests; *xp != (char *)0; xp++) {
++ if(**xp == '!' && hostmatch(*xp + 1,dest)) {
++ return(baddest(0,dest));
++ } else {
++ if(hostmatch(*xp,dest))
++ break;
++ }
++ }
++ if(*xp == (char *)0)
++ return(baddest(0,dest));
++ }
++
++ /* Extended permissions processing goes in here for destination */
++ if(extendperm) {
++ msg_int = auth_perm(confp, authuser, "ftp-gw", dest,(char *)0);
++ if(msg_int == 1) {
++ sprintf(mbuf,"Permission denied for user %s to connect to %s",authuser,dest);
++ syslog(LLEV,"deny host=%s/%s connect to %s user=%s",rladdr,riaddr,dest,authuser);
++ say(0,mbuf);
++ return(1);
++ } else {
++ if(msg_int == -1) {
++ sprintf(mbuf,"No match in netperm-table for %s to ftp to %s",authuser,dest);
++ say(0,mbuf);
++ return(1);
++ }
++ }
++ }
++
++ syslog(LLEV,"permit host=%s/%s connect to %s",rladdr,riaddr,dest);
++
++ if((rfd = conn_server(dest,port,0,buf)) < 0) {
++ char ebuf[512];
++
++ strcpy(ebuf,buf);
++ sprintf(buf,"521 %s: %s",dest,ebuf);
++ rfd = -1;
++ return(say(0,buf));
++ }
++ if(!do_transparent) {
++ sprintf(buf,"----GATEWAY CONNECTED TO %s----",dest);
++ saveline(buf);
++ }
++
++ /* we are now connected and need to try the autologin thing */
++ x = getresp(rfd,buf,sizeof(buf),1);
++ if(x / 100 != COMPLETE) {
++ sendsaved(0,-1);
++ return(say(0,buf));
++ }
++ saveline(buf);
++
++ sendsaved(0,-1);
++ return 0;
++ }
++
+
+
+ static int
+***************
+*** 1053,1058 ****
+--- 1164,1171 ----
+ static char nprn[] = "500 cannot get peername";
+ char buf[512];
+
++ /* syslog(LLEV,"DEBUG: port cmd"); */
++
+ if(ac < 2)
+ return(sayn(0,narg,sizeof(narg)-1));
+
+***************
+*** 1119,1124 ****
+--- 1232,1238 ----
+ #define UC(c) (((int)c) & 0xff)
+ sprintf(buf,"PORT %d,%d,%d,%d,%d,%d\r\n",UC(k[0]),UC(k[1]),UC(k[2]),
+ UC(k[3]),UC(l[0]),UC(l[1]));
++ /* syslog(LLEV,"DEBUG: %s",buf); */
+ s = strlen(buf);
+ if (write(rfd, buf, s) != s)
+ return 1;
+***************
+*** 1330,1335 ****
+--- 1444,1450 ----
+ callback()
+ {
+ /* if we haven't gotten a valid PORT scrub the connection */
++ /* syslog(LLEV,"DEBUG: callback()."); */
+ if((outgoing = accept(boundport,(struct sockaddr *)0,(int *)0)) < 0 || clntport.sin_port == 0)
+ goto bomb;
+ if(pasvport != -1) { /* incoming handled by PASVcallback */
+***************
+*** 1796,1801 ****
+--- 1911,1960 ----
+ }
+ return(0);
+ }
++
++ /* ok, so i'm in a hurry. english paper due RSN. */
++ sayfile2(fd,fn,code)
++ int fd;
++ char *fn;
++ int code;
++ {
++ FILE *f;
++ char buf[BUFSIZ];
++ char yuf[BUFSIZ];
++ char *c;
++ int x;
++ int saidsomething = 0;
++
++ if((f = fopen(fn,"r")) == (FILE *)0)
++ return(1);
++ while(fgets(buf,sizeof(buf),f) != (char *)0) {
++ if((c = index(buf,'\n')) != (char *)0)
++ *c = '\0';
++ x = fgetc(f);
++ if(feof(f))
++ sprintf(yuf,"%3.3d-%s",code,buf);
++ else {
++ sprintf(yuf,"%3.3d-%s",code,buf);
++ ungetc(x,f);
++ }
++ if(say(fd,yuf)) {
++ fclose(f);
++ return(1);
++ }
++ saidsomething++;
++ }
++ fclose(f);
++ if (!saidsomething) {
++ syslog(LLEV,"fwtkcfgerr: sayfile for %d is empty",code);
++ sprintf(yuf, "%3.3d The file to display is empty",code);
++ if(say(fd,yuf)) {
++ fclose(f);
++ return(1);
++ }
++ }
++ return(0);
++ }
++
+
+
+ porttoaddr(s,a)
+diff -c -r ./http-gw/http-gw.c ../../NEW/fwtk/http-gw/http-gw.c
+*** ./http-gw/http-gw.c Mon Sep 9 14:40:53 1996
+--- ../../NEW/fwtk/http-gw/http-gw.c Wed Oct 9 02:51:57 1996
+***************
+*** 27,32 ****
+--- 27,37 ----
+ static char http_buffer[8192];
+ static char reason[8192];
+ static int checkBrowserType = 1;
++ /* foo */
++ static int do_transparent=0;
++ /* foo */
++
++ char *getdsthost();
+
+ static void do_logging()
+ { char *proto = "GOPHER";
+***************
+*** 422,427 ****
+--- 427,443 ----
+ /*(NOT A SPECIAL FORM)*/
+
+ if((rem_type & TYPE_LOCAL)== 0){
++ /* foo */
++ char *psychic=getdsthost(sockfd,&def_port);
++ if(psychic) {
++ if(strlen(psychic)<=MAXHOSTNAMELEN) {
++ do_transparent++;
++ strncpy(def_httpd,psychic,strlen(psychic));
++ strncpy(def_server,psychic,strlen(psychic));
++ }
++ }
++
++ /* foo */
+ /* See if it can be forwarded */
+
+ if( can_forward(buf)){
+***************
+*** 1513,1519 ****
+ parse_vec[0],
+ parse_vec[1],
+ ourname, ourport);
+! }else{
+ sprintf(new_reply,"%s\tgopher://%s:%s/%c%s\t%s\t%u",
+ parse_vec[0], parse_vec[2],
+ parse_vec[3], chk_type_ch,
+--- 1529,1541 ----
+ parse_vec[0],
+ parse_vec[1],
+ ourname, ourport);
+! }
+! /* FOO */
+! else if(do_transparent) {
+! sprintf(new_reply,"%s\t%s\t%s\t%s",parse_vec[0],parse_vec[1],parse_vec[2],parse_vec[3]);
+! }
+! /* FOO */
+! else{
+ sprintf(new_reply,"%s\tgopher://%s:%s/%c%s\t%s\t%u",
+ parse_vec[0], parse_vec[2],
+ parse_vec[3], chk_type_ch,
+diff -c -r ./lib/hnam.c ../../NEW/fwtk/lib/hnam.c
+*** ./lib/hnam.c Fri Nov 4 18:30:19 1994
+--- ../../NEW/fwtk/lib/hnam.c Wed Oct 9 02:34:13 1996
+***************
+*** 22,27 ****
+--- 22,31 ----
+
+
+ #include "firewall.h"
++ #ifdef __FreeBSD__
++ #include <net/if.h>
++ #include "ip_nat.h"
++ #endif /* __FreeBSD__ */
+
+
+ char *
+***************
+*** 44,47 ****
+--- 48,115 ----
+
+ bcopy(hp->h_addr,&sin.sin_addr,hp->h_length);
+ return(inet_ntoa(sin.sin_addr));
++ }
++
++ char *getdsthost(fd, ptr)
++ int fd;
++ int *ptr;
++ {
++ struct sockaddr_in sin;
++ struct hostent *hp;
++ int sl=sizeof(struct sockaddr_in), err=0, local_h=0, i=0;
++ char buf[255], hostbuf[255];
++ #ifdef __FreeBSD__
++ struct sockaddr_in rsin;
++ struct natlookup natlookup;
++ #endif
++
++ #ifdef linux
++ /* This should also work for UDP. Unfortunately, it doesn't.
++ Maybe when the Linux UDP proxy code gets a little cleaner.
++ */
++ if(!(err=getsockname(0,&sin,&sl))) {
++ if(ptr) *ptr=ntohs(sin.sin_port);
++ sprintf(buf,"%s",inet_ntoa(sin.sin_addr));
++ gethostname(hostbuf,254);
++ hp=gethostbyname(hostbuf);
++ while(hp->h_addr_list[i]) {
++ bzero(&sin,&sl);
++ memcpy(&sin.sin_addr,hp->h_addr_list[i++],sizeof(hp->h_addr_list[i++]));
++ if(!strcmp(buf,inet_ntoa(sin.sin_addr))) local_h++;
++ }
++ if(local_h) { /* syslog(LLEV,"DEBUG: hnam.c: non-transparent."); */ return(NULL); }
++ else { return(buf); }
++ }
++ #endif
++
++ #ifdef __FreeBSD__
++ /* The basis for this block of code is Darren Reed's
++ patches to the TIS ftwk's ftp-gw.
++ */
++ bzero((char*)&sin,sizeof(sin));
++ bzero((char*)&rsin,sizeof(rsin));
++ if(getsockname(fd,(struct sockaddr*)&sin,&sl)<0) {
++ return NULL;
++ }
++ sl=sizeof(rsin);
++ if(getpeername(fd,(struct sockaddr*)&rsin,&sl)<0) {
++ return NULL;
++ }
++ natlookup.nl_inport=sin.sin_port;
++ 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) {
++ 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));
++ #endif
++
++ /* No transparent proxy support */
++ return(NULL);
+ }
+Only in ./lib: hnam.c.orig
+diff -c -r ./plug-gw/plug-gw.c ../../NEW/fwtk/plug-gw/plug-gw.c
+*** ./plug-gw/plug-gw.c Thu Sep 5 15:36:33 1996
+--- ../../NEW/fwtk/plug-gw/plug-gw.c Wed Oct 9 02:46:48 1996
+***************
+*** 39,44 ****
+--- 39,48 ----
+ static char **validdests = (char **)0;
+ static Cfg *confp;
+
++ int do_transparent=0;
++
++ char *getdsthost();
++
+ main(ac,av)
+ int ac;
+ char *av[];
+***************
+*** 193,201 ****
+--- 197,213 ----
+ char *ptr;
+ int state = 0;
+ int ssl_plug = 0;
++ int pport=0;
+
+ struct timeval timo;
+
++ /* Transparent plug-gw is probably a bad idea, but hey .. */
++ dhost=getdsthost(0,&pport);
++ if(dhost) {
++ do_transparent++;
++ portid=pport;
++ }
++
+ if(c->flags & PERM_DENY) {
+ if (p == -1)
+ syslog(LLEV,"deny host=%s/%s port=any",rhost,raddr);
+***************
+*** 215,221 ****
+ syslog(LLEV,"fwtkcfgerr: -plug-to takes an argument, line %d",c->ln);
+ exit (1);
+ }
+! dhost = av[x];
+ continue;
+ }
+
+--- 227,234 ----
+ syslog(LLEV,"fwtkcfgerr: -plug-to takes an argument, line %d",c->ln);
+ exit (1);
+ }
+! if(!dhost) dhost = av[x];
+! /* syslog(LLEV,"DEBUG: dhost now is [%s]",dhost); */
+ continue;
+ }
+
+diff -c -r ./rlogin-gw/rlogin-gw.c ../../NEW/fwtk/rlogin-gw/rlogin-gw.c
+*** ./rlogin-gw/rlogin-gw.c Fri Sep 6 12:56:33 1996
+--- ../../NEW/fwtk/rlogin-gw/rlogin-gw.c Wed Oct 9 02:49:04 1996
+***************
+*** 39,45 ****
+--- 39,47 ----
+
+
+ extern char *maphostname();
++ char *getdsthost();
+
++ int do_transparent=0;
+
+ static int cmd_quit();
+ static int cmd_help();
+***************
+*** 120,125 ****
+--- 122,130 ----
+ static char *tokav[56];
+ int tokac;
+ struct timeval timo;
++ /* foo */
++ char *psychic;
++ /* foo */
+
+ #ifndef LOG_NDELAY
+ openlog("rlogin-gw",LOG_PID);
+***************
+*** 185,191 ****
+ xforwarder = cf->argv[0];
+ }
+
+!
+
+ if((cf = cfg_get("directory",confp)) != (Cfg *)0) {
+ if(cf->argc != 1) {
+--- 190,203 ----
+ xforwarder = cf->argv[0];
+ }
+
+! /* foo */
+! psychic=getdsthost(0,NULL);
+! if(psychic) {
+! do_transparent++;
+! strncpy(dest,psychic,511);
+! dest[511]='\0';
+! }
+! /* foo */
+
+ if((cf = cfg_get("directory",confp)) != (Cfg *)0) {
+ if(cf->argc != 1) {
+***************
+*** 260,269 ****
+ }
+
+ /* if present a host name, chop and save username and hostname */
+! dest[0] = '\0';
+ if((p = index(rusername,'@')) != (char *)0) {
+ char *namp;
+
+ *p++ = '\0';
+ if(*p == '\0')
+ p = "localhost";
+--- 272,282 ----
+ }
+
+ /* if present a host name, chop and save username and hostname */
+! /* dest[0] = '\0'; */
+ if((p = index(rusername,'@')) != (char *)0) {
+ char *namp;
+
++ dest[0] = '\0';
+ *p++ = '\0';
+ if(*p == '\0')
+ p = "localhost";
+***************
+*** 293,300 ****
+--- 306,326 ----
+ goto leave;
+ }
+
++ /* syslog(LLEV,"DEBUG: Uh-oh, $dest = %s\n",dest); */
++
+ if(dest[0] != '\0') {
+ /* Setup connection directly to remote machine */
++ if((cf = cfg_get("welcome-msg",confp)) != (Cfg *)0) {
++ if(cf->argc != 1) {
++ syslog(LLEV,"fwtkcfgerr: welcome-msg must have one parameter, line %d",cf->ln);
++ exit(1);
++ }
++ if(sayfile(0,cf->argv[0])) {
++ syslog(LLEV,"fwtksyserr: cannot display welcome %s: %m",cf->argv[0]);
++ exit(1);
++ }
++ }
++ /* Does this cmd_connect thing feel like a kludge or what? */
+ sprintf(buf,"connect %.1000s",dest);
+ tokac = enargv(buf, tokav, 56, tokbuf, sizeof(tokbuf));
+ if (cmd_connect(tokac, tokav, buf) != 2)
+***************
+*** 526,539 ****
+ char ebuf[512];
+
+ syslog(LLEV,"permit host=%s/%s connect to %s",rhost,raddr,namp);
+ if(strlen(namp) > 20)
+ namp[20] = '\0';
+ if(rusername[0] != '\0')
+ sprintf(ebuf,"Trying %s@%s...",rusername,namp);
+ else
+ sprintf(ebuf,"Trying %s...",namp);
+! if(say(0,ebuf))
+! return(1);
+ } else
+ syslog(LLEV,"permit host=%s/%s connect to %s",rhost,raddr,av[1]);
+ if((serfd = conn_server(av[1],RLOGINPORT,1,buf)) < 0) {
+--- 552,567 ----
+ char ebuf[512];
+
+ syslog(LLEV,"permit host=%s/%s connect to %s",rhost,raddr,namp);
++ if(!do_transparent) {
+ if(strlen(namp) > 20)
+ namp[20] = '\0';
+ if(rusername[0] != '\0')
+ sprintf(ebuf,"Trying %s@%s...",rusername,namp);
+ else
+ sprintf(ebuf,"Trying %s...",namp);
+! if(say(0,ebuf))
+! return(1);
+! }
+ } else
+ syslog(LLEV,"permit host=%s/%s connect to %s",rhost,raddr,av[1]);
+ if((serfd = conn_server(av[1],RLOGINPORT,1,buf)) < 0) {
+diff -c -r ./tn-gw/tn-gw.c ../../NEW/fwtk/tn-gw/tn-gw.c
+*** ./tn-gw/tn-gw.c Fri Sep 6 12:55:48 1996
+--- ../../NEW/fwtk/tn-gw/tn-gw.c Wed Oct 9 02:50:17 1996
+***************
+*** 87,92 ****
+--- 87,94 ----
+ static int cmd_xforward();
+ static int cmd_timeout();
+
++ char *getdsthost();
++
+ static int tn3270 = 1; /* don't do tn3270 stuff */
+ static int doX;
+
+***************
+*** 97,102 ****
+--- 99,106 ----
+ static int timeout = PROXY_TIMEOUT;
+ static char timed_out_msg[] = "\r\nConnection closed due to inactivity";
+
++ int do_transparent=0;
++
+ typedef struct {
+ char *name;
+ char *hmsg;
+***************
+*** 140,145 ****
+--- 144,151 ----
+ char tokbuf[BSIZ];
+ char *tokav[56];
+ int tokac;
++ int port;
++ char *psychic;
+
+ #ifndef LOG_DAEMON
+ openlog("tn-gw",LOG_PID);
+***************
+*** 308,313 ****
+--- 314,346 ----
+ }
+ }
+
++ psychic=getdsthost(0,&port);
++ if(psychic) {
++ if((strlen(psychic) + 10) < 510) {
++ do_transparent++;
++ if(port)
++ sprintf(dest,"%s:%d",psychic,port);
++ else
++ sprintf(dest,"%s",psychic);
++
++
++ if(!welcomedone)
++ if((cf = cfg_get("welcome-msg",confp)) != (Cfg *)0) {
++ if(cf->argc != 1) {
++ syslog(LLEV,"fwtkcfgerr: welcome-msg must have one parameter, line %d",cf->ln);
++ exit(1);
++ }
++ if(sayfile(0,cf->argv[0])) {
++ syslog(LLEV,"fwtksyserr: cannot display welcome %s:%m",cf->argv[0]);
++ exit(1);
++ }
++ welcomedone = 1;
++ }
++
++
++ }
++ }
++
+ while (argc > 1) {
+ argc--;
+ argv++;
+***************
+*** 864,877 ****
+ }
+ }
+
+-
+ if((namp = maphostname(av[1])) != (char *)0) {
+ char ebuf[512];
+
+ syslog(LLEV,"permit host=%s/%s destination=%s",rladdr,riaddr,namp);
+! sprintf(ebuf,"Trying %s port %d...",namp,port);
+! if(say(0,ebuf))
+! return(1);
+ } else
+ syslog(LLEV,"permit host=%s/%s destination=%s",rladdr,riaddr,av[1]);
+
+--- 897,911 ----
+ }
+ }
+
+ if((namp = maphostname(av[1])) != (char *)0) {
+ char ebuf[512];
+
+ syslog(LLEV,"permit host=%s/%s destination=%s",rladdr,riaddr,namp);
+! if(!do_transparent) {
+! sprintf(ebuf,"Trying %s port %d...",namp,port);
+! if(say(0,ebuf))
+! return(1);
+! }
+ } else
+ syslog(LLEV,"permit host=%s/%s destination=%s",rladdr,riaddr,av[1]);
+
+***************
+*** 903,910 ****
+
+ syslog(LLEV,"connected host=%s/%s destination=%s",rladdr,riaddr,av[1]);
+ strncpy(dest,av[1], 511);
+! sprintf(buf, "Connected to %s.", dest);
+! say(0, buf);
+ return(2);
+ }
+
+--- 937,946 ----
+
+ syslog(LLEV,"connected host=%s/%s destination=%s",rladdr,riaddr,av[1]);
+ strncpy(dest,av[1], 511);
+! if(!do_transparent) {
+! sprintf(buf, "Connected to %s.", dest);
+! say(0, buf);
+! }
+ return(2);
+ }
+
+
+
diff --git a/contrib/ipfilter/HISTORY b/contrib/ipfilter/HISTORY
new file mode 100644
index 0000000..7cd9106
--- /dev/null
+++ b/contrib/ipfilter/HISTORY
@@ -0,0 +1,567 @@
+#
+# NOTE: Quite a few patches and suggestions come from other sources, to whom
+# I'm greatly indebted, even if no names are mentioned.
+#
+# 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.
+#
+3.1.7 8/2/97 - Released
+
+Macros used for ntohs/htons supplied with gcc don't always work very well
+when the assignment is the same variable being converted.
+
+Filter matching doesn't not match rule which checks tcp flags on packets
+which are fragments - David Wilson
+
+3.1.7beta 30/1/97 - Released
+
+Fix up NAT bugs introduced in last major change (now tested), including
+nat_delete(), nat_lookupredir(), checksum changes, etc.
+
+3.1.7alpha 30/1/97 - Released
+
+Many changes to NAT code, including contributions from Laurent Joncheray
+<lpj@ans.net>
+
+Use "NO_SLEEP" when allocating memory under SunOS.
+
+Make kernel printf's nicer for BSD/SunOS4
+
+Always do a checksum for packets being filtered going out and being
+processed by fastroute.
+
+Leave kernel to play with cdevsw on *BSD systems with LKM's.
+
+ipnat.1 man page fixes.
+
+3.1.6 21/1/97 - Released
+
+Allow NAT to work on BSD systems in conjunction with "pass .. to ifname"
+
+Memory leak introduced in 3.1.3 in NAT lists, clearing of NAT table tried
+to free memory twice.
+
+NAT recalculates IP header checksum based on difference between IP#'s and
+port numbers - should be just IP#'s (Solaris2 only)
+
+3.1.5 13/1/97 - Released
+
+fixed setting of NAT timeouts and use different timeouts for concurrent
+TCP sessions using the same IP# mapping (when port mapping isn't used)
+
+multiple loading/unloading of LKM's doesn't clean up cdevsw properly for
+*BSD systems.
+
+3.1.4 10/1/97 - Released
+
+add command line options -C and -F to ipnat to flush NAT list and table
+
+ipnat -l loops on output - Neil Readwin (nreadwin@nysales.micrognosis.com)
+
+NetBSD/FreeBSD kernel malloc changes - Daniel Carosone
+
+3.1.3 10/1/97 - Released
+
+NAT chains not constructed correctly in hash tables - Antony Y.R Lu
+(antony@hawk.ee.ncku.edu.tw)
+
+Updated INSTALL.NetBSD, INSTALL.FreeBSD and INSTALL.Sol2
+
+man page update (ipf.5) from Daniel Carosone (dan@geek.com.au)
+
+ICMP header checksum update now included in NAT.
+
+Solaris2 needs to modify IP header checksums in ip_natin and ip_natout.
+
+3.1.2 4/12/96 - Released
+
+ipmon doesn't use syslog all the time when given -s option
+
+fixed mclput panic in ip_input.c and replace ntohs() with NTOHS() macro
+
+check the results of hostname resolution in ipnat
+
+"make *install" fixed for subdirectories.
+
+problems with "ARCH:=" and gnu make resolved
+
+parser reports an error for lines with whitespaces only rather than skipping
+them. D.Carosone@abm.com.au (Daniel Carosone)
+
+patches for integration into NetBSD-current (post 1.2).
+
+add an option to allow non-IP packets going up/down the stream on Solaris2
+to be dropped. John Bass.
+
+3.1.2beta 21/11/96 - Released
+
+make ipsend compile on Linux 2.0.24
+
+changes to TCP kept state algorithm, making it watch state on TCP
+connections in both directions. Also use the same algorithm for NAT TCP.
+
+-Wall cleanup - Bernd Ernesti
+
+added "or-block" for "pass .. log or-block" after a suggestion from
+David Oppenheim (davido@optimation.com.au)
+
+added subdirectories for building IP Filter in SunOS5/BSD for different
+cpu architecures
+
+Solaris2 fixes to logging and pre-filtering packet processing - 3.1.1p2
+
+mbuf logging not using mtod(), remove iplbusy - 3.1.1p1 1/11/96
+
+3.1.1 28/10/96 - Released
+
+Installation script fixes and deinstall scripts for IP Filter on:
+SunOS4/FreeBSD/NetBSD
+
+Man page fixes - Paul Dubois (dubois@primate.wisc.edu)
+
+Fix use of SOLARIS macro in ipmon, rewrote ipllog() (again!)
+
+parsing isn't completely case insensitive - David Wilson
+(davidw@optimation.com.au)
+
+Release ipl_mutex across uiomove() calls
+
+print entire rule entries out for "ipf -z" when zero'ing per-rule stats.
+
+ipfstat returns same output for "hits" in "ipfstat -aio" - Terletsky Slavik
+(ts@polynet.lviv.ua)
+
+New algorithm for setting timeouts for TCP connection (more closely follow
+TCP FSM) - Pradeep Krishnan (pkrishna@netcom.com)
+
+Track both window sizes for TCP connections through "keep state".
+
+Solaris2 doesn't like _KERNEL defined in stdargs.h - Jos van Wezel
+(wezel@bio.vu.nl)
+
+3.1.1-beta2 6/10/96 - Released
+
+Solaris2 fastroute/dup-to/to now works
+
+ipmon `record' reading rewritten
+
+Added post-NetBSD1.2 packet filter patches - Mathew Green (mrg@eterna.com.au)
+
+Attempt to use in_proto.c.diff, not "..diffs" for SunOS4 - David Wilson
+(davidw@optimation.com.au)
+
+Michael Ryan (mike@NetworX.ie) reports the following:
+* The Trumpet WinSock under Windows always sends its SYN packet with an ACK
+ value of 1, unlike any other implementation I've seen, which would set it
+ to zero. The "keep state" feature of IP Filter doesn't work when receiving
+ non-zero ACK values on new connection requests.
+* */Makefile install rule doesn't install all the binaries/man pages
+* Make ipnat use "tcp/udp" instead of "tcpudp"
+* Print out "tcp/udp" properly
+* ipnat "portmap tcp" matches "portmap udp" when adding/removing
+* NAT dest. ip# increased by one on mask of 0xffffffff when it shouldn't
+
+3.1.1-beta 1/9/96 - Released
+
+add better detection of TCP connections closing to TCP state monitoring.
+
+fr_addstate() not called correctly for fragments. "keep state" and
+"keep frag" code don't work together 100% - Songqing Cai
+(songqing_cai@sterling.com)
+
+call to fr_addstate() incorrect for adding state in combination with keeping
+fragment information - Songqing Cai (songqing_cai@sterling.com)
+
+KFREE() passed fp (incorrect) and not fr (correct) in ip_frag.c - John Hood
+(cgull@smoke.marlboro.vt.us)
+
+make ipf parser recognise '\\' as a `continued line' marker - Dima Ruban
+(dima@best.net)
+
+3.1.1-alpha 23/8/96 - Released
+
+kernel panic's when ICMP packets go through NAT code
+
+stats aren't zero'd properly with ipf -Z
+
+ipnat doesn't show port numbers correctly all the time and also add the
+protocol (tcp/udp/tcpudp) to rdr output - Carson Gaspar (carson@lehman.com)
+
+fast checksum fixing not 100% - backout patch - Bill Dorsey (dorsey@lila.com)
+
+NetBSD-1.2 patches from - VaX#n8 <vax@linkdead.paranoia.com>
+
+Usage() call error in fils.c - Ajay Shekhawat (ajay@cedar.buffalo.edu)
+
+ip_optcopy() staticly defined in ip_output.c in SunOS4 - Nick Hall
+(nrh@tardis.ed.ac.uk)
+
+3.1.0 7/7/96 - Released
+
+Reformatted ipnat output to be compatible with it's input, so that
+"ipnat -l | ipnat -rf -" is possible.
+
+3.1.0beta 30/6/96 - Released
+
+NetBSD-1.2 patches from Greg Woods (woods@most.weird.com)
+
+kernel module must not be installed stripped (Solaris2), as created by
+"make package" for Solaris2 - Peter Heimann
+(peter@i3.informatik.rwth-aachen.de)
+
+3.1.0alpha 5/6/96 - Released
+
+include examples in package for solaris2
+
+patches for removing an extra ip header checksum (FreeBSD/NetBSD/SunOS)
+
+removed trailing space from printouts of rules in ipf.
+
+ipresend supports the same range of inputs that ipftest does.
+
+sending a duplicate copy of a packet to another network devices is now
+supported. ("dup-to")
+
+sending a packet to an arbitary interface is now supported, irrespective
+of its actual route, with no ttl decrement. Can also be routed without
+the ttl being decremented. ("to" and "fastroute").
+
+"call" option added to support calling a generic function if a packet is
+matched.
+
+show all (upto 4) recorded bytes from the interface name in logging from
+ipmon.
+
+support for using unix file permissions for read/write access on the device
+is now in place.
+
+recursive mutex in nat_new() for Solaris 2.x - Per L. Hagen <per@stibo.dk>
+
+ipftest doesn't call initparse() for THISHOST - Catherine Allen
+(cla@connect.com.au)
+
+Man page corrections from Rex Bona (rex@pengo.comsmiths.com.au)
+
+3.0.4 10/4/96 - Released
+
+looop in `parsing' IP packets with optlen 0 for ip options.
+
+rule number not initialized and resulted in unexpected results for state
+maching.
+
+option parsing and printing bugs - Pradeep Krishnan
+
+3.0.4beta 25/3/96 - Released
+
+wouldn't parse "keep flags keep state" correctly.
+
+SunOS4.1.x ip_input.c doesn't recognise all 1s broadcast address - Nigel Verdon
+
+patches for BSDI's BSD/OS 2.1 and libpcap reader on little endian systems
+from Thorsten Lockert <tholo@tetherless.com>
+
+b* functions in fil.c on Solaris 2.4
+
+3.0.3 17/3/96 - Released
+
+added patches to support IP Filter initialisation when compiled into the
+kernel.
+
+added -x option to ipmon to display hex dumps of logged packets.
+
+added -H option to ipftest to allow ascii-hex formatted input to specify
+arbitary IP packets.
+
+Sending TCP RSTs as a response now work for Solaris2 x86
+
+add patches to make IP Filter compile into NetBSD kernels properly.
+
+patch to stop SunOS 4.1.x kernels panicing with "data traps".
+
+ipfboot script unloads and reloads ipf module on Solaris2 if it is already
+loaded into the kernel.
+
+Installation of IP Filter as a Solaris2 package is now supported.
+
+Man pages for ipnat.4, ipnat.5 added.
+
+added some more regression tests and fixed up IP Filter to pass the new tests
+(previous versions failed some of the tests in set 12).
+
+IP option filter processing has changed so that saying "with opt lsrr" will
+check only for that one, but not mask out other options, so a packet with
+strict source routing, along with loose source routing will match all of
+"with opt lsrr", "with opt ssrr" and "with opt lsrr,ssrr".
+
+IPL_NAME needed in ipnat.c - Kelly (kelly@count04.mry.scruznet.com)
+
+patches for clean NetBSD compilation from Bernd Ernesti (bernd@arresum.inka.de)
+
+make install is incorrect - Julian Briggs (julian@lightwork.co.uk)
+
+strtol() returns 0x7fffffff for all negative numbers,
+printfr() generates incorrect output for "opt sec-class *",
+handling of "not opt xxx opt yyy" incorrect.
+- Minh Tonthat (minht@sbei.com)/Pradeep Krishnan (pradeepk@sbei.com)
+
+m_pullup() called only for input and not output; caused problems
+with filtering icmp - Nigel Verdon (verdenn@gb.swissbank.com)
+
+parsing problem for "port 1" and NetBSD patches incorrect -
+Andreas Gustafsson (gson@guava.araneus.fi)
+
+3.0.2 4/2/96 - Released
+
+Corrected bug where NAT recalculates checksums for fragments.
+
+make NAT recalculate UDP checksums (rather than setting them to 0),
+if they're non-zero.
+
+DNS patches - Real Page (Real.Page@Matrox.com)
+
+alteration of checksum recalculations in NAT code and addition of
+redirection with NAT - Mike Neuman
+
+core dump, if tcp/udp is used with a port number and not service name,
+in ipf - Mike Neuman (mcn@engarde.com)
+
+initparse() call, missing to prime "<thishost>" hook - Craig Bishop
+
+3.0.1 14/1/96 - Released
+
+miscellaneous patches for Solaris2
+
+3.0 14/1/96 - Released
+
+Patch included for FDDI, from Richard Ohnemus
+(Richard_Ohnemus@dallas.csd.sterling.com)
+
+Code cleanup for release.
+
+3.0beta4 10/1/96
+
+recursive mutex in ipfr_slowtimer fixed, reported by Craig Bishop
+
+recursive mutex in sending TCP RSTs fixed, reported by Tony Becker
+
+3.0beta3 9/1/96
+
+FIxup for Solaris2.5 install and interface name bug in ipftest from
+Julian Briggs (julian@lightwork.co.uk)
+
+Byte order patches for ipmon from Tony Becker (tony@mcrsys.com)
+
+3.0beta2 7/1/96
+
+Added the (somewhat warped) IP accounting as it exists in ipfw on FreeBSD.
+Note, this isn't really what one would call IP account, when compared to
+process accounting, sigh.
+
+Split up ipresend into iptest/ipresend/ipsend
+
+Added another m_pullup() inside fr_check() for BSD style kernels and
+added some checks to ipllog() to not log more than is present (for short
+packets).
+
+Fixed bug where failed hostname/netname resolution goes undetecte and
+becomes 0.0.0.0 (any) (reported Guido van Rooij)
+
+3.0beta 11/11/95 - Released
+
+Rewrote the way rule testing is done, reducing the number of files needed and
+generated.
+
+SIOCIPFFL was incorrectly affected by IPFILTER_LOG (Mathew Green)
+
+Patches from Guido van Rooij to fix sending back TCP RSTs on Net-2/Net-3
+BSD based Unixes (panic'd)
+
+Patches for FreeBSD/i86 ipmon from Riku Kalinen <riku@tequila.nixu.fi>
+(I think someone else already told me about these but they got lost :-/)
+
+Changed Makefile structure to build object files for different operating
+systems in separate directories by default.
+
+BSDI has ef0 for first ethernet interface
+
+Allow for a "not" operator before optional keywords.
+
+The "rule number" was being incorrectly incremented every time it went through
+the loop rather than when it matched a rule.
+
+2.8.2 24/10/95 - Released
+
+Fixed up problems with "textip" for doing lots of testing.
+
+Fixed bug in detection of "short" tcp/ip packets (all reported as being short).
+
+Solaris 2.4 port now works 100%.
+
+Man page errors reported and fixed.
+
+Removed duplicate entry in etc/services for login on port 49 (Craig Bishop).
+
+Fixed ipmon output to put a space after the log-letter.
+
+Patch from Guido van Rooij to fix parsing problem.
+
+2.8.1 15/10/95 - Released
+
+Added ttl and tos filtering.
+
+Patches for fixing up compilation and port problems (little endian)
+from Guido van Rooij <guido@IAEhv.nl>.
+
+Man page problems reported and fixed by Carson Gaspar <carson@lehman.com>.
+
+ipsend doesn't compile properly on Solaris2.4
+
+Lots of work done for Solaris2.4 to make it MT/MP safe and work.
+
+2.8 15/9/95 - Released
+
+ipmon can now send messages to syslogd (-s) and use names instead of
+numbers (-N).
+
+IP packets are now "compiled" into a structure only containing filterable
+bits.
+
+Added regression testing in the test/ subdirectory, using a new option
+(-b) with the ipftest program.
+
+Added "nomatch" return to filter results. These are counted and show
+up in reports from ipfstat.
+
+Moved filter code out of ip_fil.c and into fil.c - there is now only one
+instance of it in the package.
+
+Added Solaris 2.4 support.
+
+Added IPSO basic security option filtering.
+
+Added name support for filtering on all 19 named IP options.
+
+Patches from Ivan Brawley to log packet contents as well as packet headers.
+
+Update for sun/conf.c.diff from Ivan Brawley <ibrawley@awadi.com.AU>
+
+Added patches for FreeBSD 1, and added two new switches (-E, -D) to ipf,
+along with a new ioctl, SIOCFRENB.
+From: Dieter Dworkin Muller <dworkin@village.org>
+
+2.7.3 31/7.95 - Released
+
+Didn't compile cleanly without IPFILTER_LOG defined (Mathew Green).
+
+ipftest now deals with tcpdump3 binary output files (from libpcap) with -P.
+
+Brought ipftest program upto date with actual filter code.
+
+Filter would cause a match to occur when it wasn't meant to if the packet
+had short headers and was missing portions that should have been there.
+Err, it would rightly not match on them, but their absence caused a match
+when it shouldn't have been.
+
+2.7.2 26/7/95 - Released
+
+Problem with filtering just SYN flagged packets reported by
+Dieter Dworkin Muller <dworkin@village.org>. To solve this
+problem, added support for masking TCP flags for comparison "flags X/Y".
+
+2.7.1 9/7/95 - Released
+
+Added ip_dirbroadcast support for Sun ip_input.c
+
+Fixed up the install scripts for FreeBSD/NetBSD to recognise where they are
+better.
+
+2.7 7/7/95 - Released
+
+Added "return-rst" to return TCP RST's to TCP packets.
+
+Actually ported it to FreeBSD-i386 2.0.0, so it works there properly now.
+
+Added insertion of filter rules. Use "@<#>" at the beginning of a filter
+to insert a rule at row #.
+
+Filter keeps track of how many times each rule is matched.
+
+Changed compile time things to match kernel option (IPFILTER_LKM &
+IPFILTER_LOG).
+
+Updated ip_input.c and ip_output.c with paches for 3.5 Multicast IP.
+(No change required for 3.6)
+
+Now includes TCP fragments which start inside the TCP header as being short.
+Added counting the number of times each rule is matched.
+
+
+2.6 11/5/95 - Released
+
+Added -n option to ipf: when supplied, no changes are made to the kernel.
+
+Added installation scripts for SunOS 4.1.x and NetBSD/FreeBSD/BSDI.
+
+Rewrote filtering to use a more generic mask & match procedure for
+checking if a packet matches a rule.
+
+2.5.2 27/4/95 - Released
+
+"tcp/udp" and a non-initialised pointer caused the "proto" to become
+a `random' value; added "ip#/dotted.mask" notation to the BNF.
+From Adam W. Feigin <feigin@iis.ee.ethz.ch>
+
+2.5.1 22/3/95 - Released
+
+"tcp/udp" had a strange effect (undesired) on getserv*() functions,
+causing protocol/service lookups to fail. Reported by Matthew Green.
+
+2.5 17/3/95 - Released
+
+Added a new keyword "all" to BNF and parsing of tcpdump/etherfind/snoop
+output through the ipftest program. Suggestions from:
+Michael Ciavarella (mikec@phyto.apana.org.au)
+
+Conflicts occur when "general" filter rules are used for ports and the
+lack of a "proto" when used with "port" matches other packets when only
+TCP/UDP are implied.
+Reported Matthew Green (mrg@fulcom.com.au);
+reported & fixed 6-8/3/95
+
+Added filtering of short TCP packets using "with short" 28/2/95
+(These can possibly slip by checks for the various flags). Short UDP
+or ICMP are dropped to the floor and logged.
+
+Added filtering of fragmented packets using "with frag" 24/2/95
+
+Port to NetBSD-current completed 20/2/95, using LKM.
+
+Added logging of the rule # which caused the logging to happen and the
+interface on which the packet is currently as suggested by
+Andreas Greulich (greulich@math-stat.unibe.ch) 10/2/95
+
+2.4 9/2/95 - Released
+Fixed saving of IP headers in ICMP packets.
+
+2.3 29/1/95
+Added ipf -F [in|out|all] to flush filter rule sets (SIOCIPFFL).
+Fixed iplread() and iplsave() with help from Marc Huber.
+
+2.2 7/1/95 - Released
+Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+its own major char number dynamically when modload'ing. Fixed up
+use of <, >, <=, >= and >< for ports.
+
+2.1 21/12/94 - Released
+repackaged to include the correct ip_output.c and ip_input.c *goof*
+
+2.0 18/12/94 - Released
+added code to check for port ranges - complete.
+rewrote to work as a loadable kernel module - complete.
+
+1.1
+added code for ouput filtering as well as input filtering and added support for logging to a simple character device of packet headers.
+
+1.0 22/04/93 - Released
+First release cut.
+
diff --git a/contrib/ipfilter/IMPORTANT b/contrib/ipfilter/IMPORTANT
new file mode 100644
index 0000000..00272f2
--- /dev/null
+++ b/contrib/ipfilter/IMPORTANT
@@ -0,0 +1,41 @@
+ ****************************************
+ IMPORTANT NOTICE
+ ****************************************
+1)
+
+If you're using this software and have a rule which ends like this:
+
+flags S
+
+(for TCP), then to make it totally effective, you need to change it to appear
+as follows:
+
+flags S/SA
+
+The problem is that the old code would compare all the TCP flags against the
+rule (which just has "S") to see if that matched exactly. It is very possible
+for this to not be the case and in these cases, the rule would fail to match
+a 'valid' TCP SYN packet.
+
+Why does it need to be "S/SA" and not "S/S" ?
+
+"S/S" will match the SYN-ACK as well the SYN.
+
+By defalt, "flags S" will now be converted to "flags S/AUPRFS".
+
+If you have any queries regarding this, see the examples and ipf(4).
+If you still have a query or suggestion, please email me.
+
+
+2)
+
+If a filter rule used, in combination port comparisons and the flags
+keywords, a "short" TCP packet, if not explicitly blocked high up in
+the list of packets, would actually get matched even though it would
+otherwise not have been (due to the ports not). This behaviour has
+subsequently been fixed.
+
+
+Darren
+darrenr@cyber.com.au
+ ****************************************
diff --git a/contrib/ipfilter/INSTALL.FreeBSD b/contrib/ipfilter/INSTALL.FreeBSD
new file mode 100644
index 0000000..3910f4d
--- /dev/null
+++ b/contrib/ipfilter/INSTALL.FreeBSD
@@ -0,0 +1,41 @@
+
+To build a kernel for use with the loadable kernel module, follow these
+steps:
+ 1. do "make bsd"
+
+ 2. do "make install-bsd"
+ (probably has to be done as root)
+
+ 3. run "FreeBSD/minstall" as root
+
+ 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. do "make bsd"
+
+ 2. do "make install-bsd"
+ (probably has to be done as root)
+
+ 3. run "FreeBSD/kinstall" as root
+
+ 4. build a new kernel
+
+ 5. create /dev/ipl with "mknod /dev/ipl c 20 0".
+
+ 6. install and reboot with the new kernel
+
+Darren Reed
+darrenr@cyber.com.au
diff --git a/contrib/ipfilter/INSTALL.NetBSD b/contrib/ipfilter/INSTALL.NetBSD
new file mode 100644
index 0000000..2387827
--- /dev/null
+++ b/contrib/ipfilter/INSTALL.NetBSD
@@ -0,0 +1,48 @@
+
+To build a kernel for use with the loadable kernel module, follow these
+steps:
+ 1. do "make bsd"
+
+ 2. do "make install-bsd"
+ (probably has to be done as root)
+
+ 3(a) NetBSD systems prior to 1.2:
+ run "NetBSD/minstall" as root
+ 3(b) NetBSD 1.2 systems or later:
+ run "NetBSD-1.2/minstall" as root
+
+ 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. do "make bsd"
+
+ 2. do "make install-bsd"
+ (probably has to be done as root)
+
+ 3(a) NetBSD systems prior to 1.2:
+ run "NetBSD/kinstall" as root
+ 3(b) NetBSD 1.2 systems or later:
+ run "NetBSD-1.2/kinstall" as root
+
+ 4. build a new kernel
+
+ 5. create /dev/ipl with "mknod /dev/ipl c 59 0".
+ (for NetBSD-1.2, use "mknod /dev/ipl c 49 0")
+
+ 6. install and reboot with the new kernel
+
+Darren Reed
+darrenr@cyber.com.au
diff --git a/contrib/ipfilter/INSTALL.Sol2 b/contrib/ipfilter/INSTALL.Sol2
new file mode 100644
index 0000000..6ed6473
--- /dev/null
+++ b/contrib/ipfilter/INSTALL.Sol2
@@ -0,0 +1,27 @@
+
+For those running Solaris 2.5, please read COMPILE.2.5 before building
+IP Filter.
+
+Type "make solaris" to build all the required binaries.
+
+Once IP Filter has been successfully compiled, you may then install it using
+the usual package method (using pkgadd), however, the package needs to be
+created, prior to pkgadd'ing. To create the package in /var/spoo/pkg, change
+directory to SunOS5 and enter the following command:
+
+make package
+
+If you wish to then install it using `pkgadd', run the following command:
+
+pkgadd -s '/var/spool/pkg'
+
+As part of the postinstall script, it will install loadable kernel module
+as part of Solaris 2 (using add_drv) making it available for immeadiate use.
+
+IP Filter will be installed into /opt/CYBSipf (programs, manual pages and
+examples) and create a directory /etc/opt/CYBSipf with a null body file
+called "ipf.conf" using touch. The rc scripts have been written to look
+for the configuration file here, using the installed binaries in /sbin.
+
+Darren Reed
+darrenr@cyber.com.au
diff --git a/contrib/ipfilter/INSTALL.SunOS b/contrib/ipfilter/INSTALL.SunOS
new file mode 100644
index 0000000..836d121
--- /dev/null
+++ b/contrib/ipfilter/INSTALL.SunOS
@@ -0,0 +1,36 @@
+
+To install as a Loadable Kernel Module (LKM):
+
+ 1. do a "make sunos4" in this directory
+
+ 2. Run the script "SunOS4/minstall" as root.
+
+ 3. change directory to SunOS4 and run "make install"
+
+ 4. Reboot using the new kernel
+
+ 5. use modload(8) to load the packet filter with:
+ modload if_ipl.o
+
+ 6. 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 install as part of a SunOS 4.1.x kernel:
+
+ 1. do a "make sunos4" in this directory
+
+ 2. Run the script "SunOS4/kinstall" as root.
+ NOTE: This script sets up /dev/ipl as char. device 59,0
+ in /sys/sun/conf.c
+
+ 3. Do "mknod /dev/ipl c 59 0" as root.
+
+ 4. Reboot using the new kernel
+
+Darren Reed
+darrenr@cyber.com.au
diff --git a/contrib/ipfilter/INSTALL.xBSD b/contrib/ipfilter/INSTALL.xBSD
new file mode 100644
index 0000000..9ab66f1
--- /dev/null
+++ b/contrib/ipfilter/INSTALL.xBSD
@@ -0,0 +1,39 @@
+
+To build a kernel for use with the loadable kernel module, follow these
+steps:
+ 1. do "make bsd"
+
+ 2. cd to the "BSD" directory and type "make install"
+
+ 3. run "4bsd/minstall" as root
+
+ 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. do "make bsd"
+
+ 2. cd to the "BSD" directory and type "make install"
+
+ 3. run "4bsd/kinstall" as root
+
+ 4. build a new kernel
+
+ 5. create /dev/ipl with "mknod /dev/ipl c 59 0".
+
+ 6. install and reboot with the new kernel
+
+Darren
+darrenr@cyber.com.au
diff --git a/contrib/ipfilter/LICENCE b/contrib/ipfilter/LICENCE
new file mode 100644
index 0000000..c5a7767
--- /dev/null
+++ b/contrib/ipfilter/LICENCE
@@ -0,0 +1,16 @@
+/*
+ * (C)opyright 1993, 1994, 1995 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 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * I hate legaleese, don't you ?
+ */
diff --git a/contrib/ipfilter/Makefile b/contrib/ipfilter/Makefile
new file mode 100644
index 0000000..d0d5309
--- /dev/null
+++ b/contrib/ipfilter/Makefile
@@ -0,0 +1,158 @@
+#
+# (C)opyright 1993, 1994, 1995 by Darren Reed.
+#
+# 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 ?
+#
+# $Id: Makefile,v 2.0.1.4 1997/02/08 06:39:28 darrenr Exp $
+#
+# where to put things.
+#
+BINDEST=/usr/local/ip_fil3.1.1/bin
+SBINDEST=/usr/local/ip_fil3.1.1/sbin
+MANDIR=/usr/local/ip_fil3.1.1/man
+CC=gcc
+DEBUG=-g
+CFLAGS=-I$$(TOP)
+DCPU=`uname -m`
+#
+# To enable this to work as a Loadable Kernel Module...
+#
+IPFLKM=-DIPFILTER_LKM
+#
+# To enable logging of blocked/passed packets...
+#
+IPFLOG=-DIPFILTER_LOG
+#
+# The facility you wish to log messages from ipmon to syslogd with.
+#
+LOGFAC=-DLOGFAC=LOG_LOCAL0
+#
+# For packets which don't match any pass rules or any block rules, set either
+# FR_PASS or FR_BLOCK (respectively). It defaults to FR_PASS if left
+# undefined. This is ignored for ipftest, which can thus return three
+# results: pass, block and nomatch. This is the sort of "block unless
+# explicitly allowed" type #define switch.
+#
+POLICY=-DNOMATCH=FR_PASS
+#
+MFLAGS="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" \
+ "CC=$(CC)" 'CFLAGS=$(CFLAGS) $(SOLARIS2)' "IPFLKM=$(IPFLKM)" \
+ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \
+ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "ARCH=$(ARCH)"
+#
+########## ########## ########## ########## ########## ########## ##########
+#
+CP=/bin/cp
+RM=/bin/rm
+CHMOD=/bin/chmod
+INSTALL=install
+#
+DFLAGS=$(IPFLKM) $(IPFLOG) $(DEF)
+
+all:
+ @echo "Chose one of the following targets for making IP filter:"
+ @echo ""
+ @echo "solaris - auto-selects SunOS4.1.x/Solaris 2.[45]/Soalris2.[45]-x86"
+ @echo "bsd - compile for 4.4BSD based Unixes (FreeBSD/NetBSD/OpenBSD)"
+ @echo "bsdi - compile for BSD/OS"
+ @echo ""
+
+tests:
+ @if [ -d test ]; then (cd test; make) \
+ else echo test directory not present, sorry; fi
+
+sunos solaris:
+ ./buildsunos
+
+sunos4 solaris1:
+ (cd SunOS4; make build TOP=.. $(MFLAGS); cd ..)
+ (cd SunOS4; make -f Makefile.ipsend TOP=.. $(MFLAGS); cd ..)
+
+sunos5 solaris2:
+ (cd SunOS5/$(DCPU); make build TOP=../.. $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Dsparc -D__sparc__"; cd ..)
+ (cd SunOS5/$(DCPU); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..)
+
+sunos5x86 solaris2x86:
+ (cd SunOS5/$(DCPU); make build TOP=../.. $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Di86pc -Di386 -D__i386__"; cd ..)
+ (cd SunOS5/$(DCPU); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..)
+
+bsd netbsd freebsd:
+ -if [ ! -d BSD/$(DCPU) ] ; then mkdir BSD/$(DCPU); fi
+ -rm -f BSD/$(DCPU)/Makefile BSD/$(DCPU)/Makefile.ipsend
+ -ln -s ../Makefile BSD/$(DCPU)/Makefile
+ -ln -s ../Makefile.ipsend BSD/$(DCPU)/Makefile.ipsend
+ (cd BSD/$(DCPU); make build "TOP=../.." $(MFLAGS); cd ..)
+ (cd BSD/$(DCPU); make -f Makefile.ipsend "TOP=../.." $(MFLAGS); cd ..)
+
+bsdi bsdos:
+ -if [ ! -d BSD/$(DCPU) ] ; then mkdir BSD/$(DCPU); fi
+ -rm -f BSD/$(DCPU)/Makefile BSD/$(DCPU)/Makefile.ipsend
+ -ln -s ../Makefile BSD/$(DCPU)/Makefile
+ -ln -s ../Makefile.ipsend BSD/$(DCPU)/Makefile.ipsend
+ (cd BSD/$(DCPU); make build "TOP=../.." $(MFLAGS) LKM= ; cd ..)
+ (cd BSD/$(DCPU); make -f Makefile.ipsend "TOP=../.." $(MFLAGS); cd ..)
+
+clean:
+ ${RM} -f core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl \
+ vnode_if.h $(LKM)
+ (cd SunOS4; make clean)
+ (cd SunOS5; make clean)
+ (cd BSD; make clean)
+ [ -d test ] && (cd test; make clean)
+ (cd ipsend; make clean)
+
+clean-bsd:
+ (cd BSD; make clean)
+
+clean-sunos4:
+ (cd SunOS4; make clean)
+
+clean-sunos5:
+ (cd SunOS5; make clean)
+
+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
+
+install-bsd: bsd
+ (cd BSD/$(DCPU); $(MAKE) "TOP=../.." install)
+install-sunos4: solaris
+ (cd SunOS4; $(MAKE) "TOP=.." install)
+install-sunos5: solaris
+ (cd SunOS5; $(MAKE) "TOP=.." install)
+
+# XXX FIXME: bogus to depend on all!
+install: all ip_fil.h
+ -$(CP) ip_fil.h /usr/include/netinet/ip_fil.h
+ -$(CHMOD) 444 /usr/include/netinet/ip_fil.h
+ -$(INSTALL) -cs -g wheel -m 755 -o root ipfstat ipf ipnat $(SBINDEST)
+ -$(INSTALL) -cs -g wheel -m 755 -o root ipmon ipftest $(BINDEST)
+ (cd man; $(MAKE) INSTALL=$(INSTALL) MANDIR=$(MANDIR) install; cd ..)
+
+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
+
+do-cvs:
+ find . -type d -name CVS -print | xargs /bin/rm -rf
+ find . -type f -name .cvsignore -print | xargs /bin/rm -f
diff --git a/contrib/ipfilter/README b/contrib/ipfilter/README
new file mode 100644
index 0000000..b959d40
--- /dev/null
+++ b/contrib/ipfilter/README
@@ -0,0 +1,93 @@
+IP Filter - What's this about ?
+============================
+
+ The idea behind this package is allow those who use Unix workstations as
+routers (a common occurance in Universities it appears) to apply packet
+filtering to packets going in and out of them. This package has been
+tested on all versions of SunOS 4.1 and Solaris 2.4/2.5, running on Sparcs.
+It is also quite possible for this small kernel extension to be installed
+and used effectively on Sun workstations which don't route IP, just for
+added security. It can also be integrated with the multicast patches.
+It has also been tested successfully on all of the modern free BSDs as
+well as BSDI.
+
+ The filter keeps a rule list for both inbound and outbound sides of
+the IP packet queue and a check is made as early as possible, aiming to
+stop the packet before it even gets as far as being checked for source
+route options. In the file "BNF", a set of rules for constructing filter
+rules understood by this package is given. The files in the directory
+"rules", "example.1" ... "example.sr" show example rules you might apply.
+
+ In practise, I've successfully isolated a workstation from all
+machines except the NFS file servers on its local subnets (yeah, ok, so
+this doesn't really increase security, because of NFS, but you get the
+drift on how it can be applied and used). I've also successfully
+setup and maintained my own firewalls using it with TIS's Firewall Toolkit,
+including using it on an mbone router.
+
+ When using it with multicast IP, the calls to fr_check() should be
+before the packet is unwrapped and after it is encapsulated. So the
+filter routines will see the packet as a UDP packet, protocol XYZ.
+Whether this is better or worse than having it filter on class D addresses
+is debateable, but the idea behind this package is to be able to
+discriminate between packets as they are on the 'wire', before they
+get routed anywhere, etc.
+
+ It is worth noting, that it is possible, using a small MTU and
+generating tiny fragmented IP packets to generate a TCP packet which
+doesn't contain enough information to filter on the "flags". Filtering
+on these types of packets is possible, but under the more general case
+of the packets being "short". ICMP and UDP packets which are too small
+(they don't contain a complete header) are dropped and logged, no questions
+asked. When filtering on fragmented packets, the last fragment will get
+through for TCP/UDP/ICMP packets.
+
+
+Some general notes.
+-------------------
+ To add/delete a rule from memory, access to the device in /dev is needed,
+allowing non-root maintenaince. The filter list in kernel memory is built
+from the kernel's heap. Each packet coming *in* or *out* is checked against
+the appropriate list, rejects dropped, others passed through. Thus this will
+work on an individual host, not just gateways. Presently there is only one
+list for all interfaces, the changes required to make it a per-interface list
+require more .o replacements for the kernel. When checking a packet, the
+packet is compared to the entire list from top to bottom, the last matching
+line being effective.
+
+
+What does what ?
+----------------
+if_fil.o (Loadable kernel module)
+ - additional kernel routines to check an access list as to whether
+ or not to drop or pass a packet. It currently defaults to pass
+ on all packets.
+
+ipfstat
+ - digs through your kernel (need to check #define VMUNIX in fils.c)
+ and /dev/kmem for the access filter list and mini stats table.
+ Obviously needs to be run priviledged if required.
+
+ipf
+ - reads the files passed as parameters as input files containing new
+ filter rules to add/delete to the kernel list. The lines are
+ inserted in order; the first line is inserted first, and ends up
+ first on the list. Subsequent invocations append to the list
+ unless specified otherwise.
+
+ipftest
+ - test the ruleset given by filename. Reads in the ruleset and then
+ waits for stdin.
+
+ See the man pages (ipf.1, ipftest.1, ipfstat.8) for more detailed
+ information on what the above do.
+
+mkfilters
+ - suggests a set of filter rules to employ and suggests how to add
+ routes to back these up.
+
+BNF
+ - BNF rule set for the filter rules
+
+Darren Reed
+darrenr@cyber.com.au
diff --git a/contrib/ipfilter/bsdinstall b/contrib/ipfilter/bsdinstall
new file mode 100755
index 0000000..ce921b6
--- /dev/null
+++ b/contrib/ipfilter/bsdinstall
@@ -0,0 +1,83 @@
+#! /bin/sh
+#
+# @(#)install.sh 4.5 (Berkeley) 10/12/83
+#
+cmd=/bin/mv
+strip=""
+chmod="chmod 755"
+chown="chown -f root"
+chgrp="chgrp -f bin"
+while true ; do
+ case $1 in
+ -s ) strip="strip"
+ shift
+ ;;
+ -c ) cmd="cp"
+ shift
+ ;;
+ -m ) chmod="chmod $2"
+ shift
+ shift
+ ;;
+ -o ) chown="chown -f $2"
+ shift
+ shift
+ ;;
+ -g ) chgrp="chgrp -f $2"
+ shift
+ shift
+ ;;
+ -d ) cmd="mkdir"
+ shift
+ ;;
+ * ) break
+ ;;
+ esac
+done
+
+if [ ! ${2-""} ]
+then echo "install: no destination specified"
+ exit 1
+fi
+if [ ${3-""} ]
+then echo "install: too many files specified -> $*"
+ exit 1
+fi
+if [ $1 = $2 -o $2 = . ]
+then echo "install: can't move $1 onto itself"
+ exit 1
+fi
+case $cmd in
+/bin/mkdir )
+ file=$2/$1
+ ;;
+* )
+ if [ '!' -f $1 ]
+ then echo "install: can't open $1"
+ exit 1
+ fi
+ if [ -d $2 ]
+ then file=$2/$1
+ else file=$2
+ fi
+ /bin/rm -f $file
+ ;;
+esac
+
+case $cmd in
+/bin/mkdir )
+ if [ ! -d "$file" ]
+ then $cmd $file
+ fi
+ ;;
+* )
+ $cmd $1 $file
+ if [ $strip ]
+ then $strip $file
+ fi
+ ;;
+esac
+
+$chown $file
+$chgrp $file
+$chmod $file
diff --git a/contrib/ipfilter/buildsunos b/contrib/ipfilter/buildsunos
new file mode 100755
index 0000000..dd2aa38
--- /dev/null
+++ b/contrib/ipfilter/buildsunos
@@ -0,0 +1,23 @@
+#! /bin/sh
+# $Id: buildsunos,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp $
+:
+rev=`uname -r | sed -e 's/^\([^\.]*\)\..*/\1/'`
+cpu=`uname -m`
+if [ $rev = 5 ] ; then
+ solrev=`uname -r | sed -e 's/^\([0-9]*\)\.\([0-9]*\)$/\2/'`
+ mkdir -p SunOS5/${cpu}
+ /bin/rm -f SunOS5/${cpu}/Makefile
+ /bin/rm -f SunOS5/${cpu}/Makefile.ipsend
+ ln -s ../Makefile SunOS5/${cpu}/Makefile
+ ln -s ../Makefile.ipsend SunOS5/${cpu}/Makefile.ipsend
+fi
+if [ $cpu = i86pc ] ; then
+ make ${1+"$@"} sunos5x86 SOLARIS2="-DSOLARIS2=$solrev" DCPU=${cpu}
+ exit $?
+fi
+if [ x$solrev = x ] ; then
+ make ${1+"$@"} sunos$rev "ARCH=`uname -m`"
+ exit $?
+fi
+make ${1+"$@"} sunos$rev SOLARIS2="-DSOLARIS2=$solrev" DCPU=${cpu}
+exit $?
diff --git a/contrib/ipfilter/etc/protocols b/contrib/ipfilter/etc/protocols
new file mode 100644
index 0000000..b41aa1d
--- /dev/null
+++ b/contrib/ipfilter/etc/protocols
@@ -0,0 +1,95 @@
+icmp 1 ICMP # Internet Control Message
+igmp 2 IGMP # Internet Group Management
+ggp 3 GGP # Gateway-to-Gateway
+ip 4 IP # IP in IP (encasulation)
+st 5 ST # Stream
+tcp 6 TCP # Transmission Control
+ucl 7 UCL # UCL
+egp 8 EGP # Exterior Gateway Protocol
+igp 9 IGP # any private interior gateway
+bbn-rcc-mon 10 BBN-RCC-MON # BBN RCC Monitoring
+nvp-ii 11 NVP-II # Network Voice Protocol
+pup 12 PUP # PUP
+argus 13 ARGUS # ARGUS
+emcon 14 EMCON # EMCON
+xnet 15 XNET # Cross Net Debugger
+chaos 16 CHAOS # Chaos
+udp 17 UDP # User Datagram
+mux 18 MUX # Multiplexing
+dcn-meas 19 DCN-MEAS # DCN Measurement Subsystems
+hmp 20 HMP # Host Monitoring
+prm 21 PRM # Packet Radio Measurement
+xns-idp 22 XNS-IDP # XEROX NS IDP
+trunk-1 23 TRUNK-1 # Trunk-1
+trunk-2 24 TRUNK-2 # Trunk-2
+leaf-1 25 LEAF-1 # Leaf-1
+leaf-2 26 LEAF-2 # Leaf-2
+rdp 27 RDP # Reliable Data Protocol
+irtp 28 IRTP # Internet Reliable Transaction
+iso-tp4 29 ISO-TP4 # ISO Transport Protocol Class 4
+netblt 30 NETBLT # Bulk Data Transfer Protocol
+mfe-nsp 31 MFE-NSP # MFE Network Services Protocol
+merit-inp 32 MERIT-INP # MERIT Internodal Protocol
+sep 33 SEP # Sequential Exchange Protocol
+3pc 34 3PC # Third Party Connect Protocol
+idpr 35 IDPR # Inter-Domain Policy Routing Protocol
+xtp 36 XTP # XTP
+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
+sip 41 SIP # Simple Internet Protocol
+sdrp 42 SDRP # Source Demand Routing Protocol
+sip-sr 43 SIP-SR # SIP Source Route
+sip-frag 44 SIP-FRAG # SIP Fragment
+idrp 45 IDRP # Inter-Domain Routing Protocol
+rsvp 46 RSVP # Reservation Protocol
+gre 47 GRE # General Routing Encapsulation
+mhrp 48 MHRP # Mobile Host Routing Protocol
+bna 49 BNA # BNA
+sipp-esp 50 SIPP-ESP # SIPP Encap Security Payload
+sipp-ah 51 SIPP-AH # SIPP Authentication Header
+i-nlsp 52 I-NLSP # Integrated Net Layer Security TUBA
+swipe 53 SWIPE # IP with Encryption
+nhrp 54 NHRP # NBMA Next Hop Resolution Protocol
+any 61 any # host internal protocol
+cftp 62 CFTP # CFTP
+any 63 any # local network
+sat-expak 64 SAT-EXPAK # SATNET and Backroom EXPAK
+kryptolan 65 KRYPTOLAN # Kryptolan
+rvd 66 RVD # MIT Remote Virtual Disk Protocol
+ippc 67 IPPC # Internet Pluribus Packet Core
+any 68 any # distributed file system
+sat-mon 69 SAT-MON # SATNET Monitoring
+visa 70 VISA # VISA Protocol
+ipcv 71 IPCV # Internet Packet Core Utility
+cpnx 72 CPNX # Computer Protocol Network Executive
+cphb 73 CPHB # Computer Protocol Heart Beat
+wsn 74 WSN # Wang Span Network
+pvp 75 PVP # Packet Video Protocol
+br-sat-mon 76 BR-SAT-MON # Backroom SATNET Monitoring
+sun-nd 77 SUN-ND # SUN ND PROTOCOL-Temporary
+wb-mon 78 WB-MON # WIDEBAND Monitoring
+wb-expak 79 WB-EXPAK # WIDEBAND EXPAK
+iso-ip 80 ISO-IP # ISO Internet Protocol
+vmtp 81 VMTP # VMTP
+secure-vmtp 82 SECURE-VMTP # SECURE-VMTP
+vines 83 VINES # VINES
+ttp 84 TTP # TTP
+nsfnet-igp 85 NSFNET-IGP # NSFNET-IGP
+dgp 86 DGP # Dissimilar Gateway Protocol
+tcf 87 TCF # TCF
+igrp 88 IGRP # IGRP
+ospfigp 89 OSPFIGP # OSPFIGP
+sprite-rpc 90 Sprite-RPC # Sprite RPC Protocol
+larp 91 LARP # Locus Address Resolution Protocol
+mtp 92 MTP # Multicast Transport Protocol
+ax.25 93 AX.25 # AX.25 Frames
+ipip 94 IPIP # IP-within-IP Encapsulation Protocol
+micp 95 MICP # Mobile Internetworking Control Pro.
+scc-sp 96 SCC-SP # Semaphore Communications Sec. Pro.
+etherip 97 ETHERIP # Ethernet-within-IP Encapsulation
+encap 98 ENCAP # Encapsulation Header
+any 99 any # private encryption scheme
+gmtp 100 GMTP # GMTP
+reserved 255 Reserved #
diff --git a/contrib/ipfilter/etc/services b/contrib/ipfilter/etc/services
new file mode 100644
index 0000000..90dd07a
--- /dev/null
+++ b/contrib/ipfilter/etc/services
@@ -0,0 +1,731 @@
+tcpmux 1/tcp # TCP Port Service Multiplexer
+tcpmux 1/udp # TCP Port Service Multiplexer
+compressnet 2/tcp # Management Utility
+compressnet 2/udp # Management Utility
+compressnet 3/tcp # Compression Process
+compressnet 3/udp # Compression Process
+rje 5/tcp # Remote Job Entry
+rje 5/udp # Remote Job Entry
+echo 7/tcp # Echo
+echo 7/udp # Echo
+discard 9/tcp # Discard
+discard 9/udp # Discard
+systat 11/tcp # Active Users
+systat 11/udp # Active Users
+daytime 13/tcp # Daytime
+daytime 13/udp # Daytime
+qotd 17/tcp # Quote of the Day
+qotd 17/udp # Quote of the Day
+msp 18/tcp # Message Send Protocol
+msp 18/udp # Message Send Protocol
+chargen 19/tcp # Character Generator
+chargen 19/udp # Character Generator
+ftp-data 20/tcp # File Transfer
+ftp-data 20/udp # File Transfer
+ftp 21/tcp # File Transfer
+ftp 21/udp # File Transfer
+telnet 23/tcp # Telnet
+telnet 23/udp # Telnet
+smtp 25/tcp # Simple Mail Transfer
+smtp 25/udp # Simple Mail Transfer
+nsw-fe 27/tcp # NSW User System FE
+nsw-fe 27/udp # NSW User System FE
+msg-icp 29/tcp # MSG ICP
+msg-icp 29/udp # MSG ICP
+msg-auth 31/tcp # MSG Authentication
+msg-auth 31/udp # MSG Authentication
+dsp 33/tcp # Display Support Protocol
+dsp 33/udp # Display Support Protocol
+time 37/tcp # Time
+time 37/udp # Time
+rap 38/tcp # Route Access Protocol
+rap 38/udp # Route Access Protocol
+rlp 39/tcp # Resource Location Protocol
+rlp 39/udp # Resource Location Protocol
+graphics 41/tcp # Graphics
+graphics 41/udp # Graphics
+nameserver 42/tcp # Host Name Server
+nameserver 42/udp # Host Name Server
+nicname 43/tcp # Who Is
+nicname 43/udp # Who Is
+mpm-flags 44/tcp # MPM FLAGS Protocol
+mpm-flags 44/udp # MPM FLAGS Protocol
+mpm 45/tcp # Message Processing Module
+mpm 45/udp # Message Processing Module
+mpm-snd 46/tcp # MPM
+mpm-snd 46/udp # MPM
+ni-ftp 47/tcp # NI FTP
+ni-ftp 47/udp # NI FTP
+auditd 48/tcp # Digital Audit Daemon
+auditd 48/udp # Digital Audit Daemon
+re-mail-ck 50/tcp # Remote Mail Checking Protocol
+re-mail-ck 50/udp # Remote Mail Checking Protocol
+la-maint 51/tcp # IMP Logical Address Maintenance
+la-maint 51/udp # IMP Logical Address Maintenance
+xns-time 52/tcp # XNS Time Protocol
+xns-time 52/udp # XNS Time Protocol
+domain 53/tcp # Domain Name Server
+domain 53/udp # Domain Name Server
+xns-ch 54/tcp # XNS Clearinghouse
+xns-ch 54/udp # XNS Clearinghouse
+isi-gl 55/tcp # ISI Graphics Language
+isi-gl 55/udp # ISI Graphics Language
+xns-auth 56/tcp # XNS Authentication
+xns-auth 56/udp # XNS Authentication
+xns-mail 58/tcp # XNS Mail
+xns-mail 58/udp # XNS Mail
+ni-mail 61/tcp # NI MAIL
+ni-mail 61/udp # NI MAIL
+acas 62/tcp # ACA Services
+acas 62/udp # ACA Services
+covia 64/tcp # Communications Integrator (CI)
+covia 64/udp # Communications Integrator (CI)
+tacacs-ds 65/tcp # TACACS-Database Service
+tacacs-ds 65/udp # TACACS-Database Service
+sql*net 66/tcp # Oracle SQL*NET
+sql*net 66/udp # Oracle SQL*NET
+bootps 67/tcp # Bootstrap Protocol Server
+bootps 67/udp # Bootstrap Protocol Server
+bootpc 68/tcp # Bootstrap Protocol Client
+bootpc 68/udp # Bootstrap Protocol Client
+tftp 69/tcp # Trivial File Transfer
+tftp 69/udp # Trivial File Transfer
+gopher 70/tcp # Gopher
+gopher 70/udp # Gopher
+netrjs-1 71/tcp # Remote Job Service
+netrjs-1 71/udp # Remote Job Service
+netrjs-2 72/tcp # Remote Job Service
+netrjs-2 72/udp # Remote Job Service
+netrjs-3 73/tcp # Remote Job Service
+netrjs-3 73/udp # Remote Job Service
+netrjs-4 74/tcp # Remote Job Service
+netrjs-4 74/udp # Remote Job Service
+deos 76/tcp # Distributed External Object Store
+deos 76/udp # Distributed External Object Store
+vettcp 78/tcp # vettcp
+vettcp 78/udp # vettcp
+finger 79/tcp # Finger
+finger 79/udp # Finger
+www-http 80/tcp # World Wide Web HTTP
+www-http 80/udp # World Wide Web HTTP
+hosts2-ns 81/tcp # HOSTS2 Name Server
+hosts2-ns 81/udp # HOSTS2 Name Server
+xfer 82/tcp # XFER Utility
+xfer 82/udp # XFER Utility
+mit-ml-dev 83/tcp # MIT ML Device
+mit-ml-dev 83/udp # MIT ML Device
+ctf 84/tcp # Common Trace Facility
+ctf 84/udp # Common Trace Facility
+mit-ml-dev 85/tcp # MIT ML Device
+mit-ml-dev 85/udp # MIT ML Device
+mfcobol 86/tcp # Micro Focus Cobol
+mfcobol 86/udp # Micro Focus Cobol
+kerberos 88/tcp # Kerberos
+kerberos 88/udp # Kerberos
+su-mit-tg 89/tcp # SU/MIT Telnet Gateway
+su-mit-tg 89/udp # SU/MIT Telnet Gateway
+dnsix 90/tcp # DNSIX Securit Attribute Token Map
+dnsix 90/udp # DNSIX Securit Attribute Token Map
+mit-dov 91/tcp # MIT Dover Spooler
+mit-dov 91/udp # MIT Dover Spooler
+npp 92/tcp # Network Printing Protocol
+npp 92/udp # Network Printing Protocol
+dcp 93/tcp # Device Control Protocol
+dcp 93/udp # Device Control Protocol
+objcall 94/tcp # Tivoli Object Dispatcher
+objcall 94/udp # Tivoli Object Dispatcher
+supdup 95/tcp # SUPDUP
+supdup 95/udp # SUPDUP
+dixie 96/tcp # DIXIE Protocol Specification
+dixie 96/udp # DIXIE Protocol Specification
+swift-rvf 97/tcp # Swift Remote Vitural File Protocol
+swift-rvf 97/udp # Swift Remote Vitural File Protocol
+tacnews 98/tcp # TAC News
+tacnews 98/udp # TAC News
+metagram 99/tcp # Metagram Relay
+metagram 99/udp # Metagram Relay
+newacct 100/tcp
+hostname 101/tcp # NIC Host Name Server
+hostname 101/udp # NIC Host Name Server
+iso-tsap 102/tcp # ISO-TSAP
+iso-tsap 102/udp # ISO-TSAP
+gppitnp 103/tcp # Genesis Point-to-Point Trans Net
+gppitnp 103/udp # Genesis Point-to-Point Trans Net
+acr-nema 104/tcp # ACR-NEMA Digital Imag. & Comm. 300
+acr-nema 104/udp # ACR-NEMA Digital Imag. & Comm. 300
+csnet-ns 105/tcp # Mailbox Name Nameserver
+csnet-ns 105/udp # Mailbox Name Nameserver
+3com-tsmux 106/tcp # 3COM-TSMUX
+3com-tsmux 106/udp # 3COM-TSMUX
+rtelnet 107/tcp # Remote Telnet Service
+rtelnet 107/udp # Remote Telnet Service
+snagas 108/tcp # SNA Gateway Access Server
+snagas 108/udp # SNA Gateway Access Server
+pop2 109/tcp # Post Office Protocol - Version 2
+pop2 109/udp # Post Office Protocol - Version 2
+pop3 110/tcp # Post Office Protocol - Version 3
+pop3 110/udp # Post Office Protocol - Version 3
+sunrpc 111/tcp # SUN Remote Procedure Call
+sunrpc 111/udp # SUN Remote Procedure Call
+mcidas 112/tcp # McIDAS Data Transmission Protocol
+mcidas 112/udp # McIDAS Data Transmission Protocol
+auth 113/tcp # Authentication Service
+auth 113/udp # Authentication Service
+audionews 114/tcp # Audio News Multicast
+audionews 114/udp # Audio News Multicast
+sftp 115/tcp # Simple File Transfer Protocol
+sftp 115/udp # Simple File Transfer Protocol
+ansanotify 116/tcp # ANSA REX Notify
+ansanotify 116/udp # ANSA REX Notify
+uucp-path 117/tcp # UUCP Path Service
+uucp-path 117/udp # UUCP Path Service
+sqlserv 118/tcp # SQL Services
+sqlserv 118/udp # SQL Services
+nntp 119/tcp # Network News Transfer Protocol
+nntp 119/udp # Network News Transfer Protocol
+cfdptkt 120/tcp # CFDPTKT
+cfdptkt 120/udp # CFDPTKT
+erpc 121/tcp # Encore Expedited Remote Pro.Call
+erpc 121/udp # Encore Expedited Remote Pro.Call
+smakynet 122/tcp # SMAKYNET
+smakynet 122/udp # SMAKYNET
+ntp 123/tcp # Network Time Protocol
+ntp 123/udp # Network Time Protocol
+ansatrader 124/tcp # ANSA REX Trader
+ansatrader 124/udp # ANSA REX Trader
+locus-map 125/tcp # Locus PC-Interface Net Map Ser
+locus-map 125/udp # Locus PC-Interface Net Map Ser
+unitary 126/tcp # Unisys Unitary Login
+unitary 126/udp # Unisys Unitary Login
+locus-con 127/tcp # Locus PC-Interface Conn Server
+locus-con 127/udp # Locus PC-Interface Conn Server
+gss-xlicen 128/tcp # GSS X License Verification
+gss-xlicen 128/udp # GSS X License Verification
+pwdgen 129/tcp # Password Generator Protocol
+pwdgen 129/udp # Password Generator Protocol
+cisco-fna 130/tcp # cisco FNATIVE
+cisco-fna 130/udp # cisco FNATIVE
+cisco-tna 131/tcp # cisco TNATIVE
+cisco-tna 131/udp # cisco TNATIVE
+cisco-sys 132/tcp # cisco SYSMAINT
+cisco-sys 132/udp # cisco SYSMAINT
+statsrv 133/tcp # Statistics Service
+statsrv 133/udp # Statistics Service
+ingres-net 134/tcp # INGRES-NET Service
+ingres-net 134/udp # INGRES-NET Service
+loc-srv 135/tcp # Location Service
+loc-srv 135/udp # Location Service
+profile 136/tcp # PROFILE Naming System
+profile 136/udp # PROFILE Naming System
+netbios-ns 137/tcp # NETBIOS Name Service
+netbios-ns 137/udp # NETBIOS Name Service
+netbios-dgm 138/tcp # NETBIOS Datagram Service
+netbios-dgm 138/udp # NETBIOS Datagram Service
+netbios-ssn 139/tcp # NETBIOS Session Service
+netbios-ssn 139/udp # NETBIOS Session Service
+emfis-data 140/tcp # EMFIS Data Service
+emfis-data 140/udp # EMFIS Data Service
+emfis-cntl 141/tcp # EMFIS Control Service
+emfis-cntl 141/udp # EMFIS Control Service
+bl-idm 142/tcp # Britton-Lee IDM
+bl-idm 142/udp # Britton-Lee IDM
+imap2 143/tcp # Interim Mail Access Protocol v2
+imap2 143/udp # Interim Mail Access Protocol v2
+news 144/tcp # NewS
+news 144/udp # NewS
+uaac 145/tcp # UAAC Protocol
+uaac 145/udp # UAAC Protocol
+iso-tp0 146/tcp # ISO-IP0
+iso-tp0 146/udp # ISO-IP0
+iso-ip 147/tcp # ISO-IP
+iso-ip 147/udp # ISO-IP
+cronus 148/tcp # CRONUS-SUPPORT
+cronus 148/udp # CRONUS-SUPPORT
+aed-512 149/tcp # AED 512 Emulation Service
+aed-512 149/udp # AED 512 Emulation Service
+sql-net 150/tcp # SQL-NET
+sql-net 150/udp # SQL-NET
+hems 151/tcp # HEMS
+hems 151/udp # HEMS
+bftp 152/tcp # Background File Transfer Program
+bftp 152/udp # Background File Transfer Program
+sgmp 153/tcp # SGMP
+sgmp 153/udp # SGMP
+netsc-prod 154/tcp # NETSC
+netsc-prod 154/udp # NETSC
+netsc-dev 155/tcp # NETSC
+netsc-dev 155/udp # NETSC
+sqlsrv 156/tcp # SQL Service
+sqlsrv 156/udp # SQL Service
+knet-cmp 157/tcp # KNET/VM Command/Message Protocol
+knet-cmp 157/udp # KNET/VM Command/Message Protocol
+pcmail-srv 158/tcp # PCMail Server
+pcmail-srv 158/udp # PCMail Server
+nss-routing 159/tcp # NSS-Routing
+nss-routing 159/udp # NSS-Routing
+sgmp-traps 160/tcp # SGMP-TRAPS
+sgmp-traps 160/udp # SGMP-TRAPS
+snmp 161/tcp # SNMP
+snmp 161/udp # SNMP
+snmptrap 162/tcp # SNMPTRAP
+snmptrap 162/udp # SNMPTRAP
+cmip-man 163/tcp # CMIP/TCP Manager
+cmip-man 163/udp # CMIP/TCP Manager
+cmip-agent 164/tcp # CMIP/TCP Agent
+smip-agent 164/udp # CMIP/TCP Agent
+xns-courier 165/tcp # Xerox
+xns-courier 165/udp # Xerox
+s-net 166/tcp # Sirius Systems
+s-net 166/udp # Sirius Systems
+namp 167/tcp # NAMP
+namp 167/udp # NAMP
+rsvd 168/tcp # RSVD
+rsvd 168/udp # RSVD
+send 169/tcp # SEND
+send 169/udp # SEND
+print-srv 170/tcp # Network PostScript
+print-srv 170/udp # Network PostScript
+multiplex 171/tcp # Network Innovations Multiplex
+multiplex 171/udp # Network Innovations Multiplex
+cl/1 172/tcp # Network Innovations CL/1
+cl/1 172/udp # Network Innovations CL/1
+xyplex-mux 173/tcp # Xyplex
+xyplex-mux 173/udp # Xyplex
+mailq 174/tcp # MAILQ
+mailq 174/udp # MAILQ
+vmnet 175/tcp # VMNET
+vmnet 175/udp # VMNET
+genrad-mux 176/tcp # GENRAD-MUX
+genrad-mux 176/udp # GENRAD-MUX
+xdmcp 177/tcp # X Display Manager Control Protocol
+xdmcp 177/udp # X Display Manager Control Protocol
+nextstep 178/tcp # NextStep Window Server
+NextStep 178/udp # NextStep Window Server
+bgp 179/tcp # Border Gateway Protocol
+bgp 179/udp # Border Gateway Protocol
+ris 180/tcp # Intergraph
+ris 180/udp # Intergraph
+unify 181/tcp # Unify
+unify 181/udp # Unify
+audit 182/tcp # Unisys Audit SITP
+audit 182/udp # Unisys Audit SITP
+ocbinder 183/tcp # OCBinder
+ocbinder 183/udp # OCBinder
+ocserver 184/tcp # OCServer
+ocserver 184/udp # OCServer
+remote-kis 185/tcp # Remote-KIS
+remote-kis 185/udp # Remote-KIS
+kis 186/tcp # KIS Protocol
+kis 186/udp # KIS Protocol
+aci 187/tcp # Application Communication Interface
+aci 187/udp # Application Communication Interface
+mumps 188/tcp # Plus Five's MUMPS
+mumps 188/udp # Plus Five's MUMPS
+qft 189/tcp # Queued File Transport
+qft 189/udp # Queued File Transport
+gacp 190/tcp # Gateway Access Control Protocol
+cacp 190/udp # Gateway Access Control Protocol
+prospero 191/tcp # Prospero Directory Service
+prospero 191/udp # Prospero Directory Service
+osu-nms 192/tcp # OSU Network Monitoring System
+osu-nms 192/udp # OSU Network Monitoring System
+srmp 193/tcp # Spider Remote Monitoring Protocol
+srmp 193/udp # Spider Remote Monitoring Protocol
+irc 194/tcp # Internet Relay Chat Protocol
+irc 194/udp # Internet Relay Chat Protocol
+dn6-nlm-aud 195/tcp # DNSIX Network Level Module Audit
+dn6-nlm-aud 195/udp # DNSIX Network Level Module Audit
+dn6-smm-red 196/tcp # DNSIX Session Mgt Module Audit Redir
+dn6-smm-red 196/udp # DNSIX Session Mgt Module Audit Redir
+dls 197/tcp # Directory Location Service
+dls 197/udp # Directory Location Service
+dls-mon 198/tcp # Directory Location Service Monitor
+dls-mon 198/udp # Directory Location Service Monitor
+smux 199/tcp # SMUX
+smux 199/udp # SMUX
+src 200/tcp # IBM System Resource Controller
+src 200/udp # IBM System Resource Controller
+at-rtmp 201/tcp # AppleTalk Routing Maintenance
+at-rtmp 201/udp # AppleTalk Routing Maintenance
+at-nbp 202/tcp # AppleTalk Name Binding
+at-nbp 202/udp # AppleTalk Name Binding
+at-3 203/tcp # AppleTalk Unused
+at-3 203/udp # AppleTalk Unused
+at-echo 204/tcp # AppleTalk Echo
+at-echo 204/udp # AppleTalk Echo
+at-5 205/tcp # AppleTalk Unused
+at-5 205/udp # AppleTalk Unused
+at-zis 206/tcp # AppleTalk Zone Information
+at-zis 206/udp # AppleTalk Zone Information
+at-7 207/tcp # AppleTalk Unused
+at-7 207/udp # AppleTalk Unused
+at-8 208/tcp # AppleTalk Unused
+at-8 208/udp # AppleTalk Unused
+tam 209/tcp # Trivial Authenticated Mail Protocol
+tam 209/udp # Trivial Authenticated Mail Protocol
+z39.50 210/tcp # ANSI Z39.50
+z39.50 210/udp # ANSI Z39.50
+914c/g 211/tcp # Texas Instruments 914C/G Terminal
+914c/g 211/udp # Texas Instruments 914C/G Terminal
+anet 212/tcp # ATEXSSTR
+anet 212/udp # ATEXSSTR
+ipx 213/tcp # IPX
+ipx 213/udp # IPX
+vmpwscs 214/tcp # VM PWSCS
+vmpwscs 214/udp # VM PWSCS
+softpc 215/tcp # Insignia Solutions
+softpc 215/udp # Insignia Solutions
+atls 216/tcp # Access Technology License Server
+atls 216/udp # Access Technology License Server
+dbase 217/tcp # dBASE Unix
+dbase 217/udp # dBASE Unix
+mpp 218/tcp # Netix Message Posting Protocol
+mpp 218/udp # Netix Message Posting Protocol
+uarps 219/tcp # Unisys ARPs
+uarps 219/udp # Unisys ARPs
+imap3 220/tcp # Interactive Mail Access Protocol v3
+imap3 220/udp # Interactive Mail Access Protocol v3
+fln-spx 221/tcp # Berkeley rlogind with SPX auth
+fln-spx 221/udp # Berkeley rlogind with SPX auth
+rsh-spx 222/tcp # Berkeley rshd with SPX auth
+rsh-spx 222/udp # Berkeley rshd with SPX auth
+cdc 223/tcp # Certificate Distribution Center
+cdc 223/udp # Certificate Distribution Center
+sur-meas 243/tcp # Survey Measurement
+sur-meas 243/udp # Survey Measurement
+link 245/tcp # LINK
+link 245/udp # LINK
+dsp3270 246/tcp # Display Systems Protocol
+dsp3270 246/udp # Display Systems Protocol
+pdap 344/tcp # Prospero Data Access Protocol
+pdap 344/udp # Prospero Data Access Protocol
+pawserv 345/tcp # Perf Analysis Workbench
+pawserv 345/udp # Perf Analysis Workbench
+zserv 346/tcp # Zebra server
+zserv 346/udp # Zebra server
+fatserv 347/tcp # Fatmen Server
+fatserv 347/udp # Fatmen Server
+csi-sgwp 348/tcp # Cabletron Management Protocol
+csi-sgwp 348/udp # Cabletron Management Protocol
+clearcase 371/tcp # Clearcase
+clearcase 371/udp # Clearcase
+ulistserv 372/tcp # Unix Listserv
+ulistserv 372/udp # Unix Listserv
+legent-1 373/tcp # Legent Corporation
+legent-1 373/udp # Legent Corporation
+legent-2 374/tcp # Legent Corporation
+legent-2 374/udp # Legent Corporation
+hassle 375/tcp # Hassle
+hassle 375/udp # Hassle
+nip 376/tcp # Amiga Envoy Network Inquiry Proto
+nip 376/udp # Amiga Envoy Network Inquiry Proto
+tnETOS 377/tcp # NEC Corporation
+tnETOS 377/udp # NEC Corporation
+dsETOS 378/tcp # NEC Corporation
+dsETOS 378/udp # NEC Corporation
+is99c 379/tcp # TIA/EIA/IS-99 modem client
+is99c 379/udp # TIA/EIA/IS-99 modem client
+is99s 380/tcp # TIA/EIA/IS-99 modem server
+is99s 380/udp # TIA/EIA/IS-99 modem server
+hp-collector 381/tcp # hp performance data collector
+hp-collector 381/udp # hp performance data collector
+hp-managed-node 382/tcp # hp performance data managed node
+hp-managed-node 382/udp # hp performance data managed node
+hp-alarm-mgr 383/tcp # hp performance data alarm manager
+hp-alarm-mgr 383/udp # hp performance data alarm manager
+arns 384/tcp # A Remote Network Server System
+arns 384/udp # A Remote Network Server System
+ibm-app 385/tcp # IBM Application
+ibm-app 385/tcp # IBM Application
+asa 386/tcp # ASA Message Router Object Def.
+asa 386/udp # ASA Message Router Object Def.
+aurp 387/tcp # Appletalk Update-Based Routing Pro.
+aurp 387/udp # Appletalk Update-Based Routing Pro.
+unidata-ldm 388/tcp # Unidata LDM Version 4
+unidata-ldm 388/udp # Unidata LDM Version 4
+ldap 389/tcp # Lightweight Directory Access Protocol
+ldap 389/udp # Lightweight Directory Access Protocol
+uis 390/tcp # UIS
+uis 390/udp # UIS
+synotics-relay 391/tcp # SynOptics SNMP Relay Port
+synotics-relay 391/udp # SynOptics SNMP Relay Port
+synotics-broker 392/tcp # SynOptics Port Broker Port
+synotics-broker 392/udp # SynOptics Port Broker Port
+dis 393/tcp # Data Interpretation System
+dis 393/udp # Data Interpretation System
+embl-ndt 394/tcp # EMBL Nucleic Data Transfer
+embl-ndt 394/udp # EMBL Nucleic Data Transfer
+netcp 395/tcp # NETscout Control Protocol
+netcp 395/udp # NETscout Control Protocol
+netware-ip 396/tcp # Novell Netware over IP
+netware-ip 396/udp # Novell Netware over IP
+mptn 397/tcp # Multi Protocol Trans. Net.
+mptn 397/udp # Multi Protocol Trans. Net.
+kryptolan 398/tcp # Kryptolan
+kryptolan 398/udp # Kryptolan
+work-sol 400/tcp # Workstation Solutions
+work-sol 400/udp # Workstation Solutions
+ups 401/tcp # Uninterruptible Power Supply
+ups 401/udp # Uninterruptible Power Supply
+genie 402/tcp # Genie Protocol
+genie 402/udp # Genie Protocol
+decap 403/tcp # decap
+decap 403/udp # decap
+nced 404/tcp # nced
+nced 404/udp # nced
+ncld 405/tcp # ncld
+ncld 405/udp # ncld
+imsp 406/tcp # Interactive Mail Support Protocol
+imsp 406/udp # Interactive Mail Support Protocol
+timbuktu 407/tcp # Timbuktu
+timbuktu 407/udp # Timbuktu
+prm-sm 408/tcp # Prospero Resource Manager Sys. Man.
+prm-sm 408/udp # Prospero Resource Manager Sys. Man.
+prm-nm 409/tcp # Prospero Resource Manager Node Man.
+prm-nm 409/udp # Prospero Resource Manager Node Man.
+decladebug 410/tcp # DECLadebug Remote Debug Protocol
+decladebug 410/udp # DECLadebug Remote Debug Protocol
+rmt 411/tcp # Remote MT Protocol
+rmt 411/udp # Remote MT Protocol
+synoptics-trap 412/tcp # Trap Convention Port
+synoptics-trap 412/udp # Trap Convention Port
+smsp 413/tcp # SMSP
+smsp 413/udp # SMSP
+infoseek 414/tcp # InfoSeek
+infoseek 414/udp # InfoSeek
+bnet 415/tcp # BNet
+bnet 415/udp # BNet
+silverplatter 416/tcp # Silverplatter
+silverplatter 416/udp # Silverplatter
+onmux 417/tcp # Onmux
+onmux 417/udp # Onmux
+hyper-g 418/tcp # Hyper-G
+hyper-g 418/udp # Hyper-G
+ariel1 419/tcp # Ariel
+ariel1 419/udp # Ariel
+smpte 420/tcp # SMPTE
+smpte 420/udp # SMPTE
+ariel2 421/tcp # Ariel
+ariel2 421/udp # Ariel
+ariel3 422/tcp # Ariel
+ariel3 422/udp # Ariel
+opc-job-start 423/tcp # IBM Operations Planning and Control Start
+opc-job-start 423/udp # IBM Operations Planning and Control Start
+opc-job-track 424/tcp # IBM Operations Planning and Control Track
+opc-job-track 424/udp # IBM Operations Planning and Control Track
+icad-el 425/tcp # ICAD
+icad-el 425/udp # ICAD
+smartsdp 426/tcp # smartsdp
+smartsdp 426/udp # smartsdp
+svrloc 427/tcp # Server Location
+svrloc 427/udp # Server Location
+ocs_cmu 428/tcp # OCS_CMU
+ocs_cmu 428/udp # OCS_CMU
+ocs_amu 429/tcp # OCS_AMU
+ocs_amu 429/udp # OCS_AMU
+utmpsd 430/tcp # UTMPSD
+utmpsd 430/udp # UTMPSD
+utmpcd 431/tcp # UTMPCD
+utmpcd 431/udp # UTMPCD
+iasd 432/tcp # IASD
+iasd 432/udp # IASD
+nnsp 433/tcp # NNSP
+nnsp 433/udp # NNSP
+mobileip-agent 434/tcp # MobileIP-Agent
+mobileip-agent 434/udp # MobileIP-Agent
+mobilip-mn 435/tcp # MobilIP-MN
+mobilip-mn 435/udp # MobilIP-MN
+dna-cml 436/tcp # DNA-CML
+dna-cml 436/udp # DNA-CML
+comscm 437/tcp # comscm
+comscm 437/udp # comscm
+dsfgw 438/tcp # dsfgw
+dsfgw 438/udp # dsfgw
+dasp 439/tcp # dasp Thomas Obermair
+dasp 439/udp # dasp tommy@inlab.m.eunet.de
+sgcp 440/tcp # sgcp
+sgcp 440/udp # sgcp
+decvms-sysmgt 441/tcp # decvms-sysmgt
+decvms-sysmgt 441/udp # decvms-sysmgt
+cvc_hostd 442/tcp # cvc_hostd
+cvc_hostd 442/udp # cvc_hostd
+https 443/tcp # https MCom
+https 443/udp # https MCom
+snpp 444/tcp # Simple Network Paging Protocol
+snpp 444/udp # Simple Network Paging Protocol
+microsoft-ds 445/tcp # Microsoft-DS
+microsoft-ds 445/udp # Microsoft-DS
+ddm-rdb 446/tcp # DDM-RDB
+ddm-rdb 446/udp # DDM-RDB
+ddm-dfm 447/tcp # DDM-RFM
+ddm-dfm 447/udp # DDM-RFM
+ddm-byte 448/tcp # DDM-BYTE
+ddm-byte 448/udp # DDM-BYTE
+as-servermap 449/tcp # AS Server Mapper
+as-servermap 449/udp # AS Server Mapper
+tserver 450/tcp # TServer
+tserver 450/udp # TServer
+exec 512/tcp # remote process execution;
+biff 512/udp # used by mail system to notify users
+login 513/tcp # remote login a la telnet;
+who 513/udp # maintains data bases showing who's
+cmd 514/tcp # like exec, but automatic
+syslog 514/udp
+printer 515/tcp # spooler
+printer 515/udp # spooler
+talk 517/tcp # like tenex link, but across
+talk 517/udp # like tenex link, but across tcp connection is established)
+ntalk 518/tcp
+ntalk 518/udp
+utime 519/tcp # unixtime
+utime 519/udp # unixtime
+efs 520/tcp # extended file name server
+router 520/udp # local routing process (on site);
+timed 525/tcp # timeserver
+timed 525/udp # timeserver
+tempo 526/tcp # newdate
+tempo 526/udp # newdate
+courier 530/tcp # rpc
+courier 530/udp # rpc
+conference 531/tcp # chat
+conference 531/udp # chat
+netnews 532/tcp # readnews
+netnews 532/udp # readnews
+netwall 533/tcp # for emergency broadcasts
+netwall 533/udp # for emergency broadcasts
+apertus-ldp 539/tcp # Apertus Technologies Load Determination
+apertus-ldp 539/udp # Apertus Technologies Load Determination
+uucp 540/tcp # uucpd
+uucp 540/udp # uucpd
+uucp-rlogin 541/tcp # uucp-rlogin Stuart Lynne
+uucp-rlogin 541/udp # uucp-rlogin sl@wimsey.com
+klogin 543/tcp
+klogin 543/udp
+kshell 544/tcp # krcmd
+kshell 544/udp # krcmd
+new-rwho 550/tcp # new-who
+new-rwho 550/udp # new-who
+dsf 555/tcp
+dsf 555/udp
+remotefs 556/tcp # rfs server
+remotefs 556/udp # rfs server
+rmonitor 560/tcp # rmonitord
+rmonitor 560/udp # rmonitord
+monitor 561/tcp
+monitor 561/udp
+chshell 562/tcp # chcmd
+chshell 562/udp # chcmd
+9pfs 564/tcp # plan 9 file service
+9pfs 564/udp # plan 9 file service
+whoami 565/tcp # whoami
+whoami 565/udp # whoami
+meter 570/tcp # demon
+meter 570/udp # demon
+meter 571/tcp # udemon
+meter 571/udp # udemon
+ipcserver 600/tcp # Sun IPC server
+ipcserver 600/udp # Sun IPC server
+nqs 607/tcp # nqs
+nqs 607/udp # nqs
+urm 606/tcp # Cray Unified Resource Manager
+urm 606/udp # Cray Unified Resource Manager
+sift-uft 608/tcp # Sender-Initiated/Unsolicited File Transfer
+sift-uft 608/udp # Sender-Initiated/Unsolicited File Transfer
+npmp-trap 609/tcp # npmp-trap
+npmp-trap 609/udp # npmp-trap
+npmp-local 610/tcp # npmp-local
+npmp-local 610/udp # npmp-local
+npmp-gui 611/tcp # npmp-gui
+npmp-gui 611/udp # npmp-gui
+ginad 634/tcp # ginad
+ginad 634/udp # ginad
+mdqs 666/tcp
+mdqs 666/udp
+doom 666/tcp # doom Id Software
+doom 666/tcp # doom Id Software
+elcsd 704/tcp # errlog copy/server daemon
+elcsd 704/udp # errlog copy/server daemon
+entrustmanager 709/tcp # EntrustManager
+entrustmanager 709/udp # EntrustManager
+netviewdm1 729/tcp # IBM NetView DM/6000 Server/Client
+netviewdm1 729/udp # IBM NetView DM/6000 Server/Client
+netviewdm2 730/tcp # IBM NetView DM/6000 send/tcp
+netviewdm2 730/udp # IBM NetView DM/6000 send/tcp
+netviewdm3 731/tcp # IBM NetView DM/6000 receive/tcp
+netviewdm3 731/udp # IBM NetView DM/6000 receive/tcp
+netgw 741/tcp # netGW
+netgw 741/udp # netGW
+netrcs 742/tcp # Network based Rev. Cont. Sys.
+netrcs 742/udp # Network based Rev. Cont. Sys.
+flexlm 744/tcp # Flexible License Manager
+flexlm 744/udp # Flexible License Manager
+fujitsu-dev 747/tcp # Fujitsu Device Control
+fujitsu-dev 747/udp # Fujitsu Device Control
+ris-cm 748/tcp # Russell Info Sci Calendar Manager
+ris-cm 748/udp # Russell Info Sci Calendar Manager
+kerberos-adm 749/tcp # kerberos administration
+kerberos-adm 749/udp # kerberos administration
+rfile 750/tcp
+loadav 750/udp
+pump 751/tcp
+pump 751/udp
+qrh 752/tcp
+qrh 752/udp
+rrh 753/tcp
+rrh 753/udp
+tell 754/tcp # send
+tell 754/udp # send
+nlogin 758/tcp
+nlogin 758/udp
+con 759/tcp
+con 759/udp
+ns 760/tcp
+ns 760/udp
+rxe 761/tcp
+rxe 761/udp
+quotad 762/tcp
+quotad 762/udp
+cycleserv 763/tcp
+cycleserv 763/udp
+omserv 764/tcp
+omserv 764/udp
+webster 765/tcp
+webster 765/udp
+phonebook 767/tcp # phone
+phonebook 767/udp # phone
+vid 769/tcp
+vid 769/udp
+cadlock 770/tcp
+cadlock 770/udp
+rtip 771/tcp
+rtip 771/udp
+cycleserv2 772/tcp
+cycleserv2 772/udp
+submit 773/tcp
+notify 773/udp
+rpasswd 774/tcp
+acmaint_dbd 774/udp
+entomb 775/tcp
+acmaint_transd 775/udp
+wpages 776/tcp
+wpages 776/udp
+wpgs 780/tcp
+wpgs 780/udp
+concert 786/tcp # Concert
+concert 786/udp # Concert
+mdbs_daemon 800/tcp
+mdbs_daemon 800/udp
+device 801/tcp
+device 801/udp
+xtreelic 996/tcp # Central Point Software
+xtreelic 996/udp # Central Point Software
+maitrd 997/tcp
+maitrd 997/udp
+busboy 998/tcp
+puparp 998/udp
+garcon 999/tcp
+applix 999/udp # Applix ac
+puprouter 999/tcp
+puprouter 999/udp
+cadlock 1000/tcp
+ock 1000/udp
diff --git a/contrib/ipfilter/fil.c b/contrib/ipfilter/fil.c
new file mode 100644
index 0000000..de776f9
--- /dev/null
+++ b/contrib/ipfilter/fil.c
@@ -0,0 +1,762 @@
+/*
+ * (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.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
+static char rcsid[] = "$Id: fil.c,v 2.0.1.4 1997/02/04 13:59:41 darrenr Exp $";
+#endif
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if defined(_KERNEL) || defined(KERNEL)
+# include <sys/systm.h>
+#else
+# include <stdio.h>
+# include <string.h>
+#endif
+#include <sys/uio.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# include <sys/stream.h>
+#endif
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#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/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include "ip_nat.h"
+#include "ip_frag.h"
+#include "ip_state.h"
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef _KERNEL
+#include "ipf.h"
+extern int opts;
+extern void debug(), verbose();
+
+#define FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; second; }
+#define FR_IFDEBUG(ex,second,verb_pr) if (ex) { debug verb_pr; second; }
+#define FR_VERBOSE(verb_pr) verbose verb_pr
+#define FR_DEBUG(verb_pr) debug verb_pr
+#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi)
+# if SOLARIS
+# define bcmp memcmp
+# endif
+#else
+#define FR_IFVERBOSE(ex,second,verb_pr) ;
+#define FR_IFDEBUG(ex,second,verb_pr) ;
+#define FR_VERBOSE(verb_pr)
+#define FR_DEBUG(verb_pr)
+#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m)
+extern int send_reset();
+# if SOLARIS
+extern int icmp_error(), ipfr_fastroute();
+extern kmutex_t ipf_mutex, ipl_mutex;
+# else
+extern void ipfr_fastroute();
+# endif
+extern int ipl_unreach, ipllog();
+#endif
+
+#if SOLARIS
+# define SEND_RESET(ip, if, q) send_reset(ip, qif, q)
+# define ICMP_ERROR(b, ip, t, c, if, src) \
+ icmp_error(b, ip, t, c, if, src)
+#else
+# define SEND_RESET(ip, if, q) send_reset(ip)
+# if BSD < 199103
+# define ICMP_ERROR(b, ip, t, c, if, src) \
+ icmp_error(mtod(b, ip_t *), t, c, if, src)
+# else
+# define ICMP_ERROR(b, ip, t, c, if, src) \
+ icmp_error(b, t, c, (src).s_addr, if)
+# endif
+#endif
+
+struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
+struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
+ *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
+int fr_flags = 0, fr_active = 0;
+
+fr_info_t frcache[2];
+
+
+/*
+ * bit values for identifying presence of individual IP options
+ */
+struct optlist ipopts[20] = {
+ { IPOPT_NOP, 0x000001 },
+ { IPOPT_RR, 0x000002 },
+ { IPOPT_ZSU, 0x000004 },
+ { IPOPT_MTUP, 0x000008 },
+ { IPOPT_MTUR, 0x000010 },
+ { IPOPT_ENCODE, 0x000020 },
+ { IPOPT_TS, 0x000040 },
+ { IPOPT_TR, 0x000080 },
+ { IPOPT_SECURITY, 0x000100 },
+ { IPOPT_LSRR, 0x000200 },
+ { IPOPT_E_SEC, 0x000400 },
+ { IPOPT_CIPSO, 0x000800 },
+ { IPOPT_SATID, 0x001000 },
+ { IPOPT_SSRR, 0x002000 },
+ { IPOPT_ADDEXT, 0x004000 },
+ { IPOPT_VISA, 0x008000 },
+ { IPOPT_IMITD, 0x010000 },
+ { IPOPT_EIP, 0x020000 },
+ { IPOPT_FINN, 0x040000 },
+ { 0, 0x000000 }
+};
+
+/*
+ * bit values for identifying presence of individual IP security options
+ */
+struct optlist secopt[8] = {
+ { IPSO_CLASS_RES4, 0x01 },
+ { IPSO_CLASS_TOPS, 0x02 },
+ { IPSO_CLASS_SECR, 0x04 },
+ { IPSO_CLASS_RES3, 0x08 },
+ { IPSO_CLASS_CONF, 0x10 },
+ { IPSO_CLASS_UNCL, 0x20 },
+ { IPSO_CLASS_RES2, 0x40 },
+ { IPSO_CLASS_RES1, 0x80 }
+};
+
+
+/*
+ * compact the IP header into a structure which contains just the info.
+ * which is useful for comparing IP headers with.
+ */
+void fr_makefrip(hlen, ip, fin)
+int hlen;
+ip_t *ip;
+fr_info_t *fin;
+{
+ struct optlist *op;
+ tcphdr_t *tcp;
+ fr_ip_t *fi = &fin->fin_fi;
+ u_short optmsk = 0, secmsk = 0, auth = 0;
+ int i, mv, ol, off;
+ u_char *s, opt;
+
+ fin->fin_fr = NULL;
+ fin->fin_tcpf = 0;
+ fin->fin_data[0] = 0;
+ fin->fin_data[1] = 0;
+ fin->fin_rule = -1;
+#ifdef _KERNEL
+ fin->fin_icode = ipl_unreach;
+#endif
+ fi->fi_v = ip->ip_v;
+ fi->fi_tos = ip->ip_tos;
+ fin->fin_hlen = hlen;
+ fin->fin_dlen = ip->ip_len - hlen;
+ tcp = (tcphdr_t *)((char *)ip + hlen);
+ fin->fin_dp = (void *)tcp;
+ (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
+ (*(((u_long *)fi) + 1)) = (*(((u_long *)ip) + 3));
+ (*(((u_long *)fi) + 2)) = (*(((u_long *)ip) + 4));
+
+ fi->fi_fl = (hlen > sizeof(struct ip)) ? FI_OPTIONS : 0;
+ off = (ip->ip_off & 0x1fff) << 3;
+ if (ip->ip_off & 0x3fff)
+ fi->fi_fl |= FI_FRAG;
+ switch (ip->ip_p)
+ {
+ case IPPROTO_ICMP :
+ if ((!IPMINLEN(ip, icmp) && !off) ||
+ (off && off < sizeof(struct icmp)))
+ fi->fi_fl |= FI_SHORT;
+ if (fin->fin_dlen > 1)
+ fin->fin_data[0] = *(u_short *)tcp;
+ break;
+ case IPPROTO_TCP :
+ fi->fi_fl |= FI_TCPUDP;
+ if ((!IPMINLEN(ip, tcphdr) && !off) ||
+ (off && off < sizeof(struct tcphdr)))
+ fi->fi_fl |= FI_SHORT;
+ if (!(fi->fi_fl & FI_SHORT) && !off)
+ fin->fin_tcpf = tcp->th_flags;
+ goto getports;
+ case IPPROTO_UDP :
+ fi->fi_fl |= FI_TCPUDP;
+ if ((!IPMINLEN(ip, udphdr) && !off) ||
+ (off && off < sizeof(struct udphdr)))
+ fi->fi_fl |= FI_SHORT;
+getports:
+ if (!off && (fin->fin_dlen > 3)) {
+ fin->fin_data[0] = ntohs(tcp->th_sport);
+ fin->fin_data[1] = ntohs(tcp->th_dport);
+ }
+ break;
+ default :
+ break;
+ }
+
+
+ for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) {
+ if (!(opt = *s))
+ break;
+ ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1);
+ if (opt > 1 && (ol < 2 || ol > hlen))
+ break;
+ for (i = 9, mv = 4; mv >= 0; ) {
+ op = ipopts + i;
+ if (opt == (u_char)op->ol_val) {
+ optmsk |= op->ol_bit;
+ if (opt == IPOPT_SECURITY) {
+ struct optlist *sp;
+ u_char sec;
+ int j, m;
+
+ sec = *(s + 2); /* classification */
+ for (j = 3, m = 2; m >= 0; ) {
+ sp = secopt + j;
+ if (sec == sp->ol_val) {
+ secmsk |= sp->ol_bit;
+ auth = *(s + 3);
+ auth *= 256;
+ auth += *(s + 4);
+ break;
+ }
+ if (sec < sp->ol_val)
+ j -= m--;
+ else
+ j += m--;
+ }
+ }
+ break;
+ }
+ if (opt < op->ol_val)
+ i -= mv--;
+ else
+ i += mv--;
+ }
+ hlen -= ol;
+ s += ol;
+ }
+ if (auth && !(auth & 0x0100))
+ auth &= 0xff00;
+ fi->fi_optmsk = optmsk;
+ fi->fi_secmsk = secmsk;
+ fi->fi_auth = auth;
+}
+
+
+/*
+ * check an IP packet for TCP/UDP characteristics such as ports and flags.
+ */
+int fr_tcpudpchk(fr, fin)
+frentry_t *fr;
+fr_info_t *fin;
+{
+ register u_short po, tup;
+ register char i;
+ register 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 ((i = (int)fr->fr_dcmp)) {
+ po = fr->fr_dport;
+ tup = fin->fin_data[1];
+ /*
+ * Do opposite test to that required and
+ * continue if that succeeds.
+ */
+ if (!--i && tup != po) /* EQUAL */
+ err = 0;
+ else if (!--i && tup == po) /* NOTEQUAL */
+ err = 0;
+ else if (!--i && tup >= po) /* LESSTHAN */
+ err = 0;
+ else if (!--i && tup <= po) /* GREATERTHAN */
+ err = 0;
+ else if (!--i && tup > po) /* LT or EQ */
+ err = 0;
+ else if (!--i && tup < po) /* GT or EQ */
+ err = 0;
+ else if (!--i && /* Out of range */
+ (tup >= po && tup <= fr->fr_dtop))
+ err = 0;
+ else if (!--i && /* In range */
+ (tup <= po || tup >= fr->fr_dtop))
+ err = 0;
+ }
+ /*
+ * compare source ports
+ */
+ if (err && (i = (int)fr->fr_scmp)) {
+ po = fr->fr_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 <= fr->fr_stop))
+ err = 0;
+ else if (!--i && /* In range */
+ (tup <= po || tup >= fr->fr_stop))
+ err = 0;
+ }
+
+ /*
+ * If we don't have all the TCP/UDP header, then how can we
+ * expect to do any sort of match on it ? If we were looking for
+ * 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_fi.fi_fl & FI_SHORT)
+ return !(fr->fr_tcpf | fr->fr_tcpfm);
+ /*
+ * Match the flags ? If not, abort this match.
+ */
+ if (fr->fr_tcpf &&
+ fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) {
+ FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
+ fr->fr_tcpfm, fr->fr_tcpf));
+ err = 0;
+ }
+ }
+ 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(pass, ip, fin, m)
+int pass;
+ip_t *ip;
+register fr_info_t *fin;
+void *m;
+{
+ register struct frentry *fr;
+ register fr_ip_t *fi = &fin->fin_fi;
+ int rulen, portcmp = 0, off;
+
+ fr = fin->fin_fr;
+ fin->fin_fr = NULL;
+ fin->fin_rule = 0;
+ off = ip->ip_off & 0x1fff;
+ pass |= (fi->fi_fl << 20);
+
+ if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
+ portcmp = 1;
+
+ for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
+ /*
+ * In all checks below, a null (zero) value in the
+ * filter struture is taken to mean a wildcard.
+ *
+ * check that we are working for the right interface
+ */
+#ifdef _KERNEL
+ if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
+ continue;
+#else
+ if (opts & (OPT_VERBOSE|OPT_DEBUG))
+ printf("\n");
+ FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 'b'));
+ if (fin->fin_ifp && *fr->fr_ifname &&
+ strcasecmp((char *)fin->fin_ifp, fr->fr_ifname))
+ continue;
+ FR_VERBOSE((":i"));
+#endif
+ {
+ register u_long *ld, *lm, *lip;
+ register int i;
+
+ lip = (u_long *)fi;
+ lm = (u_long *)&fr->fr_mip;
+ ld = (u_long *)&fr->fr_ip;
+ i = ((lip[0] & lm[0]) != ld[0]);
+ FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n",
+ lip[0], lm[0], ld[0]));
+ i |= ((lip[1] & lm[1]) != ld[1]);
+ FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
+ lip[1], lm[1], ld[1]));
+ i |= ((lip[2] & lm[2]) != ld[2]);
+ FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
+ lip[2], lm[2], ld[2]));
+ i |= ((lip[3] & lm[3]) != ld[3]);
+ FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n",
+ lip[3], lm[3], ld[3]));
+ i |= ((lip[4] & lm[4]) != ld[4]);
+ FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
+ lip[4], lm[4], ld[4]));
+ if (i)
+ continue;
+ }
+
+ /*
+ * If a fragment, then only the first has what we're looking
+ * for here...
+ */
+ if (fi->fi_fl & FI_TCPUDP) {
+ if (portcmp) {
+ if (!fr_tcpudpchk(fr, fin))
+ continue;
+ } else if (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
+ fr->fr_tcpfm)
+ continue;
+ } else if (fi->fi_p == IPPROTO_ICMP) {
+ if (!off && (fin->fin_dlen > 1)) {
+ 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));
+ continue;
+ }
+ } else if (fr->fr_icmpm || fr->fr_icmp)
+ continue;
+ }
+ FR_VERBOSE(("*"));
+ /*
+ * Just log this packet...
+ */
+ pass = fr->fr_flags;
+ if ((pass & FR_CALLNOW) && fr->fr_func)
+ pass = (*fr->fr_func)(pass, ip, fin);
+#ifdef IPFILTER_LOG
+ if ((pass & FR_LOGMASK) == FR_LOG) {
+ if (!ipllog(fr->fr_flags, ip, fin, m))
+ frstats[fin->fin_out].fr_skip++;
+ frstats[fin->fin_out].fr_pkl++;
+ }
+#endif /* IPFILTER_LOG */
+ FR_DEBUG(("pass %#x\n", pass));
+ fr->fr_hits++;
+ if (pass & FR_ACCOUNT)
+ fr->fr_bytes += ip->ip_len;
+ else
+ fin->fin_icode = fr->fr_icode;
+ fin->fin_rule = rulen;
+ fin->fin_fr = fr;
+ if (pass & FR_QUICK)
+ break;
+ }
+ return pass;
+}
+
+
+/*
+ * frcheck - filter check
+ * check using source and destination addresses/pors in a packet whether
+ * or not to pass it on or not.
+ */
+int fr_check(ip, hlen, ifp, out
+#ifdef _KERNEL
+# if SOLARIS
+, qif, q, mp)
+qif_t *qif;
+queue_t *q;
+mblk_t **mp;
+# else
+, mp)
+struct mbuf **mp;
+# endif
+#else
+)
+#endif
+ip_t *ip;
+int hlen;
+struct ifnet *ifp;
+int out;
+{
+ /*
+ * The above really sucks, but short of writing a diff
+ */
+ fr_info_t frinfo, *fc;
+ register fr_info_t *fin = &frinfo;
+ frentry_t *fr = NULL;
+ int pass, changed;
+
+#if !defined(__SVR4) && !defined(__svr4__) && defined(_KERNEL)
+ register struct mbuf *m = *mp;
+ struct mbuf *mc = NULL;
+
+ if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
+ ip->ip_p == IPPROTO_ICMP)) {
+ register int up = MIN(hlen + 8, ip->ip_len);
+
+ if (up > m->m_len) {
+ if ((*mp = m_pullup(m, up)) == 0) {
+ frstats[out].fr_pull[1]++;
+ return -1;
+ } else {
+ frstats[out].fr_pull[0]++;
+ m = *mp;
+ ip = mtod(m, struct ip *);
+ }
+ }
+ }
+#endif
+#if SOLARIS && defined(_KERNEL)
+ mblk_t *mc = NULL, *m = qif->qf_m;
+#endif
+ fr_makefrip(hlen, ip, fin);
+ fin->fin_ifp = ifp;
+ fin->fin_out = out;
+
+ MUTEX_ENTER(&ipf_mutex);
+ if (!out) {
+ changed = ip_natin(ip, hlen, fin);
+ if ((fin->fin_fr = ipacct[0][fr_active]) &&
+ (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
+ frstats[0].fr_acct++;
+ }
+
+ if ((pass = ipfr_knownfrag(ip, fin))) {
+ if ((pass & FR_KEEPSTATE)) {
+ if (fr_addstate(ip, fin, pass) == -1)
+ frstats[out].fr_bads++;
+ else
+ frstats[out].fr_ads++;
+ }
+ } else if ((pass = fr_checkstate(ip, fin))) {
+ if ((pass & FR_KEEPFRAG)) {
+ if (fin->fin_fi.fi_fl & FI_FRAG) {
+ if (ipfr_newfrag(ip, fin, pass) == -1)
+ frstats[out].fr_bnfr++;
+ else
+ frstats[out].fr_nfr++;
+ } else
+ frstats[out].fr_cfr++;
+ }
+ } else {
+ fc = frcache + out;
+ if (fc->fin_fr && !bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
+ /*
+ * copy cached data so we can unlock the mutex
+ * earlier.
+ */
+ bcopy((char *)fc, (char *)fin, sizeof(*fin));
+ frstats[out].fr_chit++;
+ pass = fin->fin_fr->fr_flags;
+ } else {
+ pass = FR_NOMATCH;
+ if ((fin->fin_fr = ipfilter[out][fr_active]))
+ pass = FR_SCANLIST(FR_NOMATCH, ip, fin, m);
+ bcopy((char *)fin, (char *)fc, FI_CSIZE);
+ if (pass & FR_NOMATCH) {
+ frstats[out].fr_nom++;
+#ifdef NOMATCH
+ pass |= NOMATCH;
+#endif
+ }
+ }
+ fr = fin->fin_fr;
+
+ if ((pass & FR_KEEPFRAG)) {
+ if (fin->fin_fi.fi_fl & FI_FRAG) {
+ if (ipfr_newfrag(ip, fin, pass) == -1)
+ frstats[out].fr_bnfr++;
+ else
+ frstats[out].fr_nfr++;
+ } else
+ frstats[out].fr_cfr++;
+ }
+ if (pass & FR_KEEPSTATE) {
+ if (fr_addstate(ip, fin, pass) == -1)
+ frstats[out].fr_bads++;
+ else
+ frstats[out].fr_ads++;
+ }
+ }
+
+ if (fr && fr->fr_func)
+ pass = (*fr->fr_func)(pass, ip, fin);
+
+ if (out) {
+ if ((fin->fin_fr = ipacct[1][fr_active]) &&
+ (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
+ frstats[1].fr_acct++;
+ fin->fin_fr = NULL;
+ changed = ip_natout(ip, hlen, fin);
+ }
+ fin->fin_fr = fr;
+ MUTEX_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;
+ 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;
+ 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;
+ frstats[out].fr_bpkl++;
+logit:
+ if (!ipllog(pass, ip, fin, m)) {
+ frstats[out].fr_skip++;
+ if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
+ (FR_PASS|FR_LOGORBLOCK))
+ pass ^= FR_PASS|FR_BLOCK;
+ }
+ }
+ }
+#endif /* IPFILTER_LOG */
+
+ if (pass & FR_PASS)
+ frstats[out].fr_pass++;
+ else if (pass & FR_BLOCK) {
+ frstats[out].fr_block++;
+ /*
+ * Should we return an ICMP packet to indicate error
+ * status passing through the packet filter ?
+ */
+#ifdef _KERNEL
+ if (pass & FR_RETICMP) {
+# if SOLARIS
+ ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode,
+ qif, ip->ip_src);
+# else
+ ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode,
+ ifp, ip->ip_src);
+ m = NULL; /* freed by icmp_error() */
+# endif
+
+ frstats[0].fr_ret++;
+ } else if ((pass & FR_RETRST) &&
+ !(fin->fin_fi.fi_fl & FI_SHORT)) {
+ if (SEND_RESET(ip, qif, q) == 0)
+ frstats[1].fr_ret++;
+ }
+#else
+ if (pass & FR_RETICMP) {
+ verbose("- ICMP unreachable sent\n");
+ frstats[0].fr_ret++;
+ } else if ((pass & FR_RETRST) &&
+ !(fin->fin_fi.fi_fl & FI_SHORT)) {
+ verbose("- TCP RST sent\n");
+ frstats[1].fr_ret++;
+ }
+#endif
+ }
+#ifdef _KERNEL
+# if !SOLARIS
+ if (pass & FR_DUP)
+ mc = m_copy(m, 0, M_COPYALL);
+ if (fr) {
+ frdest_t *fdp = &fr->fr_tif;
+
+ if ((pass & FR_FASTROUTE) ||
+ (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
+ ipfr_fastroute(m, fin, fdp);
+ m = *mp = NULL;
+ pass = 0;
+ }
+ if (mc)
+ ipfr_fastroute(mc, fin, &fr->fr_dif);
+ }
+ if (!(pass & FR_PASS) && m)
+ m_freem(m);
+ return (pass & FR_PASS) ? 0 : -1;
+# else
+ if (pass & FR_DUP)
+ mc = dupmsg(m);
+ if (fr) {
+ frdest_t *fdp = &fr->fr_tif;
+
+ if ((pass & FR_FASTROUTE) ||
+ (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
+ ipfr_fastroute(qif, ip, m, mp, fin, fdp);
+ m = *mp = NULL;
+ }
+ if (mc)
+ ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif);
+ }
+ return (pass & FR_PASS) ? changed : -1;
+# endif
+#else
+ if (pass & FR_NOMATCH)
+ return 1;
+ if (pass & FR_PASS)
+ return 0;
+ return -1;
+#endif
+}
+
+
+#ifdef IPFILTER_LOG
+# if !(defined(_KERNEL))
+static void ipllog()
+{
+ verbose("l");
+}
+# endif
+
+
+int fr_copytolog(buf, len)
+char *buf;
+int len;
+{
+ int clen, tail;
+
+ tail = (iplh >= iplt) ? (iplbuf + IPLLOGSIZE - iplh) : (iplt - iplh);
+ clen = MIN(tail, len);
+ bcopy(buf, iplh, clen);
+ len -= clen;
+ tail -= clen;
+ iplh += clen;
+ buf += clen;
+ if (iplh == iplbuf + IPLLOGSIZE) {
+ iplh = iplbuf;
+ tail = iplt - iplh;
+ }
+ if (len && tail) {
+ clen = MIN(tail, len);
+ bcopy(buf, iplh, clen);
+ len -= clen;
+ iplh += clen;
+ }
+ return len;
+}
+#endif
diff --git a/contrib/ipfilter/fils.c b/contrib/ipfilter/fils.c
new file mode 100644
index 0000000..249611b
--- /dev/null
+++ b/contrib/ipfilter/fils.c
@@ -0,0 +1,366 @@
+/*
+ * (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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <nlist.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>
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include "ip_nat.h"
+#include "ip_frag.h"
+#include "ip_state.h"
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "kmem.h"
+#ifdef __NetBSD__
+#include <paths.h>
+#endif
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-1996 Darren Reed";
+static char rcsid[] = "$Id: fils.c,v 2.0.1.2 1997/01/30 10:21:48 darrenr Exp $";
+#endif
+#ifdef _PATH_UNIX
+#define VMUNIX _PATH_UNIX
+#else
+#define VMUNIX "/vmunix"
+#endif
+
+extern char *optarg;
+
+#define PRINTF (void)printf
+#define FPRINTF (void)fprintf
+#define F_IN 0
+#define F_OUT 1
+#define F_AC 2
+static char *filters[4] = { "ipfilter(in)", "ipfilter(out)",
+ "ipacct(in)", "ipacct(out)" };
+
+int opts = 0;
+
+static void showstats(), showfrstates();
+static void showlist(), showipstates();
+
+void Usage(name)
+char *name;
+{
+ fprintf(stderr, "Usage: %s [-afhIiosv] [-d <device>]\n", name);
+ exit(1);
+}
+
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ friostat_t fio;
+ ips_stat_t ipsst;
+ ipfrstat_t ifrst;
+ char c, *name = NULL, *device = IPL_NAME;
+ int fd;
+
+ if (openkmem() == -1)
+ exit(-1);
+
+ (void)setuid(getuid());
+ (void)setgid(getgid());
+
+ while ((c = getopt(argc, argv, "afhIiosvd:")) != -1)
+ {
+ switch (c)
+ {
+ case 'a' :
+ opts |= OPT_ACCNT|OPT_SHOWLIST;
+ break;
+ case 'd' :
+ device = optarg;
+ break;
+ case 'f' :
+ opts |= OPT_FRSTATES;
+ break;
+ case 'h' :
+ opts |= OPT_HITS;
+ break;
+ case 'i' :
+ opts |= OPT_INQUE|OPT_SHOWLIST;
+ break;
+ case 'n' :
+ opts |= OPT_SHOWLINENO;
+ break;
+ case 'I' :
+ opts |= OPT_INACTIVE;
+ break;
+ case 'o' :
+ opts |= OPT_OUTQUE|OPT_SHOWLIST;
+ break;
+ case 's' :
+ opts |= OPT_IPSTATES;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ Usage(argv[0]);
+ break;
+ }
+ }
+
+ if ((fd = open(device, O_RDONLY)) < 0) {
+ perror("open");
+ exit(-1);
+ }
+
+ bzero((char *)&fio, sizeof(fio));
+ bzero((char *)&ipsst, sizeof(ipsst));
+ bzero((char *)&ifrst, sizeof(ifrst));
+
+ if (ioctl(fd, SIOCGETFS, &fio) == -1) {
+ perror("ioctl(SIOCGETFS)");
+ exit(-1);
+ }
+ if ((opts & OPT_IPSTATES) && (ioctl(fd, SIOCGIPST, &ipsst) == -1)) {
+ perror("ioctl(SIOCGIPST)");
+ exit(-1);
+ }
+ if ((opts & OPT_FRSTATES) && (ioctl(fd, SIOCGFRST, &ifrst) == -1)) {
+ perror("ioctl(SIOCGFRST)");
+ exit(-1);
+ }
+
+ if (opts & OPT_VERBOSE)
+ PRINTF("opts %#x name %s\n", opts, name ? name : "<>");
+ if (opts & OPT_SHOWLIST) {
+ showlist(&fio);
+ if((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
+ opts &= ~OPT_OUTQUE;
+ showlist(&fio);
+ }
+ } else {
+ if (opts & OPT_IPSTATES)
+ showipstates(fd, &ipsst);
+ else if (opts & OPT_FRSTATES)
+ showfrstates(fd, &ifrst);
+ else
+ showstats(fd, &fio);
+ }
+ return 0;
+}
+
+
+/*
+ * read the kernel stats for packets blocked and passed
+ */
+static void showstats(fd, fp)
+int fd;
+struct friostat *fp;
+{
+ int frf = 0;
+
+ if (ioctl(fd, SIOCGETFF, &frf) == -1)
+ perror("ioctl(SIOCGETFF)");
+
+#if SOLARIS
+ PRINTF("dropped packets:\tin %lu\tout %lu\n",
+ fp->f_st[0].fr_drop, fp->f_st[1].fr_drop);
+ PRINTF("non-ip packets:\t\tin %lu\tout %lu\n",
+ fp->f_st[0].fr_notip, fp->f_st[1].fr_notip);
+ PRINTF(" bad packets:\t\tin %lu\tout %lu\n",
+ fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
+#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\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 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\n",
+ fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr);
+ PRINTF("fragment state(out):\tkept %lu\tlost %lu\n",
+ fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr);
+ 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("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("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)
+ PRINTF("\tnone\n");
+}
+
+/*
+ * print out filter rule list
+ */
+static void showlist(fiop)
+struct friostat *fiop;
+{
+ struct frentry fb;
+ struct frentry *fp = NULL;
+ int i, set, n;
+
+ set = fiop->f_active;
+ if (opts & OPT_INACTIVE)
+ set = 1 - set;
+ if (opts & OPT_ACCNT) {
+ i = F_AC;
+ if (opts & OPT_OUTQUE) {
+ fp = (struct frentry *)fiop->f_acctout[set];
+ i++;
+ } else if (opts & OPT_INQUE)
+ fp = (struct frentry *)fiop->f_acctin[set];
+ } else if (opts & OPT_OUTQUE) {
+ i = F_OUT;
+ fp = (struct frentry *)fiop->f_fout[set];
+ } else if (opts & OPT_INQUE) {
+ i = F_IN;
+ fp = (struct frentry *)fiop->f_fin[set];
+ } else
+ return;
+ if (opts & OPT_VERBOSE)
+ FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
+
+ if (opts & OPT_VERBOSE)
+ PRINTF("fp %#x set %d\n", (u_int)fp, set);
+ if (!fp) {
+ FPRINTF(stderr, "empty list for %s%s\n",
+ (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]);
+ return;
+ }
+
+ for (n = 1; fp; n++) {
+ if (kmemcpy((char *)&fb, (u_long)fp, sizeof(fb)) == -1) {
+ perror("kmemcpy");
+ return;
+ }
+ fp = &fb;
+ if (opts & OPT_OUTQUE)
+ fp->fr_flags |= FR_OUTQUE;
+ if (opts & (OPT_HITS|OPT_VERBOSE))
+ PRINTF("%ld ", fp->fr_hits);
+ if (opts & (OPT_ACCNT|OPT_VERBOSE))
+ PRINTF("%ld ", fp->fr_bytes);
+ if (opts & OPT_SHOWLINENO)
+ PRINTF("@%d ", n);
+ printfr(fp);
+ if (opts & OPT_VERBOSE)
+ binprint(fp);
+ fp = fp->fr_next;
+ }
+}
+
+
+static void showipstates(fd, ipsp)
+int fd;
+ips_stat_t *ipsp;
+{
+ ipstate_t *istab[IPSTATE_SIZE], ips;
+ int i;
+
+ PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n",
+ ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp);
+ PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, ipsp->iss_miss);
+ PRINTF("\t%lu maximum\n\t%lu no memory\n",
+ ipsp->iss_max, ipsp->iss_nomem);
+ PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n",
+ ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin);
+ if (kmemcpy((char *)istab, (u_long)ipsp->iss_table, sizeof(istab)))
+ return;
+ for (i = 0; i < IPSTATE_SIZE; i++)
+ while (istab[i]) {
+ if (kmemcpy(&ips, istab[i], sizeof(ips)) == -1)
+ break;
+ PRINTF("%s -> ", inet_ntoa(ips.is_src));
+ PRINTF("%s age %d pass %d pr %d state %d/%d\n",
+ inet_ntoa(ips.is_dst), ips.is_age,
+ ips.is_pass, ips.is_p, ips.is_state[0],
+ ips.is_state[1]);
+ if (ips.is_p == IPPROTO_TCP)
+ PRINTF("\t%hu -> %hu %lu:%lu %hu:%hu\n",
+ ntohs(ips.is_sport),
+ ntohs(ips.is_dport),
+ ips.is_seq, ips.is_ack,
+ ips.is_swin, ips.is_dwin);
+ else if (ips.is_p == IPPROTO_UDP)
+ PRINTF("\t%hu -> %hu\n", ntohs(ips.is_sport),
+ ntohs(ips.is_dport));
+ else if (ips.is_p == IPPROTO_ICMP)
+ PRINTF("\t%hu %hu %d\n", ips.is_icmp.ics_id,
+ ips.is_icmp.ics_seq,
+ ips.is_icmp.ics_type);
+ istab[i] = ips.is_next;
+ }
+}
+
+
+static void showfrstates(fd, ifsp)
+int fd;
+ipfrstat_t *ifsp;
+{
+ struct ipfr *ipfrtab[IPFT_SIZE], ifr;
+ int i;
+
+ 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 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;
+ for (i = 0; i < IPFT_SIZE; i++)
+ while (ipfrtab[i]) {
+ if (kmemcpy(&ifr, (u_long)ipfrtab[i],
+ sizeof(ifr)) == -1)
+ break;
+ PRINTF("%s -> ", inet_ntoa(ifr.ipfr_src));
+ PRINTF("%s %d %d %d %#02x = %#x\n",
+ inet_ntoa(ifr.ipfr_dst), ifr.ipfr_id,
+ ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_tos,
+ ifr.ipfr_pass);
+ ipfrtab[i] = ifr.ipfr_next;
+ }
+}
diff --git a/contrib/ipfilter/inet_addr.c b/contrib/ipfilter/inet_addr.c
new file mode 100644
index 0000000..91faec3
--- /dev/null
+++ b/contrib/ipfilter/inet_addr.c
@@ -0,0 +1,182 @@
+/*
+ * ++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) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static char rcsid[] = "$Id: inet_addr.c,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+/*
+ * 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);
+}
+
+/* these are compatibility routines, not needed on recent BSD releases */
+
+/*
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+u_long
+inet_addr(cp)
+ register const char *cp;
+{
+ struct in_addr val;
+
+ if (inet_aton(cp, &val))
+ return (val.s_addr);
+ return (0xffffffff);
+}
diff --git a/contrib/ipfilter/ip_compat.h b/contrib/ipfilter/ip_compat.h
new file mode 100644
index 0000000..5a36cc3
--- /dev/null
+++ b/contrib/ipfilter/ip_compat.h
@@ -0,0 +1,342 @@
+/*
+ * (C)opyright 1993, 1994, 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ip_compat.h 1.8 1/14/96
+ * $Id: ip_compat.h,v 2.0.1.4 1997/02/04 14:24:25 darrenr Exp $
+ */
+
+#ifndef __IP_COMPAT_H_
+#define __IP_COMPAT_H__
+
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+#if SOLARIS
+#define MTYPE(m) ((m)->b_datap->db_type)
+#endif
+#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
+
+#ifndef IP_OFFMASK
+#define IP_OFFMASK 0x1fff
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/*
+ * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108.
+ *
+ * Basic Option
+ *
+ * 00000001 - (Reserved 4)
+ * 00111101 - Top Secret
+ * 01011010 - Secret
+ * 10010110 - Confidential
+ * 01100110 - (Reserved 3)
+ * 11001100 - (Reserved 2)
+ * 10101011 - Unclassified
+ * 11110001 - (Reserved 1)
+ */
+#define IPSO_CLASS_RES4 0x01
+#define IPSO_CLASS_TOPS 0x3d
+#define IPSO_CLASS_SECR 0x5a
+#define IPSO_CLASS_CONF 0x96
+#define IPSO_CLASS_RES3 0x66
+#define IPSO_CLASS_RES2 0xcc
+#define IPSO_CLASS_UNCL 0xab
+#define IPSO_CLASS_RES1 0xf1
+
+#define IPSO_AUTH_GENSER 0x80
+#define IPSO_AUTH_ESI 0x40
+#define IPSO_AUTH_SCI 0x20
+#define IPSO_AUTH_NSA 0x10
+#define IPSO_AUTH_DOE 0x08
+#define IPSO_AUTH_UN 0x06
+#define IPSO_AUTH_FTE 0x01
+
+/*
+ * IP option #defines
+ */
+/*#define IPOPT_RR 7 */
+#define IPOPT_ZSU 10 /* ZSU */
+#define IPOPT_MTUP 11 /* MTUP */
+#define IPOPT_MTUR 12 /* MTUR */
+#define IPOPT_ENCODE 15 /* ENCODE */
+/*#define IPOPT_TS 68 */
+#define IPOPT_TR 82 /* TR */
+/*#define IPOPT_SECURITY 130 */
+/*#define IPOPT_LSRR 131 */
+#define IPOPT_E_SEC 133 /* E-SEC */
+#define IPOPT_CIPSO 134 /* CIPSO */
+/*#define IPOPT_SATID 136 */
+#ifndef IPOPT_SID
+# define IPOPT_SID IPOPT_SATID
+#endif
+/*#define IPOPT_SSRR 137 */
+#define IPOPT_ADDEXT 147 /* ADDEXT */
+#define IPOPT_VISA 142 /* VISA */
+#define IPOPT_IMITD 144 /* IMITD */
+#define IPOPT_EIP 145 /* EIP */
+#define IPOPT_FINN 205 /* FINN */
+
+
+/*
+ * Build some macros and #defines to enable the same code to compile anywhere
+ * Well, that's the idea, anyway :-)
+ */
+#ifdef _KERNEL
+# if SOLARIS
+# define MUTEX_ENTER(x) mutex_enter(x)
+# define MUTEX_EXIT(x) mutex_exit(x)
+# define MTOD(m,t) (t)((m)->b_rptr)
+# define IRCOPY(a,b,c) copyin((a), (b), (c))
+# define IWCOPY(a,b,c) copyout((a), (b), (c))
+# else
+# define MUTEX_ENTER(x) ;
+# define MUTEX_EXIT(x) ;
+# ifndef linux
+# define MTOD(m,t) mtod(m,t)
+# define IRCOPY(a,b,c) bcopy((a), (b), (c))
+# define IWCOPY(a,b,c) bcopy((a), (b), (c))
+# endif
+# endif /* SOLARIS */
+
+# ifdef sun
+# if defined(__svr4__) || defined(__SVR4)
+# define GETUNIT(n) get_unit((n))
+# else
+# include <sys/kmem_alloc.h>
+# define GETUNIT(n) ifunit((n), IFNAMSIZ)
+# endif
+# else
+# define GETUNIT(n) ifunit((n))
+# endif /* sun */
+
+# if defined(sun) && !defined(linux)
+# define UIOMOVE(a,b,c,d) uiomove(a,b,c,d)
+# define SLEEP(id, n) sleep((id), PZERO+1)
+# define KFREE(x) kmem_free((char *)(x), sizeof(*(x)))
+# if SOLARIS
+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_wqinfo;
+ void *qf_rqinfo;
+ int (*qf_inp)();
+ int (*qf_outp)();
+ mblk_t *qf_m;
+ int qf_len;
+ char qf_name[8];
+ /*
+ * in case the ILL has disappeared...
+ */
+ int qf_hl; /* header length */
+} qif_t;
+# define SPLNET(x) ;
+# undef SPLX
+# define SPLX(x) ;
+# ifdef sparc
+# define ntohs(x) (x)
+# define ntohl(x) (x)
+# define htons(x) (x)
+# define htonl(x) (x)
+# endif
+# define KMALLOC(x) kmem_alloc((x), KM_NOSLEEP)
+# define GET_MINOR(x) getminor(x)
+# else
+# define KMALLOC(x) new_kmem_alloc((x), KMEM_NOSLEEP)
+# endif /* __svr4__ */
+# endif /* sun && !linux */
+# ifndef GET_MINOR
+# define GET_MINOR(x) minor(x)
+# endif
+# if BSD >= 199306 || defined(__FreeBSD__)
+# include <vm/vm.h>
+# if !defined(__FreeBSD__)
+# include <vm/vm_extern.h>
+# include <sys/proc.h>
+extern vm_map_t kmem_map;
+# else
+# include <vm/vm_kern.h>
+# endif /* __FreeBSD__ */
+/*
+** # define KMALLOC(x) kmem_alloc(kmem_map, (x))
+** # define KFREE(x) kmem_free(kmem_map, (vm_offset_t)(x), \
+ sizeof(*(x)))
+*/
+# ifdef M_PFIL
+# define KMALLOC(x) malloc((x), M_PFIL, M_NOWAIT)
+# define KFREE(x) FREE((x), M_PFIL)
+# else
+# define KMALLOC(x) malloc((x), M_TEMP, M_NOWAIT)
+# define KFREE(x) FREE((x), M_TEMP)
+# endif
+# define UIOMOVE(a,b,c,d) uiomove(a,b,d)
+# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0)
+# endif /* BSD */
+# if defined(NetBSD1_0) && (NetBSD1_0 > 1)
+# define SPLNET(x) x = splsoftnet()
+# else
+# if !SOLARIS
+# define SPLNET(x) x = splnet()
+# define SPLX(x) (void) splx(x)
+# endif
+# endif
+#else
+# ifndef linux
+# define MUTEX_ENTER(x) ;
+# define MUTEX_EXIT(x) ;
+# define SPLNET(x) ;
+# define SPLX(x) ;
+# define KMALLOC(x) malloc(x)
+# define KFREE(x) free(x)
+# define GETUNIT(x) (x)
+# define IRCOPY(a,b,c) bcopy((a), (b), (c))
+# define IWCOPY(a,b,c) bcopy((a), (b), (c))
+# endif
+#endif /* KERNEL */
+
+#ifdef linux
+# define ICMP_UNREACH ICMP_DEST_UNREACH
+# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH
+# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED
+# define ICMP_PARAMPROB ICMP_PARAMETERPROB
+
+# define TH_FIN 0x01
+# define TH_SYN 0x02
+# define TH_RST 0x04
+# define TH_PUSH 0x08
+# define TH_ACK 0x10
+# define TH_URG 0x20
+
+typedef struct {
+ __u16 th_sport;
+ __u16 th_dport;
+ __u32 th_seq;
+ __u32 th_ack;
+ __u8 th_x;
+ __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_sun;
+} udphdr_t;
+
+typedef struct {
+# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\
+ defined(vax)
+ __u8 ip_hl:4;
+ __u8 ip_v:4;
+# else
+ __u8 ip_hl:4;
+ __u8 ip_v: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.
+ */
+struct icmp {
+ u_char icmp_type; /* type of message, see below */
+ u_char icmp_code; /* type sub code */
+ u_short icmp_cksum; /* ones complement cksum of struct */
+ union {
+ u_char ih_pptr; /* ICMP_PARAMPROB */
+ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
+ struct ih_idseq {
+ n_short icd_id;
+ n_short 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
+};
+
+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 */
+};
+
+# define SPLX(x) (void)
+# define SPLNET(x) (void)
+
+# define bcopy(a,b,c) memmove(b,a,c)
+# define bcmp(a,b,c) memcmp(a,b,c)
+
+# define UNITNAME(n) dev_get((n))
+# define ifnet device
+
+# define KMALLOC(x) kmalloc((x), GFP_ATOMIC)
+# define KFREE(x) kfree_s((x), sizeof(*(x)))
+# define IRCOPY(a,b,c) { \
+ error = verify_area(VERIFY_READ, \
+ (b) ,sizeof((b))); \
+ if (!error) \
+ memcpy_fromfs((b), (a), (c)); \
+ }
+# define IWCOPY(a,b,c) { \
+ error = verify_area(VERIFY_WRITE, \
+ (b) ,sizeof((b))); \
+ if (!error) \
+ memcpy_tofs((b), (a), (c)); \
+ }
+#else
+typedef struct tcphdr tcphdr_t;
+typedef struct udphdr udphdr_t;
+typedef struct icmp icmphdr_t;
+typedef struct ip ip_t;
+#endif /* linux */
+
+#endif /* __IP_COMPAT_H__ */
diff --git a/contrib/ipfilter/ip_fil.c b/contrib/ipfilter/ip_fil.c
new file mode 100644
index 0000000..7a24434
--- /dev/null
+++ b/contrib/ipfilter/ip_fil.c
@@ -0,0 +1,885 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed";
+static char rcsid[] = "$Id: ip_fil.c,v 2.0.1.5 1997/01/29 13:41:45 darrenr Exp $";
+#endif
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#ifdef sun
+#include <net/af.h>
+#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>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include <syslog.h>
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include "ip_frag.h"
+#include "ip_nat.h"
+#include "ip_state.h"
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+extern fr_flags, fr_active;
+extern struct protosw inetsw[];
+extern int (*fr_checkp)();
+#if BSD < 199306
+extern int ipfr_slowtimer();
+static int (*fr_saveslowtimo)();
+extern int tcp_ttl;
+#else
+extern void ipfr_slowtimer();
+static void (*fr_saveslowtimo)();
+#endif
+
+int ipl_inited = 0;
+int ipl_unreach = ICMP_UNREACH_FILTER;
+int send_reset();
+
+#ifdef IPFILTER_LOG
+# define LOGSIZE 8192
+int ipllog();
+char iplbuf[LOGSIZE];
+caddr_t iplh = iplbuf, iplt = iplbuf;
+static int iplused = 0;
+#endif /* IPFILTER_LOG */
+static void frflush();
+static int frrequest();
+static int (*fr_savep)();
+
+#if _BSDI_VERSION >= 199501
+# include <sys/device.h>
+# include <sys/conf.h>
+
+int iplioctl __P((dev_t, int, caddr_t, int, struct proc *));
+int iplopen __P((dev_t, int, int, struct proc *));
+int iplclose __P((dev_t, int, int, struct proc *));
+# ifdef IPFILTER_LOG
+int iplread __P((dev_t, struct uio *, int));
+# else
+# define iplread noread
+# endif
+int iplioctl __P((dev_t, int, caddr_t, int, struct proc *));
+
+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 >= 199501 */
+
+#ifdef IPFILTER_LKM
+int iplidentify(s)
+char *s;
+{
+ if (strcmp(s, "ipl") == 0)
+ return 1;
+ return 0;
+}
+#endif /* IPFILTER_LKM */
+
+
+int iplattach()
+{
+ int s;
+
+ SPLNET(s);
+ if (ipl_inited || (fr_checkp == fr_check)) {
+ printf("IP Filter: already initialized\n");
+ SPLX(s);
+ return EBUSY;
+ }
+ ipl_inited = 1;
+ bzero((char *)nat_table, sizeof(nat_t *) * NAT_SIZE * 2);
+ fr_savep = fr_checkp;
+ fr_checkp = fr_check;
+ fr_saveslowtimo = inetsw[0].pr_slowtimo;
+ inetsw[0].pr_slowtimo = ipfr_slowtimer;
+ SPLX(s);
+ return 0;
+}
+
+
+int ipldetach()
+{
+ int s, i = FR_INQUE|FR_OUTQUE;
+
+ SPLNET(s);
+ if (!ipl_inited)
+ {
+ printf("IP Filter: not initialized\n");
+ SPLX(s);
+ return EBUSY;
+ }
+
+ fr_checkp = fr_savep;
+ inetsw[0].pr_slowtimo = fr_saveslowtimo;
+ frflush((caddr_t)&i);
+ ipl_inited = 0;
+
+ ipfr_unload();
+ ip_natunload();
+ fr_stateunload();
+
+ SPLX(s);
+ return 0;
+}
+
+
+static void frzerostats(data)
+caddr_t data;
+{
+ struct friostat fio;
+
+ bcopy((char *)frstats, (char *)fio.f_st,
+ sizeof(struct filterstats) * 2);
+ fio.f_fin[0] = ipfilter[0][0];
+ fio.f_fin[1] = ipfilter[0][1];
+ fio.f_fout[0] = ipfilter[1][0];
+ fio.f_fout[1] = ipfilter[1][1];
+ fio.f_acctin[0] = ipacct[0][0];
+ fio.f_acctin[1] = ipacct[0][1];
+ fio.f_acctout[0] = ipacct[1][0];
+ fio.f_acctout[1] = ipacct[1][1];
+ fio.f_active = fr_active;
+ IWCOPY((caddr_t)&fio, data, sizeof(fio));
+ bzero((char *)frstats, sizeof(*frstats) * 2);
+}
+
+
+static void frflush(data)
+caddr_t data;
+{
+ struct frentry *f, **fp;
+ int flags = *(int *)data, flushed = 0, set = fr_active;
+
+ bzero((char *)frcache, sizeof(frcache[0]) * 2);
+
+ if (flags & FR_INACTIVE)
+ set = 1 - set;
+ if (flags & FR_OUTQUE) {
+ for (fp = &ipfilter[1][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ for (fp = &ipacct[1][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ }
+ if (flags & FR_INQUE) {
+ for (fp = &ipfilter[0][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ for (fp = &ipacct[0][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ }
+ *(int *)data = flushed;
+}
+
+
+/*
+ * Filter ioctl interface.
+ */
+int iplioctl(dev, cmd, data, mode
+#if _BSDI_VERSION >= 199501
+, p)
+struct proc *p;
+#else
+)
+#endif
+dev_t dev;
+int cmd;
+caddr_t data;
+int mode;
+{
+ int error = 0, s, unit;
+
+ unit = minor(dev);
+ if (unit != 0)
+ return ENXIO;
+
+ SPLNET(s);
+ switch (cmd) {
+ case FIONREAD :
+#ifdef IPFILTER_LOG
+ *(int *)data = iplused;
+#endif
+ break;
+#ifndef IPFILTER_LKM
+ case SIOCFRENB :
+ {
+ u_int enable;
+
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else {
+ IRCOPY(data, (caddr_t)&enable, sizeof(enable));
+ if (enable)
+ error = iplattach();
+ else
+ error = ipldetach();
+ }
+ break;
+ }
+#endif
+ case SIOCSETFF :
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else
+ IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags));
+ break;
+ case SIOCGETFF :
+ IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
+ break;
+ case SIOCINAFR :
+ case SIOCRMAFR :
+ case SIOCADAFR :
+ case SIOCZRLST :
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else
+ error = frrequest(cmd, data, fr_active);
+ break;
+ case SIOCINIFR :
+ case SIOCRMIFR :
+ case SIOCADIFR :
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else
+ error = frrequest(cmd, data, 1 - fr_active);
+ 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 :
+ {
+ struct friostat fio;
+
+ bcopy((char *)frstats, (char *)fio.f_st,
+ sizeof(struct filterstats) * 2);
+ fio.f_fin[0] = ipfilter[0][0];
+ fio.f_fin[1] = ipfilter[0][1];
+ fio.f_fout[0] = ipfilter[1][0];
+ fio.f_fout[1] = ipfilter[1][1];
+ fio.f_acctin[0] = ipacct[0][0];
+ fio.f_acctin[1] = ipacct[0][1];
+ fio.f_acctout[0] = ipacct[1][0];
+ fio.f_acctout[1] = ipacct[1][1];
+ fio.f_active = fr_active;
+ IWCOPY((caddr_t)&fio, data, sizeof(fio));
+ break;
+ }
+ case SIOCFRZST :
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else
+ frzerostats(data);
+ break;
+ case SIOCIPFFL :
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else
+ frflush(data);
+ break;
+#ifdef IPFILTER_LOG
+ case SIOCIPFFB :
+ if (!(mode & FWRITE))
+ error = EPERM;
+ else {
+ *(int *)data = iplused;
+ iplh = iplt = iplbuf;
+ iplused = 0;
+ }
+ break;
+#endif /* IPFILTER_LOG */
+ case SIOCADNAT :
+ case SIOCRMNAT :
+ case SIOCGNATS :
+ case SIOCGNATL :
+ case SIOCFLNAT :
+ case SIOCCNATL :
+ error = nat_ioctl(data, cmd, mode);
+ break;
+ case SIOCGFRST :
+ IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t));
+ break;
+ case SIOCGIPST :
+ IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
+ break;
+ default :
+ error = EINVAL;
+ break;
+ }
+ SPLX(s);
+ return error;
+}
+
+
+static int frrequest(req, data, set)
+int req, set;
+caddr_t data;
+{
+ register frentry_t *fp, *f, **fprev;
+ register frentry_t **ftail;
+ frentry_t fr;
+ frdest_t *fdp;
+ struct frentry frd;
+ int error = 0, in;
+
+ fp = &fr;
+ IRCOPY(data, (caddr_t)fp, sizeof(*fp));
+
+ bzero((char *)frcache, sizeof(frcache[0]) * 2);
+
+ in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
+ if (fp->fr_flags & FR_ACCOUNT) {
+ ftail = fprev = &ipacct[in][set];
+ } else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE))
+ ftail = fprev = &ipfilter[in][set];
+ else
+ return ESRCH;
+
+ IRCOPY((char *)fp, (char *)&frd, sizeof(frd));
+ fp = &frd;
+ if (*fp->fr_ifname) {
+ fp->fr_ifa = GETUNIT(fp->fr_ifname);
+ if (!fp->fr_ifa)
+ fp->fr_ifa = (struct ifnet *)-1;
+ }
+
+ fdp = &fp->fr_dif;
+ fp->fr_flags &= ~FR_DUP;
+ if (*fdp->fd_ifname) {
+ fdp->fd_ifp = GETUNIT(fdp->fd_ifname);
+ 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);
+ 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 (; (f = *ftail); ftail = &f->fr_next)
+ if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip,
+ FR_CMPSIZ) == 0)
+ break;
+
+ /*
+ * If zero'ing statistics, copy current to caller and zero.
+ */
+ if (req == SIOCZRLST) {
+ if (!f)
+ return ESRCH;
+ IWCOPY((caddr_t)f, data, sizeof(*f));
+ f->fr_hits = 0;
+ f->fr_bytes = 0;
+ return 0;
+ }
+
+ if (!f) {
+ ftail = fprev;
+ if (req != SIOCINAFR && req != SIOCINIFR)
+ while ((f = *ftail))
+ ftail = &f->fr_next;
+ else if (fp->fr_hits)
+ while (--fp->fr_hits && (f = *ftail))
+ ftail = &f->fr_next;
+ f = NULL;
+ }
+
+ if (req == SIOCDELFR || req == SIOCRMIFR) {
+ if (!f)
+ error = ESRCH;
+ else {
+ *ftail = f->fr_next;
+ (void) KFREE(f);
+ }
+ } else {
+ if (f)
+ error = EEXIST;
+ else {
+ if ((f = (struct frentry *)KMALLOC(sizeof(*f)))) {
+ bcopy((char *)fp, (char *)f, sizeof(*f));
+ f->fr_hits = 0;
+ f->fr_next = *ftail;
+ *ftail = f;
+ } else
+ error = ENOMEM;
+ }
+ }
+ return (error);
+}
+
+
+#if !defined(linux)
+/*
+ * routines below for saving IP headers to buffer
+ */
+int iplopen(dev, flags
+#if _BSDI_VERSION >= 199501
+, devtype, p)
+int devtype;
+struct proc *p;
+#else
+)
+#endif
+dev_t dev;
+int flags;
+{
+ u_int min = minor(dev);
+
+ if (min)
+ min = ENXIO;
+ return min;
+}
+
+
+int iplclose(dev, flags
+#if _BSDI_VERSION >= 199501
+, devtype, p)
+int devtype;
+struct proc *p;
+#else
+)
+#endif
+dev_t dev;
+int flags;
+{
+ u_int min = minor(dev);
+
+ if (min)
+ min = ENXIO;
+ return min;
+}
+
+# ifdef IPFILTER_LOG
+/*
+ * 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
+dev_t dev;
+register struct uio *uio;
+{
+ register int ret, s;
+ register size_t sz, sx;
+ int error;
+
+ if (!uio->uio_resid)
+ return 0;
+ while (!iplused) {
+ error = SLEEP(iplbuf, "ipl sleep");
+ if (error)
+ return error;
+ }
+ SPLNET(s);
+
+ sx = sz = MIN(uio->uio_resid, iplused);
+ if (iplh < iplt)
+ sz = MIN(sz, LOGSIZE - (iplt - iplbuf));
+ sx -= sz;
+
+# if BSD >= 199306 || defined(__FreeBSD__)
+ uio->uio_rw = UIO_READ;
+# endif
+ if (!(ret = UIOMOVE(iplt, sz, UIO_READ, uio))) {
+ iplt += sz;
+ iplused -= sz;
+ if ((iplh < iplt) && (iplt == iplbuf + LOGSIZE))
+ iplt = iplbuf;
+
+ if (sx && !(ret = UIOMOVE(iplt, sx, UIO_READ, uio))) {
+ iplt += sx;
+ iplused -= sx;
+ if ((iplh < iplt) && (iplt == iplbuf + LOGSIZE))
+ iplt = iplbuf;
+ }
+ if (!iplused) /* minimise wrapping around the end */
+ iplh = iplt = iplbuf;
+ }
+ SPLX(s);
+ return ret;
+}
+# endif /* IPFILTER_LOG */
+#endif /* linux */
+
+
+#ifdef IPFILTER_LOG
+int ipllog(flags, ip, fin, m)
+u_int flags;
+ip_t *ip;
+register fr_info_t *fin;
+struct mbuf *m;
+{
+ struct ipl_ci iplci;
+ register int len, mlen, hlen;
+ struct ifnet *ifp = fin->fin_ifp;
+
+ hlen = fin->fin_hlen;
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
+ else if (ip->ip_p == IPPROTO_ICMP) {
+ struct icmp *icmp = (struct icmp *)((char *)ip + hlen);
+
+ switch (icmp->icmp_type) {
+ case ICMP_UNREACH :
+ case ICMP_SOURCEQUENCH :
+ case ICMP_REDIRECT :
+ case ICMP_TIMXCEED :
+ case ICMP_PARAMPROB :
+ hlen += MIN(sizeof(struct icmp) + 8, fin->fin_dlen);
+ break;
+ default :
+ hlen += MIN(sizeof(struct icmp), fin->fin_dlen);
+ break;
+ }
+ }
+
+ mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0;
+ len = hlen + sizeof(iplci) + mlen;
+ if (iplused + len > LOGSIZE)
+ return 0;
+ iplused += len;
+
+# ifdef sun
+ uniqtime(&iplci);
+# endif
+# if BSD >= 199306 || defined(__FreeBSD__)
+ microtime((struct timeval *)&iplci);
+# endif
+ iplci.flags = flags;
+ iplci.hlen = (u_char)hlen;
+ iplci.plen = (u_char)mlen;
+ iplci.rule = fin->fin_rule;
+# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603))
+ strncpy(iplci.ifname, ifp->if_xname, IFNAMSIZ);
+# else
+ iplci.unit = (u_char)ifp->if_unit;
+ if ((iplci.ifname[0] = ifp->if_name[0]))
+ if ((iplci.ifname[1] = ifp->if_name[1]))
+ if ((iplci.ifname[2] = ifp->if_name[2]))
+ iplci.ifname[3] = ifp->if_name[3];
+# endif
+ /*
+ * Gauranteed to succeed from above
+ */
+ (void) fr_copytolog(&iplci, sizeof(iplci));
+
+ for (len -= sizeof(iplci); m && len > 0; m = m->m_next, len -= hlen) {
+ hlen = MIN(len, m->m_len);
+ if (fr_copytolog(mtod(m, char *), hlen))
+ break;
+ }
+
+ wakeup(iplbuf);
+ return 1;
+}
+#endif /* IPFILTER_LOG */
+
+/*
+ * 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(ti)
+struct tcpiphdr *ti;
+{
+ struct tcpiphdr *tp;
+ struct ip *ip;
+ struct tcphdr *tcp;
+ struct mbuf *m;
+ int tlen = 0;
+
+ if (ti->ti_flags & TH_RST)
+ return -1; /* feedback loop */
+#if BSD < 199306
+ m = m_get(M_DONTWAIT, MT_HEADER);
+#else
+ m = m_gethdr(M_DONTWAIT, MT_HEADER);
+ m->m_data += max_linkhdr;
+#endif
+ if (m == NULL)
+ return -1;
+
+ if (ti->ti_flags & TH_SYN)
+ tlen = 1;
+ m->m_len = sizeof (struct tcpiphdr);
+#if BSD >= 199306
+ m->m_pkthdr.len = sizeof (struct tcpiphdr);
+ m->m_pkthdr.rcvif = (struct ifnet *)0;
+#endif
+ bzero(mtod(m, char *), sizeof(struct tcpiphdr));
+ ip = mtod(m, struct ip *);
+ tp = mtod(m, struct tcpiphdr *);
+ tcp = (struct tcphdr *)((char *)ip + sizeof(struct ip));
+
+ ip->ip_src.s_addr = ti->ti_dst.s_addr;
+ ip->ip_dst.s_addr = ti->ti_src.s_addr;
+ tcp->th_dport = ti->ti_sport;
+ tcp->th_sport = ti->ti_dport;
+ tcp->th_ack = htonl(ntohl(ti->ti_seq) + tlen);
+ tcp->th_off = sizeof(struct tcphdr) >> 2;
+ tcp->th_flags = TH_RST|TH_ACK;
+ tp->ti_pr = ((struct ip *)ti)->ip_p;
+ tp->ti_len = htons(sizeof(struct tcphdr));
+ tcp->th_sum = in_cksum(m, sizeof(struct tcpiphdr));
+
+ ip->ip_tos = ((struct ip *)ti)->ip_tos;
+ ip->ip_p = ((struct ip *)ti)->ip_p;
+ ip->ip_len = sizeof (struct tcpiphdr);
+#if BSD < 199306
+ ip->ip_ttl = tcp_ttl;
+#else
+ ip->ip_ttl = ip_defttl;
+#endif
+
+ /*
+ * extra 0 in case of multicast
+ */
+ (void) ip_output(m, (struct mbuf *)0, 0, 0, 0);
+ return 0;
+}
+
+
+#ifndef IPFILTER_LKM
+void iplinit()
+{
+ (void) iplattach();
+ ip_init();
+}
+#endif
+
+
+void ipfr_fastroute(m0, fin, fdp)
+struct mbuf *m0;
+fr_info_t *fin;
+frdest_t *fdp;
+{
+ register struct ip *ip, *mhip;
+ register struct mbuf *m = m0;
+ register struct route *ro;
+ struct ifnet *ifp = fdp->fd_ifp;
+ int len, off, error = 0;
+ int hlen = fin->fin_hlen;
+ struct route iproute;
+ struct sockaddr_in *dst;
+
+ 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 = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst;
+#if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__)
+# ifdef RTF_CLONING
+ rtalloc_ign(ro, RTF_CLONING);
+# else
+ rtalloc_ign(ro, RTF_PRCLONING);
+# endif
+#else
+ rtalloc(ro);
+#endif
+ if (!ifp) {
+ if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) {
+ error = -2;
+ goto bad;
+ }
+ if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
+ 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;
+ }
+ 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.
+ */
+ (void) ip_natout(ip, hlen, fin);
+ if (fin->fin_out)
+ ip->ip_sum = 0;
+ /*
+ * If small enough for interface, can just send directly.
+ */
+ if (ip->ip_len <= ifp->if_mtu) {
+#ifndef sparc
+ ip->ip_id = htons(ip->ip_id);
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+#endif
+ if (!ip->ip_sum)
+ ip->ip_sum = in_cksum(m, hlen);
+#if BSD >= 199306
+ error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
+ ro->ro_rt);
+
+#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) {
+ MGET(m, M_DONTWAIT, MT_HEADER);
+ 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;
+ }
+#ifndef sparc
+ mhip->ip_off = htons((u_short)mhip->ip_off);
+#endif
+ 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
+ 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 (ro->ro_rt) {
+ RTFREE(ro->ro_rt);
+ }
+ return;
+bad:
+ m_freem(m);
+ goto done;
+}
diff --git a/contrib/ipfilter/ip_fil.h b/contrib/ipfilter/ip_fil.h
new file mode 100644
index 0000000..389a161
--- /dev/null
+++ b/contrib/ipfilter/ip_fil.h
@@ -0,0 +1,293 @@
+/*
+ * (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.
+ *
+ * @(#)ip_fil.h 1.35 6/5/96
+ * $Id: ip_fil.h,v 2.0.1.2 1997/01/10 00:28:15 darrenr Exp $
+ */
+
+#ifndef __IP_FIL_H__
+#define __IP_FIL_H__
+
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+
+#if defined(KERNEL) && !defined(_KERNEL)
+#define _KERNEL
+#endif
+#if SOLARIS
+# include <sys/ioccom.h>
+# include <sys/sysmacros.h>
+# ifdef _KERNEL
+# include <inet/common.h>
+/*
+ * because Solaris 2 defines these in two places :-/
+ */
+#undef IPOPT_EOL
+#undef IPOPT_NOP
+#undef IPOPT_LSRR
+#undef IPOPT_RR
+#undef IPOPT_SSRR
+# include <inet/ip.h>
+# endif
+#endif
+
+#if defined(__STDC__) || defined(__GNUC__)
+#define SIOCADAFR _IOW('r', 60, struct frentry)
+#define SIOCRMAFR _IOW('r', 61, struct frentry)
+#define SIOCSETFF _IOW('r', 62, u_int)
+#define SIOCGETFF _IOR('r', 63, u_int)
+#define SIOCGETFS _IOR('r', 64, struct friostat)
+#define 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 SIOCSWAPA _IOR('r', 69, u_int)
+#define SIOCINAFR _IOW('r', 70, struct frentry)
+#define SIOCINIFR _IOW('r', 71, struct frentry)
+#define SIOCFRENB _IOW('r', 72, u_int)
+#define SIOCFRSYN _IOW('r', 73, u_int)
+#define SIOCFRZST _IOWR('r', 74, struct friostat)
+#define SIOCZRLST _IOWR('r', 75, struct frentry)
+#else
+#define SIOCADAFR _IOW(r, 60, struct frentry)
+#define SIOCRMAFR _IOW(r, 61, struct frentry)
+#define SIOCSETFF _IOW(r, 62, u_int)
+#define SIOCGETFF _IOR(r, 63, u_int)
+#define SIOCGETFS _IOR(r, 64, struct friostat)
+#define 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 SIOCSWAPA _IOR(r, 69, u_int)
+#define SIOCINAFR _IOW(r, 70, struct frentry)
+#define SIOCINIFR _IOW(r, 71, struct frentry)
+#define SIOCFRENB _IOW(r, 72, u_int)
+#define SIOCFRSYN _IOW(r, 73, u_int)
+#define SIOCFRZST _IOWR(r, 74, struct friostat)
+#define SIOCZRLST _IOWR(r, 75, struct frentry)
+#endif
+#define SIOCADDFR SIOCADAFR
+#define SIOCDELFR SIOCRMAFR
+#define SIOCINSFR SIOCINAFR
+
+typedef struct fr_ip {
+ u_char fi_v:4; /* IP version */
+ u_char fi_fl:4; /* packet flags */
+ u_char fi_tos;
+ u_char fi_ttl;
+ u_char fi_p;
+ struct in_addr fi_src;
+ struct in_addr fi_dst;
+ u_long fi_optmsk; /* bitmask composed from IP options */
+ u_short fi_secmsk; /* bitmask composed from IP security options */
+ u_short fi_auth;
+} fr_ip_t;
+
+#define FI_OPTIONS 0x01
+#define FI_TCPUDP 0x02 /* TCP/UCP implied comparison involved */
+#define FI_FRAG 0x04
+#define FI_SHORT 0x08
+
+typedef struct fr_info {
+ struct fr_ip fin_fi;
+ void *fin_ifp;
+ u_short fin_data[2];
+ u_short fin_out;
+ u_char fin_tcpf;
+ u_char fin_icode;
+ u_short fin_rule;
+ u_short fin_hlen;
+ u_short fin_dlen;
+ char *fin_dp; /* start of data past IP header */
+ struct frentry *fin_fr;
+} fr_info_t;
+
+#define FI_CSIZE (sizeof(struct fr_ip) + 11)
+
+typedef struct frdest {
+ void *fd_ifp;
+ struct in_addr fd_ip;
+ char fd_ifname[IFNAMSIZ];
+} frdest_t;
+
+typedef struct frentry {
+ struct frentry *fr_next;
+ struct ifnet *fr_ifa;
+ u_long fr_hits;
+ u_long fr_bytes; /* this is only incremented when a packet */
+ /* matches this rule and it is the last match*/
+ /*
+ * Fields after this may not change whilst in the kernel.
+ */
+ struct fr_ip fr_ip;
+ struct fr_ip fr_mip; /* mask structure */
+
+ u_char fr_tcpfm; /* tcp flags mask */
+ u_char fr_tcpf; /* tcp flags */
+
+ u_short fr_icmpm; /* data for ICMP packets (mask) */
+ u_short fr_icmp;
+
+ u_char fr_scmp; /* data for port comparisons */
+ u_char fr_dcmp;
+ u_short fr_dport;
+ u_short fr_sport;
+ u_short fr_stop; /* top port for <> and >< */
+ u_short fr_dtop; /* top port for <> and >< */
+ u_long fr_flags; /* per-rule flags && options (see below) */
+ int (*fr_func)(); /* call this function */
+ char fr_icode; /* return ICMP code */
+ char fr_ifname[IFNAMSIZ];
+ struct frdest fr_tif; /* "to" interface */
+ struct frdest fr_dif; /* duplicate packet interfaces */
+} frentry_t;
+
+#define fr_proto fr_ip.fi_p
+#define fr_ttl fr_ip.fi_ttl
+#define fr_tos fr_ip.fi_tos
+#define fr_dst fr_ip.fi_dst
+#define fr_src fr_ip.fi_src
+#define fr_dmsk fr_mip.fi_dst
+#define fr_smsk fr_mip.fi_src
+
+#ifndef offsetof
+#define offsetof(t,m) (int)((&((t *)0L)->m))
+#endif
+#define FR_CMPSIZ (sizeof(struct frentry) - offsetof(frentry_t, fr_ip))
+
+/*
+ * fr_flags
+*/
+#define FR_BLOCK 0x00001
+#define FR_PASS 0x00002
+#define FR_OUTQUE 0x00004
+#define FR_INQUE 0x00008
+#define FR_LOG 0x00010 /* Log */
+#define FR_LOGB 0x00011 /* Log-fail */
+#define FR_LOGP 0x00012 /* Log-pass */
+#define FR_LOGBODY 0x00020 /* Log the body */
+#define FR_LOGFIRST 0x00040 /* Log the first byte if state held */
+#define FR_RETRST 0x00080 /* Return TCP RST packet - reset connection */
+#define FR_RETICMP 0x00100 /* Return ICMP unreachable packet */
+#define FR_NOMATCH 0x00200
+#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_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */
+
+#define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB)
+/*
+ * recognized flags for SIOCGETFF and SIOCSETFF
+ */
+#define FF_LOGPASS 0x100000
+#define FF_LOGBLOCK 0x200000
+#define FF_LOGNOMATCH 0x400000
+#define FF_LOGGING (FF_LOGPASS|FF_LOGBLOCK|FF_LOGNOMATCH)
+#define FF_BLOCKNONIP 0x800000 /* 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
+
+typedef struct filterstats {
+ u_long fr_pass; /* packets allowed */
+ u_long fr_block; /* packets denied */
+ u_long fr_nom; /* packets which don't match any rule */
+ u_long fr_ppkl; /* packets allowed and logged */
+ u_long fr_bpkl; /* packets denied and logged */
+ u_long fr_npkl; /* packets unmatched and logged */
+ u_long fr_pkl; /* packets logged */
+ u_long fr_skip; /* packets to be logged but buffer full */
+ u_long fr_ret; /* packets for which a return is sent */
+ u_long fr_acct; /* packets for which counting was performed */
+ u_long fr_bnfr; /* bad attempts to allocate fragment state */
+ u_long fr_nfr; /* new fragment state kept */
+ u_long fr_cfr; /* add new fragment state but complete pkt */
+ u_long fr_bads; /* bad attempts to allocate packet state */
+ u_long fr_ads; /* new packet state kept */
+ u_long fr_chit; /* cached hit */
+ u_long fr_pull[2]; /* good and bad pullup attempts */
+#if SOLARIS
+ 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! */
+#endif
+} 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];
+ int f_active;
+} friostat_t;
+
+typedef struct optlist {
+ u_short ol_val;
+ int ol_bit;
+} optlist_t;
+
+/*
+ * Log structure. Each packet header logged is prepended by one of these,
+ * minimize size to make most effective use of log space which should
+ * (ideally) be a muliple of the most common log entry size.
+ */
+typedef struct ipl_ci {
+ u_long sec;
+ u_long usec;
+ u_char hlen;
+ u_char plen;
+ u_short rule; /* assume never more than 64k rules, total */
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603))
+ u_long flags;
+ u_char ifname[IFNAMSIZ]; /* = 32 bytes */
+#else
+ u_long flags:24;
+ u_long unit:8;
+ u_char ifname[4]; /* = 20 bytes */
+#endif
+} ipl_ci_t;
+
+
+#ifndef ICMP_UNREACH_FILTER
+#define ICMP_UNREACH_FILTER 13
+#endif
+
+#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
+#define IPLLOGSIZE 8192
+
+extern int fr_check();
+extern int fr_copytolog();
+extern fr_info_t frcache[];
+extern char *iplh, *iplt;
+extern char iplbuf[IPLLOGSIZE];
+
+#ifdef _KERNEL
+
+extern struct frentry *ipfilter[2][2], *ipacct[2][2];
+extern struct filterstats frstats[];
+# if SOLARIS
+extern int ipfsync();
+# endif
+#endif /* _KERNEL */
+#endif /* __IP_FIL_H__ */
diff --git a/contrib/ipfilter/ip_frag.c b/contrib/ipfilter/ip_frag.c
new file mode 100644
index 0000000..6665404
--- /dev/null
+++ b/contrib/ipfilter/ip_frag.c
@@ -0,0 +1,278 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed";
+static char rcsid[] = "$Id: ip_frag.c,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp $";
+#endif
+
+#if !defined(_KERNEL) && !defined(KERNEL)
+# include <string.h>
+# include <stdlib.h>
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# 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/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include "ip_frag.h"
+#include "ip_nat.h"
+#include "ip_state.h"
+
+ipfr_t *ipfr_heads[IPFT_SIZE];
+ipfrstat_t ipfr_stats;
+u_long ipfr_inuse = 0,
+ fr_ipfrttl = 120; /* 60 seconds */
+#ifdef _KERNEL
+extern int ipfr_timer_id;
+#endif
+#if SOLARIS
+# ifdef _KERNEL
+extern kmutex_t ipf_frag;
+# else
+#define bcmp(a,b,c) memcmp(a,b,c)
+#define bcopy(a,b,c) memmove(b,a,c)
+# endif
+#endif
+
+
+ipfrstat_t *ipfr_fragstats()
+{
+ ipfr_stats.ifs_table = ipfr_heads;
+ ipfr_stats.ifs_inuse = ipfr_inuse;
+ return &ipfr_stats;
+}
+
+
+/*
+ * add a new entry to the fragment cache, registering it as having come
+ * through this box, with the result of the filter operation.
+ */
+int ipfr_newfrag(ip, fin, pass)
+ip_t *ip;
+fr_info_t *fin;
+int pass;
+{
+ ipfr_t **fp, *fr, frag;
+ u_int idx;
+
+ frag.ipfr_p = ip->ip_p;
+ idx = ip->ip_p;
+ frag.ipfr_id = ip->ip_id;
+ idx += ip->ip_id;
+ frag.ipfr_tos = ip->ip_tos;
+ frag.ipfr_src.s_addr = ip->ip_src.s_addr;
+ idx += ip->ip_src.s_addr;
+ frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
+ idx += ip->ip_dst.s_addr;
+ idx *= 127;
+ idx %= IPFT_SIZE;
+
+ /*
+ * first, make sure it isn't already there...
+ */
+ MUTEX_ENTER(&ipf_frag);
+ for (fp = &ipfr_heads[idx]; (fr = *fp); fp = &fr->ipfr_next)
+ if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src,
+ IPFR_CMPSZ)) {
+ ipfr_stats.ifs_exists++;
+ MUTEX_EXIT(&ipf_frag);
+ return -1;
+ }
+
+ if (!(fr = (ipfr_t *)KMALLOC(sizeof(*fr)))) {
+ ipfr_stats.ifs_nomem++;
+ MUTEX_EXIT(&ipf_frag);
+ return -1;
+ }
+ if ((fr->ipfr_next = ipfr_heads[idx]))
+ ipfr_heads[idx]->ipfr_prev = fr;
+ fr->ipfr_prev = NULL;
+ ipfr_heads[idx] = fr;
+ bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ);
+ fr->ipfr_ttl = fr_ipfrttl;
+ fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG);
+ fr->ipfr_off = (ip->ip_off & 0x1fff) + (fin->fin_dlen >> 3);
+ *fp = fr;
+ ipfr_stats.ifs_new++;
+ ipfr_inuse++;
+ MUTEX_EXIT(&ipf_frag);
+ return 0;
+}
+
+
+/*
+ * check the fragment cache to see if there is already a record of this packet
+ * with its filter result known.
+ */
+int ipfr_knownfrag(ip, fin)
+ip_t *ip;
+fr_info_t *fin;
+{
+ ipfr_t *f, frag;
+ u_int idx;
+ int ret;
+
+ /*
+ * For fragments, we record protocol, packet id, TOS and both IP#'s
+ * (these should all be the same for all fragments of a packet).
+ */
+ frag.ipfr_p = ip->ip_p;
+ idx = ip->ip_p;
+ frag.ipfr_id = ip->ip_id;
+ idx += ip->ip_id;
+ frag.ipfr_tos = ip->ip_tos;
+ frag.ipfr_src.s_addr = ip->ip_src.s_addr;
+ idx += ip->ip_src.s_addr;
+ frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
+ idx += ip->ip_dst.s_addr;
+ idx *= 127;
+ idx %= IPFT_SIZE;
+
+ MUTEX_ENTER(&ipf_frag);
+ for (f = ipfr_heads[idx]; f; f = f->ipfr_next)
+ if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src,
+ IPFR_CMPSZ)) {
+ u_short atoff, off;
+
+ if (f != ipfr_heads[idx]) {
+ /*
+ * move fragment info. to the top of the list
+ * to speed up searches.
+ */
+ if ((f->ipfr_prev->ipfr_next = f->ipfr_next))
+ f->ipfr_next->ipfr_prev = f->ipfr_prev;
+ f->ipfr_next = ipfr_heads[idx];
+ ipfr_heads[idx]->ipfr_prev = f;
+ f->ipfr_prev = NULL;
+ ipfr_heads[idx] = f;
+ }
+ ret = f->ipfr_pass;
+ off = ip->ip_off;
+ atoff = (off & 0x1fff) - (fin->fin_dlen >> 3);
+ /*
+ * If we've follwed the fragments, and this is the
+ * last (in order), shrink expiration time.
+ */
+ if (atoff == f->ipfr_off) {
+ if (!(off & IP_MF))
+ f->ipfr_ttl = 1;
+ else
+ f->ipfr_off = off;
+ }
+ ipfr_stats.ifs_hits++;
+ MUTEX_EXIT(&ipf_frag);
+ return ret;
+ }
+ MUTEX_EXIT(&ipf_frag);
+ return 0;
+}
+
+
+/*
+ * Free memory in use by fragment state info. kept.
+ */
+void ipfr_unload()
+{
+ ipfr_t **fp, *fr;
+ int idx;
+#if !SOLARIS && defined(_KERNEL)
+ int s;
+#endif
+
+ MUTEX_ENTER(&ipf_frag);
+ SPLNET(s);
+ for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
+ for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
+ *fp = fr->ipfr_next;
+ KFREE(fr);
+ }
+ SPLX(s);
+ MUTEX_EXIT(&ipf_frag);
+}
+
+
+#ifdef _KERNEL
+/*
+ * Slowly expire held state for fragments. Timeouts are set * in expectation
+ * of this being called twice per second.
+ */
+# if BSD < 199306
+int ipfr_slowtimer()
+# else
+void ipfr_slowtimer()
+# endif
+{
+ ipfr_t **fp, *fr;
+ int s, idx;
+
+ MUTEX_ENTER(&ipf_frag);
+ SPLNET(s);
+
+ for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
+ for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
+ --fr->ipfr_ttl;
+ if (fr->ipfr_ttl == 0) {
+ if (fr->ipfr_prev)
+ fr->ipfr_prev->ipfr_next =
+ fr->ipfr_next;
+ if (fr->ipfr_next)
+ fr->ipfr_next->ipfr_prev =
+ fr->ipfr_prev;
+ *fp = fr->ipfr_next;
+ ipfr_stats.ifs_expire++;
+ ipfr_inuse--;
+ KFREE(fr);
+ } else
+ fp = &fr->ipfr_next;
+ }
+ SPLX(s);
+# if SOLARIS
+ MUTEX_EXIT(&ipf_frag);
+ fr_timeoutstate();
+ ip_natexpire();
+ ipfr_timer_id = timeout(ipfr_slowtimer, NULL, HZ/2);
+# else
+ fr_timeoutstate();
+ ip_natexpire();
+ ip_slowtimo();
+# if BSD < 199306
+ return 0;
+# endif
+# endif
+}
+#endif /* defined(_KERNEL) */
diff --git a/contrib/ipfilter/ip_frag.h b/contrib/ipfilter/ip_frag.h
new file mode 100644
index 0000000..a356785
--- /dev/null
+++ b/contrib/ipfilter/ip_frag.h
@@ -0,0 +1,47 @@
+/*
+ * (C)opyright 1993, 1994, 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ip_frag.h 1.5 3/24/96
+ * $Id: ip_frag.h,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp $
+ */
+
+#ifndef __IP_FRAG_H_
+#define __IP_FRAG_H__
+
+#define IPFT_SIZE 257
+
+typedef struct ipfr {
+ struct ipfr *ipfr_next, *ipfr_prev;
+ struct in_addr ipfr_src;
+ struct in_addr ipfr_dst;
+ u_short ipfr_id;
+ u_char ipfr_p;
+ u_char ipfr_tos;
+ u_short ipfr_off;
+ u_short ipfr_ttl;
+ u_char ipfr_pass;
+} ipfr_t;
+
+
+typedef struct ipfrstat {
+ u_long ifs_exists; /* add & already exists */
+ u_long ifs_nomem;
+ u_long ifs_new;
+ u_long ifs_hits;
+ u_long ifs_expire;
+ u_long ifs_inuse;
+ struct ipfr **ifs_table;
+} ipfrstat_t;
+
+#define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1)
+
+extern ipfrstat_t *ipfr_fragstats();
+extern int ipfr_newfrag(), ipfr_knownfrag();
+# ifdef _KERNEL
+extern void ipfr_unload();
+# endif
+#endif /* __IP_FIL_H__ */
diff --git a/contrib/ipfilter/ip_nat.c b/contrib/ipfilter/ip_nat.c
new file mode 100644
index 0000000..afe9761
--- /dev/null
+++ b/contrib/ipfilter/ip_nat.c
@@ -0,0 +1,886 @@
+/*
+ * (C)opyright 1995-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.
+ *
+ * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
+static char rcsid[] = "$Id: ip_nat.c,v 2.0.1.10 1997/02/08 06:38:49 darrenr Exp $";
+#endif
+
+#if !defined(_KERNEL) && !defined(KERNEL)
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# 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>
+
+#ifdef RFC1825
+#include <vpn/md5.h>
+#include <vpn/ipsec.h>
+extern struct ifnet vpnif;
+#endif
+
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include "ip_nat.h"
+#include "ip_state.h"
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL;
+ipnat_t *nat_list = NULL;
+u_long nat_inuse = 0,
+ fr_defnatage = 1200;
+natstat_t nat_stats;
+#if SOLARIS
+# ifndef _KERNEL
+#define bzero(a,b) memset(a,0,b)
+#define bcmp(a,b,c) memcpy(a,b,c)
+#define bcopy(a,b,c) memmove(b,a,c)
+# else
+extern kmutex_t ipf_nat;
+# endif
+#endif
+
+static int flush_nattable(), clear_natlist();
+static void nattable_sync();
+
+void fix_outcksum(sp, n)
+u_short *sp;
+u_long n;
+{
+ register u_short sumshort;
+ register u_long sum1;
+
+#ifdef sparc
+ sum1 = (~(*sp)) & 0xffff;
+#else
+ sum1 = (~ntohs(*sp)) & 0xffff;
+#endif
+ sum1 += (n);
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ /* Again */
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ sumshort = ~(u_short)sum1;
+ *(sp) = htons(sumshort);
+}
+
+
+void fix_incksum(sp, n)
+u_short *sp;
+u_long n;
+{
+ register u_short sumshort;
+ register u_long sum1;
+
+#ifdef sparc
+ sum1 = (~(*sp)) & 0xffff;
+#else
+ sum1 = (~ntohs(*sp)) & 0xffff;
+#endif
+ sum1 += ~(n) & 0xffff;
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ /* Again */
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ sumshort = ~(u_short)sum1;
+ *(sp) = htons(sumshort);
+}
+
+
+/*
+ * How the NAT is organised and works.
+ *
+ * Inside (interface y) NAT Outside (interface x)
+ * -------------------- -+- -------------------------------------
+ * 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)
+caddr_t data;
+int cmd, mode;
+{
+ register ipnat_t *nat, *n = NULL, **np = NULL;
+ ipnat_t natd;
+ int error = 0, ret;
+
+ /*
+ * For add/delete, look to see if the NAT entry is already present
+ */
+ MUTEX_ENTER(&ipf_nat);
+ if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
+ IRCOPY(data, (char *)&natd, sizeof(natd));
+ nat = &natd;
+ for (np = &nat_list; (n = *np); np = &n->in_next)
+ if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
+ IPN_CMPSIZ))
+ break;
+ }
+
+ switch (cmd)
+ {
+ case SIOCADNAT :
+ if (!(mode & FWRITE)) {
+ error = EPERM;
+ break;
+ }
+ if (n) {
+ error = EEXIST;
+ break;
+ }
+ if (!(n = (ipnat_t *)KMALLOC(sizeof(*n)))) {
+ error = ENOMEM;
+ break;
+ }
+ IRCOPY((char *)data, (char *)n, sizeof(*n));
+ n->in_ifp = (void *)GETUNIT(n->in_ifname);
+ n->in_next = *np;
+ n->in_use = 0;
+ n->in_space = ~(0xffffffff & ntohl(n->in_outmsk));
+ if (n->in_space) /* lose 2: broadcast + network address */
+ n->in_space -= 2;
+ else
+ n->in_space = 1; /* single IP# mapping */
+ if (n->in_outmsk != 0xffffffff)
+ n->in_nip = ntohl(n->in_outip) + 1;
+ 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));
+ }
+ /* Otherwise, these fields are preset */
+ *np = n;
+ break;
+ case SIOCRMNAT :
+ if (!(mode & FWRITE)) {
+ error = EPERM;
+ break;
+ }
+ if (!n) {
+ error = ESRCH;
+ break;
+ }
+ *np = n->in_next;
+
+ KFREE(n);
+ nattable_sync();
+ break;
+ case SIOCGNATS :
+ 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_inuse = nat_inuse;
+ IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats));
+ break;
+ case SIOCGNATL :
+ {
+ natlookup_t nl;
+
+ IRCOPY((char *)data, (char *)&nl, sizeof(nl));
+
+ if (nat_lookupredir(&nl))
+ IWCOPY((char *)&nl, (char *)data, sizeof(nl));
+ else
+ error = ESRCH;
+ break;
+ }
+ case SIOCFLNAT :
+ if (!(mode & FWRITE)) {
+ error = EPERM;
+ break;
+ }
+ ret = flush_nattable();
+ IWCOPY((caddr_t)&ret, data, sizeof(ret));
+ break;
+ case SIOCCNATL :
+ if (!(mode & FWRITE)) {
+ error = EPERM;
+ break;
+ }
+ ret = clear_natlist();
+ IWCOPY((caddr_t)&ret, data, sizeof(ret));
+ break;
+ }
+ MUTEX_EXIT(&ipf_nat);
+ return error;
+}
+
+
+static void nat_delete(natd)
+struct nat *natd;
+{
+ register struct nat **natp, *nat;
+
+ for (natp = natd->nat_hstart[0]; (nat = *natp);
+ natp = &nat->nat_hnext[0])
+ if (nat == natd) {
+ *natp = nat->nat_hnext[0];
+ break;
+ }
+
+ for (natp = natd->nat_hstart[1]; (nat = *natp);
+ natp = &nat->nat_hnext[1])
+ if (nat == natd) {
+ *natp = nat->nat_hnext[1];
+ break;
+ }
+
+ if (natd->nat_ptr) {
+ natd->nat_ptr->in_space++;
+ natd->nat_ptr->in_use--;
+ }
+ KFREE(natd);
+ nat_inuse--;
+}
+
+
+/*
+ * flush_nattable - clear the NAT table of all mapping entries.
+ */
+static int flush_nattable()
+{
+ register nat_t *nat, **natp;
+ register int j = 0;
+
+ /*
+ * Everything will be deleted, so lets just make it the deletions
+ * quicker.
+ */
+ bzero((char *)nat_table[0], sizeof(nat_table[0]));
+ bzero((char *)nat_table[1], sizeof(nat_table[1]));
+
+ for (natp = &nat_instances; (nat = *natp); ) {
+ *natp = nat->nat_next;
+ nat_delete(nat);
+ j++;
+ }
+
+ return j;
+}
+
+
+/*
+ * I know this is O(N*M), but it can't be avoided.
+ */
+static void nattable_sync()
+{
+ register nat_t *nat;
+ register ipnat_t *np;
+ int i;
+
+ for (i = NAT_SIZE - 1; i >= 0; i--)
+ for (nat = nat_instances; nat; nat = nat->nat_next) {
+ for (np = nat_list; np; np = np->in_next)
+ if (nat->nat_ptr == np)
+ break;
+ /*
+ * XXX - is it better to remove this if ? works the
+ * same if it is just "nat->nat_ptr = np".
+ */
+ if (!np)
+ nat->nat_ptr = NULL;
+ }
+}
+
+
+/*
+ * clear_natlist - delete all entries in the active NAT mapping list.
+ */
+static int clear_natlist()
+{
+ register ipnat_t *n, **np;
+ int i = 0;
+
+ for (np = &nat_list; (n = *np); i++) {
+ *np = n->in_next;
+ KFREE(n);
+ }
+
+ nattable_sync();
+ return i;
+}
+
+
+/*
+ * Create a new NAT table entry.
+ */
+nat_t *nat_new(np, ip, fin, flags, direction)
+ipnat_t *np;
+ip_t *ip;
+fr_info_t *fin;
+u_short flags;
+int direction;
+{
+ register u_long sum1, sum2, sumd;
+ u_short port = 0, sport = 0, dport = 0, nport = 0;
+ struct in_addr in;
+ tcphdr_t *tcp = NULL;
+ nat_t *nat, **natp;
+ u_short nflags;
+
+ nflags = flags & np->in_flags;
+ if (flags & IPN_TCPUDP) {
+ tcp = (tcphdr_t *)fin->fin_dp;
+ sport = tcp->th_sport;
+ dport = tcp->th_dport;
+ }
+
+ /* Give me a new nat */
+ if (!(nat = (nat_t *)KMALLOC(sizeof(*nat))))
+ return NULL;
+
+ bzero((char *)nat, sizeof(*nat));
+
+ /*
+ * Search the current table for a match.
+ */
+ if (direction == NAT_OUTBOUND) {
+ /*
+ * If it's an outbound packet which doesn't match any existing
+ * record, then create a new port
+ */
+ do {
+ port = 0;
+ in.s_addr = np->in_nip;
+ if (nflags & IPN_TCPUDP) {
+ port = htons(np->in_pnext++);
+ if (np->in_pnext >= ntohs(np->in_pmax)) {
+ np->in_pnext = ntohs(np->in_pmin);
+ np->in_space--;
+ if (np->in_outmsk != 0xffffffff)
+ np->in_nip++;
+ }
+ } else if (np->in_outmsk != 0xffffffff) {
+ np->in_space--;
+ np->in_nip++;
+ }
+
+ if (!port && (flags & IPN_TCPUDP))
+ port = sport;
+ if ((np->in_nip & ntohl(np->in_outmsk)) >
+ ntohl(np->in_outip))
+ np->in_nip = ntohl(np->in_outip) + 1;
+ } while (nat_inlookup(flags, ip->ip_dst, dport, in, port));
+
+ /* Setup the NAT table */
+ nat->nat_inip = ip->ip_src;
+ nat->nat_outip.s_addr = htonl(in.s_addr);
+ nat->nat_oip = ip->ip_dst;
+
+ sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
+ (ntohl(ip->ip_src.s_addr) >> 16) + ntohs(sport);
+
+ sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(port);
+
+ if (flags & IPN_TCPUDP) {
+ nat->nat_inport = sport;
+ nat->nat_outport = port;
+ nat->nat_oport = dport;
+ }
+ } 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.
+ */
+ in.s_addr = ntohl(np->in_inip);
+ if (!(nport = np->in_pnext))
+ nport = dport;
+
+ nat->nat_inip.s_addr = htonl(in.s_addr);
+ nat->nat_outip = ip->ip_dst;
+ nat->nat_oip = ip->ip_src;
+
+ sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
+ (ntohl(ip->ip_dst.s_addr) >> 16) + ntohs(dport);
+
+ sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport);
+
+ if (flags & IPN_TCPUDP) {
+ nat->nat_inport = nport;
+ nat->nat_outport = dport;
+ nat->nat_oport = sport;
+ }
+ }
+
+ /* Do it twice */
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+
+ /* Do it twice */
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+
+ if (sum1 > sum2)
+ sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
+ sumd = sum2 - sum1;
+ sumd = (sumd & 0xffff) + (sumd >> 16);
+ nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
+
+ if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {
+ if (direction == NAT_OUTBOUND)
+ sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
+ (ntohl(ip->ip_src.s_addr) >> 16);
+ else
+ sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
+ (ntohl(ip->ip_dst.s_addr) >> 16);
+
+ sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16);
+
+ /* Do it twice */
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+
+ /* Do it twice */
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+
+ if (sum1 > sum2)
+ sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
+ sumd = sum2 - sum1;
+ sumd = (sumd & 0xffff) + (sumd >> 16);
+ nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
+ } else
+ nat->nat_ipsumd = nat->nat_sumd;
+
+ in.s_addr = htonl(in.s_addr);
+ nat->nat_next = nat_instances;
+ nat_instances = nat;
+ natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE];
+ nat->nat_hstart[0] = natp;
+ nat->nat_hnext[0] = *natp;
+ *natp = nat;
+ natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE];
+ nat->nat_hstart[1] = natp;
+ nat->nat_hnext[1] = *natp;
+ *natp = nat;
+ nat->nat_ptr = np;
+ np->in_use++;
+ if (direction == NAT_OUTBOUND) {
+ if (flags & IPN_TCPUDP)
+ tcp->th_sport = htons(port);
+ } else {
+ if (flags & IPN_TCPUDP)
+ tcp->th_dport = htons(nport);
+ }
+ nat_stats.ns_added++;
+ nat_inuse++;
+ return nat;
+}
+
+
+/*
+ * NB: these lookups don't lock access to the list, it assume 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(flags, src, sport, mapdst, mapdport)
+register int flags;
+struct in_addr src , mapdst;
+u_short sport, mapdport;
+{
+ register nat_t *nat;
+
+ flags &= IPN_TCPUDP;
+
+ nat = nat_table[1][mapdst.s_addr % NAT_SIZE];
+ for (; nat; nat = nat->nat_hnext[1])
+ if (nat->nat_oip.s_addr == src.s_addr &&
+ nat->nat_outip.s_addr == mapdst.s_addr &&
+ (!flags || (nat->nat_oport == sport &&
+ nat->nat_outport == mapdport)))
+ return nat;
+ return NULL;
+}
+
+
+/*
+ * 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(flags, src, sport, dst, dport)
+register int flags;
+struct in_addr src , dst;
+u_short sport, dport;
+{
+ register nat_t *nat;
+
+ flags &= IPN_TCPUDP;
+
+ nat = nat_table[0][src.s_addr % NAT_SIZE];
+ for (; nat; nat = nat->nat_hnext[0])
+ if (nat->nat_inip.s_addr == src.s_addr &&
+ nat->nat_oip.s_addr == dst.s_addr &&
+ (!flags || (nat->nat_inport == sport &&
+ nat->nat_oport == dport)))
+ return nat;
+ return NULL;
+}
+
+
+/*
+ * Lookup a nat entry based on the mapped source ip address/port and
+ * real destination address/port. We use this lookup when sending a packet
+ * out, we're looking for a table entry, based on the source address.
+ */
+nat_t *nat_lookupmapip(flags, mapsrc, mapsport, dst, dport)
+register int flags;
+struct in_addr mapsrc , dst;
+u_short mapsport, dport;
+{
+ register nat_t *nat;
+
+ flags &= IPN_TCPUDP;
+
+ nat = nat_table[1][mapsrc.s_addr % NAT_SIZE];
+ for (; nat; nat = nat->nat_hnext[0])
+ if (nat->nat_outip.s_addr == mapsrc.s_addr &&
+ nat->nat_oip.s_addr == dst.s_addr &&
+ (!flags || (nat->nat_outport == mapsport &&
+ nat->nat_oport == dport)))
+ return nat;
+ return NULL;
+}
+
+
+/*
+ * Lookup the NAT tables to search for a matching redirect
+ */
+nat_t *nat_lookupredir(np)
+register natlookup_t *np;
+{
+ nat_t *nat;
+
+ /*
+ * 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(IPN_TCPUDP, np->nl_inip, np->nl_inport,
+ np->nl_outip, np->nl_outport))) {
+ np->nl_inip = nat->nat_outip;
+ np->nl_inport = nat->nat_outport;
+ }
+ return nat;
+}
+
+
+/*
+ * Packets going out on the external interface go through this.
+ * Here, the source address requires alteration, if anything.
+ */
+int ip_natout(ip, hlen, fin)
+ip_t *ip;
+int hlen;
+fr_info_t *fin;
+{
+ register ipnat_t *np;
+ register u_long ipa;
+ tcphdr_t *tcp = NULL;
+ nat_t *nat;
+ u_short nflags = 0, sport = 0, dport = 0, *csump = NULL;
+ struct ifnet *ifp;
+ frentry_t *fr;
+
+ if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
+ fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
+ ifp = fr->fr_tif.fd_ifp;
+ else
+ ifp = fin->fin_ifp;
+
+ if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
+ if (ip->ip_p == IPPROTO_TCP)
+ nflags = IPN_TCP;
+ else if (ip->ip_p == IPPROTO_UDP)
+ nflags = IPN_UDP;
+ if (nflags) {
+ tcp = (tcphdr_t *)fin->fin_dp;
+ sport = tcp->th_sport;
+ dport = tcp->th_dport;
+ }
+ }
+
+ ipa = ip->ip_src.s_addr;
+
+ MUTEX_ENTER(&ipf_nat);
+ for (np = nat_list; np; np = np->in_next)
+ if ((np->in_ifp == ifp) && np->in_space &&
+ (!np->in_flags || (np->in_flags & nflags)) &&
+ ((ipa & np->in_inmsk) == np->in_inip) &&
+ ((np->in_redir == NAT_MAP) ||
+ (np->in_pnext == sport))) {
+ /*
+ * If there is no current entry in the nat table for
+ * this IP#, create one for it.
+ */
+ if (!(nat = nat_outlookup(nflags, ip->ip_src, sport,
+ ip->ip_dst, dport))) {
+ if (np->in_redir == NAT_REDIRECT)
+ continue;
+ /*
+ * if it's a redirection, then we don't want
+ * to create new outgoing port stuff.
+ * Redirections are only for incoming
+ * connections.
+ */
+ if (!(nat = nat_new(np, ip, fin, nflags,
+ NAT_OUTBOUND)))
+ break;
+ }
+ ip->ip_src = nat->nat_outip;
+
+ nat->nat_age = fr_defnatage; /* 5 mins */
+
+ /*
+ * Fix up checksums, not by recalculating them, but
+ * simply computing adjustments.
+ */
+#if SOLARIS
+ if (np->in_redir == NAT_MAP)
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
+ else
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
+#endif
+
+ if (nflags && !(ip->ip_off & 0x1fff) &&
+ !(fin->fin_fi.fi_fl & FI_SHORT)) {
+
+ if (nat->nat_outport)
+ tcp->th_sport = nat->nat_outport;
+
+ if (ip->ip_p == IPPROTO_TCP) {
+ csump = &tcp->th_sum;
+ set_tcp_age(&nat->nat_age,
+ nat->nat_state, ip, fin,1);
+ } else if (ip->ip_p == IPPROTO_UDP) {
+ udphdr_t *udp = (udphdr_t *)tcp;
+
+ if (udp->uh_sum)
+ csump = &udp->uh_sum;
+ } else if (ip->ip_p == IPPROTO_ICMP) {
+ icmphdr_t *ic = (icmphdr_t *)tcp;
+
+ csump = &ic->icmp_cksum;
+ }
+ if (csump) {
+ if (np->in_redir == NAT_MAP)
+ fix_outcksum(csump,
+ nat->nat_sumd);
+ else
+ fix_incksum(csump,
+ nat->nat_sumd);
+ }
+ }
+ nat_stats.ns_mapped[1]++;
+ MUTEX_EXIT(&ipf_nat);
+ return 1;
+ }
+ MUTEX_EXIT(&ipf_nat);
+ return 0;
+}
+
+
+/*
+ * Packets coming in from the external interface go through this.
+ * Here, the destination address requires alteration, if anything.
+ */
+int ip_natin(ip, hlen, fin)
+ip_t *ip;
+int hlen;
+fr_info_t *fin;
+{
+ register ipnat_t *np;
+ register struct in_addr in;
+ struct ifnet *ifp = fin->fin_ifp;
+ tcphdr_t *tcp = NULL;
+ u_short sport = 0, dport = 0, nflags = 0, *csump = NULL;
+ nat_t *nat;
+
+ if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
+ if (ip->ip_p == IPPROTO_TCP)
+ nflags = IPN_TCP;
+ else if (ip->ip_p == IPPROTO_UDP)
+ nflags = IPN_UDP;
+ if (nflags) {
+ tcp = (tcphdr_t *)((char *)ip + hlen);
+ dport = tcp->th_dport;
+ sport = tcp->th_sport;
+ }
+ }
+
+ in = ip->ip_dst;
+
+ MUTEX_ENTER(&ipf_nat);
+ for (np = nat_list; np; np = np->in_next)
+ if ((np->in_ifp == ifp) &&
+ (!np->in_flags || (nflags & np->in_flags)) &&
+ ((in.s_addr & np->in_outmsk) == np->in_outip) &&
+ (np->in_redir == NAT_MAP || np->in_pmin == dport)) {
+ if (!(nat = nat_inlookup(nflags, ip->ip_src, sport,
+ ip->ip_dst, dport))) {
+ if (np->in_redir == NAT_MAP)
+ continue;
+ else {
+ /*
+ * If this rule (np) is a redirection,
+ * rather than a mapping, then do a
+ * nat_new. Otherwise, if it's just a
+ * mapping, do a continue;
+ */
+ if (!(nat = nat_new(np, ip, fin,
+ nflags,
+ NAT_INBOUND)))
+ break;
+ }
+ }
+ ip->ip_dst = nat->nat_inip;
+
+ nat->nat_age = fr_defnatage;
+
+ /*
+ * Fix up checksums, not by recalculating them, but
+ * simply computing adjustments.
+ */
+#if SOLARIS
+ if (np->in_redir == NAT_MAP)
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
+ else
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
+#endif
+ if (nflags && !(ip->ip_off & 0x1fff) &&
+ !(fin->fin_fi.fi_fl & FI_SHORT)) {
+
+ if (nat->nat_inport)
+ tcp->th_dport = nat->nat_inport;
+
+ if (ip->ip_p == IPPROTO_TCP) {
+ csump = &tcp->th_sum;
+ set_tcp_age(&nat->nat_age,
+ nat->nat_state, ip, fin,0);
+ } else if (ip->ip_p == IPPROTO_UDP) {
+ udphdr_t *udp = (udphdr_t *)tcp;
+
+ if (udp->uh_sum)
+ csump = &udp->uh_sum;
+ } else if (ip->ip_p == IPPROTO_ICMP) {
+ icmphdr_t *ic = (icmphdr_t *)tcp;
+
+ csump = &ic->icmp_cksum;
+ }
+ if (csump) {
+ if (np->in_redir == NAT_MAP)
+ fix_incksum(csump,
+ nat->nat_sumd);
+ else
+ fix_outcksum(csump,
+ nat->nat_sumd);
+ }
+ }
+ nat_stats.ns_mapped[0]++;
+ MUTEX_EXIT(&ipf_nat);
+ return 1;
+ }
+ MUTEX_EXIT(&ipf_nat);
+ return 0;
+}
+
+
+/*
+ * Free all memory used by NAT structures allocated at runtime.
+ */
+void ip_natunload()
+{
+ MUTEX_ENTER(&ipf_nat);
+
+ (void) clear_natlist();
+ (void) flush_nattable();
+
+ MUTEX_EXIT(&ipf_nat);
+}
+
+
+/*
+ * Slowly expire held state for NAT entries. Timeouts are set in
+ * expectation of this being called twice per second.
+ */
+void ip_natexpire()
+{
+ register struct nat *nat, **natp;
+
+ MUTEX_ENTER(&ipf_nat);
+ for (natp = &nat_instances; (nat = *natp); natp = &nat->nat_next) {
+ if (--nat->nat_age)
+ continue;
+ *natp = nat->nat_next;
+ nat_delete(nat);
+ nat_stats.ns_expire++;
+ }
+ MUTEX_EXIT(&ipf_nat);
+}
diff --git a/contrib/ipfilter/ip_nat.h b/contrib/ipfilter/ip_nat.h
new file mode 100644
index 0000000..d64183a
--- /dev/null
+++ b/contrib/ipfilter/ip_nat.h
@@ -0,0 +1,118 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ip_nat.h 1.5 2/4/96
+ * $Id: ip_nat.h,v 2.0.1.7 1997/01/30 12:39:41 darrenr Exp $
+ */
+
+#ifndef __IP_NAT_H_
+#define __IP_NAT_H__
+
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+
+#if defined(__STDC__) || defined(__GNUC__)
+#define SIOCADNAT _IOW('r', 80, struct ipnat)
+#define SIOCRMNAT _IOW('r', 81, struct ipnat)
+#define SIOCGNATS _IOR('r', 82, struct natstat)
+#define SIOCGNATL _IOWR('r', 83, struct natlookup)
+#define SIOCGFRST _IOR('r', 84, struct ipfrstat)
+#define SIOCGIPST _IOR('r', 85, struct ips_stat)
+#define SIOCFLNAT _IOWR('r', 86, int)
+#define SIOCCNATL _IOWR('r', 87, int)
+
+#else
+#define SIOCADNAT _IOW(r, 80, struct ipnat)
+#define SIOCRMNAT _IOW(r, 81, struct ipnat)
+#define SIOCGNATS _IOR(r, 82, struct natstat)
+#define SIOCGNATL _IOWR(r, 83, struct natlookup)
+#define SIOCGFRST _IOR(r, 84, struct ipfrstat)
+#define SIOCGIPST _IOR(r, 85, struct ips_stat)
+#define SIOCFLNAT _IOWR(r, 86, int)
+#define SIOCCNATL _IOWR(r, 87, int)
+#endif
+
+#define NAT_SIZE 367
+
+typedef struct nat {
+ int nat_age;
+ u_long nat_sumd;
+ u_long nat_ipsumd;
+ struct in_addr nat_inip;
+ struct in_addr nat_outip;
+ struct in_addr nat_oip; /* other ip */
+ u_short nat_oport; /* other port */
+ u_short nat_inport;
+ u_short nat_outport;
+ u_short nat_use;
+ u_char nat_state[2];
+ struct ipnat *nat_ptr;
+ struct nat *nat_next;
+ struct nat *nat_hnext[2];
+ struct nat **nat_hstart[2];
+} nat_t;
+
+typedef struct ipnat {
+ struct ipnat *in_next;
+ void *in_ifp;
+ u_int in_space;
+ u_int in_use;
+ struct in_addr in_nextip;
+ u_short in_pnext;
+ u_short in_flags;
+ u_short in_port[2];
+ struct in_addr in_in[2];
+ struct in_addr in_out[2];
+ int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */
+ char in_ifname[IFNAMSIZ];
+} 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 NAT_INBOUND 0
+#define NAT_OUTBOUND 1
+
+#define NAT_MAP 0
+#define NAT_REDIRECT 1
+
+#define IPN_CMPSIZ (sizeof(struct in_addr) * 4 + sizeof(u_short) * 3 + \
+ sizeof(int))
+
+typedef struct natlookup {
+ struct in_addr nl_inip;
+ struct in_addr nl_outip;
+ u_short nl_inport;
+ u_short nl_outport;
+} natlookup_t;
+
+typedef struct natstat {
+ u_long ns_mapped[2];
+ u_long ns_added;
+ u_long ns_expire;
+ u_long ns_inuse;
+ nat_t **ns_table[2];
+ ipnat_t *ns_list;
+} natstat_t;
+
+#define IPN_ANY 0
+#define IPN_TCP 1
+#define IPN_UDP 2
+#define IPN_TCPUDP 3
+
+extern nat_t *nat_table[2][NAT_SIZE];
+extern int nat_ioctl();
+extern nat_t *nat_outlookup(), *nat_inlookup(), *nat_lookupredir();
+extern int ip_natout(), ip_natin();
+extern void ip_natunload(), ip_natexpire();
+#endif /* __IP_NAT_H__ */
diff --git a/contrib/ipfilter/ip_sfil.c b/contrib/ipfilter/ip_sfil.c
new file mode 100644
index 0000000..debc512
--- /dev/null
+++ b/contrib/ipfilter/ip_sfil.c
@@ -0,0 +1,731 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ *
+ * I hate legaleese, don't you ?
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "%W% %G% (C) 1993-1995 Darren Reed";
+static char rcsid[] = "$Id: ip_sfil.c,v 2.0.1.3 1997/02/04 14:49:15 darrenr Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/cpuvar.h>
+#include <sys/open.h>
+#include <sys/ioctl.h>
+#include <sys/systm.h>
+#include <sys/cred.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ksynch.h>
+#include <sys/kmem.h>
+#include <sys/mkdev.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/dditypes.h>
+#include <sys/cmn_err.h>
+#include <net/if.h>
+#include <net/af.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.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_fil.h"
+#include "ip_compat.h"
+#include "ip_state.h"
+#include "ip_frag.h"
+#include "ip_nat.h"
+#include <inet/ip_ire.h>
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+extern fr_flags, fr_active;
+
+int ipfr_timer_id = 0;
+int ipl_unreach = ICMP_UNREACH_HOST;
+int send_reset();
+
+#ifdef IPFILTER_LOG
+int ipllog();
+static void frflush();
+char iplbuf[IPLLOGSIZE];
+caddr_t iplh = iplbuf, iplt = iplbuf;
+static int iplused = 0;
+#endif /* IPFILTER_LOG */
+static int frrequest();
+kmutex_t ipl_mutex, ipf_mutex, ipfs_mutex;
+kmutex_t ipf_frag, ipf_state, ipf_nat;
+kcondvar_t iplwait;
+
+extern void ipfr_slowtimer();
+
+
+int ipldetach()
+{
+ int i = FR_INQUE|FR_OUTQUE;
+
+ untimeout(ipfr_timer_id);
+ frflush((caddr_t)&i);
+ ipfr_unload();
+ fr_stateunload();
+ ip_natunload();
+ cv_destroy(&iplwait);
+ mutex_destroy(&ipl_mutex);
+ mutex_destroy(&ipf_mutex);
+ mutex_destroy(&ipfs_mutex);
+ mutex_destroy(&ipf_frag);
+ mutex_destroy(&ipf_state);
+ mutex_destroy(&ipf_nat);
+ return 0;
+}
+
+
+int iplattach()
+{
+ bzero((char *)nat_table, sizeof(nat_t *) * NAT_SIZE * 2);
+ mutex_init(&ipl_mutex, "ipf log mutex", MUTEX_DRIVER, NULL);
+ mutex_init(&ipf_mutex, "ipf filter mutex", MUTEX_DRIVER, NULL);
+ mutex_init(&ipfs_mutex, "ipf solaris mutex", MUTEX_DRIVER, NULL);
+ mutex_init(&ipf_frag, "ipf fragment mutex", MUTEX_DRIVER, NULL);
+ mutex_init(&ipf_state, "ipf IP state mutex", MUTEX_DRIVER, NULL);
+ mutex_init(&ipf_nat, "ipf IP NAT mutex", MUTEX_DRIVER, NULL);
+ cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL);
+ ipfr_timer_id = timeout(ipfr_slowtimer, NULL, HZ/2);
+ return 0;
+}
+
+
+static void frzerostats(data)
+caddr_t data;
+{
+ struct friostat fio;
+
+ bcopy((char *)frstats, (char *)fio.f_st,
+ sizeof(struct filterstats) * 2);
+ fio.f_fin[0] = ipfilter[0][0];
+ fio.f_fin[1] = ipfilter[0][1];
+ fio.f_fout[0] = ipfilter[1][0];
+ fio.f_fout[1] = ipfilter[1][1];
+ fio.f_acctin[0] = ipacct[0][0];
+ fio.f_acctin[1] = ipacct[0][1];
+ fio.f_acctout[0] = ipacct[1][0];
+ fio.f_acctout[1] = ipacct[1][1];
+ fio.f_active = fr_active;
+ IWCOPY((caddr_t)&fio, data, sizeof(fio));
+ bzero((char *)frstats, sizeof(*frstats) * 2);
+}
+
+
+#ifdef IPFILTER_LOG
+static void frflush(data)
+caddr_t data;
+{
+ struct frentry *f, **fp;
+ int flags, flushed = 0, set = fr_active;
+
+ IRCOPY(data, (caddr_t)&flags, sizeof(flags));
+ bzero((char *)frcache, sizeof(frcache[0]) * 2);
+
+ if (flags & FR_INACTIVE)
+ set = 1 - set;
+ if (flags & FR_OUTQUE) {
+ for (fp = &ipfilter[1][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ for (fp = &ipacct[1][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ }
+ if (flags & FR_INQUE) {
+ for (fp = &ipfilter[0][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ for (fp = &ipacct[0][set]; (f = *fp); ) {
+ *fp = f->fr_next;
+ KFREE(f);
+ flushed++;
+ }
+ }
+
+ IWCOPY((caddr_t)&flushed, data, sizeof(flushed));
+}
+#endif /* IPFILTER_LOG */
+
+
+/*
+ * Filter ioctl interface.
+ */
+int iplioctl(dev, cmd, data, mode, cp, rp)
+dev_t dev;
+int cmd;
+caddr_t data;
+int mode;
+cred_t *cp;
+int *rp;
+{
+ int error = 0;
+
+ switch (cmd) {
+ case SIOCFRENB :
+ {
+ u_int enable;
+
+ if (!(mode & FWRITE))
+ return EPERM;
+ IRCOPY(data, (caddr_t)&enable, sizeof(enable));
+ break;
+ }
+ case SIOCSETFF :
+ if (!(mode & FWRITE))
+ return EPERM;
+ mutex_enter(&ipf_mutex);
+ IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags));
+ mutex_exit(&ipf_mutex);
+ break;
+ case SIOCGETFF :
+ IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags));
+ break;
+ case SIOCINAFR :
+ case SIOCRMAFR :
+ case SIOCADAFR :
+ case SIOCZRLST :
+ if (!(mode & FWRITE))
+ return EPERM;
+ mutex_enter(&ipf_mutex);
+ error = frrequest(cmd, data, fr_active);
+ mutex_exit(&ipf_mutex);
+ break;
+ case SIOCINIFR :
+ case SIOCRMIFR :
+ case SIOCADIFR :
+ if (!(mode & FWRITE))
+ return EPERM;
+ mutex_enter(&ipf_mutex);
+ error = frrequest(cmd, data, 1 - fr_active);
+ mutex_exit(&ipf_mutex);
+ break;
+ case SIOCSWAPA :
+ if (!(mode & FWRITE))
+ return EPERM;
+ mutex_enter(&ipf_mutex);
+ bzero((char *)frcache, sizeof(frcache[0]) * 2);
+ IWCOPY((caddr_t)&fr_active, (caddr_t)data, sizeof(fr_active));
+ fr_active = 1 - fr_active;
+ mutex_exit(&ipf_mutex);
+ break;
+ case SIOCGETFS :
+ {
+ struct friostat fio;
+
+ mutex_enter(&ipf_mutex);
+ bcopy((char *)frstats, (char *)fio.f_st,
+ sizeof(struct filterstats) * 2);
+ fio.f_fin[0] = ipfilter[0][0];
+ fio.f_fin[1] = ipfilter[0][1];
+ fio.f_fout[0] = ipfilter[1][0];
+ fio.f_fout[1] = ipfilter[1][1];
+ fio.f_acctin[0] = ipacct[0][0];
+ fio.f_acctin[1] = ipacct[0][1];
+ fio.f_acctout[0] = ipacct[1][0];
+ fio.f_acctout[1] = ipacct[1][1];
+ fio.f_active = fr_active;
+ mutex_exit(&ipf_mutex);
+ IWCOPY((caddr_t)&fio, data, sizeof(fio));
+ break;
+ }
+ case SIOCFRZST :
+ if (!(mode & FWRITE))
+ return EPERM;
+ frzerostats(data);
+ break;
+#ifdef IPFILTER_LOG
+ case SIOCIPFFL :
+ if (!(mode & FWRITE))
+ return EPERM;
+ mutex_enter(&ipf_mutex);
+ frflush(data);
+ mutex_exit(&ipf_mutex);
+ break;
+ case SIOCIPFFB :
+ if (!(mode & FWRITE))
+ return EPERM;
+ mutex_enter(&ipl_mutex);
+ IWCOPY((caddr_t)&iplused, data, sizeof(iplused));
+ iplh = iplt = iplbuf;
+ iplused = 0;
+ mutex_exit(&ipl_mutex);
+ break;
+#endif /* IPFILTER_LOG */
+ case SIOCFRSYN :
+ if (!(mode & FWRITE))
+ return EPERM;
+ error = ipfsync();
+ break;
+ case SIOCADNAT :
+ case SIOCRMNAT :
+ case SIOCGNATS :
+ case SIOCGNATL :
+ case SIOCFLNAT :
+ case SIOCCNATL :
+ error = nat_ioctl(data, cmd, mode);
+ break;
+ case SIOCGFRST :
+ IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t));
+ break;
+ case SIOCGIPST :
+ IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
+ break;
+ default :
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+
+ill_t *get_unit(name)
+char *name;
+{
+ ill_t *il;
+ int len = strlen(name) + 1; /* includes \0 */
+
+ for (il = ill_g_head; il; il = il->ill_next)
+ if ((len == il->ill_name_length) &&
+ !strncmp(il->ill_name, name, len))
+ return il;
+ return NULL;
+}
+
+
+static int frrequest(req, data, set)
+int req, set;
+caddr_t data;
+{
+ register frentry_t *fp, *f, **fprev;
+ register frentry_t **ftail;
+ frentry_t fr;
+ frdest_t *fdp;
+ int error = 0, in;
+ ill_t *ill;
+ ipif_t *ipif;
+ ire_t *ire;
+
+ fp = &fr;
+ IRCOPY(data, (caddr_t)fp, sizeof(*fp));
+
+ bzero((char *)frcache, sizeof(frcache[0]) * 2);
+
+ in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
+ if (fp->fr_flags & FR_ACCOUNT)
+ ftail = fprev = &ipacct[in][set];
+ else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE))
+ ftail = fprev = &ipfilter[in][set];
+ else
+ return ESRCH;
+
+ if (*fp->fr_ifname) {
+ fp->fr_ifa = (struct ifnet *)get_unit((char *)fp->fr_ifname);
+ if (!fp->fr_ifa)
+ fp->fr_ifa = (struct ifnet *)-1;
+ }
+
+ fdp = &fp->fr_dif;
+ fp->fr_flags &= ~FR_DUP;
+ if (*fdp->fd_ifname) {
+ ill = get_unit(fdp->fd_ifname);
+ if (!ill)
+ ire = (ire_t *)-1;
+ else if ((ipif = ill->ill_ipif)) {
+ ire = ire_lookup_myaddr(ipif->ipif_local_addr);
+ if (!ire)
+ ire = (ire_t *)-1;
+ else
+ fp->fr_flags |= FR_DUP;
+ }
+ fdp->fd_ifp = (struct ifnet *)ire;
+ }
+
+ fdp = &fp->fr_tif;
+ if (*fdp->fd_ifname) {
+ ill = get_unit(fdp->fd_ifname);
+ if (!ill)
+ ire = (ire_t *)-1;
+ else if ((ipif = ill->ill_ipif)) {
+ ire = ire_lookup_myaddr(ipif->ipif_local_addr);
+ if (!ire)
+ ire = (ire_t *)-1;
+ }
+ fdp->fd_ifp = (struct ifnet *)ire;
+ }
+
+ /*
+ * Look for a matching filter rule, but don't include the next or
+ * interface pointer in the comparison (fr_next, fr_ifa).
+ */
+ for (; (f = *ftail); ftail = &f->fr_next)
+ if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip,
+ FR_CMPSIZ) == 0)
+ break;
+
+ /*
+ * If zero'ing statistics, copy current to caller and zero.
+ */
+ if (req == SIOCZRLST) {
+ if (!f)
+ return ESRCH;
+ IWCOPY((caddr_t)f, data, sizeof(*f));
+ f->fr_hits = 0;
+ f->fr_bytes = 0;
+ return 0;
+ }
+
+ if (!f) {
+ ftail = fprev;
+ if (req != SIOCINAFR && req != SIOCINIFR)
+ while ((f = *ftail))
+ ftail = &f->fr_next;
+ else if (fp->fr_hits)
+ while (--fp->fr_hits && (f = *ftail))
+ ftail = &f->fr_next;
+ f = NULL;
+ }
+
+ if (req == SIOCDELFR || req == SIOCRMIFR) {
+ if (!f)
+ error = ESRCH;
+ else {
+ *ftail = f->fr_next;
+ KFREE(f);
+ }
+ } else {
+ if (f)
+ error = EEXIST;
+ else {
+ if ((f = (struct frentry *)KMALLOC(sizeof(*f)))) {
+ bcopy((char *)fp, (char *)f, sizeof(*f));
+ f->fr_hits = 0;
+ f->fr_next = *ftail;
+ *ftail = f;
+ } else
+ error = ENOMEM;
+ }
+ }
+ return (error);
+}
+
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+int iplopen(devp, flags, otype, cred)
+dev_t *devp;
+int flags, otype;
+cred_t *cred;
+{
+ u_int min = getminor(*devp);
+
+ if (!(otype & OTYP_CHR))
+ return ENXIO;
+ if (min)
+ min = ENXIO;
+ return min;
+}
+
+
+int iplclose(dev, flags, otype, cred)
+dev_t dev;
+int flags, otype;
+cred_t *cred;
+{
+ u_int min = getminor(dev);
+
+ if (min)
+ min = ENXIO;
+ return min;
+}
+
+#ifdef IPFILTER_LOG
+/*
+ * 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.
+ */
+int iplread(dev, uio, cp)
+dev_t dev;
+register struct uio *uio;
+cred_t *cp;
+{
+ register int ret;
+ register size_t sz, sx;
+ char *h, *t;
+ int error, used, usedo, copied;
+
+ if (!uio->uio_resid)
+ return 0;
+ if ((uio->uio_resid < 0) || (uio->uio_resid > IPLLOGSIZE))
+ return EINVAL;
+
+ /*
+ * Lock the log so we can snapshot the variables. Wait for a signal
+ * if the log is empty.
+ */
+ mutex_enter(&ipl_mutex);
+ while (!iplused) {
+ error = cv_wait_sig(&iplwait, &ipl_mutex);
+ if (!error) {
+ mutex_exit(&ipl_mutex);
+ return EINTR;
+ }
+ }
+ h = iplh;
+ t = iplt;
+ used = iplused;
+ mutex_exit(&ipl_mutex);
+ usedo = used;
+
+ /*
+ * Given up the mutex, the log can grow more, but we can't hold the
+ * mutex across the uiomove's.
+ */
+ sx = sz = MIN(uio->uio_resid, used);
+ if (h <= t)
+ sz = MIN(sz, IPLLOGSIZE + iplbuf - t);
+
+ if (!(ret = uiomove(t, sz, UIO_READ, uio))) {
+ t += sz;
+ sx -= sz;
+ used -= sz;
+ if ((h < t) && (t >= iplbuf + IPLLOGSIZE))
+ t = iplbuf;
+
+ if (sx && !(ret = uiomove(t, sx, UIO_READ, uio)))
+ used -= sx;
+ }
+
+ /*
+ * copied all the data, now adjust variables to match this.
+ */
+ mutex_enter(&ipl_mutex);
+ copied = usedo - used;
+ iplused -= copied;
+
+ if (!iplused) /* minimise wrapping around the end */
+ iplh = iplt = iplbuf;
+ else {
+ iplt += copied;
+ if (iplt >= iplbuf + IPLLOGSIZE)
+ iplt -= IPLLOGSIZE;
+ if (iplt == iplbuf + IPLLOGSIZE)
+ iplt = iplbuf;
+ }
+ mutex_exit(&ipl_mutex);
+ return ret;
+}
+
+
+int ipllog(flags, ip, fin, m)
+u_int flags;
+ip_t *ip;
+fr_info_t *fin;
+mblk_t *m;
+{
+ struct ipl_ci iplci;
+ register int len, mlen, hlen;
+ register u_char *s = (u_char *)ip;
+ ill_t *il = fin->fin_ifp;
+
+ hlen = fin->fin_hlen;
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen);
+ else if (ip->ip_p == IPPROTO_ICMP) {
+ struct icmp *icmp = (struct icmp *)(s + hlen);
+
+ switch (icmp->icmp_type) {
+ case ICMP_UNREACH :
+ case ICMP_SOURCEQUENCH :
+ case ICMP_REDIRECT :
+ case ICMP_TIMXCEED :
+ case ICMP_PARAMPROB :
+ hlen += MIN(sizeof(struct icmp) + 8, fin->fin_dlen);
+ break;
+ default :
+ hlen += MIN(sizeof(struct icmp), fin->fin_dlen);
+ break;
+ }
+ }
+
+ mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0;
+ len = hlen + sizeof(iplci) + mlen;
+ mutex_enter(&ipl_mutex);
+ if ((iplused + len) > IPLLOGSIZE) {
+ mutex_exit(&ipl_mutex);
+ return 0;
+ }
+ iplused += len;
+
+ uniqtime((struct timeval *)&iplci);
+ iplci.flags = flags;
+ iplci.hlen = (u_char)hlen;
+ iplci.plen = (u_char)mlen;
+ iplci.rule = fin->fin_rule;
+ iplci.unit = (u_char)il->ill_ppa;
+ bcopy(il->ill_name, (char *)iplci.ifname, MIN(il->ill_name_length, 4));
+
+ /*
+ * Gauranteed to succeed from above
+ */
+ (void) fr_copytolog(&iplci, sizeof(iplci));
+ len -= sizeof(iplci);
+
+ if (len && m) {
+ s = m->b_rptr;
+ do {
+ if ((hlen = MIN(m->b_wptr - s, len))) {
+ if (fr_copytolog(s, hlen))
+ break;
+ len -= hlen;
+ }
+ if ((m = m->b_cont))
+ s = m->b_rptr;
+ } while (m && len);
+ }
+
+ cv_signal(&iplwait);
+ mutex_exit(&ipl_mutex);
+ return 1;
+}
+#endif /* IPFILTER_LOG */
+
+
+u_short ipf_cksum(addr, len)
+register u_short *addr;
+register int len;
+{
+ register u_long sum = 0;
+
+ for (sum = 0; len > 1; len -= 2)
+ sum += *addr++;
+
+ /* mop up an odd byte, if necessary */
+ if (len == 1)
+ sum += *(u_char *)addr;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ return (u_short)(~sum);
+}
+
+/*
+ * 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(ti, qif, q)
+struct tcpiphdr *ti;
+qif_t *qif;
+queue_t *q;
+{
+ struct ip *ip;
+ struct tcphdr *tcp;
+ mblk_t *m;
+ int tlen = 0;
+
+ if (ti->ti_flags & TH_RST)
+ return -1;
+ if (ti->ti_flags & TH_SYN)
+ tlen = 1;
+ if ((m = (mblk_t *)allocb(sizeof(struct tcpiphdr), BPRI_HI)) == NULL)
+ return -1;
+
+ MTYPE(m) = M_DATA;
+ m->b_wptr += sizeof(struct tcpiphdr);
+ bzero((char *)m->b_rptr, sizeof(struct tcpiphdr));
+ ip = (ip_t *)m->b_rptr;
+ tcp = (struct tcphdr *)(m->b_rptr + sizeof(*ip));
+
+ ip->ip_src.s_addr = ti->ti_dst.s_addr;
+ ip->ip_dst.s_addr = ti->ti_src.s_addr;
+ tcp->th_dport = ti->ti_sport;
+ tcp->th_sport = ti->ti_dport;
+ tcp->th_ack = htonl(ntohl(ti->ti_seq) + tlen);
+ tcp->th_off = sizeof(struct tcphdr) >> 2;
+ tcp->th_flags = TH_RST|TH_ACK;
+ /*
+ * This is to get around a bug in the Solaris 2.4/2.5 TCP checksum
+ * computation that is done by their put routine.
+ */
+ tcp->th_sum = htons(0x14);
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_v = IPVERSION;
+ ip->ip_p = IPPROTO_TCP;
+ ip->ip_len = htons(sizeof(struct tcpiphdr));
+ ip->ip_tos = ((struct ip *)ti)->ip_tos;
+ ip->ip_off = 0;
+ ip->ip_ttl = 60;
+ ip->ip_sum = 0;
+ ip_wput(qif->qf_ill->ill_wq, m);
+ return 0;
+}
+
+
+int icmp_error(q, ip, type, code, qif, src)
+queue_t *q;
+ip_t *ip;
+int type, code;
+qif_t *qif;
+struct in_addr src;
+{
+ mblk_t *mb;
+ struct icmp *icmp;
+ ip_t *nip;
+ int sz = sizeof(*nip) + sizeof(*icmp) + 8;
+
+ if ((mb = (mblk_t *)allocb(sz, BPRI_HI)) == NULL)
+ return -1;
+ MTYPE(mb) = M_DATA;
+ mb->b_wptr += sz;
+ bzero((char *)mb->b_rptr, sz);
+ nip = (ip_t *)mb->b_rptr;
+ icmp = (struct icmp *)(nip + 1);
+
+ nip->ip_v = IPVERSION;
+ nip->ip_hl = (sizeof(*nip) >> 2);
+ nip->ip_p = IPPROTO_ICMP;
+ nip->ip_id = ip->ip_id;
+ nip->ip_sum = 0;
+ nip->ip_ttl = 60;
+ nip->ip_tos = ip->ip_tos;
+ nip->ip_len = htons(sz);
+ nip->ip_src.s_addr = ip->ip_dst.s_addr;
+ nip->ip_dst.s_addr = ip->ip_src.s_addr;
+
+ icmp->icmp_type = type;
+ icmp->icmp_code = code;
+ icmp->icmp_cksum = 0;
+ bcopy((char *)ip, (char *)&icmp->icmp_ip, sizeof(*ip));
+ bcopy((char *)ip + (ip->ip_hl << 2),
+ (char *)&icmp->icmp_ip + sizeof(*ip), 8); /* 64 bits */
+ icmp->icmp_cksum = ipf_cksum(icmp, sizeof(*icmp) + 8);
+ ip_wput(qif->qf_ill->ill_wq, mb);
+ return 0;
+}
diff --git a/contrib/ipfilter/ip_state.c b/contrib/ipfilter/ip_state.c
new file mode 100644
index 0000000..62a49aa
--- /dev/null
+++ b/contrib/ipfilter/ip_state.c
@@ -0,0 +1,536 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed";
+static char rcsid[] = "$Id: ip_state.c,v 2.0.1.2 1997/01/09 15:22:45 darrenr Exp $";
+#endif
+
+#if !defined(_KERNEL) && !defined(KERNEL)
+# include <stdlib.h>
+# include <string.h>
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# 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/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include "ip_state.h"
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+void set_tcp_age();
+
+#define TCP_CLOSE (TH_FIN|TH_RST)
+
+ipstate_t *ips_table[IPSTATE_SIZE];
+int ips_num = 0;
+ips_stat_t ips_stats;
+#if SOLARIS
+extern kmutex_t ipf_state;
+# if !defined(_KERNEL)
+#define bcopy(a,b,c) memmove(b,a,c)
+# endif
+#endif
+
+
+#define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */
+
+u_long fr_tcpidletimeout = FIVE_DAYS,
+ fr_tcpclosewait = 60,
+ fr_tcplastack = 20,
+ fr_tcptimeout = 120,
+ fr_tcpclosed = 1,
+ fr_udptimeout = 120,
+ fr_icmptimeout = 120;
+
+
+ips_stat_t *fr_statetstats()
+{
+ ips_stats.iss_active = ips_num;
+ ips_stats.iss_table = ips_table;
+ return &ips_stats;
+}
+
+
+#define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\
+ (((s1) == (d2)) && ((d1) == (s2))))
+#define IPPAIR(s1,d1,s2,d2) PAIRS((s1).s_addr, (d1).s_addr, \
+ (s2).s_addr, (d2).s_addr)
+
+/*
+ * Create a new ipstate structure and hang it off the hash table.
+ */
+int fr_addstate(ip, fin, pass)
+ip_t *ip;
+fr_info_t *fin;
+u_int pass;
+{
+ ipstate_t ips;
+ register ipstate_t *is = &ips;
+ register u_int hv;
+
+ if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
+ return -1;
+ if (ips_num == IPSTATE_MAX) {
+ ips_stats.iss_max++;
+ return -1;
+ }
+ ips.is_age = 1;
+ ips.is_state[0] = 0;
+ ips.is_state[1] = 0;
+ /*
+ * Copy and calculate...
+ */
+ hv = (is->is_p = ip->ip_p);
+ hv += (is->is_src.s_addr = ip->ip_src.s_addr);
+ hv += (is->is_dst.s_addr = ip->ip_dst.s_addr);
+
+ switch (ip->ip_p)
+ {
+ case IPPROTO_ICMP :
+ {
+ struct icmp *ic = (struct icmp *)fin->fin_dp;
+
+ switch (ic->icmp_type)
+ {
+ case ICMP_ECHO :
+ is->is_icmp.ics_type = 0;
+ hv += (is->is_icmp.ics_id = ic->icmp_id);
+ hv += (is->is_icmp.ics_seq = ic->icmp_seq);
+ break;
+ case ICMP_TSTAMP :
+ case ICMP_IREQ :
+ case ICMP_MASKREQ :
+ is->is_icmp.ics_type = ic->icmp_type + 1;
+ break;
+ default :
+ return -1;
+ }
+ ips_stats.iss_icmp++;
+ is->is_age = fr_icmptimeout;
+ break;
+ }
+ case IPPROTO_TCP :
+ {
+ register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
+
+ /*
+ * The endian of the ports doesn't matter, but the ack and
+ * sequence numbers do as we do mathematics on them later.
+ */
+ hv += (is->is_dport = tcp->th_dport);
+ hv += (is->is_sport = tcp->th_sport);
+ is->is_seq = ntohl(tcp->th_seq);
+ is->is_ack = ntohl(tcp->th_ack);
+ is->is_swin = ntohs(tcp->th_win);
+ is->is_dwin = is->is_swin; /* start them the same */
+ ips_stats.iss_tcp++;
+ /*
+ * If we're creating state for a starting connectoin, start the
+ * timer on it as we'll never see an error if it fails to
+ * connect.
+ */
+ if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN)
+ is->is_ack = 0; /* Trumpet WinSock 'ism */
+ set_tcp_age(&is->is_age, is->is_state, ip, fin,
+ tcp->th_sport == is->is_sport);
+ break;
+ }
+ case IPPROTO_UDP :
+ {
+ register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
+
+ hv += (is->is_dport = tcp->th_dport);
+ hv += (is->is_sport = tcp->th_sport);
+ ips_stats.iss_udp++;
+ is->is_age = fr_udptimeout;
+ break;
+ }
+ default :
+ return -1;
+ }
+
+ if (!(is = (ipstate_t *)KMALLOC(sizeof(*is)))) {
+ ips_stats.iss_nomem++;
+ return -1;
+ }
+ bcopy((char *)&ips, (char *)is, sizeof(*is));
+ hv %= IPSTATE_SIZE;
+ MUTEX_ENTER(&ipf_state);
+ is->is_next = ips_table[hv];
+ ips_table[hv] = is;
+ is->is_pass = pass;
+ if (pass & FR_LOGFIRST)
+ is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
+ ips_num++;
+ MUTEX_EXIT(&ipf_state);
+ return 0;
+}
+
+
+/*
+ * 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, sport
+#ifndef _KERNEL
+,isp)
+ipstate_t **isp;
+#else
+)
+#endif
+register ipstate_t *is;
+fr_info_t *fin;
+ip_t *ip;
+tcphdr_t *tcp;
+u_short sport;
+{
+ register int seqskew, ackskew;
+ register u_short swin, dwin;
+ register tcp_seq seq, ack;
+ int source;
+
+ /*
+ * Find difference between last checked packet and this packet.
+ */
+ seq = ntohl(tcp->th_seq);
+ ack = ntohl(tcp->th_ack);
+ if (sport == is->is_sport) {
+ seqskew = seq - is->is_seq;
+ ackskew = ack - is->is_ack;
+ } else {
+ seqskew = ack - is->is_seq;
+ if (!is->is_ack)
+ /*
+ * Must be a SYN-ACK in reply to a SYN.
+ */
+ is->is_ack = seq;
+ ackskew = seq - is->is_ack;
+ }
+
+ /*
+ * Make skew values absolute
+ */
+ if (seqskew < 0)
+ seqskew = -seqskew;
+ if (ackskew < 0)
+ ackskew = -ackskew;
+
+ /*
+ * If the difference in sequence and ack numbers is within the
+ * window size of the connection, store these values and match
+ * the packet.
+ */
+ if ((source = (sport == is->is_sport))) {
+ swin = is->is_swin;
+ dwin = is->is_dwin;
+ } else {
+ dwin = is->is_swin;
+ swin = is->is_dwin;
+ }
+
+ if ((seqskew <= swin) && (ackskew <= dwin)) {
+ if (source) {
+ is->is_seq = seq;
+ is->is_ack = ack;
+ is->is_swin = ntohs(tcp->th_win);
+ } else {
+ is->is_seq = ack;
+ is->is_ack = seq;
+ is->is_dwin = ntohs(tcp->th_win);
+ }
+ ips_stats.iss_hits++;
+ /*
+ * Nearing end of connection, start timeout.
+ */
+ set_tcp_age(&is->is_age, is->is_state, ip, fin,
+ tcp->th_sport == is->is_sport);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Check if a packet has a registered state.
+ */
+int fr_checkstate(ip, fin)
+ip_t *ip;
+fr_info_t *fin;
+{
+ register struct in_addr dst, src;
+ register ipstate_t *is, **isp;
+ register u_char pr;
+ struct icmp *ic;
+ tcphdr_t *tcp;
+ u_int hv, hlen;
+
+ if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
+ return 0;
+
+ hlen = fin->fin_hlen;
+ tcp = (tcphdr_t *)((char *)ip + hlen);
+ ic = (struct icmp *)tcp;
+ hv = (pr = ip->ip_p);
+ hv += (src.s_addr = ip->ip_src.s_addr);
+ hv += (dst.s_addr = ip->ip_dst.s_addr);
+
+ /*
+ * Search the hash table for matching packet header info.
+ */
+ switch (ip->ip_p)
+ {
+ case IPPROTO_ICMP :
+ hv += ic->icmp_id;
+ hv += ic->icmp_seq;
+ hv %= IPSTATE_SIZE;
+ MUTEX_ENTER(&ipf_state);
+ for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
+ if ((is->is_p == pr) &&
+ (ic->icmp_id == is->is_icmp.ics_id) &&
+ (ic->icmp_seq == is->is_icmp.ics_seq) &&
+ IPPAIR(src, dst, is->is_src, is->is_dst)) {
+ /*
+ * If we have type 0 stored, allow any icmp
+ * replies through.
+ */
+ if (is->is_icmp.ics_type &&
+ is->is_icmp.ics_type != ic->icmp_type)
+ continue;
+ is->is_age = fr_icmptimeout;
+ ips_stats.iss_hits++;
+ MUTEX_EXIT(&ipf_state);
+ return is->is_pass;
+ }
+ MUTEX_EXIT(&ipf_state);
+ break;
+ case IPPROTO_TCP :
+ {
+ register u_short dport = tcp->th_dport, sport = tcp->th_sport;
+
+ hv += dport;
+ hv += sport;
+ hv %= IPSTATE_SIZE;
+ MUTEX_ENTER(&ipf_state);
+ for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) {
+ if ((is->is_p == pr) &&
+ PAIRS(sport, dport, is->is_sport, is->is_dport) &&
+ IPPAIR(src, dst, is->is_src, is->is_dst))
+ if (fr_tcpstate(is, fin, ip, tcp, sport)) {
+#ifdef _KERNEL
+ MUTEX_EXIT(&ipf_state);
+ return is->is_pass;
+#else
+ int pass = is->is_pass;
+
+ if (tcp->th_flags & TCP_CLOSE) {
+ *isp = is->is_next;
+ isp = &ips_table[hv];
+ KFREE(is);
+ }
+ return pass;
+#endif
+ }
+ }
+ MUTEX_EXIT(&ipf_state);
+ break;
+ }
+ case IPPROTO_UDP :
+ {
+ register u_short dport = tcp->th_dport, sport = tcp->th_sport;
+
+ hv += dport;
+ hv += sport;
+ hv %= IPSTATE_SIZE;
+ /*
+ * Nothing else to match on but ports. and IP#'s
+ */
+ MUTEX_ENTER(&ipf_state);
+ for (is = ips_table[hv]; is; is = is->is_next)
+ if ((is->is_p == pr) &&
+ PAIRS(sport, dport, is->is_sport, is->is_dport) &&
+ IPPAIR(src, dst, is->is_src, is->is_dst)) {
+ ips_stats.iss_hits++;
+ is->is_age = fr_udptimeout;
+ MUTEX_EXIT(&ipf_state);
+ return is->is_pass;
+ }
+ MUTEX_EXIT(&ipf_state);
+ break;
+ }
+ default :
+ break;
+ }
+ ips_stats.iss_miss++;
+ return 0;
+}
+
+
+/*
+ * Free memory in use by all state info. kept.
+ */
+void fr_stateunload()
+{
+ register int i;
+ register ipstate_t *is, **isp;
+
+ MUTEX_ENTER(&ipf_state);
+ for (i = 0; i < IPSTATE_SIZE; i++)
+ for (isp = &ips_table[i]; (is = *isp); ) {
+ *isp = is->is_next;
+ KFREE(is);
+ }
+ MUTEX_EXIT(&ipf_state);
+}
+
+
+/*
+ * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set
+ * in expectation of this being called twice per second.
+ */
+void fr_timeoutstate()
+{
+ register int i;
+ register ipstate_t *is, **isp;
+
+ MUTEX_ENTER(&ipf_state);
+ for (i = 0; i < IPSTATE_SIZE; i++)
+ for (isp = &ips_table[i]; (is = *isp); )
+ if (is->is_age && !--is->is_age) {
+ *isp = is->is_next;
+ if (is->is_p == IPPROTO_TCP)
+ ips_stats.iss_fin++;
+ else
+ ips_stats.iss_expire++;
+ KFREE(is);
+ ips_num--;
+ } else
+ isp = &is->is_next;
+ MUTEX_EXIT(&ipf_state);
+}
+
+
+/*
+ * Original idea freom Pradeep Krishnan for use primarily with NAT code.
+ * (pkrishna@netcom.com)
+ */
+void set_tcp_age(age, state, ip, fin, dir)
+int *age;
+u_char *state;
+ip_t *ip;
+fr_info_t *fin;
+int dir;
+{
+ tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
+ u_char flags = tcp->th_flags;
+ int dlen, ostate;
+
+ ostate = state[1 - dir];
+
+ dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2);
+
+ 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;
+ }
+ return;
+ }
+
+ *age = fr_tcptimeout; /* 1 min */
+
+ switch(state[dir])
+ {
+ case TCPS_FIN_WAIT_2:
+ case TCPS_CLOSED:
+ if ((flags & TH_OPENING) == TH_OPENING)
+ state[dir] = TCPS_SYN_RECEIVED;
+ else if (flags & TH_SYN)
+ state[dir] = TCPS_SYN_SENT;
+ break;
+ case TCPS_SYN_RECEIVED:
+ if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
+ state[dir] = TCPS_ESTABLISHED;
+ *age = fr_tcpidletimeout;
+ }
+ break;
+ case TCPS_SYN_SENT:
+ if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
+ state[dir] = TCPS_ESTABLISHED;
+ *age = fr_tcpidletimeout;
+ }
+ break;
+ case TCPS_ESTABLISHED:
+ if (flags & TH_FIN) {
+ state[dir] = TCPS_CLOSE_WAIT;
+ if (!(flags & TH_PUSH) && !dlen &&
+ ostate > TCPS_ESTABLISHED)
+ *age = fr_tcplastack;
+ else
+ *age = fr_tcpclosewait;
+ } else
+ *age = fr_tcpidletimeout;
+ break;
+ case TCPS_CLOSE_WAIT:
+ if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen &&
+ ostate > TCPS_ESTABLISHED) {
+ *age = fr_tcplastack;
+ state[dir] = TCPS_LAST_ACK;
+ } else
+ *age = fr_tcpclosewait;
+ break;
+ case TCPS_LAST_ACK:
+ if (flags & TH_ACK) {
+ state[dir] = TCPS_FIN_WAIT_2;
+ if (!(flags & TH_PUSH) && !dlen &&
+ ostate > TCPS_ESTABLISHED)
+ *age = fr_tcplastack;
+ else {
+ *age = fr_tcpclosewait;
+ state[dir] = TCPS_CLOSE_WAIT;
+ }
+ }
+ break;
+ }
+}
diff --git a/contrib/ipfilter/ip_state.h b/contrib/ipfilter/ip_state.h
new file mode 100644
index 0000000..ee30b98
--- /dev/null
+++ b/contrib/ipfilter/ip_state.h
@@ -0,0 +1,86 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed
+ * $Id: ip_state.h,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp $
+ */
+#ifndef __IP_STATE_H__
+#define __IP_STATE_H__
+
+#define IPSTATE_SIZE 257
+#define IPSTATE_MAX 2048 /* Maximum number of states held */
+
+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 tcpstate {
+ u_short ts_sport;
+ u_short ts_dport;
+ u_long ts_seq;
+ u_long ts_ack;
+ u_short ts_swin;
+ u_short ts_dwin;
+ u_char ts_state[2];
+} tcpstate_t;
+
+typedef struct ipstate {
+ struct ipstate *is_next;
+ int is_age;
+ u_int is_pass;
+ struct in_addr is_src;
+ struct in_addr is_dst;
+ u_char is_p;
+ u_char is_flags;
+ union {
+ icmpstate_t is_ics;
+ tcpstate_t is_ts;
+ udpstate_t is_us;
+ } is_ps;
+} ipstate_t;
+
+#define is_icmp is_ps.is_ics
+#define is_tcp is_ps.is_ts
+#define is_udp is_ps.is_us
+#define is_seq is_tcp.ts_seq
+#define is_ack is_tcp.ts_ack
+#define is_dwin is_tcp.ts_dwin
+#define is_swin is_tcp.ts_swin
+#define is_sport is_tcp.ts_sport
+#define is_dport is_tcp.ts_dport
+#define is_state is_tcp.ts_state
+
+#define TH_OPENING (TH_SYN|TH_ACK)
+
+typedef struct ips_stat {
+ u_long iss_hits;
+ u_long iss_miss;
+ u_long iss_max;
+ u_long iss_tcp;
+ u_long iss_udp;
+ u_long iss_icmp;
+ u_long iss_nomem;
+ u_long iss_expire;
+ u_long iss_fin;
+ u_long iss_active;
+ ipstate_t **iss_table;
+} ips_stat_t;
+
+extern ips_stat_t *fr_statetstats();
+extern int fr_addstate(), fr_checkstate();
+extern void fr_timeoutstate(), set_tcp_age();
+# ifdef _KERNEL
+extern void fr_stateunload();
+# endif
+#endif /* __IP_STATE_H__ */
diff --git a/contrib/ipfilter/ipf.c b/contrib/ipfilter/ipf.c
new file mode 100644
index 0000000..da6baa2
--- /dev/null
+++ b/contrib/ipfilter/ipf.c
@@ -0,0 +1,434 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#if !defined(__SVR4) && defined(__GNUC__)
+extern char *index();
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <net/if.h>
+#include <netinet/ip.h>
+#include "ip_fil.h"
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-1995 Darren Reed";
+static char rcsid[] = "$Id: ipf.c,v 2.0.1.2 1997/02/04 14:37:46 darrenr Exp $";
+#endif
+
+#if SOLARIS
+void frsync(), blockunknown();
+#endif
+void zerostats();
+
+extern char *optarg;
+
+int opts = 0;
+
+static int fd = -1;
+
+static void procfile(), flushfilter(), set_state();
+static void packetlogon(), swapactive(), showstats();
+static char *getline();
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ char c;
+
+ while ((c = getopt(argc, argv, "AdDEf:F:Il:noprsUvyzZ")) != -1) {
+ switch (c)
+ {
+ case 'E' :
+ set_state(1);
+ break;
+ case 'D' :
+ set_state(0);
+ break;
+ case 'A' :
+ opts &= ~OPT_INACTIVE;
+ 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' :
+ opts |= OPT_OUTQUE;
+ break;
+ case 'p' :
+ opts |= OPT_PRINTFR;
+ break;
+ case 'r' :
+ opts |= OPT_REMOVE;
+ break;
+ case 's' :
+ swapactive();
+ break;
+#if SOLARIS
+ case 'U' :
+ blockunknown();
+ break;
+#endif
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+#if SOLARIS
+ case 'y' :
+ frsync();
+ break;
+#endif
+ case 'z' :
+ opts |= OPT_ZERORULEST;
+ break;
+ case 'Z' :
+ zerostats();
+ break;
+ }
+ }
+
+ if (fd != -1)
+ (void) close(fd);
+
+ exit(0);
+ /* NOTREACHED */
+}
+
+
+static int opendevice()
+{
+ if (opts & OPT_DONOTHING)
+ return -2;
+
+ if (!(opts & OPT_DONOTHING) && fd == -1)
+ if ((fd = open(IPL_NAME, O_RDWR)) == -1)
+ if ((fd = open(IPL_NAME, O_RDONLY)) == -1)
+ perror("open device");
+ return fd;
+}
+
+
+static void set_state(enable)
+u_int enable;
+{
+ if (opendevice() != -2)
+ if (ioctl(fd, SIOCFRENB, &enable) == -1)
+ perror("SIOCFRENB");
+ return;
+}
+
+static void procfile(name, file)
+char *name, *file;
+{
+ FILE *fp;
+ char line[513], *s;
+ struct frentry *fr;
+ u_int add = SIOCADAFR, del = SIOCRMAFR;
+
+ (void) opendevice();
+
+ if (opts & OPT_INACTIVE) {
+ add = SIOCADIFR;
+ del = SIOCRMIFR;
+ }
+ if (opts & OPT_DEBUG)
+ printf("add %x del %x\n", add, del);
+
+ initparse();
+
+ if (!strcmp(file, "-"))
+ fp = stdin;
+ else if (!(fp = fopen(file, "r"))) {
+ fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file,
+ STRERROR(errno));
+ exit(1);
+ }
+
+ while (getline(line, sizeof(line)-1, fp)) {
+ /*
+ * treat both CR and LF as EOL
+ */
+ if ((s = index(line, '\n')))
+ *s = '\0';
+ if ((s = index(line, '\r')))
+ *s = '\0';
+ /*
+ * # is comment marker, everything after is a ignored
+ */
+ if ((s = index(line, '#')))
+ *s = '\0';
+
+ if (!*line)
+ continue;
+
+ if (opts & OPT_VERBOSE)
+ (void)fprintf(stderr, "[%s]\n",line);
+
+ fr = parse(line);
+ (void)fflush(stdout);
+
+ if (fr) {
+ if (opts & OPT_ZERORULEST)
+ add = SIOCZRLST;
+ else if (opts & OPT_INACTIVE)
+ add = fr->fr_hits ? SIOCINIFR : SIOCADIFR;
+ else
+ add = fr->fr_hits ? SIOCINAFR : SIOCADAFR;
+ if (fr->fr_hits)
+ fr->fr_hits--;
+ if (fr && (opts & OPT_VERBOSE))
+ printfr(fr);
+ if (fr && (opts & OPT_OUTQUE))
+ fr->fr_flags |= FR_OUTQUE;
+
+ if (opts & OPT_DEBUG)
+ binprint(fr);
+
+ if ((opts & OPT_ZERORULEST) &&
+ !(opts & OPT_DONOTHING)) {
+ if (ioctl(fd, add, fr) == -1)
+ perror("ioctl(SIOCZRLST)");
+ else {
+ printf("hits %ld bytes %ld ",
+ fr->fr_hits, fr->fr_bytes);
+ printfr(fr);
+ }
+ } else if ((opts & OPT_REMOVE) &&
+ !(opts & OPT_DONOTHING)) {
+ if (ioctl(fd, del, fr) == -1)
+ perror("ioctl(SIOCDELFR)");
+ } else if (!(opts & OPT_DONOTHING)) {
+ if (ioctl(fd, add, fr) == -1)
+ perror("ioctl(SIOCADDFR)");
+ }
+ }
+ }
+ (void)fclose(fp);
+}
+
+/*
+ * Similar to fgets(3) but can handle '\\'
+ */
+static char *getline(str, size, file)
+register char *str;
+size_t size;
+FILE *file;
+{
+ register char *p;
+
+ do {
+ for (p = str;; p+= strlen(p) - 1) {
+ if (!fgets(p, size, file))
+ return(NULL);
+ p[strlen(p) -1] = '\0';
+ if (p[strlen(p) - 1] != '\\')
+ break;
+ }
+ } while (*str == '\0' || *str == '\n');
+ return(str);
+}
+
+
+static void packetlogon(opt)
+char *opt;
+{
+ int err, flag = 0;
+
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
+ if ((err = ioctl(fd, SIOCGETFF, &flag)))
+ perror("ioctl(SIOCGETFF)");
+
+ printf("log flag is currently %#x\n", flag);
+ }
+
+ flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
+
+ if (index(opt, 'p')) {
+ flag |= FF_LOGPASS;
+ if (opts & OPT_VERBOSE)
+ printf("set log flag: pass\n");
+ }
+ if (index(opt, 'm') && (*opt == 'n' || *opt == 'N')) {
+ flag |= FF_LOGNOMATCH;
+ if (opts & OPT_VERBOSE)
+ printf("set log flag: nomatch\n");
+ }
+ if (index(opt, 'b') || index(opt, 'd')) {
+ flag |= FF_LOGBLOCK;
+ if (opts & OPT_VERBOSE)
+ printf("set log flag: block\n");
+ }
+
+ if (opendevice() != -2 && (err = ioctl(fd, SIOCSETFF, &flag)))
+ perror("ioctl(SIOCSETFF)");
+
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
+ if ((err = ioctl(fd, SIOCGETFF, &flag)))
+ perror("ioctl(SIOCGETFF)");
+
+ printf("log flag is now %#x\n", flag);
+ }
+}
+
+
+static void flushfilter(arg)
+char *arg;
+{
+ int fl = 0, rem;
+
+ if (!arg || !*arg)
+ return;
+ 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;
+ fl |= (opts & FR_INACTIVE);
+ rem = fl;
+
+ if (opendevice() != -2 && ioctl(fd, SIOCIPFFL, &fl) == -1)
+ perror("ioctl(SIOCIPFFL)");
+ 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() != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
+ perror("ioctl(SIOCSWAPA)");
+ else
+ printf("Set %d now inactive\n", in);
+}
+
+
+#if defined(sun) && (defined(__SVR4) || defined(__svr4__))
+void frsync()
+{
+ if (opendevice() != -2 && ioctl(fd, SIOCFRSYN, 0) == -1)
+ perror("SIOCFRSYN");
+ else
+ printf("filter sync'd\n");
+}
+#endif
+
+
+void zerostats()
+{
+ friostat_t fio;
+
+ if (opendevice() != -2) {
+ if (ioctl(fd, SIOCFRZST, &fio) == -1) {
+ perror("ioctl(SIOCFRZST)");
+ exit(-1);
+ }
+ showstats(&fio);
+ }
+
+}
+
+
+/*
+ * read the kernel stats for packets blocked and passed
+ */
+static void showstats(fp)
+friostat_t *fp;
+{
+#if SOLARIS
+ printf("dropped packets:\tin %lu\tout %lu\n",
+ fp->f_st[0].fr_drop, fp->f_st[1].fr_drop);
+ printf("non-ip packets:\t\tin %lu\tout %lu\n",
+ fp->f_st[0].fr_notip, fp->f_st[1].fr_notip);
+ printf(" bad packets:\t\tin %lu\tout %lu\n",
+ fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
+#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\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);
+}
+
+
+#if SOLARIS
+void blockunknown()
+{
+ int flag;
+
+ if (opendevice() == -1)
+ return;
+
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
+ if (ioctl(fd, SIOCGETFF, &flag))
+ perror("ioctl(SIOCGETFF)");
+
+ printf("log flag is currently %#x\n", flag);
+ }
+
+ flag ^= FF_BLOCKNONIP;
+
+ if (opendevice() != -2 && ioctl(fd, SIOCSETFF, &flag))
+ perror("ioctl(SIOCSETFF)");
+
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
+ if (ioctl(fd, SIOCGETFF, &flag))
+ perror("ioctl(SIOCGETFF)");
+
+ printf("log flag is now %#x\n", flag);
+ }
+}
+#endif
diff --git a/contrib/ipfilter/ipf.h b/contrib/ipfilter/ipf.h
new file mode 100644
index 0000000..3ac76fc
--- /dev/null
+++ b/contrib/ipfilter/ipf.h
@@ -0,0 +1,67 @@
+/*
+ * (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.
+ *
+ * @(#)ipf.h 1.12 6/5/96
+ * $Id: ipf.h,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp $
+ */
+
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+#define OPT_REMOVE 0x00001
+#define OPT_DEBUG 0x00002
+#define OPT_OUTQUE FR_OUTQUE /* 0x0004 */
+#define OPT_INQUE FR_INQUE /* 0x0008 */
+#define OPT_LOG FR_LOG /* 0x0010 */
+#define OPT_SHOWLIST 0x00020
+#define OPT_VERBOSE 0x00040
+#define OPT_DONOTHING 0x00080
+#define OPT_HITS 0x00100
+#define OPT_BRIEF 0x00200
+#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 0x04000
+#define OPT_PRINTFR 0x08000
+#define OPT_ZERORULEST 0x10000
+
+extern struct frentry *parse();
+
+extern void printfr(), binprint(), initparse();
+
+#if defined(__SVR4) || defined(__svr4__)
+#define index strchr
+#define bzero(a,b) memset(a, 0, b)
+#define bcopy(a,b,c) memmove(b,a,c)
+#endif
+
+struct ipopt_names {
+ int on_value;
+ int on_bit;
+ int on_siz;
+ char *on_name;
+};
+
+
+extern u_long hostnum(), optname();
+extern void printpacket();
+#if SOLARIS
+extern int inet_aton();
+#endif
+
+#ifdef sun
+#define STRERROR(x) sys_errlist[x]
+extern char *sys_errlist[];
+#else
+#define STRERROR(x) strerror(x)
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) > (b) ? (b) : (a))
+#endif
+
diff --git a/contrib/ipfilter/ipft_ef.c b/contrib/ipfilter/ipft_ef.c
new file mode 100644
index 0000000..2c4cc0f
--- /dev/null
+++ b/contrib/ipfilter/ipft_ef.c
@@ -0,0 +1,148 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+
+/*
+ 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 <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netdb.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipft_ef.c 1.6 2/4/96 (C)1995 Darren Reed";
+static char rcsid[] = "$Id: ipft_ef.c,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp $";
+#endif
+
+static int etherf_open(), etherf_close(), etherf_readip();
+
+struct ipread etherf = { etherf_open, etherf_close, etherf_readip };
+
+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;
+ struct ip *ip = (struct ip *)&pkt;
+ struct protoent *p = NULL;
+ char src[16], dst[16], sprt[16], dprt[16];
+ char lbuf[128], len[8], prot[8], time[8], *s;
+ int slen, extra = 0, i, n;
+
+ 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 ((n = sscanf(lbuf, "%s %s %s %s %s %s", len, prot, src, dst,
+ sprt, dprt)) != 6)
+ if ((n = sscanf(lbuf, "%s %s %s %s %s %s %s", time,
+ len, prot, src, dst, sprt, dprt)) != 7)
+ return -1;
+
+ ip->ip_p = atoi(prot);
+ if (ip->ip_p == 0) {
+ if (!(p = getprotobyname(prot)))
+ return -1;
+ ip->ip_p = p->p_proto;
+ }
+
+ switch (ip->ip_p) {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ s = strtok(NULL, " :");
+ ip->ip_len += atoi(s);
+ if (p->p_proto == IPPROTO_TCP)
+ extra = sizeof(struct tcphdr);
+ else if (p->p_proto == 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->ip_hl = sizeof(struct ip);
+
+ slen = ip->ip_hl + extra;
+ i = MIN(cnt, slen);
+ bcopy((char *)&pkt, buf, i);
+ return i;
+}
diff --git a/contrib/ipfilter/ipft_hx.c b/contrib/ipfilter/ipft_hx.c
new file mode 100644
index 0000000..26dbc83
--- /dev/null
+++ b/contrib/ipfilter/ipft_hx.c
@@ -0,0 +1,140 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed";
+static char rcsid[] = "$Id: ipft_hx.c,v 2.0.1.2 1997/02/04 13:57:56 darrenr Exp $";
+#endif
+
+extern int opts;
+extern u_short portnum();
+extern u_long buildopts();
+
+static int hex_open(), hex_close(), hex_readip();
+static char *readhex();
+
+struct ipread iphex = { hex_open, hex_close, hex_readip };
+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;
+ struct ip *ip;
+ char line[513];
+
+ ip = (struct ip *)buf;
+ while (fgets(line, sizeof(line)-1, tfp)) {
+ if ((s = index(line, '\n'))) {
+ if (s == line)
+ return (char *)ip - buf;
+ *s = '\0';
+ }
+ if ((s = index(line, '#')))
+ *s = '\0';
+ if (!*line)
+ continue;
+ if (!(opts & OPT_BRIEF)) {
+ printf("input: %s\n", line);
+ fflush(stdout);
+ }
+ ip = (struct ip *)readhex(line, (char *)ip);
+ }
+ 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/ipft_pc.c b/contrib/ipfilter/ipft_pc.c
new file mode 100644
index 0000000..3d3d887
--- /dev/null
+++ b/contrib/ipfilter/ipft_pc.c
@@ -0,0 +1,224 @@
+/*
+ * (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.
+ */
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include "ipf.h"
+#include "ipt.h"
+#include "pcap.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char rcsid[] = "$Id: ipft_pc.c,v 2.0.1.1 1997/01/09 15:14:44 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.
+ */
+#define DLT_MAX 10
+
+static struct llc llcs[DLT_MAX+1] = {
+ { 0, 0, 0 }, /* DLT_NULL */
+ { 14, 12, 2 }, /* DLT_E10MB */
+ { 0, 0, 0 }, /* 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 */
+};
+
+static int pcap_open(), pcap_close(), pcap_readip();
+
+static int pfd = -1, s_type = -1, swapped = 0;
+
+struct ipread pcap = { pcap_open, pcap_close, pcap_readip };
+
+#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;
+
+ 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 || ph.pc_type > DLT_MAX) {
+ (void) close(fd);
+ return -2;
+ }
+
+ pfd = fd;
+ s_type = ph.pc_type;
+ 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;
+
+ 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;
+
+ l = &llcs[s_type];
+ 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/ipft_sn.c b/contrib/ipfilter/ipft_sn.c
new file mode 100644
index 0000000..3185b56
--- /dev/null
+++ b/contrib/ipfilter/ipft_sn.c
@@ -0,0 +1,206 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+
+/*
+ * Written to comply with the recent RFC 1761 from Sun.
+ */
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include "ipf.h"
+#include "ipt.h"
+#include "snoop.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char rcsid[] = "$Id: ipft_sn.c,v 2.0.1.1 1997/01/09 15:14:44 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(), snoop_close(), snoop_readip();
+
+static int sfd = -1, s_type = -1;
+
+struct ipread snoop = { snoop_open, snoop_close, snoop_readip };
+
+
+static int snoop_open(fname)
+char *fname;
+{
+ struct snoophdr sh;
+ int fd;
+
+ 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;
+
+ if (sh.s_v != SNOOP_VERSION ||
+ sh.s_type < 0 || sh.s_type > SDL_MAX) {
+ (void) close(fd);
+ return -2;
+ }
+
+ sfd = fd;
+ s_type = sh.s_type;
+ printf("opened snoop file %s:\n", fname);
+ printf("\tid: %8.8s version: %d type: %d\n", sh.s_id, sh.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, p;
+
+ if (read(sfd, (char *)rec, sizeof(*rec)) != sizeof(*rec))
+ return -2;
+
+ if (rec->sp_ilen > rec->sp_plen || rec->sp_plen < sizeof(*rec))
+ return -2;
+
+ p = rec->sp_plen - sizeof(*rec);
+ n = MIN(p, rec->sp_ilen);
+ if (!n || n < 0)
+ return -3;
+
+ return p;
+}
+
+
+#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/ipft_td.c b/contrib/ipfilter/ipft_td.c
new file mode 100644
index 0000000..ecd2bad
--- /dev/null
+++ b/contrib/ipfilter/ipft_td.c
@@ -0,0 +1,184 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+
+/*
+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 <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.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_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netdb.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipft_td.c 1.8 2/4/96 (C)1995 Darren Reed";
+static char rcsid[] = "$Id: ipft_td.c,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $";
+#endif
+
+static int tcpd_open(), tcpd_close(), tcpd_readip();
+
+struct ipread tcpd = { tcpd_open, tcpd_close, tcpd_readip };
+
+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;
+ struct ip *ip = (struct ip *)&pkt;
+ struct protoent *p;
+ char src[32], dst[32], misc[256], time[32], link1[32], link2[32];
+ char lbuf[160], *s;
+ int n, dots, 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, "%s > %s: %s", src, dst, misc)) != 3)
+ if ((n = sscanf(lbuf, "%s %s > %s: %s",
+ time, src, dst, misc)) != 4)
+ if ((n = sscanf(lbuf, "%s %s: %s > %s: %s",
+ link1, link2, src, dst, misc)) != 5) {
+ n = sscanf(lbuf, "%s %s %s: %s > %s: %s",
+ time, link1, link2, src, dst, misc);
+ if (n != 6)
+ return -1;
+ }
+
+ if ((dots = 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 = ip->ip_hl = sizeof(struct ip);
+
+ s = strtok(misc, " :");
+ if ((p = getprotobyname(s))) {
+ ip->ip_p = p->p_proto;
+
+ switch (p->p_proto) {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ s = strtok(NULL, " :");
+ ip->ip_len += atoi(s);
+ if (p->p_proto == IPPROTO_TCP)
+ extra = sizeof(struct tcphdr);
+ else if (p->p_proto == 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->ip_hl + extra + ip->ip_len;
+ return slen;
+}
diff --git a/contrib/ipfilter/ipft_tx.c b/contrib/ipfilter/ipft_tx.c
new file mode 100644
index 0000000..0522f96
--- /dev/null
+++ b/contrib/ipfilter/ipft_tx.c
@@ -0,0 +1,338 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ip_compat.h"
+#include "ipf.h"
+#include "ipt.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed";
+static char rcsid[] = "$Id: ipft_tx.c,v 2.0.1.2 1997/01/19 04:52:25 darrenr Exp $";
+#endif
+
+extern int opts;
+extern u_long buildopts();
+
+static char *tx_proto = "";
+
+static int text_open(), text_close(), text_readip(), parseline();
+
+static char tcp_flagset[] = "FSRPAU";
+static u_char tcp_flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH,
+ TH_ACK, TH_URG };
+
+struct ipread iptext = { text_open, text_close, text_readip };
+static FILE *tfp = NULL;
+static int tfd = -1;
+
+static u_long tx_hostnum();
+static u_short tx_portnum();
+
+
+/*
+ * returns an ip address as a long var as a result of either a DNS lookup or
+ * straight inet_addr() call
+ */
+static u_long tx_hostnum(host, resolved)
+char *host;
+int *resolved;
+{
+ struct hostent *hp;
+ struct netent *np;
+
+ *resolved = 0;
+ if (!strcasecmp("any",host))
+ return 0L;
+ if (isdigit(*host))
+ return inet_addr(host);
+
+ if (!(hp = gethostbyname(host))) {
+ if (!(np = getnetbyname(host))) {
+ *resolved = -1;
+ fprintf(stderr, "can't resolve hostname: %s\n", host);
+ return 0;
+ }
+ return np->n_net;
+ }
+ return *(u_long *)hp->h_addr;
+}
+
+
+/*
+ * 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", (char *)NULL,
+ (char *)NULL, "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;
+ struct ip *ip;
+ char line[513];
+
+ ip = (struct ip *)buf;
+ *ifn = NULL;
+ while (fgets(line, sizeof(line)-1, tfp)) {
+ if ((s = index(line, '\n')))
+ *s = '\0';
+ if ((s = index(line, '\r')))
+ *s = '\0';
+ if ((s = index(line, '#')))
+ *s = '\0';
+ if (!*line)
+ continue;
+ if (!(opts & OPT_BRIEF))
+ printf("input: %s\n", line);
+ *ifn = NULL;
+ *dir = 0;
+ if (!parseline(line, buf, ifn, dir))
+#if 0
+ return sizeof(struct tcpiphdr);
+#else
+ return sizeof(struct ip);
+#endif
+ }
+ return -1;
+}
+
+static int parseline(line, ip, ifn, out)
+char *line;
+struct ip *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;
+
+ 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->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_v = IPVERSION;
+ for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; )
+ cps[++i] = strtok(NULL, " \b\t\r\n");
+ if (i < 2)
+ return 1;
+
+ cpp = cps;
+
+ 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 (!strcasecmp(*cpp, "on")) {
+ cpp++;
+ if (!*cpp)
+ return 1;
+ *ifn = *cpp++;
+ }
+
+ c = **cpp;
+ ip->ip_len = sizeof(struct ip);
+ 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 += sizeof(struct icmp);
+ tx_proto = "icmp";
+ }
+ 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 = index(*cpp, ',');
+ if (!last) {
+ fprintf(stderr, "tcp/udp with no source port\n");
+ return 1;
+ }
+ *last++ = '\0';
+ tcp->th_sport = htons(tx_portnum(last));
+ }
+ 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 = index(*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;
+
+ for (s = *cpp; *s; s++)
+ if ((t = index(tcp_flagset, *s)))
+ tcp->th_flags |= tcp_flags[t - tcp_flagset];
+ if (tcp->th_flags)
+ cpp++;
+ assert(tcp->th_flags != 0);
+ } 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 = index(*cpp, ',')))
+ ic->icmp_code = atoi(t+1);
+ cpp++;
+ break;
+ }
+ }
+
+ if (*cpp && !strcasecmp(*cpp, "opt")) {
+ u_long olen;
+
+ cpp++;
+ olen = buildopts(*cpp, ipopts);
+ if (olen) {
+ bcopy(ipopts, (char *)(ip + 1), olen);
+ ip->ip_hl += olen >> 2;
+ }
+ }
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ bcopy((char *)tcp, ((char *)ip) + (ip->ip_hl << 2),
+ sizeof(*tcp));
+ else if (ip->ip_p == IPPROTO_ICMP)
+ bcopy((char *)ic, ((char *)ip) + (ip->ip_hl << 2),
+ sizeof(*ic));
+ return 0;
+}
diff --git a/contrib/ipfilter/ipl.h b/contrib/ipfilter/ipl.h
new file mode 100644
index 0000000..9a2e43d
--- /dev/null
+++ b/contrib/ipfilter/ipl.h
@@ -0,0 +1,16 @@
+/*
+ * (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.
+ *
+ * @(#)ipl.h 1.21 6/5/96
+ */
+
+#ifndef __IPL_H_
+#define __IPL_H__
+
+#define IPL_VERSION "IP Filter v3.1.7 - 8/2/97"
+
+#endif
diff --git a/contrib/ipfilter/ipl_ldev.c b/contrib/ipfilter/ipl_ldev.c
new file mode 100644
index 0000000..a289325
--- /dev/null
+++ b/contrib/ipfilter/ipl_ldev.c
@@ -0,0 +1,83 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+int iplopen(struct inode * inode, struct file * filp)
+{
+ u_int min = MINOR(inode->i_rdev);
+
+ if (flags & FWRITE)
+ return ENXIO;
+ if (min)
+ return ENXIO;
+ iplbusy++;
+ return 0;
+}
+
+
+int iplclose(struct inode * inode, struct file * filp)
+{
+ u_int min = MINOR(inode->i_rdev);
+
+ if (min)
+ return ENXIO;
+ iplbusy--;
+ return 0;
+}
+
+
+/*
+ * iplread/ipllog
+ * all three 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.
+ */
+int iplread(struct inode *inode, struct file *file, char *buf, int count)
+{
+ register int ret, s;
+ register size_t sz, sx;
+ int error;
+
+ if (!uio->uio_resid)
+ return 0;
+ while (!iplused) {
+ error = SLEEP(iplbuf, "ipl sleep");
+ if (error)
+ return error;
+ }
+
+ SPLNET(s);
+
+ ret = sx = sz = MIN(count, iplused);
+ if (iplh < iplt)
+ sz = MIN(sz, LOGSIZE - (iplt - iplbuf));
+ sx -= sz;
+
+ memcpy_tofs(buf, iplt, sz);
+ buf += sz;
+ iplt += sz;
+ iplused -= sz;
+ if ((iplh < iplt) && (iplt == iplbuf + LOGSIZE))
+ iplt = iplbuf;
+
+ if (sx) {
+ memcpy_tofs(buf, iplt, sx);
+ ret += sx;
+ iplt += sx;
+ iplused -= sx;
+ if ((iplh < iplt) && (iplt == iplbuf + LOGSIZE))
+ iplt = iplbuf;
+ }
+ if (!iplused) /* minimise wrapping around the end */
+ iplh = iplt = iplbuf;
+
+ SPLX(s);
+ return ret;
+}
diff --git a/contrib/ipfilter/ipmon.c b/contrib/ipfilter/ipmon.c
new file mode 100644
index 0000000..2ea34ef
--- /dev/null
+++ b/contrib/ipfilter/ipmon.c
@@ -0,0 +1,582 @@
+/*
+ * (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.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <sys/dir.h>
+#include <sys/mbuf.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/user.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char rcsid[] = "$Id: ipmon.c,v 2.0.1.2 1997/02/04 14:49:19 darrenr Exp $";
+#endif
+
+#include "ip_fil.h"
+
+
+struct flags {
+ int value;
+ char flag;
+};
+
+struct flags tcpfl[] = {
+ { TH_ACK, 'A' },
+ { TH_RST, 'R' },
+ { TH_SYN, 'S' },
+ { TH_FIN, 'F' },
+ { TH_URG, 'U' },
+ { TH_PUSH,'P' },
+ { 0, '\0' }
+};
+
+
+static char line[2048];
+static void printpacket(), dumphex();
+static int opts = 0;
+
+#define OPT_SYSLOG 0x01
+#define OPT_RESOLVE 0x02
+#define OPT_HEXBODY 0x04
+#define OPT_VERBOSE 0x08
+#define OPT_HEXHDR 0x10
+
+#ifndef LOGFAC
+#define LOGFAC LOG_LOCAL0
+#endif
+
+void printiplci(icp)
+struct ipl_ci *icp;
+{
+ printf("sec %ld usec %ld hlen %d plen %d\n", icp->sec, icp->usec,
+ icp->hlen, icp->plen);
+}
+
+
+void resynclog(fd, iplcp, log)
+int fd;
+struct ipl_ci *iplcp;
+FILE *log;
+{
+ time_t now;
+ char *s = NULL;
+ int len, nr = 0;
+
+ do {
+ if (s) {
+ s = (char *)&iplcp->sec;
+ if (opts & OPT_SYSLOG) {
+ syslog(LOG_INFO, "Sync bytes:");
+ syslog(LOG_INFO, " %02x %02x %02x %02x",
+ *s, *(s+1), *(s+2), *(s+3));
+ syslog(LOG_INFO, " %02x %02x %02x %02x\n",
+ *(s+4), *(s+5), *(s+6), *(s+7));
+ } else {
+ fprintf(log, "Sync bytes:");
+ fprintf(log, " %02x %02x %02x %02x",
+ *s, *(s+1), *(s+2), *(s+3));
+ fprintf(log, " %02x %02x %02x %02x\n",
+ *(s+4), *(s+5), *(s+6), *(s+7));
+ }
+ }
+ do {
+ s = (char *)&iplcp->sec;
+ len = sizeof(iplcp->sec);
+ while (len) {
+ switch ((nr = read(fd, s, len)))
+ {
+ case -1:
+ case 0:
+ return;
+ default :
+ s += nr;
+ len -= nr;
+ now = time(NULL);
+ break;
+ }
+ }
+ } while ((now < iplcp->sec) ||
+ ((iplcp->sec - now) > (86400*5)));
+
+ len = sizeof(iplcp->usec);
+ while (len) {
+ switch ((nr = read(fd, s, len)))
+ {
+ case -1:
+ case 0:
+ return;
+ default :
+ s += nr;
+ len -= nr;
+ break;
+ }
+ }
+ } while (iplcp->usec > 1000000);
+
+ len = sizeof(*iplcp) - sizeof(iplcp->sec) - sizeof(iplcp->usec);
+ while (len) {
+ switch ((nr = read(fd, s, len)))
+ {
+ case -1:
+ case 0:
+ return;
+ default :
+ s += nr;
+ len -= nr;
+ break;
+ }
+ }
+}
+
+
+int readlogentry(fd, lenp, buf, bufsize, log)
+int fd, bufsize, *lenp;
+char *buf;
+FILE *log;
+{
+ struct ipl_ci *icp = (struct ipl_ci *)buf;
+ time_t now;
+ char *s;
+ int len, n = bufsize, tr = sizeof(struct ipl_ci), nr;
+
+ if (bufsize < tr)
+ return 1;
+ for (s = buf; (n > 0) && (tr > 0); s += nr, n -= nr) {
+ nr = read(fd, s, tr);
+ if (nr > 0)
+ tr -= nr;
+ else
+ return -1;
+ }
+
+ now = time(NULL);
+ if ((icp->hlen > 92) || (now < icp->sec) ||
+ ((now - icp->sec) > (86400*5))) {
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_INFO, "Out of sync! (1,%x)\n", now);
+ else
+ fprintf(log, "Out of sync! (1,%x)\n", now);
+ dumphex(log, buf, sizeof(struct ipl_ci));
+ resynclog(fd, icp, log);
+ }
+
+
+ len = (int)((u_int)icp->plen);
+ if (len > 128 || len < 0) {
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_INFO, "Out of sync! (2,%d)\n", len);
+ else
+ fprintf(log, "Out of sync! (2,%d)\n", len);
+ dumphex(log, buf, sizeof(struct ipl_ci));
+ resynclog(fd, icp, log);
+ }
+
+
+ tr = icp->hlen + icp->plen;
+ if (n < tr)
+ return 1;
+
+ for (; (n > 0) && (tr > 0); s += nr, n-= nr) {
+ nr = read(fd, s, tr);
+ if (nr > 0)
+ tr -= nr;
+ else
+ return -1;
+ }
+ *lenp = s - buf;
+ return 0;
+}
+
+
+char *hostname(res, ip)
+int res;
+struct in_addr ip;
+{
+ struct hostent *hp;
+
+ if (!res)
+ return inet_ntoa(ip);
+ hp = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET);
+ if (!hp)
+ return inet_ntoa(ip);
+ return hp->h_name;
+}
+
+
+char *portname(res, proto, port)
+int res;
+char *proto;
+u_short port;
+{
+ static char pname[8];
+ struct servent *serv;
+
+ (void) sprintf(pname, "%hu", htons(port));
+ if (!res)
+ return pname;
+ serv = getservbyport((int)port, proto);
+ if (!serv)
+ return pname;
+ return serv->s_name;
+}
+
+
+static void dumphex(log, buf, len)
+FILE *log;
+u_char *buf;
+int len;
+{
+ char line[80];
+ int i, j, k;
+ u_char *s = buf, *t = (u_char *)line;
+
+ for (i = len, j = 0; i; i--, j++, s++) {
+ if (j && !(j & 0xf)) {
+ *t++ = '\n';
+ *t = '\0';
+ fputs(line, stdout);
+ t = (u_char *)line;
+ *t = '\0';
+ }
+ sprintf(t, "%02x", *s & 0xff);
+ t += 2;
+ if (!((j + 1) & 0xf)) {
+ s -= 15;
+ sprintf(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(t, " ");
+ t += 7;
+ s -= j & 0xf;
+ for (k = j & 0xf; k; k--, s++)
+ *t++ = (isprint(*s) ? *s : '.');
+ *t++ = '\n';
+ *t = '\0';
+ }
+ fputs(line, stdout);
+ fflush(stdout);
+}
+
+
+static void printpacket(log, buf, blen)
+FILE *log;
+char *buf;
+int blen;
+{
+ struct protoent *pr;
+ struct tcphdr *tp;
+ struct icmp *ic;
+ struct ip *ipc;
+ struct tm *tm;
+ char c[3], pname[8], *t, *proto;
+ u_short hl, p;
+ int i, lvl, res;
+#if !SOLARIS && !(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603))
+ int len;
+#endif
+ struct ip *ip;
+ struct ipl_ci *lp;
+
+ lp = (struct ipl_ci *)buf;
+ ip = (struct ip *)(buf + sizeof(*lp));
+ res = (opts & OPT_RESOLVE) ? 1 : 0;
+ t = line;
+ *t = '\0';
+ hl = (ip->ip_hl << 2);
+ p = (u_short)ip->ip_p;
+ tm = localtime((time_t *)&lp->sec);
+ if (!(opts & OPT_SYSLOG)) {
+ (void) sprintf(t, "%2d/%02d/%4d ",
+ tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
+ t += strlen(t);
+ }
+#if SOLARIS || (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603))
+ (void) sprintf(t, "%02d:%02d:%02d.%-.6ld %.*s @%hd ",
+ tm->tm_hour, tm->tm_min, tm->tm_sec, lp->usec,
+ (int)sizeof(lp->ifname), lp->ifname, lp->rule);
+#else
+ for (len = 0; len < 3; len++)
+ if (!lp->ifname[len])
+ break;
+ if (lp->ifname[len])
+ len++;
+ (void) sprintf(t, "%02d:%02d:%02d.%-.6ld %*.*s%ld @%hd ",
+ tm->tm_hour, tm->tm_min, tm->tm_sec, lp->usec,
+ len, len, lp->ifname, lp->unit, lp->rule);
+#endif
+ pr = getprotobynumber((int)p);
+ if (!pr) {
+ proto = pname;
+ sprintf(proto, "%d", (u_int)p);
+ } else
+ proto = pr->p_name;
+
+ if (lp->flags & (FI_SHORT << 20)) {
+ c[0] = 'S';
+ lvl = LOG_ERR;
+ } else if (lp->flags & FR_PASS) {
+ if (lp->flags & FR_LOGP)
+ c[0] = 'p';
+ else
+ c[0] = 'P';
+ lvl = LOG_NOTICE;
+ } else if (lp->flags & FR_BLOCK) {
+ if (lp->flags & FR_LOGB)
+ c[0] = 'b';
+ else
+ c[0] = 'B';
+ lvl = LOG_WARNING;
+ } else if (lp->flags & FF_LOGNOMATCH) {
+ c[0] = 'n';
+ lvl = LOG_NOTICE;
+ } else {
+ c[0] = 'L';
+ lvl = LOG_INFO;
+ }
+ c[1] = ' ';
+ c[2] = '\0';
+ (void) strcat(line, c);
+ t = line + strlen(line);
+
+ if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !(ip->ip_off & 0x1fff)) {
+ tp = (struct tcphdr *)((char *)ip + hl);
+ if (!(lp->flags & (FI_SHORT << 16))) {
+ (void) sprintf(t, "%s,%s -> ",
+ hostname(res, ip->ip_src),
+ portname(res, proto, tp->th_sport));
+ t += strlen(t);
+ (void) sprintf(t, "%s,%s PR %s len %hu %hu ",
+ hostname(res, ip->ip_dst),
+ portname(res, proto, tp->th_dport),
+ proto, hl, ip->ip_len);
+ t += strlen(t);
+
+ if (p == IPPROTO_TCP) {
+ *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)tp->th_seq,
+ (u_long)tp->th_ack, tp->th_win);
+ t += strlen(t);
+ }
+ *t = '\0';
+ } else {
+ (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src));
+ t += strlen(t);
+ (void) sprintf(t, "%s PR %s len %hu %hu",
+ hostname(res, ip->ip_dst), proto,
+ hl, ip->ip_len);
+ }
+ } else if (p == IPPROTO_ICMP) {
+ ic = (struct icmp *)((char *)ip + hl);
+ (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src));
+ t += strlen(t);
+ (void) sprintf(t, "%s PR icmp len %hu (%hu) icmp %d/%d",
+ hostname(res, ip->ip_dst), hl,
+ ip->ip_len, 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;
+ tp = (struct tcphdr *)((char *)ipc + hl);
+
+ p = (u_short)ipc->ip_p;
+ pr = getprotobynumber((int)p);
+ if (!pr) {
+ proto = pname;
+ (void) sprintf(proto, "%d", (int)p);
+ } else
+ proto = pr->p_name;
+
+ t += strlen(t);
+ (void) sprintf(t, " for %s,%s -",
+ hostname(res, ipc->ip_src),
+ portname(res, proto, tp->th_sport));
+ t += strlen(t);
+ (void) sprintf(t, " %s,%s PR %s len %hu %hu",
+ hostname(res, ipc->ip_dst),
+ portname(res, proto, tp->th_dport),
+ proto, ipc->ip_hl << 2, ipc->ip_len);
+ }
+ } else {
+ (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src));
+ t += strlen(t);
+ (void) sprintf(t, "%s PR %s len %hu (%hu)",
+ hostname(res, ip->ip_dst), proto, hl, ip->ip_len);
+ t += strlen(t);
+ if (ip->ip_off & 0x1fff)
+ (void) sprintf(t, " frag %s%s%hu@%hu",
+ ip->ip_off & IP_MF ? "+" : "",
+ ip->ip_off & IP_DF ? "-" : "",
+ ip->ip_len - hl, (ip->ip_off & 0x1fff) << 3);
+ }
+ t += strlen(t);
+
+ if (lp->flags & FR_KEEPSTATE) {
+ (void) strcpy(t, " K-S");
+ t += strlen(t);
+ }
+
+ if (lp->flags & FR_KEEPFRAG) {
+ (void) strcpy(t, " K-F");
+ t += strlen(t);
+ }
+
+ *t++ = '\n';
+ *t++ = '\0';
+ if (opts & OPT_SYSLOG)
+ syslog(lvl, "%s", line);
+ else
+ (void) fprintf(log, "%s", line);
+ if (opts & OPT_HEXHDR)
+ dumphex(log, buf, sizeof(struct ipl_ci));
+ if (opts & OPT_HEXBODY)
+ dumphex(log, ip, lp->plen + lp->hlen);
+ fflush(log);
+}
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ FILE *log = NULL;
+ int fd = -1, flushed = 0, doread, n;
+ char buf[512], c, *iplfile = IPL_NAME;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "Nf:FsvxX")) != -1)
+ switch (c)
+ {
+ case 'f' :
+ iplfile = optarg;
+ break;
+ case 'F' :
+ if ((fd == -1) &&
+ (fd = open(iplfile, O_RDWR)) == -1) {
+ (void) fprintf(stderr, "%s: ", IPL_NAME);
+ perror("open");
+ exit(-1);
+ }
+ if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
+ printf("%d bytes flushed from log buffer\n",
+ flushed);
+ fflush(stdout);
+ } else
+ perror("SIOCIPFFB");
+ break;
+ case 'N' :
+ opts |= OPT_RESOLVE;
+ break;
+ case 's' :
+ openlog(argv[0], LOG_NDELAY|LOG_PID, LOGFAC);
+ opts |= OPT_SYSLOG;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ case 'x' :
+ opts |= OPT_HEXBODY;
+ break;
+ case 'X' :
+ opts |= OPT_HEXHDR;
+ break;
+ }
+
+ if ((fd == -1) && (fd = open(iplfile, O_RDONLY)) == -1) {
+ (void) fprintf(stderr, "%s: ", IPL_NAME);
+ perror("open");
+ exit(-1);
+ }
+
+ if (!(opts & OPT_SYSLOG)) {
+ log = argv[optind] ? fopen(argv[optind], "a") : stdout;
+ setvbuf(log, NULL, _IONBF, 0);
+ }
+
+ if (flushed) {
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_INFO, "%d bytes flushed from log\n",
+ flushed);
+ else
+ fprintf(log, "%d bytes flushed from log\n", flushed);
+ }
+
+ for (doread = 1; doread; )
+ switch (readlogentry(fd, &n, buf, sizeof(buf), log))
+ {
+ case -1 :
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_ERR, "read: %m\n");
+ else
+ perror("read");
+ doread = 0;
+ break;
+ case 1 :
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_ERR, "aborting logging\n");
+ else
+ fprintf(log, "aborting logging\n");
+ doread = 0;
+ break;
+ case 2 :
+ break;
+ case 0 :
+ printpacket(log, buf, n, opts);
+ break;
+ }
+ exit(0);
+ /* NOTREACHED */
+}
diff --git a/contrib/ipfilter/ipnat.c b/contrib/ipfilter/ipnat.c
new file mode 100644
index 0000000..6458cde
--- /dev/null
+++ b/contrib/ipfilter/ipnat.c
@@ -0,0 +1,692 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ *
+ * Broken still:
+ * Displaying the nat with redirect entries is way confusing
+ *
+ * Example redirection line:
+ * rdr le1 0.0.0.0/0 port 79 -> 199.165.219.129 port 9901
+ *
+ * Will redirect all incoming packets on le1 to any machine, port 79 to
+ * host 199.165.219.129, port 9901
+ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#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>
+#include "ip_compat.h"
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include "ip_nat.h"
+#include <ctype.h>
+
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed";
+static char rcsid[] = "$Id: ipnat.c,v 2.0.1.7 1997/01/30 12:02:32 darrenr Exp $";
+#endif
+
+#if SOLARIS
+#define bzero(a,b) memset(a,0,b)
+#endif
+
+extern char *optarg;
+extern int kmemcpy();
+
+void dostats(), printnat(), parsefile(), flushtable();
+
+#define OPT_REM 1
+#define OPT_NODO 2
+#define OPT_STAT 4
+#define OPT_LIST 8
+#define OPT_VERBOSE 16
+#define OPT_FLUSH 32
+#define OPT_CLEAR 64
+
+
+void usage(name)
+char *name;
+{
+ fprintf(stderr, "%s: [-CFlnrsv] [-f filename]\n", name);
+ exit(1);
+}
+
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ char *file = NULL, c;
+ int fd, opts = 1;
+
+ while ((c = getopt(argc, argv, "CFf:lnrsv")) != -1)
+ switch (c)
+ {
+ case 'C' :
+ opts |= OPT_CLEAR;
+ break;
+ case 'f' :
+ file = optarg;
+ break;
+ case 'F' :
+ opts |= OPT_FLUSH;
+ break;
+ case 'l' :
+ opts |= OPT_LIST;
+ break;
+ case 'n' :
+ opts |= OPT_NODO;
+ break;
+ case 'r' :
+ opts &= ~OPT_REM;
+ break;
+ case 's' :
+ opts |= OPT_STAT;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ usage(argv[0]);
+ }
+
+ if (!(opts & OPT_NODO) && ((fd = open(IPL_NAME, O_RDWR)) == -1) &&
+ ((fd = open(IPL_NAME, O_RDONLY)) == -1)) {
+ perror("open");
+ exit(-1);
+ }
+
+ if (opts & (OPT_FLUSH|OPT_CLEAR))
+ flushtable(fd, opts);
+ if (file)
+ parsefile(fd, file, opts);
+ if (opts & (OPT_LIST|OPT_STAT))
+ dostats(fd, opts);
+ return 0;
+}
+
+
+/*
+ * count consecutive 1's in bit mask. If the mask generated by counting
+ * consecutive 1's is different to that passed, return -1, else return #
+ * of bits.
+ */
+int countbits(ip)
+u_long ip;
+{
+ u_long ipn;
+ int cnt = 0, i, j;
+
+ ip = ipn = ntohl(ip);
+ for (i = 32; i; i--, ipn *= 2)
+ if (ipn & 0x80000000)
+ cnt++;
+ else
+ break;
+ ipn = 0;
+ for (i = 32, j = cnt; i; i--, j--) {
+ ipn *= 2;
+ if (j > 0)
+ ipn++;
+ }
+ if (ipn == ip)
+ return cnt;
+ return -1;
+}
+
+
+void printnat(np, verbose, ptr)
+ipnat_t *np;
+int verbose;
+void *ptr;
+{
+ int bits;
+
+ if (np->in_redir == NAT_REDIRECT) {
+ printf("rdr %s %s", np->in_ifname, inet_ntoa(np->in_out[0]));
+ bits = countbits(np->in_out[1].s_addr);
+ if (bits != -1)
+ printf("/%d ", bits);
+ else
+ printf("/%s ", inet_ntoa(np->in_out[1]));
+ if (np->in_pmin)
+ printf("port %d ", ntohs(np->in_pmin));
+ printf("-> %s", inet_ntoa(np->in_in[0]));
+ if (np->in_pnext)
+ printf(" port %d", ntohs(np->in_pnext));
+ if (np->in_flags & IPN_TCPUDP)
+ printf(" tcp/udp");
+ else if (np->in_flags & IPN_TCP)
+ printf(" tcp");
+ else if (np->in_flags & IPN_UDP)
+ printf(" udp");
+ printf("\n");
+ if (verbose)
+ printf("\t%x %u %x %u %x %d\n", (u_int)np->in_ifp,
+ np->in_space, np->in_flags, np->in_pnext, np,
+ np->in_use);
+ } else {
+ np->in_nextip.s_addr = htonl(np->in_nextip.s_addr);
+ printf("map %s %s/", np->in_ifname, inet_ntoa(np->in_in[0]));
+ bits = countbits(np->in_in[1].s_addr);
+ if (bits != -1)
+ printf("%d ", bits);
+ else
+ printf("%s", inet_ntoa(np->in_in[1]));
+ printf(" -> %s/", inet_ntoa(np->in_out[0]));
+ bits = countbits(ntohl(np->in_out[1].s_addr));
+ if (bits != -1)
+ printf("%d ", bits);
+ else
+ printf("%s", inet_ntoa(np->in_out[1]));
+ if (np->in_pmin || np->in_pmax) {
+ printf(" portmap");
+ 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");
+ printf(" %d:%d", ntohs(np->in_pmin),
+ ntohs(np->in_pmax));
+ }
+ printf("\n");
+ if (verbose)
+ printf("\t%x %u %s %d %x\n", (u_int)np->in_ifp,
+ np->in_space, inet_ntoa(np->in_nextip),
+ np->in_pnext, np->in_flags);
+ }
+}
+
+
+/*
+ * Get a nat filter type given its kernel address.
+ */
+char *getnattype(ipnat)
+ipnat_t *ipnat;
+{
+ ipnat_t ipnatbuff;
+
+ if (ipnat && kmemcpy(&ipnatbuff, ipnat, sizeof(ipnatbuff)))
+ return "???";
+
+ return (ipnatbuff.in_redir == NAT_MAP) ? "MAP" : "RDR";
+}
+
+
+void dostats(fd, opts)
+int fd, opts;
+{
+ natstat_t ns;
+ ipnat_t ipn;
+ nat_t **nt[2], *np, nat;
+ int i = 0;
+
+ bzero((char *)&ns, sizeof(ns));
+
+ if (!(opts & OPT_NODO) && ioctl(fd, SIOCGNATS, &ns) == -1) {
+ perror("ioctl(SIOCGNATS)");
+ return;
+ }
+
+ if (opts & OPT_STAT) {
+ printf("mapped\tin\t%lu\tout\t%lu\n",
+ ns.ns_mapped[0], ns.ns_mapped[1]);
+ printf("added\t%lu\texpired\t%lu\n",
+ ns.ns_added, ns.ns_expire);
+ printf("inuse\t%lu\n", ns.ns_inuse);
+ if (opts & OPT_VERBOSE)
+ printf("table %#x list %#x\n",
+ (u_int)ns.ns_table, (u_int)ns.ns_list);
+ }
+ if (opts & OPT_LIST) {
+ printf("List of active MAP/Redirect filters:\n");
+ while (ns.ns_list) {
+ if (kmemcpy(&ipn, ns.ns_list, sizeof(ipn))) {
+ perror("kmemcpy");
+ break;
+ }
+ printnat(&ipn, opts & OPT_VERBOSE, (void *)ns.ns_list);
+ ns.ns_list = ipn.in_next;
+ }
+
+ nt[0] = (nat_t **)malloc(sizeof(*nt) * NAT_SIZE);
+ if (kmemcpy(nt[0], ns.ns_table[0], sizeof(**nt) * NAT_SIZE)) {
+ perror("kmemcpy");
+ return;
+ }
+
+ printf("\nList of active sessions:\n");
+
+ for (i = 0; i < NAT_SIZE; i++)
+ for (np = nt[0][i]; np; np = nat.nat_hnext[0]) {
+ if (kmemcpy(&nat, np, sizeof(nat)))
+ break;
+
+ printf("%s %-15s %-5hu <- ->",
+ getnattype(nat.nat_ptr),
+ inet_ntoa(nat.nat_inip),
+ ntohs(nat.nat_inport));
+ printf(" %-15s %-5hu",
+ inet_ntoa(nat.nat_outip),
+ ntohs(nat.nat_outport));
+ printf(" [%s %hu]", inet_ntoa(nat.nat_oip),
+ ntohs(nat.nat_oport));
+ printf(" %d %hu %lx", nat.nat_age,
+ nat.nat_use, nat.nat_sumd);
+#if SOLARIS
+ printf(" %lx", nat.nat_ipsumd);
+#endif
+ putchar('\n');
+ }
+ free(nt[0]);
+ }
+}
+
+
+u_short portnum(name, proto)
+char *name, *proto;
+{
+ struct servent *sp, *sp2;
+ u_short p1 = 0;
+
+ if (isdigit(*name))
+ return htons((u_short)atoi(name));
+ if (!proto)
+ proto = "tcp/udp";
+ if (strcasecmp(proto, "tcp/udp")) {
+ sp = getservbyname(name, proto);
+ if (sp)
+ return sp->s_port;
+ (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 p1;
+}
+
+
+u_long hostmask(msk)
+char *msk;
+{
+ int bits = -1;
+ u_long mask;
+
+ if (!isdigit(*msk))
+ return (u_long)-1;
+ if (strchr(msk, '.'))
+ return inet_addr(msk);
+ if (strchr(msk, 'x'))
+ return (u_long)strtol(msk, NULL, 0);
+ /*
+ * set x most significant bits
+ */
+ for (mask = 0, bits = atoi(msk); bits; bits--) {
+ mask /= 2;
+ mask |= ntohl(inet_addr("128.0.0.0"));
+ }
+ mask = htonl(mask);
+ return mask;
+}
+
+
+/*
+ * returns an ip address as a long var as a result of either a DNS lookup or
+ * straight inet_addr() call
+ */
+u_long hostnum(host, resolved)
+char *host;
+int *resolved;
+{
+ struct hostent *hp;
+ struct netent *np;
+
+ *resolved = 0;
+ if (!strcasecmp("any",host))
+ return 0L;
+ if (isdigit(*host))
+ return inet_addr(host);
+
+ if (!(hp = gethostbyname(host))) {
+ if (!(np = getnetbyname(host))) {
+ *resolved = -1;
+ fprintf(stderr, "can't resolve hostname: %s\n", host);
+ return 0;
+ }
+ return np->n_net;
+ }
+ return *(u_long *)hp->h_addr;
+}
+
+
+ipnat_t *parse(line)
+char *line;
+{
+ static ipnat_t ipn;
+ char *s, *t;
+ char *shost, *snetm, *dhost, *proto;
+ char *dnetm = NULL, *dport = NULL, *tport = NULL;
+ int resolved;
+
+ bzero((char *)&ipn, sizeof(ipn));
+ if ((s = strchr(line, '\n')))
+ *s = '\0';
+ if ((s = strchr(line, '#')))
+ *s = '\0';
+ if (!*line)
+ return NULL;
+ if (!(s = strtok(line, " \t")))
+ return NULL;
+ if (!strcasecmp(s, "map"))
+ ipn.in_redir = NAT_MAP;
+ else if (!strcasecmp(s, "rdr"))
+ ipn.in_redir = NAT_REDIRECT;
+ else {
+ (void)fprintf(stderr,
+ "expected \"map\" or \"rdr\", got \"%s\"\n", s);
+ return NULL;
+ }
+
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (interface)\n");
+ return NULL;
+ }
+ strncpy(ipn.in_ifname, s, sizeof(ipn.in_ifname) - 1);
+ ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0';
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (%s)\n",
+ ipn.in_redir ? "destination": "source");
+ return NULL;
+ }
+ shost = s;
+
+ if (ipn.in_redir == NAT_REDIRECT) {
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (destination port)\n");
+ return NULL;
+ }
+
+ if (strcasecmp(s, "port")) {
+ fprintf(stderr, "missing fields (port)\n");
+ return NULL;
+ }
+
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (destination port)\n");
+ return NULL;
+ }
+
+ dport = s;
+ }
+
+
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (->)\n");
+ return NULL;
+ }
+ if (!strcmp(s, "->")) {
+ snetm = strrchr(shost, '/');
+ if (!snetm) {
+ fprintf(stderr, "missing fields (%s netmask)\n",
+ ipn.in_redir ? "destination":"source");
+ return NULL;
+ }
+ } else {
+ if (strcasecmp(s, "netmask")) {
+ fprintf(stderr, "missing fields (netmask)\n");
+ return NULL;
+ }
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (%s netmask)\n",
+ ipn.in_redir ? "destination":"source");
+ return NULL;
+ }
+ snetm = s;
+ }
+
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (%s)\n",
+ ipn.in_redir ? "destination":"target");
+ return NULL;
+ }
+ dhost = s;
+
+ if (ipn.in_redir == NAT_MAP) {
+ if (!(s = strtok(NULL, " \t"))) {
+ dnetm = strrchr(dhost, '/');
+ if (!dnetm) {
+ fprintf(stderr,
+ "missing fields (dest netmask)\n");
+ return NULL;
+ }
+ }
+ if (!s || !strcasecmp(s, "portmap")) {
+ dnetm = strrchr(dhost, '/');
+ if (!dnetm) {
+ fprintf(stderr,
+ "missing fields (dest netmask)\n");
+ return NULL;
+ }
+ } else {
+ if (strcasecmp(s, "netmask")) {
+ fprintf(stderr,
+ "missing fields (dest netmask)\n");
+ return NULL;
+ }
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr,
+ "missing fields (dest netmask)\n");
+ return NULL;
+ }
+ dnetm = s;
+ }
+ if (*dnetm == '/')
+ *dnetm++ = '\0';
+ } else {
+ /* If it's a in_redir, expect target port */
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (destination port)\n");
+ return NULL;
+ }
+
+ if (strcasecmp(s, "port")) {
+ fprintf(stderr, "missing fields (port)\n");
+ return NULL;
+ }
+
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "missing fields (destination port)\n");
+ return NULL;
+ }
+ tport = s;
+ }
+
+
+ if (*snetm == '/')
+ *snetm++ = '\0';
+
+ if (ipn.in_redir == NAT_MAP) {
+ ipn.in_inip = hostnum(shost, &resolved);
+ if (resolved == -1)
+ return NULL;
+ ipn.in_inmsk = hostmask(snetm);
+ ipn.in_outip = hostnum(dhost, &resolved);
+ if (resolved == -1)
+ return NULL;
+ ipn.in_outmsk = hostmask(dnetm);
+ } else {
+ ipn.in_inip = hostnum(dhost, &resolved); /* Inside is target */
+ if (resolved == -1)
+ return NULL;
+ ipn.in_inmsk = hostmask("255.255.255.255");
+ ipn.in_outip = hostnum(shost, &resolved);
+ if (resolved == -1)
+ return NULL;
+ ipn.in_outmsk = hostmask(snetm);
+ if (!(s = strtok(NULL, " \t"))) {
+ ipn.in_flags = IPN_TCP; /* XXX- TCP only by default */
+ proto = "tcp";
+ } else {
+ if (!strcasecmp(s, "tcp"))
+ ipn.in_flags = IPN_TCP;
+ else if (!strcasecmp(s, "udp"))
+ ipn.in_flags = IPN_UDP;
+ else if (!strcasecmp(s, "tcp/udp"))
+ ipn.in_flags = IPN_TCPUDP;
+ else if (!strcasecmp(s, "tcpudp"))
+ ipn.in_flags = IPN_TCPUDP;
+ else {
+ fprintf(stderr,
+ "expected protocol - got \"%s\"\n", s);
+ return NULL;
+ }
+ proto = s;
+ if ((s = strtok(NULL, " \t"))) {
+ fprintf(stderr,
+ "extra junk at the end of rdr: %s\n",
+ s);
+ return NULL;
+ }
+ }
+ ipn.in_pmin = portnum(dport, proto); /* dest port */
+ ipn.in_pmax = ipn.in_pmin; /* NECESSARY of removing nats */
+ ipn.in_pnext = portnum(tport, proto); /* target port */
+ s = NULL; /* That's all she wrote! */
+ }
+ if (!s)
+ return &ipn;
+ if (strcasecmp(s, "portmap")) {
+ fprintf(stderr, "expected \"portmap\" - got \"%s\"\n", s);
+ return NULL;
+ }
+ if (!(s = strtok(NULL, " \t")))
+ return NULL;
+ if (!strcasecmp(s, "tcp"))
+ ipn.in_flags = IPN_TCP;
+ else if (!strcasecmp(s, "udp"))
+ ipn.in_flags = IPN_UDP;
+ else if (!strcasecmp(s, "tcpudp"))
+ ipn.in_flags = IPN_TCPUDP;
+ else if (!strcasecmp(s, "tcp/udp"))
+ ipn.in_flags = IPN_TCPUDP;
+ else {
+ fprintf(stderr, "expected protocol name - got \"%s\"\n", s);
+ return NULL;
+ }
+ proto = s;
+ if (!(s = strtok(NULL, " \t"))) {
+ fprintf(stderr, "no port range found\n");
+ return NULL;
+ }
+ if (!(t = strchr(s, ':'))) {
+ fprintf(stderr, "no port range in \"%s\"\n", s);
+ return NULL;
+ }
+ *t++ = '\0';
+ ipn.in_pmin = portnum(s, proto);
+ ipn.in_pmax = portnum(t, proto);
+ return &ipn;
+}
+
+
+void parsefile(fd, file, opts)
+int fd;
+char *file;
+int opts;
+{
+ char line[512], *s;
+ ipnat_t *np;
+ FILE *fp;
+ int linenum = 1;
+
+ if (strcmp(file, "-"))
+ fp = fopen(file, "r");
+ else
+ fp = stdin;
+
+ while (fgets(line, sizeof(line) - 1, fp)) {
+ line[sizeof(line) - 1] = '\0';
+ if ((s = strchr(line, '\n')))
+ *s = '\0';
+ if (!(np = parse(line))) {
+ if (*line)
+ fprintf(stderr, "%d: syntax error in \"%s\"\n",
+ linenum, line);
+ } else if (!(opts & OPT_NODO)) {
+ if ((opts & OPT_VERBOSE) && np)
+ printnat(np, opts & OPT_VERBOSE, NULL);
+ if (opts & OPT_REM) {
+ if (ioctl(fd, SIOCADNAT, np) == -1)
+ perror("ioctl(SIOCADNAT)");
+ } else if (ioctl(fd, SIOCRMNAT, np) == -1)
+ perror("ioctl(SIOCRMNAT)");
+ }
+ linenum++;
+ }
+ fclose(stdin);
+}
+
+
+void flushtable(fd, opts)
+int fd, opts;
+{
+ int n = 0;
+
+ if (opts & OPT_FLUSH) {
+ n = 0;
+ if (!(opts & OPT_NODO) && ioctl(fd, SIOCFLNAT, &n) == -1)
+ perror("ioctl(SIOCFLNAT)");
+ else
+ printf("%d entries flushed from NAT table\n", n);
+ }
+
+ if (opts & OPT_CLEAR) {
+ n = 0;
+ if (!(opts & OPT_NODO) && ioctl(fd, SIOCCNATL, &n) == -1)
+ perror("ioctl(SIOCCNATL)");
+ else
+ printf("%d entries flushed from NAT list\n", n);
+ }
+}
diff --git a/contrib/ipfilter/ipsd/Makefile b/contrib/ipfilter/ipsd/Makefile
new file mode 100644
index 0000000..eb1986e
--- /dev/null
+++ b/contrib/ipfilter/ipsd/Makefile
@@ -0,0 +1,63 @@
+#
+# (C)opyright 1993-1996 by Darren Reed.
+#
+# 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 ?
+#
+OBJS=ipsd.o
+BINDEST=/usr/local/bin
+SBINDEST=/sbin
+MANDIR=/usr/share/man
+BPF=sbpf.o
+NIT=snit.o
+SUNOS4=
+BSD=
+LINUX=slinux.o
+SUNOS5=dlcommon.o sdlpi.o
+
+CC=gcc
+CFLAGS=-g -I..
+
+all:
+ @echo "Use one of these targets:"
+ @echo " sunos4-nit (standard SunOS 4.1.x)"
+ @echo " sunos4-bpf (SunOS4.1.x with BPF in the kernel)"
+ @echo " bsd-bpf (4.4BSD variant with BPF in the kernel)"
+ @echo " linux (Linux kernels)"
+ @echo " sunos5 (Solaris 2.x)"
+
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $@
+
+ipsdr: ipsdr.o
+ $(CC) ipsdr.o -o $@ $(LIBS)
+
+bpf sunos4-bpf :
+ make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS)"
+
+nit sunos4 sunos4-nit :
+ make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS)"
+
+sunos5 :
+ make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -Dsolaris" "LIBS=-lsocket -lnsl"
+
+bsd-bpf :
+ make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS)"
+
+linux :
+ make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -I /usr/src/linux"
+
+ipsd: $(OBJS) $(UNIXOBJS)
+ $(CC) $(OBJS) $(UNIXOBJS) -o $@ $(LIBS)
+
+../ipft_sn.o ../ipft_pc.o:
+ (cd ..; make $(@:../%=%))
+
+clean:
+ rm -rf *.o core a.out ipsd ipsdr
diff --git a/contrib/ipfilter/ipsd/README b/contrib/ipfilter/ipsd/README
new file mode 100644
index 0000000..6746d01
--- /dev/null
+++ b/contrib/ipfilter/ipsd/README
@@ -0,0 +1,32 @@
+
+IP Scan Detetor.
+----------------
+
+This program is designed to be a passive listener for TCP packets sent to
+the host. It does not exercise the promiscous mode of interfaces. For
+routing Unix boxes (and firewalls which route/proxy) this is sufficient to
+detect all packets going to/through them.
+
+Upon compiling, a predefined set of "sensitive" ports are configured into
+the program. Any TCP packets which are seen sent to these ports are counted
+and the IP# of the sending host recorded, along with the time of the first
+packet to that port for that IP#.
+
+After a given number of "hits", it will write the current table of packets
+out to disk. This number defaults to 10,000.
+
+To analyze the information written to disk, a sample program called "ipsdr"
+is used (should but doesn't implement a tree algorithm for storing data)
+which reads all log files it recognises and totals up the number of ports
+each host hit. By default, all ports have the same weighting (1). Another
+group of passes is then made over this table using a netmask of 0xfffffffe,
+grouping all results which fall under the same resulting IP#. This netmask
+is then shrunk back to 0, with a output for each level given. This is aimed
+at detecting port scans done from different hosts on the same subnet (although
+I've not seen this done, if one was trying to do it obscurely...)
+
+Lastly, being passive means that no action is taken to stop port scans being
+done or discourage them.
+
+Darren
+darrenr@cyber.com.au
diff --git a/contrib/ipfilter/ipsd/ip_compat.h b/contrib/ipfilter/ipsd/ip_compat.h
new file mode 100644
index 0000000..a911fd8
--- /dev/null
+++ b/contrib/ipfilter/ipsd/ip_compat.h
@@ -0,0 +1,201 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * 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 ?
+ *
+ * @(#)ip_compat.h 1.1 9/14/95
+ */
+
+/*
+ * 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_UNREACH
+# define ICMP_UNREACH ICMP_DEST_UNREACH
+#endif
+#ifndef ICMP_SOURCEQUENCH
+# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH
+#endif
+#ifndef ICMP_TIMXCEED
+# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED
+#endif
+#ifndef ICMP_PARAMPROB
+# define ICMP_PARAMPROB ICMP_PARAMETERPROB
+#endif
+#ifndef IPVERSION
+# define IPVERSION 4
+#endif
+#ifndef IPOPT_MINOFF
+# define IPOPT_MINOFF 4
+#endif
+#ifndef IPOPT_COPIED
+# define IPOPT_COPIED(x) ((x)&0x80)
+#endif
+#ifndef IPOPT_EOL
+# define IPOPT_EOL 0
+#endif
+#ifndef IPOPT_NOP
+# define IPOPT_NOP 1
+#endif
+#ifndef IP_MF
+# define IP_MF ((u_short)0x2000)
+#endif
+#ifndef ETHERTYPE_IP
+# define ETHERTYPE_IP ((u_short)0x0800)
+#endif
+#ifndef TH_FIN
+# define TH_FIN 0x01
+#endif
+#ifndef TH_SYN
+# define TH_SYN 0x02
+#endif
+#ifndef TH_RST
+# define TH_RST 0x04
+#endif
+#ifndef TH_PUSH
+# define TH_PUSH 0x08
+#endif
+#ifndef TH_ACK
+# define TH_ACK 0x10
+#endif
+#ifndef TH_URG
+# define TH_URG 0x20
+#endif
+#ifndef IPOPT_EOL
+# define IPOPT_EOL 0
+#endif
+#ifndef IPOPT_NOP
+# define IPOPT_NOP 1
+#endif
+#ifndef IPOPT_RR
+# define IPOPT_RR 7
+#endif
+#ifndef IPOPT_TS
+# define IPOPT_TS 68
+#endif
+#ifndef IPOPT_SECURITY
+# define IPOPT_SECURITY 130
+#endif
+#ifndef IPOPT_LSRR
+# define IPOPT_LSRR 131
+#endif
+#ifndef IPOPT_SATID
+# define IPOPT_SATID 136
+#endif
+#ifndef IPOPT_SSRR
+# define IPOPT_SSRR 137
+#endif
+#ifndef IPOPT_SECUR_UNCLASS
+# define IPOPT_SECUR_UNCLASS ((u_short)0x0000)
+#endif
+#ifndef IPOPT_SECUR_CONFID
+# define IPOPT_SECUR_CONFID ((u_short)0xf135)
+#endif
+#ifndef IPOPT_SECUR_EFTO
+# define IPOPT_SECUR_EFTO ((u_short)0x789a)
+#endif
+#ifndef IPOPT_SECUR_MMMM
+# define IPOPT_SECUR_MMMM ((u_short)0xbc4d)
+#endif
+#ifndef IPOPT_SECUR_RESTR
+# define IPOPT_SECUR_RESTR ((u_short)0xaf13)
+#endif
+#ifndef IPOPT_SECUR_SECRET
+# define IPOPT_SECUR_SECRET ((u_short)0xd788)
+#endif
+#ifndef IPOPT_SECUR_TOPSECRET
+# define IPOPT_SECUR_TOPSECRET ((u_short)0x6bc5)
+#endif
+
+#ifdef linux
+# define icmp icmphdr
+# define icmp_type type
+# define icmp_code code
+
+/*
+ * From /usr/include/netinet/ip_var.h
+ * !%@#!$@# linux...
+ */
+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 */
+};
+
+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;
+ __s16 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_hl:4;
+ __u8 ip_v: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;
+
+typedef struct {
+ __u8 ether_dhost[6];
+ __u8 ether_shost[6];
+ __u16 ether_type;
+} ether_header_t;
+
+# define bcopy(a,b,c) memmove(b,a,c)
+# define bcmp(a,b,c) memcmp(a,b,c)
+
+# define ifnet device
+
+#else
+
+typedef struct udphdr udphdr_t;
+typedef struct tcphdr tcphdr_t;
+typedef struct ip ip_t;
+typedef struct ether_header ether_header_t;
+
+#endif
+
+#ifdef solaris
+# define bcopy(a,b,c) memmove(b,a,c)
+# define bcmp(a,b,c) memcmp(a,b,c)
+# define bzero(a,b) memset(a,0,b)
+#endif
diff --git a/contrib/ipfilter/ipsd/ipsd.c b/contrib/ipfilter/ipsd/ipsd.c
new file mode 100644
index 0000000..96364dd
--- /dev/null
+++ b/contrib/ipfilter/ipsd/ipsd.c
@@ -0,0 +1,297 @@
+/*
+ * (C)opyright December 1995 Darren Reed.
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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>
+#include <signal.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <string.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 <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#ifndef linux
+#include <netinet/ip_var.h>
+#include <netinet/tcpip.h>
+#endif
+#include "ip_compat.h"
+#ifdef linux
+#include <linux/sockios.h>
+#include "tcpip.h"
+#endif
+#include "ipsd.h"
+
+#ifndef lint
+static char sccsid[] = "@(#)ipsd.c 1.3 12/3/95 (C)1995 Darren Reed";
+#endif
+
+extern char *optarg;
+extern int optind;
+
+#ifdef linux
+char default_device[] = "eth0";
+#else
+# ifdef sun
+char default_device[] = "le0";
+# else
+# ifdef ultrix
+char default_device[] = "ln0";
+# else
+char default_device[] = "lan0";
+# endif
+# endif
+#endif
+
+#define NPORTS 21
+
+u_short defports[NPORTS] = {
+ 7, 9, 20, 21, 23, 25, 53, 69, 79, 111,
+ 123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0
+ };
+
+ipsd_t *iphits[NPORTS];
+int writes = 0;
+
+
+int ipcmp(sh1, sh2)
+sdhit_t *sh1, *sh2;
+{
+ return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr;
+}
+
+
+/*
+ * Check to see if we've already received a packet from this host for this
+ * port.
+ */
+int findhit(ihp, src, dport)
+ipsd_t *ihp;
+struct in_addr src;
+u_short dport;
+{
+ int i, j, k;
+ sdhit_t *sh;
+
+ sh = NULL;
+
+ if (ihp->sd_sz == 4) {
+ for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++)
+ if (src.s_addr == sh->sh_ip.s_addr)
+ return 1;
+ } else {
+ for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) {
+ k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr;
+ if (!k)
+ return 1;
+ else if (k < 0)
+ i -= j;
+ else
+ i += j;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Search for port number amongst the sorted array of targets we're
+ * interested in.
+ */
+int detect(ip, tcp)
+ip_t *ip;
+tcphdr_t *tcp;
+{
+ ipsd_t *ihp;
+ sdhit_t *sh;
+ int i, j, k;
+
+ for (i = 10, j = 4; j >= 0; j--) {
+ k = tcp->th_dport - defports[i];
+ if (!k) {
+ ihp = iphits[i];
+ if (findhit(ihp, ip->ip_src, tcp->th_dport))
+ return 0;
+ sh = ihp->sd_hit + ihp->sd_cnt;
+ sh->sh_date = time(NULL);
+ sh->sh_ip.s_addr = ip->ip_src.s_addr;
+ if (++ihp->sd_cnt == ihp->sd_sz)
+ {
+ ihp->sd_sz += 8;
+ sh = realloc(sh, ihp->sd_sz * sizeof(*sh));
+ ihp->sd_hit = sh;
+ }
+ qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp);
+ return 0;
+ }
+ if (k < 0)
+ i -= j;
+ else
+ i += j;
+ }
+ return -1;
+}
+
+
+/*
+ * Allocate initial storage for hosts
+ */
+setuphits()
+{
+ int i;
+
+ for (i = 0; i < NPORTS; i++) {
+ if (iphits[i]) {
+ if (iphits[i]->sd_hit)
+ free(iphits[i]->sd_hit);
+ free(iphits[i]);
+ }
+ iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t));
+ iphits[i]->sd_port = defports[i];
+ iphits[i]->sd_cnt = 0;
+ iphits[i]->sd_sz = 4;
+ iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4);
+ }
+}
+
+
+/*
+ * cleanup exits
+ */
+waiter()
+{
+ wait(0);
+}
+
+
+/*
+ * Write statistics out to a file
+ */
+writestats(nwrites)
+int nwrites;
+{
+ ipsd_t **ipsd, *ips;
+ char fname[32];
+ int i, fd;
+
+ (void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites);
+ fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644);
+ for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) {
+ ips = *ipsd;
+ if (ips->sd_cnt) {
+ write(fd, ips, sizeof(ipsd_t));
+ write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz);
+ }
+ }
+ (void) close(fd);
+ exit(0);
+}
+
+
+void writenow()
+{
+ signal(SIGCHLD, waiter);
+ switch (fork())
+ {
+ case 0 :
+ writestats(writes);
+ exit(0);
+ case -1 :
+ perror("vfork");
+ break;
+ default :
+ writes++;
+ setuphits();
+ break;
+ }
+}
+
+
+void usage(prog)
+char *prog;
+{
+ fprintf(stderr, "Usage: %s [-d device]\n", prog);
+ exit(1);
+}
+
+
+void detecthits(fd, writecount)
+int fd, writecount;
+{
+ struct in_addr ip;
+ int hits = 0;
+
+ while (1) {
+ hits += readloop(fd, ip);
+ if (hits > writecount) {
+ writenow();
+ hits = 0;
+ }
+ }
+}
+
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char c, *name = argv[0], *dev = NULL;
+ int fd, writeafter = 10000, angelic = 0;
+
+ while ((c = getopt(argc, argv, "ad:n:")) != -1)
+ switch (c)
+ {
+ case 'a' :
+ angelic = 1;
+ break;
+ case 'd' :
+ dev = optarg;
+ break;
+ case 'n' :
+ writeafter = atoi(optarg);
+ break;
+ default :
+ fprintf(stderr, "Unknown option \"%c\"\n", c);
+ usage(name);
+ }
+
+ bzero(iphits, sizeof(iphits));
+ setuphits();
+
+ if (!dev)
+ dev = default_device;
+ printf("Device: %s\n", dev);
+ fd = initdevice(dev, 60);
+
+ if (!angelic) {
+ switch (fork())
+ {
+ case 0 :
+ (void) close(0);
+ (void) close(1);
+ (void) close(2);
+ (void) setpgrp(0, getpgrp());
+ (void) setsid();
+ break;
+ case -1:
+ perror("fork");
+ exit(-1);
+ default:
+ exit(0);
+ }
+ }
+ signal(SIGUSR1, writenow);
+ detecthits(fd, writeafter);
+}
diff --git a/contrib/ipfilter/ipsd/ipsd.h b/contrib/ipfilter/ipsd/ipsd.h
new file mode 100644
index 0000000..a9f3920
--- /dev/null
+++ b/contrib/ipfilter/ipsd/ipsd.h
@@ -0,0 +1,30 @@
+/*
+ * (C)opyright December 1995 Darren Reed.
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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
+ */
+
+typedef struct {
+ time_t sh_date;
+ struct in_addr sh_ip;
+} sdhit_t;
+
+typedef struct {
+ u_int sd_sz;
+ u_int sd_cnt;
+ u_short sd_port;
+ sdhit_t *sd_hit;
+} ipsd_t;
+
+typedef struct {
+ struct in_addr ss_ip;
+ int ss_hits;
+ u_long ss_ports;
+} ipss_t;
+
diff --git a/contrib/ipfilter/ipsd/ipsdr.c b/contrib/ipfilter/ipsd/ipsdr.c
new file mode 100644
index 0000000..b3bf957
--- /dev/null
+++ b/contrib/ipfilter/ipsd/ipsdr.c
@@ -0,0 +1,315 @@
+/*
+ * (C)opyright December 1995 Darren Reed.
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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>
+#include <signal.h>
+#include <malloc.h>
+#include <netdb.h>
+#include <string.h>
+#include <sys/dir.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 <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#ifndef linux
+#include <netinet/ip_var.h>
+#include <netinet/tcpip.h>
+#endif
+#include "ip_compat.h"
+#ifdef linux
+#include <linux/sockios.h>
+#include "tcpip.h"
+#endif
+#include "ipsd.h"
+
+#ifndef lint
+static char sccsid[] = "@(#)ipsdr.c 1.3 12/3/95 (C)1995 Darren Reed";
+#endif
+
+extern char *optarg;
+extern int optind;
+
+#define NPORTS 21
+
+u_short defports[NPORTS] = {
+ 7, 9, 20, 21, 23, 25, 53, 69, 79, 111,
+ 123, 161, 162, 512, 513, 513, 515, 520, 540, 6000, 0
+ };
+u_short pweights[NPORTS] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ };
+
+ipsd_t *iphits[NPORTS];
+int pkts;
+
+
+int ipcmp(sh1, sh2)
+sdhit_t *sh1, *sh2;
+{
+ return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr;
+}
+
+
+int ssipcmp(sh1, sh2)
+ipss_t *sh1, *sh2;
+{
+ return sh1->ss_ip.s_addr - sh2->ss_ip.s_addr;
+}
+
+
+int countpbits(num)
+u_long num;
+{
+ int i, j;
+
+ for (i = 1, j = 0; i; i <<= 1)
+ if (num & i)
+ j++;
+ return j;
+}
+
+
+/*
+ * Check to see if we've already received a packet from this host for this
+ * port.
+ */
+int findhit(ihp, src, dport)
+ipsd_t *ihp;
+struct in_addr src;
+u_short dport;
+{
+ int i, j, k;
+ sdhit_t *sh;
+
+ sh = NULL;
+
+ if (ihp->sd_sz == 4) {
+ for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++)
+ if (src.s_addr == sh->sh_ip.s_addr)
+ return 1;
+ } else {
+ for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) {
+ k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr;
+ if (!k)
+ return 1;
+ else if (k < 0)
+ i -= j;
+ else
+ i += j;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Search for port number amongst the sorted array of targets we're
+ * interested in.
+ */
+int detect(srcip, dport, date)
+struct in_addr srcip;
+u_short dport;
+time_t date;
+{
+ ipsd_t *ihp;
+ sdhit_t *sh;
+ int i, j, k;
+
+ for (i = 10, j = 4; j >= 0; j--) {
+ k = dport - defports[i];
+ if (!k) {
+ ihp = iphits[i];
+ if (findhit(ihp, srcip, dport))
+ return 0;
+ sh = ihp->sd_hit + ihp->sd_cnt;
+ sh->sh_date = date;
+ sh->sh_ip = srcip;
+ if (++ihp->sd_cnt == ihp->sd_sz)
+ {
+ ihp->sd_sz += 8;
+ sh = realloc(sh, ihp->sd_sz * sizeof(*sh));
+ ihp->sd_hit = sh;
+ }
+ qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp);
+ return 0;
+ }
+ if (k < 0)
+ i -= j;
+ else
+ i += j;
+ }
+ return -1;
+}
+
+
+/*
+ * Allocate initial storage for hosts
+ */
+setuphits()
+{
+ int i;
+
+ for (i = 0; i < NPORTS; i++) {
+ if (iphits[i]) {
+ if (iphits[i]->sd_hit)
+ free(iphits[i]->sd_hit);
+ free(iphits[i]);
+ }
+ iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t));
+ iphits[i]->sd_port = defports[i];
+ iphits[i]->sd_cnt = 0;
+ iphits[i]->sd_sz = 4;
+ iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4);
+ }
+}
+
+
+/*
+ * Write statistics out to a file
+ */
+addfile(file)
+char *file;
+{
+ ipsd_t ipsd, *ips = &ipsd;
+ sdhit_t hit, *hp;
+ char fname[32];
+ int i, fd, sz;
+
+ if ((fd = open(file, O_RDONLY)) == -1) {
+ perror("open");
+ return;
+ }
+
+ printf("opened %s\n", file);
+ do {
+ if (read(fd, ips, sizeof(*ips)) != sizeof(*ips))
+ break;
+ sz = ips->sd_sz * sizeof(*hp);
+ hp = (sdhit_t *)malloc(sz);
+ if (read(fd, hp, sz) != sz)
+ break;
+ for (i = 0; i < ips->sd_cnt; i++)
+ detect(hp[i].sh_ip, ips->sd_port, hp[i].sh_date);
+ } while (1);
+ (void) close(fd);
+}
+
+
+readfiles(dir)
+char *dir;
+{
+ struct direct **d;
+ int i, j;
+
+ d = NULL;
+ i = scandir(dir, &d, NULL, NULL);
+
+ for (j = 0; j < i; j++) {
+ if (strncmp(d[j]->d_name, "ipsd-hits.", 10))
+ continue;
+ addfile(d[j]->d_name);
+ }
+}
+
+
+void printreport(ss, num)
+ipss_t *ss;
+int num;
+{
+ struct in_addr ip;
+ ipss_t *sp;
+ int i, j, mask;
+ u_long ports;
+
+ printf("Hosts detected: %d\n", num);
+ if (!num)
+ return;
+ for (i = 0; i < num; i++)
+ printf("%s %d %d\n", inet_ntoa(ss[i].ss_ip), ss[i].ss_hits,
+ countpbits(ss[i].ss_ports));
+
+ printf("--------------------------\n");
+ for (mask = 0xfffffffe, j = 32; j; j--, mask <<= 1) {
+ ip.s_addr = ss[0].ss_ip.s_addr & mask;
+ ports = ss[0].ss_ports;
+ for (i = 1; i < num; i++) {
+ sp = ss + i;
+ if (ip.s_addr != (sp->ss_ip.s_addr & mask)) {
+ printf("Netmask: 0x%08x\n", mask);
+ printf("%s %d\n", inet_ntoa(ip),
+ countpbits(ports));
+ ip.s_addr = sp->ss_ip.s_addr & mask;
+ ports = 0;
+ }
+ ports |= sp->ss_ports;
+ }
+ if (ports) {
+ printf("Netmask: 0x%08x\n", mask);
+ printf("%s %d\n", inet_ntoa(ip), countpbits(ports));
+ }
+ }
+}
+
+
+collectips()
+{
+ ipsd_t *ips;
+ ipss_t *ss;
+ int i, num, nip, in, j, k;
+
+ for (i = 0; i < NPORTS; i++)
+ nip += iphits[i]->sd_cnt;
+
+ ss = (ipss_t *)malloc(sizeof(ipss_t) * nip);
+
+ for (in = 0, i = 0, num = 0; i < NPORTS; i++) {
+ ips = iphits[i];
+ for (j = 0; j < ips->sd_cnt; j++) {
+ for (k = 0; k < num; k++)
+ if (!bcmp(&ss[k].ss_ip, &ips->sd_hit[j].sh_ip,
+ sizeof(struct in_addr))) {
+ ss[k].ss_hits += pweights[i];
+ ss[k].ss_ports |= (1 << i);
+ break;
+ }
+ if (k == num) {
+ ss[num].ss_ip = ips->sd_hit[j].sh_ip;
+ ss[num].ss_hits = pweights[i];
+ ss[k].ss_ports |= (1 << i);
+ num++;
+ }
+ }
+ }
+
+ qsort(ss, num, sizeof(*ss), ssipcmp);
+
+ printreport(ss, num);
+}
+
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char c, *name = argv[0], *dir = NULL;
+ int fd;
+
+ setuphits();
+ dir = dir ? dir : ".";
+ readfiles(dir);
+ collectips();
+}
diff --git a/contrib/ipfilter/ipsd/linux.h b/contrib/ipfilter/ipsd/linux.h
new file mode 100644
index 0000000..7eb382b
--- /dev/null
+++ b/contrib/ipfilter/ipsd/linux.h
@@ -0,0 +1,17 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * 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
+ */
+
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
+
+#include "ip_compat.h"
diff --git a/contrib/ipfilter/ipsd/sbpf.c b/contrib/ipfilter/ipsd/sbpf.c
new file mode 100644
index 0000000..d008a5f
--- /dev/null
+++ b/contrib/ipfilter/ipsd/sbpf.c
@@ -0,0 +1,195 @@
+/*
+ * (C)opyright October 1995 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if BSD < 199103
+#include <sys/fcntlcom.h>
+#endif
+#include <sys/dir.h>
+#include <net/bpf.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 <netinet/tcpip.h>
+#include "ip_compat.h"
+
+#ifndef lint
+static char sbpf[] = "@(#)sbpf.c 1.2 12/3/95 (C)1995 Darren Reed";
+#endif
+
+/*
+(000) ldh [12]
+(001) jeq #0x800 jt 2 jf 5
+(002) ldb [23]
+(003) jeq #0x6 jt 4 jf 5
+(004) ret #68
+(005) ret #0
+*/
+struct bpf_insn filter[] = {
+/* 0. */ { BPF_LD|BPF_H|BPF_ABS, 0, 0, 12 },
+/* 1. */ { BPF_JMP|BPF_JEQ, 0, 3, 0x0800 },
+/* 2. */ { BPF_LD|BPF_B|BPF_ABS, 0, 0, 23 },
+/* 3. */ { BPF_JMP|BPF_JEQ, 0, 1, 0x06 },
+/* 4. */ { BPF_RET, 0, 0, 68 },
+/* 5. */ { BPF_RET, 0, 0, 0 }
+};
+/*
+ * the code herein is dervied from libpcap.
+ */
+static u_char *buf = NULL;
+static u_int bufsize = 32768, timeout = 1;
+
+
+int ack_recv(ep)
+char *ep;
+{
+ struct tcpiphdr tip;
+ tcphdr_t *tcp;
+ ip_t *ip;
+
+ ip = (ip_t *)&tip;
+ tcp = (tcphdr_t *)(ip + 1);
+ bcopy(ep + 14, (char *)ip, sizeof(*ip));
+ bcopy(ep + 14 + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp));
+ if (ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP)
+ return -1;
+ if (ip->ip_p & 0x1fff != 0)
+ return 0;
+ if (0 == detect(ip, tcp))
+ return 1;
+ return 0;
+}
+
+
+int readloop(fd, port, dst)
+int fd, port;
+struct in_addr dst;
+{
+ register u_char *bp, *cp, *bufend;
+ register struct bpf_hdr *bh;
+ register int cc;
+ time_t in = time(NULL);
+ int done = 0;
+
+ while ((cc = read(fd, buf, bufsize)) >= 0) {
+ if (!cc && (time(NULL) - in) > timeout)
+ return done;
+ bp = buf;
+ bufend = buf + cc;
+ /*
+ * loop through each snapshot in the chunk
+ */
+ while (bp < bufend) {
+ bh = (struct bpf_hdr *)bp;
+ cp = bp + bh->bh_hdrlen;
+ done += ack_recv(cp);
+ bp += BPF_WORDALIGN(bh->bh_caplen + bh->bh_hdrlen);
+ }
+ return done;
+ }
+ perror("read");
+ exit(-1);
+}
+
+int initdevice(device, tout)
+char *device;
+int tout;
+{
+ struct bpf_program prog;
+ struct bpf_version bv;
+ struct timeval to;
+ struct ifreq ifr;
+ char bpfname[16];
+ int fd, i;
+
+ for (i = 0; i < 16; i++)
+ {
+ (void) sprintf(bpfname, "/dev/bpf%d", i);
+ if ((fd = open(bpfname, O_RDWR)) >= 0)
+ break;
+ }
+ if (i == 16)
+ {
+ fprintf(stderr, "no bpf devices available as /dev/bpfxx\n");
+ return -1;
+ }
+
+ if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0)
+ {
+ perror("BIOCVERSION");
+ return -1;
+ }
+ if (bv.bv_major != BPF_MAJOR_VERSION ||
+ bv.bv_minor < BPF_MINOR_VERSION)
+ {
+ fprintf(stderr, "kernel bpf (v%d.%d) filter out of date:\n",
+ bv.bv_major, bv.bv_minor);
+ fprintf(stderr, "current version: %d.%d\n",
+ BPF_MAJOR_VERSION, BPF_MINOR_VERSION);
+ return -1;
+ }
+
+ (void) strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, &ifr) == -1)
+ {
+ fprintf(stderr, "%s(%d):", ifr.ifr_name, fd);
+ perror("BIOCSETIF");
+ exit(1);
+ }
+ /*
+ * set the timeout
+ */
+ timeout = tout;
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ if (ioctl(fd, BIOCSRTIMEOUT, (caddr_t)&to) == -1)
+ {
+ perror("BIOCSRTIMEOUT");
+ exit(-1);
+ }
+ /*
+ * get kernel buffer size
+ */
+ if (ioctl(fd, BIOCSBLEN, &bufsize) == -1)
+ perror("BIOCSBLEN");
+ if (ioctl(fd, BIOCGBLEN, &bufsize) == -1)
+ {
+ perror("BIOCGBLEN");
+ exit(-1);
+ }
+ printf("BPF buffer size: %d\n", bufsize);
+ buf = (u_char*)malloc(bufsize);
+
+ prog.bf_len = sizeof(filter) / sizeof(struct bpf_insn);
+ prog.bf_insns = filter;
+ if (ioctl(fd, BIOCSETF, (caddr_t)&prog) == -1)
+ {
+ perror("BIOCSETF");
+ exit(-1);
+ }
+ (void) ioctl(fd, BIOCFLUSH, 0);
+ return fd;
+}
diff --git a/contrib/ipfilter/ipsd/sdlpi.c b/contrib/ipfilter/ipsd/sdlpi.c
new file mode 100644
index 0000000..1d0e41d
--- /dev/null
+++ b/contrib/ipfilter/ipsd/sdlpi.c
@@ -0,0 +1,263 @@
+/*
+ * (C)opyright October 1992 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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 <netdb.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/stropts.h>
+
+#include <sys/pfmod.h>
+#include <sys/bufmod.h>
+#include <sys/dlpi.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 <netinet/tcpip.h>
+
+#include "ip_compat.h"
+
+#ifndef lint
+static char snitid[] = "%W% %G% (C)1995 Darren Reed";
+#endif
+
+#define BUFSPACE 32768
+
+static int solfd;
+
+/*
+ * Be careful to only include those defined in the flags option for the
+ * interface are included in the header size.
+ */
+static int timeout;
+
+
+void nullbell()
+{
+ return 0;
+}
+
+
+int ack_recv(ep)
+char *ep;
+{
+ struct tcpiphdr tip;
+ tcphdr_t *tcp;
+ ip_t *ip;
+
+ ip = (ip_t *)&tip;
+ tcp = (tcphdr_t *)(ip + 1);
+ bcopy(ep, (char *)ip, sizeof(*ip));
+ bcopy(ep + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp));
+
+ if (ip->ip_off & 0x1fff != 0)
+ return 0;
+ if (0 == detect(ip, tcp))
+ return 1;
+ return 0;
+}
+
+
+int readloop(fd, port, dst)
+int fd, port;
+struct in_addr dst;
+{
+ static u_char buf[BUFSPACE];
+ register u_char *bp, *cp, *bufend;
+ register struct sb_hdr *hp;
+ register int cc;
+ struct strbuf dbuf;
+ ether_header_t eh;
+ time_t now = time(NULL);
+ int flags = 0, i, done = 0;
+
+ fd = solfd;
+ dbuf.len = 0;
+ dbuf.buf = buf;
+ dbuf.maxlen = sizeof(buf);
+ /*
+ * no control data buffer...
+ */
+ while (1) {
+ (void) signal(SIGALRM, nullbell);
+ alarm(1);
+ i = getmsg(fd, NULL, &dbuf, &flags);
+ alarm(0);
+ (void) signal(SIGALRM, nullbell);
+
+ cc = dbuf.len;
+ if ((time(NULL) - now) > timeout)
+ return done;
+ if (i == -1)
+ if (errno == EINTR)
+ continue;
+ else
+ break;
+ bp = buf;
+ bufend = buf + cc;
+ /*
+ * loop through each snapshot in the chunk
+ */
+ while (bp < bufend) {
+ /*
+ * get past bufmod header
+ */
+ hp = (struct sb_hdr *)bp;
+ cp = (u_char *)((char *)bp + sizeof(*hp));
+ bcopy(cp, (char *)&eh, sizeof(eh));
+ /*
+ * next snapshot
+ */
+ bp += hp->sbh_totlen;
+ cc -= hp->sbh_totlen;
+
+ if (eh.ether_type != ETHERTYPE_IP)
+ continue;
+
+ cp += sizeof(eh);
+ done += ack_recv(cp);
+ }
+ alarm(1);
+ }
+ perror("getmsg");
+ exit(-1);
+}
+
+int initdevice(device, tout)
+char *device;
+int tout;
+{
+ struct strioctl si;
+ struct timeval to;
+ struct ifreq ifr;
+ struct packetfilt pfil;
+ u_long if_flags;
+ u_short *fwp = pfil.Pf_Filter;
+ char devname[16], *s, buf[256];
+ int i, offset, fd, snaplen= 58, chunksize = BUFSPACE;
+
+ (void) sprintf(devname, "/dev/%s", device);
+
+ s = devname + 5;
+ while (*s && !isdigit(*s))
+ s++;
+ if (!*s)
+ {
+ fprintf(stderr, "bad device name %s\n", devname);
+ exit(-1);
+ }
+ i = atoi(s);
+ *s = '\0';
+ /*
+ * For reading
+ */
+ if ((fd = open(devname, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "O_RDWR(0) ");
+ perror(devname);
+ exit(-1);
+ }
+ if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1)
+ {
+ fprintf(stderr, "DLPI error\n");
+ exit(-1);
+ }
+ dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0);
+ dlbindack(fd, buf);
+ /*
+ * read full headers
+ */
+ if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1)
+ {
+ fprintf(stderr, "DLIOCRAW error\n");
+ exit(-1);
+ }
+ /*
+ * Create some filter rules for our TCP watcher. We only want ethernet
+ * pacets which are IP protocol and only the TCP packets from IP.
+ */
+ offset = 6;
+ *fwp++ = ENF_PUSHWORD + offset;
+ *fwp++ = ENF_PUSHLIT | ENF_CAND;
+ *fwp++ = htons(ETHERTYPE_IP);
+ *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
+ *fwp++ = ENF_PUSHLIT | ENF_AND;
+ *fwp++ = htons(0x00ff);
+ *fwp++ = ENF_PUSHLIT | ENF_COR;
+ *fwp++ = htons(IPPROTO_TCP);
+ *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
+ *fwp++ = ENF_PUSHLIT | ENF_AND;
+ *fwp++ = htons(0x00ff);
+ *fwp++ = ENF_PUSHLIT | ENF_CAND;
+ *fwp++ = htons(IPPROTO_UDP);
+ pfil.Pf_FilterLen = (fwp - &pfil.Pf_Filter[0]);
+ /*
+ * put filter in place.
+ */
+
+ if (ioctl(fd, I_PUSH, "pfmod") == -1)
+ {
+ perror("ioctl: I_PUSH pf");
+ exit(1);
+ }
+ if (strioctl(fd, PFIOCSETF, -1, sizeof(pfil), (char *)&pfil) == -1)
+ {
+ perror("ioctl: PFIOCSETF");
+ exit(1);
+ }
+
+ /*
+ * arrange to get messages from the NIT STREAM and use NIT_BUF option
+ */
+ if (ioctl(fd, I_PUSH, "bufmod") == -1)
+ {
+ perror("ioctl: I_PUSH bufmod");
+ exit(1);
+ }
+ i = 128;
+ strioctl(fd, SBIOCSSNAP, -1, sizeof(i), (char *)&i);
+ /*
+ * set the timeout
+ */
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ if (strioctl(fd, SBIOCSTIME, -1, sizeof(to), (char *)&to) == -1)
+ {
+ perror("strioctl(SBIOCSTIME)");
+ exit(-1);
+ }
+ /*
+ * flush read queue
+ */
+ if (ioctl(fd, I_FLUSH, FLUSHR) == -1)
+ {
+ perror("I_FLUSHR");
+ exit(-1);
+ }
+ timeout = tout;
+ solfd = fd;
+ return fd;
+}
diff --git a/contrib/ipfilter/ipsd/slinux.c b/contrib/ipfilter/ipsd/slinux.c
new file mode 100644
index 0000000..1115b86
--- /dev/null
+++ b/contrib/ipfilter/ipsd/slinux.c
@@ -0,0 +1,120 @@
+/*
+ * (C)opyright October 1992 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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 <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/dir.h>
+#include <linux/netdevice.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include "ip_compat.h"
+#include "tcpip.h"
+
+#ifndef lint
+static char sccsid[] = "@(#)slinux.c 1.1 12/3/95 (C) 1995 Darren Reed";
+#endif
+
+#define BUFSPACE 32768
+
+/*
+ * Be careful to only include those defined in the flags option for the
+ * interface are included in the header size.
+ */
+
+static int timeout;
+static char *eth_dev = NULL;
+
+
+int ack_recv(bp)
+char *bp;
+{
+ struct tcpip tip;
+ tcphdr_t *tcp;
+ ip_t *ip;
+
+ ip = (struct ip *)&tip;
+ tcp = (tcphdr_t *)(ip + 1);
+
+ bcopy(bp, (char *)&tip, sizeof(tip));
+ bcopy(bp + (ip.ip_hl << 2), (char *)tcp, sizeof(*tcp));
+ if (0 == detect(ip, tcp))
+ return 1;
+ return 0;
+}
+
+
+void readloop(fd, port, dst)
+int fd, port;
+struct in_addr dst;
+{
+ static u_char buf[BUFSPACE];
+ struct sockaddr dest;
+ register u_char *bp = buf;
+ register int cc;
+ int dlen, done = 0;
+ time_t now = time(NULL);
+
+ do {
+ fflush(stdout);
+ dlen = sizeof(dest);
+ bzero((char *)&dest, dlen);
+ cc = recvfrom(fd, buf, BUFSPACE, 0, &dest, &dlen);
+ if (!cc)
+ if ((time(NULL) - now) > timeout)
+ return done;
+ else
+ continue;
+
+ if (bp[12] != 0x8 || bp[13] != 0)
+ continue; /* not ip */
+
+ /*
+ * get rid of non-tcp or fragmented packets here.
+ */
+ if (cc >= sizeof(struct tcpiphdr))
+ {
+ if (((bp[14+9] != IPPROTO_TCP) &&
+ (bp[14+9] != IPPROTO_UDP)) ||
+ (bp[14+6] & 0x1f) || (bp[14+6] & 0xff))
+ continue;
+ done += ack_recv(bp + 14);
+ }
+ } while (cc >= 0);
+ perror("read");
+ exit(-1);
+}
+
+int initdevice(dev, tout)
+char *dev;
+int tout;
+{
+ int fd;
+
+ eth_dev = strdup(dev);
+ if ((fd = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_IP))) == -1)
+ {
+ perror("socket(SOCK_PACKET)");
+ exit(-1);
+ }
+
+ return fd;
+}
diff --git a/contrib/ipfilter/ipsd/snit.c b/contrib/ipfilter/ipsd/snit.c
new file mode 100644
index 0000000..4b5fd03
--- /dev/null
+++ b/contrib/ipfilter/ipsd/snit.c
@@ -0,0 +1,230 @@
+/*
+ * (C)opyright October 1992 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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 <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <net/nit.h>
+#include <sys/fcntlcom.h>
+#include <sys/dir.h>
+#include <net/nit_if.h>
+#include <net/nit_pf.h>
+#include <net/nit_buf.h>
+#include <net/packetfilt.h>
+#include <sys/stropts.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 <netinet/tcpip.h>
+
+#ifndef lint
+static char snitid[] = "@(#)snit.c 1.2 12/3/95 (C)1995 Darren Reed";
+#endif
+
+#define BUFSPACE 32768
+
+/*
+ * Be careful to only include those defined in the flags option for the
+ * interface are included in the header size.
+ */
+#define BUFHDR_SIZE (sizeof(struct nit_bufhdr))
+#define NIT_HDRSIZE (BUFHDR_SIZE)
+
+static int timeout;
+
+
+int ack_recv(ep)
+char *ep;
+{
+ struct tcpiphdr tip;
+ struct tcphdr *tcp;
+ struct ip *ip;
+
+ ip = (struct ip *)&tip;
+ tcp = (struct tcphdr *)(ip + 1);
+ bcopy(ep + 14, (char *)ip, sizeof(*ip));
+ bcopy(ep + 14 + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp));
+ if (ip->ip_off & 0x1fff != 0)
+ return 0;
+ if (0 == detect(ip, tcp))
+ return 1;
+ return 0;
+}
+
+
+int readloop(fd, dst)
+int fd;
+struct in_addr dst;
+{
+ static u_char buf[BUFSPACE];
+ register u_char *bp, *cp, *bufend;
+ register struct nit_bufhdr *hp;
+ register int cc;
+ time_t now = time(NULL);
+ int done = 0;
+
+ while ((cc = read(fd, buf, BUFSPACE-1)) >= 0) {
+ if (!cc)
+ if ((time(NULL) - now) > timeout)
+ return done;
+ else
+ continue;
+ bp = buf;
+ bufend = buf + cc;
+ /*
+ * loop through each snapshot in the chunk
+ */
+ while (bp < bufend) {
+ cp = (u_char *)((char *)bp + NIT_HDRSIZE);
+ /*
+ * get past NIT buffer
+ */
+ hp = (struct nit_bufhdr *)bp;
+ /*
+ * next snapshot
+ */
+ bp += hp->nhb_totlen;
+ done += ack_recv(cp);
+ }
+ return done;
+ }
+ perror("read");
+ exit(-1);
+}
+
+int initdevice(device, tout)
+char *device;
+int tout;
+{
+ struct strioctl si;
+ struct timeval to;
+ struct ifreq ifr;
+ struct packetfilt pfil;
+ u_long if_flags;
+ u_short *fwp = pfil.Pf_Filter;
+ int ret, offset, fd, snaplen= 76, chunksize = BUFSPACE;
+
+ if ((fd = open("/dev/nit", O_RDWR)) < 0)
+ {
+ perror("/dev/nit");
+ exit(-1);
+ }
+
+ /*
+ * Create some filter rules for our TCP watcher. We only want ethernet
+ * pacets which are IP protocol and only the TCP packets from IP.
+ */
+ offset = 6;
+ *fwp++ = ENF_PUSHWORD + offset;
+ *fwp++ = ENF_PUSHLIT | ENF_CAND;
+ *fwp++ = htons(ETHERTYPE_IP);
+ *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
+ *fwp++ = ENF_PUSHLIT | ENF_AND;
+ *fwp++ = htons(0x00ff);
+ *fwp++ = ENF_PUSHLIT | ENF_COR;
+ *fwp++ = htons(IPPROTO_TCP);
+ *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4;
+ *fwp++ = ENF_PUSHLIT | ENF_AND;
+ *fwp++ = htons(0x00ff);
+ *fwp++ = ENF_PUSHLIT | ENF_CAND;
+ *fwp++ = htons(IPPROTO_UDP);
+ pfil.Pf_FilterLen = fwp - &pfil.Pf_Filter[0];
+ /*
+ * put filter in place.
+ */
+ if (ioctl(fd, I_PUSH, "pf") == -1)
+ {
+ perror("ioctl: I_PUSH pf");
+ exit(1);
+ }
+ if (ioctl(fd, NIOCSETF, &pfil) == -1)
+ {
+ perror("ioctl: NIOCSETF");
+ exit(1);
+ }
+ /*
+ * arrange to get messages from the NIT STREAM and use NIT_BUF option
+ */
+ ioctl(fd, I_SRDOPT, (char*)RMSGD);
+ ioctl(fd, I_PUSH, "nbuf");
+ /*
+ * set the timeout
+ */
+ timeout = tout;
+ si.ic_timout = 1;
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ si.ic_cmd = NIOCSTIME;
+ si.ic_len = sizeof(to);
+ si.ic_dp = (char*)&to;
+ if (ioctl(fd, I_STR, (char*)&si) == -1)
+ {
+ perror("ioctl: NIT timeout");
+ exit(-1);
+ }
+ /*
+ * set the chunksize
+ */
+ si.ic_cmd = NIOCSCHUNK;
+ si.ic_len = sizeof(chunksize);
+ si.ic_dp = (char*)&chunksize;
+ if (ioctl(fd, I_STR, (char*)&si) == -1)
+ perror("ioctl: NIT chunksize");
+ if (ioctl(fd, NIOCGCHUNK, (char*)&chunksize) == -1)
+ {
+ perror("ioctl: NIT chunksize");
+ exit(-1);
+ }
+ printf("NIT buffer size: %d\n", chunksize);
+
+ /*
+ * request the interface
+ */
+ strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = ' ';
+ si.ic_cmd = NIOCBIND;
+ si.ic_len = sizeof(ifr);
+ si.ic_dp = (char*)&ifr;
+ if (ioctl(fd, I_STR, (char*)&si) == -1)
+ {
+ perror(ifr.ifr_name);
+ exit(1);
+ }
+
+ /*
+ * set the snapshot length
+ */
+ si.ic_cmd = NIOCSSNAP;
+ si.ic_len = sizeof(snaplen);
+ si.ic_dp = (char*)&snaplen;
+ if (ioctl(fd, I_STR, (char*)&si) == -1)
+ {
+ perror("ioctl: NIT snaplen");
+ exit(1);
+ }
+ (void) ioctl(fd, I_FLUSH, (char*)FLUSHR);
+ return fd;
+}
diff --git a/contrib/ipfilter/ipsend/44arp.c b/contrib/ipfilter/ipsend/44arp.c
new file mode 100644
index 0000000..621d84c
--- /dev/null
+++ b/contrib/ipfilter/ipsend/44arp.c
@@ -0,0 +1,95 @@
+/*
+ * Based upon 4.4BSD's /usr/sbin/arp
+ */
+#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>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <nlist.h>
+#include <stdio.h>
+
+/*
+ * lookup host and return
+ * its IP address in address
+ * (4 bytes)
+ */
+int resolve(host, address)
+char *host, *address;
+{
+ struct hostent *hp;
+ u_long add;
+
+ add = inet_addr(host);
+ if (add == -1)
+ {
+ if (!(hp = gethostbyname(host)))
+ {
+ fprintf(stderr, "unknown host: %s\n", host);
+ return -1;
+ }
+ bcopy((char *)hp->h_addr, (char *)address, 4);
+ return 0;
+ }
+ bcopy((char*)&add, address, 4);
+ return 0;
+}
+
+
+int arp(addr, eaddr)
+char *addr, *eaddr;
+{
+ int mib[6];
+ size_t needed;
+ char *malloc(), *lim, *buf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_inarp *sin;
+ struct sockaddr_dl *sdl;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
+ {
+ perror("route-sysctl-estimate");
+ exit(-1);
+ }
+ if ((buf = malloc(needed)) == NULL)
+ {
+ perror("malloc");
+ exit(-1);
+ }
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
+ {
+ perror("actual retrieval of routing table");
+ exit(-1);
+ }
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen)
+ {
+ 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)))
+ {
+ bcopy(LLADDR(sdl), eaddr, sdl->sdl_alen);
+ return 0;
+ }
+ }
+ return -1;
+}
diff --git a/contrib/ipfilter/ipsend/Crashable b/contrib/ipfilter/ipsend/Crashable
new file mode 100644
index 0000000..dbe1b87
--- /dev/null
+++ b/contrib/ipfilter/ipsend/Crashable
@@ -0,0 +1,20 @@
+Test 1:
+ Solaris 2.4 - upto and including 101945-34, > 34 ?
+ Solaris 2.5 - 11/95
+ Linux 1.2.13, < 1.3.45(?)
+ 3com/sonix bridge
+ Instant Internet
+ KA9Q NOS
+ Netblazer 40i, Version 3.2 OS
+ Irix 6.x
+ HP-UX 9.0
+ HP-UX 10.1
+ LivingstonsComOS
+
+Test 6:
+ SunOS 4.1.x
+ ULtrix 4.3
+
+Test 7:
+ SunOS 4.1.x
+ Linux <= 1.3.84
diff --git a/contrib/ipfilter/ipsend/Makefile b/contrib/ipfilter/ipsend/Makefile
new file mode 100644
index 0000000..1f04912
--- /dev/null
+++ b/contrib/ipfilter/ipsend/Makefile
@@ -0,0 +1,91 @@
+#
+# (C)opyright 1993-1996 by Darren Reed.
+#
+# 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 ?
+#
+OBJS=ipsend.o ip.o ipsopt.o
+ROBJS=ipresend.o ip.o resend.o
+TOBJS=iptest.o iptests.o ip.o
+BPF=sbpf.o
+NIT=snit.o
+SUNOS4=sock.o arp.o
+BSD=sock.o 44arp.o
+LINUX=lsock.o slinux.o larp.o
+LINUXK=
+TOP=..
+SUNOS5=dlcommon.o sdlpi.o arp.o
+
+CC=gcc
+CFLAGS=-g -I.. -DNO_IPF
+
+all:
+ @echo "Use one of these targets:"
+ @echo " sunos4-nit (standard SunOS 4.1.x)"
+ @echo " sunos4-bpf (SunOS4.1.x with BPF in the kernel)"
+ @echo " bsd-bpf (4.4BSD variant with BPF in the kernel)"
+ @echo " linux10 (Linux 1.0 kernels)"
+ @echo " linux20 (Linux 2.0 kernels)"
+ @echo " sunos5 (Solaris 2.x)"
+
+.c.o:
+ $(CC) $(CFLAGS) $(LINUXK) -c $< -o $@
+
+bpf sunos4-bpf :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+
+nit sunos4 sunos4-nit :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+
+dlpi sunos5 :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -Dsolaris" "LIBS=-lsocket -lnsl"
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -Dsolaris" "LIBS=-lsocket -lnsl"
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -Dsolaris" "LIBS=-lsocket -lnsl"
+
+bsd-bpf :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET"
+
+linuxrev :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -I/usr/src/linux/include -DDOSOCKET" $(LINUXK)
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -I/usr/src/linux/include -DDOSOCKET" $(LINUXK)
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -I/usr/src/linux/include -DDOSOCKET" $(LINUXK)
+
+linux10:
+ make linuxrev 'LINUXK="LINUXK=-DLINUX=0100"'
+
+linux20:
+ make linuxrev 'LINUXK="LINUXK=-DLINUX=0200"'
+
+ipsend: $(OBJS) $(UNIXOBJS)
+ $(CC) $(OBJS) $(UNIXOBJS) -o $@ $(LIBS)
+
+ipresend: $(ROBJS) $(UNIXOBJS)
+ $(CC) $(ROBJS) $(UNIXOBJS) -o $@ $(LIBS)
+
+iptest: $(TOBJS) $(UNIXOBJS)
+ $(CC) $(TOBJS) $(UNIXOBJS) -o $@ $(LIBS)
+
+clean:
+ rm -rf *.o *core a.out ipsend ipresend iptest
diff --git a/contrib/ipfilter/ipsend/arp.c b/contrib/ipfilter/ipsend/arp.c
new file mode 100644
index 0000000..47f6fce
--- /dev/null
+++ b/contrib/ipfilter/ipsend/arp.c
@@ -0,0 +1,119 @@
+/*
+ * arp.c (C) 1995 Darren Reed
+ *
+ * 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.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)arp.c 1.4 1/11/96 (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+
+#if defined(__SVR4) || defined(__svr4__)
+#define bcopy(a,b,c) memmove(b,a,c)
+#define bzero(a,c) memset(a,0,c)
+#define bcmp(a,b,c) memcmp(a,b,c)
+#endif
+
+/*
+ * lookup host and return
+ * its IP address in address
+ * (4 bytes)
+ */
+int resolve(host, address)
+char *host, *address;
+{
+ struct hostent *hp;
+ u_long add;
+
+ add = inet_addr(host);
+ if (add == -1)
+ {
+ if (!(hp = gethostbyname(host)))
+ {
+ fprintf(stderr, "unknown host: %s\n", host);
+ return -1;
+ }
+ bcopy((char *)hp->h_addr, (char *)address, 4);
+ return 0;
+ }
+ bcopy((char*)&add, address, 4);
+ return 0;
+}
+
+/*
+ * ARP for the MAC address corresponding
+ * to the IP address. This taken from
+ * some BSD program, I cant remember which.
+ */
+int arp(ip, ether)
+char *ip;
+char *ether;
+{
+ static int sfd = -1;
+ static char ethersave[6], ipsave[4];
+ struct arpreq ar;
+ struct sockaddr_in *sin, san;
+ struct hostent *hp;
+ char *inet_ntoa();
+ int fd;
+
+ if (!bcmp(ipsave, ip, 4)) {
+ bcopy(ethersave, ether, 6);
+ return 0;
+ }
+ fd = -1;
+ bzero((char *)&ar, sizeof(ar));
+ sin = (struct sockaddr_in *)&ar.arp_pa;
+ sin->sin_family = AF_INET;
+ bcopy(ip, (char *)&sin->sin_addr.s_addr, 4);
+ if ((hp = gethostbyaddr(ip, 4, AF_INET)))
+ if (!(ether_hostton(hp->h_name, ether)))
+ goto savearp;
+
+ if (sfd == -1)
+ if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ {
+ perror("arp: socket");
+ return -1;
+ }
+tryagain:
+ if (ioctl(sfd, SIOCGARP, (caddr_t)&ar) == -1)
+ {
+ if (fd == -1)
+ {
+ bzero((char *)&san, sizeof(san));
+ san.sin_family = AF_INET;
+ san.sin_port = htons(1);
+ bcopy(ip, &san.sin_addr.s_addr, 4);
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ (void) sendto(fd, ip, 4, 0,
+ (struct sockaddr *)&san, sizeof(san));
+ sleep(1);
+ (void) close(fd);
+ goto tryagain;
+ }
+ fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr));
+ if (errno != ENXIO)
+ perror("SIOCGARP");
+ return -1;
+ }
+
+ bcopy(ar.arp_ha.sa_data, ether, 6);
+savearp:
+ bcopy(ether, ethersave, 6);
+ bcopy(ip, ipsave, 4);
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/dlcommon.c b/contrib/ipfilter/ipsend/dlcommon.c
new file mode 100644
index 0000000..59b283d
--- /dev/null
+++ b/contrib/ipfilter/ipsend/dlcommon.c
@@ -0,0 +1,1359 @@
+/*
+ * Common (shared) DLPI test routines.
+ * Mostly pretty boring boilerplate sorta stuff.
+ * These can be split into individual library routines later
+ * but it's just convenient to keep them in a single file
+ * while they're being developed.
+ *
+ * Not supported:
+ * Connection Oriented stuff
+ * QOS stuff
+ */
+
+/*
+typedef unsigned long ulong;
+*/
+
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/dlpi.h>
+#include <sys/signal.h>
+#include <stdio.h>
+#include <string.h>
+#include "dltest.h"
+
+#define CASERET(s) case s: return ("s")
+
+char *dlprim();
+char *dlstate();
+char *dlerrno();
+char *dlpromisclevel();
+char *dlservicemode();
+char *dlstyle();
+char *dlmactype();
+
+
+dlinforeq(fd)
+int fd;
+{
+ dl_info_req_t info_req;
+ struct strbuf ctl;
+ int flags;
+
+ info_req.dl_primitive = DL_INFO_REQ;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (info_req);
+ ctl.buf = (char *) &info_req;
+
+ flags = RS_HIPRI;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlinforeq: putmsg");
+}
+
+dlinfoack(fd, bufp)
+int fd;
+char *bufp;
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_INFO_ACK, dlp);
+
+ if (ctl.len < sizeof (dl_info_ack_t))
+ err("dlinfoack: response ctl.len too short: %d", ctl.len);
+
+ if (flags != RS_HIPRI)
+ err("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_info_ack_t))
+ err("dlinfoack: short response ctl.len: %d", ctl.len);
+}
+
+dlattachreq(fd, ppa)
+int fd;
+u_long ppa;
+{
+ dl_attach_req_t attach_req;
+ struct strbuf ctl;
+ int flags;
+
+ attach_req.dl_primitive = DL_ATTACH_REQ;
+ attach_req.dl_ppa = ppa;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (attach_req);
+ ctl.buf = (char *) &attach_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlattachreq: putmsg");
+}
+
+dlenabmultireq(fd, addr, length)
+int fd;
+char *addr;
+int length;
+{
+ long buf[MAXDLBUF];
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ dlp = (union DL_primitives*) buf;
+
+ dlp->enabmulti_req.dl_primitive = DL_ENABMULTI_REQ;
+ dlp->enabmulti_req.dl_addr_length = length;
+ dlp->enabmulti_req.dl_addr_offset = sizeof (dl_enabmulti_req_t);
+
+ (void) memcpy((char*)OFFADDR(buf, sizeof (dl_enabmulti_req_t)), addr, length);
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (dl_enabmulti_req_t) + length;
+ ctl.buf = (char*) buf;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlenabmultireq: putmsg");
+}
+
+dldisabmultireq(fd, addr, length)
+int fd;
+char *addr;
+int length;
+{
+ long buf[MAXDLBUF];
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ dlp = (union DL_primitives*) buf;
+
+ dlp->disabmulti_req.dl_primitive = DL_ENABMULTI_REQ;
+ dlp->disabmulti_req.dl_addr_length = length;
+ dlp->disabmulti_req.dl_addr_offset = sizeof (dl_disabmulti_req_t);
+
+ (void) memcpy((char*)OFFADDR(buf, sizeof (dl_disabmulti_req_t)), addr, length);
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (dl_disabmulti_req_t) + length;
+ ctl.buf = (char*) buf;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dldisabmultireq: putmsg");
+}
+
+dlpromisconreq(fd, level)
+int fd;
+u_long level;
+{
+ dl_promiscon_req_t promiscon_req;
+ struct strbuf ctl;
+ int flags;
+
+ promiscon_req.dl_primitive = DL_PROMISCON_REQ;
+ promiscon_req.dl_level = level;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (promiscon_req);
+ ctl.buf = (char *) &promiscon_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlpromiscon: putmsg");
+
+}
+
+dlpromiscoff(fd, level)
+int fd;
+u_long level;
+{
+ dl_promiscoff_req_t promiscoff_req;
+ struct strbuf ctl;
+ int flags;
+
+ promiscoff_req.dl_primitive = DL_PROMISCOFF_REQ;
+ promiscoff_req.dl_level = level;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (promiscoff_req);
+ ctl.buf = (char *) &promiscoff_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlpromiscoff: putmsg");
+}
+
+dlphysaddrreq(fd, addrtype)
+int fd;
+u_long addrtype;
+{
+ dl_phys_addr_req_t phys_addr_req;
+ struct strbuf ctl;
+ int flags;
+
+ phys_addr_req.dl_primitive = DL_PHYS_ADDR_REQ;
+ phys_addr_req.dl_addr_type = addrtype;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (phys_addr_req);
+ ctl.buf = (char *) &phys_addr_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlphysaddrreq: putmsg");
+}
+
+dlsetphysaddrreq(fd, addr, length)
+int fd;
+char *addr;
+int length;
+{
+ long buf[MAXDLBUF];
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ dlp = (union DL_primitives*) buf;
+
+ dlp->set_physaddr_req.dl_primitive = DL_ENABMULTI_REQ;
+ dlp->set_physaddr_req.dl_addr_length = length;
+ dlp->set_physaddr_req.dl_addr_offset = sizeof (dl_set_phys_addr_req_t);
+
+ (void) memcpy((char*)OFFADDR(buf, sizeof (dl_set_phys_addr_req_t)), addr, length);
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (dl_set_phys_addr_req_t) + length;
+ ctl.buf = (char*) buf;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlsetphysaddrreq: putmsg");
+}
+
+dldetachreq(fd)
+int fd;
+{
+ dl_detach_req_t detach_req;
+ struct strbuf ctl;
+ int flags;
+
+ detach_req.dl_primitive = DL_DETACH_REQ;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (detach_req);
+ ctl.buf = (char *) &detach_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dldetachreq: putmsg");
+}
+
+dlbindreq(fd, sap, max_conind, service_mode, conn_mgmt, xidtest)
+int fd;
+u_long sap;
+u_long max_conind;
+u_long service_mode;
+u_long conn_mgmt;
+u_long xidtest;
+{
+ dl_bind_req_t bind_req;
+ struct strbuf ctl;
+ int flags;
+
+ bind_req.dl_primitive = DL_BIND_REQ;
+ bind_req.dl_sap = sap;
+ bind_req.dl_max_conind = max_conind;
+ bind_req.dl_service_mode = service_mode;
+ bind_req.dl_conn_mgmt = conn_mgmt;
+ bind_req.dl_xidtest_flg = xidtest;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (bind_req);
+ ctl.buf = (char *) &bind_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlbindreq: putmsg");
+}
+
+dlunitdatareq(fd, addrp, addrlen, minpri, maxpri, datap, datalen)
+int fd;
+u_char *addrp;
+int addrlen;
+u_long minpri, maxpri;
+u_char *datap;
+int datalen;
+{
+ long buf[MAXDLBUF];
+ union DL_primitives *dlp;
+ struct strbuf data, ctl;
+
+ dlp = (union DL_primitives*) buf;
+
+ dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
+ dlp->unitdata_req.dl_dest_addr_length = addrlen;
+ dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
+ dlp->unitdata_req.dl_priority.dl_min = minpri;
+ dlp->unitdata_req.dl_priority.dl_max = maxpri;
+
+ (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
+ ctl.buf = (char *) buf;
+
+ data.maxlen = 0;
+ data.len = datalen;
+ data.buf = (char *) datap;
+
+ if (putmsg(fd, &ctl, &data, 0) < 0)
+ syserr("dlunitdatareq: putmsg");
+}
+
+dlunbindreq(fd)
+int fd;
+{
+ dl_unbind_req_t unbind_req;
+ struct strbuf ctl;
+ int flags;
+
+ unbind_req.dl_primitive = DL_UNBIND_REQ;
+
+ ctl.maxlen = 0;
+ ctl.len = sizeof (unbind_req);
+ ctl.buf = (char *) &unbind_req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+ syserr("dlunbindreq: putmsg");
+}
+
+dlokack(fd, bufp)
+int fd;
+char *bufp;
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_OK_ACK, dlp);
+
+ if (ctl.len < sizeof (dl_ok_ack_t))
+ err("dlokack: response ctl.len too short: %d", ctl.len);
+
+ if (flags != RS_HIPRI)
+ err("dlokack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_ok_ack_t))
+ err("dlokack: short response ctl.len: %d", ctl.len);
+}
+
+dlerrorack(fd, bufp)
+int fd;
+char *bufp;
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlerrorack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_ERROR_ACK, dlp);
+
+ if (ctl.len < sizeof (dl_error_ack_t))
+ err("dlerrorack: response ctl.len too short: %d", ctl.len);
+
+ if (flags != RS_HIPRI)
+ err("dlerrorack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_error_ack_t))
+ err("dlerrorack: short response ctl.len: %d", ctl.len);
+}
+
+dlbindack(fd, bufp)
+int fd;
+char *bufp;
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_BIND_ACK, dlp);
+
+ if (flags != RS_HIPRI)
+ err("dlbindack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_bind_ack_t))
+ err("dlbindack: short response ctl.len: %d", ctl.len);
+}
+
+dlphysaddrack(fd, bufp)
+int fd;
+char *bufp;
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags;
+
+ ctl.maxlen = MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = bufp;
+
+ strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlphysaddrack");
+
+ dlp = (union DL_primitives *) ctl.buf;
+
+ expecting(DL_PHYS_ADDR_ACK, dlp);
+
+ if (flags != RS_HIPRI)
+ err("dlbindack: DL_OK_ACK was not M_PCPROTO");
+
+ if (ctl.len < sizeof (dl_phys_addr_ack_t))
+ err("dlphysaddrack: short response ctl.len: %d", ctl.len);
+}
+
+void
+sigalrm()
+{
+ (void) err("sigalrm: TIMEOUT");
+}
+
+strgetmsg(fd, ctlp, datap, flagsp, caller)
+int fd;
+struct strbuf *ctlp, *datap;
+int *flagsp;
+char *caller;
+{
+ int rc;
+ static char errmsg[80];
+
+ /*
+ * Start timer.
+ */
+ (void) signal(SIGALRM, sigalrm);
+ if (alarm(MAXWAIT) < 0) {
+ (void) sprintf(errmsg, "%s: alarm", caller);
+ syserr(errmsg);
+ }
+
+ /*
+ * Set flags argument and issue getmsg().
+ */
+ *flagsp = 0;
+ if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
+ (void) sprintf(errmsg, "%s: getmsg", caller);
+ syserr(errmsg);
+ }
+
+ /*
+ * Stop timer.
+ */
+ if (alarm(0) < 0) {
+ (void) sprintf(errmsg, "%s: alarm", caller);
+ syserr(errmsg);
+ }
+
+ /*
+ * Check for MOREDATA and/or MORECTL.
+ */
+ if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA))
+ err("%s: MORECTL|MOREDATA", caller);
+ if (rc & MORECTL)
+ err("%s: MORECTL", caller);
+ if (rc & MOREDATA)
+ err("%s: MOREDATA", caller);
+
+ /*
+ * Check for at least sizeof (long) control data portion.
+ */
+ if (ctlp->len < sizeof (long))
+ err("getmsg: control portion length < sizeof (long): %d", ctlp->len);
+}
+
+expecting(prim, dlp)
+int prim;
+union DL_primitives *dlp;
+{
+ if (dlp->dl_primitive != (u_long)prim) {
+ printdlprim(dlp);
+ err("expected %s got %s", dlprim(prim),
+ dlprim(dlp->dl_primitive));
+ exit(1);
+ }
+}
+
+/*
+ * Print any DLPI msg in human readable format.
+ */
+printdlprim(dlp)
+union DL_primitives *dlp;
+{
+ switch (dlp->dl_primitive) {
+ case DL_INFO_REQ:
+ printdlinforeq(dlp);
+ break;
+
+ case DL_INFO_ACK:
+ printdlinfoack(dlp);
+ break;
+
+ case DL_ATTACH_REQ:
+ printdlattachreq(dlp);
+ break;
+
+ case DL_OK_ACK:
+ printdlokack(dlp);
+ break;
+
+ case DL_ERROR_ACK:
+ printdlerrorack(dlp);
+ break;
+
+ case DL_DETACH_REQ:
+ printdldetachreq(dlp);
+ break;
+
+ case DL_BIND_REQ:
+ printdlbindreq(dlp);
+ break;
+
+ case DL_BIND_ACK:
+ printdlbindack(dlp);
+ break;
+
+ case DL_UNBIND_REQ:
+ printdlunbindreq(dlp);
+ break;
+
+ case DL_SUBS_BIND_REQ:
+ printdlsubsbindreq(dlp);
+ break;
+
+ case DL_SUBS_BIND_ACK:
+ printdlsubsbindack(dlp);
+ break;
+
+ case DL_SUBS_UNBIND_REQ:
+ printdlsubsunbindreq(dlp);
+ break;
+
+ case DL_ENABMULTI_REQ:
+ printdlenabmultireq(dlp);
+ break;
+
+ case DL_DISABMULTI_REQ:
+ printdldisabmultireq(dlp);
+ break;
+
+ case DL_PROMISCON_REQ:
+ printdlpromisconreq(dlp);
+ break;
+
+ case DL_PROMISCOFF_REQ:
+ printdlpromiscoffreq(dlp);
+ break;
+
+ case DL_UNITDATA_REQ:
+ printdlunitdatareq(dlp);
+ break;
+
+ case DL_UNITDATA_IND:
+ printdlunitdataind(dlp);
+ break;
+
+ case DL_UDERROR_IND:
+ printdluderrorind(dlp);
+ break;
+
+ case DL_UDQOS_REQ:
+ printdludqosreq(dlp);
+ break;
+
+ case DL_PHYS_ADDR_REQ:
+ printdlphysaddrreq(dlp);
+ break;
+
+ case DL_PHYS_ADDR_ACK:
+ printdlphysaddrack(dlp);
+ break;
+
+ case DL_SET_PHYS_ADDR_REQ:
+ printdlsetphysaddrreq(dlp);
+ break;
+
+ default:
+ err("printdlprim: unknown primitive type 0x%x",
+ dlp->dl_primitive);
+ break;
+ }
+}
+
+/* ARGSUSED */
+printdlinforeq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_INFO_REQ\n");
+}
+
+printdlinfoack(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+ u_char brdcst[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->info_ack.dl_addr_offset),
+ dlp->info_ack.dl_addr_length, addr);
+ addrtostring(OFFADDR(dlp, dlp->info_ack.dl_brdcst_addr_offset),
+ dlp->info_ack.dl_brdcst_addr_length, brdcst);
+
+ (void) printf("DL_INFO_ACK: max_sdu %d min_sdu %d\n",
+ dlp->info_ack.dl_max_sdu,
+ dlp->info_ack.dl_min_sdu);
+ (void) printf("addr_length %d mac_type %s current_state %s\n",
+ dlp->info_ack.dl_addr_length,
+ dlmactype(dlp->info_ack.dl_mac_type),
+ dlstate(dlp->info_ack.dl_current_state));
+ (void) printf("sap_length %d service_mode %s qos_length %d\n",
+ dlp->info_ack.dl_sap_length,
+ dlservicemode(dlp->info_ack.dl_service_mode),
+ dlp->info_ack.dl_qos_length);
+ (void) printf("qos_offset %d qos_range_length %d qos_range_offset %d\n",
+ dlp->info_ack.dl_qos_offset,
+ dlp->info_ack.dl_qos_range_length,
+ dlp->info_ack.dl_qos_range_offset);
+ (void) printf("provider_style %s addr_offset %d version %d\n",
+ dlstyle(dlp->info_ack.dl_provider_style),
+ dlp->info_ack.dl_addr_offset,
+ dlp->info_ack.dl_version);
+ (void) printf("brdcst_addr_length %d brdcst_addr_offset %d\n",
+ dlp->info_ack.dl_brdcst_addr_length,
+ dlp->info_ack.dl_brdcst_addr_offset);
+ (void) printf("addr %s\n", addr);
+ (void) printf("brdcst_addr %s\n", brdcst);
+}
+
+printdlattachreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_ATTACH_REQ: ppa %d\n",
+ dlp->attach_req.dl_ppa);
+}
+
+printdlokack(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_OK_ACK: correct_primitive %s\n",
+ dlprim(dlp->ok_ack.dl_correct_primitive));
+}
+
+printdlerrorack(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_ERROR_ACK: error_primitive %s errno %s unix_errno %d\n",
+ dlprim(dlp->error_ack.dl_error_primitive),
+ dlerrno(dlp->error_ack.dl_errno),
+ dlp->error_ack.dl_unix_errno);
+}
+
+printdlenabmultireq(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->enabmulti_req.dl_addr_offset),
+ dlp->enabmulti_req.dl_addr_length, addr);
+
+ (void) printf("DL_ENABMULTI_REQ: addr_length %d addr_offset %d\n",
+ dlp->enabmulti_req.dl_addr_length,
+ dlp->enabmulti_req.dl_addr_offset);
+ (void) printf("addr %s\n", addr);
+}
+
+printdldisabmultireq(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->disabmulti_req.dl_addr_offset),
+ dlp->disabmulti_req.dl_addr_length, addr);
+
+ (void) printf("DL_DISABMULTI_REQ: addr_length %d addr_offset %d\n",
+ dlp->disabmulti_req.dl_addr_length,
+ dlp->disabmulti_req.dl_addr_offset);
+ (void) printf("addr %s\n", addr);
+}
+
+printdlpromisconreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_PROMISCON_REQ: level %s\n",
+ dlpromisclevel(dlp->promiscon_req.dl_level));
+}
+
+printdlpromiscoffreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_PROMISCOFF_REQ: level %s\n",
+ dlpromisclevel(dlp->promiscoff_req.dl_level));
+}
+
+printdlphysaddrreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_PHYS_ADDR_REQ: addr_type 0x%x\n",
+ dlp->physaddr_req.dl_addr_type);
+}
+
+printdlphysaddrack(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->physaddr_ack.dl_addr_offset),
+ dlp->physaddr_ack.dl_addr_length, addr);
+
+ (void) printf("DL_PHYS_ADDR_ACK: addr_length %d addr_offset %d\n",
+ dlp->physaddr_ack.dl_addr_length,
+ dlp->physaddr_ack.dl_addr_offset);
+ (void) printf("addr %s\n", addr);
+}
+
+printdlsetphysaddrreq(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->set_physaddr_req.dl_addr_offset),
+ dlp->set_physaddr_req.dl_addr_length, addr);
+
+ (void) printf("DL_SET_PHYS_ADDR_REQ: addr_length %d addr_offset %d\n",
+ dlp->set_physaddr_req.dl_addr_length,
+ dlp->set_physaddr_req.dl_addr_offset);
+ (void) printf("addr %s\n", addr);
+}
+
+/* ARGSUSED */
+printdldetachreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_DETACH_REQ\n");
+}
+
+printdlbindreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_BIND_REQ: sap %d max_conind %d\n",
+ dlp->bind_req.dl_sap,
+ dlp->bind_req.dl_max_conind);
+ (void) printf("service_mode %s conn_mgmt %d xidtest_flg 0x%x\n",
+ dlservicemode(dlp->bind_req.dl_service_mode),
+ dlp->bind_req.dl_conn_mgmt,
+ dlp->bind_req.dl_xidtest_flg);
+}
+
+printdlbindack(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->bind_ack.dl_addr_offset),
+ dlp->bind_ack.dl_addr_length, addr);
+
+ (void) printf("DL_BIND_ACK: sap %d addr_length %d addr_offset %d\n",
+ dlp->bind_ack.dl_sap,
+ dlp->bind_ack.dl_addr_length,
+ dlp->bind_ack.dl_addr_offset);
+ (void) printf("max_conind %d xidtest_flg 0x%x\n",
+ dlp->bind_ack.dl_max_conind,
+ dlp->bind_ack.dl_xidtest_flg);
+ (void) printf("addr %s\n", addr);
+}
+
+/* ARGSUSED */
+printdlunbindreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_UNBIND_REQ\n");
+}
+
+printdlsubsbindreq(dlp)
+union DL_primitives *dlp;
+{
+ u_char sap[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->subs_bind_req.dl_subs_sap_offset),
+ dlp->subs_bind_req.dl_subs_sap_length, sap);
+
+ (void) printf("DL_SUBS_BIND_REQ: subs_sap_offset %d sub_sap_len %d\n",
+ dlp->subs_bind_req.dl_subs_sap_offset,
+ dlp->subs_bind_req.dl_subs_sap_length);
+ (void) printf("sap %s\n", sap);
+}
+
+printdlsubsbindack(dlp)
+union DL_primitives *dlp;
+{
+ u_char sap[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->subs_bind_ack.dl_subs_sap_offset),
+ dlp->subs_bind_ack.dl_subs_sap_length, sap);
+
+ (void) printf("DL_SUBS_BIND_ACK: subs_sap_offset %d sub_sap_length %d\n",
+ dlp->subs_bind_ack.dl_subs_sap_offset,
+ dlp->subs_bind_ack.dl_subs_sap_length);
+ (void) printf("sap %s\n", sap);
+}
+
+printdlsubsunbindreq(dlp)
+union DL_primitives *dlp;
+{
+ u_char sap[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->subs_unbind_req.dl_subs_sap_offset),
+ dlp->subs_unbind_req.dl_subs_sap_length, sap);
+
+ (void) printf("DL_SUBS_UNBIND_REQ: subs_sap_offset %d sub_sap_length %d\n",
+ dlp->subs_unbind_req.dl_subs_sap_offset,
+ dlp->subs_unbind_req.dl_subs_sap_length);
+ (void) printf("sap %s\n", sap);
+}
+
+printdlunitdatareq(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->unitdata_req.dl_dest_addr_offset),
+ dlp->unitdata_req.dl_dest_addr_length, addr);
+
+ (void) printf("DL_UNITDATA_REQ: dest_addr_length %d dest_addr_offset %d\n",
+ dlp->unitdata_req.dl_dest_addr_length,
+ dlp->unitdata_req.dl_dest_addr_offset);
+ (void) printf("dl_priority.min %d dl_priority.max %d\n",
+ dlp->unitdata_req.dl_priority.dl_min,
+ dlp->unitdata_req.dl_priority.dl_max);
+ (void) printf("addr %s\n", addr);
+}
+
+printdlunitdataind(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+ u_char src[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->unitdata_ind.dl_dest_addr_offset),
+ dlp->unitdata_ind.dl_dest_addr_length, dest);
+ addrtostring(OFFADDR(dlp, dlp->unitdata_ind.dl_src_addr_offset),
+ dlp->unitdata_ind.dl_src_addr_length, src);
+
+ (void) printf("DL_UNITDATA_IND: dest_addr_length %d dest_addr_offset %d\n",
+ dlp->unitdata_ind.dl_dest_addr_length,
+ dlp->unitdata_ind.dl_dest_addr_offset);
+ (void) printf("src_addr_length %d src_addr_offset %d\n",
+ dlp->unitdata_ind.dl_src_addr_length,
+ dlp->unitdata_ind.dl_src_addr_offset);
+ (void) printf("group_address 0x%x\n",
+ dlp->unitdata_ind.dl_group_address);
+ (void) printf("dest %s\n", dest);
+ (void) printf("src %s\n", src);
+}
+
+printdluderrorind(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->uderror_ind.dl_dest_addr_offset),
+ dlp->uderror_ind.dl_dest_addr_length, addr);
+
+ (void) printf("DL_UDERROR_IND: dest_addr_length %d dest_addr_offset %d\n",
+ dlp->uderror_ind.dl_dest_addr_length,
+ dlp->uderror_ind.dl_dest_addr_offset);
+ (void) printf("unix_errno %d errno %s\n",
+ dlp->uderror_ind.dl_unix_errno,
+ dlerrno(dlp->uderror_ind.dl_errno));
+ (void) printf("addr %s\n", addr);
+}
+
+printdltestreq(dlp)
+union DL_primitives *dlp;
+{
+ u_char addr[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->test_req.dl_dest_addr_offset),
+ dlp->test_req.dl_dest_addr_length, addr);
+
+ (void) printf("DL_TEST_REQ: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->test_req.dl_flag,
+ dlp->test_req.dl_dest_addr_length,
+ dlp->test_req.dl_dest_addr_offset);
+ (void) printf("dest_addr %s\n", addr);
+}
+
+printdltestind(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+ u_char src[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->test_ind.dl_dest_addr_offset),
+ dlp->test_ind.dl_dest_addr_length, dest);
+ addrtostring(OFFADDR(dlp, dlp->test_ind.dl_src_addr_offset),
+ dlp->test_ind.dl_src_addr_length, src);
+
+ (void) printf("DL_TEST_IND: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->test_ind.dl_flag,
+ dlp->test_ind.dl_dest_addr_length,
+ dlp->test_ind.dl_dest_addr_offset);
+ (void) printf("src_addr_length %d src_addr_offset %d\n",
+ dlp->test_ind.dl_src_addr_length,
+ dlp->test_ind.dl_src_addr_offset);
+ (void) printf("dest_addr %s\n", dest);
+ (void) printf("src_addr %s\n", src);
+}
+
+printdltestres(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->test_res.dl_dest_addr_offset),
+ dlp->test_res.dl_dest_addr_length, dest);
+
+ (void) printf("DL_TEST_RES: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->test_res.dl_flag,
+ dlp->test_res.dl_dest_addr_length,
+ dlp->test_res.dl_dest_addr_offset);
+ (void) printf("dest_addr %s\n", dest);
+}
+
+printdltestcon(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+ u_char src[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->test_con.dl_dest_addr_offset),
+ dlp->test_con.dl_dest_addr_length, dest);
+ addrtostring(OFFADDR(dlp, dlp->test_con.dl_src_addr_offset),
+ dlp->test_con.dl_src_addr_length, src);
+
+ (void) printf("DL_TEST_CON: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->test_con.dl_flag,
+ dlp->test_con.dl_dest_addr_length,
+ dlp->test_con.dl_dest_addr_offset);
+ (void) printf("src_addr_length %d src_addr_offset %d\n",
+ dlp->test_con.dl_src_addr_length,
+ dlp->test_con.dl_src_addr_offset);
+ (void) printf("dest_addr %s\n", dest);
+ (void) printf("src_addr %s\n", src);
+}
+
+printdlxidreq(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->xid_req.dl_dest_addr_offset),
+ dlp->xid_req.dl_dest_addr_length, dest);
+
+ (void) printf("DL_XID_REQ: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->xid_req.dl_flag,
+ dlp->xid_req.dl_dest_addr_length,
+ dlp->xid_req.dl_dest_addr_offset);
+ (void) printf("dest_addr %s\n", dest);
+}
+
+printdlxidind(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+ u_char src[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->xid_ind.dl_dest_addr_offset),
+ dlp->xid_ind.dl_dest_addr_length, dest);
+ addrtostring(OFFADDR(dlp, dlp->xid_ind.dl_src_addr_offset),
+ dlp->xid_ind.dl_src_addr_length, src);
+
+ (void) printf("DL_XID_IND: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->xid_ind.dl_flag,
+ dlp->xid_ind.dl_dest_addr_length,
+ dlp->xid_ind.dl_dest_addr_offset);
+ (void) printf("src_addr_length %d src_addr_offset %d\n",
+ dlp->xid_ind.dl_src_addr_length,
+ dlp->xid_ind.dl_src_addr_offset);
+ (void) printf("dest_addr %s\n", dest);
+ (void) printf("src_addr %s\n", src);
+}
+
+printdlxidres(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->xid_res.dl_dest_addr_offset),
+ dlp->xid_res.dl_dest_addr_length, dest);
+
+ (void) printf("DL_XID_RES: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->xid_res.dl_flag,
+ dlp->xid_res.dl_dest_addr_length,
+ dlp->xid_res.dl_dest_addr_offset);
+ (void) printf("dest_addr %s\n", dest);
+}
+
+printdlxidcon(dlp)
+union DL_primitives *dlp;
+{
+ u_char dest[MAXDLADDR];
+ u_char src[MAXDLADDR];
+
+ addrtostring(OFFADDR(dlp, dlp->xid_con.dl_dest_addr_offset),
+ dlp->xid_con.dl_dest_addr_length, dest);
+ addrtostring(OFFADDR(dlp, dlp->xid_con.dl_src_addr_offset),
+ dlp->xid_con.dl_src_addr_length, src);
+
+ (void) printf("DL_XID_CON: flag 0x%x dest_addr_length %d dest_addr_offset %d\n",
+ dlp->xid_con.dl_flag,
+ dlp->xid_con.dl_dest_addr_length,
+ dlp->xid_con.dl_dest_addr_offset);
+ (void) printf("src_addr_length %d src_addr_offset %d\n",
+ dlp->xid_con.dl_src_addr_length,
+ dlp->xid_con.dl_src_addr_offset);
+ (void) printf("dest_addr %s\n", dest);
+ (void) printf("src_addr %s\n", src);
+}
+
+printdludqosreq(dlp)
+union DL_primitives *dlp;
+{
+ (void) printf("DL_UDQOS_REQ: qos_length %d qos_offset %d\n",
+ dlp->udqos_req.dl_qos_length,
+ dlp->udqos_req.dl_qos_offset);
+}
+
+/*
+ * Return string.
+ */
+addrtostring(addr, length, s)
+u_char *addr;
+u_long length;
+u_char *s;
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ (void) sprintf((char*) s, "%x:", addr[i] & 0xff);
+ s = s + strlen((char*)s);
+ }
+ if (length)
+ *(--s) = '\0';
+}
+
+/*
+ * Return length
+ */
+stringtoaddr(sp, addr)
+char *sp;
+char *addr;
+{
+ int n = 0;
+ char *p;
+ int val;
+
+ p = sp;
+ while (p = strtok(p, ":")) {
+ if (sscanf(p, "%x", &val) != 1)
+ err("stringtoaddr: invalid input string: %s", sp);
+ if (val > 0xff)
+ err("stringtoaddr: invalid input string: %s", sp);
+ *addr++ = val;
+ n++;
+ p = NULL;
+ }
+
+ return (n);
+}
+
+
+static char
+hexnibble(c)
+char c;
+{
+ static char hextab[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ return (hextab[c & 0x0f]);
+}
+
+char*
+dlprim(prim)
+u_long prim;
+{
+ static char primbuf[80];
+
+ switch ((int)prim) {
+ CASERET(DL_INFO_REQ);
+ CASERET(DL_INFO_ACK);
+ CASERET(DL_ATTACH_REQ);
+ CASERET(DL_DETACH_REQ);
+ CASERET(DL_BIND_REQ);
+ CASERET(DL_BIND_ACK);
+ CASERET(DL_UNBIND_REQ);
+ CASERET(DL_OK_ACK);
+ CASERET(DL_ERROR_ACK);
+ CASERET(DL_SUBS_BIND_REQ);
+ CASERET(DL_SUBS_BIND_ACK);
+ CASERET(DL_UNITDATA_REQ);
+ CASERET(DL_UNITDATA_IND);
+ CASERET(DL_UDERROR_IND);
+ CASERET(DL_UDQOS_REQ);
+ CASERET(DL_CONNECT_REQ);
+ CASERET(DL_CONNECT_IND);
+ CASERET(DL_CONNECT_RES);
+ CASERET(DL_CONNECT_CON);
+ CASERET(DL_TOKEN_REQ);
+ CASERET(DL_TOKEN_ACK);
+ CASERET(DL_DISCONNECT_REQ);
+ CASERET(DL_DISCONNECT_IND);
+ CASERET(DL_RESET_REQ);
+ CASERET(DL_RESET_IND);
+ CASERET(DL_RESET_RES);
+ CASERET(DL_RESET_CON);
+ default:
+ (void) sprintf(primbuf, "unknown primitive 0x%x", prim);
+ return (primbuf);
+ }
+}
+
+
+char*
+dlstate(state)
+u_long state;
+{
+ static char statebuf[80];
+
+ switch (state) {
+ CASERET(DL_UNATTACHED);
+ CASERET(DL_ATTACH_PENDING);
+ CASERET(DL_DETACH_PENDING);
+ CASERET(DL_UNBOUND);
+ CASERET(DL_BIND_PENDING);
+ CASERET(DL_UNBIND_PENDING);
+ CASERET(DL_IDLE);
+ CASERET(DL_UDQOS_PENDING);
+ CASERET(DL_OUTCON_PENDING);
+ CASERET(DL_INCON_PENDING);
+ CASERET(DL_CONN_RES_PENDING);
+ CASERET(DL_DATAXFER);
+ CASERET(DL_USER_RESET_PENDING);
+ CASERET(DL_PROV_RESET_PENDING);
+ CASERET(DL_RESET_RES_PENDING);
+ CASERET(DL_DISCON8_PENDING);
+ CASERET(DL_DISCON9_PENDING);
+ CASERET(DL_DISCON11_PENDING);
+ CASERET(DL_DISCON12_PENDING);
+ CASERET(DL_DISCON13_PENDING);
+ CASERET(DL_SUBS_BIND_PND);
+ default:
+ (void) sprintf(statebuf, "unknown state 0x%x", state);
+ return (statebuf);
+ }
+}
+
+char*
+dlerrno(errno)
+u_long errno;
+{
+ static char errnobuf[80];
+
+ switch (errno) {
+ CASERET(DL_ACCESS);
+ CASERET(DL_BADADDR);
+ CASERET(DL_BADCORR);
+ CASERET(DL_BADDATA);
+ CASERET(DL_BADPPA);
+ CASERET(DL_BADPRIM);
+ CASERET(DL_BADQOSPARAM);
+ CASERET(DL_BADQOSTYPE);
+ CASERET(DL_BADSAP);
+ CASERET(DL_BADTOKEN);
+ CASERET(DL_BOUND);
+ CASERET(DL_INITFAILED);
+ CASERET(DL_NOADDR);
+ CASERET(DL_NOTINIT);
+ CASERET(DL_OUTSTATE);
+ CASERET(DL_SYSERR);
+ CASERET(DL_UNSUPPORTED);
+ CASERET(DL_UNDELIVERABLE);
+ CASERET(DL_NOTSUPPORTED);
+ CASERET(DL_TOOMANY);
+ CASERET(DL_NOTENAB);
+ CASERET(DL_BUSY);
+ CASERET(DL_NOAUTO);
+ CASERET(DL_NOXIDAUTO);
+ CASERET(DL_NOTESTAUTO);
+ CASERET(DL_XIDAUTO);
+ CASERET(DL_TESTAUTO);
+ CASERET(DL_PENDING);
+
+ default:
+ (void) sprintf(errnobuf, "unknown dlpi errno 0x%x", errno);
+ return (errnobuf);
+ }
+}
+
+char*
+dlpromisclevel(level)
+u_long level;
+{
+ static char levelbuf[80];
+
+ switch (level) {
+ CASERET(DL_PROMISC_PHYS);
+ CASERET(DL_PROMISC_SAP);
+ CASERET(DL_PROMISC_MULTI);
+ default:
+ (void) sprintf(levelbuf, "unknown promisc level 0x%x", level);
+ return (levelbuf);
+ }
+}
+
+char*
+dlservicemode(servicemode)
+u_long servicemode;
+{
+ static char servicemodebuf[80];
+
+ switch (servicemode) {
+ CASERET(DL_CODLS);
+ CASERET(DL_CLDLS);
+ CASERET(DL_CODLS|DL_CLDLS);
+ default:
+ (void) sprintf(servicemodebuf,
+ "unknown provider service mode 0x%x", servicemode);
+ return (servicemodebuf);
+ }
+}
+
+char*
+dlstyle(style)
+long style;
+{
+ static char stylebuf[80];
+
+ switch (style) {
+ CASERET(DL_STYLE1);
+ CASERET(DL_STYLE2);
+ default:
+ (void) sprintf(stylebuf, "unknown provider style 0x%x", style);
+ return (stylebuf);
+ }
+}
+
+char*
+dlmactype(media)
+u_long media;
+{
+ static char mediabuf[80];
+
+ switch (media) {
+ CASERET(DL_CSMACD);
+ CASERET(DL_TPB);
+ CASERET(DL_TPR);
+ CASERET(DL_METRO);
+ CASERET(DL_ETHER);
+ CASERET(DL_HDLC);
+ CASERET(DL_CHAR);
+ CASERET(DL_CTCA);
+ default:
+ (void) sprintf(mediabuf, "unknown media type 0x%x", media);
+ return (mediabuf);
+ }
+}
+
+/*VARARGS1*/
+err(fmt, a1, a2, a3, a4)
+char *fmt;
+char *a1, *a2, *a3, *a4;
+{
+ (void) fprintf(stderr, fmt, a1, a2, a3, a4);
+ (void) fprintf(stderr, "\n");
+ (void) exit(1);
+}
+
+syserr(s)
+char *s;
+{
+ (void) perror(s);
+ exit(1);
+}
+
+strioctl(fd, cmd, timout, len, dp)
+int fd;
+int cmd;
+int timout;
+int len;
+char *dp;
+{
+ struct strioctl sioc;
+ int rc;
+
+ sioc.ic_cmd = cmd;
+ sioc.ic_timout = timout;
+ sioc.ic_len = len;
+ sioc.ic_dp = dp;
+ rc = ioctl(fd, I_STR, &sioc);
+
+ if (rc < 0)
+ return (rc);
+ else
+ return (sioc.ic_len);
+}
diff --git a/contrib/ipfilter/ipsend/dltest.h b/contrib/ipfilter/ipsend/dltest.h
new file mode 100644
index 0000000..4c32c30
--- /dev/null
+++ b/contrib/ipfilter/ipsend/dltest.h
@@ -0,0 +1,32 @@
+/*
+ * Common DLPI Test Suite header file
+ *
+ */
+
+/*
+ * Maximum control/data buffer size (in long's !!) for getmsg().
+ */
+#define MAXDLBUF 8192
+
+/*
+ * Maximum number of seconds we'll wait for any
+ * particular DLPI acknowledgment from the provider
+ * after issuing a request.
+ */
+#define MAXWAIT 15
+
+/*
+ * Maximum address buffer length.
+ */
+#define MAXDLADDR 1024
+
+
+/*
+ * Handy macro.
+ */
+#define OFFADDR(s, n) (u_char*)((char*)(s) + (int)(n))
+
+/*
+ * externs go here
+ */
+extern void sigalrm();
diff --git a/contrib/ipfilter/ipsend/in_var.h b/contrib/ipfilter/ipsend/in_var.h
new file mode 100644
index 0000000..63980ef
--- /dev/null
+++ b/contrib/ipfilter/ipsend/in_var.h
@@ -0,0 +1,177 @@
+/* @(#)in_var.h 1.3 88/08/19 SMI; from UCB 7.1 6/5/86 */
+
+/*
+ * Copyright (c) 1985, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+/*
+ * Interface address, Internet version. One of these structures
+ * is allocated for each interface with an Internet address.
+ * The ifaddr structure contains the protocol-independent part
+ * of the structure and is assumed to be first.
+ */
+
+#ifndef _netinet_in_var_h
+#define _netinet_in_var_h
+
+struct in_ifaddr {
+ struct ifaddr ia_ifa; /* protocol-independent info */
+#define ia_addr ia_ifa.ifa_addr
+#define ia_broadaddr ia_ifa.ifa_broadaddr
+#define ia_dstaddr ia_ifa.ifa_dstaddr
+#define ia_ifp ia_ifa.ifa_ifp
+ u_long ia_net; /* network number of interface */
+ u_long ia_netmask; /* mask of net part */
+ u_long ia_subnet; /* subnet number, including net */
+ u_long ia_subnetmask; /* mask of net + subnet */
+ struct in_addr ia_netbroadcast; /* broadcast addr for (logical) net */
+ int ia_flags;
+ struct in_ifaddr *ia_next; /* next in list of internet addresses */
+ struct in_multi *ia_multiaddrs;/* list of multicast addresses */
+};
+/*
+ * Given a pointer to an in_ifaddr (ifaddr),
+ * return a pointer to the addr as a sockadd_in.
+ */
+#define IA_SIN(ia) ((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_addr))
+/*
+ * ia_flags
+ */
+#define IFA_ROUTE 0x01 /* routing entry installed */
+
+#ifdef KERNEL
+struct in_ifaddr *in_ifaddr;
+struct in_ifaddr *in_iaonnetof();
+struct ifqueue ipintrq; /* ip packet input queue */
+#endif
+
+#ifdef KERNEL
+/*
+ * Macro for finding the interface (ifnet structure) corresponding to one
+ * of our IP addresses.
+ */
+#define INADDR_TO_IFP(addr, ifp) \
+ /* struct in_addr addr; */ \
+ /* struct ifnet *ifp; */ \
+{ \
+ register struct in_ifaddr *ia; \
+ \
+ for (ia = in_ifaddr; \
+ ia != NULL && IA_SIN(ia)->sin_addr.s_addr != (addr).s_addr; \
+ ia = ia->ia_next); \
+ (ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \
+}
+
+/*
+ * Macro for finding the internet address structure (in_ifaddr) corresponding
+ * to a given interface (ifnet structure).
+ */
+#define IFP_TO_IA(ifp, ia) \
+ /* struct ifnet *ifp; */ \
+ /* struct in_ifaddr *ia; */ \
+{ \
+ for ((ia) = in_ifaddr; \
+ (ia) != NULL && (ia)->ia_ifp != (ifp); \
+ (ia) = (ia)->ia_next); \
+}
+#endif KERNEL
+
+/*
+ * Per-interface router version information is kept in this list.
+ * This information should be part of the ifnet structure but we don't wish
+ * to change that - as it might break a number of things
+ */
+
+struct router_info {
+ struct ifnet *ifp;
+ int type; /* type of router which is querier on this interface */
+ int time; /* # of slow timeouts since last old query */
+ struct router_info *next;
+};
+
+/*
+ * Internet multicast address structure. There is one of these for each IP
+ * multicast group to which this host belongs on a given network interface.
+ * They are kept in a linked list, rooted in the interface's in_ifaddr
+ * structure.
+ */
+
+struct in_multi {
+ struct in_addr inm_addr; /* IP multicast address */
+ struct ifnet *inm_ifp; /* back pointer to ifnet */
+ struct in_ifaddr *inm_ia; /* back pointer to in_ifaddr */
+ u_int inm_refcount;/* no. membership claims by sockets */
+ u_int inm_timer; /* IGMP membership report timer */
+ struct in_multi *inm_next; /* ptr to next multicast address */
+ u_int inm_state; /* state of the membership */
+ struct router_info *inm_rti; /* router info*/
+};
+
+#ifdef KERNEL
+/*
+ * Structure used by macros below to remember position when stepping through
+ * all of the in_multi records.
+ */
+struct in_multistep {
+ struct in_ifaddr *i_ia;
+ struct in_multi *i_inm;
+};
+
+/*
+ * Macro for looking up the in_multi record for a given IP multicast address
+ * on a given interface. If no matching record is found, "inm" returns NULL.
+ */
+#define IN_LOOKUP_MULTI(addr, ifp, inm) \
+ /* struct in_addr addr; */ \
+ /* struct ifnet *ifp; */ \
+ /* struct in_multi *inm; */ \
+{ \
+ register struct in_ifaddr *ia; \
+ \
+ IFP_TO_IA((ifp), ia); \
+ if (ia == NULL) \
+ (inm) = NULL; \
+ else \
+ for ((inm) = ia->ia_multiaddrs; \
+ (inm) != NULL && (inm)->inm_addr.s_addr != (addr).s_addr; \
+ (inm) = inm->inm_next); \
+}
+
+/*
+ * Macro to step through all of the in_multi records, one at a time.
+ * The current position is remembered in "step", which the caller must
+ * provide. IN_FIRST_MULTI(), below, must be called to initialize "step"
+ * and get the first record. Both macros return a NULL "inm" when there
+ * are no remaining records.
+ */
+#define IN_NEXT_MULTI(step, inm) \
+ /* struct in_multistep step; */ \
+ /* struct in_multi *inm; */ \
+{ \
+ if (((inm) = (step).i_inm) != NULL) { \
+ (step).i_inm = (inm)->inm_next; \
+ } \
+ else while ((step).i_ia != NULL) { \
+ (inm) = (step).i_ia->ia_multiaddrs; \
+ (step).i_ia = (step).i_ia->ia_next; \
+ if ((inm) != NULL) { \
+ (step).i_inm = (inm)->inm_next; \
+ break; \
+ } \
+ } \
+}
+
+#define IN_FIRST_MULTI(step, inm) \
+ /* struct in_multistep step; */ \
+ /* struct in_multi *inm; */ \
+{ \
+ (step).i_ia = in_ifaddr; \
+ (step).i_inm = NULL; \
+ IN_NEXT_MULTI((step), (inm)); \
+}
+
+struct in_multi *in_addmulti();
+#endif KERNEL
+#endif /*!_netinet_in_var_h*/
diff --git a/contrib/ipfilter/ipsend/ip.c b/contrib/ipfilter/ipsend/ip.c
new file mode 100644
index 0000000..2c7f7ff
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ip.c
@@ -0,0 +1,346 @@
+/*
+ * ip.c (C) 1995 Darren Reed
+ *
+ * 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.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "%W% %G% (C)1995";
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.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>
+#ifndef linux
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcpip.h>
+#endif
+#include "ip_compat.h"
+#ifdef linux
+#include "tcpip.h"
+#endif
+
+
+static char *ipbuf = NULL, *ethbuf = NULL;
+
+extern int arp(), sendip();
+
+u_short chksum(buf,len)
+u_short *buf;
+int len;
+{
+ u_long sum = 0;
+ int nwords = len >> 1;
+
+ for(; nwords > 0; nwords--)
+ sum += *buf++;
+ sum = (sum>>16) + (sum & 0xffff);
+ sum += (sum >>16);
+ return (~sum);
+}
+
+
+int send_ether(nfd, buf, len, gwip)
+int nfd, len;
+char *buf;
+struct in_addr gwip;
+{
+ static struct in_addr last_gw;
+ static char last_arp[6] = { 0, 0, 0, 0, 0, 0};
+ ether_header_t *eh;
+ char *s;
+ int err;
+
+ if (!ethbuf)
+ ethbuf = (char *)calloc(1, 65536+1024);
+ s = ethbuf;
+ eh = (ether_header_t *)s;
+
+ bcopy((char *)buf, s + sizeof(*eh), len);
+ if (gwip.s_addr == last_gw.s_addr)
+ bcopy(last_arp, (char *)&eh->ether_dhost, 6);
+ else if (arp((char *)&gwip, &eh->ether_dhost) == -1)
+ {
+ perror("arp");
+ return -2;
+ }
+ eh->ether_type = ETHERTYPE_IP;
+ last_gw.s_addr = gwip.s_addr;
+ err = sendip(nfd, s, sizeof(*eh) + len);
+ return err;
+}
+
+
+/*
+ */
+int send_ip(nfd, mtu, ip, gwip, frag)
+int nfd, mtu;
+ip_t *ip;
+struct in_addr gwip;
+int frag;
+{
+ static struct in_addr last_gw;
+ static char last_arp[6] = { 0, 0, 0, 0, 0, 0};
+ static u_short id = 0;
+ ether_header_t *eh;
+ ip_t ipsv;
+ int err;
+
+ if (!ipbuf)
+ ipbuf = (char *)malloc(65536);
+ eh = (ether_header_t *)ipbuf;
+
+ bzero((char *)&eh->ether_shost, sizeof(eh->ether_shost));
+ if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr))
+ bcopy(last_arp, (char *)&eh->ether_dhost, 6);
+ else if (arp((char *)&gwip, &eh->ether_dhost) == -1)
+ {
+ perror("arp");
+ return -2;
+ }
+ bcopy((char *)&eh->ether_dhost, last_arp, sizeof(last_arp));
+ eh->ether_type = ETHERTYPE_IP;
+
+ bcopy((char *)ip, (char *)&ipsv, sizeof(*ip));
+ last_gw.s_addr = gwip.s_addr;
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+ if (!ip->ip_v)
+ ip->ip_v = IPVERSION;
+ if (!ip->ip_id)
+ ip->ip_id = htons(id++);
+ if (!ip->ip_ttl)
+ ip->ip_ttl = 60;
+
+ if (!frag || (sizeof(*eh) + ntohs(ip->ip_len) < mtu))
+ {
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum(ip, ip->ip_hl << 2);
+
+ bcopy((char *)ip, ipbuf + sizeof(*eh), ntohs(ip->ip_len));
+ err = sendip(nfd, ipbuf, sizeof(*eh) + ntohs(ip->ip_len));
+ }
+ else
+ {
+ /*
+ * Actually, this is bogus because we're putting all IP
+ * options in every packet, which isn't always what should be
+ * done. Will do for now.
+ */
+ ether_header_t eth;
+ char optcpy[48], ol;
+ char *s;
+ int i, iplen, sent = 0, ts, hlen, olen;
+
+ hlen = ip->ip_hl << 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);
+ for (i = 0, s = (char*)(ip + 1); ol > 0; )
+ if (*s == IPOPT_EOL) {
+ optcpy[i++] = *s;
+ break;
+ } else if (*s == IPOPT_NOP) {
+ s++;
+ ol--;
+ } else
+ {
+ olen = (int)(*(u_char *)(s + 1));
+ ol -= olen;
+ if (IPOPT_COPIED(*s))
+ {
+ bcopy(s, optcpy + i, olen);
+ i += olen;
+ s += olen;
+ }
+ }
+ if (i)
+ {
+ /*
+ * pad out
+ */
+ while ((i & 3) && (i & 3) != 3)
+ optcpy[i++] = IPOPT_NOP;
+ if ((i & 3) == 3)
+ optcpy[i++] = IPOPT_EOL;
+ }
+
+ bcopy((char *)eh, (char *)&eth, sizeof(eth));
+ s = (char *)ip + hlen;
+ iplen = ntohs(ip->ip_len) - hlen;
+ ip->ip_off |= htons(IP_MF);
+
+ while (1)
+ {
+ if ((sent + (mtu - hlen)) >= iplen)
+ {
+ ip->ip_off ^= htons(IP_MF);
+ ts = iplen - sent;
+ }
+ else
+ ts = (mtu - hlen);
+ ip->ip_off &= htons(0xe000);
+ ip->ip_off |= htons(sent >> 3);
+ ts += hlen;
+ ip->ip_len = htons(ts);
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum(ip, hlen);
+ bcopy((char *)ip, ipbuf + sizeof(*eh), hlen);
+ bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen);
+ err = sendip(nfd, ipbuf, sizeof(*eh) + ts);
+
+ bcopy((char *)&eth, ipbuf, sizeof(eth));
+ sent += (ts - hlen);
+ if (!(ntohs(ip->ip_off) & IP_MF))
+ break;
+ else if (!(ip->ip_off & htons(0x1fff)))
+ {
+ hlen = i + sizeof(*ip);
+ ip->ip_hl = (sizeof(*ip) + i) >> 2;
+ bcopy(optcpy, (char *)(ip + 1), i);
+ }
+ }
+ }
+
+ bcopy((char *)&ipsv, (char *)ip, sizeof(*ip));
+ return err;
+}
+
+
+/*
+ * send a tcp packet.
+ */
+int send_tcp(nfd, mtu, ip, gwip)
+int nfd, mtu;
+ip_t *ip;
+struct in_addr gwip;
+{
+ static tcp_seq iss = 2;
+ struct tcpiphdr *ti;
+ int thlen, i;
+ u_long lbuf[20];
+
+ ti = (struct tcpiphdr *)lbuf;
+ bzero((char *)ti, sizeof(*ti));
+ thlen = sizeof(tcphdr_t);
+ 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 + (ip->ip_hl << 2),
+ (char *)&ti->ti_sport, sizeof(tcphdr_t));
+
+ if (!ti->ti_win)
+ ti->ti_win = htons(4096);
+ if (!ti->ti_seq)
+ ti->ti_seq = htonl(iss);
+ iss += 64;
+
+ if ((ti->ti_flags == TH_SYN) && !ip->ip_off)
+ {
+ ip = (ip_t *)realloc((char *)ip, ntohs(ip->ip_len) + 4);
+ i = sizeof(struct tcpiphdr) / sizeof(long);
+ lbuf[i] = htonl(0x020405b4);
+ bcopy((char *)(lbuf + i), (char*)ip + ntohs(ip->ip_len),
+ sizeof(u_long));
+ thlen += 4;
+ }
+ if (!ti->ti_off)
+ ti->ti_off = thlen >> 2;
+ ti->ti_len = htons(thlen);
+ ip->ip_len = (ip->ip_hl << 2) + thlen;
+ ti->ti_sum = 0;
+ ti->ti_sum = chksum(ti, thlen + sizeof(ip_t));
+
+ bcopy((char *)&ti->ti_sport,
+ (char *)ip + (ip->ip_hl << 2), thlen);
+ return send_ip(nfd, mtu, ip, gwip, 1);
+}
+
+
+/*
+ * send a udp packet.
+ */
+int send_udp(nfd, mtu, ip, gwip)
+int nfd, mtu;
+ip_t *ip;
+struct in_addr gwip;
+{
+ struct tcpiphdr *ti;
+ int thlen;
+ u_long lbuf[20];
+
+ ti = (struct tcpiphdr *)lbuf;
+ bzero((char *)ti, sizeof(*ti));
+ thlen = sizeof(udphdr_t);
+ 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),
+ (char *)&ti->ti_sport, sizeof(udphdr_t));
+
+ ti->ti_len = htons(thlen);
+ ip->ip_len = (ip->ip_hl << 2) + thlen;
+ ti->ti_sum = 0;
+ ti->ti_sum = chksum(ti, thlen + sizeof(ip_t));
+
+ bcopy((char *)&ti->ti_sport,
+ (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t));
+ return send_ip(nfd, mtu, ip, gwip, 1);
+}
+
+
+/*
+ * send an icmp packet.
+ */
+int send_icmp(nfd, mtu, ip, gwip)
+int nfd, mtu;
+ip_t *ip;
+struct in_addr gwip;
+{
+ struct icmp *ic;
+
+ ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2));
+
+ ic->icmp_cksum = 0;
+ ic->icmp_cksum = chksum((char *)ic, sizeof(struct icmp));
+
+ return send_ip(nfd, mtu, ip, gwip, 1);
+}
+
+
+int send_packet(nfd, mtu, ip, gwip)
+int nfd, mtu;
+ip_t *ip;
+struct in_addr gwip;
+{
+ switch (ip->ip_p)
+ {
+ case IPPROTO_TCP :
+ return send_tcp(nfd, mtu, ip, gwip);
+ case IPPROTO_UDP :
+ return send_udp(nfd, mtu, ip, gwip);
+ case IPPROTO_ICMP :
+ return send_icmp(nfd, mtu, ip, gwip);
+ default :
+ return send_ip(nfd, mtu, ip, gwip, 1);
+ }
+}
diff --git a/contrib/ipfilter/ipsend/ip_compat.h b/contrib/ipfilter/ipsend/ip_compat.h
new file mode 100644
index 0000000..c38fa59
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ip_compat.h
@@ -0,0 +1,242 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * 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 ?
+ *
+ * @(#)ip_compat.h 1.2 12/7/95
+ */
+
+/*
+ * 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_UNREACH
+# define ICMP_UNREACH ICMP_DEST_UNREACH
+#endif
+#ifndef ICMP_SOURCEQUENCH
+# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH
+#endif
+#ifndef ICMP_TIMXCEED
+# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED
+#endif
+#ifndef ICMP_PARAMPROB
+# define ICMP_PARAMPROB ICMP_PARAMETERPROB
+#endif
+#ifndef IPVERSION
+# define IPVERSION 4
+#endif
+#ifndef IPOPT_MINOFF
+# define IPOPT_MINOFF 4
+#endif
+#ifndef IPOPT_COPIED
+# define IPOPT_COPIED(x) ((x)&0x80)
+#endif
+#ifndef IPOPT_EOL
+# define IPOPT_EOL 0
+#endif
+#ifndef IPOPT_NOP
+# define IPOPT_NOP 1
+#endif
+#ifndef IP_MF
+# define IP_MF ((u_short)0x2000)
+#endif
+#ifndef ETHERTYPE_IP
+# define ETHERTYPE_IP ((u_short)0x0800)
+#endif
+#ifndef TH_FIN
+# define TH_FIN 0x01
+#endif
+#ifndef TH_SYN
+# define TH_SYN 0x02
+#endif
+#ifndef TH_RST
+# define TH_RST 0x04
+#endif
+#ifndef TH_PUSH
+# define TH_PUSH 0x08
+#endif
+#ifndef TH_ACK
+# define TH_ACK 0x10
+#endif
+#ifndef TH_URG
+# define TH_URG 0x20
+#endif
+#ifndef IPOPT_EOL
+# define IPOPT_EOL 0
+#endif
+#ifndef IPOPT_NOP
+# define IPOPT_NOP 1
+#endif
+#ifndef IPOPT_RR
+# define IPOPT_RR 7
+#endif
+#ifndef IPOPT_TS
+# define IPOPT_TS 68
+#endif
+#ifndef IPOPT_SECURITY
+# define IPOPT_SECURITY 130
+#endif
+#ifndef IPOPT_LSRR
+# define IPOPT_LSRR 131
+#endif
+#ifndef IPOPT_SATID
+# define IPOPT_SATID 136
+#endif
+#ifndef IPOPT_SSRR
+# define IPOPT_SSRR 137
+#endif
+#ifndef IPOPT_SECUR_UNCLASS
+# define IPOPT_SECUR_UNCLASS ((u_short)0x0000)
+#endif
+#ifndef IPOPT_SECUR_CONFID
+# define IPOPT_SECUR_CONFID ((u_short)0xf135)
+#endif
+#ifndef IPOPT_SECUR_EFTO
+# define IPOPT_SECUR_EFTO ((u_short)0x789a)
+#endif
+#ifndef IPOPT_SECUR_MMMM
+# define IPOPT_SECUR_MMMM ((u_short)0xbc4d)
+#endif
+#ifndef IPOPT_SECUR_RESTR
+# define IPOPT_SECUR_RESTR ((u_short)0xaf13)
+#endif
+#ifndef IPOPT_SECUR_SECRET
+# define IPOPT_SECUR_SECRET ((u_short)0xd788)
+#endif
+#ifndef IPOPT_SECUR_TOPSECRET
+# define IPOPT_SECUR_TOPSECRET ((u_short)0x6bc5)
+#endif
+
+#ifdef linux
+# if LINUX < 0200
+# define icmp icmphdr
+# define icmp_type type
+# define icmp_code code
+# endif
+
+/*
+ * From /usr/include/netinet/ip_var.h
+ * !%@#!$@# linux...
+ */
+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 */
+};
+
+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;
+ __s16 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_hl:4;
+ __u8 ip_v: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;
+
+typedef struct {
+ __u8 ether_dhost[6];
+ __u8 ether_shost[6];
+ __u16 ether_type;
+} ether_header_t;
+
+typedef struct icmp {
+ u_char icmp_type; /* type of message, see below */
+ u_char icmp_code; /* type sub code */
+ u_short icmp_cksum; /* ones complement cksum of struct */
+ union {
+ u_char ih_pptr; /* ICMP_PARAMPROB */
+ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
+ struct ih_idseq {
+ n_short icd_id;
+ n_short 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;
+
+# define bcopy(a,b,c) memmove(b,a,c)
+# define bcmp(a,b,c) memcmp(a,b,c)
+
+# define ifnet device
+
+#else
+
+typedef struct udphdr udphdr_t;
+typedef struct tcphdr tcphdr_t;
+typedef struct ip ip_t;
+typedef struct ether_header ether_header_t;
+
+#endif
+
+#if defined(__SVR4) || defined(__svr4__)
+# define bcopy(a,b,c) memmove(b,a,c)
+# define bcmp(a,b,c) memcmp(a,b,c)
+# define bzero(a,b) memset(a,0,b)
+#endif
diff --git a/contrib/ipfilter/ipsend/ip_var.h b/contrib/ipfilter/ipsend/ip_var.h
new file mode 100644
index 0000000..92eb38a
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ip_var.h
@@ -0,0 +1,123 @@
+/* @(#)ip_var.h 1.11 88/08/19 SMI; from UCB 7.1 6/5/86 */
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+/*
+ * Overlay for ip header used by other protocols (tcp, udp).
+ */
+
+#ifndef _netinet_ip_var_h
+#define _netinet_ip_var_h
+
+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 */
+};
+
+/*
+ * Ip reassembly queue structure. Each fragment
+ * being reassembled is attached to one of these structures.
+ * They are timed out after ipq_ttl drops to 0, and may also
+ * be reclaimed if memory becomes tight.
+ */
+struct ipq {
+ struct ipq *next,*prev; /* to other reass headers */
+ u_char ipq_ttl; /* time for reass q to live */
+ u_char ipq_p; /* protocol of this fragment */
+ u_short ipq_id; /* sequence id for reassembly */
+ struct ipasfrag *ipq_next,*ipq_prev;
+ /* to ip headers of fragments */
+ struct in_addr ipq_src,ipq_dst;
+};
+
+/*
+ * Ip header, when holding a fragment.
+ *
+ * Note: ipf_next must be at same offset as ipq_next above
+ */
+struct ipasfrag {
+#if defined(vax) || defined(i386)
+ u_char ip_hl:4,
+ ip_v:4;
+#endif
+#if defined(mc68000) || defined(sparc)
+ u_char ip_v:4,
+ ip_hl:4;
+#endif
+ u_char ipf_mff; /* copied from (ip_off&IP_MF) */
+ short ip_len;
+ u_short ip_id;
+ short ip_off;
+ u_char ip_ttl;
+ u_char ip_p;
+ u_short ip_sum;
+ struct ipasfrag *ipf_next; /* next fragment */
+ struct ipasfrag *ipf_prev; /* previous fragment */
+};
+
+/*
+ * Structure stored in mbuf in inpcb.ip_options
+ * and passed to ip_output when ip options are in use.
+ * The actual length of the options (including ipopt_dst)
+ * is in m_len.
+ */
+#define MAX_IPOPTLEN 40
+
+struct ipoption {
+ struct in_addr ipopt_dst; /* first-hop dst if source routed */
+ char ipopt_list[MAX_IPOPTLEN]; /* options proper */
+};
+
+/*
+ * Structure stored in an mbuf attached to inpcb.ip_moptions and
+ * passed to ip_output when IP multicast options are in use.
+ */
+struct ip_moptions {
+ struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */
+ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */
+ u_char imo_multicast_loop; /* 1 => hear sends if a member */
+ u_short imo_num_memberships;/* no. memberships this socket */
+ struct in_multi *imo_membership[IP_MAX_MEMBERSHIPS];
+#ifdef RSVP_ISI
+ long imo_multicast_vif; /* vif for outgoing multicasts */
+#endif /* RSVP_ISI */
+};
+
+struct ipstat {
+ long ips_total; /* total packets received */
+ long ips_badsum; /* checksum bad */
+ long ips_tooshort; /* packet too short */
+ long ips_toosmall; /* not enough data */
+ long ips_badhlen; /* ip header length < data size */
+ long ips_badlen; /* ip length < ip header length */
+ long ips_fragments; /* fragments received */
+ long ips_fragdropped; /* frags dropped (dups, out of space) */
+ long ips_fragtimeout; /* fragments timed out */
+ long ips_forward; /* packets forwarded */
+ long ips_cantforward; /* packets rcvd for unreachable dest */
+ long ips_redirectsent; /* packets forwarded on same net */
+};
+
+#ifdef KERNEL
+/* flags passed to ip_output as last parameter */
+#define IP_FORWARDING 0x1 /* most of ip header exists */
+#define IP_MULTICASTOPTS 0x2 /* multicast opts present */
+#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */
+#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */
+
+struct ipstat ipstat;
+struct ipq ipq; /* ip reass. queue */
+u_short ip_id; /* ip packet ctr, for ids */
+
+struct mbuf *ip_srcroute();
+#endif
+
+#endif /*!_netinet_ip_var_h*/
diff --git a/contrib/ipfilter/ipsend/ipresend.c b/contrib/ipfilter/ipsend/ipresend.c
new file mode 100644
index 0000000..6fd91bf
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipresend.c
@@ -0,0 +1,165 @@
+/*
+ * ipsend.c (C) 1995 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.
+ *
+ * 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.
+ *
+ * This was written and tested (successfully) on SunOS 4.1.x.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "%W% %G% (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.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>
+#include <netinet/tcpip.h>
+#endif
+#include "ip_compat.h"
+#ifdef linux
+#include <linux/sockios.h>
+#include "tcpip.h"
+#endif
+#include "ipt.h"
+
+
+extern char *optarg;
+extern int optind;
+#ifndef NO_IPF
+extern struct ipread snoop, pcap, etherf, iphex, tcpd, iptext;
+#endif
+extern int resolve(), ip_resend();
+
+int opts = 0;
+#ifndef DEFAULT_DEVICE
+# ifdef linux
+char default_device[] = "eth0";
+# else
+# ifdef sun
+char default_device[] = "le0";
+# else
+# ifdef ultrix
+char default_device[] = "ln0";
+# else
+# ifdef __bsdi__
+char default_device[] = "ef0";
+# else
+char default_device[] = "lan0";
+# endif
+# endif
+# endif
+# endif
+#else
+char default_device[] = DEFAULT_DEVICE;
+#endif
+
+
+void usage(prog)
+char *prog;
+{
+ fprintf(stderr, "Usage: %s [options] <-r filename|-R filename>\n\
+\t\t-r filename\tsnoop data file to resend\n\
+\t\t-R filename\tlibpcap data file to resend\n\
+\toptions:\n\
+\t\t-d device\tSend out on this device\n\
+\t\t-g gateway\tIP gateway to use if non-local dest.\n\
+\t\t-m mtu\t\tfake MTU to use when sending out\n\
+", prog);
+ exit(1);
+}
+
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ struct in_addr gwip;
+ struct ipread *ipr = NULL;
+ char *name = argv[0], *gateway = NULL, *dev = NULL;
+ char c, *resend = NULL;
+ int mtu = 1500;
+
+ while ((c = getopt(argc, argv, "EHPSTXd:g:m:r:")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ dev = optarg;
+ break;
+ case 'g' :
+ gateway = optarg;
+ break;
+ case 'm' :
+ mtu = atoi(optarg);
+ if (mtu < 28)
+ {
+ fprintf(stderr, "mtu must be > 28\n");
+ exit(1);
+ }
+ case 'r' :
+ resend = optarg;
+ break;
+#ifndef NO_IPF
+ case 'E' :
+ ipr = &etherf;
+ break;
+ case 'H' :
+ ipr = &iphex;
+ break;
+ case 'P' :
+ ipr = &pcap;
+ break;
+ case 'S' :
+ ipr = &snoop;
+ break;
+ case 'T' :
+ ipr = &tcpd;
+ break;
+ case 'X' :
+ ipr = &iptext;
+ break;
+#endif
+ default :
+ fprintf(stderr, "Unknown option \"%c\"\n", c);
+ usage(name);
+ }
+
+ if (!ipr || !resend)
+ usage(name);
+
+ gwip.s_addr = 0;
+ if (gateway && resolve(gateway, (char *)&gwip) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", gateway);
+ exit(2);
+ }
+
+ if (!dev)
+ dev = default_device;
+
+ printf("Device: %s\n", dev);
+ printf("Gateway: %s\n", inet_ntoa(gwip));
+ printf("mtu: %d\n", mtu);
+
+ return ip_resend(dev, mtu, ipr, gwip, resend);
+}
diff --git a/contrib/ipfilter/ipsend/ipsend.c b/contrib/ipfilter/ipsend/ipsend.c
new file mode 100644
index 0000000..e45d3ee
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipsend.c
@@ -0,0 +1,350 @@
+/*
+ * ipsend.c (C) 1995 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.
+ *
+ * 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.
+ *
+ * This was written and tested (successfully) on SunOS 4.1.x.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.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>
+#include <netinet/tcpip.h>
+#endif
+#include "ip_compat.h"
+#ifdef linux
+#include <linux/sockios.h>
+#include "tcpip.h"
+#endif
+#include "ipt.h"
+
+
+extern char *optarg;
+extern int optind;
+
+extern int resolve(), optname(), initdevice(), send_packet();
+
+char options[68];
+#ifdef linux
+char default_device[] = "eth0";
+#else
+# ifdef sun
+char default_device[] = "le0";
+# else
+# ifdef ultrix
+char default_device[] = "ln0";
+# else
+# ifdef __bsdi__
+char default_device[] = "ef0";
+# else
+char default_device[] = "lan0";
+# endif
+# endif
+# endif
+#endif
+
+
+void usage(prog)
+char *prog;
+{
+ fprintf(stderr, "Usage: %s [options] dest [flags]\n\
+\toptions:\n\
+\t\t-d device\tSend out on this device\n\
+\t\t-f fragflags\tcan set IP_MF or IP_DF\n\
+\t\t-g gateway\tIP gateway to use if non-local dest.\n\
+\t\t-I code,type[,gw[,dst[,src]]]\tSet ICMP protocol\n\
+\t\t-m mtu\t\tfake MTU to use when sending out\n\
+\t\t-P protocol\tSet protocol by name\n\
+\t\t-s src\t\tsource address for IP packet\n\
+\t\t-T\t\tSet TCP protocol\n\
+\t\t-t port\t\tdestination port\n\
+\t\t-U\t\tSet UDP protocol\n\
+", prog);
+ exit(1);
+}
+
+
+void do_icmp(ip, args)
+ip_t *ip;
+char *args;
+{
+ struct icmp *ic;
+ char *s;
+
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_len += sizeof(*ic);
+ ic = (struct icmp *)(ip + 1);
+ bzero((char *)ic, sizeof(*ic));
+ if (!(s = strchr(args, ',')))
+ {
+ fprintf(stderr, "ICMP args missing: ,\n");
+ return;
+ }
+ *s++ = '\0';
+ ic->icmp_type = atoi(args);
+ ic->icmp_code = atoi(s);
+ if (ic->icmp_type == ICMP_REDIRECT && strchr(s, ','))
+ {
+ char *t;
+
+ t = strtok(s, ",");
+ t = strtok(NULL, ",");
+ if (resolve(t, (char *)&ic->icmp_gwaddr) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", t);
+ exit(2);
+ }
+ if ((t = strtok(NULL, ",")))
+ {
+ if (resolve(t, (char *)&ic->icmp_ip.ip_dst) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", t);
+ exit(2);
+ }
+ if ((t = strtok(NULL, ",")))
+ {
+ if (resolve(t,
+ (char *)&ic->icmp_ip.ip_src) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", t);
+ exit(2);
+ }
+ }
+ }
+ }
+}
+
+
+int send_packets(dev, mtu, ip, gwip)
+char *dev;
+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);
+
+ return send_packet(wfd, mtu, ip, gwip);
+}
+
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ struct tcpiphdr *ti;
+ struct in_addr gwip;
+ tcphdr_t *tcp;
+ ip_t *ip;
+ char *name = argv[0], host[64], *gateway = NULL, *dev = NULL;
+ char *src = NULL, *dst, c, *s;
+ int mtu = 1500, olen = 0;
+
+ /*
+ * 65535 is maximum packet size...you never know...
+ */
+ ip = (ip_t *)calloc(1, 65536);
+ ti = (struct tcpiphdr *)ip;
+ tcp = (tcphdr_t *)&ti->ti_sport;
+ ip->ip_len = sizeof(*ip);
+ ip->ip_hl = sizeof(*ip) >> 2;
+
+ while ((c = getopt(argc, argv, "IP:TUd:f:g:m:o:s:t:")) != -1)
+ switch (c)
+ {
+ case 'I' :
+ if (ip->ip_p)
+ {
+ fprintf(stderr, "Protocol already set: %d\n",
+ ip->ip_p);
+ break;
+ }
+ do_icmp(ip, optarg);
+ break;
+ case 'P' :
+ {
+ struct protoent *p;
+
+ if (ip->ip_p)
+ {
+ fprintf(stderr, "Protocol already set: %d\n",
+ ip->ip_p);
+ break;
+ }
+ if ((p = getprotobyname(optarg)))
+ ip->ip_p = p->p_proto;
+ else
+ fprintf(stderr, "Unknown protocol: %s\n",
+ optarg);
+ break;
+ }
+ case 'T' :
+ if (ip->ip_p)
+ {
+ fprintf(stderr, "Protocol already set: %d\n",
+ ip->ip_p);
+ break;
+ }
+ ip->ip_p = IPPROTO_TCP;
+ ip->ip_len += sizeof(tcphdr_t);
+ break;
+ case 'U' :
+ if (ip->ip_p)
+ {
+ fprintf(stderr, "Protocol already set: %d\n",
+ ip->ip_p);
+ break;
+ }
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_len += sizeof(udphdr_t);
+ break;
+ case 'd' :
+ dev = optarg;
+ break;
+ case 'f' :
+ ip->ip_off = strtol(optarg, NULL, 0);
+ break;
+ case 'g' :
+ gateway = optarg;
+ break;
+ case 'm' :
+ mtu = atoi(optarg);
+ if (mtu < 28)
+ {
+ fprintf(stderr, "mtu must be > 28\n");
+ exit(1);
+ }
+ break;
+ case 'o' :
+ olen = optname(optarg, options);
+ break;
+ case 's' :
+ src = optarg;
+ break;
+ case 't' :
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ tcp->th_dport = htons(atoi(optarg));
+ break;
+ case 'w' :
+ if (ip->ip_p == IPPROTO_TCP)
+ tcp->th_win = atoi(optarg);
+ else
+ fprintf(stderr, "set protocol to TCP first\n");
+ break;
+ default :
+ fprintf(stderr, "Unknown option \"%c\"\n", c);
+ usage(name);
+ }
+
+ if (argc - optind < 2)
+ usage(name);
+ dst = argv[optind++];
+
+ if (!src)
+ {
+ gethostname(host, sizeof(host));
+ src = host;
+ }
+
+ if (resolve(src, (char *)&ip->ip_src) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", src);
+ exit(2);
+ }
+
+ if (resolve(dst, (char *)&ip->ip_dst) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", dst);
+ exit(2);
+ }
+
+ if (!gateway)
+ gwip = ip->ip_dst;
+ else if (resolve(gateway, (char *)&gwip) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", gateway);
+ exit(2);
+ }
+
+ if (ip->ip_p == IPPROTO_TCP)
+ for (s = argv[optind]; (c = *s); s++)
+ switch(c)
+ {
+ case 'S' : case 's' :
+ tcp->th_flags |= TH_SYN;
+ break;
+ case 'A' : case 'a' :
+ tcp->th_flags |= TH_ACK;
+ break;
+ case 'F' : case 'f' :
+ tcp->th_flags |= TH_FIN;
+ break;
+ case 'R' : case 'r' :
+ tcp->th_flags |= TH_RST;
+ break;
+ case 'P' : case 'p' :
+ tcp->th_flags |= TH_PUSH;
+ break;
+ case 'U' : case 'u' :
+ tcp->th_flags |= TH_URG;
+ break;
+ }
+
+ if (!dev)
+ dev = default_device;
+ printf("Device: %s\n", dev);
+ printf("Source: %s\n", inet_ntoa(ip->ip_src));
+ printf("Dest: %s\n", inet_ntoa(ip->ip_dst));
+ printf("Gateway: %s\n", inet_ntoa(gwip));
+ if (ip->ip_p == IPPROTO_TCP && tcp->th_flags)
+ printf("Flags: %#x\n", tcp->th_flags);
+ printf("mtu: %d\n", mtu);
+
+ if (olen)
+ {
+ printf("Options: %d\n", olen);
+ ti = (struct tcpiphdr *)malloc(olen + ip->ip_len);
+ bcopy((char *)ip, (char *)ti, sizeof(*ip));
+ ip = (ip_t *)ti;
+ ip->ip_hl += (olen >> 2);
+ bcopy(options, (char *)(ip + 1), olen);
+ bcopy((char *)tcp, (char *)(ip + 1) + olen, sizeof(*tcp));
+ tcp = (tcphdr_t *)((char *)(ip + 1) + olen);
+ ip->ip_len += olen;
+ }
+
+#ifdef DOSOCKET
+ if (tcp->th_dport)
+ return do_socket(dev, mtu, ti, gwip);
+#endif
+ return send_packets(dev, mtu, ti, gwip);
+}
diff --git a/contrib/ipfilter/ipsend/ipsopt.c b/contrib/ipfilter/ipsend/ipsopt.c
new file mode 100644
index 0000000..75c4f16
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipsopt.c
@@ -0,0 +1,111 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * 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 ?
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <string.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 "ip_compat.h"
+
+struct ipopt_names {
+ int on_value;
+ int on_bit;
+ int on_siz;
+ char *on_name;
+};
+
+struct ipopt_names ionames[] = {
+ { IPOPT_EOL, 0x01, 1, "eol" },
+ { IPOPT_NOP, 0x02, 1, "nop" },
+ { IPOPT_RR, 0x04, 7, "rr" }, /* 1 route */
+ { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */
+ { IPOPT_SECURITY, 0x08, 11, "sec-level" },
+ { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */
+ { IPOPT_SATID, 0x20, 4, "satid" },
+ { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */
+ { 0, 0, 0, NULL } /* must be last */
+};
+
+struct ipopt_names secnames[] = {
+ { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" },
+ { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" },
+ { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" },
+ { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" },
+ { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" },
+ { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" },
+ { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" },
+ { 0, 0, 0, NULL } /* must be last */
+};
+
+
+u_short seclevel(slevel)
+char *slevel;
+{
+ struct ipopt_names *so;
+
+ for (so = secnames; 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 so->on_value;
+}
+
+
+u_long optname(cp, op)
+char *cp, *op;
+{
+ struct ipopt_names *io;
+ u_short lvl;
+ u_long msk = 0;
+ char *s, *t;
+ int len = 0;
+
+ 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 ((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) {
+ *op++ = io->on_siz;
+ *op++ = IPOPT_MINOFF;
+
+ if (t && !strcasecmp(s, "sec-level")) {
+ lvl = seclevel(t);
+ bcopy(&lvl, op, sizeof(lvl));
+ }
+ op += io->on_siz - 3;
+ }
+ 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/ipsend/iptest.c b/contrib/ipfilter/ipsend/iptest.c
new file mode 100644
index 0000000..c5d48fa
--- /dev/null
+++ b/contrib/ipfilter/ipsend/iptest.c
@@ -0,0 +1,211 @@
+/*
+ * ipsend.c (C) 1995 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.
+ *
+ * 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.
+ *
+ * This was written and tested (successfully) on SunOS 4.1.x.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "%W% %G% (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.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>
+#include <netinet/tcpip.h>
+#endif
+#include "ip_compat.h"
+#ifdef linux
+#include <linux/sockios.h>
+#include "tcpip.h"
+#endif
+#include "ipt.h"
+
+
+extern char *optarg;
+extern int optind;
+
+extern int initdevice(), resolve();
+extern int ip_test1(), ip_test2(), ip_test3(), ip_test4(), ip_test5();
+extern int ip_test6(), ip_test7();
+
+char options[68];
+#ifdef linux
+char default_device[] = "eth0";
+#else
+# ifdef sun
+char default_device[] = "le0";
+# else
+# ifdef ultrix
+char default_device[] = "ln0";
+# else
+# ifdef __bsdi__
+char default_device[] = "ef0";
+# else
+char default_device[] = "lan0";
+# endif
+# endif
+# endif
+#endif
+
+
+void usage(prog)
+char *prog;
+{
+ fprintf(stderr, "Usage: %s [options] dest\n\
+\toptions:\n\
+\t\t-d device\tSend out on this device\n\
+\t\t-g gateway\tIP gateway to use if non-local dest.\n\
+\t\t-m mtu\t\tfake MTU to use when sending out\n\
+\t\t-p pointtest\t\n\
+\t\t-s src\t\tsource address for IP packet\n\
+\t\t-1 \t\tPerform test 1 (IP header)\n\
+\t\t-2 \t\tPerform test 2 (IP options)\n\
+\t\t-3 \t\tPerform test 3 (ICMP)\n\
+\t\t-4 \t\tPerform test 4 (UDP)\n\
+\t\t-5 \t\tPerform test 5 (TCP)\n\
+\t\t-6 \t\tPerform test 6 (overlapping fragments)\n\
+\t\t-7 \t\tPerform test 7 (random packets)\n\
+", prog);
+ exit(1);
+}
+
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ struct tcpiphdr *ti;
+ struct in_addr gwip;
+ ip_t *ip;
+ char *name = argv[0], host[64], *gateway = NULL, *dev = NULL;
+ char *src = NULL, *dst, c;
+ int mtu = 1500, tests = 0, pointtest = 0;
+
+ /*
+ * 65535 is maximum packet size...you never know...
+ */
+ ip = (ip_t *)calloc(1, 65536);
+ ti = (struct tcpiphdr *)ip;
+ ip->ip_len = sizeof(*ip);
+ ip->ip_hl = sizeof(*ip) >> 2;
+
+ while ((c = getopt(argc, argv, "1234567IP:TUd:f:g:m:o:p:s:t:")) != -1)
+ switch (c)
+ {
+ case '1' :
+ case '2' :
+ case '3' :
+ case '4' :
+ case '5' :
+ case '6' :
+ case '7' :
+ tests = c - '0';
+ break;
+ case 'd' :
+ dev = optarg;
+ break;
+ case 'g' :
+ gateway = optarg;
+ break;
+ case 'm' :
+ mtu = atoi(optarg);
+ if (mtu < 28)
+ {
+ fprintf(stderr, "mtu must be > 28\n");
+ exit(1);
+ }
+ break;
+ case 'p' :
+ pointtest = atoi(optarg);
+ break;
+ case 's' :
+ src = optarg;
+ break;
+ default :
+ fprintf(stderr, "Unknown option \"%c\"\n", c);
+ usage(name);
+ }
+
+ if (argc - optind < 2 && !tests)
+ usage(name);
+ dst = argv[optind++];
+
+ if (!src)
+ {
+ gethostname(host, sizeof(host));
+ src = host;
+ }
+
+ if (resolve(dst, (char *)&ip->ip_dst) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", dst);
+ exit(2);
+ }
+
+ if (resolve(src, (char *)&ip->ip_src) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", src);
+ exit(2);
+ }
+
+ if (!gateway)
+ gwip = ip->ip_dst;
+ else if (resolve(gateway, (char *)&gwip) == -1)
+ {
+ fprintf(stderr,"Cant resolve %s\n", gateway);
+ exit(2);
+ }
+
+
+ if (!dev)
+ dev = default_device;
+ printf("Device: %s\n", dev);
+ printf("Source: %s\n", inet_ntoa(ip->ip_src));
+ printf("Dest: %s\n", inet_ntoa(ip->ip_dst));
+ printf("Gateway: %s\n", inet_ntoa(gwip));
+ printf("mtu: %d\n", mtu);
+
+ switch (tests)
+ {
+ case 1 :
+ return ip_test1(dev, mtu, ti, gwip, pointtest);
+ case 2 :
+ return ip_test2(dev, mtu, ti, gwip, pointtest);
+ case 3 :
+ return ip_test3(dev, mtu, ti, gwip, pointtest);
+ case 4 :
+ return ip_test4(dev, mtu, ti, gwip, pointtest);
+ case 5 :
+ return ip_test5(dev, mtu, ti, gwip, pointtest);
+ case 6 :
+ return ip_test6(dev, mtu, ti, gwip, pointtest);
+ case 7 :
+ return ip_test7(dev, mtu, ti, gwip, pointtest);
+ default :
+ break;
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/iptests.c b/contrib/ipfilter/ipsend/iptests.c
new file mode 100644
index 0000000..b9da7b2
--- /dev/null
+++ b/contrib/ipfilter/ipsend/iptests.c
@@ -0,0 +1,1296 @@
+/*
+ * (C)opyright 1993, 1994, 1995 by Darren Reed.
+ *
+ * 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 ?
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "%W% %G% (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#if !defined(solaris)
+# define _KERNEL
+# define KERNEL
+# include <sys/file.h>
+# undef _KERNEL
+# undef KERNEL
+# include <nlist.h>
+# include <sys/user.h>
+# include <sys/proc.h>
+#endif
+#include <kvm.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#ifdef sun
+#include <sys/systm.h>
+#include <sys/session.h>
+#endif
+#if BSD >= 199103
+#include <sys/sysctl.h>
+#include <sys/filedesc.h>
+#include <paths.h>
+#endif
+#include <netinet/in_systm.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>
+#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>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include "ip_compat.h"
+#ifdef linux
+#include "tcpip.h"
+#else
+#include <netinet/tcpip.h>
+# if defined(__SVR4) || defined(__svr4__)
+#include <sys/sysmacros.h>
+# endif
+#endif
+
+#define PAUSE() tv.tv_sec = 0; tv.tv_usec = 10000; \
+ (void) select(0, NULL, NULL, NULL, &tv)
+
+extern int send_ip(), send_tcp(), send_udp(), send_icmp(), send_ether();
+extern int initdevice(), kmemcpy();
+extern u_short chksum();
+extern struct tcpcb *find_tcp();
+
+void ip_test1(dev, mtu, ip, gwip, ptest)
+char *dev;
+int mtu;
+ip_t *ip;
+struct in_addr gwip;
+int ptest;
+{
+ struct timeval tv;
+ udphdr_t *u;
+ int nfd, i, len, id = getpid();
+
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_v = 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 *)(ip + 1);
+ u->uh_sport = 1;
+ u->uh_dport = 9;
+ u->uh_sum = 0;
+ u->uh_ulen = sizeof(*u) + 4;
+ ip->ip_len = sizeof(*ip) + u->uh_ulen;
+ len = ip->ip_len;
+ nfd = initdevice(dev, u->uh_sport, 1);
+
+ u->uh_sport = htons(u->uh_sport);
+ u->uh_dport = htons(u->uh_dport);
+ u->uh_ulen = htons(u->uh_ulen);
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Part1: hl < len
+ */
+ ip->ip_id = 0;
+ printf("1.1. sending packets with ip_hl < ip_len\n");
+ for (i = 0; i < ((sizeof(*ip) + u->uh_ulen) >> 2); i++) {
+ ip->ip_hl = i >> 2;
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 2)) {
+ /*
+ * Part2: hl > len
+ */
+ ip->ip_id = 0;
+ printf("1.2. sending packets with ip_hl > ip_len\n");
+ for (; i < ((sizeof(*ip) * 2 + u->uh_ulen) >> 2); i++) {
+ ip->ip_hl = i >> 2;
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 3)) {
+ /*
+ * Part3: v < 4
+ */
+ ip->ip_id = 0;
+ printf("1.3. ip_v < 4\n");
+ ip->ip_hl = sizeof(*ip) >> 2;
+ for (i = 0; i < 4; i++) {
+ ip->ip_v = i;
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 4)) {
+ /*
+ * Part4: v > 4
+ */
+ ip->ip_id = 0;
+ printf("1.4. ip_v > 4\n");
+ for (i = 5; i < 16; i++) {
+ ip->ip_v = i;
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 5)) {
+ /*
+ * Part5: len < packet
+ */
+ ip->ip_id = 0;
+ ip->ip_v = IPVERSION;
+ i = ip->ip_len + 1;
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+ printf("1.5.0 ip_len < packet size (size++, long packets)\n");
+ for (; i < (ntohs(ip->ip_len) * 2); i++) {
+ ip->ip_id = htons(id++);
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum(ip, ip->ip_hl << 2);
+ (void) send_ether(nfd, ip, i, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ printf("1.5.1 ip_len < packet size (ip_len-, short packets)\n");
+ for (i = len; i > 0; i--) {
+ ip->ip_id = htons(id++);
+ ip->ip_len = htons(i);
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum(ip, ip->ip_hl << 2);
+ (void) send_ether(nfd, ip, len, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 6)) {
+ /*
+ * Part6: len > packet
+ */
+ ip->ip_id = 0;
+ printf("1.6.0 ip_len > packet size (increase ip_len)\n");
+ for (i = len + 1; i < (len * 2); i++) {
+ ip->ip_id = htons(id++);
+ ip->ip_len = htons(i);
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum(ip, ip->ip_hl << 2);
+ (void) send_ether(nfd, ip, len, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ ip->ip_len = htons(len);
+ printf("1.6.1 ip_len > packet size (size--, short packets)\n");
+ for (i = len; i > 0; i--) {
+ ip->ip_id = htons(id++);
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum(ip, ip->ip_hl << 2);
+ (void) send_ether(nfd, ip, i, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 7)) {
+ /*
+ * Part7: 0 length fragment
+ */
+ printf("1.7.0 Zero length fragments (ip_off = 0x2000)\n");
+ ip->ip_id = 0;
+ ip->ip_len = sizeof(*ip);
+ ip->ip_off = htons(IP_MF);
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("1.7.1 Zero length fragments (ip_off = 0x3000)\n");
+ ip->ip_id = 0;
+ ip->ip_len = sizeof(*ip);
+ ip->ip_off = htons(IP_MF);
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("1.7.2 Zero length fragments (ip_off = 0xa000)\n");
+ ip->ip_id = 0;
+ ip->ip_len = sizeof(*ip);
+ ip->ip_off = htons(0xa000);
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("1.7.3 Zero length fragments (ip_off = 0x0100)\n");
+ ip->ip_id = 0;
+ ip->ip_len = sizeof(*ip);
+ ip->ip_off = htons(0x0100);
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 8)) {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ srand(tv.tv_sec ^ getpid() ^ tv.tv_usec);
+ /*
+ * Part8.1: 63k packet + 1k fragment at offset 0x1ffe
+ * Mark it as being ICMP (so it doesn't get junked), but
+ * don't bother about the ICMP header, we're not worrying
+ * about that here.
+ */
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_off = IP_MF;
+ u->uh_dport = htons(9);
+ ip->ip_id = htons(id++);
+ printf("1.8.1 63k packet + 1k fragment at offset 0x1ffe\n");
+ ip->ip_len = 768 + 20 + 8;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+
+ ip->ip_len = MIN(768 + 20, mtu - 68);
+ i = 512;
+ for (; i < (63 * 1024 + 768); i += 768) {
+ ip->ip_off = 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 = (i >> 3);
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+ putchar('\n');
+ fflush(stdout);
+
+ /*
+ * Part8.2: 63k packet + 1k fragment at offset 0x1ffe
+ * Mark it as being ICMP (so it doesn't get junked), but
+ * don't bother about the ICMP header, we're not worrying
+ * about that here. (Lossage here)
+ */
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_off = IP_MF;
+ u->uh_dport = htons(9);
+ ip->ip_id = htons(id++);
+ printf("1.8.2 63k packet + 1k fragment at offset 0x1ffe\n");
+ ip->ip_len = 768 + 20 + 8;
+ if ((rand() & 0x1f) != 0) {
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+ } else
+ printf("skip 0\n");
+
+ ip->ip_len = MIN(768 + 20, mtu - 68);
+ i = 512;
+ for (; i < (63 * 1024 + 768); i += 768) {
+ ip->ip_off = IP_MF | (i >> 3);
+ if ((rand() & 0x1f) != 0) {
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+ } else
+ printf("skip %d\n", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ ip->ip_len = 896 + 20;
+ ip->ip_off = (i >> 3);
+ if ((rand() & 0x1f) != 0) {
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+ } else
+ printf("skip\n");
+ putchar('\n');
+ fflush(stdout);
+
+ /*
+ * Part8.3: 33k packet - test for not dealing with -ve length
+ * Mark it as being ICMP (so it doesn't get junked), but
+ * don't bother about the ICMP header, we're not worrying
+ * about that here.
+ */
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_off = IP_MF;
+ u->uh_dport = htons(9);
+ ip->ip_id = htons(id++);
+ printf("1.8.3 33k packet\n");
+ ip->ip_len = 768 + 20 + 8;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+
+ ip->ip_len = MIN(768 + 20, mtu - 68);
+ i = 512;
+ for (; i < (32 * 1024 + 768); i += 768) {
+ ip->ip_off = 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 = (i >> 3);
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+ putchar('\n');
+ fflush(stdout);
+ }
+
+ ip->ip_len = len;
+ ip->ip_off = 0;
+ if (!ptest || (ptest == 9)) {
+ /*
+ * Part9: off & 0x8000 == 0x8000
+ */
+ ip->ip_id = 0;
+ ip->ip_off = 0x8000;
+ printf("1.9. ip_off & 0x8000 == 0x8000\n");
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ ip->ip_off = 0;
+
+ if (!ptest || (ptest == 10)) {
+ /*
+ * Part10: ttl = 255
+ */
+ ip->ip_id = 0;
+ ip->ip_ttl = 255;
+ printf("1.10.0 ip_ttl = 255\n");
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ ip->ip_ttl = 128;
+ printf("1.10.1 ip_ttl = 128\n");
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ ip->ip_ttl = 0;
+ printf("1.10.2 ip_ttl = 0\n");
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ (void) close(nfd);
+}
+
+
+void ip_test2(dev, mtu, ip, gwip, ptest)
+char *dev;
+int mtu;
+ip_t *ip;
+struct in_addr gwip;
+int ptest;
+{
+ struct timeval tv;
+ int nfd;
+ u_char *s;
+
+ s = (u_char *)(ip + 1);
+ nfd = initdevice(dev, 1, 1);
+
+ ip->ip_hl = 6;
+ ip->ip_len = ip->ip_hl << 2;
+ s[IPOPT_OPTVAL] = IPOPT_NOP;
+ s++;
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Test 1: option length > packet length,
+ * header length == packet length
+ */
+ s[IPOPT_OPTVAL] = IPOPT_TS;
+ s[IPOPT_OLEN] = 4;
+ s[IPOPT_OFFSET] = IPOPT_MINOFF;
+ ip->ip_p = IPPROTO_IP;
+ printf("2.1 option length > packet length\n");
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ ip->ip_hl = 7;
+ ip->ip_len = ip->ip_hl << 2;
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Test 2: options have length = 0
+ */
+ printf("2.2.1 option length = 0, RR\n");
+ s[IPOPT_OPTVAL] = IPOPT_RR;
+ s[IPOPT_OLEN] = 0;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("2.2.2 option length = 0, TS\n");
+ s[IPOPT_OPTVAL] = IPOPT_TS;
+ s[IPOPT_OLEN] = 0;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("2.2.3 option length = 0, SECURITY\n");
+ s[IPOPT_OPTVAL] = IPOPT_SECURITY;
+ s[IPOPT_OLEN] = 0;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("2.2.4 option length = 0, LSRR\n");
+ s[IPOPT_OPTVAL] = IPOPT_LSRR;
+ s[IPOPT_OLEN] = 0;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("2.2.5 option length = 0, SATID\n");
+ s[IPOPT_OPTVAL] = IPOPT_SATID;
+ s[IPOPT_OLEN] = 0;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+
+ printf("2.2.6 option length = 0, SSRR\n");
+ s[IPOPT_OPTVAL] = IPOPT_SSRR;
+ s[IPOPT_OLEN] = 0;
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ (void) close(nfd);
+}
+
+
+/*
+ * test 3 (ICMP)
+ */
+void ip_test3(dev, mtu, ip, gwip, ptest)
+char *dev;
+int mtu;
+ip_t *ip;
+struct in_addr gwip;
+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 };
+ struct timeval tv;
+ struct icmp *icp;
+ int nfd, i;
+
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_v = 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, 1, 1);
+
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Type 0 - 31, 255, code = 0
+ */
+ bzero((char *)icp, sizeof(*icp));
+ for (i = 0; i < 32; i++) {
+ icp->icmp_type = i;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.1.%d ICMP type %d code 0 (all 0's)\r", i, i);
+ }
+ icp->icmp_type = 255;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.1.%d ICMP type %d code 0 (all 0's)\r", i, 255);
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 2)) {
+ /*
+ * Type 3, code = 0 - 31
+ */
+ icp->icmp_type = 3;
+ for (i = 0; i < 32; i++) {
+ icp->icmp_code = i;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.2.%d ICMP type 3 code %d (all 0's)\r", i, i);
+ }
+ }
+
+ if (!ptest || (ptest == 3)) {
+ /*
+ * Type 4, code = 0,127,128,255
+ */
+ icp->icmp_type = 4;
+ icp->icmp_code = 0;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.3.1 ICMP type 4 code 0 (all 0's)\r");
+ icp->icmp_code = 127;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.3.2 ICMP type 4 code 127 (all 0's)\r");
+ icp->icmp_code = 128;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.3.3 ICMP type 4 code 128 (all 0's)\r");
+ icp->icmp_code = 255;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.3.4 ICMP type 4 code 255 (all 0's)\r");
+ }
+
+ if (!ptest || (ptest == 4)) {
+ /*
+ * Type 5, code = 0,127,128,255
+ */
+ icp->icmp_type = 5;
+ icp->icmp_code = 0;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.4.1 ICMP type 5 code 0 (all 0's)\r");
+ icp->icmp_code = 127;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.4.2 ICMP type 5 code 127 (all 0's)\r");
+ icp->icmp_code = 128;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.4.3 ICMP type 5 code 128 (all 0's)\r");
+ icp->icmp_code = 255;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.4.4 ICMP type 5 code 255 (all 0's)\r");
+ }
+
+ if (!ptest || (ptest == 5)) {
+ /*
+ * Type 8-10;13-18, code - 0,127,128,255
+ */
+ for (i = 0; ict1[i]; i++) {
+ icp->icmp_type = ict1[i];
+ icp->icmp_code = 0;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type 5 code 0 (all 0's)\r",
+ i * 4);
+ icp->icmp_code = 127;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type 5 code 127 (all 0's)\r",
+ i * 4 + 1);
+ icp->icmp_code = 128;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type 5 code 128 (all 0's)\r",
+ i * 4 + 2);
+ icp->icmp_code = 255;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type 5 code 255 (all 0's)\r",
+ i * 4 + 3);
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 6)) {
+ /*
+ * Type 12, code - 0,127,128,129,255
+ */
+ icp->icmp_type = 12;
+ icp->icmp_code = 0;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.6.1 ICMP type 12 code 0 (all 0's)\r");
+ icp->icmp_code = 127;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.6.2 ICMP type 12 code 127 (all 0's)\r");
+ icp->icmp_code = 128;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.6.3 ICMP type 12 code 128 (all 0's)\r");
+ icp->icmp_code = 129;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.6.4 ICMP type 12 code 129 (all 0's)\r");
+ icp->icmp_code = 255;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.6.5 ICMP type 12 code 255 (all 0's)\r");
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 7)) {
+ /*
+ * Type 3;9-10;13-14;17-18 - shorter packets
+ */
+ ip->ip_len = sizeof(*ip) + sizeof(*icp) / 2;
+ for (i = 0; ict2[i]; i++) {
+ icp->icmp_type = ict1[i];
+ icp->icmp_code = 0;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type %d code 0 (all 0's)\r",
+ i * 4, icp->icmp_type);
+ icp->icmp_code = 127;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type %d code 127 (all 0's)\r",
+ i * 4 + 1, icp->icmp_type);
+ icp->icmp_code = 128;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type %d code 128 (all 0's)\r",
+ i * 4 + 2, icp->icmp_type);
+ icp->icmp_code = 255;
+ (void) send_icmp(nfd, mtu, ip, gwip);
+ PAUSE();
+ printf("3.5.%d ICMP type %d code 127 (all 0's)\r",
+ i * 4 + 3, icp->icmp_type);
+ }
+ putchar('\n');
+ }
+}
+
+
+/* Perform test 4 (UDP) */
+
+void ip_test4(dev, mtu, ip, gwip, ptest)
+char *dev;
+int mtu;
+ip_t *ip;
+struct in_addr gwip;
+int ptest;
+{
+ struct timeval tv;
+ struct udphdr *u;
+ int nfd, i;
+
+
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_v = 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->uh_sport = 1;
+ u->uh_dport = 1;
+ u->uh_ulen = sizeof(*u) + 4;
+ nfd = initdevice(dev, u->uh_sport, 1);
+
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Test 1. ulen > packet
+ */
+ u->uh_ulen = sizeof(*u) + 4;
+ ip->ip_len = (ip->ip_hl << 2) + u->uh_ulen;
+ printf("4.1 UDP uh_ulen > packet size - short packets\n");
+ for (i = u->uh_ulen * 2; i > sizeof(*u) + 4; i--) {
+ u->uh_ulen = i;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 2)) {
+ /*
+ * Test 2. ulen < packet
+ */
+ u->uh_ulen = sizeof(*u) + 4;
+ ip->ip_len = (ip->ip_hl << 2) + u->uh_ulen;
+ printf("4.2 UDP uh_ulen < packet size - short packets\n");
+ for (i = u->uh_ulen * 2; i > sizeof(*u) + 4; i--) {
+ ip->ip_len = i;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 3)) {
+ /*
+ * Test 3: sport = 0, sport = 1, sport = 32767
+ * sport = 32768, sport = 65535
+ */
+ u->uh_ulen = sizeof(*u) + 4;
+ ip->ip_len = (ip->ip_hl << 2) + u->uh_ulen;
+ printf("4.3.1 UDP sport = 0\n");
+ u->uh_sport = 0;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("0\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.3.2 UDP sport = 1\n");
+ u->uh_sport = 1;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("1\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.3.3 UDP sport = 32767\n");
+ u->uh_sport = 32767;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("32767\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.3.4 UDP sport = 32768\n");
+ u->uh_sport = 32768;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("32768\n");
+ putchar('\n');
+ fflush(stdout);
+ PAUSE();
+ printf("4.3.5 UDP sport = 65535\n");
+ u->uh_sport = 65535;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("65535\n");
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 4)) {
+ /*
+ * Test 4: dport = 0, dport = 1, dport = 32767
+ * dport = 32768, dport = 65535
+ */
+ u->uh_ulen = sizeof(*u) + 4;
+ u->uh_sport = 1;
+ ip->ip_len = (ip->ip_hl << 2) + u->uh_ulen;
+ printf("4.4.1 UDP dport = 0\n");
+ u->uh_dport = 0;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("0\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.4.2 UDP dport = 1\n");
+ u->uh_dport = 1;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("1\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.4.3 UDP dport = 32767\n");
+ u->uh_dport = 32767;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("32767\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.4.4 UDP dport = 32768\n");
+ u->uh_dport = 32768;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("32768\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.4.5 UDP dport = 65535\n");
+ u->uh_dport = 65535;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("65535\n");
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 4)) {
+ /*
+ * Test 5: sizeof(struct ip) <= MTU <= sizeof(struct udphdr) +
+ * sizeof(struct ip)
+ */
+ printf("4.5 UDP 20 <= MTU <= 32\n");
+ for (i = sizeof(*ip); i <= u->uh_ulen; i++) {
+ (void) send_udp(nfd, i, ip, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+}
+
+
+/* Perform test 5 (TCP) */
+
+void ip_test5(dev, mtu, ip, gwip, ptest)
+char *dev;
+int mtu;
+ip_t *ip;
+struct in_addr gwip;
+int ptest;
+{
+ struct timeval tv;
+ tcphdr_t *t;
+ int nfd, i;
+
+ t = (tcphdr_t *)((char *)ip + (ip->ip_hl << 2));
+ t->th_x2 = 0;
+ t->th_off = 0;
+ t->th_sport = 1;
+ t->th_dport = 1;
+ t->th_win = 4096;
+ t->th_urp = 0;
+ t->th_sum = 0;
+ t->th_seq = 1;
+ t->th_ack = 0;
+ nfd = initdevice(dev, t->th_sport, 1);
+
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Test 1: flags variations, 0 - 3f
+ */
+ t->th_off = 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++) {
+ t->th_flags = i;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ if (!ptest || (ptest == 2)) {
+ t->th_flags = TH_SYN;
+ /*
+ * Test 2: seq = 0, seq = 1, seq = 0x7fffffff, seq=0x80000000,
+ * seq = 0xa000000, seq = 0xffffffff
+ */
+ printf("5.2.1 TCP seq = 0\n");
+ t->th_seq = 0;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.2 TCP seq = 1\n");
+ t->th_seq = 1;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.3 TCP seq = 0x7fffffff\n");
+ t->th_seq = 0x7fffffff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.4 TCP seq = 0x80000000\n");
+ t->th_seq = 0x80000000;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.5 TCP seq = 0xc0000000\n");
+ t->th_seq = 0xc0000000;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.6 TCP seq = 0xffffffff\n");
+ t->th_seq = 0xffffffff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 3)) {
+ t->th_flags = TH_ACK;
+ /*
+ * Test 3: ack = 0, ack = 1, ack = 0x7fffffff, ack = 0x8000000
+ * ack = 0xa000000, ack = 0xffffffff
+ */
+ printf("5.3.1 TCP ack = 0\n");
+ t->th_ack = 0;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.2 TCP ack = 1\n");
+ t->th_ack = 1;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.3 TCP ack = 0x7fffffff\n");
+ t->th_ack = 0x7fffffff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.4 TCP ack = 0x80000000\n");
+ t->th_ack = 0x80000000;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.5 TCP ack = 0xc0000000\n");
+ t->th_ack = 0xc0000000;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.6 TCP ack = 0xffffffff\n");
+ t->th_ack = 0xffffffff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 4)) {
+ t->th_flags = TH_SYN;
+ /*
+ * Test 4: win = 0, win = 32768, win = 65535
+ */
+ printf("5.4.1 TCP win = 0\n");
+ t->th_seq = 0;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.4.2 TCP win = 32768\n");
+ t->th_seq = 0x7fff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.4.3 TCP win = 65535\n");
+ t->th_win = 0xffff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+
+#if !defined(linux) && !defined(__SVR4) && !defined(__svr4__)
+ {
+ struct tcpcb *t, tcb;
+ struct tcpiphdr ti;
+ struct sockaddr_in sin;
+ int fd, slen;
+
+ bzero((char *)&sin, sizeof(sin));
+
+ for (i = 1; i < 63; i++) {
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ sin.sin_addr.s_addr = ip->ip_dst.s_addr;
+ sin.sin_port = htons(i);
+ if (!connect(fd, (struct sockaddr *)&sin, sizeof(sin)))
+ break;
+ }
+
+ if (i == 63) {
+ printf("Couldn't open a TCP socket between ports 1 and 63\n");
+ printf("to host %s for test 5 and 6 - skipping.\n",
+ inet_ntoa(ip->ip_dst));
+ goto skip_five_and_six;
+ }
+
+ bcopy((char *)ip, (char *)&ti, sizeof(*ip));
+ ti.ti_dport = i;
+ slen = sizeof(sin);
+ if (!getsockname(fd, (struct sockaddr *)&sin, &slen))
+ ti.ti_sport = sin.sin_port;
+ if (!(t = find_tcp(fd, &ti))) {
+ printf("Can't find PCB\n");
+ goto skip_five_and_six;
+ }
+ kmemcpy((char*)&tcb, (void *)t, sizeof(tcb));
+ ti.ti_win = tcb.rcv_adv;
+ ti.ti_seq = tcb.snd_nxt - 1;
+ ti.ti_ack = tcb.rcv_nxt;
+
+ if (!ptest || (ptest == 5)) {
+ /*
+ * Test 5: urp
+ */
+ printf("5.1 TCP Urgent pointer\n");
+ ti.ti_urp = 1;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+ ti.ti_urp = 0x7fff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+ ti.ti_urp = 0x8000;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+ ti.ti_urp = 0xffff;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 6)) {
+ /*
+ * Test 6: data offset, off = 0, off is inside, off is outside
+ */
+ printf("6.1 TCP off = 0-15, len = 40\n");
+ for (i = 0; i < 16; i++) {
+ ti.ti_off = ntohs(i);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ }
+
+ (void) close(fd);
+ }
+skip_five_and_six:
+#endif
+ t->th_seq = 1;
+ t->th_ack = 1;
+
+ if (!ptest || (ptest == 7)) {
+ t->th_off = 0;
+ t->th_flags = TH_SYN;
+ /*
+ * Test 7: sport = 0, sport = 1, sport = 32767
+ * sport = 32768, sport = 65535
+ */
+ printf("5.7.1 TCP sport = 0\n");
+ t->th_sport = 0;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.7.2 TCP sport = 1\n");
+ t->th_sport = 1;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.7.3 TCP sport = 32767\n");
+ t->th_sport = 32767;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.7.4 TCP sport = 32768\n");
+ t->th_sport = 32768;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.7.5 TCP sport = 65535\n");
+ t->th_sport = 65535;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 8)) {
+ t->th_sport = 1;
+ /*
+ * Test 8: dport = 0, dport = 1, dport = 32767
+ * dport = 32768, dport = 65535
+ */
+ printf("5.8.1 TCP dport = 0\n");
+ t->th_dport = 0;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.8.2 TCP dport = 1\n");
+ t->th_dport = 1;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.8.3 TCP dport = 32767\n");
+ t->th_dport = 32767;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.8.4 TCP dport = 32768\n");
+ t->th_dport = 32768;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.8.5 TCP dport = 65535\n");
+ t->th_dport = 65535;
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+ /* TCP options header checking */
+ /* 0 length options, etc */
+}
+
+
+/* Perform test 6 (exhaust mbuf test) */
+
+void ip_test6(dev, mtu, ip, gwip, ptest)
+char *dev;
+int mtu;
+ip_t *ip;
+struct in_addr gwip;
+int ptest;
+{
+ struct timeval tv;
+ udphdr_t *u;
+ int nfd, i, j, k;
+
+ ip->ip_v = 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 *)(ip + 1);
+ u->uh_sport = 1;
+ u->uh_dport = 9;
+ u->uh_sum = 0;
+
+ nfd = initdevice(dev, u->uh_sport, 1);
+ u->uh_sport = htons(u->uh_sport);
+ u->uh_dport = htons(u->uh_dport);
+ u->uh_ulen = 7168;
+
+ for (i = 0; i < 128; i++) {
+ /*
+ * First send the entire packet in 768 byte chunks.
+ */
+ ip->ip_len = sizeof(*ip) + 768 + sizeof(*u);
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_off = IP_MF;
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d %d\r", i, 0);
+ fflush(stdout);
+ PAUSE();
+ /*
+ * And again using 128 byte chunks.
+ */
+ ip->ip_len = sizeof(*ip) + 128 + sizeof(*u);
+ ip->ip_off = IP_MF;
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d %d\r", i, 0);
+ fflush(stdout);
+ PAUSE();
+
+ for (j = 768; j < 3584; j += 768) {
+ ip->ip_len = sizeof(*ip) + 768;
+ ip->ip_off = IP_MF|(j>>3);
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d %d\r", i, j);
+ fflush(stdout);
+ PAUSE();
+
+ ip->ip_len = sizeof(*ip) + 128;
+ for (k = j - 768; k < j; k += 128) {
+ ip->ip_off = IP_MF|(k>>3);
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d %d\r", i, k);
+ fflush(stdout);
+ PAUSE();
+ }
+ }
+ }
+ putchar('\n');
+}
+
+
+/* Perform test 7 (random packets) */
+
+static u_long tbuf[64];
+
+void ip_test7(dev, mtu, ip, gwip, ptest)
+char *dev;
+int mtu;
+ip_t *ip;
+struct in_addr gwip;
+int ptest;
+{
+ ip_t *pip;
+ struct timeval tv;
+ int nfd, i, j;
+ u_char *s;
+
+ nfd = initdevice(dev, 0, 1);
+ pip = (ip_t *)tbuf;
+
+ srand(time(NULL) ^ (getpid() * getppid()));
+
+ printf("7. send 1024 random IP packets.\n");
+
+ 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;
+ bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst,
+ sizeof(struct in_addr));
+ pip->ip_sum = 0;
+ pip->ip_len &= 0xff;
+ (void) send_ip(nfd, mtu, pip, gwip, 0);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+
+ 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;
+ pip->ip_off &= 0xc000;
+ bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst,
+ sizeof(struct in_addr));
+ pip->ip_sum = 0;
+ pip->ip_len &= 0xff;
+ (void) send_ip(nfd, mtu, pip, gwip, 0);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+}
diff --git a/contrib/ipfilter/ipsend/larp.c b/contrib/ipfilter/ipsend/larp.c
new file mode 100644
index 0000000..1eb4b2f
--- /dev/null
+++ b/contrib/ipfilter/ipsend/larp.c
@@ -0,0 +1,85 @@
+/*
+ * larp.c (C) 1995 Darren Reed
+ *
+ * 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.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)larp.c 1.1 8/19/95 (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <errno.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>
+
+/*
+ * lookup host and return
+ * its IP address in address
+ * (4 bytes)
+ */
+int resolve(host, address)
+char *host, *address;
+{
+ struct hostent *hp;
+ u_long add;
+
+ add = inet_addr(host);
+ if (add == -1)
+ {
+ if (!(hp = gethostbyname(host)))
+ {
+ fprintf(stderr, "unknown host: %s\n", host);
+ return -1;
+ }
+ bcopy((char *)hp->h_addr, (char *)address, 4);
+ return 0;
+ }
+ bcopy((char*)&add, address, 4);
+ return 0;
+}
+
+/*
+ * ARP for the MAC address corresponding
+ * to the IP address. This taken from
+ * some BSD program, I cant remember which.
+ */
+int arp(ip, ether)
+char *ip;
+char *ether;
+{
+ static int s = -1;
+ struct arpreq ar;
+ struct sockaddr_in *sin;
+ char *inet_ntoa();
+
+ bzero((char *)&ar, sizeof(ar));
+ sin = (struct sockaddr_in *)&ar.arp_pa;
+ sin->sin_family = AF_INET;
+ bcopy(ip, (char *)&sin->sin_addr.s_addr, 4);
+
+ if (s == -1)
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ {
+ perror("arp: socket");
+ return -1;
+ }
+
+ if (ioctl(s, SIOCGARP, (caddr_t)&ar) == -1)
+ {
+ fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr));
+ if (errno != ENXIO)
+ perror("SIOCGARP");
+ return -1;
+ }
+
+ bcopy(ar.arp_ha.sa_data, ether, 6);
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/linux.h b/contrib/ipfilter/ipsend/linux.h
new file mode 100644
index 0000000..7eb382b
--- /dev/null
+++ b/contrib/ipfilter/ipsend/linux.h
@@ -0,0 +1,17 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * 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
+ */
+
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
+
+#include "ip_compat.h"
diff --git a/contrib/ipfilter/ipsend/lsock.c b/contrib/ipfilter/ipsend/lsock.c
new file mode 100644
index 0000000..89b6ab7
--- /dev/null
+++ b/contrib/ipfilter/ipsend/lsock.c
@@ -0,0 +1,261 @@
+/*
+ * lsock.c (C) 1995 Darren Reed
+ *
+ * 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.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)lsock.c 1.2 1/11/96 (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/dir.h>
+#define __KERNEL__
+#if LINUX >= 0200
+# undef UINT_MAX
+# undef INT_MAX
+# undef ULONG_MAX
+# undef LONG_MAX
+# include <linux/notifier.h>
+#endif
+#include <linux/fs.h>
+#if LINUX >= 0200
+#include "linux/netdevice.h"
+#include "net/sock.h"
+#endif
+#undef __KERNEL__
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <nlist.h>
+#include <sys/user.h>
+#include <sys/socket.h>
+#include <math.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <net/if.h>
+#if LINUX < 0103
+#include <net/inet/sock.h>
+#endif
+#include "ip_compat.h"
+#include "tcpip.h"
+
+int nproc;
+struct task_struct *proc;
+
+#ifndef KMEM
+# ifdef _PATH_KMEM
+# define KMEM _PATH_KMEM
+# endif
+#endif
+#ifndef KMEM
+# define KMEM "/dev/kmem"
+#endif
+#ifndef KERNEL
+# define KERNEL "/System.map"
+#endif
+
+int kmemcpy(buf, pos, n)
+char *buf;
+void *pos;
+int n;
+{
+ static int kfd = -1;
+
+ if (kfd == -1)
+ kfd = open(KMEM, O_RDONLY);
+
+ if (lseek(kfd, (off_t)pos, SEEK_SET) == -1)
+ {
+ perror("lseek");
+ return -1;
+ }
+ if (read(kfd, buf, n) == -1)
+ {
+ perror("read");
+ return -1;
+ }
+ return n;
+}
+
+struct nlist names[3] = {
+ { "_task" },
+ { "_nr_tasks" },
+ { NULL }
+ };
+
+struct task_struct *getproc()
+{
+ struct task_struct *p, **pp;
+ void *v;
+ pid_t pid = getpid();
+ int siz, n;
+
+ n = nlist(KERNEL, names);
+ if (n != 0)
+ {
+ fprintf(stderr, "nlist(%#x) == %d\n", names, n);
+ return NULL;
+ }
+ if (kmemcpy((char *)&nproc, (void *)names[1].n_value,
+ sizeof(nproc)) == -1)
+ {
+ fprintf(stderr, "read nproc (%#x)\n", names[1].n_value);
+ return NULL;
+ }
+ siz = nproc * sizeof(struct task_struct *);
+ if (kmemcpy((char *)&v, (void *)names[0].n_value, sizeof(v)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) proc\n",
+ names[0].n_value, &v, sizeof(v));
+ return NULL;
+ }
+ pp = (struct task_struct **)malloc(siz);
+ if (kmemcpy((char *)pp, (void *)v, siz) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) proc\n",
+ v, pp, siz);
+ return NULL;
+ }
+ proc = (struct task_struct *)malloc(siz);
+ for (n = 0; n < NR_TASKS; n++)
+ {
+ if (kmemcpy((char *)(proc + n), (void *)pp[n],
+ sizeof(*proc)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) proc\n",
+ pp[n], proc + n, sizeof(*proc));
+ return NULL;
+ }
+ }
+
+ p = proc;
+
+ for (n = NR_TASKS; n; n--, p++)
+ if (p->pid == pid)
+ break;
+ if (!n)
+ return NULL;
+
+ return p;
+}
+
+
+struct sock *find_tcp(fd, ti)
+int fd;
+struct tcpiphdr *ti;
+{
+ struct sock *s;
+ struct inode *i;
+ struct files_struct *fs;
+ struct task_struct *p;
+ struct file *f, **o;
+
+ if (!(p = getproc()))
+ return NULL;
+
+ fs = p->files;
+ o = (struct file **)calloc(1, sizeof(*o) * (fs->count + 1));
+ if (kmemcpy((char *)o, (void *)fs->fd,
+ (fs->count + 1) * sizeof(*o)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - fd - failed\n",
+ fs->fd, o, sizeof(*o));
+ return NULL;
+ }
+ f = (struct file *)calloc(1, sizeof(*f));
+ if (kmemcpy((char *)f, (void *)o[fd], sizeof(*f)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - o[fd] - failed\n",
+ o[fd], f, sizeof(*f));
+ return NULL;
+ }
+
+ i = (struct inode *)calloc(1, sizeof(*i));
+ if (kmemcpy((char *)i, (void *)f->f_inode, sizeof(*i)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - f_inode - failed\n",
+ f->f_inode, i, sizeof(*i));
+ return NULL;
+ }
+ return i->u.socket_i.data;
+}
+
+int do_socket(dev, mtu, ti, gwip, flags)
+char *dev;
+int mtu;
+struct tcpiphdr *ti;
+struct in_addr gwip;
+int flags;
+{
+ struct sockaddr_in rsin, lsin;
+ struct sock *s, sk;
+ int fd, nfd, len;
+
+ printf("Dest. Port: %d\n", ti->ti_dport);
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ {
+ perror("socket");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, FNDELAY) == -1)
+ {
+ perror("fcntl");
+ return -1;
+ }
+
+ bzero((char *)&lsin, sizeof(lsin));
+ lsin.sin_family = AF_INET;
+ bcopy((char *)&ti->ti_src, (char *)&lsin.sin_addr,
+ sizeof(struct in_addr));
+ if (bind(fd, (struct sockaddr *)&lsin, sizeof(lsin)) == -1)
+ {
+ perror("bind");
+ return -1;
+ }
+ len = sizeof(lsin);
+ (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));
+
+ if (!(s = find_tcp(fd, ti)))
+ return -1;
+
+ bzero((char *)&rsin, sizeof(rsin));
+ rsin.sin_family = AF_INET;
+ bcopy((char *)&ti->ti_dst, (char *)&rsin.sin_addr,
+ sizeof(struct in_addr));
+ rsin.sin_port = ti->ti_dport;
+ if (connect(fd, (struct sockaddr *)&rsin, sizeof(rsin)) == -1 &&
+ errno != EINPROGRESS)
+ {
+ perror("connect");
+ return -1;
+ }
+ kmemcpy((char*)&sk, (void *)s, sizeof(sk));
+ ti->ti_win = sk.window;
+ ti->ti_seq = sk.sent_seq - 1;
+ ti->ti_ack = sk.rcv_ack_seq;
+
+ if (send_tcp(nfd, mtu, ti, gwip, TH_SYN) == -1)
+ return -1;
+ (void)write(fd, "Hello World\n", 12);
+ sleep(2);
+ close(fd);
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/resend.c b/contrib/ipfilter/ipsend/resend.c
new file mode 100644
index 0000000..59ed75e
--- /dev/null
+++ b/contrib/ipfilter/ipsend/resend.c
@@ -0,0 +1,130 @@
+/*
+ * resend.c (C) 1995 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.
+ *
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <net/if.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>
+#include <netinet/tcpip.h>
+#include <netinet/if_ether.h>
+#endif
+#include "ip_compat.h"
+#ifdef linux
+#include <linux/sockios.h>
+#include "tcpip.h"
+#endif
+#include "ipt.h"
+
+
+static u_char buf[65536]; /* 1 big packet */
+
+extern int initdevice(), arp(), sendip();
+
+void printpacket(ip)
+ip_t *ip;
+{
+ tcphdr_t *t;
+ int i, j;
+
+ t = (tcphdr_t *)((char *)ip + (ip->ip_hl << 2));
+ if (ip->ip_tos)
+ printf("tos %#x ", ip->ip_tos);
+ if (ip->ip_off & 0x3fff)
+ printf("frag @%#x ", (ip->ip_off & 0x1fff) << 3);
+ printf("len %d id %d ", ip->ip_len, ip->ip_id);
+ printf("ttl %d p %d src %s", ip->ip_ttl, ip->ip_p,
+ inet_ntoa(ip->ip_src));
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ printf(",%d", t->th_sport);
+ printf(" dst %s", inet_ntoa(ip->ip_dst));
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ printf(",%d", t->th_dport);
+ if (ip->ip_p == IPPROTO_TCP) {
+ printf(" seq %lu:%lu flags ",
+ (u_long)t->th_seq, (u_long)t->th_ack);
+ for (j = 0, i = 1; i < 256; i *= 2, j++)
+ if (t->th_flags & i)
+ printf("%c", "FSRPAU--"[j]);
+ }
+ putchar('\n');
+}
+
+
+int ip_resend(dev, mtu, r, gwip, datain)
+char *dev;
+int mtu;
+struct in_addr gwip;
+struct ipread *r;
+char *datain;
+{
+ ether_header_t *eh;
+ char dhost[6];
+ ip_t *ip;
+ int fd, wfd = initdevice(dev, 0, 5), len, i;
+
+ if (datain)
+ fd = (*r->r_open)(datain);
+ else
+ fd = (*r->r_open)("-");
+
+ if (fd < 0)
+ exit(-1);
+
+ ip = (struct ip *)buf;
+ eh = (ether_header_t *)malloc(sizeof(*eh));
+
+ bzero(&eh->ether_shost, sizeof(eh->ether_shost));
+ if (gwip.s_addr && (arp((char *)&gwip, dhost) == -1))
+ {
+ perror("arp");
+ return -2;
+ }
+
+ while ((i = (*r->r_readip)(buf, sizeof(buf), NULL, NULL)) > 0)
+ {
+ len = ntohs(ip->ip_len);
+ eh = (ether_header_t *)realloc((char *)eh, sizeof(*eh) + len);
+ eh->ether_type = htons((u_short)ETHERTYPE_IP);
+ if (!gwip.s_addr) {
+ if (arp((char *)&gwip,
+ (char *)&eh->ether_dhost) == -1) {
+ perror("arp");
+ continue;
+ }
+ } else
+ bcopy(dhost, (char *)&eh->ether_dhost, sizeof(dhost));
+ bcopy(ip, (char *)(eh + 1), len);
+ printpacket(ip);
+
+ if (sendip(wfd, eh, sizeof(*eh) + len) == -1)
+ {
+ perror("send_packet");
+ break;
+ }
+ }
+ (*r->r_close)();
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/sbpf.c b/contrib/ipfilter/ipsend/sbpf.c
new file mode 100644
index 0000000..5eb9d9b
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sbpf.c
@@ -0,0 +1,136 @@
+/*
+ * (C)opyright October 1995 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ */
+#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/mbuf.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if BSD < 199103
+#include <sys/fcntlcom.h>
+#endif
+#include <sys/dir.h>
+#include <net/bpf.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 <netinet/tcpip.h>
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sbpf[] = "@(#)sbpf.c 1.3 8/25/95 (C)1995 Darren Reed";
+#endif
+
+/*
+ * the code herein is dervied from libpcap.
+ */
+static u_char *buf = NULL;
+static int bufsize = 0, timeout = 1;
+
+
+int initdevice(device, sport, tout)
+char *device;
+int sport, tout;
+{
+ struct bpf_version bv;
+ struct timeval to;
+ struct ifreq ifr;
+ char bpfname[16];
+ int fd, i;
+
+ for (i = 0; i < 16; i++)
+ {
+ (void) sprintf(bpfname, "/dev/bpf%d", i);
+ if ((fd = open(bpfname, O_RDWR)) >= 0)
+ break;
+ }
+ if (i == 16)
+ {
+ fprintf(stderr, "no bpf devices available as /dev/bpfxx\n");
+ return -1;
+ }
+
+ if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0)
+ {
+ perror("BIOCVERSION");
+ return -1;
+ }
+ if (bv.bv_major != BPF_MAJOR_VERSION ||
+ bv.bv_minor < BPF_MINOR_VERSION)
+ {
+ fprintf(stderr, "kernel bpf (v%d.%d) filter out of date:\n",
+ bv.bv_major, bv.bv_minor);
+ fprintf(stderr, "current version: %d.%d\n",
+ BPF_MAJOR_VERSION, BPF_MINOR_VERSION);
+ return -1;
+ }
+
+ (void) strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, &ifr) == -1)
+ {
+ fprintf(stderr, "%s(%d):", ifr.ifr_name, fd);
+ perror("BIOCSETIF");
+ exit(1);
+ }
+ /*
+ * get kernel buffer size
+ */
+ if (ioctl(fd, BIOCGBLEN, &bufsize) == -1)
+ {
+ perror("BIOCSBLEN");
+ exit(-1);
+ }
+ buf = (u_char*)malloc(bufsize);
+ /*
+ * set the timeout
+ */
+ timeout = tout;
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ if (ioctl(fd, BIOCSRTIMEOUT, (caddr_t)&to) == -1)
+ {
+ perror("BIOCSRTIMEOUT");
+ exit(-1);
+ }
+
+ (void) ioctl(fd, BIOCFLUSH, 0);
+ return fd;
+}
+
+
+/*
+ * output an IP packet onto a fd opened for /dev/bpf
+ */
+int sendip(fd, pkt, len)
+int fd, len;
+char *pkt;
+{
+ if (write(fd, pkt, len) == -1)
+ {
+ perror("send");
+ return -1;
+ }
+
+ return len;
+}
diff --git a/contrib/ipfilter/ipsend/sdlpi.c b/contrib/ipfilter/ipsend/sdlpi.c
new file mode 100644
index 0000000..eabd61e
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sdlpi.c
@@ -0,0 +1,130 @@
+/*
+ * (C)opyright October 1992 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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 <netdb.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/stropts.h>
+
+#include <sys/pfmod.h>
+#include <sys/bufmod.h>
+#include <sys/dlpi.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 <netinet/tcpip.h>
+
+#include "ip_compat.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char snitid[] = "@(#)sdlpi.c 1.3 10/30/95 (C)1995 Darren Reed";
+#endif
+
+#define CHUNKSIZE 8192
+#define BUFSPACE (4*CHUNKSIZE)
+
+
+/*
+ * 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)
+char *device;
+int sport, tout;
+{
+ char devname[16], *s, buf[256];
+ int i, fd;
+
+ (void) sprintf(devname, "/dev/%s", device);
+
+ s = devname + 5;
+ while (*s && !isdigit(*s))
+ s++;
+ if (!*s)
+ {
+ fprintf(stderr, "bad device name %s\n", devname);
+ exit(-1);
+ }
+ i = atoi(s);
+ *s = '\0';
+ /*
+ * For writing
+ */
+ if ((fd = open(devname, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "O_RDWR(1) ");
+ perror(devname);
+ exit(-1);
+ }
+
+ if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1)
+ {
+ fprintf(stderr, "DLPI error\n");
+ exit(-1);
+ }
+ dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0);
+ dlbindack(fd, buf);
+ /*
+ * write full headers
+ */
+ if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1)
+ {
+ fprintf(stderr, "DLIOCRAW error\n");
+ exit(-1);
+ }
+ return fd;
+}
+
+
+/*
+ * output an IP packet onto a fd opened for /dev/nit
+ */
+int sendip(fd, pkt, len)
+int fd, len;
+char *pkt;
+{
+ struct strbuf dbuf, *dp = &dbuf;
+
+ /*
+ * construct NIT STREAMS messages, first control then data.
+ */
+ dp->buf = pkt;
+ dp->len = len;
+ dp->maxlen = dp->len;
+
+ if (putmsg(fd, NULL, dp, 0) == -1)
+ {
+ perror("putmsg");
+ return -1;
+ }
+ if (ioctl(fd, I_FLUSH, FLUSHW) == -1)
+ {
+ perror("I_FLUSHW");
+ return -1;
+ }
+ return len;
+}
diff --git a/contrib/ipfilter/ipsend/slinux.c b/contrib/ipfilter/ipsend/slinux.c
new file mode 100644
index 0000000..1767dfe
--- /dev/null
+++ b/contrib/ipfilter/ipsend/slinux.c
@@ -0,0 +1,94 @@
+/*
+ * (C)opyright October 1992 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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 <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/dir.h>
+#include <linux/netdevice.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include "ip_compat.h"
+#include "tcpip.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)slinux.c 1.2 8/25/95";
+#endif
+
+#define CHUNKSIZE 8192
+#define BUFSPACE (4*CHUNKSIZE)
+
+/*
+ * Be careful to only include those defined in the flags option for the
+ * interface are included in the header size.
+ */
+
+static int timeout;
+static char *eth_dev = NULL;
+
+
+int initdevice(dev, sport, tout)
+char *dev;
+int sport, tout;
+{
+ int fd;
+
+ eth_dev = strdup(dev);
+ if ((fd = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_IP))) == -1)
+ {
+ perror("socket(SOCK_PACKET)");
+ exit(-1);
+ }
+
+ return fd;
+}
+
+
+/*
+ * output an IP packet onto a fd opened for /dev/nit
+ */
+int sendip(fd, pkt, len)
+int fd, len;
+char *pkt;
+{
+ struct sockaddr s;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, eth_dev, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1)
+ {
+ perror("SIOCGIFHWADDR");
+ return -1;
+ }
+ bcopy(ifr.ifr_hwaddr.sa_data, pkt + 6, 6);
+ s.sa_family = ETHERTYPE_IP;
+ strncpy(s.sa_data, eth_dev, sizeof(s.sa_data));
+
+ if (sendto(fd, pkt, len, 0, &s, sizeof(s)) == -1)
+ {
+ perror("send");
+ return -1;
+ }
+
+ return len;
+}
diff --git a/contrib/ipfilter/ipsend/snit.c b/contrib/ipfilter/ipsend/snit.c
new file mode 100644
index 0000000..d022192
--- /dev/null
+++ b/contrib/ipfilter/ipsend/snit.c
@@ -0,0 +1,160 @@
+/*
+ * (C)opyright October 1992 Darren Reed. (from tcplog)
+ *
+ * This software may be freely distributed as long as it is not altered
+ * in any way and that this messagge always accompanies it.
+ *
+ * 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 <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <net/nit.h>
+#include <sys/fcntlcom.h>
+#include <sys/dir.h>
+#include <net/nit_if.h>
+#include <net/nit_pf.h>
+#include <net/nit_buf.h>
+#include <net/packetfilt.h>
+#include <sys/stropts.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 <netinet/tcpip.h>
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char snitid[] = "@(#)snit.c 1.5 1/11/96 (C)1995 Darren Reed";
+#endif
+
+#define CHUNKSIZE 8192
+#define BUFSPACE (4*CHUNKSIZE)
+
+/*
+ * Be careful to only include those defined in the flags option for the
+ * interface are included in the header size.
+ */
+#define BUFHDR_SIZE (sizeof(struct nit_bufhdr))
+#define NIT_HDRSIZE (BUFHDR_SIZE)
+
+static int timeout;
+
+
+int initdevice(device, sport, tout)
+char *device;
+int sport, tout;
+{
+ struct strioctl si;
+ struct timeval to;
+ struct ifreq ifr;
+ int fd;
+
+ if ((fd = open("/dev/nit", O_RDWR)) < 0)
+ {
+ perror("/dev/nit");
+ exit(-1);
+ }
+
+ /*
+ * arrange to get messages from the NIT STREAM and use NIT_BUF option
+ */
+ ioctl(fd, I_SRDOPT, (char*)RMSGD);
+ ioctl(fd, I_PUSH, "nbuf");
+
+ /*
+ * set the timeout
+ */
+ timeout = tout;
+ si.ic_timout = 1;
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ si.ic_cmd = NIOCSTIME;
+ si.ic_len = sizeof(to);
+ si.ic_dp = (char*)&to;
+ if (ioctl(fd, I_STR, (char*)&si) == -1)
+ {
+ perror("ioctl: NIT timeout");
+ exit(-1);
+ }
+
+ /*
+ * request the interface
+ */
+ strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = ' ';
+ si.ic_cmd = NIOCBIND;
+ si.ic_len = sizeof(ifr);
+ si.ic_dp = (char*)&ifr;
+ if (ioctl(fd, I_STR, (char*)&si) == -1)
+ {
+ perror(ifr.ifr_name);
+ exit(1);
+ }
+ return fd;
+}
+
+
+/*
+ * output an IP packet onto a fd opened for /dev/nit
+ */
+int sendip(fd, pkt, len)
+int fd, len;
+char *pkt;
+{
+ struct sockaddr sk, *sa = &sk;
+ struct strbuf cbuf, *cp = &cbuf, dbuf, *dp = &dbuf;
+
+ /*
+ * For ethernet, need at least 802.3 header and IP header.
+ */
+ if (len < (sizeof(sa->sa_data) + sizeof(struct ip)))
+ return -1;
+ /*
+ * to avoid any output processing for IP, say we're not.
+ */
+ sa->sa_family = AF_UNSPEC;
+ bcopy(pkt, sa->sa_data, sizeof(sa->sa_data));
+ pkt += sizeof(sa->sa_data);
+ len -= sizeof(sa->sa_data);
+
+ /*
+ * construct NIT STREAMS messages, first control then data.
+ */
+ cp->len = sizeof(*sa);
+ cp->maxlen = sizeof(*sa);
+ cp->buf = (char *)sa;
+
+ dp->buf = pkt;
+ dp->len = len;
+ dp->maxlen = dp->len;
+
+ if (putmsg(fd, cp, dp, 0) == -1)
+ {
+ perror("putmsg");
+ return -1;
+ }
+
+ if (ioctl(fd, I_FLUSH, FLUSHW) == -1)
+ {
+ perror("I_FLUSH");
+ return -1;
+ }
+ return len;
+}
diff --git a/contrib/ipfilter/ipsend/sock.c b/contrib/ipfilter/ipsend/sock.c
new file mode 100644
index 0000000..58949c5
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sock.c
@@ -0,0 +1,370 @@
+/*
+ * sock.c (C) 1995 Darren Reed
+ *
+ * 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.
+ */
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)sock.c 1.2 1/11/96 (C)1995 Darren Reed";
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/dir.h>
+#define _KERNEL
+#define KERNEL
+#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>
+#include <kvm.h>
+#ifdef sun
+#include <sys/systm.h>
+#include <sys/session.h>
+#endif
+#if BSD >= 199103
+#include <sys/sysctl.h>
+#include <sys/filedesc.h>
+#include <paths.h>
+#endif
+#include <math.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#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 <netinet/tcpip.h>
+
+int nproc;
+struct proc *proc;
+
+extern int initdevice(), send_tcp();
+
+#ifndef KMEM
+# ifdef _PATH_KMEM
+# define KMEM _PATH_KMEM
+# endif
+#endif
+#ifndef KERNEL
+# ifdef _PATH_UNIX
+# define KERNEL _PATH_UNIX
+# endif
+#endif
+#ifndef KMEM
+# define KMEM "/dev/kmem"
+#endif
+#ifndef KERNEL
+# define KERNEL "/vmunix"
+#endif
+
+int kmemcpy(buf, pos, n)
+char *buf;
+off_t pos;
+int n;
+{
+ static int kfd = -1;
+
+ if (kfd == -1)
+ kfd = open(KMEM, O_RDONLY);
+
+ if (lseek(kfd, pos, SEEK_SET) == -1)
+ {
+ perror("lseek");
+ return -1;
+ }
+ if (read(kfd, buf, n) == -1)
+ {
+ perror("read");
+ return -1;
+ }
+ return n;
+}
+
+struct nlist names[3] = {
+ { "_proc" },
+ { "_nproc" },
+ { NULL }
+ };
+
+#if BSD < 199103
+struct proc *getproc()
+{
+ struct proc *p;
+ pid_t pid = getpid();
+ int siz, n;
+
+ n = nlist(KERNEL, names);
+ if (n != 0)
+ {
+ fprintf(stderr, "nlist(%#x) == %d\n", names, n);
+ return NULL;
+ }
+ if (kmemcpy((char *)&nproc, (off_t)names[1].n_value,
+ sizeof(nproc)) == -1)
+ {
+ fprintf(stderr, "read nproc (%#x)\n", names[1].n_value);
+ return NULL;
+ }
+ siz = nproc * sizeof(struct proc);
+ if (kmemcpy((char *)&p, (off_t)names[0].n_value, sizeof(p)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) proc\n",
+ names[0].n_value, &p, sizeof(p));
+ return NULL;
+ }
+ proc = (struct proc *)malloc(siz);
+ if (kmemcpy((char *)proc, (off_t)p, siz) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) proc\n",
+ p, proc, siz);
+ return NULL;
+ }
+
+ p = proc;
+
+ for (n = nproc; n; n--, p++)
+ if (p->p_pid == pid)
+ break;
+ if (!n)
+ return NULL;
+
+ return p;
+}
+
+
+struct tcpcb *find_tcp(fd, ti)
+int fd;
+struct tcpiphdr *ti;
+{
+ struct tcpcb *t;
+ struct inpcb *i;
+ struct socket *s;
+ struct user *up;
+ struct proc *p;
+ struct file *f, **o;
+
+ if (!(p = getproc()))
+ return NULL;
+
+ up = (struct user *)malloc(sizeof(*up));
+ if (kmemcpy((char *)up, (off_t)p->p_uarea, sizeof(*up)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x) failed\n", p, p->p_uarea);
+ return NULL;
+ }
+
+ o = (struct file **)calloc(1, sizeof(*o) * (up->u_lastfile + 1));
+ if (kmemcpy((char *)o, (off_t)up->u_ofile,
+ (up->u_lastfile + 1) * sizeof(*o)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - u_ofile - failed\n",
+ up->u_ofile_arr, o, sizeof(*o));
+ return NULL;
+ }
+ f = (struct file *)calloc(1, sizeof(*f));
+ if (kmemcpy((char *)f, (off_t)o[fd], sizeof(*f)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - o[fd] - failed\n",
+ up->u_ofile_arr[fd], f, sizeof(*f));
+ return NULL;
+ }
+
+ s = (struct socket *)calloc(1, sizeof(*s));
+ if (kmemcpy((char *)s, (off_t)f->f_data, sizeof(*s)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - f_data - failed\n",
+ o[fd], s, sizeof(*s));
+ return NULL;
+ }
+
+ i = (struct inpcb *)calloc(1, sizeof(*i));
+ if (kmemcpy((char *)i, (off_t)s->so_pcb, sizeof(*i)) == -1)
+ {
+ fprintf(stderr, "kvm_read(%#x,%#x,%d) - so_pcb - failed\n",
+ s->so_pcb, i, sizeof(*i));
+ return NULL;
+ }
+
+ t = (struct tcpcb *)calloc(1, sizeof(*t));
+ if (kmemcpy((char *)t, (off_t)i->inp_ppcb, sizeof(*t)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - inp_ppcb - failed\n",
+ i->inp_ppcb, t, sizeof(*t));
+ return NULL;
+ }
+ return (struct tcpcb *)i->inp_ppcb;
+}
+#else
+struct kinfo_proc *getproc()
+{
+ static struct kinfo_proc kp;
+ pid_t pid = getpid();
+ int n, mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+
+ n = 1;
+ if (sysctl(mib, 4, &kp, &n, NULL, 0) == -1)
+ {
+ perror("sysctl");
+ return NULL;
+ }
+ return &kp;
+}
+
+
+struct tcpcb *find_tcp(tfd, ti)
+int tfd;
+struct tcpiphdr *ti;
+{
+ struct tcpcb *t;
+ struct inpcb *i;
+ struct socket *s;
+ struct filedesc *fd;
+ struct kinfo_proc *p;
+ struct file *f, **o;
+
+ if (!(p = getproc()))
+ return NULL;
+
+ fd = (struct filedesc *)malloc(sizeof(*fd));
+ if (kmemcpy((char *)fd, (void *)p->kp_proc.p_fd, sizeof(*fd)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx) failed\n",
+ (u_long)p, (u_long)p->kp_proc.p_fd);
+ return NULL;
+ }
+
+ o = (struct file **)calloc(1, sizeof(*o) * (fd->fd_lastfile + 1));
+ if (kmemcpy((char *)o, (void *)fd->fd_ofiles,
+ (fd->fd_lastfile + 1) * sizeof(*o)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%d) - u_ofile - failed\n",
+ (u_long)fd->fd_ofiles, (u_long)o, sizeof(*o));
+ return NULL;
+ }
+ f = (struct file *)calloc(1, sizeof(*f));
+ if (kmemcpy((char *)f, (void *)o[tfd], sizeof(*f)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%d) - o[tfd] - failed\n",
+ (u_long)o[tfd], (u_long)f, sizeof(*f));
+ return NULL;
+ }
+
+ s = (struct socket *)calloc(1, sizeof(*s));
+ if (kmemcpy((char *)s, (void *)f->f_data, sizeof(*s)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%d) - f_data - failed\n",
+ (u_long)f->f_data, (u_long)s, sizeof(*s));
+ return NULL;
+ }
+
+ i = (struct inpcb *)calloc(1, sizeof(*i));
+ if (kmemcpy((char *)i, (void *)s->so_pcb, sizeof(*i)) == -1)
+ {
+ fprintf(stderr, "kvm_read(%#lx,%#lx,%d) - so_pcb - failed\n",
+ (u_long)s->so_pcb, (u_long)i, sizeof(*i));
+ return NULL;
+ }
+
+ t = (struct tcpcb *)calloc(1, sizeof(*t));
+ if (kmemcpy((char *)t, (void *)i->inp_ppcb, sizeof(*t)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%d) - inp_ppcb - failed\n",
+ (u_long)i->inp_ppcb, (u_long)t, sizeof(*t));
+ return NULL;
+ }
+ return (struct tcpcb *)i->inp_ppcb;
+}
+#endif /* BSD < 199301 */
+
+int do_socket(dev, mtu, ti, gwip, flags)
+char *dev;
+int mtu;
+struct tcpiphdr *ti;
+struct in_addr gwip;
+int flags;
+{
+ struct sockaddr_in rsin, lsin;
+ struct tcpcb *t, tcb;
+ int fd, nfd, len;
+
+ printf("Dest. Port: %d\n", ti->ti_dport);
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ {
+ perror("socket");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, FNDELAY) == -1)
+ {
+ perror("fcntl");
+ return -1;
+ }
+
+ bzero((char *)&lsin, sizeof(lsin));
+ lsin.sin_family = AF_INET;
+ bcopy((char *)&ti->ti_src, (char *)&lsin.sin_addr,
+ sizeof(struct in_addr));
+ if (bind(fd, (struct sockaddr *)&lsin, sizeof(lsin)) == -1)
+ {
+ perror("bind");
+ return -1;
+ }
+ len = sizeof(lsin);
+ (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));
+
+ if (!(t = find_tcp(fd, ti)))
+ return -1;
+
+ bzero((char *)&rsin, sizeof(rsin));
+ rsin.sin_family = AF_INET;
+ bcopy((char *)&ti->ti_dst, (char *)&rsin.sin_addr,
+ sizeof(struct in_addr));
+ rsin.sin_port = ti->ti_dport;
+ if (connect(fd, (struct sockaddr *)&rsin, sizeof(rsin)) == -1 &&
+ errno != EINPROGRESS)
+ {
+ perror("connect");
+ return -1;
+ }
+ kmemcpy((char*)&tcb, (void *)t, sizeof(tcb));
+ ti->ti_win = tcb.rcv_adv;
+ ti->ti_seq = tcb.snd_nxt - 1;
+ ti->ti_ack = tcb.rcv_nxt;
+
+ if (send_tcp(nfd, mtu, ti, gwip, TH_SYN) == -1)
+ return -1;
+ (void)write(fd, "Hello World\n", 12);
+ sleep(2);
+ close(fd);
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/tcpip.h b/contrib/ipfilter/ipsend/tcpip.h
new file mode 100644
index 0000000..78f274f
--- /dev/null
+++ b/contrib/ipfilter/ipsend/tcpip.h
@@ -0,0 +1,38 @@
+/* @(#)tcpip.h 1.7 88/08/19 SMI; from UCB 7.1 6/5/85 */
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+/*
+ * Tcp+ip header, after ip options removed.
+ */
+
+#ifndef _netinet_tcpip_h
+#define _netinet_tcpip_h
+
+struct tcpiphdr {
+ struct ipovly ti_i; /* overlaid ip structure */
+ tcphdr_t ti_t; /* tcp header */
+};
+#define ti_next ti_i.ih_next
+#define ti_prev ti_i.ih_prev
+#define ti_x1 ti_i.ih_x1
+#define ti_pr ti_i.ih_pr
+#define ti_len ti_i.ih_len
+#define ti_src ti_i.ih_src
+#define ti_dst ti_i.ih_dst
+#define ti_sport ti_t.th_sport
+#define ti_dport ti_t.th_dport
+#define ti_seq ti_t.th_seq
+#define ti_ack ti_t.th_ack
+#define ti_x2 ti_t.th_x2
+#define ti_off ti_t.th_off
+#define ti_flags ti_t.th_flags
+#define ti_win ti_t.th_win
+#define ti_sum ti_t.th_sum
+#define ti_urp ti_t.th_urp
+
+#endif /*!_netinet_tcpip_h*/
diff --git a/contrib/ipfilter/ipt.c b/contrib/ipfilter/ipt.c
new file mode 100644
index 0000000..b934c2f
--- /dev/null
+++ b/contrib/ipfilter/ipt.c
@@ -0,0 +1,199 @@
+/*
+ * (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.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include "ip_fil.h"
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "ipt.h"
+#include <ctype.h>
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-1996 Darren Reed";
+static char rcsid[] = "$Id: ipt.c,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $";
+#endif
+
+extern int fr_check();
+extern char *optarg;
+extern struct frentry *ipfilter[2][2];
+extern struct ipread snoop, etherf, tcpd, pcap, iptext, iphex;
+extern void debug(), verbose();
+
+struct frentry *ft_in = NULL, *ft_out = NULL;
+
+int opts = 0;
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ struct ipread *r = &iptext;
+ struct frentry *f;
+ struct ip *ip;
+ u_long buf[64];
+ char c;
+ char *rules = NULL, *datain = NULL, *iface = NULL;
+ int fd, i, dir = 0;
+
+ while ((c = getopt(argc, argv, "bdEHi:I:Pr:STvX")) != -1)
+ switch (c)
+ {
+ case 'b' :
+ opts |= OPT_BRIEF;
+ break;
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'i' :
+ datain = optarg;
+ break;
+ case 'I' :
+ iface = optarg;
+ break;
+ case 'r' :
+ rules = optarg;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ case 'E' :
+ r = &etherf;
+ break;
+ case 'H' :
+ r = &iphex;
+ break;
+ case 'P' :
+ r = &pcap;
+ break;
+ case 'S' :
+ r = &snoop;
+ break;
+ case 'T' :
+ r = &tcpd;
+ break;
+ case 'X' :
+ r = &iptext;
+ break;
+ }
+
+ if (!rules) {
+ (void)fprintf(stderr,"no rule file present\n");
+ exit(-1);
+ }
+
+ initparse();
+
+ if (rules) {
+ struct frentry *fr;
+ char line[513], *s;
+ FILE *fp;
+
+ if (!strcmp(rules, "-"))
+ fp = stdin;
+ else if (!(fp = fopen(rules, "r"))) {
+ (void)fprintf(stderr, "couldn't open %s\n", rules);
+ exit(-1);
+ }
+ if (!(opts & OPT_BRIEF))
+ (void)printf("opening rule file \"%s\"\n", rules);
+ while (fgets(line, sizeof(line)-1, fp)) {
+ /*
+ * treat both CR and LF as EOL
+ */
+ if ((s = index(line, '\n')))
+ *s = '\0';
+ if ((s = index(line, '\r')))
+ *s = '\0';
+ /*
+ * # is comment marker, everything after is a ignored
+ */
+ if ((s = index(line, '#')))
+ *s = '\0';
+
+ if (!*line)
+ continue;
+
+ if (!(fr = parse(line)))
+ continue;
+ f = (struct frentry *)malloc(sizeof(*f));
+ if (fr->fr_flags & FR_INQUE) {
+ if (!ft_in)
+ ft_in = ipfilter[0][0] = f;
+ else
+ ft_in->fr_next = f, ft_in = f;
+ } else if (fr->fr_flags & FR_OUTQUE) {
+ if (!ft_out)
+ ft_out = ipfilter[1][0] = f;
+ else
+ ft_out->fr_next = f, ft_out = f;
+ }
+ bcopy((char *)fr, (char *)f, sizeof(*fr));
+ }
+ (void)fclose(fp);
+ }
+
+ if (datain)
+ fd = (*r->r_open)(datain);
+ else
+ fd = (*r->r_open)("-");
+
+ if (fd < 0)
+ exit(-1);
+
+ ip = (struct ip *)buf;
+ while ((i = (*r->r_readip)(buf, sizeof(buf), &iface, &dir)) > 0) {
+ ip->ip_off = ntohs(ip->ip_off);
+ ip->ip_len = ntohs(ip->ip_len);
+ switch (fr_check(ip, ip->ip_hl << 2, iface, dir))
+ {
+ case -1 :
+ (void)printf("block");
+ break;
+ case 0 :
+ (void)printf("pass");
+ break;
+ case 1 :
+ (void)printf("nomatch");
+ break;
+ }
+ if (!(opts & OPT_BRIEF)) {
+ putchar(' ');
+ printpacket(buf);
+ printf("--------------");
+ }
+ putchar('\n');
+ dir = 0;
+ }
+ (*r->r_close)();
+ return 0;
+}
diff --git a/contrib/ipfilter/ipt.h b/contrib/ipfilter/ipt.h
new file mode 100644
index 0000000..be481ca
--- /dev/null
+++ b/contrib/ipfilter/ipt.h
@@ -0,0 +1,16 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ * $Id: ipt.h,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $
+ */
+
+#include <fcntl.h>
+
+struct ipread {
+ int (*r_open)();
+ int (*r_close)();
+ int (*r_readip)();
+};
diff --git a/contrib/ipfilter/kmem.c b/contrib/ipfilter/kmem.c
new file mode 100644
index 0000000..3334580
--- /dev/null
+++ b/contrib/ipfilter/kmem.c
@@ -0,0 +1,68 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+/*
+ * kmemcpy() - copies n bytes from kernel memory into user buffer.
+ * returns 0 on success, -1 on error.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/file.h>
+
+#define KMEM "/dev/kmem"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed";
+static char rcsid[] = "$Id: kmem.c,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $";
+#endif
+
+static int kmemfd = -1;
+
+int openkmem()
+{
+ if ((kmemfd = open(KMEM,O_RDONLY)) == -1)
+ {
+ perror("kmeminit:open");
+ return -1;
+ }
+ return kmemfd;
+}
+
+int kmemcpy(buf, pos, n)
+register char *buf;
+long pos;
+register int n;
+{
+ register int r;
+
+ if (!n)
+ return 0;
+ if (kmemfd == -1)
+ if (openkmem() == -1)
+ return -1;
+ if (lseek(kmemfd, pos, 0) == -1)
+ {
+ perror("kmemcpy:lseek");
+ return -1;
+ }
+ while ((r = read(kmemfd, buf, n)) < n)
+ if (r <= 0)
+ {
+ perror("kmemcpy:read");
+ return -1;
+ }
+ else
+ {
+ buf += r;
+ n -= r;
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/kmem.h b/contrib/ipfilter/kmem.h
new file mode 100644
index 0000000..18c1c23
--- /dev/null
+++ b/contrib/ipfilter/kmem.h
@@ -0,0 +1,12 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ * $Id: kmem.h,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $
+ */
+
+extern int openkmem();
+extern int kmemcpy();
+
diff --git a/contrib/ipfilter/linux.h b/contrib/ipfilter/linux.h
new file mode 100644
index 0000000..f4d3bda
--- /dev/null
+++ b/contrib/ipfilter/linux.h
@@ -0,0 +1,19 @@
+/*
+ * (C)opyright 1993,1994,1995 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. The author accepts no
+ * responsibility and is not changed in any way.
+ *
+ * I hate legaleese, don't you ?
+ * $Id: linux.h,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $
+ */
+
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
+
+#include "ip_compat.h"
diff --git a/contrib/ipfilter/man/Makefile b/contrib/ipfilter/man/Makefile
new file mode 100644
index 0000000..c62e54c
--- /dev/null
+++ b/contrib/ipfilter/man/Makefile
@@ -0,0 +1,21 @@
+#
+# (C)opyright 1993, 1994, 1995 by Darren Reed.
+#
+# 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 ?
+
+all:
+
+install:
+ $(INSTALL) -m 0644 -c -o root -g bin ipf.1 $(MANDIR)/man1
+ $(INSTALL) -m 0644 -c -o root -g bin ipftest.1 $(MANDIR)/man1
+ $(INSTALL) -m 0644 -c -o root -g bin ipnat.1 $(MANDIR)/man1
+ $(INSTALL) -m 0644 -c -o root -g bin ipf.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 ipnat.5 $(MANDIR)/man5
+ $(INSTALL) -m 0644 -c -o root -g bin ipmon.8 $(MANDIR)/man8
+ $(INSTALL) -m 0644 -c -o root -g bin ipfstat.8 $(MANDIR)/man8
+ @echo "Remember to rebuild the whatis database."
diff --git a/contrib/ipfilter/man/ipf.1 b/contrib/ipfilter/man/ipf.1
new file mode 100644
index 0000000..912d7ef
--- /dev/null
+++ b/contrib/ipfilter/man/ipf.1
@@ -0,0 +1,109 @@
+.TH IPF 1
+.SH NAME
+ipf \- alters packet filtering lists for IP packet input and ouput
+.SH SYNOPSIS
+.B ipf
+[
+.B \-AdDEInorsUvyzZ
+] [
+.B \-l
+<block|pass|nomatch>
+] [
+.B \-F
+<i|o|a>
+]
+.B \-f
+<\fIfilename\fP>
+[
+.B \-f
+<\fIfilename\fP>
+[...]]
+.SH DESCRIPTION
+.PP
+\fBipf\fP opens the filenames listed (treating "\-" as stdin) and parses the
+file for a set of rules which are to be added or removed from the packet
+filter rule set.
+.PP
+Each rule processed by \fBipf\fP
+is added to the kernel's 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 \fBipf\fP.
+.SH OPTIONS
+.TP
+.B \-A
+Set the list to make changes to the active list (default).
+.TP
+.B \-d
+Turn debug mode on. Causes a hexdump of filter rules to be generated as
+it processes each one.
+.TP
+.B \-D
+Disable the filter (if enabled). Not effective for loadable kernel versions.
+.TP
+.B \-E
+Enable the filter (if disabled). Not effective for loadable kernel versions.
+.TP
+.BR \-F \0<param>
+This option specifies which filter list to flush. The parameter should
+either be "i" (input), "o" (output) or "a" (remove all filter rules).
+Either a single letter or an entire word starting with the appropriate
+letter maybe used. This option maybe before, or after, any other with
+the order on the command line being that used to execute options.
+.TP
+.BR \-f \0<filename>
+This option specifies which files
+\fBipf\fP should use to get input from for modifying the packet filter rule
+lists.
+.TP
+.B \-I
+Set the list to make changes to the inactive list.
+.TP
+.B \-l \0<param>
+Use of the \fB-l\fP flag toggles default logging of packets. Valid
+arguments to this option are \fBpass\fP, \fBblock\fP and \fBnomatch\fP.
+When an option is set, any packet which exits filtering and matches the
+set category is logged. This is most useful for causing all packets
+which don't match any of the loaded rules to be logged.
+.TP
+.B \-n
+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 \-o
+Force rules by default to be added/deleted to/from the output list, rather
+than the (default) input list.
+.TP
+.B \-r
+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.
+.TP
+.B \-v
+Turn verbose mode on. Displays information relating to rule processing.
+.TP
+.B \-y
+(SOLARIS 2 ONLY) Manually resync the in-kernel interface list maintained
+by IP Filter with the current interface status list.
+.TP
+.B \-z
+For each rule in the input file, reset the statistics for it to zero and
+display the statistics prior to them being zero'd.
+.TP
+.B \-Z
+Zero global statistics held in the kernel for filtering only (this doesn't
+affect fragment or state statistics).
+.DT
+.SH SEE ALSO
+ipfstat(1), ipftest(1), ipf(5)
+.SH DIAGNOSTICS
+.PP
+Needs to be run as root for the packet filtering lists to actually
+be affected inside the kernel.
+.SH BUGS
+.PP
+If you find any, please send email to me at darrenr@cyber.com.au
diff --git a/contrib/ipfilter/man/ipf.4 b/contrib/ipfilter/man/ipf.4
new file mode 100644
index 0000000..ff17f4f
--- /dev/null
+++ b/contrib/ipfilter/man/ipf.4
@@ -0,0 +1,184 @@
+.TH IPF 4
+.SH NAME
+ipf \- packet filtering kernel interface
+.SH SYNOPSIS
+#include <sys/ip_fil.h>
+.SH IOCTLS
+.PP
+To add and delete rules to the filter list, three 'basic' ioctls are provided
+for use. The ioctl's are called as:
+.LP
+.nf
+ ioctl(fd, SIOCADDFR, struct frentry *)
+ ioctl(fd, SIOCDELFR, struct frentry *)
+ ioctl(fd, SIOCIPFFL, int *)
+.fi
+.PP
+However, the full complement is as follows:
+.LP
+.nf
+ ioctl(fd, SIOCADAFR, struct frentry *) (same as SUICADDFR)
+ ioctl(fd, SIOCRMAFR, struct frentry *) (same as SUICDELFR)
+ ioctl(fd, SIOCADIFR, struct frentry *)
+ ioctl(fd, SIOCRMIFR, struct frentry *)
+ ioctl(fd, SIOCINAFR, struct frentry *)
+ ioctl(fd, SIOCINIFR, struct frentry *)
+ ioctl(fd, SIOCIPFFL, int *)
+.fi
+.PP
+The variations, SIOCADAFR vs. SIOCADIFR, allow operation on the two lists,
+active and inactive, respectively. All of these ioctl's are implemented
+as being routing ioctls and thus the same rules for the various routing
+ioctls and the file descriptor are employed, mainly being that the fd must
+be that of the device associated with the module (i.e., /dev/ipl).
+.LP
+.PP
+The three groups of ioctls above perform adding rules to the end of the
+list (SIOCAD*), deletion of rules from any place in the list (SIOCRM*)
+and insertion of a rule into the list (SIOCIN*). The rule place into
+which it is inserted is stored in the "fr_hits" field, below.
+.LP
+.nf
+typedef struct frentry {
+ struct frentry *fr_next;
+ struct ifnet *fr_ifa;
+ u_long fr_hits;
+ u_long fr_bytes; /* this is only incremented when a packet */
+ /* stops matching on this rule */
+ /*
+ * Fields after this may not change whilst in the kernel.
+ */
+ struct fr_ip fr_ip;
+ struct fr_ip fr_mip;
+
+ u_char fr_tcpfm; /* tcp flags mask */
+ u_char fr_tcpf; /* tcp flags */
+
+ u_short fr_icmpm; /* data for ICMP packets (mask) */
+ u_short fr_icmp;
+
+ u_char fr_scmp; /* data for port comparisons */
+ u_char fr_dcmp;
+ u_short fr_dport;
+ u_short fr_sport;
+ u_short fr_stop; /* top port for <> and >< */
+ u_short fr_dtop; /* top port for <> and >< */
+ u_long fr_flags; /* per-rule flags && options (see below) */
+ int (*fr_func)(); /* call this function */
+ char fr_icode; /* return ICMP code */
+ char fr_ifname[IFNAMSIZ];
+ struct frdest fr_tif; /* "to" interface */
+ struct frdest fr_dif; /* duplicate packet interfaces */
+} frentry_t;
+.fi
+.PP
+When adding a new rule, all unused fields (in the filter rule) should be
+initialised to be zero. To insert a rule, at a particular position in the
+filter list, the number of the rule which it is to be inserted before must
+be put in the "fr_hits" field (the first rule is number 0).
+.LP
+.PP
+Flags which are recognised in fr_pass:
+.nf
+
+ FR_BLOCK 0x00001 /* do not allow packet to pass */
+ FR_PASS 0x00002 /* allow packet to pass */
+ FR_OUTQUE 0x00004 /* outgoing packets */
+ FR_INQUE 0x00008 /* ingoing packets */
+ FR_LOG 0x00010 /* Log */
+ FR_LOGP 0x00011 /* Log-pass */
+ FR_LOGB 0x00012 /* Log-fail */
+ FR_LOGBODY 0x00020 /* log the body of packets too */
+ FR_LOGFIRST 0x00040 /* log only the first packet to match */
+ FR_RETRST 0x00080 /* return a TCP RST packet if blocked */
+ FR_RETICMP 0x00100 /* return an ICMP packet if blocked */
+ FR_NOMATCH 0x00200 /* no match occured */
+ FR_ACCOUNT 0x00400 /* count packet bytes */
+ FR_KEEPFRAG 0x00800
+ FR_KEEPSTATE 0x01000 /* keep packet flow state information */
+ FR_INACTIVE 0x02000
+ FR_QUICK 0x04000 /* quick-match and return */
+ FR_FASTROUTE 0x08000
+ FR_CALLFUNC 0x10000
+ FR_CALLNOW 0x20000
+ FR_DUP 0x40000 /* duplicate the packet (not Solaris2)
+
+.fi
+.PP
+Values for fr_scomp and fr_dcomp (source and destination port value
+comparisons) :
+.LP
+.nf
+ FR_NONE 0
+ FR_EQUAL 1
+ FR_NEQUAL 2
+ FR_LESST 3
+ FR_GREATERT 4
+ FR_LESSTE 5
+ FR_GREATERTE 6
+ FR_OUTRANGE 7
+ FR_INRANGE 8
+.fi
+.PP
+The third ioctl, SIOCIPFFL, flushes either the input filter list, the
+output filter list or both and it returns the number of filters removed
+from the list(s). The values which it will take and recognise are FR_INQUE
+and FR_OUTQUE (see above).
+
+\fBGeneral Logging Flags\fP
+There are two flags which can be set to log packets independantly of the
+rules used. These allow for packets which are either passed or blocked
+to be logged. To set (and clear)/get these flags, two ioctls are
+provided:
+.IP SIOCSETFF 16
+Takes an unsigned integer as the parameter. The flags are then set to
+those provided (clearing/setting all in one).
+.nf
+
+ FF_LOGPASS 1
+ FF_LOGBLOCK 2
+.fi
+.IP SIOCGETFF 16
+Takes a pointer to an unsigned integer as the parameter. A copy of the
+flags currently in used is copied to user space.
+.LP
+\fBFilter statistics\fP
+Statistics on the various operations performed by this package on packets
+is kept inside the kernel. These statistics apply to packets traversing
+through the kernel. To retrieve this structure, use this ioctl:
+.nf
+
+ ioctl(fd, SIOCGETFS, struct friostat *)
+
+struct friostat {
+ struct filterstats f_st[2];
+ struct frentry *f_fin;
+ struct frentry *f_fout;
+};
+
+struct filterstats {
+ u_long fr_pass; /* packets allowed */
+ u_long fr_block; /* packets denied */
+ u_long fr_nom; /* packets which don't match any rule */
+ u_long fr_ppkl; /* packets allowed and logged */
+ u_long fr_bpkl; /* packets denied and logged */
+ u_long fr_npkl; /* packets unmatched and logged */
+ u_long fr_pkl; /* packets logged */
+ u_long fr_skip; /* packets to be logged but buffer full */
+ u_long fr_ret; /* packets for which a return is sent */
+ u_long fr_acct; /* packets for which counting was performed */
+ u_long fr_bnfr; /* bad attempts to allocate fragment state */
+ u_long fr_nfr; /* new fragment state kept */
+ u_long fr_cfr; /* add new fragment state but complete pkt */
+ u_long fr_bads; /* bad attempts to allocate packet state */
+ u_long fr_ads; /* new packet state kept */
+ u_long fr_chit; /* cached hit */
+#if SOLARIS
+ 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! */
+#endif
+};
+.fi
+.SH SEE ALSO
+ipfstat(1), ipf(1), ipf(5)
diff --git a/contrib/ipfilter/man/ipf.5 b/contrib/ipfilter/man/ipf.5
new file mode 100644
index 0000000..417a0ea
--- /dev/null
+++ b/contrib/ipfilter/man/ipf.5
@@ -0,0 +1,433 @@
+.TH IPF 5
+.SH NAME
+ipf \- IP packet filter rule syntax
+.SH DESCRIPTION
+.PP
+A rule file for \fBipf\fP may have any name or even be stdin. As
+\fBipfstat\fP produces parseable rules as output when displaying the internal
+kernel filter lists, it is quite plausible to use its output to feed back
+into \fBipf\fP. Thus, to remove all filters on input packets, the following
+could be done:
+.nf
+
+\fC# ipfstat \-i | ipf \-rf \-\fP
+.fi
+.SH GRAMMAR
+.PP
+The format used by \fBipf\fP for construction of filtering rules can be
+described using the following grammar in BNF:
+\fC
+.nf
+filter-rule = [ insert ] action in-out [ options ] [ match ] [ keep ]
+
+insert = "@" decnumber .
+action = block | "pass" | log | "count" | call .
+in-out = "in" | "out" .
+options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] ] .
+match = [ tos ] [ ttl ] [ proto ] [ ip ] .
+keep = "keep state" | "keep frags" .
+
+block = "block" [ "return-icmp"[return-code] | "return-rst" ] .
+log = "log" [ "body" ] [ "first" ] [ "or-block" ] .
+call = "call" [ "now" ] function-name .
+
+dup = "dup-to" interface-name[":"ipaddr] .
+froute = "fastroute" | "to" interface-name .
+
+tos = "tos" decnumber | "tos" hexnumber .
+ttl = "ttl" decnumber .
+proto = "proto" protocol .
+ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
+
+protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber .
+srcdst = "all" | fromto .
+fromto = "from" object "to" object .
+
+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")" .
+
+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" | "frag" | "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" | 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" .
+optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" |
+ "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" |
+ "visa" | "imitd" | "eip" | "finn" .
+
+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" .
+.fi
+.PP
+This syntax is somewhat simplified for readability, some combinations
+that match this grammar are disallowed by the software because they do
+not make sense (such as tcp \fBflags\fP for non-TCP packets).
+.SH FILTER RULES
+.PP
+The "briefest" valid rules are (currently) no-ops and are of the form:
+.nf
+ block in
+ pass in
+ log in
+ count in
+.fi
+.PP
+These are supposed to be the same as, but currently differ from:
+.\" XXX How, why do they differ??
+.nf
+ block in all
+ pass in from any to any
+ log in all
+ count in all
+.fi
+.PP
+Filter rules are checked in order, with the last matching rule
+determining the fate of the packet (but see the \fBquick\fP option,
+below).
+.PP
+Filters are installed by default at the end of the kernel's filter
+lists, prepending the rule with \fB@n\fP will cause it to be inserted
+as the n'th entry in the current list. This is especially useful when
+modifying and testing active filter rulesets. See ipf(1) for more
+information.
+.SH ACTIONS
+.PP
+The action indicates what to do with the packet if it matches the rest
+of the filter rule. Each rule MUST have an action. The following
+actions are recognised:
+.TP
+.B block
+indicates that the packet should be flagged to be dropped. In response
+to blocking a packet, the filter may be instructed to send a reply
+packet, either an ICMP packet (\fBreturn-icmp\fP) or a TCP "reset"
+(\fBreturn-rst\fP). An ICMP packet may be generated in response to
+any IP packet, and its type may optionally be specified, but a TCP
+reset may only be used with a rule which is being applied to TCP
+packets.
+.TP
+.B pass
+will flag the packet to be let through the filter.
+.TP
+.B log
+causes the packet to be logged (as described in the LOGGING section
+below) and has no effect on whether the packet will be allowed through
+the filter.
+.TP
+.B count
+causes the packet to be included in the accounting statistics kept by
+the filter, and has no effect on whether the packet will be allowed through
+the filter. These statistics are viewable with ipfstat(8).
+.TP
+.B call
+this action is used to invoke the named function in the kernel, which
+must conform to a specific calling interface. Customised actions and
+semantics can thus be implemented to supplement those available. This
+feature is for use by knowledgeable hackers, and is not currently
+documented.
+.PP
+The next word must be either \fBin\fP or \fBout\fP. Each packet
+moving through the kernel is either inbound (just been received on an
+interface, and moving towards the kernel's protocol processing) or
+outbound (transmitted or forwarded by the stack, and on its way to an
+interface). There is a requirement that each filter rule explicitly
+state which side of the I/O it is to be used on.
+.SH OPTIONS
+.PP
+The list of options is brief, and all are indeed optional. Where
+options are used, they must be present in the order shown here. These
+are the currently supported options:
+.TP
+.B log
+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 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
+\fBquick\fP, this rule will be the last rule checked, allowing a
+"short-circuit" path to avoid processing later rules for this
+packet. The current status of the packet (after any effects of the
+current rule) will determine whether it is passed or blocked.
+.IP
+If this option is missing, the rule is taken to be a "fall-through"
+rule, meaning that the result of the match (block/pass) is saved and
+that processing will continue to see if there are any more matches.
+.TP
+.B on
+allows an interface name to be incorporated into the matching
+procedure. Interface names are as printed by "netstat \-i". If this
+option is used, the rule will only match if the packet is going
+through that interface in the specified direction (in/out). If this
+option is absent, the rule is taken to be applied to a packet
+regardless of the interface it is present on (i.e. on all interfaces).
+Filter rulesets are common to all interfaces, rather than having a
+filter list for each interface.
+.IP
+This option is especially useful for simple IP-spoofing protection:
+packets should only be allowed to pass inbound on the interface from
+which the specified source address would be expected, others may be
+logged and/or dropped.
+.TP
+.B dup-to
+causes the packet to be copied, and the duplicate packet to be sent outbound on the specified interface, optionally with the destination IP address changed to that specified. This is useful for off-host logging, using a network sniffer.
+.TP
+.B to
+causes the packet to be moved to the outbound queue on the
+specified interface. This can be used to circumvent kernel routing
+decisions, and even to bypass the rest of the kernel processing of the
+packet (if applied to an inbound rule). It is thus possible to
+construct a firewall that behaves transparently, like a filtering hub
+or switch, rather than a router. The \fBfastroute\fP keyword is a
+synonym for this option.
+.SH MATCHING PARAMETERS
+.PP
+The keywords described in this section are used to describe attributes
+of the packet to be used when determining whether rules match or don't
+match. The following general-purpose attributes are provided for
+matching, and must be used in this order:
+.TP
+.B tos
+packets with different Type-Of-Service values can be filtered.
+Individual service levels or combinations can be filtered upon. The
+value for the TOS mask can either be represented as a hex number or a
+decimal integer value.
+.\" XXX TOS mask?? not in grammar!
+.TP
+.B ttl
+packets may also be selected by their Time-To-Live value. The value given in
+the filter rule must exactly match that in the packet for a match to occur.
+This value can only be given as a decimal integer value.
+.TP
+.B proto
+allows a specific protocol to be matched against. All protocol names
+found in \fB/etc/protocols\fP are recognised and may be used.
+However, the protocol may also be given as a DECIMAL number, allowing
+for rules to match your own protocols, or new ones which would
+out-date any attempted listing.
+.IP
+The special protocol keyword \fBtcp/udp\fP may be used to match either
+a TCP or a UDP packet, and has been added as a convenience to save
+duplication of otherwise-identical rules.
+.\" XXX grammar should reflect this (/etc/protocols)
+.PP
+The \fBfrom\fP and \fBto\fP keywords are used to match against IP
+addresses (and optionally port numbers). Rules must specify BOTH
+source and destination parameters.
+.PP
+IP addresses may be specified in one of two ways: as a numerical
+address\fB/\fPmask, or as a hostname \fBmask\fP netmask. The hostname
+may either be a valid hostname, from either the hosts file or DNS
+(depending on your configuration and library) or of the dotted numeric
+form. There is no special designation for networks but network names
+are recognised. Note that having your filter rules depend on DNS
+results can introduce an avenue of attack, and is discouraged.
+.PP
+There is a special case for the hostname \fBany\fP which is taken to
+be 0.0.0.0/0 (see below for mask syntax) and matches all IP addresses.
+Only the presence of "any" has an implied mask, in all other
+situations, a hostname MUST be accompanied by a mask. It is possible
+to give "any" a hostmask, but in the context of this language, it is
+non-sensical.
+.PP
+The numerical format "x\fB/\fPy" indicates that a mask of y
+consecutive 1 bits set is generated, starting with the MSB, so a y value
+of 16 would give 0xffff0000. The symbolic "x \fBmask\fP y" indicates
+that the mask y is in dotted IP notation or a hexadecimal number of
+the form 0x12345678. Note that all the bits of the IP address
+indicated by the bitmask must match the address on the packet exactly;
+there isn't currently a way to invert the sense of the match, or to
+match ranges of IP addresses which do not express themselves easily as
+bitmasks (anthropomorphization; it's not just for breakfast anymore).
+.PP
+If a \fBport\fP match is included, for either or both of source and
+destination, then it is only applied to
+.\" XXX - "may only be" ? how does this apply to other protocols? will it not match, or will it be ignored?
+TCP and UDP packets. If there is no \fBproto\fP match parameter,
+packets from both protocols are compared. This is equivalent to "proto
+tcp/udp". When composing \fBport\fP comparisons, either the service
+name or an integer port number may be used. Port comparisons may be
+done in a number of forms, with a number of comparison operators, or
+port ranges may be specified. See the examples for more information.
+.PP
+The \fBall\fP keyword is essentially a synonym for "from any to any"
+with no other match parameters.
+.PP
+Following the source and destination matching parameters, the
+following additional parameters may be used:
+.TP
+.B with
+is used to match irregular attributes that some packets may have
+associated with them. To match the presence of IP options in general,
+use \fBwith ipopts\fP. To match packets that are too short to contain
+a complete header, use \fBwith short\fP. To match fragmented packets,
+use \fBwith frag\fP. For more specific filtering on IP options,
+individual options can be listed.
+.IP
+Before any parameter used after the \fBwith\fP keyword, the word
+\fBnot\fP or \fBno\fP may be inserted to cause the filter rule to only
+match if the option(s) is not present.
+.IP
+Multiple consecutive \fBwith\fP clauses are allowed. Alternatively,
+the keyword \fBand\fP may be used in place of \fBwith\fP, this is
+provided purely to make the rules more readable ("with ... and ...").
+When multiple clauses are listed, all those must match to cause a
+match of the rule.
+.\" XXX describe the options more specifically in a separate section
+.TP
+.B flags
+is only effective for TCP filtering. Each of the letters possible
+represents one of the possible flags that can be set in the TCP
+header. The association is as follows:
+.LP
+.nf
+ F - FIN
+ S - SYN
+ R - RST
+ P - PUSH
+ A - ACK
+ U - URG
+.fi
+.IP
+The various flag symbols may be used in combination, so that "SA"
+would represent a SYN-ACK combination present in a packet. There is
+nothing preventing the specification of combinations, such as "SFR",
+that would not normally be generated by law-abiding TCP
+implementations. However, to guard against weird aberrations, it is
+necessary to state which flags you are filtering against. To allow
+this, it is possible to set a mask indicating which TCP flags you wish
+to compare (i.e., those you deem significant). This is done by
+appending "/<flags>" to the set of TCP flags you wish to match
+against, e.g.:
+.LP
+.nf
+ ... flags S
+ # becomes "flags S/AUPRFS" and will match
+ # packets with ONLY the SYN flag set.
+
+ ... flags SA
+ # becomes "flags SA/AUPRFS" and will match any
+ # packet with only the SYN and ACK flags set.
+
+ ... flags S/SA
+ # will match any packet with just the SYN flag set
+ # out of the SYN-ACK pair; the common "establish"
+ # keyword action. "S/SA" will NOT match a packet
+ # with BOTH SYN and ACK set, but WILL match "SFP".
+.fi
+.TP
+.B icmp-type
+is only effective when used with \fBproto icmp\fP and must NOT be used
+in conjuction with \fBflags\fP. There are a number of types, which can be
+referred to by an abbreviation recognised by this language, or the numbers
+with which they are associated can be used. The most important from
+a security point of view is the ICMP redirect.
+.SH KEEP HISTORY
+.PP
+The last parameter which can be set for a filter rule is whether on not to
+record historical information for that packet, and what sort to keep. The following information can be kept:
+.TP
+.B state
+keeps information about the flow of a communication session. State can
+be kept for TCP, UDP, and ICMP packets.
+.TP
+.B frags
+keeps information on fragmented packets, to be applied to later
+fragments.
+.PP
+allowing packets which match these to flow straight through, rather
+than going through the access control list.
+.SH LOGGING
+.PP
+When a packet is logged, with either the \fBlog\fP action or option,
+the headers of the packet are written to the \fBipl\fP packet logging
+psuedo-device. Immediately following the \fBlog\fP keyword, the
+following qualifiers may be used (in order):
+.TP
+.B body
+indicates that the first 128 bytes of the packet contents will be
+logged after the headers.
+.TP
+.B first
+??
+.TP
+.B or-block
+indicates that, if for some reason the filter is unable to log the packet (such as the log reader being too slow) then the rule should be interpreted as if the action was \fBblock\fP for this packet.
+.PP
+See ipl(4) for the format of records written
+to this device. The ipmon(8) program can be used to read and format
+this log.
+.SH EXAMPLES
+.PP
+The \fBquick\fP option is good for rules such as:
+\fC
+.nf
+block in quick from any to any with ipopts
+.fi
+.PP
+which will match any packet with a non-standard header length (IP
+options present) and abort further processing of later rules,
+recording a match and also that the packet should be blocked.
+.PP
+The "fall-through" rule parsing allows for effects such as this:
+.LP
+.nf
+ block in from any to any port < 6000
+ pass in from any to any port >= 6000
+ block in from any to port > 6003
+.fi
+.PP
+which sets up the range 6000-6003 as being permitted and all others being
+denied. Note that the effect of the first rule is overridden by subsequent
+rules. Another (easier) way to do the same is:
+.LP
+.nf
+ block in from any to any port 6000 <> 6003
+ pass in from any to any port 5999 >< 6004
+.fi
+.PP
+Note that both the "block" and "pass" are needed here to effect a
+result as a failed match on the "block" action does not imply a pass,
+only that the rule hasn't taken effect. To then allow ports < 1024, a
+rule such as:
+.LP
+.nf
+ pass in quick from any to any port < 1024
+.fi
+.PP
+would be needed before the first block.
+.SH FILES
+/etc/services
+.br
+/etc/hosts
+.SH SEE ALSO
+ipf(1), ipftest(1)
diff --git a/contrib/ipfilter/man/ipfstat.8 b/contrib/ipfilter/man/ipfstat.8
new file mode 100644
index 0000000..db23e39
--- /dev/null
+++ b/contrib/ipfilter/man/ipfstat.8
@@ -0,0 +1,73 @@
+.TH ipfstat 8
+.SH NAME
+ipfstat \- reports on packet filter statistics and filter list
+.SH SYNOPSIS
+.B ipfstat
+[
+.B \-hIinov
+] [
+.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
+kernel itself. The kernel name defaults to \fB/vmunix\fP.
+.PP
+The default behaviour of \fBipfstat\fP
+is to retrieve and display the accumulated statistics which have been
+accumulated over time as the kernel has put packets through the filter.
+.SH OPTIONS
+.TP
+.B \-a
+Display the accounting filter list and show bytes counted against each rule.
+.TP
+.BR \-d \0<device>
+Use a device other than \fB/dev/ipl\fP for interfacing with the kernel.
+.TP
+.B \-f
+Show fragment state information (statistics) and held state information (in
+the kernel) if any is present.
+.TP
+.B \-h
+Show per-rule the number of times each one scores a "hit". For use in
+combination with \fB\-i\fP.
+.TP
+.B \-i
+Display the filter list used for the input side of the kernel IP processing.
+.TP
+.B \-I
+Swap between retrieving "inactive"/"active" filter list details. For use
+in combination with \fB\-i\fP.
+.TP
+.B \-n
+Show the "rule number" for each rule as it is printed.
+.TP
+.B \-o
+Display the filter list used for the output side of the kernel IP processing.
+.TP
+.B \-s
+Show packet/flow state information (statistics) and held state information (in
+the kernel) if any is present.
+.TP
+.B \-v
+Turn verbose mode on. Displays more debugging information.
+.SH SYNOPSIS
+The role of \fBipfstat\fP is to display current kernel statistics gathered
+as a result of applying the filters in place (if any) to packets going in and
+out of the kernel. This is the default operation when no command line
+parameters are present.
+.PP
+When supplied with either \fB\-i\fP or \fB\-o\fP, it will retrieve and display
+the appropriate list of filter rules currently installed and in use by the
+kernel.
+.SH FILES
+/dev/kmem
+.br
+/vmunix
+.SH SEE ALSO
+ipf(1), ipfstat(1)
+.SH BUGS
+none known.
diff --git a/contrib/ipfilter/man/ipftest.1 b/contrib/ipfilter/man/ipftest.1
new file mode 100644
index 0000000..912b3a3
--- /dev/null
+++ b/contrib/ipfilter/man/ipftest.1
@@ -0,0 +1,127 @@
+.TH ipftest 8
+.SH NAME
+ipftest \- test packet filter rules with arbitary input.
+.SH SYNOPSIS
+.B ipftest
+[
+.B \-vbdPSTEHX
+] [
+.B \-I
+interface
+]
+.B \-r
+<filename>
+[
+.B \-i
+<filename>
+]
+.SH DESCRIPTION
+.PP
+\fBipftest\fP is provided for the purpose of being able to test a set of
+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
+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
+.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).
+.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.
+.TP
+.B \-P
+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 \-S
+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
+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:
+.PP
+.nf
+ tcpdump -n
+ tcpdump -nq
+ tcpdump -nqt
+ 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.
+.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:
+.PP
+.nf
+ etherfind -n
+ etherfind -n -t
+.fi
+.LP
+.TP
+.BR \-i \0<filename>
+Specify the filename from which to take input. Default is stdin.
+.TP
+.BR \-r \0<filename>
+Specify the filename from which to read filter rules.
+.SH FILES
+.SH SEE ALSO
+ipf(1), ipf(5), snoop(1m), tcpdump(8), etherfind(8c)
+.SH BUGS
+Not all of the input formats are sufficiently capable of introducing a
+wide enough variety of packets for them to be all useful in testing.
diff --git a/contrib/ipfilter/man/ipl.4 b/contrib/ipfilter/man/ipl.4
new file mode 100644
index 0000000..0e58a50
--- /dev/null
+++ b/contrib/ipfilter/man/ipl.4
@@ -0,0 +1,62 @@
+.TH IPL 4
+.SH NAME
+ipl \- IP packet log device
+.SH DESCRIPTION
+The \fBipl\fP pseudo device's purpose is to provide an easy way to gather
+packet headers of packets you wish to log. If a packet header is to be
+logged, the entire header is logged (including any IP options \- TCP/UDP
+options are not included when it calculates header size) or not at all.
+The packet contents are also logged after the header.
+.PP
+Prepending every packet header logged is a structure containing information
+relevant to the packet following and why it was logged. The structure's
+format is as follows:
+.LP
+.nf
+struct ipl_ci {
+ u_long sec; /* time when the packet was logged */
+ u_long usec;
+ u_long plen; /* length of packet data logged */
+ u_short hlen; /* length of headers logged */
+ u_short rule; /* rule number (for log ...) or 0 if result = log */
+ u_long flags:24; /* XXX FIXME do we care about the extra bytes? */
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606))
+ u_long filler:8; /* XXX FIXME do we care? */
+ u_char ifname[IFNAMSIZ];
+#else
+ u_long unit:8;
+ u_char ifname[4];
+#endif
+};
+.fi
+.PP
+In the case of the header causing the buffer to finish on a non-32bit
+boundary, padding will be `appended' to ensure that the next log entry
+is aligned to a 32bit boundary.
+.LP
+.PP
+If the packet contents is more then 128 bytes, then only 128 bytes of the
+packet contents is logged. Should the packet contents finish on a non-32bit
+boundary, then the last few bytes are not logged to ensure the log entry
+is aligned to a 32bit boundary.
+
+\fBipl\fP is a read-only (sequential) character pseudo-device.
+
+The ioctls which are loaded with this device can be found under \fBipf(4)\fP.
+The only ioctl which is used for logging and doesn't affect the filter is:
+.LP
+.nf
+ ioctl(fd, SIOCIPFFB, int *)
+.fi
+.PP
+This ioctl flushes the log buffer and returns the number of bytes flushed.
+.PP
+There is currently no support for non-blocking IO with this device, meaning
+all read operations should be considered blocking in nature (if there is no
+data to read, it will sleep until some is made available).
+.SH SEE ALSO
+ipf(4)
+.SH BUGS
+Packet headers are dropped when the internal buffer (static size) fills.
+.SH FILES
+/dev/ipl0
diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8
new file mode 100644
index 0000000..11ac23a
--- /dev/null
+++ b/contrib/ipfilter/man/ipmon.8
@@ -0,0 +1,56 @@
+.TH ipmon 8
+.SH NAME
+ipmon \- monitors /dev/ipl for logged packets
+.SH SYNOPSIS
+.B ipmon
+[
+.B \-sfN
+] [
+<filename>
+]
+.SH DESCRIPTION
+.LP
+\fBipmon\fP opens \fB/dev/ipl\fP for reading and awaits data to be saved from
+the packet filter. The binary data read from the device is reprinted in
+human readable for, however, IP#'s are not mapped back to hostnames, nor are
+ports mapped back to service names. The output goes to standard output by
+default or a filename, if given on the command line. Should the \fB\-s\fP
+option be used, output is instead sent to \fBsyslogd(8)\fP. Messages sent
+via syslog have the day, month and year removed from the message, but the
+time (including microseconds), as recorded in the log, is still included.
+.SH OPTIONS
+.TP
+.B \-s
+Packet information read in will be sent through syslogd rather than
+saved to a file. The following levels are used:
+.IP
+.B LOG_INFO
+\- packets logged using the "log" keyword as the action rather
+than pass or block.
+.IP
+.B LOG_NOTICE
+\- packets logged which are also passed
+.IP
+.B LOG_WARNING
+\- packets logged which are also blocked
+.IP
+.B LOG_ERR
+\- packets which have been logged and which can be considered
+"short".
+.TP
+.B \-f
+Flush the current packet log buffer. The number of bytes flushed is displayed,
+even should the result be zero.
+.TP
+.B \-N
+IP addresses and port numbers will be mapped, where possible, back into
+hostnames and service names.
+.SH DIAGNOSTICS
+\fBipmon\fP expects data that it reads to be consistant with how it should be
+saved and will abort if it fails an assertion which detects an anomoly in the
+recorded data.
+.SH FILES
+/dev/ipl
+.SH SEE ALSO
+ipf(1), ipfstat(1)
+.SH BUGS
diff --git a/contrib/ipfilter/man/ipnat.1 b/contrib/ipfilter/man/ipnat.1
new file mode 100644
index 0000000..c61e03b
--- /dev/null
+++ b/contrib/ipfilter/man/ipnat.1
@@ -0,0 +1,45 @@
+.TH IPNAT 1
+.SH NAME
+ipnat \- user interface to the NAT
+.SH SYNOPSIS
+.B ipnat
+[
+.B \-lnrsvCF
+]
+.B \-f <\fIfilename\fP>
+.SH DESCRIPTION
+.PP
+\fBipnat\fP opens the filename given (treating "\-" as stdin) and parses the
+file for a set of rules which are to be added or removed from the IP NAT.
+.PP
+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.
+.SH OPTIONS
+.TP
+.B \-C
+delete all entries in the current NAT listing (NAT rules)
+.TP
+.B \-F
+delete all active entries in the current NAT table (currently active
+NAT mappings)
+.TP
+.B \-l
+Show the list of current NAT table entry mappings.
+.TP
+.B \-n
+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 \-v
+Turn verbose mode on. Displays information relating to rule processing.
+.DT
+.SH SEE ALSO
+ipfstat(1), ipftest(1), ipf(1), ipnat(5)
diff --git a/contrib/ipfilter/man/ipnat.4 b/contrib/ipfilter/man/ipnat.4
new file mode 100644
index 0000000..3346ef9
--- /dev/null
+++ b/contrib/ipfilter/man/ipnat.4
@@ -0,0 +1,88 @@
+.TH IPNAT 4
+.SH NAME
+ipnat \- Network Address Translation kernel interface
+.SH SYNOPSIS
+#include <sys/ip_fil.h>
+.SH IOCTLS
+.PP
+To add and delete rules to the NAT list, two 'basic' ioctls are provided
+for use. The ioctl's are called as:
+.LP
+.nf
+ ioctl(fd, SIOCADNAT, struct ipnat *)
+ ioctl(fd, SIOCRMNAT, struct ipnat *)
+.fi
+.PP
+Unlike \fBipf(4)\fP, there is only a single list supported by the kernel NAT
+interface. An inactive list which can be swapped to is not currently
+supported.
+
+These ioctl's are implemented as being routing ioctls and thus the same rules
+for the various routing ioctls and the file descriptor are employed, mainly
+being that the fd must be that of the device associated with the module
+(i.e., /dev/ipl).
+.LP
+.PP
+The strcture used with the NAT interface is described below:
+.LP
+.nf
+typedef struct ipnat {
+ struct ipnat *in_next;
+ void *in_ifp;
+ u_short in_flags;
+ u_short in_pnext;
+ u_short in_port[2];
+ struct in_addr in_in[2];
+ struct in_addr in_out[2];
+ struct in_addr in_nextip;
+ int in_space;
+ int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */
+ char in_ifname[IFNAMSIZ];
+} 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
+
+.fi
+.PP
+Recognised values for in_redir:
+.LP
+.nf
+#define NAT_MAP 0
+#define NAT_REDIRECT 1
+.fi
+.PP
+.LP
+\fBNAT statistics\fP
+Statistics on the the number of packets mapped, going in and out are kept,
+the number of times a new entry is added and deleted (through expiration) to
+the NAT table and the current usage level of the NAT table.
+.PP
+Pointers to the NAT table inside the kernel, as well as to the top of the
+internal NAT lists constructed with the \fBSIOCADNAT\fP ioctls. The table
+itself is a hash table of size NAT_SIZE (default size is 367).
+.PP
+To retrieve the statistics, the \fBSIOCGNATS\fP ioctl must be used, with
+the appropriate structure passed by reference, as follows:
+.nf
+ ioctl(fd, SIOCGNATS, struct natstat *)
+
+typedef struct natstat {
+ u_long ns_mapped[2];
+ u_long ns_added;
+ u_long ns_expire;
+ u_long ns_inuse;
+ nat_t ***ns_table;
+ ipnat_t *ns_list;
+} natstat_t;
+.fi
+.SH BUGS
+It would be nice if there were more flexibility when adding and deleting
+filter rules.
+.SH SEE ALSO
+ipfstat(1), ipf(1), ipf(4), ipnat(5)
diff --git a/contrib/ipfilter/man/ipnat.5 b/contrib/ipfilter/man/ipnat.5
new file mode 100644
index 0000000..7832623
--- /dev/null
+++ b/contrib/ipfilter/man/ipnat.5
@@ -0,0 +1,70 @@
+.TH IPNAT 5
+.SH NAME
+ipnat \- IP NAT file format
+.SH DESCRIPTION
+The format for files accepted by ipnat is described by the following grammar:
+.LP
+.nf
+ipmap :: = mapit ifname ipmask "->" ipmask [ mapport ] .
+
+mapit ::= "map" | "rdr" .
+ipmask ::= ip "/" bits | ip "/" mask | ip "netmask" mask .
+mapport ::= "portmap" tcpudp portnumber ":" portnumber .
+
+tcpudp ::= "tcp" | "udp" | "tcp/udp" .
+portnumber ::= number { numbers } .
+ifname ::= 'A' - 'Z' { 'A' - 'Z' } numbers .
+
+numbers ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' .
+.fi
+.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.
+.PP
+Packets which will be rewritten can only be selected by matching the original
+source address. A netmask must be specified with the IP address.
+.PP
+The address selected for replacing the original is chosen from an IP#/netmask
+pair. A netmask of all 1's indicating a hostname is valid. A netmask of
+31 1's (255.255.255.254) is considered invalid as there is no space for
+allocating host IP#'s after consideration for broadcast and network
+addresses.
+.PP
+When remapping TCP and UDP packets, it is also possible to change the source
+port number. Either TCP or UDP or both can be selected by each rule, with a
+range of port numbers to remap into given as \fBport-number:port-number\fP.
+.SH Examples
+.PP
+To change IP#'s used internally from network 10 into an ISP provided 8 bit
+subnet at 209.1.2.0, the following would be used:
+.LP
+.nf
+map 10.0.0.0/8 -> 209.1.2.0/24
+.fi
+.PP
+The obvious problem here is we're trying to squeeze over 16,000,000 IP
+addresses into a 254 address space. To increase the scope, remapping for TCP
+and/or UDP, port remapping can be used;
+.LP
+.nf
+map 10.0.0.0/8 -> 209.1.2.0/24 portmap tcp/udp 1025:65000
+.fi
+.PP
+which falls only 527,566 `addresses' short of the space available in network
+10. If we were to combine these rules, they would need to be specified as
+follows:
+.LP
+.nf
+map 10.0.0.0/8 -> 209.1.2.0/24 portmap tcp/udp 1025:65000
+map 10.0.0.0/8 -> 209.1.2.0/24
+.fi
+.PP
+so that all TCP/UDP packets were port mapped and only other protocols, such as
+ICMP, only have their IP# changed.
+.SH FILES
+/etc/services
+.br
+/etc/hosts
+.SH SEE ALSO
+ipnat(1), ipf(5), ipnat(4)
diff --git a/contrib/ipfilter/misc.c b/contrib/ipfilter/misc.c
new file mode 100644
index 0000000..dc6e92c
--- /dev/null
+++ b/contrib/ipfilter/misc.c
@@ -0,0 +1,85 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.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_var.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include "ip_fil.h"
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)misc.c 1.3 2/4/96 (C) 1995 Darren Reed";
+static char rcsid[] = "$Id: misc.c,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $";
+#endif
+
+void debug(), verbose();
+
+extern int opts;
+
+
+void printpacket(ip)
+struct ip *ip;
+{
+ struct tcphdr *tcp;
+
+ tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2));
+ printf("ip %d(%d) %d ", ip->ip_len, ip->ip_hl << 2, ip->ip_p);
+ if (ip->ip_off & 0x1fff)
+ printf("@%d", ip->ip_off << 3);
+ (void)printf(" %s", inet_ntoa(ip->ip_src));
+ if (!(ip->ip_off & 0x1fff))
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ (void)printf(",%d", ntohs(tcp->th_sport));
+ (void)printf(" > ");
+ (void)printf("%s", inet_ntoa(ip->ip_dst));
+ if (!(ip->ip_off & 0x1fff))
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ (void)printf(",%d", ntohs(tcp->th_dport));
+ putchar('\n');
+}
+
+
+void verbose(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+char *fmt, *p1, *p2, *p3, *p4, *p5, *p6, *p7,*p8,*p9;
+{
+ if (opts & OPT_VERBOSE)
+ printf(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+}
+
+
+void debug(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+char *fmt, *p1, *p2, *p3, *p4, *p5, *p6, *p7,*p8,*p9;
+{
+ if (opts & OPT_DEBUG)
+ printf(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+}
diff --git a/contrib/ipfilter/mkfilters b/contrib/ipfilter/mkfilters
new file mode 100644
index 0000000..4cd7059
--- /dev/null
+++ b/contrib/ipfilter/mkfilters
@@ -0,0 +1,65 @@
+#!/usr/local/bin/perl
+# for best results, bring up all your interfaces before running this
+open(I, "ifconfig -a|") || die $!;
+while (<I>) {
+ chop;
+ if (/^[a-zA-Z]+\d+:/) {
+ ($iface = $_) =~ s/^([a-zA-Z]+\d+).*/$1/;
+ $ifaces{$iface} = $iface;
+ next;
+ }
+ if (/inet/) {
+ if (/\-\-\>/) { # PPP, (SLIP?)
+ ($inet{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$1/;
+ ($ppp{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$2/;
+ } else {
+ ($inet{$iface} = $_) =~ s/.*inet ([^ ]+).*/$1/;
+ }
+ }
+ if (/netmask/) {
+ ($mask = $_) =~ s/.*netmask ([^ ]+).*/$1/;
+ $mask =~ s/^/0x/ if ($mask =~ /^[0-9a-f]*$/);
+ $netmask{$iface} = $mask;
+ }
+ if (/broadcast/) {
+ ($bcast{$iface} = $_) =~ s/.*broadcast ([^ ]+).*/$1/;
+ }
+}
+foreach $i (keys %ifaces) {
+ $net{$i} = $inet{$i}."/".$netmask{$i} if (defined($inet{$i}));
+}
+#
+# print out route suggestions
+#
+print "#\n";
+print "# The following routes should be configured, if not already:\n";
+print "#\n";
+foreach $i (keys %ifaces) {
+ next if (($i =~ /lo/) || !defined($net{$i}) || defined($ppp{$i}));
+ print "# route add $inet{$i} localhost 0\n";
+}
+print "#\n";
+
+#
+# print out some generic filters which people should use somewhere near the top
+#
+print "block in log quick from any to any with ipopts\n";
+print "block in log quick proto tcp from any to any with short\n";
+
+foreach $i (keys %ifaces) {
+ if (!defined($inet{$i})) {
+ next;
+ }
+ if ($i !~ /lo/) {
+ print "block in on $i from 127.0.0.0/8 to any\n";
+ print "block out on $i from 127.0.0.0/8 to any\n";
+ print "block out on $i from any to 127.0.0.0/8\n";
+ print "block in on $i from $inet{$i}/32 to any\n";
+ print "block out on $i from any to $inet{$i}/32\n";
+ foreach $j (keys %ifaces) {
+ if ($i ne $j && $j !~ /^lo/ && defined($net{$j})) {
+ print "block in on $i from $net{$j} to any\n";
+ }
+ }
+ }
+}
diff --git a/contrib/ipfilter/ml_ipl.c b/contrib/ipfilter/ml_ipl.c
new file mode 100644
index 0000000..9c3ec3e
--- /dev/null
+++ b/contrib/ipfilter/ml_ipl.c
@@ -0,0 +1,167 @@
+/*
+ * (C)opyright 1993,1994,1995 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. The author accepts no
+ * responsibility and is not changed in any way.
+ *
+ * I hate legaleese, don't you ?
+ */
+/*
+ * 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/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <sys/syslog.h>
+#include <sys/buf.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+#include <sundev/mbvar.h>
+#include <sun/autoconf.h>
+#include <sun/vddrv.h>
+#if defined(sun4c) || defined(sun4m)
+#include <sun/openprom.h>
+#endif
+
+#ifndef IPL_NAME
+#define IPL_NAME "/dev/ipl"
+#endif
+
+extern int iplattach(), iplopen(), iplclose(), iplioctl(), iplread();
+extern int nulldev(), iplidentify(), errno;
+
+struct cdevsw ipldevsw =
+{
+ iplopen, iplclose, iplread, nulldev,
+ iplioctl, nulldev, nulldev, nulldev,
+ 0, nulldev,
+};
+
+
+struct dev_ops ipl_ops =
+{
+ 1,
+ iplidentify,
+ iplattach,
+ iplopen,
+ iplclose,
+ iplread,
+ NULL, /* write */
+ NULL, /* strategy */
+ NULL, /* dump */
+ 0, /* psize */
+ iplioctl,
+ NULL, /* reset */
+ NULL /* mmap */
+};
+
+int ipl_major = 0;
+
+#ifdef sun4m
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO,
+ "ipl",
+ &ipl_ops,
+ NULL,
+ &ipldevsw,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 1,
+};
+#else /* sun4m */
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO, /* magic */
+ "ipl", /* name */
+#ifdef sun4c
+ &ipl_ops, /* dev_ops */
+#else
+ NULL, /* struct mb_ctlr *mb_ctlr */
+ NULL, /* struct mb_driver *mb_driver */
+ NULL, /* struct mb_device *mb_device */
+ 0, /* num ctlrs */
+ 1, /* numdevs */
+#endif /* sun4c */
+ NULL, /* bdevsw */
+ &ipldevsw, /* cdevsw */
+ 0, /* block major */
+ 0, /* char major */
+};
+#endif /* sun4m */
+
+extern int vd_unuseddev();
+extern struct cdevsw cdevsw[];
+extern int nchrdev;
+
+xxxinit(fc, vdp, vdi, vds)
+u_int fc;
+struct vddrv *vdp;
+caddr_t vdi;
+struct vdstat *vds;
+{
+ struct vdlinkage *v;
+ int i;
+
+ switch (fc)
+ {
+ case VDLOAD:
+ while (ipl_major < nchrdev &&
+ cdevsw[ipl_major].d_open != vd_unuseddev)
+ ipl_major++;
+ if (ipl_major == nchrdev)
+ return ENODEV;
+ vd.Drv_charmajor = ipl_major;
+ vdp->vdd_vdtab = (struct vdlinkage *)&vd;
+ return ipl_attach(vdi);
+ case VDUNLOAD:
+ return unload(vdp, vdi);
+
+ case VDSTAT:
+ return 0;
+
+ default:
+ return EIO;
+ }
+}
+
+static unload(vdp, vdi)
+ struct vddrv *vdp;
+ struct vdioctl_unload *vdi;
+{
+ int i;
+
+ (void) vn_remove(IPL_NAME, UIO_SYSSPACE, FILE);
+ return ipldetach();
+}
+
+
+static int ipl_attach(vdi)
+struct vdioctl_load *vdi;
+{
+ struct vnode *vp;
+ struct vattr vattr;
+ int error = 0, fmode = S_IFCHR|0600;
+
+ (void) vn_remove(IPL_NAME, UIO_SYSSPACE, FILE);
+ vattr_null(&vattr);
+ vattr.va_type = MFTOVT(fmode);
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = ipl_major<<8;
+
+ error = vn_create(IPL_NAME, UIO_SYSSPACE, &vattr, EXCL, 0, &vp);
+ if (error == 0)
+ VN_RELE(vp);
+ return iplattach(0);
+}
diff --git a/contrib/ipfilter/mln_ipl.c b/contrib/ipfilter/mln_ipl.c
new file mode 100644
index 0000000..08a9c36
--- /dev/null
+++ b/contrib/ipfilter/mln_ipl.c
@@ -0,0 +1,237 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+/*
+ * 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>
+
+/*
+ * Post NetBSD 1.2 has the PFIL interface for packet filters. This turns
+ * on those hooks. We don't need any special mods with this!
+ */
+#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \
+ (defined(NetBSD1_2) && NetBSD1_2 > 1)
+# define NETBSD_PF
+#endif
+
+#if defined(__FreeBSD__) && (__FreeBSD__ > 1)
+# include <osreldate.h>
+#endif
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/uio.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 defined(__NetBSD__) || (defined(__FreeBSD_version) && \
+ (__FreeBSD_version >= 199607))
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#endif
+#ifndef __NetBSD__
+#include <sys/sysent.h>
+#endif
+#include <sys/lkm.h>
+#include "ipl.h"
+#include "ip_fil.h"
+
+#ifndef IPL_NAME
+#define IPL_NAME "/dev/ipl"
+#endif
+#if !defined(VOP_LEASE) && defined(LEASE_CHECK)
+#define VOP_LEASE LEASE_CHECK
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+extern int lkmenodev(), lkmexists(), lkmdispatch();
+
+extern int iplattach(), iplopen(), iplclose(), iplioctl(), ipldetach();
+#ifdef NETBSD_PF
+#include <net/pfil.h>
+#endif
+#ifdef IPFILTER_LOG
+extern int iplread();
+#else
+#ifdef NETBSD_PF
+#define iplread enodev
+#else
+#define iplread nodev
+#endif
+#endif
+extern int iplidentify();
+
+#ifdef NETBSD_PF
+int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **)) = NULL;
+#endif
+
+static int ipl_unload(), ipl_load();
+#if (defined(NetBSD1_0) && (NetBSD1_0 > 1)) || \
+ (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199511))
+struct cdevsw ipldevsw =
+{
+ iplopen, /* open */
+ iplclose, /* close */
+ iplread, /* read */
+ 0, /* write */
+ iplioctl, /* ioctl */
+ 0, /* stop */
+ 0, /* tty */
+ 0, /* select */
+ 0, /* mmap */
+ NULL /* strategy */
+};
+#else
+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 */
+};
+#endif
+static struct cdevsw cdev_sav;
+int ipl_major = 0;
+
+MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
+
+extern int vd_unuseddev();
+extern struct cdevsw cdevsw[];
+extern int nchrdev;
+
+static int iplaction(lkmtp, cmd)
+struct lkm_table *lkmtp;
+int cmd;
+{
+ int i;
+ struct lkm_dev *args = lkmtp->private.lkm_dev;
+ int err = 0;
+
+ switch (cmd)
+ {
+ case LKM_E_LOAD :
+ if (lkmexists(lkmtp))
+ return EEXIST;
+
+ for (i = 0; i < nchrdev; i++)
+ if (cdevsw[i].d_open == lkmenodev ||
+ cdevsw[i].d_open == iplopen)
+ break;
+ if (i == nchrdev) {
+ printf("IP Filter: No free cdevsw slots\n");
+ return ENODEV;
+ }
+
+ ipl_major = i;
+ args->lkm_offset = i; /* slot in cdevsw[] */
+ printf("IP Filter: loaded into slot %d\n", ipl_major);
+ return ipl_load();
+ case LKM_E_UNLOAD :
+ printf("IP Filter: unloaded from slot %d\n", ipl_major);
+ return ipl_unload();
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return 0;
+}
+
+
+static int ipl_remove()
+{
+ struct nameidata nd;
+ int error;
+
+ NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, IPL_NAME, curproc);
+ if ((error = namei(&nd)))
+ return (error);
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+ VOP_LOCK(nd.ni_vp);
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ return VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+}
+
+
+static int ipl_unload()
+{
+ int error;
+
+ error = ipldetach();
+#ifdef NETBSD_PF
+ pfil_remove_hook(fr_check, PFIL_IN|PFIL_OUT);
+#endif
+ if (!error)
+ error = ipl_remove();
+ return error;
+}
+
+
+static int ipl_load()
+{
+ struct nameidata nd;
+ struct vattr vattr;
+ int error, fmode = S_IFCHR|0600;
+
+ error = iplattach();
+#ifdef NETBSD_PF
+ pfil_add_hook(fr_check, PFIL_IN|PFIL_OUT);
+#endif
+ if (error)
+ return error;
+ (void) ipl_remove();
+ error = 0;
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, IPL_NAME, curproc);
+ if (error = namei(&nd))
+ return error;
+ if (nd.ni_vp != NULL) {
+ VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ vrele(nd.ni_vp);
+ return (EEXIST);
+ }
+ VATTR_NULL(&vattr);
+ vattr.va_type = VCHR;
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = ipl_major<<8;
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ return VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+}
+
+
+int xxxinit(lkmtp, cmd, ver)
+struct lkm_table *lkmtp;
+int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction);
+}
diff --git a/contrib/ipfilter/mls_ipl.c b/contrib/ipfilter/mls_ipl.c
new file mode 100644
index 0000000..22e2db9
--- /dev/null
+++ b/contrib/ipfilter/mls_ipl.c
@@ -0,0 +1,174 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+/*
+ * 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/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <sys/syslog.h>
+#include <sys/buf.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+#include <sundev/mbvar.h>
+#include <sun/autoconf.h>
+#include <sun/vddrv.h>
+#if defined(sun4c) || defined(sun4m)
+# include <sun/openprom.h>
+#endif
+#include "ipl.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)mls_ipl.c 2.6 10/15/95 (C) 1993-1995 Darren Reed";
+static char rcsid[] = "$Id: mls_ipl.c,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $";
+#endif
+
+#ifndef IPL_NAME
+#define IPL_NAME "/dev/ipl"
+#endif
+
+extern int iplattach(), iplopen(), iplclose(), iplioctl(), ipldetach();
+#ifdef IPFILTER_LOG
+extern int iplread();
+#else
+#define iplread nulldev
+#endif
+extern int nulldev(), iplidentify(), errno;
+
+static int unload(), ipl_attach();
+
+struct cdevsw ipldevsw =
+{
+ iplopen, iplclose, iplread, nulldev,
+ iplioctl, nulldev, nulldev, nulldev,
+ 0, nulldev,
+};
+
+
+struct dev_ops ipl_ops =
+{
+ 1,
+ iplidentify,
+ iplattach,
+ iplopen,
+ iplclose,
+ iplread,
+ NULL, /* write */
+ NULL, /* strategy */
+ NULL, /* dump */
+ 0, /* psize */
+ iplioctl,
+ NULL, /* reset */
+ NULL /* mmap */
+};
+
+int ipl_major = 0;
+
+#ifdef sun4m
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO,
+ IPL_VERSION,
+ &ipl_ops,
+ NULL,
+ &ipldevsw,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 1,
+};
+#else /* sun4m */
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO, /* magic */
+ IPL_VERSION,
+#ifdef sun4c
+ &ipl_ops, /* dev_ops */
+#else
+ NULL, /* struct mb_ctlr *mb_ctlr */
+ NULL, /* struct mb_driver *mb_driver */
+ NULL, /* struct mb_device *mb_device */
+ 0, /* num ctlrs */
+ 1, /* numdevs */
+#endif /* sun4c */
+ NULL, /* bdevsw */
+ &ipldevsw, /* cdevsw */
+ 0, /* block major */
+ 0, /* char major */
+};
+#endif /* sun4m */
+
+extern int vd_unuseddev();
+extern struct cdevsw cdevsw[];
+extern int nchrdev;
+
+xxxinit(fc, vdp, vdi, vds)
+u_int fc;
+struct vddrv *vdp;
+caddr_t vdi;
+struct vdstat *vds;
+{
+ switch (fc)
+ {
+ case VDLOAD:
+ while (ipl_major < nchrdev &&
+ cdevsw[ipl_major].d_open != vd_unuseddev)
+ ipl_major++;
+ if (ipl_major == nchrdev)
+ return ENODEV;
+ vd.Drv_charmajor = ipl_major;
+ vdp->vdd_vdtab = (struct vdlinkage *)&vd;
+ return ipl_attach();
+ case VDUNLOAD:
+ return unload();
+ case VDSTAT:
+ return 0;
+ default:
+ return EIO;
+ }
+}
+
+static int unload()
+{
+ int err;
+
+ err = ipldetach();
+ if (!err)
+ (void) vn_remove(IPL_NAME, UIO_SYSSPACE, FILE);
+ return err;
+}
+
+
+static int ipl_attach()
+{
+ struct vnode *vp;
+ struct vattr vattr;
+ int error = 0, fmode = S_IFCHR|0600;
+
+ error = iplattach();
+ if (error)
+ return error;
+ (void) vn_remove(IPL_NAME, UIO_SYSSPACE, FILE);
+ vattr_null(&vattr);
+ vattr.va_type = MFTOVT(fmode);
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = ipl_major<<8;
+
+ error = vn_create(IPL_NAME, UIO_SYSSPACE, &vattr, EXCL, 0, &vp);
+ if (error == 0)
+ VN_RELE(vp);
+ return error;
+}
diff --git a/contrib/ipfilter/opt.c b/contrib/ipfilter/opt.c
new file mode 100644
index 0000000..4576b55
--- /dev/null
+++ b/contrib/ipfilter/opt.c
@@ -0,0 +1,134 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <string.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 <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include "ip_compat.h"
+#include "ipf.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] = "@(#)opt.c 1.8 4/10/96 (C) 1993-1995 Darren Reed";
+static char rcsid[] = "$Id: opt.c,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $";
+#endif
+
+extern int opts;
+
+struct ipopt_names ionames[] ={
+ { IPOPT_NOP, 0x000001, 1, "nop" },
+ { IPOPT_RR, 0x000002, 7, "rr" }, /* 1 route */
+ { IPOPT_ZSU, 0x000004, 3, "zsu" },
+ { IPOPT_MTUP, 0x000008, 3, "mtup" },
+ { IPOPT_MTUR, 0x000010, 3, "mtur" },
+ { IPOPT_ENCODE, 0x000020, 3, "encode" },
+ { IPOPT_TS, 0x000040, 8, "ts" }, /* 1 TS */
+ { IPOPT_TR, 0x000080, 3, "tr" },
+ { IPOPT_SECURITY,0x000100, 11, "sec" },
+ { IPOPT_SECURITY,0x000100, 11, "sec-class" },
+ { IPOPT_LSRR, 0x000200, 7, "lsrr" }, /* 1 route */
+ { IPOPT_E_SEC, 0x000400, 3, "e-sec" },
+ { IPOPT_CIPSO, 0x000800, 3, "cipso" },
+ { IPOPT_SATID, 0x001000, 4, "satid" },
+ { IPOPT_SSRR, 0x002000, 7, "ssrr" }, /* 1 route */
+ { IPOPT_ADDEXT, 0x004000, 3, "addext" },
+ { IPOPT_VISA, 0x008000, 3, "visa" },
+ { IPOPT_IMITD, 0x010000, 3, "imitd" },
+ { IPOPT_EIP, 0x020000, 3, "eip" },
+ { IPOPT_FINN, 0x040000, 3, "finn" },
+ { 0, 0, 0, (char *)NULL } /* must be last */
+};
+
+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 */
+};
+
+
+static 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_long buildopts(cp, op)
+char *cp, *op;
+{
+ struct ipopt_names *io;
+ u_char lvl;
+ u_long msk = 0;
+ char *s, *t;
+ int len = 0;
+
+ 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 ((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) {
+ *op++ = io->on_siz;
+ *op++ = IPOPT_MINOFF;
+
+ if (t && !strcasecmp(s, "sec-class")) {
+ lvl = seclevel(t);
+ *(op - 1) = lvl;
+ }
+ 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);
+ 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/parse.c b/contrib/ipfilter/parse.c
new file mode 100644
index 0000000..1c463e8
--- /dev/null
+++ b/contrib/ipfilter/parse.c
@@ -0,0 +1,1249 @@
+/*
+ * (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.
+ */
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include "ip_fil.h"
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include "ipf.h"
+#include <ctype.h>
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sccsid[] ="@(#)parse.c 1.44 6/5/96 (C) 1993-1996 Darren Reed";
+static char rcsid[] = "$Id: parse.c,v 2.0.1.1 1997/01/09 15:14:44 darrenr Exp $";
+#endif
+
+extern struct ipopt_names ionames[], secclass[];
+extern int opts;
+extern int gethostname();
+
+u_long hostnum(), optname();
+u_short portnum();
+u_char tcp_flags();
+struct frentry *parse();
+void binprint(), printfr();
+int addicmp(), extras(), hostmask(), ports(), icmpcode(), addkeep();
+int to_interface();
+
+
+char *proto = NULL;
+char flagset[] = "FSRPAU";
+u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG };
+
+static char thishost[64];
+
+
+void initparse()
+{
+ gethostname(thishost, sizeof(thishost));
+ thishost[sizeof(thishost) - 1] = '\0';
+}
+
+
+/* parse()
+ *
+ * parse a line read from the input filter rule file
+ */
+struct frentry *parse(line)
+char *line;
+{
+ static struct frentry fil;
+ struct protoent *p = NULL;
+ char *cps[31], **cpp;
+ u_char ch;
+ int i, cnt = 1;
+
+ while (*line && isspace(*line))
+ line++;
+ if (!*line)
+ return NULL;
+
+ bzero((char *)&fil, sizeof(fil));
+ fil.fr_mip.fi_v = 0xf;
+ fil.fr_ip.fi_v = 4;
+ /*
+ * 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) {
+ (void)fprintf(stderr,"not enough segments in line\n");
+ return NULL;
+ }
+
+ cpp = cps;
+ if (**cpp == '@')
+ fil.fr_hits = atoi(*cpp++ + 1) + 1;
+
+ if (!strcasecmp("block", *cpp)) {
+ fil.fr_flags = FR_BLOCK;
+ if (!strncasecmp(*(cpp+1), "return-icmp", 11)) {
+ fil.fr_flags |= FR_RETICMP;
+ cpp++;
+ if (*(*cpp + 11) == '(') {
+ fil.fr_icode = icmpcode(*cpp + 12);
+ if (fil.fr_icode == -1) {
+ fprintf(stderr,
+ "uncrecognised icmp code %s\n",
+ *cpp + 12);
+ return NULL;
+ }
+ }
+ } else if (!strncasecmp(*(cpp+1), "return-rst", 10)) {
+ fil.fr_flags |= FR_RETRST;
+ cpp++;
+ }
+ } else if (!strcasecmp("count", *cpp)) {
+ fil.fr_flags = FR_ACCOUNT;
+ } else if (!strcasecmp("pass", *cpp)) {
+ fil.fr_flags = FR_PASS;
+ } else if (!strcasecmp("log", *cpp)) {
+ fil.fr_flags = FR_LOG;
+ if (!strcasecmp(*(cpp+1), "body")) {
+ fil.fr_flags |= FR_LOGBODY;
+ cpp++;
+ }
+ if (!strcasecmp(*(cpp+1), "first")) {
+ fil.fr_flags |= FR_LOGFIRST;
+ cpp++;
+ }
+ } else {
+ /*
+ * Doesn't start with one of the action words
+ */
+ (void)fprintf(stderr, "unknown keyword (%s)\n", *cpp);
+ return NULL;
+ }
+ cpp++;
+
+ if (!strcasecmp("in", *cpp))
+ fil.fr_flags |= FR_INQUE;
+ else if (!strcasecmp("out", *cpp))
+ fil.fr_flags |= FR_OUTQUE;
+ else {
+ (void)fprintf(stderr,
+ "missing 'in'/'out' keyword (%s)\n", *cpp);
+ return NULL;
+ }
+ if (!*++cpp)
+ return NULL;
+
+ if (!strcasecmp("log", *cpp)) {
+ cpp++;
+ if (fil.fr_flags & FR_PASS)
+ fil.fr_flags |= FR_LOGP;
+ else if (fil.fr_flags & FR_BLOCK)
+ fil.fr_flags |= FR_LOGB;
+ if (!strcasecmp(*cpp, "body")) {
+ fil.fr_flags |= FR_LOGBODY;
+ cpp++;
+ }
+ if (!strcasecmp(*cpp, "first")) {
+ fil.fr_flags |= FR_LOGFIRST;
+ cpp++;
+ }
+ if (!strcasecmp(*cpp, "or-block")) {
+ if (!(fil.fr_flags & FR_PASS)) {
+ (void)fprintf(stderr,
+ "or-block must be used with pass\n");
+ return NULL;
+ }
+ fil.fr_flags |= FR_LOGORBLOCK;
+ cpp++;
+ }
+ }
+
+ if (!strcasecmp("quick", *cpp)) {
+ cpp++;
+ fil.fr_flags |= FR_QUICK;
+ }
+
+ *fil.fr_ifname = '\0';
+ if (*cpp && !strcasecmp(*cpp, "on")) {
+ if (!*++cpp) {
+ (void)fprintf(stderr, "interface name missing\n");
+ return NULL;
+ }
+ (void)strncpy(fil.fr_ifname, *cpp, IFNAMSIZ-1);
+ fil.fr_ifname[IFNAMSIZ-1] = '\0';
+ cpp++;
+ if (!*cpp) {
+ if (fil.fr_flags & FR_RETRST) {
+ (void)fprintf(stderr,
+ "%s can only be used with TCP\n",
+ "return-rst");
+ return NULL;
+ }
+ return &fil;
+ }
+
+ if (*cpp) {
+ if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) {
+ cpp++;
+ if (to_interface(&fil.fr_dif, *cpp))
+ return NULL;
+ cpp++;
+ }
+ if (!strcasecmp(*cpp, "to") && *(cpp + 1)) {
+ cpp++;
+ if (to_interface(&fil.fr_tif, *cpp))
+ return NULL;
+ cpp++;
+ } else if (!strcasecmp(*cpp, "fastroute")) {
+ fil.fr_flags |= FR_FASTROUTE;
+ cpp++;
+ }
+ }
+ }
+ if (*cpp && !strcasecmp(*cpp, "tos")) {
+ if (!*++cpp) {
+ (void)fprintf(stderr, "tos missing value\n");
+ return NULL;
+ }
+ fil.fr_tos = strtol(*cpp, NULL, 0);
+ fil.fr_mip.fi_tos = 0xff;
+ cpp++;
+ }
+
+ if (*cpp && !strcasecmp(*cpp, "ttl")) {
+ if (!*++cpp) {
+ (void)fprintf(stderr, "ttl missing hopcount value\n");
+ return NULL;
+ }
+ fil.fr_ttl = atoi(*cpp);
+ fil.fr_mip.fi_ttl = 0xff;
+ cpp++;
+ }
+
+ /*
+ * check for "proto <protoname>" only decode udp/tcp/icmp as protoname
+ */
+ proto = NULL;
+ if (*cpp && !strcasecmp(*cpp, "proto")) {
+ if (!*++cpp) {
+ (void)fprintf(stderr, "protocol name missing\n");
+ return NULL;
+ }
+ if (!strcasecmp(*cpp, "tcp/udp")) {
+ fil.fr_ip.fi_fl |= FI_TCPUDP;
+ fil.fr_mip.fi_fl |= FI_TCPUDP;
+ } else {
+ if (!(p = getprotobyname(*cpp)) && !isdigit(**cpp)) {
+ (void)fprintf(stderr,
+ "unknown protocol (%s)\n", *cpp);
+ return NULL;
+ }
+ if (p)
+ fil.fr_proto = p->p_proto;
+ else if (isdigit(**cpp))
+ fil.fr_proto = atoi(*cpp);
+ fil.fr_mip.fi_p = 0xff;
+ }
+ proto = *cpp;
+ if (fil.fr_proto != IPPROTO_TCP && fil.fr_flags & FR_RETRST) {
+ (void)fprintf(stderr,
+ "%s can only be used with TCP\n",
+ "return-rst");
+ return NULL;
+ }
+ if (!*++cpp)
+ return &fil;
+ }
+ if (fil.fr_proto != IPPROTO_TCP && fil.fr_flags & FR_RETRST) {
+ (void)fprintf(stderr, "%s can only be used with TCP\n",
+ "return-rst");
+ return NULL;
+ }
+
+ /*
+ * get the from host and bit mask to use against packets
+ */
+
+ if (!*cpp) {
+ fprintf(stderr, "missing source specification\n");
+ return NULL;
+ }
+ if (!strcasecmp(*cpp, "all")) {
+ cpp++;
+ if (!*cpp)
+ return &fil;
+ } else {
+ if (strcasecmp(*cpp, "from")) {
+ (void)fprintf(stderr,
+ "unexpected keyword (%s) - from\n", *cpp);
+ return NULL;
+ }
+ if (!*++cpp) {
+ (void)fprintf(stderr, "missing host after from\n");
+ return NULL;
+ }
+ ch = 0;
+ if (hostmask(&cpp, &fil.fr_src, &fil.fr_smsk,
+ &fil.fr_sport, &ch, &fil.fr_stop)) {
+ (void)fprintf(stderr, "bad host (%s)\n", *cpp);
+ return NULL;
+ }
+ fil.fr_scmp = ch;
+ if (!*cpp) {
+ (void)fprintf(stderr, "missing to fields\n");
+ return NULL;
+ }
+
+ /*
+ * do the same for the to field (destination host)
+ */
+ if (strcasecmp(*cpp, "to")) {
+ (void)fprintf(stderr,
+ "unexpected keyword (%s) - to\n", *cpp);
+ return NULL;
+ }
+ if (!*++cpp) {
+ (void)fprintf(stderr, "missing host after to\n");
+ return NULL;
+ }
+ ch = 0;
+ if (hostmask(&cpp, &fil.fr_dst, &fil.fr_dmsk,
+ &fil.fr_dport, &ch, &fil.fr_dtop)) {
+ (void)fprintf(stderr, "bad host (%s)\n", *cpp);
+ return NULL;
+ }
+ fil.fr_dcmp = ch;
+ }
+
+ /*
+ * check some sanity, make sure we don't have icmp checks with tcp
+ * or udp or visa versa.
+ */
+ if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) &&
+ fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) {
+ (void)fprintf(stderr, "port operation on non tcp/udp\n");
+ return NULL;
+ }
+ if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) {
+ (void)fprintf(stderr, "icmp comparisons on wrong protocol\n");
+ return NULL;
+ }
+
+ if (!*cpp)
+ return &fil;
+
+ if (*cpp && !strcasecmp(*cpp, "flags")) {
+ if (!*++cpp) {
+ (void)fprintf(stderr, "no flags present\n");
+ return NULL;
+ }
+ fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm);
+ cpp++;
+ }
+
+ /*
+ * extras...
+ */
+ if (*cpp && (!strcasecmp(*cpp, "with") || !strcasecmp(*cpp, "and")))
+ if (extras(&cpp, &fil))
+ return NULL;
+
+ /*
+ * icmp types for use with the icmp protocol
+ */
+ if (*cpp && !strcasecmp(*cpp, "icmp-type")) {
+ if (fil.fr_proto != IPPROTO_ICMP) {
+ (void)fprintf(stderr,
+ "icmp with wrong protocol (%d)\n",
+ fil.fr_proto);
+ return NULL;
+ }
+ if (addicmp(&cpp, &fil))
+ return NULL;
+ fil.fr_icmp = htons(fil.fr_icmp);
+ fil.fr_icmpm = htons(fil.fr_icmpm);
+ }
+
+ /*
+ * Keep something...
+ */
+ while (*cpp && !strcasecmp(*cpp, "keep"))
+ if (addkeep(&cpp, &fil))
+ return NULL;
+
+ /*
+ * leftovers...yuck
+ */
+ if (*cpp && **cpp) {
+ fprintf(stderr, "unknown words at end: [");
+ for (; *cpp; cpp++)
+ (void)fprintf(stderr, "%s ", *cpp);
+ (void)fprintf(stderr, "]\n");
+ return NULL;
+ }
+
+ /*
+ * lazy users...
+ */
+ if (!fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp || fil.fr_tcpf)) {
+ (void)fprintf(stderr,
+ "no protocol given for TCP/UDP comparisons\n");
+ return NULL;
+ }
+/*
+ if ((fil.fr_flags & FR_KEEPFRAG) &&
+ (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) {
+ (void)fprintf(stderr,
+ "must use 'with frags' with 'keep frags'\n");
+ return NULL;
+ }
+*/
+ return &fil;
+}
+
+
+int to_interface(fdp, to)
+frdest_t *fdp;
+char *to;
+{
+ int r = 0;
+ char *s;
+
+ s = index(to, ':');
+ fdp->fd_ifp = NULL;
+ if (s) {
+ *s++ = '\0';
+ fdp->fd_ip.s_addr = hostnum(s, &r);
+ if (r == -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;
+}
+
+
+void print_toif(tag, fdp)
+char *tag;
+frdest_t *fdp;
+{
+ (void)printf("%s %s%s", tag, fdp->fd_ifname,
+ (fdp->fd_ifp || (int)fdp->fd_ifp == -1) ? "" : "(!)");
+ if (fdp->fd_ip.s_addr)
+ (void)printf(":%s", inet_ntoa(fdp->fd_ip));
+ putchar(' ');
+}
+
+
+/*
+ * returns false if neither "hostmask/num" or "hostmask mask addr" are
+ * found in the line segments
+ */
+int hostmask(seg, sa, msk, pp, cp, tp)
+char ***seg;
+u_long *sa, *msk;
+u_short *pp, *tp;
+u_char *cp;
+{
+ char *s;
+ int bits = -1, resolved;
+
+ /*
+ * is it possibly hostname/num ?
+ */
+ if ((s = index(**seg, '/'))) {
+ *s++ = '\0';
+ if (!isdigit(*s))
+ return -1;
+ if (index(s, '.'))
+ *msk = inet_addr(s);
+ if (!index(s, '.') && !index(s, 'x')) {
+ /*
+ * set x most significant bits
+ */
+ for (bits = atoi(s); bits; bits--) {
+ *msk /= 2;
+ *msk |= ntohl(inet_addr("128.0.0.0"));
+ }
+ *msk = htonl(*msk);
+ } else {
+ if (inet_aton(s, (struct in_addr *)msk) == -1)
+ return -1;
+ }
+ *sa = hostnum(**seg, &resolved) & *msk;
+ if (resolved == -1)
+ return -1;
+ (*seg)++;
+ return ports(seg, pp, cp, tp);
+ }
+
+ /*
+ * look for extra segments if "mask" found in right spot
+ */
+ if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) {
+ *sa = hostnum(**seg, &resolved);
+ if (resolved == -1)
+ return -1;
+ (*seg)++;
+ (*seg)++;
+ if (inet_aton(**seg, (struct in_addr *)msk) == -1)
+ return -1;
+ (*seg)++;
+ *sa &= *msk;
+ return ports(seg, pp, cp, tp);
+ }
+
+ if (**seg) {
+ *sa = hostnum(**seg, &resolved);
+ if (resolved == -1)
+ return -1;
+ (*seg)++;
+ *msk = (*sa ? inet_addr("255.255.255.255") : 0L);
+ *sa &= *msk;
+ return ports(seg, pp, cp, tp);
+ }
+ return -1;
+}
+
+/*
+ * returns an ip address as a long var as a result of either a DNS lookup or
+ * straight inet_addr() call
+ */
+u_long hostnum(host, resolved)
+char *host;
+int *resolved;
+{
+ struct hostent *hp;
+ struct netent *np;
+
+ *resolved = 0;
+ if (!strcasecmp("any",host))
+ return 0L;
+ if (isdigit(*host))
+ return inet_addr(host);
+ if (!strcasecmp("<thishost>", host))
+ host = thishost;
+
+ if (!(hp = gethostbyname(host))) {
+ if (!(np = getnetbyname(host))) {
+ *resolved = -1;
+ fprintf(stderr, "can't resolve hostname: %s\n", host);
+ return 0;
+ }
+ return np->n_net;
+ }
+ return *(u_long *)hp->h_addr;
+}
+
+/*
+ * check for possible presence of the port fields in the line
+ */
+int ports(seg, pp, cp, tp)
+char ***seg;
+u_short *pp, *tp;
+u_char *cp;
+{
+ int comp = -1;
+
+ if (!*seg || !**seg || !***seg)
+ return 0;
+ if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) {
+ (*seg)++;
+ if (isdigit(***seg) && *(*seg + 2)) {
+ *pp = portnum(**seg);
+ (*seg)++;
+ if (!strcmp(**seg, "<>"))
+ comp = FR_OUTRANGE;
+ else if (!strcmp(**seg, "><"))
+ comp = FR_INRANGE;
+ (*seg)++;
+ *tp = portnum(**seg);
+ } 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 {
+ (void)fprintf(stderr,"unknown comparator (%s)\n",
+ **seg);
+ return -1;
+ }
+ if (comp != FR_OUTRANGE && comp != FR_INRANGE) {
+ (*seg)++;
+ *pp = portnum(**seg);
+ }
+ *cp = comp;
+ (*seg)++;
+ }
+ return 0;
+}
+
+/*
+ * find the port number given by the name, either from getservbyname() or
+ * straight atoi()
+ */
+u_short portnum(name)
+char *name;
+{
+ struct servent *sp, *sp2;
+ u_short p1 = 0;
+
+ if (isdigit(*name))
+ return (u_short)atoi(name);
+ if (!proto)
+ proto = "tcp/udp";
+ if (strcasecmp(proto, "tcp/udp")) {
+ sp = getservbyname(name, 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);
+}
+
+
+u_char tcp_flags(flgs, mask)
+char *flgs;
+u_char *mask;
+{
+ u_char tcpf = 0, tcpfm = 0, *fp = &tcpf;
+ char *s, *t;
+
+ for (s = flgs; *s; s++) {
+ if (*s == '/' && fp == &tcpf) {
+ fp = &tcpfm;
+ continue;
+ }
+ if (!(t = index(flagset, *s))) {
+ (void)fprintf(stderr, "unknown flag (%c)\n", *s);
+ return 0;
+ }
+ *fp |= flags[t - flagset];
+ }
+ if (!tcpfm)
+ tcpfm = 0xff;
+ *mask = tcpfm;
+ return tcpf;
+}
+
+
+/*
+ * deal with extra bits on end of the line
+ */
+int extras(cp, fr)
+char ***cp;
+struct frentry *fr;
+{
+ u_short secmsk;
+ u_long opts;
+ int notopt;
+ char oflags;
+
+ opts = 0;
+ secmsk = 0;
+ notopt = 0;
+ (*cp)++;
+ if (!**cp)
+ return -1;
+
+ while (**cp && (!strncasecmp(**cp, "ipopt", 5) ||
+ !strncasecmp(**cp, "not", 3) || !strncasecmp(**cp, "opt", 4) ||
+ !strncasecmp(**cp, "frag", 3) || !strncasecmp(**cp, "no", 2) ||
+ !strncasecmp(**cp, "short", 5))) {
+ if (***cp == 'n' || ***cp == 'N') {
+ notopt = 1;
+ (*cp)++;
+ continue;
+ } else if (***cp == 'i' || ***cp == 'I') {
+ if (!notopt)
+ fr->fr_ip.fi_fl |= FI_OPTIONS;
+ fr->fr_mip.fi_fl |= FI_OPTIONS;
+ goto nextopt;
+ } else if (***cp == 'f' || ***cp == 'F') {
+ if (!notopt)
+ fr->fr_ip.fi_fl |= FI_FRAG;
+ fr->fr_mip.fi_fl |= FI_FRAG;
+ goto nextopt;
+ } else if (***cp == 'o' || ***cp == 'O') {
+ if (!*(*cp + 1)) {
+ (void)fprintf(stderr,
+ "opt missing arguements\n");
+ return -1;
+ }
+ (*cp)++;
+ if (!(opts = optname(cp, &secmsk)))
+ return -1;
+ oflags = FI_OPTIONS;
+ } else if (***cp == 's' || ***cp == 'S') {
+ if (fr->fr_tcpf) {
+ (void) fprintf(stderr,
+ "short cannot be used with TCP flags\n");
+ return -1;
+ }
+
+ if (!notopt)
+ fr->fr_ip.fi_fl |= FI_SHORT;
+ fr->fr_mip.fi_fl |= FI_SHORT;
+ goto nextopt;
+ } else
+ return -1;
+
+ if (!notopt || !opts)
+ fr->fr_mip.fi_fl |= oflags;
+ if (notopt)
+ if (!secmsk)
+ fr->fr_mip.fi_optmsk |= opts;
+ else
+ fr->fr_mip.fi_optmsk |= (opts & ~0x0100);
+ else
+ fr->fr_mip.fi_optmsk |= opts;
+ fr->fr_mip.fi_secmsk |= secmsk;
+
+ if (notopt) {
+ fr->fr_ip.fi_fl &= (~oflags & 0xf);
+ fr->fr_ip.fi_optmsk &= ~opts;
+ fr->fr_ip.fi_secmsk &= ~secmsk;
+ } else {
+ fr->fr_ip.fi_fl |= oflags;
+ fr->fr_ip.fi_optmsk |= opts;
+ fr->fr_ip.fi_secmsk |= secmsk;
+ }
+nextopt:
+ notopt = 0;
+ opts = 0;
+ oflags = 0;
+ secmsk = 0;
+ (*cp)++;
+ }
+ return 0;
+}
+
+
+u_long optname(cp, sp)
+char ***cp;
+u_short *sp;
+{
+ 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, "unknown IP option name %s\n", s);
+ return 0;
+ }
+ if (!strcasecmp(s, "sec-class"))
+ sec = 1;
+ }
+
+ if (sec && !*(*cp + 1)) {
+ fprintf(stderr, "missing security level after sec-class\n");
+ 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, "no such security level: %s\n",
+ s);
+ return 0;
+ }
+ }
+ if (smsk)
+ *sp = smsk;
+ }
+ return msk;
+}
+
+
+void optprint(secmsk, secbits, optmsk, optbits)
+u_short secmsk, secbits;
+u_long optmsk, optbits;
+{
+ struct ipopt_names *io, *so;
+ char *s;
+ int secflag = 0;
+
+ 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 = ",";
+ } else
+ secflag = 1;
+ }
+
+
+ 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 = ",";
+ } 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 = ",";
+ }
+ }
+ }
+}
+
+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"
+};
+
+/*
+ * set the icmp field to the correct type if "icmp" word is found
+ */
+int addicmp(cp, fp)
+char ***cp;
+struct frentry *fp;
+{
+ char **t;
+ int i;
+
+ (*cp)++;
+ if (!**cp)
+ return -1;
+ if (!fp->fr_proto) /* to catch lusers */
+ fp->fr_proto = IPPROTO_ICMP;
+ if (isdigit(***cp)) {
+ i = atoi(**cp);
+ (*cp)++;
+ } 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)
+ 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)) {
+ i = atoi(**cp);
+ fp->fr_icmp |= (u_short)i;
+ fp->fr_icmpm = (u_short)0xffff;
+ (*cp)++;
+ return 0;
+ }
+ return -1;
+}
+
+
+#define MAX_ICMPCODE 12
+
+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 };
+/*
+ * Return the number for the associated ICMP unreachable code.
+ */
+int icmpcode(str)
+char *str;
+{
+ char *s;
+ int i, len;
+
+ if (!(s = strrchr(str, ')')))
+ return -1;
+ *s = '\0';
+ if (isdigit(*str))
+ return atoi(str);
+ len = strlen(str);
+ for (i = 0; icmpcodes[i]; i++)
+ if (!strncasecmp(str, icmpcodes[i], MIN(len,
+ strlen(icmpcodes[i])) ))
+ return i;
+ return -1;
+}
+
+
+/*
+ * set the icmp field to the correct type if "icmp" word is found
+ */
+int addkeep(cp, fp)
+char ***cp;
+struct frentry *fp;
+{
+ if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP &&
+ fp->fr_proto != IPPROTO_ICMP && !(fp->fr_ip.fi_fl & FI_TCPUDP)) {
+ (void)fprintf(stderr, "Can only use keep with UDP/ICMP/TCP\n");
+ return -1;
+ }
+
+ (*cp)++;
+ if (**cp && strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) {
+ (void)fprintf(stderr, "Unrecognised state keyword \"%s\"\n",
+ **cp);
+ return -1;
+ }
+
+ if (***cp == 's' || ***cp == 'S')
+ fp->fr_flags |= FR_KEEPSTATE;
+ else if (***cp == 'f' || ***cp == 'F')
+ fp->fr_flags |= FR_KEEPFRAG;
+ (*cp)++;
+ return 0;
+}
+
+
+/*
+ * count consecutive 1's in bit mask. If the mask generated by counting
+ * consecutive 1's is different to that passed, return -1, else return #
+ * of bits.
+ */
+int countbits(ip)
+u_long ip;
+{
+ u_long ipn;
+ int cnt = 0, i, j;
+
+ ip = ipn = ntohl(ip);
+ for (i = 32; i; i--, ipn *= 2)
+ if (ipn & 0x80000000)
+ cnt++;
+ else
+ break;
+ ipn = 0;
+ for (i = 32, j = cnt; i; i--, j--) {
+ ipn *= 2;
+ if (j > 0)
+ ipn++;
+ }
+ if (ipn == ip)
+ return cnt;
+ return -1;
+}
+
+
+char *portname(pr, port)
+int pr, port;
+{
+ static char buf[32];
+ struct protoent *p = NULL;
+ struct servent *sv = NULL, *sv1 = NULL;
+
+ if (pr == -1) {
+ if ((sv = getservbyport(port, "tcp"))) {
+ strncpy(buf, sv->s_name, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ sv1 = getservbyport(port, "udp");
+ sv = strncasecmp(buf, sv->s_name, strlen(buf)) ?
+ NULL : sv1;
+ }
+ if (sv)
+ return buf;
+ } else if (pr && (p = getprotobynumber(pr))) {
+ if ((sv = getservbyport(port, p->p_name))) {
+ strncpy(buf, sv->s_name, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ return buf;
+ }
+ }
+
+ (void) sprintf(buf, "%d", port);
+ return buf;
+}
+
+
+/*
+ * print the filter structure in a useful way
+ */
+void printfr(fp)
+struct frentry *fp;
+{
+ static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=",
+ "<>", "><"};
+ struct protoent *p;
+ int ones = 0, pr;
+ char *s;
+ u_char *t;
+
+ if (fp->fr_flags & FR_PASS) {
+ (void)printf("pass");
+ } else if (fp->fr_flags & FR_BLOCK) {
+ (void)printf("block");
+ if (fp->fr_flags & FR_RETICMP) {
+ (void)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);
+ }
+ if (fp->fr_flags & FR_RETRST)
+ (void)printf(" return-rst");
+ } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
+ (void)printf("log");
+ if (fp->fr_flags & FR_LOGBODY)
+ (void)printf(" body");
+ if (fp->fr_flags & FR_LOGFIRST)
+ (void)printf(" first");
+ } else if (fp->fr_flags & FR_ACCOUNT)
+ (void)printf("count");
+
+ if (fp->fr_flags & FR_OUTQUE)
+ (void)printf(" out ");
+ else
+ (void)printf(" in ");
+
+ if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
+ ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
+ (void)printf("log ");
+ if (fp->fr_flags & FR_LOGBODY)
+ (void)printf("body ");
+ if (fp->fr_flags & FR_LOGFIRST)
+ (void)printf("first ");
+ if (fp->fr_flags & FR_LOGORBLOCK)
+ (void)printf("or-block ");
+ }
+ if (fp->fr_flags & FR_QUICK)
+ (void)printf("quick ");
+
+ if (*fp->fr_ifname) {
+ (void)printf("on %s%s ", fp->fr_ifname,
+ (fp->fr_ifa || (int)fp->fr_ifa == -1) ? "" : "(!)");
+ if (*fp->fr_dif.fd_ifname)
+ print_toif("dup-to", &fp->fr_dif);
+ if (*fp->fr_tif.fd_ifname)
+ print_toif("to", &fp->fr_tif);
+ if (fp->fr_flags & FR_FASTROUTE)
+ (void)printf("fastroute ");
+
+ }
+ if (fp->fr_mip.fi_tos)
+ (void)printf("tos %#x ", fp->fr_tos);
+ if (fp->fr_mip.fi_ttl)
+ (void)printf("ttl %d ", fp->fr_ttl);
+ if (fp->fr_ip.fi_fl & FI_TCPUDP) {
+ (void)printf("proto tcp/udp ");
+ pr = -1;
+ } else if ((pr = fp->fr_mip.fi_p)) {
+ if ((p = getprotobynumber(fp->fr_proto)))
+ (void)printf("proto %s ", p->p_name);
+ else
+ (void)printf("proto %d ", fp->fr_proto);
+ }
+
+ if (!fp->fr_src.s_addr & !fp->fr_smsk.s_addr)
+ (void)printf("from any ");
+ else {
+ (void)printf("from %s", inet_ntoa(fp->fr_src));
+ if ((ones = countbits(fp->fr_smsk.s_addr)) == -1)
+ (void)printf("/%s ", inet_ntoa(fp->fr_smsk));
+ else
+ (void)printf("/%d ", ones);
+ }
+ if (fp->fr_scmp)
+ if (fp->fr_scmp == FR_INRANGE || fp->fr_scmp == FR_OUTRANGE)
+ (void)printf("port %d %s %d ", fp->fr_sport,
+ pcmp1[fp->fr_scmp], fp->fr_stop);
+ else
+ (void)printf("port %s %s ", pcmp1[fp->fr_scmp],
+ portname(pr, fp->fr_sport));
+ if (!fp->fr_dst.s_addr & !fp->fr_dmsk.s_addr)
+ (void)printf("to any");
+ else {
+ (void)printf("to %s", inet_ntoa(fp->fr_dst));
+ if ((ones = countbits(fp->fr_dmsk.s_addr)) == -1)
+ (void)printf("/%s", inet_ntoa(fp->fr_dmsk));
+ else
+ (void)printf("/%d", ones);
+ }
+ if (fp->fr_dcmp) {
+ if (fp->fr_dcmp == FR_INRANGE || fp->fr_dcmp == FR_OUTRANGE)
+ (void)printf(" port %d %s %d", fp->fr_dport,
+ pcmp1[fp->fr_dcmp], fp->fr_dtop);
+ else
+ (void)printf(" port %s %s", pcmp1[fp->fr_dcmp],
+ portname(pr, fp->fr_dport));
+ }
+ if ((fp->fr_ip.fi_fl & ~FI_TCPUDP) ||
+ (fp->fr_mip.fi_fl & ~FI_TCPUDP) ||
+ fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
+ fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) {
+ (void)printf(" with");
+ if (fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
+ fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk)
+ optprint(fp->fr_mip.fi_secmsk,
+ fp->fr_ip.fi_secmsk,
+ fp->fr_mip.fi_optmsk,
+ fp->fr_ip.fi_optmsk);
+ else if (fp->fr_mip.fi_fl & FI_OPTIONS) {
+ if (!(fp->fr_ip.fi_fl & FI_OPTIONS))
+ (void)printf(" not");
+ (void)printf(" ipopt");
+ }
+ if (fp->fr_mip.fi_fl & FI_SHORT) {
+ if (!(fp->fr_ip.fi_fl & FI_SHORT))
+ (void)printf(" not");
+ (void)printf(" short");
+ }
+ if (fp->fr_mip.fi_fl & FI_FRAG) {
+ if (!(fp->fr_ip.fi_fl & FI_FRAG))
+ (void)printf(" not");
+ (void)printf(" frag");
+ }
+ }
+ 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 *)) &&
+ icmptypes[type])
+ (void)printf(" icmp-type %s", icmptypes[type]);
+ else
+ (void)printf(" icmp-type %d", type);
+ if (code)
+ (void)printf(" code %d", code);
+ }
+ if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) {
+ (void)printf(" flags ");
+ for (s = flagset, t = flags; *s; s++, t++)
+ if (fp->fr_tcpf & *t)
+ (void)putchar(*s);
+ if (fp->fr_tcpfm) {
+ (void)putchar('/');
+ for (s = flagset, t = flags; *s; s++, t++)
+ if (fp->fr_tcpfm & *t)
+ (void)putchar(*s);
+ }
+ }
+
+ if (fp->fr_flags & FR_KEEPSTATE)
+ printf(" keep state");
+ if (fp->fr_flags & FR_KEEPFRAG)
+ printf(" keep frags");
+ (void)putchar('\n');
+}
+
+void binprint(fp)
+struct frentry *fp;
+{
+ int i = sizeof(*fp), j = 0;
+ u_char *s;
+
+ for (s = (u_char *)fp; i; i--, s++) {
+ j++;
+ (void)printf("%02x ",*s);
+ if (j == 16) {
+ (void)printf("\n");
+ j = 0;
+ }
+ }
+ putchar('\n');
+ (void)fflush(stdout);
+}
diff --git a/contrib/ipfilter/pcap.h b/contrib/ipfilter/pcap.h
new file mode 100644
index 0000000..c909297
--- /dev/null
+++ b/contrib/ipfilter/pcap.h
@@ -0,0 +1,35 @@
+/*
+ * (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.
+ * $Id: pcap.h,v 2.0.1.1 1997/01/09 15:14:45 darrenr Exp $
+ */
+/*
+ * 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/relay.c b/contrib/ipfilter/relay.c
new file mode 100644
index 0000000..9a181a1
--- /dev/null
+++ b/contrib/ipfilter/relay.c
@@ -0,0 +1,179 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include "ip_nat.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;
+ natlookup_t nl;
+ int fd, sl = sizeof(sl), se;
+
+ openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON);
+ if ((fd = open("/dev/ipl", O_RDONLY)) == -1) {
+ se = errno;
+ perror("open");
+ errno = se;
+ syslog(LOG_ERR, "open: %m\n");
+ exit(-1);
+ }
+
+ 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, &nl) == -1) {
+ se = errno;
+ perror("ioctl");
+ errno = se;
+ syslog(LOG_ERR, "ioctl: %m\n");
+ exit(-1);
+ }
+
+ sin.sin_port = nl.nl_inport;
+ sin.sin_addr = nl.nl_inip;
+ 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/rules/example.1 b/contrib/ipfilter/rules/example.1
new file mode 100644
index 0000000..604346e
--- /dev/null
+++ b/contrib/ipfilter/rules/example.1
@@ -0,0 +1,4 @@
+#
+# block all incoming TCP packets on le0 from host "foo" to any destination.
+#
+block in on le0 proto tcp from foo/32 to any
diff --git a/contrib/ipfilter/rules/example.10 b/contrib/ipfilter/rules/example.10
new file mode 100644
index 0000000..477c2e0
--- /dev/null
+++ b/contrib/ipfilter/rules/example.10
@@ -0,0 +1,12 @@
+#
+# pass ack packets (ie established connection)
+#
+pass in proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A
+pass out proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A
+#
+# block incoming connection requests to my internal network from the big bad
+# internet.
+#
+block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA
+# to block the replies:
+block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA
diff --git a/contrib/ipfilter/rules/example.11 b/contrib/ipfilter/rules/example.11
new file mode 100644
index 0000000..7fc26eb
--- /dev/null
+++ b/contrib/ipfilter/rules/example.11
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+pass in proto tcp from fubar/24 to 10.1.1.2/32 port = 6667
+#
+# allow in UDP packets which are NOT from port 53 and are destined for
+# localhost
+#
+pass in proto udp from fubar port != 53 to localhost
+#
+# block anything trying to get to X terminal ports, X:0 to X:9
+#
+block in proto tcp from any to any port 5999 >< 6010
+#
+# allow any connections to be made, except to BSD print/r-services
+# this will also protect syslog.
+#
+block in proto tcp/udp all
+pass in proto tcp/udp from any to any port 512 <> 515
+#
+# allow any connections to be made, except to BSD print/r-services
+# this will also protect syslog.
+#
+pass in proto tcp/udp all
+block in proto tcp/udp from any to any port 511 >< 516
diff --git a/contrib/ipfilter/rules/example.12 b/contrib/ipfilter/rules/example.12
new file mode 100644
index 0000000..c0ba1d3
--- /dev/null
+++ b/contrib/ipfilter/rules/example.12
@@ -0,0 +1,17 @@
+#
+# get rid of all short IP fragments (too small for valid comparison)
+#
+block in proto tcp all with short
+#
+# drop and log any IP packets with options set in them.
+#
+block in log all with ipopts
+#
+# log packets with BOTH ssrr and lsrr set
+#
+log in all with opt lsrr,ssrr
+#
+# drop any source routing options
+#
+block in quick all with opt lsrr
+block in quick all with opt ssrr
diff --git a/contrib/ipfilter/rules/example.13 b/contrib/ipfilter/rules/example.13
new file mode 100644
index 0000000..df13d0a
--- /dev/null
+++ b/contrib/ipfilter/rules/example.13
@@ -0,0 +1,17 @@
+#
+# Log all short TCP packets to qe3, with "packetlog" as the intended
+# destination for the packet.
+#
+block in to qe3:packetlog proto tcp all with short
+#
+# Log all connection attempts for TCP
+#
+pass in dup-to le0:packetlog proto tcp all flags S/SA
+#
+# Route all UDP packets through transparently.
+#
+pass in fastroute proto udp all
+#
+# Route all ICMP packets to network 10 out through le1, to "router"
+#
+pass in to le1:router proto icmp all
diff --git a/contrib/ipfilter/rules/example.2 b/contrib/ipfilter/rules/example.2
new file mode 100644
index 0000000..59d9ec8
--- /dev/null
+++ b/contrib/ipfilter/rules/example.2
@@ -0,0 +1,4 @@
+#
+# block all outgoing TCP packets on le0 from any host to port 23 of host bar.
+#
+block out on le0 proto tcp from any to bar/32 port != 23
diff --git a/contrib/ipfilter/rules/example.3 b/contrib/ipfilter/rules/example.3
new file mode 100644
index 0000000..cd31f73
--- /dev/null
+++ b/contrib/ipfilter/rules/example.3
@@ -0,0 +1,40 @@
+#
+# block all inbound packets.
+#
+block in from any to any
+#
+# pass through packets to and from localhost.
+#
+pass in from 127.0.0.1/32 to 127.0.0.1/32
+#
+# allow a variety of individual hosts to send any type of IP packet to any
+# other host.
+#
+pass in from 10.1.3.1/32 to any
+pass in from 10.1.3.2/32 to any
+pass in from 10.1.3.3/32 to any
+pass in from 10.1.3.4/32 to any
+pass in from 10.1.3.5/32 to any
+pass in from 10.1.0.13/32 to any
+pass in from 10.1.1.1/32 to any
+pass in from 10.1.2.1/32 to any
+#
+#
+# block all outbound packets.
+#
+block out from any to any
+#
+# allow any packets destined for localhost out.
+#
+pass out from any to 127.0.0.1/32
+#
+# allow any host to send any IP packet out to a limited number of hosts.
+#
+pass out from any to 10.1.3.1/32
+pass out from any to 10.1.3.2/32
+pass out from any to 10.1.3.3/32
+pass out from any to 10.1.3.4/32
+pass out from any to 10.1.3.5/32
+pass out from any to 10.1.0.13/32
+pass out from any to 10.1.1.1/32
+pass out from any to 10.1.2.1/32
diff --git a/contrib/ipfilter/rules/example.4 b/contrib/ipfilter/rules/example.4
new file mode 100644
index 0000000..7918ec2
--- /dev/null
+++ b/contrib/ipfilter/rules/example.4
@@ -0,0 +1,4 @@
+#
+# block all ICMP packets.
+#
+block in proto icmp from any to any
diff --git a/contrib/ipfilter/rules/example.5 b/contrib/ipfilter/rules/example.5
new file mode 100644
index 0000000..6e122e0
--- /dev/null
+++ b/contrib/ipfilter/rules/example.5
@@ -0,0 +1,25 @@
+#
+# test ruleset
+#
+# allow packets coming from foo to bar through.
+#
+pass from foo to bar
+#
+# 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.
+#
+pass proto tcp from fubar/24 to 10.1.1.2/32 port = 6667
+#
+# allow in UDP packets which are NOT from port 53 and are destined for
+# localhost
+#
+pass proto udp from fubar port != 53 to localhost
+#
+# block all ICMP unreachables.
+#
+block from any to any icmp unreach
+#
+# allow packets through which have a non-standard IP header length (ie there
+# are IP options such as source-routing present).
+#
+pass from any to any with ipopts
diff --git a/contrib/ipfilter/rules/example.6 b/contrib/ipfilter/rules/example.6
new file mode 100644
index 0000000..d40f0f3
--- /dev/null
+++ b/contrib/ipfilter/rules/example.6
@@ -0,0 +1,5 @@
+#
+# 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.
+#
+block in proto tcp from any to any flags S/SA
diff --git a/contrib/ipfilter/rules/example.7 b/contrib/ipfilter/rules/example.7
new file mode 100644
index 0000000..062de98
--- /dev/null
+++ b/contrib/ipfilter/rules/example.7
@@ -0,0 +1,12 @@
+# block all ICMP packets.
+#
+block in proto icmp all
+#
+# allow in ICMP echos and echo-replies.
+#
+pass in on le1 proto icmp from any to any icmp-type echo
+pass in on le1 proto icmp from any to any icmp-type echorep
+#
+# block all ICMP destination unreachable packets which are port-unreachables
+#
+block in on le1 proto icmp from any to any icmp-type unreach code 3
diff --git a/contrib/ipfilter/rules/example.8 b/contrib/ipfilter/rules/example.8
new file mode 100644
index 0000000..baa0258
--- /dev/null
+++ b/contrib/ipfilter/rules/example.8
@@ -0,0 +1,10 @@
+#
+# block all incoming TCP connections but send back a TCP-RST for ones to
+# the ident port
+#
+block in proto tcp from any to any flags S/SA
+block return-rst in quick proto tcp from any to any port = 113 flags S/SA
+#
+# block all inbound UDP packets and send back an ICMP error.
+#
+block return-icmp in proto udp from any to any
diff --git a/contrib/ipfilter/rules/example.9 b/contrib/ipfilter/rules/example.9
new file mode 100644
index 0000000..77968f8
--- /dev/null
+++ b/contrib/ipfilter/rules/example.9
@@ -0,0 +1,12 @@
+#
+# drop all packets without IP security options
+#
+block in all
+pass in all with opt sec
+#
+# only allow packets in and out on le0 which are top secret
+#
+block out on le1 all
+pass out on le1 all with opt sec-class topsecret
+block in on le1 all
+pass in on le1 all with opt sec-class topsecret
diff --git a/contrib/ipfilter/rules/example.sr b/contrib/ipfilter/rules/example.sr
new file mode 100644
index 0000000..c4c1994
--- /dev/null
+++ b/contrib/ipfilter/rules/example.sr
@@ -0,0 +1,61 @@
+#
+# log all inbound packet on le0 which has IP options present
+#
+log in on le0 from any to any with ipopts
+#
+# block any inbound packets on le0 which are fragmented and "too short" to
+# do any meaningful comparison on. This actually only applies to TCP
+# packets which can be missing the flags/ports (depending on which part
+# of the fragment you see).
+#
+block in log quick on le0 from any to any with short frag
+#
+# log all inbound TCP packets with the SYN flag (only) set
+# (NOTE: if it were an inbound TCP packet with the SYN flag set and it
+# had IP options present, this rule and the above would cause it
+# to be logged twice).
+#
+log in on le0 proto tcp from any to any flags S/SA
+#
+# block and log any inbound ICMP unreachables
+#
+block in log on le0 proto icmp from any to any icmp-type unreach
+#
+# block and log any inbound UDP packets on le0 which are going to port 2049
+# (the NFS port).
+#
+block in log on le0 proto udp from any to any port = 2049
+#
+# quickly allow any packets to/from a particular pair of hosts
+#
+pass in quick from any to 10.1.3.2/32
+pass in quick from any to 10.1.0.13/32
+pass in quick from 10.1.3.2/32 to any
+pass in quick from 10.1.0.13/32 to any
+#
+# block (and stop matching) any packet with IP options present.
+#
+block in quick on le0 from any to any with ipopts
+#
+# allow any packet through
+#
+pass in from any to any
+#
+# block any inbound UDP packets destined for these subnets.
+#
+block in on le0 proto udp from any to 10.1.3.0/24
+block in on le0 proto udp from any to 10.1.1.0/24
+block in on le0 proto udp from any to 10.1.2.0/24
+#
+# block any inbound TCP packets with only the SYN flag set that are
+# destined for these subnets.
+#
+block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA
+#
+# block any inbound ICMP packets destined for these subnets.
+#
+block in on le0 proto icmp from any to 10.1.3.0/24
+block in on le0 proto icmp from any to 10.1.1.0/24
+block in on le0 proto icmp from any to 10.1.2.0/24
diff --git a/contrib/ipfilter/rules/nat.eg b/contrib/ipfilter/rules/nat.eg
new file mode 100644
index 0000000..9c26754
--- /dev/null
+++ b/contrib/ipfilter/rules/nat.eg
@@ -0,0 +1,14 @@
+# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source
+# port number to something between 10,000 and 20,000 inclusive. For all other
+# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily
+# for each new user.
+#
+map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000
+map ed1 10.1.0.0/16 -> 240.1.0.0/24
+#
+# Redirection is triggered for input packets.
+# For example, to redirect FTP connections through this box, to the local ftp
+# port, forcing them to connect through a proxy, you would use:
+#
+rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp
+#
diff --git a/contrib/ipfilter/rules/server b/contrib/ipfilter/rules/server
new file mode 100644
index 0000000..5eafc7c
--- /dev/null
+++ b/contrib/ipfilter/rules/server
@@ -0,0 +1,11 @@
+#
+# For a network server, which has two interfaces, 128.1.40.1 (le0) and
+# 128.1.2.1 (le1), we want to block all IP spoofing attacks. le1 is
+# connected to the majority of the network, whilst le0 is connected to a
+# leaf subnet. We're not concerned about filtering individual services
+# or
+#
+pass in quick on le0 from 128.1.40.0/24 to any
+block in quick log on le0 from any to any
+block in quick log on le1 from 128.1.1.0/24 to any
+pass in quick on le1 from any to any
diff --git a/contrib/ipfilter/rules/tcpstate b/contrib/ipfilter/rules/tcpstate
new file mode 100644
index 0000000..339a25f
--- /dev/null
+++ b/contrib/ipfilter/rules/tcpstate
@@ -0,0 +1,13 @@
+#
+# Only allow TCP packets in/out of le0 if there is an outgoing connection setup
+# somewhere, waiting for it.
+#
+pass out quick on le0 proto tcp from any to any flags S/SAFR keep state
+block out on le0 proto tcp all
+block in on le0 proto tcp all
+#
+# allow nameserver queries and replies to pass through, but no other UDP
+#
+pass out quick on le0 proto udp from any to any port = 53 keep state
+block out on le0 proto udp all
+block in on le0 proto udp all
diff --git a/contrib/ipfilter/snoop.h b/contrib/ipfilter/snoop.h
new file mode 100644
index 0000000..fdebcef
--- /dev/null
+++ b/contrib/ipfilter/snoop.h
@@ -0,0 +1,42 @@
+/*
+ * (C)opyright 1993,1994,1995 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.
+ */
+
+/*
+ * written to comply with the RFC (1761) from Sun.
+ * $Id: snoop.h,v 2.0.1.1 1997/01/09 15:14:45 darrenr Exp $
+ */
+struct snoophdr {
+ char s_id[8];
+ int s_v;
+ int s_type;
+};
+
+#define SNOOP_VERSION 2
+
+#define SDL_8023 0
+#define SDL_8024 1
+#define SDL_8025 2
+#define SDL_8026 3
+#define SDL_ETHER 4
+#define SDL_HDLC 5
+#define SDL_CHSYNC 6
+#define SDL_IBMCC 7
+#define SDL_FDDI 8
+#define SDL_OTHER 9
+
+#define SDL_MAX 9
+
+
+struct snooppkt {
+ int sp_olen;
+ int sp_ilen;
+ int sp_plen;
+ int sp_drop;
+ int sp_sec;
+ int sp_usec;
+};
diff --git a/contrib/ipfilter/solaris.c b/contrib/ipfilter/solaris.c
new file mode 100644
index 0000000..73db28f
--- /dev/null
+++ b/contrib/ipfilter/solaris.c
@@ -0,0 +1,1018 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+/* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/
+#pragma ident "$Id: solaris.c,v 2.0.1.4 1997/02/08 06:38:30 darrenr Exp $";
+
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/uio.h>
+#include <sys/buf.h>
+#include <sys/modctl.h>
+#include <sys/open.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/stat.h>
+#include <sys/cred.h>
+#include <sys/dditypes.h>
+#include <sys/stream.h>
+#include <sys/poll.h>
+#include <sys/autoconf.h>
+#include <sys/byteorder.h>
+#include <sys/socket.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 "ipl.h"
+#include "ip_fil.h"
+#include "ip_compat.h"
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <inet/ip_ire.h>
+
+char _depends_on[] = "drv/ip";
+
+extern int iplopen(), iplclose(), iplread(), iplioctl();
+extern int iplattach(), ipldetach();
+extern void copyout_mblk(), copyin_mblk();
+
+int solattach(), soldetach();
+
+extern struct filterstats frstats[];
+extern kmutex_t ipl_mutex, ipf_mutex, ipfs_mutex;
+extern int fr_flags;
+
+static qif_t *qif_head = NULL;
+
+static int ipl_getinfo(), ipl_probe(), ipl_identify(), ipl_attach();
+static int ipl_detach();
+
+static struct cb_ops ipl_cb_ops = {
+ iplopen,
+ iplclose,
+ nodev, /* strategy */ nodev, /* print */
+ nodev, /* dump */
+ iplread,
+ nodev, /* write */
+ iplioctl, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ nochpoll, /* poll */
+ ddi_prop_op,
+ NULL,
+ D_MTSAFE
+};
+
+static struct dev_ops ipl_ops = {
+ DEVO_REV,
+ 0,
+ ipl_getinfo,
+ ipl_identify,
+ ipl_probe,
+ ipl_attach,
+ ipl_detach,
+ nodev, /* reset */
+ &ipl_cb_ops,
+ (struct bus_ops *)0
+};
+
+extern struct mod_ops mod_driverops;
+static struct modldrv iplmod = {
+ &mod_driverops, IPL_VERSION, &ipl_ops };
+static struct modlinkage modlink1 = { MODREV_1, &iplmod, 0 };
+
+
+static dev_info_t *ipf_dev_info = NULL;
+
+
+int _init()
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipf_init()");
+#endif
+ return mod_install(&modlink1);
+}
+
+
+int _fini(void)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipf_fini()");
+#endif
+ return mod_remove(&modlink1);
+}
+
+
+int _info(struct modinfo *modinfop)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipf_info(%x)", modinfop);
+#endif
+ return mod_info(&modlink1, modinfop);
+}
+
+
+static int ipl_probe(dev_info_t *dip)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_probe(%x)", dip);
+#endif
+ return DDI_PROBE_SUCCESS;
+}
+
+
+static int ipl_identify(dev_info_t *dip)
+{
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_identify(%x)", dip);
+#endif
+ if (strcmp(ddi_get_name(dip), "ipf") == 0)
+ return (DDI_IDENTIFIED);
+ return (DDI_NOT_IDENTIFIED);
+}
+
+
+static int ipl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ int instance;
+
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_attach(%x,%x)", dip, cmd);
+#endif
+ switch (cmd) {
+ case DDI_ATTACH:
+ instance = ddi_get_instance(dip);
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: attach ipf instace %d", instance);
+#endif
+ if (ddi_create_minor_node(dip, "ipf", S_IFCHR, instance,
+ DDI_PSEUDO, 0) == DDI_FAILURE) {
+ ddi_remove_minor_node(dip, NULL);
+ goto attach_failed;
+ }
+ ipf_dev_info = dip;
+ sync();
+ /*
+ * Initialize mutex's
+ */
+ iplattach();
+ solattach();
+ cmn_err(CE_CONT, "IP Filter: attaching complete.\n");
+ return (DDI_SUCCESS);
+ default:
+ return (DDI_FAILURE);
+ }
+
+attach_failed:
+ /*
+ * Use our own detach routine to toss
+ * away any stuff we allocated above.
+ */
+ (void) ipl_detach(dip, DDI_DETACH);
+ return (DDI_FAILURE);
+}
+
+
+static int ipl_detach(dip, cmd)
+dev_info_t *dip;
+ddi_detach_cmd_t cmd;
+{
+ int instance;
+
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_detach(%x,%x)", dip, cmd);
+#endif
+ switch (cmd) {
+ case DDI_DETACH:
+ /*
+ * Undo what we did in ipl_attach, freeing resources
+ * and removing things we installed. The system
+ * framework guarantees we are not active with this devinfo
+ * node in any other entry points at this time.
+ */
+ ddi_prop_remove_all(dip);
+ instance = ddi_get_instance(dip);
+ ddi_remove_minor_node(dip, NULL);
+ sync();
+ if (!soldetach()) {
+ cmn_err(CE_CONT, "IP Filter: detached\n");
+ return (DDI_SUCCESS);
+ }
+ default:
+ return (DDI_FAILURE);
+ }
+}
+
+
+static int ipl_getinfo(dip, infocmd, arg, result)
+dev_info_t *dip;
+ddi_info_cmd_t infocmd;
+void *arg, **result;
+{
+ int error = DDI_FAILURE;
+
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter: ipl_getinfo(%x,%x)", dip, infocmd);
+#endif
+ switch (infocmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ *result = ipf_dev_info;
+ error = DDI_SUCCESS;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ *result = (void *)getminor((dev_t) arg);
+ error = DDI_SUCCESS;
+ break;
+ default:
+ break;
+ }
+ return (error);
+}
+
+/*
+ * find the filter structure setup for this queue
+ */
+qif_t *qif_from_queue(q)
+queue_t *q;
+{
+ qif_t *qif;
+
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if ((qif->qf_iptr == q->q_ptr) || (qif->qf_optr == q->q_ptr))
+ break;
+ return qif;
+}
+
+
+/*
+ * OK, this is pretty scrappy code, but then it's essentially just here for
+ * debug purposes and that's it. Packets should not normally come through
+ * here, and if they do, well, we would like to see as much information as
+ * possible about them and what they claim to hold.
+ */
+void fr_donotip(out, qif, q, m, mt, ip, off)
+int out;
+qif_t *qif;
+queue_t *q;
+mblk_t *m, *mt;
+ip_t *ip;
+int off;
+{
+ u_char *s, outb[256], *t;
+ int i;
+
+ outb[0] = '\0';
+ outb[1] = '\0';
+ outb[2] = '\0';
+ outb[3] = '\0';
+ s = ip ? (u_char *)ip : outb;
+ if (!ip && (m == mt) && m->b_cont && (MTYPE(m) != M_DATA))
+ m = m->b_cont;
+
+ printf("!IP %s:%d %x %x %x %d %x %x %x %d %d %x\n%02x%02x%02x%02x\n",
+ qif ? qif->qf_name : "?", out, q, q ? q->q_ptr : NULL,
+ q ? q->q_qinfo : NULL, mt->b_wptr - mt->b_rptr, m, mt,
+ m->b_rptr, m->b_wptr - m->b_rptr, off, ip,
+ *s, *(s+1), *(s+2), *(s+3));
+ if (m != mt) {
+ i = 0;
+ t = outb;
+ s = mt->b_rptr;
+ sprintf(t, "%d:", MTYPE(mt));
+ t += strlen(t);
+ for (; (i < 100) && (s < mt->b_wptr); i++) {
+ sprintf(t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
+ t += ((i & 3) == 3) ? 3 : 2;
+ }
+ *t++ = '\n';
+ *t = '\0';
+ printf("%s", outb);
+ }
+ i = 0;
+ t = outb;
+ s = m->b_rptr;
+ sprintf(t, "%d:", MTYPE(m));
+ t += strlen(t);
+ for (; (i < 100) && (s < m->b_wptr); i++) {
+ sprintf(t, "%02x%s", *s++, ((i & 3) == 3) ? " " : "");
+ t += ((i & 3) == 3) ? 3 : 2;
+ }
+ *t++ = '\n';
+ *t = '\0';
+ printf("%s", outb);
+}
+
+
+/*
+ * find the first data mblk, if present, in the chain we're processing. Also
+ * make a few sanity checks to try prevent the filter from causing a panic -
+ * none of the nice IP sanity checks (including checksumming) should have been
+ * done yet - dangerous!
+ */
+int fr_precheck(mp, q, qif, out)
+mblk_t **mp;
+queue_t *q;
+qif_t *qif;
+int out;
+{
+ u_long lbuf[48];
+ mblk_t *m, *mp1, *mt = *mp;
+ register ip_t *ip;
+ int iphlen, hlen, len, err, mlen, off, synced = 0;
+#ifndef sparc
+ u_short __iplen, __ipoff;
+#endif
+tryagain:
+ /*
+ * If there is only M_DATA for a packet going out, then any header
+ * information (which would otherwise appear in an M_PROTO mblk before
+ * the M_DATA) is prepended before the IP header. We need to set the
+ * offset to account for this. - see MMM
+ */
+ off = (out) ? qif->qf_hl : 0;
+
+ /*
+ * Find the first data block, count the data blocks in this chain and
+ * the total amount of data.
+ */
+ for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont)
+ off = 0; /* Any non-M_DATA cancels the offset */
+
+ if (!m)
+ return 0; /* No data blocks */
+
+ ip = (ip_t *)(m->b_rptr + off); /* MMM */
+
+ /*
+ * We might have a 1st data block which is really M_PROTO, i.e. it is
+ * only big enough for the link layer header
+ */
+ while ((u_char *)ip >= m->b_wptr) {
+ len = (u_char *)ip - m->b_wptr;
+ if (!(m = m->b_cont))
+ return 0; /* not enough data for IP */
+ ip = (ip_t *)(m->b_rptr + len);
+ }
+ if ((off = (u_char *)ip - m->b_rptr))
+ m->b_rptr = (u_char *)ip;
+ mlen = msgdsize(m);
+
+ /*
+ * Ok, the IP header isn't on a 32bit aligned address. To get around
+ * this, we copy the data to an aligned buffer and work with that.
+ */
+ if (!OK_32PTR(ip)) {
+ len = MIN(mlen, sizeof(ip_t));
+ copyout_mblk(m, 0, lbuf, len);
+ frstats[out].fr_pull[0]++;
+ ip = (ip_t *)lbuf;
+ } else
+ len = m->b_wptr - (u_char *)ip;
+
+ if (ip->ip_v != IPVERSION) {
+ m->b_rptr -= off;
+ if (!synced) {
+ synced = 1;
+ ipfsync();
+ goto tryagain;
+ }
+ fr_donotip(out, qif, q, m, mt, ip, off);
+ frstats[out].fr_notip++;
+ return (fr_flags & FF_BLOCKNONIP) ? -1 : 0;
+ }
+
+ hlen = iphlen = ip->ip_hl << 2;
+
+ /*
+ * Make hlen the total size of the IP header plus TCP/UDP/ICMP header
+ * (if it is one of these three).
+ */
+ if (!(ip->ip_off & 0x1fff))
+ switch (ip->ip_p)
+ {
+ case IPPROTO_TCP :
+ hlen += sizeof(tcphdr_t);
+ break;
+ case IPPROTO_UDP :
+ hlen += sizeof(udphdr_t);
+ break;
+ case IPPROTO_ICMP :
+ hlen += sizeof(icmphdr_t);
+ break;
+ default :
+ break;
+ }
+ /*
+ * If we don't have enough data in the mblk or we haven't yet copied
+ * enough (above), then copy some more.
+ */
+ if ((hlen > len)) {
+ len = MIN(hlen, sizeof(lbuf));
+ len = MIN(mlen, len);
+ copyout_mblk(m, 0, lbuf, len);
+ frstats[out].fr_pull[0]++;
+ ip = (ip_t *)lbuf;
+ }
+
+#ifndef sparc
+ __iplen = ip->ip_len;
+ ip->ip_len = ntohs(__iplen);
+ __ipoff = ip->ip_off;
+ ip->ip_off = ntohs(__ipoff);
+#endif
+
+ if ((iphlen < sizeof(ip_t)) || (iphlen > (u_short)ip->ip_len) ||
+ (mlen < (u_short)ip->ip_len)) {
+ /*
+ * Bad IP packet or not enough data/data length mismatches
+ */
+ m->b_rptr -= off;
+ frstats[out].fr_bad++;
+ return -1;
+ }
+
+ qif->qf_m = m;
+ qif->qf_len = len;
+ err = fr_check(ip, iphlen, qif->qf_ill, out, qif, q, mp);
+ /*
+ * Copy back the ip header data if it was changed, we haven't yet
+ * freed the message and we aren't going to drop the packet.
+ */
+#ifndef sparc
+ if (*mp) {
+ ip->ip_len = __iplen;
+ ip->ip_off = __ipoff;
+ }
+#endif
+ if (err == 1) {
+ if (*mp && (ip == (ip_t *)lbuf)) {
+ copyin_mblk(m, 0, lbuf, len);
+ frstats[out].fr_pull[1]++;
+ }
+ err = 0;
+ }
+ m->b_rptr -= off;
+ return err;
+}
+
+
+int fr_qin(q, mb)
+queue_t *q;
+mblk_t *mb;
+{
+ int (*pnext)(), type, synced = 0;
+ qif_t qfb, *qif;
+
+again:
+ mutex_enter(&ipfs_mutex);
+ while (!(qif = qif_from_queue(q))) {
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if (qif->qf_rqinfo == q->q_qinfo && qif->qf_inp) {
+ pnext = qif->qf_inp;
+ mutex_exit(&ipfs_mutex);
+ frstats[0].fr_notip++;
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
+ return (*pnext)(q, mb);
+ }
+ mutex_exit(&ipfs_mutex);
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ cmn_err(CE_WARN,
+ "IP Filter: dropped: fr_qin(%x,%x): type %x qif %x",
+ q, mb, MTYPE(mb), qif);
+ cmn_err(CE_CONT, "info %x next %x ptr %x fsrv %x bsrv %x\n",
+ q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
+ q->q_nbsrv);
+ cmn_err(CE_CONT, "IP Filter: info: putp %x srvp %x info %x\n",
+ q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
+ q->q_qinfo->qi_infop);
+ frstats[0].fr_drop++;
+ freemsg(mb);
+ return 0;
+ }
+ /*
+ * So we can be more re-entrant.
+ */
+ bcopy((char *)qif, (char *)&qfb, sizeof(*qif));
+ mutex_exit(&ipfs_mutex);
+ qif = &qfb;
+ pnext = qif->qf_inp;
+
+ type = MTYPE(mb);
+ if (type == M_DATA || type == M_PROTO || type == M_PCPROTO)
+ if (fr_precheck(&mb, q, qif, 0)) {
+ if (mb)
+ freemsg(mb);
+ return 0;
+ }
+
+ if (mb) {
+ if (pnext)
+ return (*pnext)(q, mb);
+
+ cmn_err(CE_WARN, "IP Filter: inp NULL: qif %x %s q %x info %x",
+ qif, qif->qf_name, q, q->q_qinfo);
+ freemsg(mb);
+ }
+ return 0;
+}
+
+
+int fr_qout(q, mb)
+queue_t *q;
+mblk_t *mb;
+{
+ int (*pnext)(), type, synced = 0;
+ qif_t qfb, *qif;
+
+again:
+ mutex_enter(&ipfs_mutex);
+ if (!(qif = qif_from_queue(q))) {
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if (qif->qf_wqinfo == q->q_qinfo && qif->qf_outp) {
+ pnext = qif->qf_outp;
+ mutex_exit(&ipfs_mutex);
+ frstats[1].fr_notip++;
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ /* fr_donotip(0, NULL, q, mb, mb, NULL, 0); */
+ return (*pnext)(q, mb);
+ }
+ mutex_exit(&ipfs_mutex);
+ if (!synced) {
+ ipfsync();
+ synced = 1;
+ goto again;
+ }
+ cmn_err(CE_WARN,
+ "IP Filter: dropped: fr_qout(%x,%x): type %x: qif %x",
+ q, mb, MTYPE(mb), qif);
+ cmn_err(CE_CONT, "info %x next %x ptr %x fsrv %x bsrv %x\n",
+ q->q_qinfo, q->q_next, q->q_ptr, q->q_nfsrv,
+ q->q_nbsrv);
+ cmn_err(CE_CONT, "IP Filter: info: putp %x srvp %x info %x\n",
+ q->q_qinfo->qi_putp, q->q_qinfo->qi_srvp,
+ q->q_qinfo->qi_infop);
+ if (q->q_nfsrv)
+ cmn_err(CE_CONT, "nfsrv: info %x next %x ptr %x\n",
+ q->q_nfsrv->q_qinfo, q->q_nfsrv->q_next,
+ q->q_nfsrv->q_ptr);
+ if (q->q_nbsrv)
+ cmn_err(CE_CONT, "nbsrv: info %x next %x ptr %x\n",
+ q->q_nbsrv->q_qinfo, q->q_nbsrv->q_next,
+ q->q_nbsrv->q_ptr);
+ frstats[1].fr_drop++;
+ freemsg(mb);
+ return 0;
+ }
+ /*
+ * So we can be more re-entrant.
+ */
+ bcopy((char *)qif, (char *)&qfb, sizeof(*qif));
+ mutex_exit(&ipfs_mutex);
+ qif = &qfb;
+ pnext = qif->qf_outp;
+
+ type = MTYPE(mb);
+ if (type == M_DATA || type == M_PROTO || type == M_PCPROTO)
+ if (fr_precheck(&mb, q, qif, 1)) {
+ if (mb)
+ freemsg(mb);
+ return 0;
+ }
+
+ if (mb) {
+ if (pnext)
+ return (*pnext)(q, mb);
+
+ cmn_err(CE_WARN, "IP Filter: outp NULL: qif %x %s q %x info %x",
+ qif, qif->qf_name, q, q->q_qinfo);
+ freemsg(mb);
+ }
+ return 0;
+}
+
+
+/*
+ * attach the packet filter to each interface that is defined as having an
+ * IP address associated with it and save some of the info. for that struct
+ * so we're not out of date as soon as te ill disappears - but we must sync
+ * to be correct!
+ */
+int solattach()
+{
+ queue_t *in, *out;
+ qif_t *qif, *qf2;
+ ill_t *il;
+
+ for (il = ill_g_head; il; il = il->ill_next) {
+ in = il->ill_rq;
+ if (!in || !il->ill_wq)
+ continue;
+
+ out = il->ill_wq->q_next;
+
+ mutex_enter(&ipfs_mutex);
+ /*
+ * Look for entry already setup for this device
+ */
+ for (qif = qif_head; qif; qif = qif->qf_next)
+ if (qif->qf_iptr == in->q_ptr &&
+ qif->qf_optr == out->q_ptr)
+ break;
+ if (qif) {
+ mutex_exit(&ipfs_mutex);
+ continue;
+ }
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE,
+ "IP Filter: il %x ipt %x opt %x ipu %x opu %x i %x/%x",
+ il, in->q_ptr, out->q_ptr, in->q_qinfo->qi_putp,
+ out->q_qinfo->qi_putp, out->q_qinfo, in->q_qinfo);
+#endif
+ qif = (qif_t *)KMALLOC(sizeof(*qif));
+
+ if (in->q_qinfo->qi_putp == fr_qin) {
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_rqinfo == in->q_qinfo) {
+ qif->qf_inp = qf2->qf_inp;
+ break;
+ }
+ if (!qf2) {
+#ifdef IPFDEBUG
+ cmn_err(CE_WARN,
+ "IP Filter: rq:%s put %x qi %x",
+ il->ill_name, in->q_qinfo->qi_putp,
+ in->q_qinfo);
+#endif
+ mutex_exit(&ipfs_mutex);
+ KFREE(qif);
+ continue;
+ }
+ } else
+ qif->qf_inp = in->q_qinfo->qi_putp;
+
+ if (out->q_qinfo->qi_putp == fr_qout) {
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_wqinfo == out->q_qinfo) {
+ qif->qf_outp = qf2->qf_outp;
+ break;
+ }
+ if (!qf2) {
+#ifdef IPFDEBUG
+ cmn_err(CE_WARN,
+ "IP Filter: wq:%s put %x qi %x",
+ il->ill_name, out->q_qinfo->qi_putp,
+ out->q_qinfo);
+#endif
+ mutex_exit(&ipfs_mutex);
+ KFREE(qif);
+ continue;
+ }
+ } else
+ qif->qf_outp = out->q_qinfo->qi_putp;
+
+ qif->qf_ill = il;
+ qif->qf_iptr = in->q_ptr;
+ qif->qf_optr = out->q_ptr;
+ qif->qf_hl = il->ill_hdr_length;
+ strncpy(qif->qf_name, il->ill_name, sizeof(qif->qf_name));
+ qif->qf_name[sizeof(qif->qf_name) - 1] = '\0';
+ qif->qf_wqinfo = out->q_qinfo;
+ qif->qf_rqinfo = in->q_qinfo;
+
+ qif->qf_next = qif_head;
+ qif_head = qif;
+ in->q_qinfo->qi_putp = fr_qin;
+ out->q_qinfo->qi_putp = fr_qout;
+ mutex_exit(&ipfs_mutex);
+ cmn_err(CE_CONT, "IP Filter: attach to [%s,%d]\n",
+ qif->qf_name, il->ill_ppa);
+ }
+ if (!qif_head) {
+ cmn_err(CE_CONT, "IP Filter: not attached to any interfaces\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * look for bad consistancies between the list of interfaces the filter knows
+ * about and those which are currently configured.
+ */
+int ipfsync()
+{
+ register struct frentry *f, **fp;
+ register qif_t *qif, **qp;
+ register ill_t *il;
+
+ mutex_enter(&ipfs_mutex);
+ for (qp = &qif_head; (qif = *qp); ) {
+ for (il = ill_g_head; il; il = il->ill_next)
+ if ((qif->qf_ill == il) &&
+ !strcmp(qif->qf_name, il->ill_name)) {
+ mblk_t *m = il->ill_hdr_mp;
+
+ qif->qf_hl = il->ill_hdr_length;
+ if (m && qif->qf_hl != (m->b_wptr - m->b_rptr))
+ printf("ILL Header Length Mismatch\n");
+ break;
+ }
+ if (il) {
+ qp = &qif->qf_next;
+ continue;
+ }
+ cmn_err(CE_CONT, "IP Filter: detaching [%s]\n", qif->qf_name);
+ *qp = qif->qf_next;
+
+ /*
+ * Delete any rules directly associated with this interface
+ */
+ mutex_enter(&ipf_mutex);
+ for (fp = &ipfilter[0][0]; (f = *fp); )
+ if ((void *)f->fr_ifa == (void *)qif->qf_ill) {
+ *fp = f->fr_next;
+ KFREE(f);
+ } else
+ fp = &f->fr_next;
+ for (fp = &ipfilter[1][0]; (f = *fp); )
+ if ((void *)f->fr_ifa == (void *)qif->qf_ill) {
+ *fp = f->fr_next;
+ KFREE(f);
+ } else
+ fp = &f->fr_next;
+ mutex_exit(&ipf_mutex);
+
+ KFREE(qif);
+ qif = *qp;
+ }
+ mutex_exit(&ipfs_mutex);
+ return solattach();
+}
+
+
+/*
+ * unhook the IP filter from all defined interfaces with IP addresses
+ */
+int soldetach()
+{
+ queue_t *in, *out;
+ qif_t *qif, *qf2, **qp;
+ ill_t *il;
+
+ mutex_enter(&ipfs_mutex);
+ /*
+ * Make two passes, first get rid of all the unknown devices, next
+ * unlink known devices.
+ */
+ for (qp = &qif_head; (qif = *qp); ) {
+ for (il = ill_g_head; il; il = il->ill_next)
+ if (qif->qf_ill == il)
+ break;
+ if (il) {
+ qp = &qif->qf_next;
+ continue;
+ }
+ cmn_err(CE_CONT, "IP Filter: removing [%s]\n", qif->qf_name);
+ *qp = qif->qf_next;
+ KFREE(qif);
+ }
+
+ while ((qif = qif_head)) {
+ qif_head = qif->qf_next;
+ for (il = ill_g_head; il; il = il->ill_next)
+ if (qif->qf_ill == il)
+ break;
+ if (il) {
+ in = il->ill_rq;
+ out = il->ill_wq->q_next;
+ printf("IP Filter: detaching [%s,%d]\n", qif->qf_name,
+ il->ill_ppa);
+ in->q_qinfo->qi_putp = qif->qf_inp;
+ /*
+ * and change back if something is still interested
+ * in filtering (read side) on this interface.
+ */
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_rqinfo == in->q_qinfo) {
+ in->q_qinfo->qi_putp = fr_qin;
+ break;
+ }
+ /*
+ * and the write queue...
+ */
+ out->q_qinfo->qi_putp = qif->qf_outp;
+ for (qf2 = qif_head; qf2; qf2 = qf2->qf_next)
+ if (qf2->qf_wqinfo == out->q_qinfo) {
+ out->q_qinfo->qi_putp = fr_qout;
+ break;
+ }
+
+ }
+ KFREE(qif);
+ }
+ mutex_exit(&ipfs_mutex);
+ return ipldetach();
+}
+
+
+printire(ire)
+ire_t *ire;
+{
+ printf("ire: ll_hdr_mp %x rfq %x stq %x src_addr %x max_frag %d\n",
+ ire->ire_ll_hdr_mp, ire->ire_rfq, ire->ire_stq,
+ ire->ire_src_addr, ire->ire_max_frag);
+ printf("ire: mask %x addr %x gateway_addr %x type %d\n",
+ ire->ire_mask, ire->ire_addr, ire->ire_gateway_addr,
+ ire->ire_type);
+ printf("ire: ll_hdr_length %d ll_hdr_saved_mp %x\n",
+ ire->ire_ll_hdr_length, ire->ire_ll_hdr_saved_mp);
+}
+
+
+int ipfr_fastroute(qf, ip, mb, mpp, fin, fdp)
+qif_t *qf;
+ip_t *ip;
+mblk_t *mb, **mpp;
+fr_info_t *fin;
+frdest_t *fdp;
+{
+ mblk_t *mp = NULL;
+ struct in_addr dst;
+ ire_t *ir, *dir;
+ int hlen = 0;
+ u_char *s;
+ queue_t *q = NULL;
+
+#ifndef sparc
+ u_short __iplen, __ipoff;
+
+ /*
+ * If this is a duplicate mblk then we want ip to point at that
+ * data, not the original, if and only if it is already pointing at
+ * the current mblk data.
+ */
+ if (ip == (ip_t *)qf->qf_m->b_rptr && qf->qf_m != mb)
+ ip = (ip_t *)mb->b_rptr;
+ /*
+ * In fr_precheck(), we modify ip_len and ip_off in an aligned data
+ * area. However, we only need to change it back if we didn't copy
+ * the IP header data out.
+ */
+
+ __iplen = (u_short)ip->ip_len,
+ __ipoff = (u_short)ip->ip_off;
+
+ ip->ip_len = htons(__iplen);
+ ip->ip_off = htons(__ipoff);
+#endif
+
+ if (ip != (ip_t *)mb->b_rptr) {
+ copyin_mblk(mb, 0, ip, qf->qf_len);
+ frstats[fin->fin_out].fr_pull[1]++;
+ }
+
+ /*
+ * If there is another M_PROTO, we don't want it
+ */
+ if (*mpp != mb) {
+ (*mpp)->b_cont = NULL;
+ freemsg(*mpp);
+ }
+
+ ir = (ire_t *)fdp->fd_ifp;
+
+ if (fdp->fd_ip.s_addr)
+ dst = fdp->fd_ip;
+ else
+ dst = fin->fin_fi.fi_dst;
+
+ if (dir = ire_lookup(dst.s_addr))
+ if (!dir->ire_ll_hdr_mp || !dir->ire_ll_hdr_length)
+ dir = NULL;
+
+ if (!ir)
+ ir = dir;
+
+ if (ir && dir) {
+ if ((mp = dir->ire_ll_hdr_mp)) {
+ hlen = dir->ire_ll_hdr_length;
+
+ s = mb->b_rptr;
+
+ if (hlen && (s - mb->b_datap->db_base) >= hlen) {
+ s -= hlen;
+ mb->b_rptr = (u_char *)s;
+ bcopy((char *)mp->b_rptr, (char *)s, hlen);
+ } else {
+ mblk_t *mp2;
+
+ mp2 = copyb(mp);
+ if (!mp2)
+ goto bad_fastroute;
+ mp2->b_cont = mb;
+ mb = mp2;
+ }
+ }
+
+ if (ir->ire_stq)
+ q = ir->ire_stq;
+ else if (ir->ire_rfq)
+ q = WR(ir->ire_rfq);
+ if (q) {
+ putnext(q, mb);
+ return 0;
+ }
+ }
+bad_fastroute:
+ return -1;
+}
+
+
+void copyout_mblk(m, off, buf, len)
+mblk_t *m;
+int off, len;
+char *buf;
+{
+ char *s, *bp = buf;
+ int mlen, olen, clen;
+
+ for (; m && len; m = m->b_cont) {
+ if (MTYPE(m) != M_DATA)
+ continue;
+ s = m->b_rptr;
+ mlen = (char *)m->b_wptr - s;
+ olen = MIN(off, mlen);
+ if ((olen == mlen) || (olen < off)) {
+ off -= olen;
+ continue;
+ } else if (olen) {
+ off -= olen;
+ s += olen;
+ mlen -= olen;
+ }
+ clen = MIN(mlen, len);
+ bcopy(s, bp, clen);
+ len -= clen;
+ bp += clen;
+ }
+}
+
+
+void copyin_mblk(m, off, buf, len)
+mblk_t *m;
+int off, len;
+char *buf;
+{
+ char *s, *bp = buf;
+ int mlen, olen, clen;
+
+ for (; m && len; m = m->b_cont) {
+ if (MTYPE(m) != M_DATA)
+ continue;
+ s = m->b_rptr;
+ mlen = (char *)m->b_wptr - s;
+ olen = MIN(off, mlen);
+ if ((olen == mlen) || (olen < off)) {
+ off -= olen;
+ continue;
+ } else if (olen) {
+ off -= olen;
+ s += olen;
+ mlen -= olen;
+ }
+ clen = MIN(mlen, len);
+ bcopy(bp, s, clen);
+ len -= clen;
+ bp += clen;
+ }
+}
diff --git a/contrib/ipfilter/test/Makefile b/contrib/ipfilter/test/Makefile
new file mode 100644
index 0000000..d3bdcc2
--- /dev/null
+++ b/contrib/ipfilter/test/Makefile
@@ -0,0 +1,39 @@
+#
+# (C)opyright 1993-1996 by Darren Reed.
+#
+# 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 ?
+#
+# where to put things.
+#
+BINDEST=/usr/local/bin
+SBINDEST=/sbin
+MANDIR=/usr/share/man
+
+tests: first 0 ftests ptests
+
+first:
+ -mkdir -p results
+
+# Filtering tests
+ftests: 1 2 3 4 5 6 7 8 9 10 11 12
+
+# Rule parsing tests
+ptests: i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11
+
+0:
+ @(cd ..; make ipftest; )
+
+1 2 3 4 5 6 7 8 9 10 11:
+ @./dotest $@
+
+12:
+ @./hextest $@
+
+i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11:
+ @./itest $@
+
+clean:
+ /bin/rm -f 1 2 3 4 5 6 7 8 9 10 11 12 results/*
+ /bin/rm -f i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11
diff --git a/contrib/ipfilter/test/dotest b/contrib/ipfilter/test/dotest
new file mode 100644
index 0000000..06d04c5
--- /dev/null
+++ b/contrib/ipfilter/test/dotest
@@ -0,0 +1,26 @@
+#!/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...";
+/bin/cp /dev/null results/$1
+( while read rule; do
+ echo "$rule" | ../ipftest -br - -i input/$1 >> results/$1;
+ if [ $? -ne 0 ] ; then
+ exit 1;
+ fi
+done ) < regress/$1
+cmp expected/$1 results/$1
+status=$?
+if [ $status = 0 ] ; then
+ $TOUCH $1
+fi
+exit $status
diff --git a/contrib/ipfilter/test/expected/1 b/contrib/ipfilter/test/expected/1
new file mode 100644
index 0000000..93b7333
--- /dev/null
+++ b/contrib/ipfilter/test/expected/1
@@ -0,0 +1,16 @@
+block
+block
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
+nomatch
+pass
+pass
diff --git a/contrib/ipfilter/test/expected/10 b/contrib/ipfilter/test/expected/10
new file mode 100644
index 0000000..bc0d83e
--- /dev/null
+++ b/contrib/ipfilter/test/expected/10
@@ -0,0 +1,108 @@
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+block
+block
+block
+nomatch
+nomatch
+block
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+block
+block
+nomatch
+nomatch
+nomatch
+block
+pass
+pass
+nomatch
+nomatch
+nomatch
+pass
+block
+block
+block
+block
+block
+block
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+block
+block
+block
+nomatch
+block
+nomatch
+pass
+pass
+pass
+nomatch
+pass
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+pass
+pass
+pass
+pass
+pass
+block
+block
+nomatch
+block
+nomatch
+block
+pass
+pass
+nomatch
+pass
+nomatch
+pass
+block
+block
+block
+block
+block
+block
+pass
+pass
+pass
+pass
+pass
+pass
+block
+block
+block
+nomatch
+nomatch
+block
diff --git a/contrib/ipfilter/test/expected/11 b/contrib/ipfilter/test/expected/11
new file mode 100644
index 0000000..eb00875
--- /dev/null
+++ b/contrib/ipfilter/test/expected/11
@@ -0,0 +1,66 @@
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
diff --git a/contrib/ipfilter/test/expected/12 b/contrib/ipfilter/test/expected/12
new file mode 100644
index 0000000..f94cf76
--- /dev/null
+++ b/contrib/ipfilter/test/expected/12
@@ -0,0 +1,54 @@
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
diff --git a/contrib/ipfilter/test/expected/2 b/contrib/ipfilter/test/expected/2
new file mode 100644
index 0000000..03b71cd
--- /dev/null
+++ b/contrib/ipfilter/test/expected/2
@@ -0,0 +1,36 @@
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
diff --git a/contrib/ipfilter/test/expected/3 b/contrib/ipfilter/test/expected/3
new file mode 100644
index 0000000..d06d92b
--- /dev/null
+++ b/contrib/ipfilter/test/expected/3
@@ -0,0 +1,40 @@
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+block
+block
+block
+block
+block
+pass
+pass
+pass
+pass
+pass
diff --git a/contrib/ipfilter/test/expected/4 b/contrib/ipfilter/test/expected/4
new file mode 100644
index 0000000..d06d92b
--- /dev/null
+++ b/contrib/ipfilter/test/expected/4
@@ -0,0 +1,40 @@
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+block
+block
+block
+block
+block
+pass
+pass
+pass
+pass
+pass
diff --git a/contrib/ipfilter/test/expected/5 b/contrib/ipfilter/test/expected/5
new file mode 100644
index 0000000..bc80580
--- /dev/null
+++ b/contrib/ipfilter/test/expected/5
@@ -0,0 +1,1344 @@
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
diff --git a/contrib/ipfilter/test/expected/6 b/contrib/ipfilter/test/expected/6
new file mode 100644
index 0000000..bc80580
--- /dev/null
+++ b/contrib/ipfilter/test/expected/6
@@ -0,0 +1,1344 @@
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+block
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+block
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+pass
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
diff --git a/contrib/ipfilter/test/expected/7 b/contrib/ipfilter/test/expected/7
new file mode 100644
index 0000000..c53d6ea
--- /dev/null
+++ b/contrib/ipfilter/test/expected/7
@@ -0,0 +1,54 @@
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
diff --git a/contrib/ipfilter/test/expected/8 b/contrib/ipfilter/test/expected/8
new file mode 100644
index 0000000..398058a
--- /dev/null
+++ b/contrib/ipfilter/test/expected/8
@@ -0,0 +1,36 @@
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+block
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
diff --git a/contrib/ipfilter/test/expected/9 b/contrib/ipfilter/test/expected/9
new file mode 100644
index 0000000..a4572e6
--- /dev/null
+++ b/contrib/ipfilter/test/expected/9
@@ -0,0 +1,108 @@
+block
+block
+block
+block
+block
+block
+nomatch
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+pass
+pass
+pass
+pass
+block
+block
+nomatch
+nomatch
+nomatch
+nomatch
+pass
+pass
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+nomatch
+block
+block
+nomatch
diff --git a/contrib/ipfilter/test/expected/i1 b/contrib/ipfilter/test/expected/i1
new file mode 100644
index 0000000..f69e055
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i1
@@ -0,0 +1,11 @@
+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
+count in from any to any
+pass in on ed0(!) from 127.0.0.1/32 to 127.0.0.1/32
+block in log first on lo0(!) from any to any
+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
diff --git a/contrib/ipfilter/test/expected/i10 b/contrib/ipfilter/test/expected/i10
new file mode 100644
index 0000000..57bd4ef
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i10
@@ -0,0 +1,4 @@
+pass in from 127.0.0.1/32 to 127.0.0.1/32 with opt sec
+block in from any to any with not opt sec-class topsecret
+block in from any to any with not opt sec-class topsecret,secret
+pass in from any to any with opt sec-class topsecret,confid not opt sec-class unclass
diff --git a/contrib/ipfilter/test/expected/i11 b/contrib/ipfilter/test/expected/i11
new file mode 100644
index 0000000..9268c66
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i11
@@ -0,0 +1,4 @@
+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 = 53 keep state keep frags
diff --git a/contrib/ipfilter/test/expected/i2 b/contrib/ipfilter/test/expected/i2
new file mode 100644
index 0000000..9d3398d
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i2
@@ -0,0 +1,6 @@
+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 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
new file mode 100644
index 0000000..4d70a94
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i3
@@ -0,0 +1,8 @@
+log in from any to any
+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
+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
diff --git a/contrib/ipfilter/test/expected/i4 b/contrib/ipfilter/test/expected/i4
new file mode 100644
index 0000000..dfa3674
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i4
@@ -0,0 +1,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 tcp from any port = 25 to any port > 25
+pass in proto tcp/udp from any port 1 >< 3 to any port 1 <> 3
diff --git a/contrib/ipfilter/test/expected/i5 b/contrib/ipfilter/test/expected/i5
new file mode 100644
index 0000000..3bcb10b
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i5
@@ -0,0 +1,5 @@
+log in from any to any
+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
+pass in quick ttl 1 from any to any
diff --git a/contrib/ipfilter/test/expected/i6 b/contrib/ipfilter/test/expected/i6
new file mode 100644
index 0000000..4849626
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i6
@@ -0,0 +1,4 @@
+pass in on lo0(!) fastroute from any to any
+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
+block in quick on qe0(!) to qe1(!) from any to any
diff --git a/contrib/ipfilter/test/expected/i7 b/contrib/ipfilter/test/expected/i7
new file mode 100644
index 0000000..2414f57
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i7
@@ -0,0 +1,3 @@
+pass in on ed0(!) proto tcp from 127.0.0.1/32 to 127.0.0.1/32 port = 23 flags S/SA
+block in on lo0(!) proto tcp from any to any flags A/FSRPAU
+pass in on lo0(!) proto tcp from any to any flags /SPA
diff --git a/contrib/ipfilter/test/expected/i8 b/contrib/ipfilter/test/expected/i8
new file mode 100644
index 0000000..77dc177
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i8
@@ -0,0 +1,2 @@
+pass in proto icmp from 127.0.0.1/32 to 127.0.0.1/32 icmp-type timest
+block in proto icmp from any to any icmp-type unreach code 1
diff --git a/contrib/ipfilter/test/expected/i9 b/contrib/ipfilter/test/expected/i9
new file mode 100644
index 0000000..b36d864
--- /dev/null
+++ b/contrib/ipfilter/test/expected/i9
@@ -0,0 +1,5 @@
+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 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
diff --git a/contrib/ipfilter/test/hextest b/contrib/ipfilter/test/hextest
new file mode 100644
index 0000000..76e1af5
--- /dev/null
+++ b/contrib/ipfilter/test/hextest
@@ -0,0 +1,23 @@
+#!/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...";
+/bin/cp /dev/null results/$1
+( while read rule; do
+ echo "$rule" | ../ipftest -br - -Hi input/$1 >> 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/input/1 b/contrib/ipfilter/test/input/1
new file mode 100644
index 0000000..7c3ae8a
--- /dev/null
+++ b/contrib/ipfilter/test/input/1
@@ -0,0 +1,4 @@
+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
diff --git a/contrib/ipfilter/test/input/10 b/contrib/ipfilter/test/input/10
new file mode 100644
index 0000000..254cee7
--- /dev/null
+++ b/contrib/ipfilter/test/input/10
@@ -0,0 +1,6 @@
+in 1.1.1.1 2.1.1.1 opt lsrr
+in 1.1.1.1 2.1.1.1
+in 1.1.1.1 2.1.1.1 opt ts
+in 1.1.1.1 2.1.1.1 opt sec-class=topsecret
+in 1.1.1.1 2.1.1.1 opt ssrr,sec-class=topsecret
+in 1.1.1.1 2.1.1.1 opt sec
diff --git a/contrib/ipfilter/test/input/11 b/contrib/ipfilter/test/input/11
new file mode 100644
index 0000000..b6e2c1d
--- /dev/null
+++ b/contrib/ipfilter/test/input/11
@@ -0,0 +1,11 @@
+in tcp 1.1.1.1,1 2.1.2.2,23 S
+in tcp 1.1.1.1,1 2.1.2.2,23 A
+in tcp 2.1.2.2,23 1.1.1.1,1 A
+in tcp 1.1.1.1,1 2.1.2.2,23 F
+in tcp 1.1.1.1,1 2.1.2.2,23 A
+in tcp 1.1.1.1,2 2.1.2.2,23 A
+in udp 1.1.1.1,1 4.4.4.4,53
+in udp 2.2.2.2,2 4.4.4.4,53
+in udp 4.4.4.4,53 1.1.1.1,1
+in udp 4.4.4.4,1023 1.1.1.1,2049
+in udp 4.4.4.4,2049 1.1.1.1,1023
diff --git a/contrib/ipfilter/test/input/12 b/contrib/ipfilter/test/input/12
new file mode 100644
index 0000000..5d9c1de
--- /dev/null
+++ b/contrib/ipfilter/test/input/12
@@ -0,0 +1,35 @@
+# 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF SYN
+45 00 0028 0000 4000 3f 06 0000 01010101 02010101
+0401 0019 00000000 00000000 50 02 2000 0000 0000
+
+# 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF ACK
+45 00 0028 0000 4000 3f 06 0000 01010101 02010101
+0401 0019 00000000 00000000 50 10 2000 0000 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 0000 01010101 02010101
+0401 0019 00000000 00000000 50 10 2000 0000 0000
+
+# 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP DF FO=0
+45 00 001c 0000 6000 3f 06 0000 01010101 02010101
+0401 0019 00000000
+
+# 1.1.1.1 -> 2.1.1.1 TTL=63 TCP DF FO=1 ACK
+45 00 001c 0000 6001 3f 06 0000 01010101 02010101
+00000000 50 10 2000
+
+# 1.1.1.1 -> 2.1.1.1 TTL=63 UDP DF MF FO=0
+45 00 0014 0000 6000 3f 11 0000 01010101 02010101
+
+# 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP MF FO=0
+45 00 0018 0000 2000 3f 11 0000 01010101 02010101
+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 0000 01010101 02010101
+0001 0001 0004 0000
+
+# 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP MF FO=0
+45 00 001c 0000 2000 3f 11 0000 01010101 02010101
+0035 0035 0004 0000
+
diff --git a/contrib/ipfilter/test/input/13 b/contrib/ipfilter/test/input/13
new file mode 100644
index 0000000..56ec16d
--- /dev/null
+++ b/contrib/ipfilter/test/input/13
@@ -0,0 +1,39 @@
+# 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 0000 01010101 02010101
+0401 0019 00000000 00000000 50 02 2000 0000 0000
+
+# 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP MF ACK
+45 00 0024 0002 2000 3f 06 0000 01010101 02010101
+0401001900000000 0000000050102000
+
+# 1.1.1.1,1025 -> 2.1.1.1,25 TTL=63 TCP FO=2 ACK
+45 00 002c 0002 0002 3f 06 0000 01010101 02010101
+0000000000010203 0405060708090a0b 0c0d0e0f10111213
+
+# 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 0000 01010101 02010101
+0401 0019 00000000 00000000 50 10 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 0000 01010101 02010101
+0401 0019 00000000
+
+# 1.1.1.1 -> 2.1.1.1 TTL=63 TCP DF FO=1 SYN
+45 00 001c 0005 6001 3f 06 0000 01010101 02010101
+00000000 50 10 2000
+
+# 1.1.1.1 -> 2.1.1.1 TTL=63 UDP DF MF FO=0
+45 00 0014 0006 6000 3f 11 0000 01010101 02010101
+
+# 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP MF FO=0
+45 00 0018 0007 2000 3f 11 0000 01010101 02010101
+0035 0035
+
+# 1.1.1.1,1 -> 2.1.1.1,1 TTL=63 UDP MF FO=0
+45 00 001c 0008 2000 3f 11 0000 01010101 02010101
+0035003500040000
+
+# 1.1.1.1,53 -> 2.1.1.1,53 TTL=63 UDP FO=1
+45 00 001c 0008 0001 3f 11 0000 01010101 02010101
+0000000000000000
+
diff --git a/contrib/ipfilter/test/input/2 b/contrib/ipfilter/test/input/2
new file mode 100644
index 0000000..d168af0
--- /dev/null
+++ b/contrib/ipfilter/test/input/2
@@ -0,0 +1,6 @@
+in tcp 127.0.0.1,1 127.0.0.1,21
+in tcp 1.1.1.1,1 1.2.1.1,21
+in udp 127.0.0.1,1 127.0.0.1,21
+in udp 1.1.1.1,1 1.2.1.1,21
+in icmp 127.0.0.1 127.0.0.1
+in icmp 1.1.1.1 1.2.1.1
diff --git a/contrib/ipfilter/test/input/3 b/contrib/ipfilter/test/input/3
new file mode 100644
index 0000000..16a806f
--- /dev/null
+++ b/contrib/ipfilter/test/input/3
@@ -0,0 +1,5 @@
+in 127.0.0.1 127.0.0.1
+in 1.1.1.1 1.2.1.1
+in 1.1.1.2 1.2.1.1
+in 1.1.2.2 1.2.1.1
+in 1.2.2.2 1.2.1.1
diff --git a/contrib/ipfilter/test/input/4 b/contrib/ipfilter/test/input/4
new file mode 100644
index 0000000..2956d1b
--- /dev/null
+++ b/contrib/ipfilter/test/input/4
@@ -0,0 +1,5 @@
+in 127.0.0.1 127.0.0.1
+in 1.1.1.1 1.1.1.1
+in 1.1.1.1 1.1.1.2
+in 1.1.1.1 1.1.2.2
+in 1.1.1.1 1.2.2.2
diff --git a/contrib/ipfilter/test/input/5 b/contrib/ipfilter/test/input/5
new file mode 100644
index 0000000..41600c1
--- /dev/null
+++ b/contrib/ipfilter/test/input/5
@@ -0,0 +1,28 @@
+in tcp 1.1.1.1,0 2.2.2.2,2222
+in tcp 1.1.1.1,1 2.2.2.2,2222
+in tcp 1.1.1.1,23 2.2.2.2,2222
+in tcp 1.1.1.1,21 2.2.2.2,2222
+in tcp 1.1.1.1,1023 2.2.2.2,2222
+in tcp 1.1.1.1,1024 2.2.2.2,2222
+in tcp 1.1.1.1,1025 2.2.2.2,2222
+in tcp 1.1.1.1,32767 2.2.2.2,2222
+in tcp 1.1.1.1,32768 2.2.2.2,2222
+in tcp 1.1.1.1,65535 2.2.2.2,2222
+in tcp 1.1.1.1,5999 2.2.2.2,2222
+in tcp 1.1.1.1,6000 2.2.2.2,2222
+in tcp 1.1.1.1,6009 2.2.2.2,2222
+in tcp 1.1.1.1,6010 2.2.2.2,2222
+in udp 1.1.1.1,0 2.2.2.2,2222
+in udp 1.1.1.1,1 2.2.2.2,2222
+in udp 1.1.1.1,23 2.2.2.2,2222
+in udp 1.1.1.1,21 2.2.2.2,2222
+in udp 1.1.1.1,1023 2.2.2.2,2222
+in udp 1.1.1.1,1024 2.2.2.2,2222
+in udp 1.1.1.1,1025 2.2.2.2,2222
+in udp 1.1.1.1,32767 2.2.2.2,2222
+in udp 1.1.1.1,32768 2.2.2.2,2222
+in udp 1.1.1.1,65535 2.2.2.2,2222
+in udp 1.1.1.1,5999 2.2.2.2,2222
+in udp 1.1.1.1,6000 2.2.2.2,2222
+in udp 1.1.1.1,6009 2.2.2.2,2222
+in udp 1.1.1.1,6010 2.2.2.2,2222
diff --git a/contrib/ipfilter/test/input/6 b/contrib/ipfilter/test/input/6
new file mode 100644
index 0000000..21f0be3
--- /dev/null
+++ b/contrib/ipfilter/test/input/6
@@ -0,0 +1,28 @@
+in tcp 2.2.2.2,2222 1.1.1.1,0
+in tcp 2.2.2.2,2222 1.1.1.1,1
+in tcp 2.2.2.2,2222 1.1.1.1,23
+in tcp 2.2.2.2,2222 1.1.1.1,21
+in tcp 2.2.2.2,2222 1.1.1.1,1023
+in tcp 2.2.2.2,2222 1.1.1.1,1024
+in tcp 2.2.2.2,2222 1.1.1.1,1025
+in tcp 2.2.2.2,2222 1.1.1.1,32767
+in tcp 2.2.2.2,2222 1.1.1.1,32768
+in tcp 2.2.2.2,2222 1.1.1.1,65535
+in tcp 2.2.2.2,2222 1.1.1.1,5999
+in tcp 2.2.2.2,2222 1.1.1.1,6000
+in tcp 2.2.2.2,2222 1.1.1.1,6009
+in tcp 2.2.2.2,2222 1.1.1.1,6010
+in udp 2.2.2.2,2222 1.1.1.1,0
+in udp 2.2.2.2,2222 1.1.1.1,1
+in udp 2.2.2.2,2222 1.1.1.1,23
+in udp 2.2.2.2,2222 1.1.1.1,21
+in udp 2.2.2.2,2222 1.1.1.1,1023
+in udp 2.2.2.2,2222 1.1.1.1,1024
+in udp 2.2.2.2,2222 1.1.1.1,1025
+in udp 2.2.2.2,2222 1.1.1.1,32767
+in udp 2.2.2.2,2222 1.1.1.1,32768
+in udp 2.2.2.2,2222 1.1.1.1,65535
+in udp 2.2.2.2,2222 1.1.1.1,5999
+in udp 2.2.2.2,2222 1.1.1.1,6000
+in udp 2.2.2.2,2222 1.1.1.1,6009
+in udp 2.2.2.2,2222 1.1.1.1,6010
diff --git a/contrib/ipfilter/test/input/7 b/contrib/ipfilter/test/input/7
new file mode 100644
index 0000000..2721af2
--- /dev/null
+++ b/contrib/ipfilter/test/input/7
@@ -0,0 +1,9 @@
+in icmp 1.1.1.1 2.1.1.1 echo
+in icmp 1.1.1.1 2.1.1.1 echo,1
+in icmp 1.1.1.1 2.1.1.1 echo,3
+in icmp 1.1.1.1 2.1.1.1 unreach
+in icmp 1.1.1.1 2.1.1.1 unreach,1
+in icmp 1.1.1.1 2.1.1.1 unreach,3
+in icmp 1.1.1.1 2.1.1.1 echorep
+in icmp 1.1.1.1 2.1.1.1 echorep,1
+in icmp 1.1.1.1 2.1.1.1 echorep,3
diff --git a/contrib/ipfilter/test/input/8 b/contrib/ipfilter/test/input/8
new file mode 100644
index 0000000..cace511
--- /dev/null
+++ b/contrib/ipfilter/test/input/8
@@ -0,0 +1,6 @@
+in tcp 1.1.1.1,1 2.1.2.2,1 S
+in tcp 1.1.1.1,1 2.1.2.2,1 SA
+in tcp 1.1.1.1,1 2.1.2.2,1 SF
+in tcp 1.1.1.1,1 2.1.2.2,1 SFPAUR
+in tcp 1.1.1.1,1 2.1.2.2,1 PAU
+in tcp 1.1.1.1,1 2.1.2.2,1 A
diff --git a/contrib/ipfilter/test/input/9 b/contrib/ipfilter/test/input/9
new file mode 100644
index 0000000..33f3be3
--- /dev/null
+++ b/contrib/ipfilter/test/input/9
@@ -0,0 +1,6 @@
+in 1.1.1.1 2.1.1.1 opt lsrr
+in 1.1.1.1 2.1.1.1 opt lsrr,ssrr
+in 1.1.1.1 2.1.1.1 opt ts
+in 1.1.1.1 2.1.1.1 opt sec-class=topsecret
+in 1.1.1.1 2.1.1.1 opt ssrr,sec-class=topsecret
+in 1.1.1.1 2.1.1.1 opt sec
diff --git a/contrib/ipfilter/test/itest b/contrib/ipfilter/test/itest
new file mode 100644
index 0000000..c1b5f57
--- /dev/null
+++ b/contrib/ipfilter/test/itest
@@ -0,0 +1,21 @@
+#!/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...";
+/bin/cp /dev/null results/$1
+../ipf -nvf regress/$1 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/regress/1 b/contrib/ipfilter/test/regress/1
new file mode 100644
index 0000000..6a2ede9
--- /dev/null
+++ b/contrib/ipfilter/test/regress/1
@@ -0,0 +1,4 @@
+block in all
+pass in all
+block out all
+pass out all
diff --git a/contrib/ipfilter/test/regress/10 b/contrib/ipfilter/test/regress/10
new file mode 100644
index 0000000..444737a
--- /dev/null
+++ b/contrib/ipfilter/test/regress/10
@@ -0,0 +1,18 @@
+block in from any to any and not ipopts
+pass in from any to any and not opt sec-class topsecret
+block in from any to any and not opt ssrr,sec-class topsecret
+pass in from any to any and not opt ssrr,sec-class topsecret
+block in from any to any and not opt ts,sec-class topsecret
+pass in from any to any and not opt ts,sec-class topsecret
+block in from any to any and not opt sec-class secret
+pass in from any to any and not opt sec-class secret
+block in from any to any and not opt lsrr,ssrr
+pass in from any to any and not opt lsrr,ssrr
+pass in from any to any and not ipopts
+block in from any to any and not opt lsrr
+pass in from any to any and not opt lsrr
+block in from any to any and not opt ssrr,ts
+pass in from any to any and not opt ssrr,ts
+block in from any to any and not opt rr
+pass in from any to any and not opt rr
+block in from any to any and not opt sec-class topsecret
diff --git a/contrib/ipfilter/test/regress/11 b/contrib/ipfilter/test/regress/11
new file mode 100644
index 0000000..0bf0a2a
--- /dev/null
+++ b/contrib/ipfilter/test/regress/11
@@ -0,0 +1,6 @@
+pass in proto tcp from any to any port = 23 flags S/SA keep state
+block in proto tcp from any to any port = 23 flags S/SA keep state
+pass in proto udp from any to any port = 53 keep frags
+block in proto udp from any to any port = 53 keep frags
+pass in proto udp from any to any port = 53 keep state
+block in proto udp from any to any port = 53 keep state
diff --git a/contrib/ipfilter/test/regress/12 b/contrib/ipfilter/test/regress/12
new file mode 100644
index 0000000..c29f839
--- /dev/null
+++ b/contrib/ipfilter/test/regress/12
@@ -0,0 +1,6 @@
+pass in proto tcp from any port > 1024 to any port = 25 with not short
+pass in proto tcp from any port > 1024 to any port = 25
+block in proto tcp from any to any with short
+block in proto tcp from any to any with frag
+pass in proto udp from any port = 53 to any port = 53
+block in proto udp from any port = 53 to any port = 53 with not short
diff --git a/contrib/ipfilter/test/regress/13 b/contrib/ipfilter/test/regress/13
new file mode 100644
index 0000000..f123e47
--- /dev/null
+++ b/contrib/ipfilter/test/regress/13
@@ -0,0 +1,6 @@
+pass in proto tcp from any to any port = 25 flags S/SA keep frags
+block in proto tcp from any to any port = 25 flags S/SA keep frags
+pass in proto udp from any to any port = 53 keep frags
+block in proto udp from any to any port = 53 keep frags
+pass in proto tcp from any to any port = 25 flags S/SA keep state keep frags
+block in proto tcp from any to any port = 25 flags S/SA keep state keep frags
diff --git a/contrib/ipfilter/test/regress/2 b/contrib/ipfilter/test/regress/2
new file mode 100644
index 0000000..e2f02a4
--- /dev/null
+++ b/contrib/ipfilter/test/regress/2
@@ -0,0 +1,6 @@
+block in proto tcp from any to any
+pass in proto tcp from any to any
+block in proto udp from any to any
+pass in proto udp from any to any
+block in proto icmp from any to any
+pass in proto icmp from any to any
diff --git a/contrib/ipfilter/test/regress/3 b/contrib/ipfilter/test/regress/3
new file mode 100644
index 0000000..ee80729
--- /dev/null
+++ b/contrib/ipfilter/test/regress/3
@@ -0,0 +1,8 @@
+block in from 1.1.1.1 to any
+pass in from 1.1.1.1 to any
+block in from 1.1.1.1/24 to any
+pass in from 1.1.1.1/24 to any
+block in from 1.1.1.1/16 to any
+pass in from 1.1.1.1/16 to any
+block in from 1.1.1.1/0 to any
+pass in from 1.1.1.1/0 to any
diff --git a/contrib/ipfilter/test/regress/4 b/contrib/ipfilter/test/regress/4
new file mode 100644
index 0000000..bc8af2f
--- /dev/null
+++ b/contrib/ipfilter/test/regress/4
@@ -0,0 +1,8 @@
+block in from any to 1.1.1.1
+pass in from any to 1.1.1.1
+block in from any to 1.1.1.1/24
+pass in from any to 1.1.1.1/24
+block in from any to 1.1.1.1/16
+pass in from any to 1.1.1.1/16
+block in from any to 1.1.1.1/0
+pass in from any to 1.1.1.1/0
diff --git a/contrib/ipfilter/test/regress/5 b/contrib/ipfilter/test/regress/5
new file mode 100644
index 0000000..998eabd
--- /dev/null
+++ b/contrib/ipfilter/test/regress/5
@@ -0,0 +1,48 @@
+block in proto tcp from any port = 23 to any
+block in proto udp from any port = 23 to any
+block in proto tcp/udp from any port = 23 to any
+pass in proto tcp from any port <= 1023 to any
+pass in proto udp from any port <= 1023 to any
+pass in proto tcp/udp from any port <= 1023 to any
+block in proto tcp from any port >= 1024 to any
+block in proto udp from any port >= 1024 to any
+block in proto tcp/udp from any port >= 1024 to any
+pass in proto tcp from any port >= 1024 to any
+pass in proto udp from any port >= 1024 to any
+pass in proto tcp/udp from any port >= 1024 to any
+block in proto tcp from any port 0 >< 512 to any
+block in proto udp from any port 0 >< 512 to any
+block in proto tcp/udp from any port 0 >< 512 to any
+pass in proto tcp from any port 0 >< 512 to any
+pass in proto udp from any port 0 >< 512 to any
+pass in proto tcp/udp from any port 0 >< 512 to any
+block in proto tcp from any port 6000 <> 6009 to any
+block in proto udp from any port 6000 <> 6009 to any
+block in proto tcp/udp from any port 6000 <> 6009 to any
+pass in proto tcp from any port 6000 <> 6009 to any
+pass in proto udp from any port 6000 <> 6009 to any
+pass in proto tcp/udp from any port 6000 <> 6009 to any
+pass in proto tcp from any port = 23 to any
+pass in proto udp from any port = 23 to any
+pass in proto tcp/udp from any port = 23 to any
+block in proto tcp from any port != 21 to any
+block in proto udp from any port != 21 to any
+block in proto tcp/udp from any port != 21 to any
+pass in proto tcp from any port != 21 to any
+pass in proto udp from any port != 21 to any
+pass in proto tcp/udp from any port != 21 to any
+block in proto tcp from any port < 1024 to any
+block in proto udp from any port < 1024 to any
+block in proto tcp/udp from any port < 1024 to any
+pass in proto tcp from any port < 1024 to any
+pass in proto udp from any port < 1024 to any
+pass in proto tcp/udp from any port < 1024 to any
+block in proto tcp from any port > 1023 to any
+block in proto udp from any port > 1023 to any
+block in proto tcp/udp from any port > 1023 to any
+pass in proto tcp from any port > 1023 to any
+pass in proto udp from any port > 1023 to any
+pass in proto tcp/udp from any port > 1023 to any
+block in proto tcp from any port <= 1023 to any
+block in proto udp from any port <= 1023 to any
+block in proto tcp/udp from any port <= 1023 to any
diff --git a/contrib/ipfilter/test/regress/6 b/contrib/ipfilter/test/regress/6
new file mode 100644
index 0000000..291f09ad
--- /dev/null
+++ b/contrib/ipfilter/test/regress/6
@@ -0,0 +1,48 @@
+block in proto tcp from any to any port = 23
+block in proto udp from any to any port = 23
+block in proto tcp/udp from any to any port = 23
+pass in proto tcp from any to any port <= 1023
+pass in proto udp from any to any port <= 1023
+pass in proto tcp/udp from any to any port <= 1023
+block in proto tcp from any to any port >= 1024
+block in proto udp from any to any port >= 1024
+block in proto tcp/udp from any to any port >= 1024
+pass in proto tcp from any to any port >= 1024
+pass in proto udp from any to any port >= 1024
+pass in proto tcp/udp from any to any port >= 1024
+block in proto tcp from any to any port 0 >< 512
+block in proto udp from any to any port 0 >< 512
+block in proto tcp/udp from any to any port 0 >< 512
+pass in proto tcp from any to any port 0 >< 512
+pass in proto udp from any to any port 0 >< 512
+pass in proto tcp/udp from any to any port 0 >< 512
+block in proto tcp from any to any port 6000 <> 6009
+block in proto udp from any to any port 6000 <> 6009
+block in proto tcp/udp from any to any port 6000 <> 6009
+pass in proto tcp from any to any port 6000 <> 6009
+pass in proto udp from any to any port 6000 <> 6009
+pass in proto tcp/udp from any to any port 6000 <> 6009
+pass in proto tcp from any to any port = 23
+pass in proto udp from any to any port = 23
+pass in proto tcp/udp from any to any port = 23
+block in proto tcp from any to any port != 21
+block in proto udp from any to any port != 21
+block in proto tcp/udp from any to any port != 21
+pass in proto tcp from any to any port != 21
+pass in proto udp from any to any port != 21
+pass in proto tcp/udp from any to any port != 21
+block in proto tcp from any to any port < 1024
+block in proto udp from any to any port < 1024
+block in proto tcp/udp from any to any port < 1024
+pass in proto tcp from any to any port < 1024
+pass in proto udp from any to any port < 1024
+pass in proto tcp/udp from any to any port < 1024
+block in proto tcp from any to any port > 1023
+block in proto udp from any to any port > 1023
+block in proto tcp/udp from any to any port > 1023
+pass in proto tcp from any to any port > 1023
+pass in proto udp from any to any port > 1023
+pass in proto tcp/udp from any to any port > 1023
+block in proto tcp from any to any port <= 1023
+block in proto udp from any to any port <= 1023
+block in proto tcp/udp from any to any port <= 1023
diff --git a/contrib/ipfilter/test/regress/7 b/contrib/ipfilter/test/regress/7
new file mode 100644
index 0000000..6848a68
--- /dev/null
+++ b/contrib/ipfilter/test/regress/7
@@ -0,0 +1,6 @@
+block in proto icmp from any to any icmp-type echo
+pass in proto icmp from any to any icmp-type echo
+block in proto icmp from any to any icmp-type unreach code 3
+pass in proto icmp from any to any icmp-type unreach code 3
+block in proto icmp from any to any icmp-type echorep
+pass in proto icmp from any to any icmp-type echorep
diff --git a/contrib/ipfilter/test/regress/8 b/contrib/ipfilter/test/regress/8
new file mode 100644
index 0000000..0f28fd2
--- /dev/null
+++ b/contrib/ipfilter/test/regress/8
@@ -0,0 +1,6 @@
+block in proto tcp from any to any flags S
+pass in proto tcp from any to any flags S
+block in proto tcp from any to any flags S/SA
+pass in proto tcp from any to any flags S/SA
+block in proto tcp from any to any flags S/APU
+pass in proto tcp from any to any flags S/APU
diff --git a/contrib/ipfilter/test/regress/9 b/contrib/ipfilter/test/regress/9
new file mode 100644
index 0000000..17bc967
--- /dev/null
+++ b/contrib/ipfilter/test/regress/9
@@ -0,0 +1,18 @@
+block in from any to any with ipopts
+pass in from any to any with opt sec-class topsecret
+block in from any to any with opt ssrr,sec-class topsecret
+pass in from any to any with opt ssrr,sec-class topsecret
+block in from any to any with opt ts,sec-class topsecret
+pass in from any to any with opt ts,sec-class topsecret
+block in from any to any with opt sec-class secret
+pass in from any to any with opt sec-class secret
+block in from any to any with opt lsrr,ssrr
+pass in from any to any with opt lsrr,ssrr
+pass in from any to any with ipopts
+block in from any to any with opt lsrr
+pass in from any to any with opt lsrr
+block in from any to any with opt ssrr,ts
+pass in from any to any with opt ssrr,ts
+block in from any to any with opt rr
+pass in from any to any with opt rr
+block in from any to any with opt sec-class topsecret
diff --git a/contrib/ipfilter/test/regress/i1 b/contrib/ipfilter/test/regress/i1
new file mode 100644
index 0000000..583cd8b
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i1
@@ -0,0 +1,11 @@
+pass in all
+block out all
+log in all
+log body in all
+count in from any to any
+pass in on ed0 from localhost to localhost
+block in log first on lo0 from any to any
+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
diff --git a/contrib/ipfilter/test/regress/i10 b/contrib/ipfilter/test/regress/i10
new file mode 100644
index 0000000..ece2712
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i10
@@ -0,0 +1,4 @@
+pass in from localhost to localhost with opt sec
+block in from any to any with not opt sec-class topsecret
+block in from any to any with not opt sec-class topsecret,secret
+pass in from any to any with opt sec-class topsecret,confid not opt sec-class unclass
diff --git a/contrib/ipfilter/test/regress/i11 b/contrib/ipfilter/test/regress/i11
new file mode 100644
index 0000000..c257f51
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i11
@@ -0,0 +1,4 @@
+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 = 53 keep state keep frags
diff --git a/contrib/ipfilter/test/regress/i2 b/contrib/ipfilter/test/regress/i2
new file mode 100644
index 0000000..101deaa
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i2
@@ -0,0 +1,6 @@
+log in proto tcp all
+pass in proto 6 from any to any
+pass in proto udp from localhost to localhost
+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
new file mode 100644
index 0000000..e69663e
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i3
@@ -0,0 +1,8 @@
+log in all
+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
+pass in from 128.0.0.1 mask 255.255.255.0 to 128.0.0.1 mask 255.255.0.0
+pass in from localhost to localhost
+block in log from 0/0 to 0/0
diff --git a/contrib/ipfilter/test/regress/i4 b/contrib/ipfilter/test/regress/i4
new file mode 100644
index 0000000..1095ed9
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i4
@@ -0,0 +1,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 tcp from any port = smtp to any port > 25
+pass in proto tcp/udp from any port 1 >< 3 to any port 1 <> 3
diff --git a/contrib/ipfilter/test/regress/i5 b/contrib/ipfilter/test/regress/i5
new file mode 100644
index 0000000..38482f3
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i5
@@ -0,0 +1,5 @@
+log in all
+count in tos 0x80 from any to any
+pass in on ed0 tos 64 from localhost to localhost
+block in log on lo0 ttl 0 from any to any
+pass in quick ttl 1 from any to any
diff --git a/contrib/ipfilter/test/regress/i6 b/contrib/ipfilter/test/regress/i6
new file mode 100644
index 0000000..a35633b
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i6
@@ -0,0 +1,4 @@
+pass in on lo0 fastroute from any to any
+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
+block in quick on qe0 to qe1 from any to any
diff --git a/contrib/ipfilter/test/regress/i7 b/contrib/ipfilter/test/regress/i7
new file mode 100644
index 0000000..9cb3572
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i7
@@ -0,0 +1,3 @@
+pass in on ed0 proto tcp from localhost to localhost port = 23 flags S/SA
+block in on lo0 proto tcp from any to any flags A
+pass in on lo0 proto tcp from any to any flags /SAP
diff --git a/contrib/ipfilter/test/regress/i8 b/contrib/ipfilter/test/regress/i8
new file mode 100644
index 0000000..bde6ed5
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i8
@@ -0,0 +1,2 @@
+pass in proto icmp from localhost to localhost icmp-type timest
+block in proto icmp from any to any icmp-type unreach code 1
diff --git a/contrib/ipfilter/test/regress/i9 b/contrib/ipfilter/test/regress/i9
new file mode 100644
index 0000000..327cff4
--- /dev/null
+++ b/contrib/ipfilter/test/regress/i9
@@ -0,0 +1,5 @@
+pass in from localhost to localhost with short
+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
diff --git a/contrib/ipfilter/todo b/contrib/ipfilter/todo
new file mode 100644
index 0000000..f1664c0
--- /dev/null
+++ b/contrib/ipfilter/todo
@@ -0,0 +1,19 @@
+* automatically use the interface's IP# for NAT rather than any specific IP#
+
+* use fr_tcpstate() with NAT code for increased NAT usage security or even
+ fr_checkstate()
+
+* use minor devices for controlling access to alternate parts of IP Filter
+ such as filtering, accounting, state, NAT, etc.
+
+* see if the Solaris2 and dynamic plumb/unplumb problem is solvable
+
+time permitting:
+
+* load balancing across interfaces
+
+* record buffering for TCP/UDP
+
+* modular application proxying
+
+* invesitgate making logging better
OpenPOWER on IntegriCloud