summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2015-10-05 03:26:51 +0000
committerngie <ngie@FreeBSD.org>2015-10-05 03:26:51 +0000
commite1dd16d965b177f109afb771e59432e36f335d0a (patch)
tree15db092a5401cf329f1bff9d3bf700d1fde0f121
parent115d008392113efc6f844baa7cc407e9eaae63db (diff)
downloadFreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.zip
FreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.tar.gz
Revert r288682
I meant to do this on ^/user/ngie/more-tests Pointyhat to: ngie (use svn info next time...)
-rw-r--r--contrib/ipfilter/BNF81
-rw-r--r--contrib/ipfilter/BugReport12
-rw-r--r--contrib/ipfilter/HISTORY1830
-rw-r--r--contrib/ipfilter/LICENCE16
-rw-r--r--contrib/ipfilter/Makefile410
-rw-r--r--contrib/ipfilter/NAT.FreeBSD104
-rw-r--r--contrib/ipfilter/README101
-rw-r--r--contrib/ipfilter/STYLE.TXT57
-rw-r--r--contrib/ipfilter/WhatsNew50.txt83
-rw-r--r--contrib/ipfilter/Y2K3
-rw-r--r--contrib/ipfilter/arc4random.c277
-rw-r--r--contrib/ipfilter/bpf-ipf.h452
-rw-r--r--contrib/ipfilter/bpf_filter.c595
-rw-r--r--contrib/ipfilter/genmask.c68
-rw-r--r--contrib/ipfilter/ip_dstlist.c1351
-rw-r--r--contrib/ipfilter/ip_dstlist.h68
-rw-r--r--contrib/ipfilter/ip_fil.c884
-rw-r--r--contrib/ipfilter/ip_fil_compat.c4854
-rw-r--r--contrib/ipfilter/ip_msnrpc_pxy.c328
-rw-r--r--contrib/ipfilter/ipf.h403
-rw-r--r--contrib/ipfilter/ipf_rb.h364
-rw-r--r--contrib/ipfilter/iplang/BNF69
-rw-r--r--contrib/ipfilter/iplang/Makefile31
-rw-r--r--contrib/ipfilter/iplang/iplang.h54
-rw-r--r--contrib/ipfilter/iplang/iplang.tst11
-rw-r--r--contrib/ipfilter/iplang/iplang_l.l322
-rw-r--r--contrib/ipfilter/iplang/iplang_y.y1858
-rw-r--r--contrib/ipfilter/ipmon.h142
-rw-r--r--contrib/ipfilter/ipsd/Celler/ip_compat.h203
-rw-r--r--contrib/ipfilter/ipsd/Makefile61
-rw-r--r--contrib/ipfilter/ipsd/README32
-rw-r--r--contrib/ipfilter/ipsd/ipsd.c296
-rw-r--r--contrib/ipfilter/ipsd/ipsd.h28
-rw-r--r--contrib/ipfilter/ipsd/ipsdr.c314
-rw-r--r--contrib/ipfilter/ipsd/linux.h17
-rw-r--r--contrib/ipfilter/ipsd/sbpf.c210
-rw-r--r--contrib/ipfilter/ipsd/sdlpi.c261
-rw-r--r--contrib/ipfilter/ipsd/slinux.c118
-rw-r--r--contrib/ipfilter/ipsd/snit.c228
-rw-r--r--contrib/ipfilter/ipsend/.OLD/ip_compat.h244
-rw-r--r--contrib/ipfilter/ipsend/44arp.c120
-rw-r--r--contrib/ipfilter/ipsend/Crashable21
-rw-r--r--contrib/ipfilter/ipsend/Makefile183
-rw-r--r--contrib/ipfilter/ipsend/arp.c141
-rw-r--r--contrib/ipfilter/ipsend/dlcommon.c1383
-rw-r--r--contrib/ipfilter/ipsend/dltest.h34
-rw-r--r--contrib/ipfilter/ipsend/ip.c364
-rw-r--r--contrib/ipfilter/ipsend/ipresend.1108
-rw-r--r--contrib/ipfilter/ipsend/ipresend.c151
-rw-r--r--contrib/ipfilter/ipsend/ipsend.1111
-rw-r--r--contrib/ipfilter/ipsend/ipsend.5402
-rw-r--r--contrib/ipfilter/ipsend/ipsend.c440
-rw-r--r--contrib/ipfilter/ipsend/ipsend.h73
-rw-r--r--contrib/ipfilter/ipsend/ipsopt.c200
-rw-r--r--contrib/ipfilter/ipsend/iptest.1103
-rw-r--r--contrib/ipfilter/ipsend/iptest.c218
-rw-r--r--contrib/ipfilter/ipsend/iptests.c1426
-rw-r--r--contrib/ipfilter/ipsend/larp.c93
-rw-r--r--contrib/ipfilter/ipsend/linux.h19
-rw-r--r--contrib/ipfilter/ipsend/lsock.c259
-rw-r--r--contrib/ipfilter/ipsend/resend.c143
-rw-r--r--contrib/ipfilter/ipsend/sbpf.c153
-rw-r--r--contrib/ipfilter/ipsend/sdlpi.c173
-rw-r--r--contrib/ipfilter/ipsend/sirix.c93
-rw-r--r--contrib/ipfilter/ipsend/slinux.c92
-rw-r--r--contrib/ipfilter/ipsend/snit.c160
-rw-r--r--contrib/ipfilter/ipsend/sock.c457
-rw-r--r--contrib/ipfilter/ipsend/sockraw.c89
-rw-r--r--contrib/ipfilter/ipt.h40
-rw-r--r--contrib/ipfilter/kmem.h34
-rw-r--r--contrib/ipfilter/l4check/Makefile10
-rw-r--r--contrib/ipfilter/l4check/http.check2
-rw-r--r--contrib/ipfilter/l4check/http.ok1
-rw-r--r--contrib/ipfilter/l4check/l4check.c807
-rw-r--r--contrib/ipfilter/l4check/l4check.conf31
-rw-r--r--contrib/ipfilter/lib/Makefile443
-rw-r--r--contrib/ipfilter/lib/addicmp.c21
-rw-r--r--contrib/ipfilter/lib/addipopt.c65
-rw-r--r--contrib/ipfilter/lib/alist_free.c20
-rw-r--r--contrib/ipfilter/lib/alist_new.c93
-rw-r--r--contrib/ipfilter/lib/allocmbt.c22
-rw-r--r--contrib/ipfilter/lib/assigndefined.c27
-rw-r--r--contrib/ipfilter/lib/bcopywrap.c20
-rw-r--r--contrib/ipfilter/lib/binprint.c31
-rw-r--r--contrib/ipfilter/lib/buildopts.c50
-rw-r--r--contrib/ipfilter/lib/checkrev.c46
-rw-r--r--contrib/ipfilter/lib/connecttcp.c48
-rw-r--r--contrib/ipfilter/lib/count4bits.c40
-rw-r--r--contrib/ipfilter/lib/count6bits.c29
-rw-r--r--contrib/ipfilter/lib/debug.c58
-rw-r--r--contrib/ipfilter/lib/dupmbt.c24
-rw-r--r--contrib/ipfilter/lib/facpri.c153
-rw-r--r--contrib/ipfilter/lib/facpri.h43
-rw-r--r--contrib/ipfilter/lib/familyname.c12
-rw-r--r--contrib/ipfilter/lib/fill6bits.c48
-rw-r--r--contrib/ipfilter/lib/findword.c25
-rw-r--r--contrib/ipfilter/lib/flags.c25
-rw-r--r--contrib/ipfilter/lib/freembt.c16
-rw-r--r--contrib/ipfilter/lib/ftov.c16
-rw-r--r--contrib/ipfilter/lib/gethost.c76
-rw-r--r--contrib/ipfilter/lib/geticmptype.c29
-rw-r--r--contrib/ipfilter/lib/getifname.c95
-rw-r--r--contrib/ipfilter/lib/getnattype.c70
-rw-r--r--contrib/ipfilter/lib/getport.c90
-rw-r--r--contrib/ipfilter/lib/getportproto.c40
-rw-r--r--contrib/ipfilter/lib/getproto.c41
-rw-r--r--contrib/ipfilter/lib/getsumd.c23
-rw-r--r--contrib/ipfilter/lib/hostname.c60
-rw-r--r--contrib/ipfilter/lib/icmpcode.c24
-rw-r--r--contrib/ipfilter/lib/icmptypename.c28
-rw-r--r--contrib/ipfilter/lib/icmptypes.c107
-rw-r--r--contrib/ipfilter/lib/inet_addr.c210
-rw-r--r--contrib/ipfilter/lib/initparse.c20
-rw-r--r--contrib/ipfilter/lib/interror.c582
-rw-r--r--contrib/ipfilter/lib/ionames.c41
-rw-r--r--contrib/ipfilter/lib/ipf_dotuning.c74
-rw-r--r--contrib/ipfilter/lib/ipf_perror.c47
-rw-r--r--contrib/ipfilter/lib/ipft_hx.c185
-rw-r--r--contrib/ipfilter/lib/ipft_pc.c254
-rw-r--r--contrib/ipfilter/lib/ipft_tx.c510
-rw-r--r--contrib/ipfilter/lib/ipoptsec.c61
-rw-r--r--contrib/ipfilter/lib/kmem.c201
-rw-r--r--contrib/ipfilter/lib/kmem.h34
-rw-r--r--contrib/ipfilter/lib/kmemcpywrap.c23
-rw-r--r--contrib/ipfilter/lib/kvatoname.c39
-rw-r--r--contrib/ipfilter/lib/load_dstlist.c69
-rw-r--r--contrib/ipfilter/lib/load_dstlistnode.c70
-rw-r--r--contrib/ipfilter/lib/load_file.c96
-rw-r--r--contrib/ipfilter/lib/load_hash.c103
-rw-r--r--contrib/ipfilter/lib/load_hashnode.c67
-rw-r--r--contrib/ipfilter/lib/load_http.c208
-rw-r--r--contrib/ipfilter/lib/load_pool.c72
-rw-r--r--contrib/ipfilter/lib/load_poolnode.c70
-rw-r--r--contrib/ipfilter/lib/load_url.c31
-rw-r--r--contrib/ipfilter/lib/mb_hexdump.c32
-rw-r--r--contrib/ipfilter/lib/msgdsize.c20
-rw-r--r--contrib/ipfilter/lib/mutex_emul.c133
-rw-r--r--contrib/ipfilter/lib/nametokva.c38
-rw-r--r--contrib/ipfilter/lib/nat_setgroupmap.c34
-rw-r--r--contrib/ipfilter/lib/ntomask.c47
-rw-r--r--contrib/ipfilter/lib/optname.c65
-rw-r--r--contrib/ipfilter/lib/optprint.c83
-rw-r--r--contrib/ipfilter/lib/optprintv6.c47
-rw-r--r--contrib/ipfilter/lib/optvalue.c34
-rw-r--r--contrib/ipfilter/lib/parsefields.c48
-rw-r--r--contrib/ipfilter/lib/parseipfexpr.c283
-rw-r--r--contrib/ipfilter/lib/parsewhoisline.c132
-rw-r--r--contrib/ipfilter/lib/poolio.c53
-rw-r--r--contrib/ipfilter/lib/portname.c43
-rw-r--r--contrib/ipfilter/lib/prependmbt.c18
-rw-r--r--contrib/ipfilter/lib/print_toif.c50
-rw-r--r--contrib/ipfilter/lib/printactiveaddr.c37
-rw-r--r--contrib/ipfilter/lib/printactivenat.c149
-rw-r--r--contrib/ipfilter/lib/printaddr.c75
-rw-r--r--contrib/ipfilter/lib/printaps.c113
-rw-r--r--contrib/ipfilter/lib/printbuf.c34
-rw-r--r--contrib/ipfilter/lib/printdstl_live.c84
-rw-r--r--contrib/ipfilter/lib/printdstlist.c60
-rw-r--r--contrib/ipfilter/lib/printdstlistdata.c47
-rw-r--r--contrib/ipfilter/lib/printdstlistnode.c78
-rw-r--r--contrib/ipfilter/lib/printdstlistpolicy.c31
-rw-r--r--contrib/ipfilter/lib/printfieldhdr.c55
-rw-r--r--contrib/ipfilter/lib/printfr.c473
-rw-r--r--contrib/ipfilter/lib/printfraginfo.c42
-rw-r--r--contrib/ipfilter/lib/printhash.c58
-rw-r--r--contrib/ipfilter/lib/printhash_live.c70
-rw-r--r--contrib/ipfilter/lib/printhashdata.c94
-rw-r--r--contrib/ipfilter/lib/printhashnode.c69
-rw-r--r--contrib/ipfilter/lib/printhost.c35
-rw-r--r--contrib/ipfilter/lib/printhostmap.c31
-rw-r--r--contrib/ipfilter/lib/printhostmask.c39
-rw-r--r--contrib/ipfilter/lib/printifname.c22
-rw-r--r--contrib/ipfilter/lib/printip.c43
-rw-r--r--contrib/ipfilter/lib/printipfexpr.c199
-rw-r--r--contrib/ipfilter/lib/printiphdr.c20
-rw-r--r--contrib/ipfilter/lib/printlog.c39
-rw-r--r--contrib/ipfilter/lib/printlookup.c42
-rw-r--r--contrib/ipfilter/lib/printmask.c30
-rw-r--r--contrib/ipfilter/lib/printnat.c353
-rw-r--r--contrib/ipfilter/lib/printnataddr.c48
-rw-r--r--contrib/ipfilter/lib/printnatfield.c220
-rw-r--r--contrib/ipfilter/lib/printnatside.c55
-rw-r--r--contrib/ipfilter/lib/printpacket.c110
-rw-r--r--contrib/ipfilter/lib/printpacket6.c60
-rw-r--r--contrib/ipfilter/lib/printpool.c65
-rw-r--r--contrib/ipfilter/lib/printpool_live.c71
-rw-r--r--contrib/ipfilter/lib/printpooldata.c50
-rw-r--r--contrib/ipfilter/lib/printpoolfield.c168
-rw-r--r--contrib/ipfilter/lib/printpoolnode.c51
-rw-r--r--contrib/ipfilter/lib/printportcmp.c30
-rw-r--r--contrib/ipfilter/lib/printproto.c55
-rw-r--r--contrib/ipfilter/lib/printsbuf.c42
-rw-r--r--contrib/ipfilter/lib/printstate.c224
-rw-r--r--contrib/ipfilter/lib/printstatefields.c358
-rw-r--r--contrib/ipfilter/lib/printtcpflags.c30
-rw-r--r--contrib/ipfilter/lib/printtqtable.c26
-rw-r--r--contrib/ipfilter/lib/printtunable.c30
-rw-r--r--contrib/ipfilter/lib/printunit.c47
-rw-r--r--contrib/ipfilter/lib/remove_hash.c50
-rw-r--r--contrib/ipfilter/lib/remove_hashnode.c56
-rw-r--r--contrib/ipfilter/lib/remove_pool.c47
-rw-r--r--contrib/ipfilter/lib/remove_poolnode.c54
-rw-r--r--contrib/ipfilter/lib/resetlexer.c25
-rw-r--r--contrib/ipfilter/lib/rwlock_emul.c145
-rw-r--r--contrib/ipfilter/lib/save_execute.c80
-rw-r--r--contrib/ipfilter/lib/save_file.c130
-rw-r--r--contrib/ipfilter/lib/save_nothing.c62
-rw-r--r--contrib/ipfilter/lib/save_syslog.c137
-rw-r--r--contrib/ipfilter/lib/save_v1trap.c463
-rw-r--r--contrib/ipfilter/lib/save_v2trap.c459
-rw-r--r--contrib/ipfilter/lib/tcp_flags.c50
-rw-r--r--contrib/ipfilter/lib/tcpflags.c45
-rw-r--r--contrib/ipfilter/lib/tcpoptnames.c22
-rw-r--r--contrib/ipfilter/lib/v6ionames.c28
-rw-r--r--contrib/ipfilter/lib/v6optvalue.c39
-rw-r--r--contrib/ipfilter/lib/var.c179
-rw-r--r--contrib/ipfilter/lib/verbose.c55
-rw-r--r--contrib/ipfilter/lib/vtof.c16
-rw-r--r--contrib/ipfilter/man/Makefile31
-rw-r--r--contrib/ipfilter/man/ipf.4254
-rw-r--r--contrib/ipfilter/man/ipf.51698
-rw-r--r--contrib/ipfilter/man/ipf.8172
-rw-r--r--contrib/ipfilter/man/ipfilter.4241
-rw-r--r--contrib/ipfilter/man/ipfilter.4.mandoc267
-rw-r--r--contrib/ipfilter/man/ipfilter.511
-rw-r--r--contrib/ipfilter/man/ipfs.8127
-rw-r--r--contrib/ipfilter/man/ipfstat.8194
-rw-r--r--contrib/ipfilter/man/ipftest.1205
-rw-r--r--contrib/ipfilter/man/ipl.481
-rw-r--r--contrib/ipfilter/man/ipmon.5226
-rw-r--r--contrib/ipfilter/man/ipmon.8186
-rw-r--r--contrib/ipfilter/man/ipnat.148
-rw-r--r--contrib/ipfilter/man/ipnat.497
-rw-r--r--contrib/ipfilter/man/ipnat.5728
-rw-r--r--contrib/ipfilter/man/ipnat.876
-rw-r--r--contrib/ipfilter/man/ippool.5320
-rw-r--r--contrib/ipfilter/man/ippool.8133
-rw-r--r--contrib/ipfilter/man/ipscan.552
-rw-r--r--contrib/ipfilter/man/ipscan.844
-rw-r--r--contrib/ipfilter/man/mkfilters.116
-rw-r--r--contrib/ipfilter/md5.c319
-rw-r--r--contrib/ipfilter/md5.h72
-rw-r--r--contrib/ipfilter/mkfilters116
-rw-r--r--contrib/ipfilter/ml_ipl.c164
-rw-r--r--contrib/ipfilter/mlf_ipl.c596
-rw-r--r--contrib/ipfilter/mlf_rule.c168
-rw-r--r--contrib/ipfilter/mlfk_ipl.c529
-rw-r--r--contrib/ipfilter/mlfk_rule.c70
-rw-r--r--contrib/ipfilter/mlh_rule.c114
-rw-r--r--contrib/ipfilter/mli_ipl.c683
-rw-r--r--contrib/ipfilter/mln_ipl.c355
-rw-r--r--contrib/ipfilter/mln_rule.c83
-rw-r--r--contrib/ipfilter/mlo_ipl.c364
-rw-r--r--contrib/ipfilter/mlo_rule.c80
-rw-r--r--contrib/ipfilter/mls_ipl.c351
-rw-r--r--contrib/ipfilter/mls_rule.c116
-rw-r--r--contrib/ipfilter/mlso_rule.c130
-rw-r--r--contrib/ipfilter/opt_inet6.h1
-rw-r--r--contrib/ipfilter/opts.h69
-rw-r--r--contrib/ipfilter/pcap-bpf.h687
-rw-r--r--contrib/ipfilter/pcap-ipf.h35
-rw-r--r--contrib/ipfilter/radix_ipf.c1528
-rw-r--r--contrib/ipfilter/radix_ipf.h97
-rw-r--r--contrib/ipfilter/rules/BASIC.NAT46
-rw-r--r--contrib/ipfilter/rules/BASIC_1.FW99
-rw-r--r--contrib/ipfilter/rules/BASIC_2.FW72
-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.25
-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/firewall39
-rw-r--r--contrib/ipfilter/rules/ftp-proxy45
-rwxr-xr-xcontrib/ipfilter/rules/ftppxy6
-rw-r--r--contrib/ipfilter/rules/ip_rules3
-rw-r--r--contrib/ipfilter/rules/ipmon.conf25
-rw-r--r--contrib/ipfilter/rules/nat-setup77
-rw-r--r--contrib/ipfilter/rules/nat.eg14
-rw-r--r--contrib/ipfilter/rules/pool.conf4
-rw-r--r--contrib/ipfilter/rules/server11
-rw-r--r--contrib/ipfilter/rules/tcpstate13
-rw-r--r--contrib/ipfilter/samples/Makefile24
-rw-r--r--contrib/ipfilter/samples/ipfilter-pb.gifbin0 -> 795 bytes
-rw-r--r--contrib/ipfilter/samples/proxy.c317
-rw-r--r--contrib/ipfilter/samples/relay.c196
-rw-r--r--contrib/ipfilter/samples/userauth.c62
-rw-r--r--contrib/ipfilter/snoop.h47
-rw-r--r--contrib/ipfilter/sys/tree.h750
-rw-r--r--contrib/ipfilter/tools/BNF.ipf80
-rw-r--r--contrib/ipfilter/tools/BNF.ipnat28
-rw-r--r--contrib/ipfilter/tools/Makefile104
-rw-r--r--contrib/ipfilter/tools/ipf.c601
-rw-r--r--contrib/ipfilter/tools/ipf_y.y2749
-rw-r--r--contrib/ipfilter/tools/ipfcomp.c1374
-rw-r--r--contrib/ipfilter/tools/ipfs.c881
-rw-r--r--contrib/ipfilter/tools/ipfstat.c2375
-rw-r--r--contrib/ipfilter/tools/ipfsyncd.c671
-rw-r--r--contrib/ipfilter/tools/ipftest.c874
-rw-r--r--contrib/ipfilter/tools/ipmon.c1910
-rw-r--r--contrib/ipfilter/tools/ipmon_y.y1052
-rw-r--r--contrib/ipfilter/tools/ipnat.c855
-rw-r--r--contrib/ipfilter/tools/ipnat_y.y1782
-rw-r--r--contrib/ipfilter/tools/ippool.c1073
-rw-r--r--contrib/ipfilter/tools/ippool_y.y818
-rw-r--r--contrib/ipfilter/tools/ipscan_y.y572
-rw-r--r--contrib/ipfilter/tools/ipsyncm.c256
-rw-r--r--contrib/ipfilter/tools/ipsyncs.c274
-rw-r--r--contrib/ipfilter/tools/lex_var.h60
-rw-r--r--contrib/ipfilter/tools/lexer.c735
-rw-r--r--contrib/ipfilter/tools/lexer.h38
-rw-r--r--tests/sys/kern/execve/Makefile39
-rw-r--r--tests/sys/kern/execve/bad_interp_len4
-rw-r--r--tests/sys/kern/execve/dev_null_script4
-rw-r--r--tests/sys/kern/execve/execve_helper.c54
-rw-r--r--tests/sys/kern/execve/execve_test.sh115
-rw-r--r--tests/sys/kern/execve/good_aout.c45
-rw-r--r--tests/sys/kern/execve/good_script4
-rw-r--r--tests/sys/kern/execve/non_exist_shell4
-rw-r--r--tests/sys/kern/execve/script_arg4
-rw-r--r--tests/sys/kern/execve/script_arg_nospace4
-rw-r--r--tests/sys/kqueue/Makefile26
-rw-r--r--tests/sys/kqueue/common.h78
-rw-r--r--tests/sys/kqueue/config.h13
-rwxr-xr-xtests/sys/kqueue/kqueue_test.sh17
-rw-r--r--tests/sys/kqueue/main.c284
-rw-r--r--tests/sys/kqueue/proc.c255
-rw-r--r--tests/sys/kqueue/read.c324
-rw-r--r--tests/sys/kqueue/signal.c199
-rw-r--r--tests/sys/kqueue/timer.c178
-rw-r--r--tests/sys/kqueue/user.c129
-rw-r--r--tests/sys/kqueue/vnode.c266
340 files changed, 72805 insertions, 0 deletions
diff --git a/contrib/ipfilter/BNF b/contrib/ipfilter/BNF
new file mode 100644
index 0000000..ef35d25
--- /dev/null
+++ b/contrib/ipfilter/BNF
@@ -0,0 +1,81 @@
+filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ]
+ [ proto ] [ ip ] [ group ] [ tag ] [ pps ] .
+
+insert = "@" decnumber .
+action = block | "pass" | log | "count" | auth | call .
+in-out = "in" | "out" .
+options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] .
+tos = "tos" decnumber | "tos" hexnumber .
+ttl = "ttl" decnumber .
+proto = "proto" protocol .
+ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
+group = [ "head" decnumber ] [ "group" decnumber ] .
+pps = "pps" decnumber .
+
+onif = "on" interface-name [ "out-via" interface-name ] .
+block = "block" [ return-icmp[return-code] | "return-rst" ] .
+auth = "auth" | "preauth" .
+log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] .
+tag = "tag" tagid .
+call = "call" [ "now" ] function-name "/" decnumber.
+dup = "dup-to" interface-name[":"ipaddr] .
+froute = "fastroute" | "to" interface-name .
+replyto = "reply-to" interface-name [ ":" ipaddr ] .
+protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber .
+srcdst = "all" | fromto .
+fromto = "from" object "to" object .
+
+return-icmp = "return-icmp" | "return-icmp-as-dest" .
+loglevel = facility"."priority | priority .
+object = addr [ port-comp | port-range ] .
+addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] .
+port-comp = "port" compare port-num .
+port-range = "port" port-num range port-num .
+flags = "flags" flag { flag } [ "/" flag { flag } ] .
+with = "with" | "and" .
+icmp = "icmp-type" icmp-type [ "code" decnumber ] .
+return-code = "("icmp-code")" .
+keep = "keep" "state" [ "limit" number ] | "keep" "frags" .
+
+nummask = host-name [ "/" decnumber ] .
+host-name = ipaddr | hostname | "any" .
+ipaddr = host-num "." host-num "." host-num "." host-num .
+host-num = digit [ digit [ digit ] ] .
+port-num = service-name | decnumber .
+
+withopt = [ "not" | "no" ] opttype [ [ "," ] withopt ] .
+opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" |
+ "mbcast" | "opt" ipopts .
+optname = ipopts [ "," optname ] .
+ipopts = optlist | "sec-class" [ secname ] .
+secname = seclvl [ "," secname ] .
+seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" |
+ "reserv-4" | "secret" | "topsecret" .
+icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" |
+ "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" |
+ "inforep" | "maskreq" | "maskrep" | "routerad" |
+ "routersol" | decnumber .
+icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" |
+ "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
+ "net-prohib" | "host-prohib" | "net-tos" | "host-tos" |
+ "filter-prohib" | "host-preced" | "cutoff-preced" .
+optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" |
+ "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" |
+ "visa" | "imitd" | "eip" | "finn" .
+facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" |
+ "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" |
+ "audit" | "logalert" | "local0" | "local1" | "local2" |
+ "local3" | "local4" | "local5" | "local6" | "local7" .
+priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" |
+ "info" | "debug" .
+
+hexnumber = "0" "x" hexstring .
+hexstring = hexdigit [ hexstring ] .
+decnumber = digit [ decnumber ] .
+
+compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" |
+ "le" | "ge" .
+range = "<>" | "><" .
+hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" .
+digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
+flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" .
diff --git a/contrib/ipfilter/BugReport b/contrib/ipfilter/BugReport
new file mode 100644
index 0000000..6994831
--- /dev/null
+++ b/contrib/ipfilter/BugReport
@@ -0,0 +1,12 @@
+Please submit this information at SourceForge using this URL:
+http://sourceforge.net/tracker/?func=add&group_id=169098&atid=849053
+
+Please also send an email to darrenr@reed.wattle.id.au.
+
+Some information that I generally find important:
+--------------------------
+* IP Filter Version
+* Operating System and its Version
+* Configuration: (LKM or compiled-into-kernel)
+* Description of problem
+* How to repeat
diff --git a/contrib/ipfilter/HISTORY b/contrib/ipfilter/HISTORY
new file mode 100644
index 0000000..8b67de7
--- /dev/null
+++ b/contrib/ipfilter/HISTORY
@@ -0,0 +1,1830 @@
+#
+# 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 the Coombs Computing Unit at the ANU for their continued support
+# in providing a very available location for the IP Filter home page and
+# distribution center.
+#
+# Thanks also to all those who have contributed patches and other code,
+# and especially those who have found the time to port IP Filter to new
+# platforms.
+#
+5.1.2 - RELEASED - 22 Jul 2012
+
+3546266 macro letters could be more consistent
+3546265 not all of the state statistics are displayed
+3546261 scripts for updating BSD environment out of date
+3546260 compiler warnings about non-integer array subscript
+3546259 asserting numdereflists == 0 is not correct
+3546258 expression matching does not see IPF_EXP_END
+3544317 ipnat/ipfstat are not using ipfexp_t
+3545324 proxy checksum calculation is not hardware aware
+3545321 FTP sequence number adjustment incorrectly applied
+3545320 EPSV is not recognised
+3545319 move nat rule creation to ip_proxy.c
+3545317 better feedback of checksum requirements for proxies
+3545314 ftp proxy levels do not make sense
+3545312 EPRT is not supported by ftp proxy
+3544318 ipnat.conf parsing ignores LHS address family
+3545309 non-ipv6 safe proxies do not fail with ipv6
+3545323 NAT updates the source port twice
+3545322 ipv6 nat rules cannot start proxies
+3544314 bucket copyout tries to copy too much data
+3544313 remove nat encap feature
+3546248 compat rule pointer type mismatch
+3546247 UDP hardware checksum offload not recognised
+3545311 ifp_ifaddr does not find the first set address
+3545310 ipmon needs ipl_sec on 64bit boundary
+3545326 reference count changes made without lock
+3544315 stateful matching does not use ipfexp_t
+3543493 tokens are not flushed when disabled
+3543487 NAT rules do not always release lookup objects
+3543491 function comments in ip_state.c are old
+3543404 ipnat.conf parsing uses family/ip version badly
+3543403 incorrect line number printed in ipnat parsing errors
+3543402 Not all NAT statistics are printed
+3542979 NAT session list management is too simple
+3542978 ipv4 and ipv6 nat insert have common hash insertion
+3542977 ipnat_t refence tracking incomplete
+3542975 proxies must use ipnat_t separately
+3542980 printing ipv6 expressions is wrong
+3542983 ippool cannot handle more than one ipv6 address
+3543018 mask array shifted incorrectly.
+3542974 reason for dropping packet is lost
+3542982 line numbers not recorded/displayed correctly by ipf
+3542981 exclamation mark cuases trouble with pools
+3541655 test suite checksums incorrect
+3541653 display proxy fail status correctly
+3540993 IP header offset excluded in pullup calculations
+3540994 pullupmsg does not work as required
+3540992 pointer to ipv6 frag header not updated on pullup
+3541645 netmask management adds /32 for /0
+3541637 ipnat parser does not zero port fields for non-port protocol
+3541635 pool names cannot by numbers
+3540995 IPv6 fragment tracking does not always work
+3540996 printing of nextip for ipv6 nat rules is wrong
+3540999 ipnat.conf parsing has trouble with icmpidmap for ipv6
+3540825 whois output parsing error for ipv6
+3540814 ipfd_lock serves no purpose
+3540810 lookup objects need tail pointers
+3540809 refactor hash table lookups for nat
+3540819 radix tree does not work with ipv6
+3540820 mutex emulation should be logged
+3540828 ipfstat filtering with -m fails tests
+3536480 ippool could be more like the others
+3536477 pool printing not uniform
+3536483 flushing empty destination lists causes panic
+3536481 more use of bzero after KMALLOC required
+3536479 ipnat.conf line numbers not stored
+3536484 Makefile missing dependency for ippool
+3536199 TFTP proxy requires something extra
+3536198 ICMP checksum out by one
+3536203 ipnat does not return an error
+3536201 ipf.conf parsing too address friendly
+3536200 printing of bytes/packets not indented
+3497941 ipv4 multicast detection incorrect on little endian
+3535361 to interfaces printed out of order
+3535363 ipf parser is inconsistent
+3532306 deleting ipnat rules does not work
+3532054 new error required for ipf_rx_create
+3532053 icmp6 checksums wrong
+3532052 icmpv6 state check with incorrect length
+3531871 checksum verification wants too many icmp6 bytes
+3531870 ipnat.conf parsing needs to support inet6
+3532048 error in ipf group parsing
+3531868 ICMPV6 checksum not validated
+3531893 ipftest exits without error for bad input
+3531890 whois pool parsing builds bad structures
+3531891 icmpv6 text parsing ignorant of icmp types
+3531653 rewrite with icmp does not work
+3530563 NAT operations fail with EPERM
+3530544 first pass at gcc -Wextra cleanup
+3530540 lookup create functions do not set error properly
+3530539 ipf_main_soft_destroy doesn't need 2nd arg
+3530541 reorder structure for better packing
+3530543 ipnat purge needs documentation
+3530515 BSD upgrade script required
+3528029 ipmon bad-mutex panic
+3530247 loading address pools light on input validation
+3530255 radix tree delete uses wrong lookup
+3530254 radix tree allocation support wrong
+3530264 ipmon prints qd for some 64bit numbers
+3530260 decapsulate rules not printed correctly.
+3530266 ipfstat -v/-d flags confused
+2939220 why a packet is blocked is not discernable
+2939218 output interface not recorded
+2941850 use of destination lists with to/dup-to beneficial
+3457747 build errors introduced with radix change
+3535360 timeout groups leak
+3535359 memory leak with tokens
+3535358 listing rules in groups requires tracking groups
+3535357 rule head removal is problematic
+3530259 not all ioctl error checked wth SIOCIPFINTERROR
+3530258 error routine that uses fd required
+3530253 inadequate function comment blocks
+3530249 walking lookup tables leaks memory
+3530241 extra lock padding required for freebsd
+3529901 ipf returns 0 when rules fail to load
+3529491 checksum validation could be better
+3529486 tcp checksum wrong for ipv6
+3533779 ipv6 nat rules missing inet6 keyword
+3532693 ipnat.conf rejects some ipv6 addresses
+3532691 ipv4 should not be forced for icmp
+3532689 ipv6 nat rules do not print inet6
+3532688 ipv6 address always printed with "to <if>"
+3532687 with v6hdrs not supported like with ipopts
+3532686 ipf expressions do not work with ipv6
+3540825 whois output parsing error for ipv6
+3540818 NAT for certain IPv6 ICMP packets should not be allowed
+3540815 memory leak with destination lists
+3540814 ipfd_lock serves no purpose
+3540810 lookup objects need tail pointers
+3540809 refactor hash table lookups for nat
+3540808 completed tokens do not stop iteration
+3530492 address hash table name not used
+3528029 ipmon bad-mutex panic
+3530256 hook memory leaked
+3530271 pools parsing produces badly formed address structures
+3488061 cleanup for illumos build
+3484434 SIOCIPFINTERROR must work for all devices
+3484067 mandoc -Tlint warnings to be fixed
+3483343 compile warning in ipfcomp.c
+3482893 building without IPFILTER_LOG fails
+3482765 building netbsd kernel without inet6 fails
+3482116 ipf_check frees packet from ipftest
+3481663 does not compile on solaris 11
+
+5.1.1 - RELEASED - 9 May 2012
+
+3481322 ip_fil_compat.c needs a cleanup
+3481211 add user errors to dtrace
+3481152 compatibility for 4.1 needs more work
+3481153 PRIu64 problems on FreeBSD
+3481155 ipnat listing incorrect
+3480543 change leads to compat problems
+3480538 compiler errors from earlier patch
+3480537 ipf_instance_destroy is incomplete
+3480536 _fini order leads to panic
+3479991 compiler warnings about size mismatches
+3479974 copyright dates are wrong (fix)
+3479464 add support for leaks testing
+3479457 %qu is not the prefered way
+3479451 iterators leak memory
+3479453 nat rules with pools leak
+3479454 memory leak in hostmap table
+3479461 load_hash uses memory after free
+3479462 printpool leaks memory
+3479452 missing FREE_MB_T to freembt leaks
+3479450 ipfdetach is called when detached
+3479448 group mapping rules memory leak
+3479455 memory leak from tuning
+3479458 ipf must be running in global zone
+3479460 driver replace is wrong
+3479459 radix tree tries to free null pointer
+3479463 rwlock emulation does not free memory
+3479465 parser leaks memory
+3475959 hardware checksum not correctly used
+3475426 ip pseudo checksum wrong
+3473566 radix tree does not delete dups right
+3472987 compile is not clean
+3472337 not everything is zero'd
+3472344 interface setup needs to be after insert
+3472340 wildcard counter drops twice
+3472338 change fastroute interface
+3472335 kernel lock defines not placed correctly
+3472324 ICMP INFOREQ/REPLY not handled
+3472330 multicast packets tagged by address
+3472333 ipf_deliverlocal called incorrectly
+3472345 mutex debug could be more granular
+3472761 building i19 regression is flawed
+3456457 use of bsd tree.h needs to be removed
+3460522 code cleanup required for building on freebsd
+3459734 trade some cpu for memory
+3457747 build errors introduced with radix change
+3457804 build errors from removal of pcap-int,h
+3440163 rewrite radix tree
+3428004 snoop, tcpdump, etherfind readers are unused
+3439495 ipf_rand_push never called (fix brackets)
+3437732 getnattype does not need to use ipnat_t (fix variable name)
+3437696 fr_cksum is a nightmare
+3439061 ipf_send_ip doesn't need 3rd arg
+3439059 ipid needs to be file local
+3437740 complete buildout of fnew
+3438575 add dtrace probes to block events
+3438347 comment blocks missing softc
+3437687 description of ipf_makefrip wrong
+3438340 more stats as dtrace probes
+3438316 free on nat structure uses fixed size
+3437745 nat iterator using the wrong size
+3437710 fail checksum verification if packet is short
+3437696 fr_cksum is a nightmare
+3437732 getnattype does not need to use ipnat_t
+3437735 rename ipf_allocmbt to allocmbt
+3437697 fr_family to version assignment is wrong
+3437746 ap_session_t has unused fields
+3437747 move softc structure to .h file (ip_state.c)
+3437704 there is no DTRACE_PROBE5
+3437748 wrong interface in qpktinfo_t
+3437729 create function to hexdump mb_t
+3438273 msgdsize should be easier to read
+3437683 object direction not set for 32bit
+3433767 calling ip_cksum could be easier
+3433764 left over locking
+3428015 printing proxy data size is useless
+3428013 add M_ADJ to hide adjmsg/m_adj
+3428012 interface name is not always returned correctly
+3428002 ip_ttl is too low
+3427997 ipft readers do not set buffer length
+3426558 resistence is futile
+3424495 various copy-paste errors
+1826936 shall we allow ipf to be as dumb as its admin
+3424477 specfuncs needs to go
+3424484 missing fr_checkv6sum
+3424478 one entry at a time
+2998760 auth rules do not mix well with to/dup-to/fastroute
+3424195 add ctfmerge to sunos5 makefile
+3424132 some dtrace probes to start with
+3423812 makefile needs ip_frag.h for some files
+3423817 reference count useful in verbose output
+3423800 walking lists does not drop reference
+3423805 fragmentation stats not reported correclty
+3423808 ip addresses reportied incorrectly with ipfstat -f
+3423821 track packets and bytes for fragmentation
+3423803 attempt to double free rule
+3423805 fragmentation stats not reported correctly
+3422712 system panic with ipfstat -f
+3422619 pullup counter bumped for every packet
+3422608 dummy rtentry required to build
+3422018 frflush next to ipf_fini_all is redundant
+3422012 instance cleanup is not clean
+3421845 instance name not set
+3005622 ip_fil5.1.0 does not load on Solaris 10 U8
+2976332 stateful filtering is incompatible with ipv4 options
+3387509 ipftest needs help construction ip packets with options
+2998746 passp can never be null
+3064034 mbuf clobbering problem with ipv6
+3105725 ipnat divide by zero panic
+2998750 ipf_htent_insert can leak memory
+3064034 mbuf clobbering problem with ipv6
+3105725 ipnat divie by zero panic
+
+5.1 - RELEASED - 9 May 2010
+
+* See WhatsNew50.txt
+
+4.1 - RELEASED - 12 February 2004
+
+4.0-BETA1 20 August 2003
+
+support 0/32 and 0/0 on the RHS in redirect rules
+
+where LHS and RHS netmasks are the same size for redirect, do 1:1 mapping
+for bimap rules.
+
+allow NAT rule to match 'all' interfaces with * as interface name
+
+do mapping of ICMP sequence id#'s in pings
+
+allow default age for NAT entries to be set per NAT rule
+
+provide round robin selection of destination addresses for redirect
+
+ipmon can load a configuration file with instructions on actions
+to take when a matching log entry is received
+
+now requires pfil to work on Solaris & HP-UX
+
+supports mapping outbound connections to a specific address/port
+
+support toggling of logging per ipfilter 'device'
+
+use queues to expire data rather than lists
+
+add MSN RPC proxy
+
+add IRC proxy
+
+support rules with dynamic ip addresses
+
+add ability to define a pool of addresses & networks which can then
+be placed in a single rule
+
+support passing entire packet back to user program for authentication
+
+support master/slave for state information sharing
+
+reorganise generic code into a lib directory and make libipf.a
+
+user programs enforce version matching with the kernel
+
+supports window scaling if seen at TCP session setup
+
+generates C code from filter rules to compile in or load as native
+machine code.
+
+supports loading rules comprised of BPF bytecode statements
+
+HP-UX 11 port completed
+
+and packets-per-second filtering
+
+add numerical tags to rules for filtering and display in ipmon output
+
+3.4.4 23/05/2000 - Released
+
+don't add TCP state if it is an RST packet and (attempt) to send out
+RST/ICMP packets in a manner that bypasses IP Filter.
+
+add patch to work with 4.0_STABLE delayed checksums
+
+3.4.3 20/05/2000 - Released
+
+fix ipmon -F
+
+don't truncate IPv6 packets on Solaris
+
+fix keep state for ICMP ECHO
+
+add some NAT stats and use def_nat_age rather than DEF_NAT_AGE
+
+don't make ftp proxy drop packets
+
+use MCLISREFERENCED() in tandem with M_EXT to check if IP fields need to be
+swapped back.
+
+fix up RST generation for non-Solaris
+
+get "short" flag right for IPv6
+
+3.4.2 - 10/5/2000 - Released
+
+Fix bug in dealing with "hlen == 1 and opt > 1" - Itojun
+
+ignore previous NAT mappings for 0/0 and 0/32 rules
+
+bring in a completely new ftp proxy
+
+allow NAT to cause packets to be dropped.
+
+add NetBSD callout support for 1.4-current
+
+3.4.1 - 30/4/2000 - Released
+
+add ratoui() and fix parsing of group numbers to allow 0 - UINT_MAX
+
+don't include opt_inet6.h for FreeBSD if KLD_MODULE is defined
+
+Solaris must use copyin() for all types of ioctl() args
+
+fix up screen/tty when leaving "top mode" of ipfstat
+
+linked list for maptable not setup correctly in nat_hostmap()
+
+check for maptable rather than nat_table[1] to see if malloc for maptable
+succeeded in nat_init
+
+fix handling of map NAT rules with "from/to" host specs
+
+fix printout out of source address when using "from/to" with map rules
+
+convert ip_len back to network byte order, not plen, for solaris as ip_len
+may have been changed by NAT and plen won't reflect this
+
+3.4 - 27/4/2000 - Released
+
+source address spoofing can be turned on (fr_chksrc) without using
+filter rules
+
+group numbers are now 32bits in size, up from 16bits
+
+IPv6 filtering available
+
+add frank volf's state-top patches
+
+add load splitting and round-robin attribute to redirect rules
+
+FreeBSD-4.0 support (including KLD)
+
+add top-style operation mode for ipfstat (-t)
+
+add save/restore of IP Filter state/NAT information (ipfs)
+
+further ftp proxy security checks
+
+support for adding and removing proxies at runtime
+
+3.3.13 26/04/2000 - Released
+
+Fix parsing of "range" with "portmap"
+
+Relax checking of ftp replies, slightly.
+
+Fix NAT timeouts for ICMP packets
+
+SunOS4 patches for ICMP redirects from Jurgen Keil (jk@tools.de)
+
+3.3.12 16/03/2000 - Released
+
+tighten up ftp proxy behaviour. sigh. yuck. hate.
+
+fix bug in range check for NAT where the last IP# was not used.
+
+fix problem with icmp codes > 127 in filter rules caused bad things to
+happen and in particular, where #18 caused the rule to be printed
+erroneously.
+
+fix bug with the spl level not being reset when returning EIO from
+iplioctl due to ipfilter not being initialized yet.
+
+3.3.11 04/03/2000 - Released
+
+make "or-block" work with lines that start with "log"
+
+fix up parsing and printing of rules with syslog levels in them
+
+fix from Cy Schubert for calling of apr_fini only if non-null
+
+
+3.3.10 24/02/2000 - Released
+
+* fix back from guido for state tracking interfaces
+
+* update for NetBSD pfil interface changes
+
+* if attaching fails and we can abort, then cleanup when doing so.
+
+julian@computer.org:
+* solaris.c (fr_precheck): After calling freemsg on mt, set it point to *mp.
+* ipf.c (packetlogon): use flag to store the return value from get_flags.
+* ipmon.c (init_tabs): General cleanup so we do not have to cast
+ an int s->s_port to u_int port and try to check if the u_int port
+ is less than zero.
+
+3.3.9 15/02/2000 - Released
+
+fix scheduling of bad locking in fr_addstate() used when we attach onto
+a filter rule.
+
+fix up ip_statesync() with storing interface names in ipstate_t
+
+fix fr_running for LKM's - Eugene Polovnikov
+
+junk using pullupmsg() for solaris - it's next to useless for what we
+need to do here anyway - and implement what we require.
+
+don't call fr_delstate() in fr_checkstate(), when compiled for a user
+program, early but when we're finished with it (got fr & pass)
+
+ipnat(5) fix from Guido
+
+on solaris2, copy message and use that with filter if there is another
+copy if it being used (db_ref > 1). bad for performance, but better
+than causing a crash.
+
+patch for solaris8-fcs compile from Casper Dik
+
+3.3.8 01/02/2000 - Released
+
+fix state handling of SYN packets.
+
+add parsing recognition of extra icmp types/codes and fix handling of
+icmp time stamps and mask requests - Frank volf
+
+3.3.7 25/01/2000 - Released
+
+sync on state information as well as NAT information when required
+
+record nat protocol in all nat log records
+
+don't reuse the IP# from an active NAT session if the IP# in the rule
+has changed dynamically.
+
+lookup the protocol for NAT log information in ipmon and pass that to
+portname.
+
+fix the bug with changing the outbound interface of a packet where it
+would lead to a panic.
+
+use fr_running instead of ipl_inited. (sysctl name change on freebsd)
+
+return EIO if someone attempts an ioctl on state/nat if ipfilter is not
+enabled.
+
+fix rule insertion bug
+
+make state flushing clean anything that's not fully established (4/4)
+
+call fr_state_flush() after we've released ipf_state so we don't generate
+a recursive mutex acquisition panic
+
+fix parsing of icmp code after return-icmp/return-icmp-as-dest and add
+some patches to enhance parsing strength
+
+3.3.6 28/12/1999 - Released
+
+add in missing rwlock release in fr_checkicmpmatchingstate() and fix check
+for ICMP_ECHO to only be for packet, not state entry which we don't have yet.
+
+handle SIOCIPFFB in nat_ioctl() and fr_state_ioctl()
+
+fix size of friostat for SunOS4
+
+fix bug in running off the end of a buffer in real audio proxy
+
+3.3.5 11/12/1999 - Released
+
+fix parsing of "log level" and printing it back out too
+
+<net/if_types.h> is only present on Solaris2.6/7/8
+
+use send_icmp_err rather than icmp_error to send back a frag-needed error
+when doing PMTU
+
+do not use -b with add_drv on Solaris unless $BASEDIR is set.
+
+fix problem where source address in icmp replies is reversed
+
+fix yet another problem with real audio.
+
+3.3.4 4/12/1999 - Released
+
+fix up the real audio proxy to properly setup state information and NAT
+entries, thanks to Laine Stump for testing/advice/fixes.
+
+fix ipfr_fastroute to set dst->sin_addr (Sean Farley - appears to prevent
+FreeBSD 3.3 from panic'ing) as this had been removed in prior hacks to this
+routine.
+
+fix kinstall for BSDI
+
+support ICMP errors being allowed through for ICMP packets going out with
+keep state enabled
+
+support hardware checksumming (gigabit ethernet cards) on Solaris thanks to
+Tel.Net Media for providing hardware for testing.
+
+patched from Frank Volf for ipmon (ICMP & fragmented packets) and allowing
+ICMP responses to ICMP packets in the keep state table.
+
+add in patches for hardware checksumming under solaris
+
+Solaris install scripts now use $BASEDIR as appropriate.
+
+add Solaris8 support
+
+fix "ipf -y" on solaris so that it rescans rules also for changes in
+interface pointers
+
+let ipmon become a daemon with -D if it is using syslog
+
+fix parsing of return-icmp-as-dest(foo)
+
+add reference to ipfstat -g to ipfstat.8
+
+ipf_mutex needs to be declared for irix in ip_fil.c
+
+3.3.3 22/10/1999 - Released
+
+add -g command line option to ipfstat to show groups still define.
+
+fix problem with fragment table not recording rule pointer when called
+from state functions (fin_fr not set).
+
+fixup fastroute problems with keep state rules.
+
+load rules into inactive set first, so we don't disable things like NIS
+lookups half way through processing - found by Kevin Littlejohn
+
+fix handling of unaligned ip pointer for solaris
+
+patch for fr_newauth from Rudi Sluijtman
+
+fixed htons() bug in fr_tcpsum() where ip_p wasn't cast to u_short
+
+3.3.2 23/09/1999 - Released
+
+patches from Scott Presnell to fix rcmd proxy
+
+patches from Greg to fix Solaris detachment of interfaces
+
+add openbsd compatibility fixes
+
+fix free'ing already freed memory in ipfr_slowtimer()
+
+fix for deferencing invalid memory in cleaning up after a device disappears
+
+3.3.1 14/8/1999 - Released
+
+remove include file sys/user.h for irix
+
+prevent people from running buildsunos directly
+
+fix up some problems with the saving of rule pointers so that NAT saves
+that information in case it should need to call fr_addstate() from a proxy.
+
+fix up scanning for the end of FTP messages
+
+don't remove /etc/opt/ipf in postremove
+
+attempt to prevent people running buildsolaris script without doing a
+"make solaris"
+
+fix timeout losing on freebsd3
+
+3.3 7/8/1999 - Released
+
+NAT: information (rules, mappings) are stored in hash tables; setup some
+basic NAT regression testing.
+
+display version name of installed kernel code when initializing.
+
+add -V command line option to ipf, showing version (program and kernel
+module) as well as the run-status of the kernel code.
+
+fix problem with "log" rules actually affecting result of filtering.
+
+automatically use SUNWspro if available and on a 64bit Solaris system for
+compiling.
+
+add kernel proxies for rcmd(3) and RealAudio (PNA)
+
+use timeout/untimeout on SunOS4/BSD platforms too rather than hijacking
+ip_slowtimo
+
+fix IP headers generated through parsing of text information
+
+fix NAT rules to be in the correct order again.
+
+make keep-state work with to/fastroute keywords and enforce usage of those
+interfaces.
+
+update keep-state code with new algorithm from Guido
+
+add FreeBSD-3 support
+
+add return-icmp-as-dest option to retrun an ICMP packet using the original
+destination as the source rather than a local IP address
+
+add "level [facility.]<priority>" option to filter language
+
+add changes from Guido to state code.
+
+add code to return EPERM if the device is opened for writing and we're
+in securelevel 2 or greater.
+
+authentication code patches from Guido
+
+fix real audio proxy
+
+fix ipmon rule printing of interfaces and add IN/OUT to the end of ipmon
+log output.
+
+fix bimap rules with hash tables
+
+update addresses used in NAT mappings for 0/32 rules for any protocol but TCP
+if it changes on the interface - check every ip_natexpire()
+
+add redirect regression test
+
+count buckets used in the state hash table.
+
+fix sending of RST's with return-rst to use the ack number provided in
+the packet being replied to in addition to the sequence number.
+
+fix to compile as a 64bit application on solaris7-64bit
+
+add NAT IP mapping to ranges of IP addresses that aren't CIDR specified
+
+fix calculation of in_space parameter for NAT
+
+fix `wrapping' when incrementing the next ip address for use in NAT
+
+fix free'ing of kernel memory in ip_natunload on solaris
+
+fix -l/-U command line options from interfering with each other
+
+fix fastroute under solaris2 and cleanup compilation for solaris7
+
+add install scripts and compile cleanly on BSD/OS 4.0
+
+safely open files in /tmp for writing device output when testing.
+
+fix uninitialized pointer bug in NAT
+
+fix SIOCZRLST (zero list rule stats) bug with groups
+
+change some usage of u_short to u_int in function calling
+
+fix compilation for Solaris7 (SUNWspro)
+
+change solaris makefiles to build for either sparc or i386 rather than
+per-cpu (sun4u, etc).
+
+fixed bug in ipllog
+
+add patches from George Michaelson for FreeBSD 3.0
+
+add patch from Guido to provide ICMP checking for known state in the same
+manner as is done for NAT.
+
+enable FTP PASV proxying and enable wildcarding in NAT/state code for ports
+for better PORT/PASV support with FTP.
+
+bring into main tree static nat features: map-block and "auto" portmapping.
+
+add in source host filtering for redirects (alan jones)
+
+3.2.10 22/11/98 - Released
+
+3.2.10beta9 17/11/98 - Released
+
+fix fr_tcpsum problems in handling mbufs with an odd number of bytes
+and/or split across an mbuf boundary
+
+fix NAT list entry comparisons and allow multiple entries for the same
+proxy (but on different ports).
+
+don't create duplicate NAT entries for repeated PORT commands.
+
+3.2.10beta8 14/11/98 - Released
+
+always exit an rwlock before expecting to enter it again on solaris
+
+fix loop in nat_new for pre-existing nat
+
+don't setup state for an ftp connection if creating nat fails.
+
+3.2.10beta7 05/11/98 - Released
+
+set fake window in ipft_tx.c to ensure code passes tests.
+
+cleaned up/enhanced ipnat -l/ipnat -lv output
+
+fixed NAT handling of non-TCP/UDP packets, esp. for ICMP errors returned.
+
+Solaris recusive mutex on icmp-error/tcp-reset - requires rwlock's rather
+than mutexes.
+
+3.2.10beta6 03/11/98 - Released
+
+fix mixed use of krwlock_t and kmutex_t on Solaris2
+
+fix FTP proxy back up, splitting pasv code out of port code.
+
+3.2.10beta5 02/11/98 - Released
+
+fixed port translation in ICMP reply handling
+
+3.2.10beta4 01/11/98 - Released
+
+increase useful statistic collection on solaris
+
+filter DL_UNITDATA_REQ as well as DL_UNITDATA_IND on solaris
+
+disable PASV reply translation for now
+
+fail with an error if we try to load a NAT rule with a non-existant
+ proxy name - Guido
+
+fix portmap usage with 0/0 and 0/32 map rules
+
+remove ap_unload/ap_expire - automatically done when NAT is cleaned up
+
+print "STATE:CLOSED" from ipmon if the connection progresses past established
+ rather than "STATE:EXPIRED"
+
+3.2.10beta3 26/10/98 - Released
+
+fixed traceroute/nat problem
+
+rewrote nat/proxy interface
+
+ipnat now lists associated proxy sessions for each NAT where applicable
+
+3.2.10beta2 13/10/98 - Released
+
+use KRWLOCK_T in place of krwlock_t for solaris as well as irix
+
+disable use of read-write lock acquisition by default
+
+add in mb_t for linux, non-kernel
+
+some changes to progress compilation on linux with glibc
+
+change PASV as well as PORT when passed through kernel ftp proxy.
+
+don't allow window to become 0 in tcp state code
+
+make ipmon compile cleaner
+
+irix patches
+
+3.2.10beta 11/09/98 - Released
+
+stop fr_tcpsum() thinking it has run out of data when it hasn't.
+
+stop solaris panics due to fin_dp being something wild.
+
+revisit usage of ATOMIC_*()
+
+log closing state of TCP connection in "keep state"
+
+fix fake-arp table code for ipsend.
+
+ipmon now writes pid to a file.
+
+fix "ipmon -a" to actually activate all logging devices.
+
+add patches for BSDOS4.
+
+perl scripts for log analysis donated.
+
+3.2.9 22/06/98 - Released
+
+fix byte order for ICMP packets generated on Solaris
+
+fix some locking problems.
+
+fix malloc bug in NAT (introduced in 3.2.8).
+
+patch from guido for state connections that get fragmented
+
+3.2.8 08/06/98 - Released
+
+use readers/writers locks in Solaris2 in place of some mutexes.
+
+Solaris2 installation enhancements - Martin Forssen (maf@carlstedt.se)
+
+3.2.7 24/05/98 - Released
+
+u_long -> u_32_t conversions
+
+patches from Bernd Ernesti for NetBSD
+
+fixup ipmon to actually handle HUP's.
+
+Linux fixes from Michael H. Warfield (mhw@wittsend.com)
+
+update for keep state patch (not security related) - Guido
+
+dumphex() uses stdout rather than log
+
+3.2.6 18/05/98 - Released
+
+fix potential security loop hole in keep state code.
+
+update examples.
+
+3.2.5 09/05/98 - Released
+
+BSD/OS 3.1 .o files added for the kernel.
+
+fix sequence # skew vs window size check.
+
+fix minimum ICMP header size check.
+
+remove references to Cybersource.
+
+fix my email address.
+
+remove ntohl in ipnat - Thomas Tornblom
+
+3.2.4 09/04/98 - Released
+
+add script to make devices for /dev on BSD boxes
+
+fixup building into the kernel for FreeBSD 2.2.5
+
+add -D command line option to ipmon to make it a daemon and SIGHUP causes
+it to close and reopen the logfile
+
+fixup make clean and make package for SunOS5 - Marc Boucher
+
+postinstall keeps adding "minor=ipf ipl" - George Ross <gdmr@dcs.ed.ac.uk>
+
+protected by IP Filter gif - Sergey Solyanik <solik@atom.ru>
+
+3.2.3 10/11/97 - Released
+
+fix some iplang bugs
+
+fix tcp checksum data overrun, sgi #define changes,
+avoid infinite loop when nat'ing to single IP# - Marc Boucher
+
+fixup DEVFS usage for FreeBSD
+
+fix sunos5 "make clean" cleaning up too much
+
+3.2.2 28/11/97 - Released
+
+change packet matching to return actual error, if bad packet, to facilitate
+ECONNRESET for TCP.
+
+allow ip:netmask in grammar too now - Guido
+
+assume IRIX has u_int32_t in sys/types.h (needed for R10000)
+
+rewrite parts of command line options for ipmon
+
+fix TCP urgent packet & offset testing and add LAND attack test for iptest
+
+fix grammar error in yacc grammar for iplang
+
+redirect (rdr) destination port bytes-wapped when it shouldn't be.
+
+general: fr_check now returns error code, such as EHOSTUNREACH or
+ECONNRESET (attempt to make ECONNRESET work for locally outbound
+packets).
+
+linux: enable return-rst, need to filter tcp retransmits which are sent
+ separately from normal packets
+
+memory leak plugged in ip_proxy.c
+
+BSDI compatibility patches from Guido
+
+tcp checksum fix - Marc Boucher
+
+recursive mutex and ioctl param fix - Marc Boucher
+
+3.2.1 12/11/97 - Released
+
+port to BSD/OS 3.0
+
+port to Linux 2.0.31
+
+patches to make "map a/m -> 0/0" work with ftp proxying properly - Marc Boucher
+
+add "ipf -F s" and "ipf -F S" to flush state table entries.
+
+announce if logging is on or off when ip filter initializes.
+
+"ipf -F a" doesn't flush groups properly for Solaris.
+
+3.2 30/10/97 - Released
+
+ipnat doesn't successfully remove proxy mappings with "-rf" -
+Alexander Romanyu
+
+use K&R C function style for solaris kernel code
+
+use m_adj() to decrease packet size in ftp proxy
+
+use mbufchainlen rather than msgdsize,
+IRIX update - Marc Boucher
+
+fix NetBSD modunload bug (pfil_add_hook done twice)
+
+patches for OpenBSD 2.1 - Craig Bevins <craigb@bitcom.net.au>
+
+3.2beta10 24/10/97 - Released
+
+fix fragment table entries allocated for NAT.
+
+fix tcp checksum calculations over mbuf/mblk boundaries
+
+fix panic for blen < 0 in ftp kernel proxy - marc boucher
+
+fix flushing of rules which have been grouped.
+
+3.2beta9 20/10/97 - Released
+
+some nit picking on solaris2 with SUNWspro - Michael Lyle <mrl@rpnet.net>
+
+ftp kernel proxy patches from Marc Boucher
+
+3.2beta8 13/10/97 - Released
+
+add support for passing ICMP errors back through NAT.
+
+IRIX port update - Marc Boucher
+
+calculate correct MIN size of packet to log for UDP - Marc Boucher
+
+need htons(ETHERTYPE_x) on little endian BSD boxes - Dave Huang
+
+copyright header fixups
+
+3.2beta7 23/09/97 - Released
+
+fickup problems introduced by prior merges & changes.
+
+3.2beta6 23/09/97 - Released
+
+patch for spin-reading race condition - Marc Boucher.
+
+IRIX port by Marc Boucher.
+
+compatibility updates for Linux to ipsend
+
+3.2beta5 13/09/97 - Released
+
+patches from Bernd Ernesti for NetBSD integration (mostly prototyping and
+compiler warning things)
+
+ipf -y will resync IP#'s allocated with 0/32 in NAT to match interface if it
+changes.
+
+update manual pages and other documentation updates.
+
+3.2beta4 27/8/97 - Released
+
+enable setting IP and TCP options for iplang/
+
+Solaris2 patches from Marc Boucher.
+
+add groups for filter rules.
+
+3.2beta3 21/8/97 - Released
+
+patches for Solaris2 (interface panic solution ?): fix FIONREAD and
+replacing q_qinfo points - Marc Boucher <marc@CAM.ORG>
+
+change ipsend/* and ipsd/* copyright notices to be the same as ip filter's
+
+patch for SYN-ACK skew testing fix from Eric V. Smith <EricSmith@windsor.com>
+
+3.2beta2 6/8/97 - Released
+
+make it load on Solaris 2.3
+
+rewrote logging to remove solaris errors, introduced checking to see if the
+same packet is logged successively.
+
+fix filter cache to work when there are no rules loaded.
+
+add "raw" option to ipresend to send entire ethernet frames.
+
+nat list corruption bug - NetBSD - Klaus Klein
+
+3.2beta1 5/7/97 - Released
+
+patches from Jason Thorpe fixing: UNSIGNED_CHAR lossage, off_t being 64bits
+lossage, and other NetBSD bits.
+
+NetBSD 1.2G update.
+
+fixup fwtk patches and add protocol field for SIOCGNATL.
+
+rdr bugs reported by Alexander Romanyu (alexr@aix.krid.crimea.ua), with
+fixes:
+* rdr matched all packets of a given protocol (ignored ports).
+* severe bug in nat_delete which caused system crash/freeze.
+
+change Makefile so that CC isn't passed on for FreeBSD/NetBSD (will use
+the default CC - cc, not gcc)
+
+3.2alpha9 16/6/97 - Released
+
+added "skip" keyword.
+
+implement preauthentication of packets, as outlined by Guido.
+
+Make it compile as cleanly as possible with -Wall & general code cleanup
+
+getopt returns int, not char. Bernd Ernesti
+
+3.2alpha8 13/6/97 - Released
+
+code added to support "auth" rules which require a user program to allow them
+through. First revision and much of the code came from Guido.
+
+hex output from ipmon doesn't goto syslog when recovering from out of sync
+error. Luke Mewburn (lukem@connect.com.au)
+
+fix solaris2.6 lookup of destination ire's.
+
+ipnat doesn't throw away unused bits (after masking), causing it to
+behave incorrectly. Carson Gaspar
+
+NAT code doesn't include inteface name when matching - Alexey Mavrin
+<lha@elco.spb.ru>
+
+replace old SunOS tcpip.h with new tcpip.h (from 4.4BSD) - Jason Thorpe.
+
+update install procedures to include ip_proxy.c
+
+mask out unused bits in NAT/RDR rules.
+
+use a generic type (u_32_t) for 32bit variables, rather than rely on
+u_long being such - Jason Thorpe.
+
+create a local "netinet" directory and include from ~netinet/*" rather than
+just "*" to make keeping the code working on ports easier.
+
+add an m_copydata and m_copyback for SunOS4 (based on 4.4BSD-Lite versions)
+
+documentation updates.
+
+NetBSD update from Jason Thorpe <thorpej@netbsd.org>
+
+allow RST's through with a matching SEQ # and 0 ACK. Guido Van Rooij
+
+ipmon uses excessive amounts of CPU on Solaris2 - Reinhard Bertram
+<Reinhard.Bertram@KOM.th-darmstadt.de>
+
+3.2alpha7 25/5/97 - Released
+
+add strlen for pre-2.2 kernels - Doug Kite <dkite@websgi.icomnet.com>
+
+setup bits and pieces for compiling into a FreeBSD-2.2 kernel.
+
+split up "bsd" targets. Now a separate netbsd/freebsd/bsd target.
+mln_ipl.c has been split up into itself and mlf_ipl.c (for freebsd).
+
+fix (negative) host matching in filtering.
+
+add sysctl interface for some variables when compiled into FreeBSD-2.2 kernels
+or later.
+
+make all the candidates for kernel compiling include "netinet/..." and build
+a subdirectory "netinet" when compiling and symlink all .h files into this.
+
+add install make target to Makefile.ipsend
+
+3.2alpha6 8/5/97 - Released
+
+Add "!" (not) to hostname/ip matching.
+
+Automatically add packet info to the fragment cache if it is a fragment
+and we're translating addreses for.
+
+Automatically add packet info to the fragment cache if it is a fragment
+and we're "keeping state" for the packet.
+
+Solaris2 patches - Anthony Baxter (arb@connect.com.au)
+
+change install procedure for FreeBSD 2.2 to allow building to a kernel
+which is different to the running kernel.
+
+add FIONREAD for Solaris2!
+
+when expiring NAT table entries, if we would set a time to fr_tcpclosed
+(which is 1), make it fr_tcplaskack(20) so that the state tables have a
+chance to clear up.
+
+3.2alpha5
+
+add proxying skeleton support and sample ftp transparent proxy code.
+
+add printfs at startup to tell user what is happening.
+
+add packets & bytes for EXPIRE NAT log records.
+
+fix the "install-bsd" target in the root Makefile. Chris Williams
+<psion@mv.mv.com>
+
+Fixes for FreeBSD 2.2 (and later revs) to prevent panics. Julian Assange.
+
+3.2alpha4 2/4/97 - Released
+
+Some compiler warnings cleaned up.
+
+FreeBSD-2.2 patches for LKM completed.
+
+3.2alpha3 31/3/97 - Released
+
+ipmon changes: -N for reading NAT logfile, -S for reading state logfile.
+-a for reading all. -n now toggles hostname resolution.
+
+Add logging of new state entries and expiration of old state entries.
+count log successes and failures.
+
+Add logging of new NAT entries and expiration of old NAT entries.
+count log successes and failures.
+
+Use u_quad_t for records of bytes & packets where kept
+(IP Accounting: fr_hits, fr_bytes; IP state: is_pkts, is_bytes).
+
+Fixup use of CPU and DCPU in Makefiles.
+
+Fix broken 0/32 NAT mapping. Carl Makin <cmakin@nla.gov.au>
+
+3.2alpha2
+
+Implement mapping to 0/32 as being an alias for automatically using the
+interface's first IP address.
+
+Implement separate minor devices for both NAT and IP state code.
+
+Fully prototype all functions.
+
+Fix Makefile problem due to attempt to fix Sun compiling problems.
+
+3.1.10 23/3/97 - Released
+
+ipfstat -a requires a -i or -o command line option too. Print an error
+when not present rather than attempt to do something.
+
+patch updates for SunOS4 for kernel compiling.
+patch for ipmon -s (flush's syslog file which isn't good). Andrew J. Schorr
+<schorr@ead.dsa.com>
+
+too many people hit their heads hard when compiling code into the kernel
+that doesn't let any packets through. (fil.c - IPF_NOMATCH)
+
+icmp-type parsing doesn't return any errors when it isn't constructed
+correctly. Neil Readwin
+
+Using "-conf" with modload on SunOS4 doesn't work.
+Timothy Demarest <demarest@arraycomm.com>
+
+Need to define ARCH in makefile for SunOS4 building. "make sunos4"
+in INSTALL.SunOS is incorrect. James R Grinter <jrg@blodwen.demon.co.uk>
+[all SunOS targets now run buildsunos]
+
+NAT lookups are still incorrect, matching non-TCP/UDP with TCP/UDP
+information. ArkanoiD <ark@paranoid.convey.ru>
+
+Need to check for __FreeBSD_version being 199511 rather than 199607
+in mln_ipl.c. Eric Feillant <Eric.Feillant@EUnet.fr>
+
+3.1.9 8/3/97 - Released
+
+fixed incorrect lookup of active NAT entries.
+
+patch for ip_deq() wrong for pre 2.1.6 FreeBSD.
+fyeung@fyeung8.netific.com (Francis Yeung)
+
+check for out with return-rst/return-icmp at wrong place - Erkki Ritoniemi
+(erkki@vlsi.fi)
+
+text_readip returns the interface pointer pointing to text on stack -
+Neil Readwin
+
+fix from Pradeep Krishnan for printout rules "with not opt sec".
+
+3.1.8 18/2/97 - Released
+
+Diffs for ip_output.c and ip_input.c updated to fix bug with fastroute and
+compiling warnings about reuse of m0.
+
+prevent use of return-rst and return-icmp with rules blocking packets going
+out, preventing panics in certain situations.
+
+loop forms in frag cache table - Yury Pshenychny <yura@rd.zgik.zaporizhzhe.ua>
+
+should use SPLNET/SPLX around expire routines in NAT/frag/state code.
+
+redeclared malloc in 44arp.c -
+
+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/LICENCE b/contrib/ipfilter/LICENCE
new file mode 100644
index 0000000..f4cc8ee
--- /dev/null
+++ b/contrib/ipfilter/LICENCE
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 1993-2000 by Darren Reed.
+ *
+ * The author accepts no responsibility for the use of this software and
+ * provides it on an ``as is'' basis without express or implied warranty.
+ *
+ * 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..1ac9c94
--- /dev/null
+++ b/contrib/ipfilter/Makefile
@@ -0,0 +1,410 @@
+#
+# Copyright (C) 2012 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.
+#
+# $FreeBSD$
+# Id: Makefile,v 2.76.2.24 2007/09/26 10:04:03 darrenr Exp $
+#
+SHELL=/bin/sh
+BINDEST=/usr/local/bin
+SBINDEST=/sbin
+MANDIR=/usr/local/man
+#To test prototyping
+CC=gcc -Wstrict-prototypes -Wmissing-prototypes -Wunused -Wuninitialized
+#CC=gcc
+#CC=cc -Dconst=
+DEBUG=-g
+# -O
+CFLAGS=-I$$(TOP) -D_BSD_SOURCE
+CPU=`uname -m`
+CPUDIR=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m`
+OBJ=.
+#
+# To enable this to work as a Loadable Kernel Module...
+#
+IPFLKM=-DIPFILTER_LKM
+#
+# To enable logging of blocked/passed packets...
+#
+IPFLOG=-DIPFILTER_LOG
+#
+# To enable loading filter rules compiled to C code...
+#
+#COMPIPF=-DIPFILTER_COMPILED
+#
+# To enable IPFilter compatibility with older CLI utilities
+#
+#COMPATIPF=-DIPFILTER_COMPAT
+#
+# To enable synchronisation between IPFilter hosts
+#
+#SYNC=-DIPFILTER_SYNC
+#
+# The facility you wish to log messages from ipmon to syslogd with.
+#
+LOGFAC=-DLOGFAC=LOG_SECURITY
+#
+# To enable rules to be written with BPF syntax, uncomment these two lines.
+#
+# WARNING: If you're building a commercial product based on IPFilter, using
+# this options *may* infringe at least one patent held by CheckPoint
+# (5,606,668.)
+#
+#IPFBPF=-DIPFILTER_BPF -I/usr/local/include
+#LIBBPF=-L/usr/local/lib -lpcap
+#
+# HP-UX and Solaris require this uncommented for BPF.
+#
+#BPFILTER=bpf_filter.o
+#
+# LINUXKERNEL is the path to the top of your Linux kernel source tree.
+# By default IPFilter looks for /usr/src/linux, but you may have to change
+# it to /usr/src/linux-2.4 or similar.
+#
+LINUXKERNEL=/usr/src/kernels/2.6.29.5-191.fc11.i586
+LINUX=`uname -r | awk -F. ' { printf"%d",$$1;for(i=1;i<NF&&i<3;i++){printf("%02d",$$(i+1));}}'`
+#
+#
+#
+#BUILDROOT=/usr/src/redhat/BUILD/ipfilter
+BUILDROOT=${HOME}/rpmbuild/BUILDROOT/ipfilter-4.1.32-1.i386
+
+#
+# All of the compile-time options are here, used for compiling the userland
+# tools for regression testing. Well, all except for IPFILTER_LKM, of course.
+#
+ALLOPTS=-DIPFILTER_LOG -DIPFILTER_LOOKUP \
+ -DIPFILTER_SYNC -DIPFILTER_CKSUM
+
+#
+# Uncomment the next 3 lines if you want to view the state table a la top(1)
+# (requires that you have installed ncurses).
+#STATETOP_CFLAGS=-DSTATETOP
+#
+# Where to find the ncurses include files (if not in default path),
+#
+#STATETOP_INC=
+#STATETOP_INC=-I/usr/local/include
+#
+# How to link the ncurses library
+#
+#STATETOP_LIB=-lncurses
+#STATETOP_LIB=-L/usr/local/lib -lncurses
+
+#
+# Uncomment this when building IPv6 capability.
+#
+INET6=-DUSE_INET6
+#
+# For packets which don't match any pass rules or any block rules, set either
+# FR_PASS or FR_BLOCK (respectively). It defaults to FR_PASS if left
+# 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=-DIPF_DEFAULT_PASS=FR_PASS
+#
+MFLAGS1='CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2) $(SGIREV) $(INET6)' \
+ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \
+ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \
+ "LIBBPF=$(LIBBPF)" "CPUDIR=$(CPUDIR)" "IPFBPF=$(IPFBPF)" \
+ 'STATETOP_CFLAGS=$(STATETOP_CFLAGS)' "BPFILTER=$(BPFILTER)" \
+ 'STATETOP_INC=$(STATETOP_INC)' 'STATETOP_LIB=$(STATETOP_LIB)' \
+ "BITS=$(BITS)" "OBJ=$(OBJ)" "LOOKUP=$(LOOKUP)" "COMPIPF=$(COMPIPF)" \
+ "COMPATIPF=$(COMPATIPF)" \
+ 'SYNC=$(SYNC)' 'ALLOPTS=$(ALLOPTS)' 'LIBBPF=$(LIBBPF)'
+MFLAGS=$(MFLAGS1) "IPFLKM=$(IPFLKM)"
+MACHASSERT=`/bin/ls -1 /usr/sys/*/mach_assert.h | head -1`
+#
+SHELL=/bin/sh
+#
+########## ########## ########## ########## ########## ########## ##########
+#
+CP=/bin/cp
+RM=/bin/rm
+CHMOD=/bin/chmod
+INSTALL=install
+#
+
+all:
+ @echo "Chose one of the following targets for making IP filter:"
+ @echo ""
+ @echo "solaris - auto-selects SunOS4.1.x/Solaris 2.3-6/Solaris2.4-6x86"
+ @echo "netbsd - compile for NetBSD"
+ @echo "openbsd - compile for OpenBSD"
+ @echo "freebsd20 - compile for FreeBSD 2.0, 2.1 or earlier"
+ @echo "freebsd22 - compile for FreeBSD-2.2 or greater"
+ @echo "freebsd - compile for all other versions of FreeBSD"
+ @echo "bsd - compile for generic 4.4BSD systems"
+ @echo "bsdi - compile for BSD/OS"
+ @echo "irix - compile for SGI IRIX"
+ @echo "hpux - compile for HP-UX 11.00"
+ @echo "osf - compile for OSF/Tru64 5.1"
+ @echo ""
+
+tests:
+ @if [ -d test ]; then (cd test; make) \
+ else echo test directory not present, sorry; fi
+
+retest:
+ @if [ -d test ]; then (cd test; make clean && make) \
+ else echo test directory not present, sorry; fi
+
+include:
+ -mkdir -p net netinet
+ if [ ! -f netinet/done ] ; then \
+ (cd netinet; ln -s ../*.h .; ln -s ../ip_*_pxy.c .;); \
+ (cd netinet; ln -s ../ipsend/tcpip.h tcpip.h); \
+ touch netinet/done; \
+ fi
+ -(cd netinet; ln -s ../ip_rules.h ip_rules.h)
+
+sunos solaris: include
+ MAKE="$(MAKE)" MAKEFLAGS="$(MAKEFLAGS)" BPFILTER=$(BPFILTER) \
+ CC="$(CC)" DEBUG="$(DEBUG)" ./buildsunos
+
+freebsd:
+ make freebsd`uname -r|cut -c1`
+
+freebsd22: include
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ -rm -f BSD/$(CPUDIR)/ioconf.h
+ -if [ x$(IPFILKERN) != x ] ; then \
+ if [ -f /sys/compile/$(IPFILKERN)/ioconf.h ] ; then \
+ ln -s /sys/compile/$(IPFILKERN)/ioconf.h BSD/$$y; \
+ else \
+ ln -s /sys/$(IPFILKERN)/ioconf.h BSD/$$y; \
+ fi \
+ else \
+ x=`uname -v|sed -e 's@^.*:\(/[^: ]*\).*$$@\1/ioconf.h@'`; \
+ y=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m`; \
+ if [ ! -f $$x ] ; then \
+ echo -n "Can't find ioconf.h at $$x "; \
+ exit 1;\
+ else \
+ ln -s $$x BSD/$$y ; \
+ fi \
+ fi
+ make freebsd20
+
+freebsd5 freebsd6 freebsd7 freebsd8: include
+ if [ x$(INET6) = x ] ; then \
+ echo "#undef INET6" > opt_inet6.h; \
+ else \
+ echo "#define INET6" > opt_inet6.h; \
+ fi
+ if [ "x$(IPFBPF)" = "x" ] ; then \
+ echo "#undef NBPF" > opt_bpf.h; \
+ echo "#undef NBPFILTER" > opt_bpf.h; \
+ echo "#undef DEV_BPF" > opt_bpf.h; \
+ else \
+ echo "#define NBPF" > opt_bpf.h; \
+ echo "#define NBPFILTER" > opt_bpf.h; \
+ echo "#define DEV_BPF" > opt_bpf.h; \
+ fi
+ if [ x$(ENABLE_PFIL) = x ] ; then \
+ echo "#undef PFIL_HOOKS" > opt_pfil.h; \
+ else \
+ echo "#define PFIL_HOOKS" > opt_pfil.h; \
+ fi
+
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko.5" "LKMR=ipfrule.ko.5" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..)
+# (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..)
+
+freebsd4 : include
+ if [ x$(INET6) = x ] ; then \
+ echo "#undef INET6" > opt_inet6.h; \
+ else \
+ echo "#define INET6" > opt_inet6.h; \
+ fi
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko" "LKMR=ipfrule.ko" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..)
+ (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..)
+
+freebsd3 freebsd30: include
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS1) "ML=mlf_ipl.c" "MLR=mlf_rule.o" LKM= LKMR=; cd ..)
+ (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..)
+
+netbsd: include
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ @if [ ! -d /sys -o ! -d /sys/arch ] ; then \
+ echo "*****************************************************"; \
+ echo "* *"; \
+ echo "* Please extract source code to create /sys and *";\
+ echo "* /sys/arch and run 'config GENERIC' *"; \
+ echo "* *"; \
+ echo "*****************************************************"; \
+ exit 1; \
+ fi
+ (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" LKMR= "MLR=mln_rule.o"; cd ..)
+# (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..)
+
+openbsd: include
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mlo_ipl.c" LKMR= "MLR=mlo_rule.o"; cd ..)
+ (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..)
+
+freebsd20 freebsd21: include
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlf_ipl.c" "MLR=mlf_rule.o"; cd ..)
+ (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..)
+
+osf tru64: null include
+ make setup "TARGOS=OSF" "CPUDIR=`OSF/cpurev`"
+ (cd OSF/`OSF/cpurev`; make build TRU64=`uname -v` TOP=../.. "DEBUG=-g" $(MFLAGS) "MACHASSERT=$(MACHASSERT)" "OSREV=`../cpurev`"; cd ..)
+ (cd OSF/`OSF/cpurev`; make -f Makefile.ipsend build TRU64=`uname -v` TOP=../.. $(MFLAGS) "OSREV=`../cpurev`"; cd ..)
+
+aix: null include
+ make setup "TARGOS=AIX" "CPUDIR=`AIX/cpurev`"
+ (cd AIX/`AIX/cpurev`; make build AIX=`uname -v` TOP=../.. "DEBUG=-g" $(MFLAGS) "OSREV=`../cpurev`" BITS=`../bootbits.sh`; cd ..)
+# (cd AIX/`AIX/cpurev`; make -f Makefile.ipsend build AIX=`uname -v` TOP=../.. $(MFLAGS) "OSREV=`../cpurev`"; cd ..)
+
+bsd: include
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" "MLR=mln_rule.o"; cd ..)
+ (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..)
+
+bsdi bsdos: include
+ make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)"
+ (cd BSD/$(CPUDIR); make build "CC=$(CC)" TOP=../.. $(MFLAGS) LKM= LKMR= ; cd ..)
+ (cd BSD/$(CPUDIR); make -f Makefile.ipsend build "CC=$(CC)" TOP=../.. $(MFLAGS); cd ..)
+
+irix IRIX: include
+ make setup TARGOS=IRIX CPUDIR=`IRIX/cpurev`
+ if [ "x${SGIREV}" = "x" ] ; then \
+ make irix "SGIREV=-D_KMEMUSER -DIRIX=`IRIX/getrev`"; \
+ else \
+ (cd IRIX/`IRIX/cpurev`; smake -l -J 1 build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \
+ (cd IRIX/`IRIX/cpurev`; make -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \
+ fi
+
+setup:
+ -if [ ! -d $(TARGOS)/$(CPUDIR) ] ; then mkdir $(TARGOS)/$(CPUDIR); fi
+ -rm -f $(TARGOS)/$(CPUDIR)/Makefile $(TARGOS)/$(CPUDIR)/Makefile.ipsend
+ -ln -s ../Makefile $(TARGOS)/$(CPUDIR)/Makefile
+ -ln -s ../Makefile.ipsend $(TARGOS)/$(CPUDIR)/Makefile.ipsend
+ -if [ -f $(TARGOS)/Makefile.common ] ; then \
+ rm -f $(TARGOS)/$(CPUDIR)/Makefile.common; \
+ ln -s ../Makefile.common $(TARGOS)/$(CPUDIR)/Makefile.common;\
+ fi
+
+clean: clean-include
+ /bin/rm -rf h y.output
+ ${RM} -f core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl ipflkm \
+ vnode_if.h $(LKM) *~
+ /bin/rm -rf sparcv7 sparcv9 mdbgen_build
+ (cd SunOS4; $(MAKE) TOP=.. clean)
+ -(cd SunOS5; $(MAKE) TOP=.. clean)
+ (cd BSD; $(MAKE) TOP=.. clean)
+ (cd HPUX; $(MAKE) BITS=32 TOP=.. clean)
+ (cd Linux; $(MAKE) TOP=.. clean)
+ (cd OSF; $(MAKE) TOP=.. clean)
+ (cd AIX; $(MAKE) TOP=.. clean)
+ if [ "`uname -s`" = "IRIX" ]; then (cd IRIX; $(MAKE) clean); fi
+ [ -d test ] && (cd test; $(MAKE) clean)
+ (cd ipsend; $(MAKE) clean)
+
+clean-include:
+ sh -c 'if [ -d netinet ] ; then cd netinet; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi'
+ sh -c 'if [ -d net ] ; then cd net; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi'
+ ${RM} -f netinet/done net/done
+
+clean-bsd: clean-include
+ (cd BSD; make TOP=.. clean)
+
+clean-hpux: clean-include
+ (cd HPUX; $(MAKE) BITS=32 clean)
+
+clean-osf: clean-include
+ (cd OSF; make clean)
+
+clean-aix: clean-include
+ (cd AIX; make clean)
+
+clean-linux: clean-include
+ (cd Linux; make clean)
+
+clean-sunos4: clean-include
+ (cd SunOS4; make clean)
+
+clean-sunos5: clean-include
+ (cd SunOS5; $(MAKE) clean)
+ /bin/rm -rf sparcv?
+
+clean-irix: clean-include
+ (cd IRIX; $(MAKE) clean)
+
+h/xti.h:
+ mkdir -p h
+ ln -s /usr/include/sys/xti.h h
+
+hpux: include h/xti.h
+ make setup CPUDIR=`HPUX/cpurev` TARGOS=HPUX
+ (cd HPUX/`HPUX/cpurev`; $(MAKE) build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..)
+ (cd HPUX/`HPUX/cpurev`; $(MAKE) -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..)
+
+sunos4 solaris1:
+ (cd SunOS4; make build TOP=.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..)
+ (cd SunOS4; make -f Makefile.ipsend build "CC=$(CC)" TOP=.. $(DEST) $(MFLAGS); cd ..)
+
+sunos5 solaris2: null
+ (cd SunOS5/$(CPUDIR); $(MAKE) build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" INSTANCE=$(INSTANCE); cd ..)
+ (cd SunOS5/$(CPUDIR); $(MAKE) -f Makefile.ipsend build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..)
+
+linux: include
+ (cd Linux; make build LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) LINUXKERNEL=$(LINUXKERNEL); cd ..)
+ (cd Linux; make ipflkm LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) LINUXKERNEL=$(LINUXKERNEL) WORKDIR=`pwd`; cd ..)
+# (cd Linux; make -f Makefile.ipsend build LINUX=$(LINUX) TOP=.. "CC=$(CC)" $(MFLAGS); cd ..)
+
+install-linux: linux
+ (cd Linux/; make LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) ROOTDIR=$(BUILDROOT) install ; cd ..)
+
+install-bsd:
+ (cd BSD/$(CPUDIR); make install "TOP=../.." $(MFLAGS); cd ..)
+ (cd BSD/$(CPUDIR); make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(MFLAGS); cd ..)
+
+install-sunos4: solaris
+ (cd SunOS4; $(MAKE) CPU=$(CPU) TOP=.. install)
+
+install-sunos5: solaris null
+ (cd SunOS5; $(MAKE) TOP=.. install)
+
+install-aix:
+ (cd AIX/`AIX/cpurev`; make install "TOP=../.." $(MFLAGS); cd ..)
+# (cd AIX/`AIX/cpurev`; make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(MFLAGS); cd ..)
+
+install-hpux: hpux
+ (cd HPUX/`HPUX/cpurev`; $(MAKE) CPU=$(CPU) TOP=../.. "BITS=`getconf KERNEL_BITS`" install)
+
+install-irix: irix
+ (cd IRIX; smake install CPU=$(CPU) TOP=.. $(DEST) $(MFLAGS) CPUDIR=`./cpurev`)
+
+install-osf install-tru64:
+ (cd OSF/`OSF/cpurev`; make install "TOP=../.." $(MFLAGS); cd ..)
+
+do-cvs:
+ find . -type d -name CVS -print | xargs /bin/rm -rf
+ find . -type f -name .cvsignore -print | xargs /bin/rm -f
+ /bin/rm -f ip_msnrpc_pxy.c ip_sunrpc_pxy.c
+
+ip_rules.c ip_rules.h: rules/ip_rules tools/ipfcomp.c
+ -./ipf -n -cc -f rules/ip_rules 2>/dev/null 1>&2
+
+null:
+ @if [ "`$(MAKE) -v 2>&1 | sed -ne 's/GNU.*/GNU/p'`" = "GNU" ] ; then \
+ echo 'Do not use GNU make (gmake) to compile IPFilter'; \
+ exit 1; \
+ fi
+ -@echo make ok
+
+mdb:
+ /bin/rm -rf mdbgen_build
+ mdbgen -D_KERNEL -DIPFILTER_LOG -DIPFILTER_LOOKUP -DSUNDDI \
+ -DIPFILTER_SCAN -DIPFILTER_LKM -DSOLARIS2=10 -n ipf_mdb -k \
+ -I/home/dr146992/pfil -I/home/dr146992/ipf -f \
+ /usr/include/netinet/in_systm.h,/usr/include/sys/ethernet.h,/usr/include/netinet/in.h,/usr/include/netinet/ip.h,/usr/include/netinet/ip_var.h,/usr/include/netinet/tcp.h,/usr/include/netinet/tcpip.h,/usr/include/netinet/ip_icmp.h,/usr/include/netinet/udp.h,ip_compat.h,ip_fil.h,ip_nat.h,ip_state.h,ip_proxy.h,ip_scan.h
diff --git a/contrib/ipfilter/NAT.FreeBSD b/contrib/ipfilter/NAT.FreeBSD
new file mode 100644
index 0000000..4a1a7ed
--- /dev/null
+++ b/contrib/ipfilter/NAT.FreeBSD
@@ -0,0 +1,104 @@
+These are Instructions for Configuring A FreeBSD Box For NAT
+After you have installed IpFilter.
+
+You will need to change three files:
+
+/etc/rc.local
+/etc/rc.conf
+/etc/natrules
+
+You will have to:
+
+1) Load the kernel module
+2) Make the ipnat rules
+3) Load the ipnat rules
+4) Enable routing between interfaces
+5) Add static routes for the subnet ranges
+6) Configure your network interfaces
+7) reboot the computer for the changes to take effect.
+
+The FAQ was written by Chris Coleman <chris@@bbcc.ctc.edu>
+This was tested using ipfilter 3.1.4 and FreeBSD 2.1.6-RELEASE
+_________________________________________________________
+1) Loading the Kernel Module
+
+If you are using a Kernal Loadable Module you need to edit your
+/etc/rc.local file and load the module at boot time.
+use the line:
+
+ modload /lkm/if_ipl.o
+
+If you are not loading a kernel module, skip this step.
+_________________________________________________________
+2) Setting up the NAT Rules
+
+Make a file called /etc/natrules
+put in the rules that you need for your system.
+
+If you want to use the whole 10 Network. Try:
+
+map fpx0 10.0.0.0/8 -> 208.8.0.1/32 portmap tcp/udp 10000:65000
+
+_________________________________________________________
+Here is an explaination of each part of the command:
+
+map starts the command.
+
+fpx0 is the interface with the real internet address.
+
+10.0.0.0 is the subnet you want to use.
+
+/8 is the subnet mask. ie 255.0.0.0
+
+208.8.0.1 is the real ip address that you use.
+
+/32 is the subnet mask 255.255.255.255, ie only use this ip address.
+
+portmap tcp/udp 10000:65000
+ tells it to use the ports to redirect the tcp/udp calls through
+
+
+The one line should work for the whole network.
+_________________________________________________________
+3) Loading the NAT Rules:
+
+The NAT Rules will need to be loaded every time the computer
+reboots.
+
+In your /etc/rc.local put the line:
+
+ipnat -f /etc/natrules
+
+To check and see if it is loaded, as root type
+ ipnat -ls
+_________________________________________________________
+4) Enable Routing between interfaces.
+
+Tell the kernel to route these addresses.
+
+in the rc.local file put the line:
+
+sysctl -w net.inet.ip.forwarding=1
+
+_________________________________________________________
+5) Static Routes to Subnet Ranges
+
+Now you have to add a static routes for the subnet ranges.
+Edit your /etc/sysconfig to add them at bootup.
+
+static_routes="foo"
+route_foo="10.0.0.0 -netmask 0xf0000000 -interface 10.0.0.1"
+
+
+_________________________________________________________
+6) Make sure that you have your interfaces configured.
+
+I have two Intel Ether Express Pro B cards.
+One is on 208.8.0.1 The other is on 10.0.0.1
+
+You need to configure these in the /etc/sysconfig
+
+network_interfaces="fxp0 fxp1"
+ifconfig_fxp0="inet 208.8.0.1 netmask 255.255.255.0"
+ifconfig_fxp1="inet 10.0.0.1 netmask 255.0.0.0"
+_________________________________________________________
diff --git a/contrib/ipfilter/README b/contrib/ipfilter/README
new file mode 100644
index 0000000..8464af4
--- /dev/null
+++ b/contrib/ipfilter/README
@@ -0,0 +1,101 @@
+IP Filter - What's this about ?
+============================
+Web site: http://coombs.anu.edu.au/~avalon/ip-filter.html
+How-to: http://www.obfuscation.org/ipf/ipf-howto.txt
+
+ The idea behind this package is allow those who use Unix workstations as
+routers (a common occurance in Universities it appears) to apply packet
+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, and SGI's IRIX 6.2.
+
+ 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.
+
+Bugs/Problems
+-------------
+If you have a problem with IP Filter on your operating system, please email
+a copy of the file "BugReport" with the details of your setup as required
+and email to darrenr@pobox.com.
+
+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@pobox.com
+http://coombs.anu.edu.au/~avalon/ip-filter.html
diff --git a/contrib/ipfilter/STYLE.TXT b/contrib/ipfilter/STYLE.TXT
new file mode 100644
index 0000000..384bcec
--- /dev/null
+++ b/contrib/ipfilter/STYLE.TXT
@@ -0,0 +1,57 @@
+
+Over time, I am moving all of the IPFilter code to what I consider a better
+coding style than it had before. If you submit patches, I expect them to
+conform as appropriate.
+
+Function Comments
+=================
+Preceeding each and every function, a comment block like this should
+be present:
+
+/* ------------------------------------------------------------------------ */
+/* Function: function-name */
+/* Returns: return-type */
+/* Parameters: param1(I) - param1 is an input parameter */
+/* p2(O) - p2 is an output parameter passed as an arg */
+/* par3(IO) - par3 is a parameter which is both input and */
+/* output. Pointers to things which are used and */
+/* then get a result stored in them qualify here. */
+/* */
+/* Description about what the function does. This comment should explain */
+/* any gotchas or algorithms that are used which aren't obvious to the */
+/* casual reader. It should not be an excuse to not use comments inside */
+/* the function. */
+/* ------------------------------------------------------------------------ */
+
+
+Tab spacing
+===========
+Tabs are to be at 8 characters.
+
+
+Conditions
+==========
+All expressions which evaluate to a boolean for a test condition, such as
+in an if()/while() statement must involve a boolean operation. Since C
+has no native boolean type, this means that one of <,>,<=,>=,==,!= must
+be present. Implied boolean evaluations are out.
+
+In code, the following is banned:
+
+if (x)
+if (!x)
+while ((a = b))
+
+and should be replaced by:
+
+if (x != 0)
+if (x == 0)
+while ((a = b) != 0)
+
+If pointers are involved, always compare with NULL, ie.:
+
+if (x != NULL)
+if (x == NULL)
+while ((a = b) != NULL)
+
+
diff --git a/contrib/ipfilter/WhatsNew50.txt b/contrib/ipfilter/WhatsNew50.txt
new file mode 100644
index 0000000..adbf0a9
--- /dev/null
+++ b/contrib/ipfilter/WhatsNew50.txt
@@ -0,0 +1,83 @@
+What's new in 5.1
+=================
+
+General
+-------
+* all of the tuneables can now be set at any time, not just whilst disabled
+ or prior to loading rules;
+
+* group identifiers may now be a number or name (universal);
+
+* man pages rewritten
+
+* tunables can now be set via ipf.conf;
+
+Logging
+-------
+* ipmon.conf can now be used to generate SNMPv1 and SNMPv2 traps using
+ information from log entries from the kernel;
+
+NAT changes
+-----------
+* DNS proxy for the kernel that can block queries based on domain names;
+
+* FTP proxy can be configured to limit data connections to one or many
+ connections per client;
+
+* NAT on IPv6 is now supported;
+
+* rewrite command allows changing both the source and destination address
+ in a single NAT rule;
+
+* simple encapsulation can now be configured with ipnat.conf,
+
+* TFTP proxy now included;
+
+Packet Filtering
+----------------
+* acceptance of ICMP packets for "keep state" rules can be refined through
+ the use of filtering rules;
+
+* alternative form for writing rules using simple filtering expressions;
+
+* CIPSO headers now recognised and analysed for filtering on DOI;
+
+* comments can now be a part of a rule and loaded into the kernel and
+ thus displayed with ipfstat;
+
+* decapsulation rules allow filtering on inner headers, providing they
+ are not encrypted;
+
+* interface names, aside from that the packet is on, can be present in
+ filter rules;
+
+* internally now a single list of filter rules, there is no longer an
+ IPv4 and IPv6 list;
+
+* rules can now be added with an expiration time, allowing for their
+ automatic removal after some period of time;
+
+* single file, ipf.conf, can now be used for both IPv4 and IPv6 rules;
+
+* stateful filtering now allows for limits to be placed on the number
+ of distinct hosts allowed per rule;
+
+Pools
+-----
+* addresses added to a pool via the command line (only!) can be given
+ an expiration timeout;
+
+* destination lists are a new type of address pool, primarily for use with
+ NAT rdr rules, supporting newer algorithms for target selection;
+
+* raw whois information saved to a file can be used to populate a pool;
+
+Solaris
+-------
+* support for use in zones with exclusive IP instances fully supported.
+
+Tools
+-----
+* use of matching expressions allows for refining what is displayed or
+ flushed;
+
diff --git a/contrib/ipfilter/Y2K b/contrib/ipfilter/Y2K
new file mode 100644
index 0000000..a8350a5
--- /dev/null
+++ b/contrib/ipfilter/Y2K
@@ -0,0 +1,3 @@
+IP Filter is Year 2000 (Y2K) Compliant.
+
+Darren
diff --git a/contrib/ipfilter/arc4random.c b/contrib/ipfilter/arc4random.c
new file mode 100644
index 0000000..04b0797
--- /dev/null
+++ b/contrib/ipfilter/arc4random.c
@@ -0,0 +1,277 @@
+/*-
+ * THE BEER-WARE LICENSE
+ *
+ * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you
+ * think this stuff is worth it, you can buy me a beer in return.
+ *
+ * Dan Moschuk
+ */
+#if !defined(SOLARIS2) && !defined(__osf__)
+# include <sys/cdefs.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef __FreeBSD__
+# include <sys/kernel.h>
+#endif
+#if !defined(__osf__)
+# include <sys/random.h>
+#endif
+#ifdef __FreeBSD__
+# include <sys/libkern.h>
+#endif
+#include <sys/lock.h>
+#ifndef __osf__
+# include <sys/mutex.h>
+#endif
+#include <sys/time.h>
+
+#if defined(SOLARIS2) && (SOLARIS2 < 9)
+# include <netinet/in_systm.h>
+#endif
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef __osf__
+# include <net/route.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include "netinet/ip_compat.h"
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+
+#ifdef NEED_LOCAL_RAND
+#if !defined(__GNUC__)
+# define __inline
+#endif
+
+#define ARC4_RESEED_BYTES 65536
+#define ARC4_RESEED_SECONDS 300
+#define ARC4_KEYBYTES (256 / 8)
+
+static u_int8_t arc4_i, arc4_j;
+static int arc4_numruns = 0;
+static u_int8_t arc4_sbox[256];
+static time_t arc4_t_reseed;
+static ipfmutex_t arc4_mtx;
+static MD5_CTX md5ctx;
+
+static u_int8_t arc4_randbyte(void);
+static int ipf_read_random(void *dest, int length);
+
+static __inline void
+arc4_swap(u_int8_t *a, u_int8_t *b)
+{
+ u_int8_t c;
+
+ c = *a;
+ *a = *b;
+ *b = c;
+}
+
+/*
+ * Stir our S-box.
+ */
+static void
+arc4_randomstir (void)
+{
+ u_int8_t key[256];
+ int r, n;
+ struct timeval tv_now;
+
+ /*
+ * XXX read_random() returns unsafe numbers if the entropy
+ * device is not loaded -- MarkM.
+ */
+ r = ipf_read_random(key, ARC4_KEYBYTES);
+ GETKTIME(&tv_now);
+ MUTEX_ENTER(&arc4_mtx);
+ /* If r == 0 || -1, just use what was on the stack. */
+ if (r > 0) {
+ for (n = r; n < sizeof(key); n++)
+ key[n] = key[n % r];
+ }
+
+ for (n = 0; n < 256; n++) {
+ arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256;
+ arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]);
+ }
+
+ /* Reset for next reseed cycle. */
+ arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS;
+ arc4_numruns = 0;
+
+ /*
+ * Throw away the first N words of output, as suggested in the
+ * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
+ * by Fluher, Mantin, and Shamir. (N = 256 in our case.)
+ */
+ for (n = 0; n < 256*4; n++)
+ arc4_randbyte();
+ MUTEX_EXIT(&arc4_mtx);
+}
+
+/*
+ * Initialize our S-box to its beginning defaults.
+ */
+static void
+arc4_init(void)
+{
+ int n;
+
+ MD5Init(&md5ctx);
+
+ MUTEX_INIT(&arc4_mtx, "arc4_mtx");
+ arc4_i = arc4_j = 0;
+ for (n = 0; n < 256; n++)
+ arc4_sbox[n] = (u_int8_t) n;
+
+ arc4_t_reseed = 0;
+}
+
+
+/*
+ * Generate a random byte.
+ */
+static u_int8_t
+arc4_randbyte(void)
+{
+ u_int8_t arc4_t;
+
+ arc4_i = (arc4_i + 1) % 256;
+ arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256;
+
+ arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]);
+
+ arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256;
+ return arc4_sbox[arc4_t];
+}
+
+/*
+ * MPSAFE
+ */
+void
+arc4rand(void *ptr, u_int len, int reseed)
+{
+ u_int8_t *p;
+ struct timeval tv;
+
+ GETKTIME(&tv);
+ if (reseed ||
+ (arc4_numruns > ARC4_RESEED_BYTES) ||
+ (tv.tv_sec > arc4_t_reseed))
+ arc4_randomstir();
+
+ MUTEX_ENTER(&arc4_mtx);
+ arc4_numruns += len;
+ p = ptr;
+ while (len--)
+ *p++ = arc4_randbyte();
+ MUTEX_EXIT(&arc4_mtx);
+}
+
+uint32_t
+ipf_random(void)
+{
+ uint32_t ret;
+
+ arc4rand(&ret, sizeof ret, 0);
+ return ret;
+}
+
+
+static u_char pot[ARC4_RESEED_BYTES];
+static u_char *pothead = pot, *pottail = pot;
+static int inpot = 0;
+
+/*
+ * This is not very strong, and this is understood, but the aim isn't to
+ * be cryptographically strong - it is just to make up something that is
+ * pseudo random.
+ */
+void
+ipf_rand_push(void *src, int length)
+{
+ static int arc4_inited = 0;
+ u_char *nsrc;
+ int mylen;
+
+ if (arc4_inited == 0) {
+ arc4_init();
+ arc4_inited = 1;
+ }
+
+ if (length < 64) {
+ MD5Update(&md5ctx, src, length);
+ return;
+ }
+
+ nsrc = src;
+ mylen = length;
+
+#if defined(_SYS_MD5_H) && defined(SOLARIS2)
+# define buf buf_un.buf8
+#endif
+ MUTEX_ENTER(&arc4_mtx);
+ while ((mylen > 64) && (sizeof(pot) - inpot > sizeof(md5ctx.buf))) {
+ MD5Update(&md5ctx, nsrc, 64);
+ mylen -= 64;
+ nsrc += 64;
+ if (pottail + sizeof(md5ctx.buf) > pot + sizeof(pot)) {
+ int left, numbytes;
+
+ numbytes = pot + sizeof(pot) - pottail;
+ bcopy(md5ctx.buf, pottail, numbytes);
+ left = sizeof(md5ctx.buf) - numbytes;
+ pottail = pot;
+ bcopy(md5ctx.buf + sizeof(md5ctx.buf) - left,
+ pottail, left);
+ pottail += left;
+ } else {
+ bcopy(md5ctx.buf, pottail, sizeof(md5ctx.buf));
+ pottail += sizeof(md5ctx.buf);
+ }
+ inpot += 64;
+ }
+ MUTEX_EXIT(&arc4_mtx);
+#if defined(_SYS_MD5_H) && defined(SOLARIS2)
+# undef buf
+#endif
+}
+
+
+static int
+ipf_read_random(void *dest, int length)
+{
+ if (length > inpot)
+ return 0;
+
+ MUTEX_ENTER(&arc4_mtx);
+ if (pothead + length > pot + sizeof(pot)) {
+ int left, numbytes;
+
+ left = length;
+ numbytes = pot + sizeof(pot) - pothead;
+ bcopy(pothead, dest, numbytes);
+ left -= numbytes;
+ pothead = pot;
+ bcopy(pothead, dest + length - left, left);
+ pothead += left;
+ } else {
+ bcopy(pothead, dest, length);
+ pothead += length;
+ }
+ inpot -= length;
+ if (inpot == 0)
+ pothead = pottail = pot;
+ MUTEX_EXIT(&arc4_mtx);
+
+ return length;
+}
+
+#endif /* NEED_LOCAL_RAND */
diff --git a/contrib/ipfilter/bpf-ipf.h b/contrib/ipfilter/bpf-ipf.h
new file mode 100644
index 0000000..dc2b660
--- /dev/null
+++ b/contrib/ipfilter/bpf-ipf.h
@@ -0,0 +1,452 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.h 7.1 (Berkeley) 5/7/91
+ *
+ * @(#) $Header: /devel/CVS/IP-Filter/bpf-ipf.h,v 2.1 2002/10/26 12:14:26 darrenr Exp $ (LBL)
+ */
+
+#ifndef BPF_MAJOR_VERSION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BSD style release date */
+#define BPF_RELEASE 199606
+
+typedef int bpf_int32;
+typedef u_int bpf_u_int32;
+
+/*
+ * Alignment macros. BPF_WORDALIGN rounds up to the next
+ * even multiple of BPF_ALIGNMENT.
+ */
+#ifndef __NetBSD__
+#define BPF_ALIGNMENT sizeof(bpf_int32)
+#else
+#define BPF_ALIGNMENT sizeof(long)
+#endif
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_MAXINSNS 512
+#define BPF_MAXBUFSIZE 0x8000
+#define BPF_MINBUFSIZE 32
+
+/*
+ * Structure for BIOCSETF.
+ */
+struct bpf_program {
+ u_int bf_len;
+ struct bpf_insn *bf_insns;
+};
+
+/*
+ * Struct returned by BIOCGSTATS.
+ */
+struct bpf_stat {
+ u_int bs_recv; /* number of packets received */
+ u_int bs_drop; /* number of packets dropped */
+};
+
+/*
+ * Struct return by BIOCVERSION. This represents the version number of
+ * the filter language described by the instruction encodings below.
+ * bpf understands a program iff kernel_major == filter_major &&
+ * kernel_minor >= filter_minor, that is, if the value returned by the
+ * running kernel has the same major number and a minor number equal
+ * equal to or less than the filter being downloaded. Otherwise, the
+ * results are undefined, meaning an error may be returned or packets
+ * may be accepted haphazardly.
+ * It has nothing to do with the source code version.
+ */
+struct bpf_version {
+ u_short bv_major;
+ u_short bv_minor;
+};
+/* Current version number of filter architecture. */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+/*
+ * BPF ioctls
+ *
+ * The first set is for compatibility with Sun's pcc style
+ * header files. If your using gcc, we assume that you
+ * have run fixincludes so the latter set should work.
+ */
+#if (defined(sun) || defined(ibm032)) && !defined(__GNUC__)
+#define BIOCGBLEN _IOR(B,102, u_int)
+#define BIOCSBLEN _IOWR(B,102, u_int)
+#define BIOCSETF _IOW(B,103, struct bpf_program)
+#define BIOCFLUSH _IO(B,104)
+#define BIOCPROMISC _IO(B,105)
+#define BIOCGDLT _IOR(B,106, u_int)
+#define BIOCGETIF _IOR(B,107, struct ifreq)
+#define BIOCSETIF _IOW(B,108, struct ifreq)
+#define BIOCSRTIMEOUT _IOW(B,109, struct timeval)
+#define BIOCGRTIMEOUT _IOR(B,110, struct timeval)
+#define BIOCGSTATS _IOR(B,111, struct bpf_stat)
+#define BIOCIMMEDIATE _IOW(B,112, u_int)
+#define BIOCVERSION _IOR(B,113, struct bpf_version)
+#define BIOCSTCPF _IOW(B,114, struct bpf_program)
+#define BIOCSUDPF _IOW(B,115, struct bpf_program)
+#else
+#define BIOCGBLEN _IOR('B',102, u_int)
+#define BIOCSBLEN _IOWR('B',102, u_int)
+#define BIOCSETF _IOW('B',103, struct bpf_program)
+#define BIOCFLUSH _IO('B',104)
+#define BIOCPROMISC _IO('B',105)
+#define BIOCGDLT _IOR('B',106, u_int)
+#define BIOCGETIF _IOR('B',107, struct ifreq)
+#define BIOCSETIF _IOW('B',108, struct ifreq)
+#define BIOCSRTIMEOUT _IOW('B',109, struct timeval)
+#define BIOCGRTIMEOUT _IOR('B',110, struct timeval)
+#define BIOCGSTATS _IOR('B',111, struct bpf_stat)
+#define BIOCIMMEDIATE _IOW('B',112, u_int)
+#define BIOCVERSION _IOR('B',113, struct bpf_version)
+#define BIOCSTCPF _IOW('B',114, struct bpf_program)
+#define BIOCSUDPF _IOW('B',115, struct bpf_program)
+#endif
+
+/*
+ * Structure prepended to each packet.
+ */
+struct bpf_hdr {
+ struct timeval bh_tstamp; /* time stamp */
+ bpf_u_int32 bh_caplen; /* length of captured portion */
+ bpf_u_int32 bh_datalen; /* original length of packet */
+ u_short bh_hdrlen; /* length of bpf header (this struct
+ plus alignment padding) */
+};
+/*
+ * Because the structure above is not a multiple of 4 bytes, some compilers
+ * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work.
+ * Only the kernel needs to know about it; applications use bh_hdrlen.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+#define SIZEOF_BPF_HDR 18
+#endif
+
+/*
+ * Data-link level type codes.
+ */
+
+/*
+ * These are the types that are the same on all platforms; on other
+ * platforms, a <net/bpf.h> should be supplied that defines the additional
+ * DLT_* codes appropriately for that platform (the BSDs, for example,
+ * should not just pick up this version of "bpf.h"; they should also define
+ * the additional DLT_* codes used by their kernels, as well as the values
+ * defined here - and, if the values they use for particular DLT_ types
+ * differ from those here, they should use their values, not the ones
+ * here).
+ */
+#define DLT_NULL 0 /* no link-layer encapsulation */
+#define DLT_EN10MB 1 /* Ethernet (10Mb) */
+#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
+#define DLT_AX25 3 /* Amateur Radio AX.25 */
+#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
+#define DLT_CHAOS 5 /* Chaos */
+#define DLT_IEEE802 6 /* IEEE 802 Networks */
+#define DLT_ARCNET 7 /* ARCNET */
+#define DLT_SLIP 8 /* Serial Line IP */
+#define DLT_PPP 9 /* Point-to-point Protocol */
+#define DLT_FDDI 10 /* FDDI */
+
+/*
+ * These are values from the traditional libpcap "bpf.h".
+ * Ports of this to particular platforms should replace these definitions
+ * with the ones appropriate to that platform, if the values are
+ * different on that platform.
+ */
+#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */
+#define DLT_RAW 12 /* raw IP */
+
+/*
+ * These are values from BSD/OS's "bpf.h".
+ * These are not the same as the values from the traditional libpcap
+ * "bpf.h"; however, these values shouldn't be generated by any
+ * OS other than BSD/OS, so the correct values to use here are the
+ * BSD/OS values.
+ *
+ * Platforms that have already assigned these values to other
+ * DLT_ codes, however, should give these codes the values
+ * from that platform, so that programs that use these codes will
+ * continue to compile - even though they won't correctly read
+ * files of these types.
+ */
+#ifdef __NetBSD__
+#ifndef DLT_SLIP_BSDOS
+#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */
+#endif
+#else
+#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */
+#endif
+
+#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */
+
+/*
+ * These values are defined by NetBSD; other platforms should refrain from
+ * using them for other purposes, so that NetBSD savefiles with link
+ * types of 50 or 51 can be read as this type on all platforms.
+ */
+#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */
+#define DLT_PPP_ETHER 51 /* PPP over Ethernet */
+
+/*
+ * Values between 100 and 103 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that differ
+ * between platforms; don't use those values for new DLT_ new types.
+ */
+
+/*
+ * This value was defined by libpcap 0.5; platforms that have defined
+ * it with a different value should define it here with that value -
+ * a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ * whatever value that happens to be, so programs will correctly
+ * handle files with that link type regardless of the value of
+ * DLT_C_HDLC.
+ *
+ * The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ * compatibility with programs written for BSD/OS.
+ *
+ * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ * for source compatibility with programs written for libpcap 0.5.
+ */
+#define DLT_C_HDLC 104 /* Cisco HDLC */
+#define DLT_CHDLC DLT_C_HDLC
+
+#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */
+
+/*
+ * Values between 106 and 107 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ new types.
+ */
+
+/*
+ * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ * that the AF_ type in the link-layer header is in network byte order.
+ *
+ * OpenBSD defines it as 12, but that collides with DLT_RAW, so we
+ * define it as 108 here. If OpenBSD picks up this file, it should
+ * define DLT_LOOP as 12 in its version, as per the comment above -
+ * and should not use 108 as a DLT_ value.
+ */
+#define DLT_LOOP 108
+
+/*
+ * Values between 109 and 112 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ types
+ * other than the corresponding DLT_ types.
+ */
+
+/*
+ * This is for Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL 113
+
+/*
+ * Apple LocalTalk hardware.
+ */
+#define DLT_LTALK 114
+
+/*
+ * Acorn Econet.
+ */
+#define DLT_ECONET 115
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define DLT_IPFILTER 116
+
+/*
+ * Reserved for use in capture-file headers as a link-layer type
+ * corresponding to OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD,
+ * but that's DLT_LANE8023 in SuSE 6.3, so we can't use 17 for it
+ * in capture-file headers.
+ */
+#define DLT_PFLOG 117
+
+/*
+ * Registered for Cisco-internal use.
+ */
+#define DLT_CISCO_IOS 118
+
+/*
+ * Reserved for 802.11 cards using the Prism II chips, with a link-layer
+ * header including Prism monitor mode information plus an 802.11
+ * header.
+ */
+#define DLT_PRISM_HEADER 119
+
+/*
+ * Reserved for Aironet 802.11 cards, with an Aironet link-layer header
+ * (see Doug Ambrisko's FreeBSD patches).
+ */
+#define DLT_AIRONET_HEADER 120
+
+/*
+ * Reserved for Siemens HiPath HDLC.
+ */
+#define DLT_HHDLC 121
+
+/*
+ * Reserved for RFC 2625 IP-over-Fibre Channel, as per a request from
+ * Don Lee <donlee@cray.com>.
+ *
+ * This is not for use with raw Fibre Channel, where the link-layer
+ * header starts with a Fibre Channel frame header; it's for IP-over-FC,
+ * where the link-layer header starts with an RFC 2625 Network_Header
+ * field.
+ */
+#define DLT_IP_OVER_FC 122
+
+/*
+ * The instruction encodings.
+ */
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define BPF_A 0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define BPF_TAX 0x00
+#define BPF_TXA 0x80
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+ u_short code;
+ u_char jt;
+ u_char jf;
+ bpf_int32 k;
+};
+
+/*
+ * Macros for insn array initializers.
+ */
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+#if defined(BSD) && (defined(KERNEL) || defined(_KERNEL))
+/*
+ * Systems based on non-BSD kernels don't have ifnet's (or they don't mean
+ * anything if it is in <net/if.h>) and won't work like this.
+ */
+# if __STDC__
+extern void bpf_tap(struct ifnet *, u_char *, u_int);
+extern void bpf_mtap(struct ifnet *, struct mbuf *);
+extern void bpfattach(struct ifnet *, u_int, u_int);
+extern void bpfilterattach(int);
+# else
+extern void bpf_tap();
+extern void bpf_mtap();
+extern void bpfattach();
+extern void bpfilterattach();
+# endif /* __STDC__ */
+#endif /* BSD && (_KERNEL || KERNEL) */
+#if __STDC__ || defined(__cplusplus)
+extern int bpf_validate(struct bpf_insn *, int);
+extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
+#else
+extern int bpf_validate();
+extern u_int bpf_filter();
+#endif
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/ipfilter/bpf_filter.c b/contrib/ipfilter/bpf_filter.c
new file mode 100644
index 0000000..d75570e
--- /dev/null
+++ b/contrib/ipfilter/bpf_filter.c
@@ -0,0 +1,595 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.c 7.5 (Berkeley) 7/15/91
+ */
+
+#if !(defined(lint) || defined(KERNEL) || defined(_KERNEL))
+static const char rcsid[] =
+ "@(#) $Header: /devel/CVS/IP-Filter/bpf_filter.c,v 2.2.2.3 2006/10/03 11:25:56 darrenr Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include "netinet/ip_compat.h"
+#include "bpf-ipf.h"
+
+
+#if (defined(__hpux) || SOLARIS) && (defined(_KERNEL) || defined(KERNEL))
+# include <sys/sysmacros.h>
+# include <sys/stream.h>
+#endif
+
+#include "pcap-ipf.h"
+
+#if !defined(KERNEL) && !defined(_KERNEL)
+#include <stdlib.h>
+#endif
+
+#define int32 bpf_int32
+#define u_int32 bpf_u_int32
+
+static int m_xword __P((mb_t *, int, int *));
+static int m_xhalf __P((mb_t *, int, int *));
+
+#ifndef LBL_ALIGN
+/*
+ * XXX - IA-64? If not, this probably won't work on Win64 IA-64
+ * systems, unless LBL_ALIGN is defined elsewhere for them.
+ * XXX - SuperH? If not, this probably won't work on WinCE SuperH
+ * systems, unless LBL_ALIGN is defined elsewhere for them.
+ */
+#if defined(sparc) || defined(__sparc__) || defined(mips) || \
+ defined(ibm032) || defined(__alpha) || defined(__hpux) || \
+ defined(__arm__)
+#define LBL_ALIGN
+#endif
+#endif
+
+#ifndef LBL_ALIGN
+
+#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p))
+#else
+#define EXTRACT_SHORT(p)\
+ ((u_short)\
+ ((u_short)*((u_char *)p+0)<<8|\
+ (u_short)*((u_char *)p+1)<<0))
+#define EXTRACT_LONG(p)\
+ ((u_int32)*((u_char *)p+0)<<24|\
+ (u_int32)*((u_char *)p+1)<<16|\
+ (u_int32)*((u_char *)p+2)<<8|\
+ (u_int32)*((u_char *)p+3)<<0)
+#endif
+
+#define MINDEX(len, _m, _k) \
+{ \
+ len = M_LEN(m); \
+ while ((_k) >= len) { \
+ (_k) -= len; \
+ (_m) = (_m)->m_next; \
+ if ((_m) == 0) \
+ return 0; \
+ len = M_LEN(m); \
+ } \
+}
+
+static int
+m_xword(m, k, err)
+ register mb_t *m;
+ register int k, *err;
+{
+ register int len;
+ register u_char *cp, *np;
+ register mb_t *m0;
+
+ MINDEX(len, m, k);
+ cp = MTOD(m, u_char *) + k;
+ if (len - k >= 4) {
+ *err = 0;
+ return EXTRACT_LONG(cp);
+ }
+ m0 = m->m_next;
+ if (m0 == 0 || M_LEN(m0) + len - k < 4)
+ goto bad;
+ *err = 0;
+ np = MTOD(m0, u_char *);
+ switch (len - k) {
+
+ case 1:
+ return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
+
+ case 2:
+ return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1];
+
+ default:
+ return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0];
+ }
+ bad:
+ *err = 1;
+ return 0;
+}
+
+static int
+m_xhalf(m, k, err)
+ register mb_t *m;
+ register int k, *err;
+{
+ register int len;
+ register u_char *cp;
+ register mb_t *m0;
+
+ MINDEX(len, m, k);
+ cp = MTOD(m, u_char *) + k;
+ if (len - k >= 2) {
+ *err = 0;
+ return EXTRACT_SHORT(cp);
+ }
+ m0 = m->m_next;
+ if (m0 == 0)
+ goto bad;
+ *err = 0;
+ return (cp[0] << 8) | MTOD(m0, u_char *)[0];
+ bad:
+ *err = 1;
+ return 0;
+}
+
+/*
+ * Execute the filter program starting at pc on the packet p
+ * wirelen is the length of the original packet
+ * buflen is the amount of data present
+ * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0,
+ * in all other cases, p is a pointer to a buffer and buflen is its size.
+ */
+u_int
+bpf_filter(pc, p, wirelen, buflen)
+ register struct bpf_insn *pc;
+ register u_char *p;
+ u_int wirelen;
+ register u_int buflen;
+{
+ register u_int32 A, X;
+ register int k;
+ int32 mem[BPF_MEMWORDS];
+ mb_t *m, *n;
+ int merr = 0; /* XXX: GCC */
+ int len;
+
+ if (buflen == 0) {
+ m = (mb_t *)p;
+ p = MTOD(m, u_char *);
+ buflen = M_LEN(m);
+ } else
+ m = NULL;
+
+ if (pc == 0)
+ /*
+ * No filter means accept all.
+ */
+ return (u_int)-1;
+ A = 0;
+ X = 0;
+ --pc;
+ while (1) {
+ ++pc;
+ switch (pc->code) {
+
+ default:
+ return 0;
+ case BPF_RET|BPF_K:
+ return (u_int)pc->k;
+
+ case BPF_RET|BPF_A:
+ return (u_int)A;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ k = pc->k;
+ if (k + sizeof(int32) > buflen) {
+ if (m == NULL)
+ return 0;
+ A = m_xword(m, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+ }
+ A = EXTRACT_LONG(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ k = pc->k;
+ if (k + sizeof(short) > buflen) {
+ if (m == NULL)
+ return 0;
+ A = m_xhalf(m, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ k = pc->k;
+ if (k >= buflen) {
+ if (m == NULL)
+ return 0;
+ n = m;
+ MINDEX(len, n, k);
+ A = MTOD(n, u_char *)[k];
+ continue;
+ }
+ A = p[k];
+ continue;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ A = wirelen;
+ continue;
+
+ case BPF_LDX|BPF_W|BPF_LEN:
+ X = wirelen;
+ continue;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ k = X + pc->k;
+ if (k + sizeof(int32) > buflen) {
+ if (m == NULL)
+ return 0;
+ A = m_xword(m, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+ }
+ A = EXTRACT_LONG(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ k = X + pc->k;
+ if (k + sizeof(short) > buflen) {
+ if (m == NULL)
+ return 0;
+ A = m_xhalf(m, k, &merr);
+ if (merr != 0)
+ return 0;
+ continue;
+ }
+ A = EXTRACT_SHORT(&p[k]);
+ continue;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ k = X + pc->k;
+ if (k >= buflen) {
+ if (m == NULL)
+ return 0;
+ n = m;
+ MINDEX(len, n, k);
+ A = MTOD(n, u_char *)[k];
+ continue;
+ }
+ A = p[k];
+ continue;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ k = pc->k;
+ if (k >= buflen) {
+ if (m == NULL)
+ return 0;
+ n = m;
+ MINDEX(len, n, k);
+ X = (MTOD(n, char *)[k] & 0xf) << 2;
+ continue;
+ }
+ X = (p[pc->k] & 0xf) << 2;
+ continue;
+
+ case BPF_LD|BPF_IMM:
+ A = pc->k;
+ continue;
+
+ case BPF_LDX|BPF_IMM:
+ X = pc->k;
+ continue;
+
+ case BPF_LD|BPF_MEM:
+ A = mem[pc->k];
+ continue;
+
+ case BPF_LDX|BPF_MEM:
+ X = mem[pc->k];
+ continue;
+
+ case BPF_ST:
+ mem[pc->k] = A;
+ continue;
+
+ case BPF_STX:
+ mem[pc->k] = X;
+ continue;
+
+ case BPF_JMP|BPF_JA:
+ pc += pc->k;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ pc += (A > pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ pc += (A >= pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ pc += (A == pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ pc += (A & pc->k) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ pc += (A > X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ pc += (A >= X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ pc += (A == X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ pc += (A & X) ? pc->jt : pc->jf;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ A += X;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ A -= X;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ A *= X;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ if (X == 0)
+ return 0;
+ A /= X;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ A &= X;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ A |= X;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ A <<= X;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ A >>= X;
+ continue;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ A += pc->k;
+ continue;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ A -= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ A *= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ A /= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ A &= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ A |= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ A <<= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ A >>= pc->k;
+ continue;
+
+ case BPF_ALU|BPF_NEG:
+ A = -A;
+ continue;
+
+ case BPF_MISC|BPF_TAX:
+ X = A;
+ continue;
+
+ case BPF_MISC|BPF_TXA:
+ A = X;
+ continue;
+ }
+ }
+}
+
+
+/*
+ * Return true if the 'fcode' is a valid filter program.
+ * The constraints are that each jump be forward and to a valid
+ * code, that memory accesses are within valid ranges (to the
+ * extent that this can be checked statically; loads of packet
+ * data have to be, and are, also checked at run time), and that
+ * the code terminates with either an accept or reject.
+ *
+ * The kernel needs to be able to verify an application's filter code.
+ * Otherwise, a bogus program could easily crash the system.
+ */
+int
+bpf_validate(f, len)
+ struct bpf_insn *f;
+ int len;
+{
+ u_int i, from;
+ const struct bpf_insn *p;
+
+ if (len == 0)
+ return 1;
+
+ if (len < 1 || len > BPF_MAXINSNS)
+ return 0;
+
+ for (i = 0; i < len; ++i) {
+ p = &f[i];
+ switch (BPF_CLASS(p->code)) {
+ /*
+ * Check that memory operations use valid addresses.
+ */
+ case BPF_LD:
+ case BPF_LDX:
+ switch (BPF_MODE(p->code)) {
+ case BPF_IMM:
+ break;
+ case BPF_ABS:
+ case BPF_IND:
+ case BPF_MSH:
+ /*
+ * More strict check with actual packet length
+ * is done runtime.
+ */
+#if 0
+ if (p->k >= bpf_maxbufsize)
+ return 0;
+#endif
+ break;
+ case BPF_MEM:
+ if (p->k >= BPF_MEMWORDS)
+ return 0;
+ break;
+ case BPF_LEN:
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_ST:
+ case BPF_STX:
+ if (p->k >= BPF_MEMWORDS)
+ return 0;
+ break;
+ case BPF_ALU:
+ switch (BPF_OP(p->code)) {
+ case BPF_ADD:
+ case BPF_SUB:
+ case BPF_OR:
+ case BPF_AND:
+ case BPF_LSH:
+ case BPF_RSH:
+ case BPF_NEG:
+ break;
+ case BPF_DIV:
+ /*
+ * Check for constant division by 0.
+ */
+ if (BPF_RVAL(p->code) == BPF_K && p->k == 0)
+ return 0;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_JMP:
+ /*
+ * Check that jumps are within the code block,
+ * and that unconditional branches don't go
+ * backwards as a result of an overflow.
+ * Unconditional branches have a 32-bit offset,
+ * so they could overflow; we check to make
+ * sure they don't. Conditional branches have
+ * an 8-bit offset, and the from address is <=
+ * BPF_MAXINSNS, and we assume that BPF_MAXINSNS
+ * is sufficiently small that adding 255 to it
+ * won't overflow.
+ *
+ * We know that len is <= BPF_MAXINSNS, and we
+ * assume that BPF_MAXINSNS is < the maximum size
+ * of a u_int, so that i + 1 doesn't overflow.
+ */
+ from = i + 1;
+ switch (BPF_OP(p->code)) {
+ case BPF_JA:
+ if (from + p->k < from || from + p->k >= len)
+ return 0;
+ break;
+ case BPF_JEQ:
+ case BPF_JGT:
+ case BPF_JGE:
+ case BPF_JSET:
+ if (from + p->jt >= len || from + p->jf >= len)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case BPF_RET:
+ break;
+ case BPF_MISC:
+ break;
+ default:
+ return 0;
+ }
+ }
+ return BPF_CLASS(f[len - 1].code) == BPF_RET;
+}
diff --git a/contrib/ipfilter/genmask.c b/contrib/ipfilter/genmask.c
new file mode 100644
index 0000000..75193e3
--- /dev/null
+++ b/contrib/ipfilter/genmask.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+int genmask(family, msk, mskp)
+ int family;
+ char *msk;
+ i6addr_t *mskp;
+{
+ char *endptr = 0L;
+ u_32_t addr;
+ int bits;
+
+ if (strchr(msk, '.') || strchr(msk, 'x') || strchr(msk, ':')) {
+ /* possibly of the form xxx.xxx.xxx.xxx
+ * or 0xYYYYYYYY */
+ switch (family)
+ {
+#ifdef USE_INET6
+ case AF_INET6 :
+ if (inet_pton(AF_INET6, msk, &mskp->in4) != 1)
+ return -1;
+ break;
+#endif
+ case AF_INET :
+ if (inet_aton(msk, &mskp->in4) == 0)
+ return -1;
+ break;
+ default :
+ return -1;
+ /*NOTREACHED*/
+ }
+ } else {
+ /*
+ * set x most significant bits
+ */
+ bits = (int)strtol(msk, &endptr, 0);
+
+ switch (family)
+ {
+ case AF_INET6 :
+ if ((*endptr != '\0') || (bits < 0) || (bits > 128))
+ return -1;
+ fill6bits(bits, mskp->i6);
+ break;
+ case AF_INET :
+ if (*endptr != '\0' || bits > 32 || bits < 0)
+ return -1;
+ if (bits == 0)
+ addr = 0;
+ else
+ addr = htonl(0xffffffff << (32 - bits));
+ mskp->in4.s_addr = addr;
+ break;
+ default :
+ return -1;
+ /*NOTREACHED*/
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/ip_dstlist.c b/contrib/ipfilter/ip_dstlist.c
new file mode 100644
index 0000000..ce2e72e
--- /dev/null
+++ b/contrib/ipfilter/ip_dstlist.c
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define KERNEL 1
+# define _KERNEL 1
+#endif
+#if defined(__osf__)
+# define _PROTO_NET_H_
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#if !defined(_KERNEL) && !defined(__KERNEL__)
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# define _KERNEL
+# ifdef __OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#else
+# include <sys/systm.h>
+# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
+# include <sys/proc.h>
+# endif
+#endif
+#include <sys/time.h>
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
+# include <sys/mbuf.h>
+#endif
+#if defined(__SVR4) || defined(__svr4__)
+# include <sys/filio.h>
+# include <sys/byteorder.h>
+# ifdef _KERNEL
+# include <sys/dditypes.h>
+# endif
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
+
+/* END OF INCLUDES */
+
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: ip_dstlist.c,v 1.13.2.12 2012/07/20 08:40:19 darren_r Exp $";
+#endif
+
+typedef struct ipf_dstl_softc_s {
+ ippool_dst_t *dstlist[LOOKUP_POOL_SZ];
+ ippool_dst_t **tails[LOOKUP_POOL_SZ];
+ ipf_dstl_stat_t stats;
+} ipf_dstl_softc_t;
+
+
+static void *ipf_dstlist_soft_create __P((ipf_main_softc_t *));
+static void ipf_dstlist_soft_destroy __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_soft_init __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_addr_find __P((ipf_main_softc_t *, void *, int,
+ void *, u_int));
+static size_t ipf_dstlist_flush __P((ipf_main_softc_t *, void *,
+ iplookupflush_t *));
+static int ipf_dstlist_iter_deref __P((ipf_main_softc_t *, void *, int, int,
+ void *));
+static int ipf_dstlist_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
+ ipflookupiter_t *));
+static int ipf_dstlist_node_add __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+static int ipf_dstlist_node_del __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+static int ipf_dstlist_stats_get __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_dstlist_table_add __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_dstlist_table_del __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_dstlist_table_deref __P((ipf_main_softc_t *, void *, void *));
+static void *ipf_dstlist_table_find __P((void *, int, char *));
+static void ipf_dstlist_table_free __P((ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_remove __P((ipf_main_softc_t *,
+ ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_clearnodes __P((ipf_dstl_softc_t *,
+ ippool_dst_t *));
+static ipf_dstnode_t *ipf_dstlist_select __P((fr_info_t *, ippool_dst_t *));
+static void *ipf_dstlist_select_ref __P((void *, int, char *));
+static void ipf_dstlist_node_free __P((ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *));
+static int ipf_dstlist_node_deref __P((void *, ipf_dstnode_t *));
+static void ipf_dstlist_expire __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_sync __P((ipf_main_softc_t *, void *));
+
+ipf_lookup_t ipf_dstlist_backend = {
+ IPLT_DSTLIST,
+ ipf_dstlist_soft_create,
+ ipf_dstlist_soft_destroy,
+ ipf_dstlist_soft_init,
+ ipf_dstlist_soft_fini,
+ ipf_dstlist_addr_find,
+ ipf_dstlist_flush,
+ ipf_dstlist_iter_deref,
+ ipf_dstlist_iter_next,
+ ipf_dstlist_node_add,
+ ipf_dstlist_node_del,
+ ipf_dstlist_stats_get,
+ ipf_dstlist_table_add,
+ ipf_dstlist_table_del,
+ ipf_dstlist_table_deref,
+ ipf_dstlist_table_find,
+ ipf_dstlist_select_ref,
+ ipf_dstlist_select_node,
+ ipf_dstlist_expire,
+ ipf_dstlist_sync
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_create */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Allocating a chunk of memory filled with 0's is enough for the current */
+/* soft context used with destination lists. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_dstl_softc_t *softd;
+ int i;
+
+ KMALLOC(softd, ipf_dstl_softc_t *);
+ if (softd == NULL) {
+ IPFERROR(120028);
+ return NULL;
+ }
+
+ bzero((char *)softd, sizeof(*softd));
+ for (i = 0; i <= IPL_LOGMAX; i++)
+ softd->tails[i] = &softd->dstlist[i];
+
+ return softd;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* For destination lists, the only thing we have to do when destroying the */
+/* soft context is free it! */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_dstl_softc_t *softd = arg;
+
+ KFREE(softd);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_init */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* There is currently no soft context for destination list management. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_fini */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* There is currently no soft context for destination list management. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_dstl_softc_t *softd = arg;
+ int i;
+
+ for (i = -1; i <= IPL_LOGMAX; i++) {
+ while (softd->dstlist[i + 1] != NULL) {
+ ipf_dstlist_table_remove(softc, softd,
+ softd->dstlist[i + 1]);
+ }
+ }
+
+ ASSERT(softd->stats.ipls_numderefnodes == 0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_addr_find */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg1(I) - pointer to local context to use */
+/* arg2(I) - pointer to local context to use */
+/* arg3(I) - pointer to local context to use */
+/* arg4(I) - pointer to local context to use */
+/* */
+/* There is currently no such thing as searching a destination list for an */
+/* address so this function becomes a no-op. Its presence is required as */
+/* ipf_lookup_res_name() stores the "addr_find" function pointer in the */
+/* pointer passed in to it as funcptr, although it could be a generic null- */
+/* op function rather than a specific one. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_addr_find(softc, arg1, arg2, arg3, arg4)
+ ipf_main_softc_t *softc;
+ void *arg1, *arg3;
+ int arg2;
+ u_int arg4;
+{
+ return -1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_flush */
+/* Returns: int - number of objects deleted */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* fop(I) - pointer to lookup flush operation data */
+/* */
+/* Flush all of the destination tables that match the data passed in with */
+/* the iplookupflush_t. There are two ways to match objects: the device for */
+/* which they are to be used with and their name. */
+/* ------------------------------------------------------------------------ */
+static size_t
+ipf_dstlist_flush(softc, arg, fop)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupflush_t *fop;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ippool_dst_t *node, *next;
+ int n, i;
+
+ for (n = 0, i = -1; i <= IPL_LOGMAX; i++) {
+ if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i)
+ continue;
+ for (node = softd->dstlist[i + 1]; node != NULL; node = next) {
+ next = node->ipld_next;
+
+ if ((*fop->iplf_name != '\0') &&
+ strncmp(fop->iplf_name, node->ipld_name,
+ FR_GROUPLEN))
+ continue;
+
+ ipf_dstlist_table_remove(softc, softd, node);
+ n++;
+ }
+ }
+ return n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_iter_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* otype(I) - type of data structure to iterate through */
+/* unit(I) - device we are working with */
+/* data(I) - address of object in kernel space */
+/* */
+/* This function is called when the iteration token is being free'd and is */
+/* responsible for dropping the reference count of the structure it points */
+/* to. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_deref(softc, arg, otype, unit, data)
+ ipf_main_softc_t *softc;
+ void *arg;
+ int otype, unit;
+ void *data;
+{
+ if (data == NULL) {
+ IPFERROR(120001);
+ return EINVAL;
+ }
+
+ if (unit < -1 || unit > IPL_LOGMAX) {
+ IPFERROR(120002);
+ return EINVAL;
+ }
+
+ switch (otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data);
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data);
+ break;
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_iter_next */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - uid of process doing the ioctl */
+/* */
+/* This function is responsible for either selecting the next destination */
+/* list or node on a destination list to be returned as a user process */
+/* iterates through the list of destination lists or nodes. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_next(softc, arg, token, iter)
+ ipf_main_softc_t *softc;
+ void *arg;
+ ipftoken_t *token;
+ ipflookupiter_t *iter;
+{
+ ipf_dstnode_t zn, *nextnode = NULL, *node = NULL;
+ ippool_dst_t zero, *next = NULL, *dsttab = NULL;
+ ipf_dstl_softc_t *softd = arg;
+ int err = 0;
+ void *hint;
+
+ switch (iter->ili_otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ dsttab = token->ipt_data;
+ if (dsttab == NULL) {
+ next = softd->dstlist[(int)iter->ili_unit + 1];
+ } else {
+ next = dsttab->ipld_next;
+ }
+
+ if (next != NULL) {
+ ATOMIC_INC32(next->ipld_ref);
+ token->ipt_data = next;
+ hint = next->ipld_next;
+ } else {
+ bzero((char *)&zero, sizeof(zero));
+ next = &zero;
+ token->ipt_data = NULL;
+ hint = NULL;
+ }
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ node = token->ipt_data;
+ if (node == NULL) {
+ dsttab = ipf_dstlist_table_find(arg, iter->ili_unit,
+ iter->ili_name);
+ if (dsttab == NULL) {
+ IPFERROR(120004);
+ err = ESRCH;
+ nextnode = NULL;
+ } else {
+ if (dsttab->ipld_dests == NULL)
+ nextnode = NULL;
+ else
+ nextnode = *dsttab->ipld_dests;
+ dsttab = NULL;
+ }
+ } else {
+ nextnode = node->ipfd_next;
+ }
+
+ if (nextnode != NULL) {
+ MUTEX_ENTER(&nextnode->ipfd_lock);
+ nextnode->ipfd_ref++;
+ MUTEX_EXIT(&nextnode->ipfd_lock);
+ token->ipt_data = nextnode;
+ hint = nextnode->ipfd_next;
+ } else {
+ bzero((char *)&zn, sizeof(zn));
+ nextnode = &zn;
+ token->ipt_data = NULL;
+ hint = NULL;
+ }
+ break;
+ default :
+ IPFERROR(120003);
+ err = EINVAL;
+ break;
+ }
+
+ if (err != 0)
+ return err;
+
+ switch (iter->ili_otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ if (dsttab != NULL)
+ ipf_dstlist_table_deref(softc, arg, dsttab);
+ err = COPYOUT(next, iter->ili_data, sizeof(*next));
+ if (err != 0) {
+ IPFERROR(120005);
+ err = EFAULT;
+ }
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ if (node != NULL)
+ ipf_dstlist_node_deref(arg, node);
+ err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode));
+ if (err != 0) {
+ IPFERROR(120006);
+ err = EFAULT;
+ }
+ break;
+ }
+
+ if (hint == NULL)
+ ipf_token_mark_complete(token);
+
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_add */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - uid of process doing the ioctl */
+/* Locks: WRITE(ipf_poolrw) */
+/* */
+/* Add a new node to a destination list. To do this, we only copy in the */
+/* frdest_t structure because that contains the only data required from the */
+/* application to create a new node. The frdest_t doesn't contain the name */
+/* itself. When loading filter rules, fd_name is a 'pointer' to the name. */
+/* In this case, the 'pointer' does not work, instead it is the length of */
+/* the name and the name is immediately following the frdest_t structure. */
+/* fd_name must include the trailing \0, so it should be strlen(str) + 1. */
+/* For simple sanity checking, an upper bound on the size of fd_name is */
+/* imposed - 128. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_add(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstnode_t *node, **nodes;
+ ippool_dst_t *d;
+ frdest_t dest;
+ int err;
+
+ if (op->iplo_size < sizeof(frdest_t)) {
+ IPFERROR(120007);
+ return EINVAL;
+ }
+
+ err = COPYIN(op->iplo_struct, &dest, sizeof(dest));
+ if (err != 0) {
+ IPFERROR(120009);
+ return EFAULT;
+ }
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d == NULL) {
+ IPFERROR(120010);
+ return ESRCH;
+ }
+
+ switch (dest.fd_addr.adf_family)
+ {
+ case AF_INET :
+ case AF_INET6 :
+ break;
+ default :
+ IPFERROR(120019);
+ return EINVAL;
+ }
+
+ if (dest.fd_name < -1 || dest.fd_name > 128) {
+ IPFERROR(120018);
+ return EINVAL;
+ }
+
+ KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name);
+ if (node == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120008);
+ return ENOMEM;
+ }
+ bzero((char *)node, sizeof(*node) + dest.fd_name);
+
+ bcopy(&dest, &node->ipfd_dest, sizeof(dest));
+ node->ipfd_size = sizeof(*node) + dest.fd_name;
+
+ if (dest.fd_name > 0) {
+ /*
+ * fd_name starts out as the length of the string to copy
+ * in (including \0) and ends up being the offset from
+ * fd_names (0).
+ */
+ err = COPYIN((char *)op->iplo_struct + sizeof(dest),
+ node->ipfd_names, dest.fd_name);
+ if (err != 0) {
+ IPFERROR(120017);
+ KFREES(node, node->ipfd_size);
+ return EFAULT;
+ }
+ node->ipfd_dest.fd_name = 0;
+ } else {
+ node->ipfd_dest.fd_name = -1;
+ }
+
+ if (d->ipld_nodes == d->ipld_maxnodes) {
+ KMALLOCS(nodes, ipf_dstnode_t **,
+ sizeof(*nodes) * (d->ipld_maxnodes + 1));
+ if (nodes == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120022);
+ KFREES(node, node->ipfd_size);
+ return ENOMEM;
+ }
+ if (d->ipld_dests != NULL) {
+ bcopy(d->ipld_dests, nodes,
+ sizeof(*nodes) * d->ipld_maxnodes);
+ KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes);
+ nodes[0]->ipfd_pnext = nodes;
+ }
+ d->ipld_dests = nodes;
+ d->ipld_maxnodes++;
+ }
+ d->ipld_dests[d->ipld_nodes] = node;
+ d->ipld_nodes++;
+
+ if (d->ipld_nodes == 1) {
+ node->ipfd_pnext = d->ipld_dests;
+ } else if (d->ipld_nodes > 1) {
+ node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next;
+ }
+ *node->ipfd_pnext = node;
+
+ MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock");
+ node->ipfd_uid = uid;
+ node->ipfd_ref = 1;
+ if (node->ipfd_dest.fd_name == 0)
+ (void) ipf_resolvedest(softc, node->ipfd_names,
+ &node->ipfd_dest, AF_INET);
+#ifdef USE_INET6
+ if (node->ipfd_dest.fd_name == 0 &&
+ node->ipfd_dest.fd_ptr == (void *)-1)
+ (void) ipf_resolvedest(softc, node->ipfd_names,
+ &node->ipfd_dest, AF_INET6);
+#endif
+
+ softd->stats.ipls_numnodes++;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: arg(I) - pointer to local context to use */
+/* node(I) - pointer to destionation node to free */
+/* */
+/* Dereference the use count by one. If it drops to zero then we can assume */
+/* that it has been removed from any lists/tables and is ripe for freeing. */
+/* The pointer to context is required for the purpose of maintaining */
+/* statistics. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_deref(arg, node)
+ void *arg;
+ ipf_dstnode_t *node;
+{
+ ipf_dstl_softc_t *softd = arg;
+ int ref;
+
+ MUTEX_ENTER(&node->ipfd_lock);
+ ref = --node->ipfd_ref;
+ MUTEX_EXIT(&node->ipfd_lock);
+
+ if (ref > 0)
+ return 0;
+
+ if ((node->ipfd_flags & IPDST_DELETE) != 0)
+ softd->stats.ipls_numderefnodes--;
+ MUTEX_DESTROY(&node->ipfd_lock);
+ KFREES(node, node->ipfd_size);
+ softd->stats.ipls_numnodes--;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - uid of process doing the ioctl */
+/* */
+/* Look for a matching destination node on the named table and free it if */
+/* found. Because the name embedded in the frdest_t is variable in length, */
+/* it is necessary to allocate some memory locally, to complete this op. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_del(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstnode_t *node;
+ frdest_t frd, *temp;
+ ippool_dst_t *d;
+ size_t size;
+ int err;
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d == NULL) {
+ IPFERROR(120012);
+ return ESRCH;
+ }
+
+ err = COPYIN(op->iplo_struct, &frd, sizeof(frd));
+ if (err != 0) {
+ IPFERROR(120011);
+ return EFAULT;
+ }
+
+ size = sizeof(*temp) + frd.fd_name;
+ KMALLOCS(temp, frdest_t *, size);
+ if (temp == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120026);
+ return ENOMEM;
+ }
+
+ err = COPYIN(op->iplo_struct, temp, size);
+ if (err != 0) {
+ IPFERROR(120027);
+ return EFAULT;
+ }
+
+ MUTEX_ENTER(&d->ipld_lock);
+ for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) {
+ if ((uid != 0) && (node->ipfd_uid != uid))
+ continue;
+ if (node->ipfd_size != size)
+ continue;
+ if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6,
+ size - offsetof(frdest_t, fd_ip6))) {
+ ipf_dstlist_node_free(softd, d, node);
+ MUTEX_EXIT(&d->ipld_lock);
+ KFREES(temp, size);
+ return 0;
+ }
+ }
+ MUTEX_EXIT(&d->ipld_lock);
+ KFREES(temp, size);
+
+ return ESRCH;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_free */
+/* Returns: Nil */
+/* Parameters: softd(I) - pointer to the destination list context */
+/* d(I) - pointer to destination list */
+/* node(I) - pointer to node to free */
+/* Locks: MUTEX(ipld_lock) or WRITE(ipf_poolrw) */
+/* */
+/* Free the destination node by first removing it from any lists and then */
+/* checking if this was the last reference held to the object. While the */
+/* array of pointers to nodes is compacted, its size isn't reduced (by way */
+/* of allocating a new smaller one and copying) because the belief is that */
+/* it is likely the array will again reach that size. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_node_free(softd, d, node)
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *d;
+ ipf_dstnode_t *node;
+{
+ int i;
+
+ /*
+ * Compact the array of pointers to nodes.
+ */
+ for (i = 0; i < d->ipld_nodes; i++)
+ if (d->ipld_dests[i] == node)
+ break;
+ if (d->ipld_nodes - i > 1) {
+ bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i],
+ sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1));
+ }
+ d->ipld_nodes--;
+
+ if (node->ipfd_pnext != NULL)
+ *node->ipfd_pnext = node->ipfd_next;
+ if (node->ipfd_next != NULL)
+ node->ipfd_next->ipfd_pnext = node->ipfd_pnext;
+ node->ipfd_pnext = NULL;
+ node->ipfd_next = NULL;
+
+ if ((node->ipfd_flags & IPDST_DELETE) == 0) {
+ softd->stats.ipls_numderefnodes++;
+ node->ipfd_flags |= IPDST_DELETE;
+ }
+
+ ipf_dstlist_node_deref(softd, node);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_stats_get */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Return the current statistics for destination lists. This may be for all */
+/* of them or just information pertaining to a particular table. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_stats_get(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstl_stat_t stats;
+ int unit, i, err = 0;
+
+ if (op->iplo_size != sizeof(ipf_dstl_stat_t)) {
+ IPFERROR(120023);
+ return EINVAL;
+ }
+
+ stats = softd->stats;
+ unit = op->iplo_unit;
+ if (unit == IPL_LOGALL) {
+ for (i = 0; i <= IPL_LOGMAX; i++)
+ stats.ipls_list[i] = softd->dstlist[i];
+ } else if (unit >= 0 && unit <= IPL_LOGMAX) {
+ void *ptr;
+
+ if (op->iplo_name[0] != '\0')
+ ptr = ipf_dstlist_table_find(softd, unit,
+ op->iplo_name);
+ else
+ ptr = softd->dstlist[unit + 1];
+ stats.ipls_list[unit] = ptr;
+ } else {
+ IPFERROR(120024);
+ err = EINVAL;
+ }
+
+ if (err == 0) {
+ err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+ if (err != 0) {
+ IPFERROR(120025);
+ return EFAULT;
+ }
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_add */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Add a new destination table to the list of those available for the given */
+/* device. Because we seldom operate on these objects (find/add/delete), */
+/* they are just kept in a simple linked list. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_add(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ippool_dst_t user, *d, *new;
+ int unit, err;
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d != NULL) {
+ IPFERROR(120013);
+ return EEXIST;
+ }
+
+ err = COPYIN(op->iplo_struct, &user, sizeof(user));
+ if (err != 0) {
+ IPFERROR(120021);
+ return EFAULT;
+ }
+
+ KMALLOC(new, ippool_dst_t *);
+ if (new == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120014);
+ return ENOMEM;
+ }
+ bzero((char *)new, sizeof(*new));
+
+ MUTEX_INIT(&new->ipld_lock, "ipf dst table lock");
+
+ strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN);
+ unit = op->iplo_unit;
+ new->ipld_unit = unit;
+ new->ipld_policy = user.ipld_policy;
+ new->ipld_seed = ipf_random();
+ new->ipld_ref = 1;
+
+ new->ipld_pnext = softd->tails[unit + 1];
+ *softd->tails[unit + 1] = new;
+ softd->tails[unit + 1] = &new->ipld_next;
+ softd->stats.ipls_numlists++;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Find a named destinstion list table and delete it. If there are other */
+/* references to it, the caller isn't told. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_del(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ ippool_dst_t *d;
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d == NULL) {
+ IPFERROR(120015);
+ return ESRCH;
+ }
+
+ if (d->ipld_dests != NULL) {
+ IPFERROR(120016);
+ return EBUSY;
+ }
+
+ ipf_dstlist_table_remove(softc, arg, d);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_remove */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softd(I) - pointer to the destination list context */
+/* d(I) - pointer to destination list */
+/* */
+/* Remove a given destination list from existance. While the IPDST_DELETE */
+/* flag is set every time we call this function and the reference count is */
+/* non-zero, the "numdereflists" counter is always incremented because the */
+/* decision about whether it will be freed or not is not made here. This */
+/* means that the only action the code can take here is to treat it as if */
+/* it will become a detached. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_remove(softc, softd, d)
+ ipf_main_softc_t *softc;
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *d;
+{
+
+ if (softd->tails[d->ipld_unit + 1] == &d->ipld_next)
+ softd->tails[d->ipld_unit + 1] = d->ipld_pnext;
+
+ if (d->ipld_pnext != NULL)
+ *d->ipld_pnext = d->ipld_next;
+ if (d->ipld_next != NULL)
+ d->ipld_next->ipld_pnext = d->ipld_pnext;
+ d->ipld_pnext = NULL;
+ d->ipld_next = NULL;
+
+ ipf_dstlist_table_clearnodes(softd, d);
+
+ softd->stats.ipls_numdereflists++;
+ d->ipld_flags |= IPDST_DELETE;
+
+ ipf_dstlist_table_deref(softc, softd, d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_free */
+/* Returns: Nil */
+/* Parameters: softd(I) - pointer to the destination list context */
+/* d(I) - pointer to destination list */
+/* */
+/* Free up a destination list data structure and any other memory that was */
+/* directly allocated as part of creating it. Individual destination list */
+/* nodes are not freed. It is assumed the caller will have already emptied */
+/* the destination list. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_free(softd, d)
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *d;
+{
+ MUTEX_DESTROY(&d->ipld_lock);
+
+ if ((d->ipld_flags & IPDST_DELETE) != 0)
+ softd->stats.ipls_numdereflists--;
+ softd->stats.ipls_numlists--;
+
+ if (d->ipld_dests != NULL) {
+ KFREES(d->ipld_dests,
+ d->ipld_maxnodes * sizeof(*d->ipld_dests));
+ }
+
+ KFREE(d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Drops the reference count on a destination list table object and free's */
+/* it if 0 has been reached. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_deref(softc, arg, table)
+ ipf_main_softc_t *softc;
+ void *arg;
+ void *table;
+{
+ ippool_dst_t *d = table;
+
+ d->ipld_ref--;
+ if (d->ipld_ref > 0)
+ return d->ipld_ref;
+
+ ipf_dstlist_table_free(arg, d);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_clearnodes */
+/* Returns: Nil */
+/* Parameters: softd(I) - pointer to the destination list context */
+/* dst(I) - pointer to destination list */
+/* */
+/* Free all of the destination nodes attached to the given table. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_clearnodes(softd, dst)
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *dst;
+{
+ ipf_dstnode_t *node;
+
+ if (dst->ipld_dests == NULL)
+ return;
+
+ while ((node = *dst->ipld_dests) != NULL) {
+ ipf_dstlist_node_free(softd, dst, node);
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_find */
+/* Returns: int - 0 = success, else error */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - device we are working with */
+/* name(I) - destination table name to find */
+/* */
+/* Return a pointer to a destination table that matches the unit+name that */
+/* is passed in. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_table_find(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ippool_dst_t *d;
+
+ for (d = softd->dstlist[unit + 1]; d != NULL; d = d->ipld_next) {
+ if ((d->ipld_unit == unit) &&
+ !strncmp(d->ipld_name, name, FR_GROUPLEN)) {
+ return d;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_select_ref */
+/* Returns: void * - NULL = failure, else pointer to table */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - device we are working with */
+/* name(I) - destination table name to find */
+/* */
+/* Attempt to find a destination table that matches the name passed in and */
+/* if successful, bump up the reference count on it because we intend to */
+/* store the pointer to it somewhere else. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_select_ref(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
+{
+ ippool_dst_t *d;
+
+ d = ipf_dstlist_table_find(arg, unit, name);
+ if (d != NULL) {
+ MUTEX_ENTER(&d->ipld_lock);
+ d->ipld_ref++;
+ MUTEX_EXIT(&d->ipld_lock);
+ }
+ return d;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_select */
+/* Returns: void * - NULL = failure, else pointer to table */
+/* Parameters: fin(I) - pointer to packet information */
+/* d(I) - pointer to destination list */
+/* */
+/* Find the next node in the destination list to be used according to the */
+/* defined policy. Of these, "connection" is the most expensive policy to */
+/* implement as it always looks for the node with the least number of */
+/* connections associated with it. */
+/* */
+/* The hashes exclude the port numbers so that all protocols map to the */
+/* same destination. Otherwise, someone doing a ping would target a */
+/* different server than their TCP connection, etc. MD-5 is used to */
+/* transform the addressese into something random that the other end could */
+/* not easily guess and use in an attack. ipld_seed introduces an unknown */
+/* into the hash calculation to increase the difficult of an attacker */
+/* guessing the bucket. */
+/* */
+/* One final comment: mixing different address families in a single pool */
+/* will currently result in failures as the address family of the node is */
+/* only matched up with that in the packet as the last step. While this can */
+/* be coded around for the weighted connection and round-robin models, it */
+/* cannot be supported for the hash/random models as they do not search and */
+/* nor is the algorithm conducive to searching. */
+/* ------------------------------------------------------------------------ */
+static ipf_dstnode_t *
+ipf_dstlist_select(fin, d)
+ fr_info_t *fin;
+ ippool_dst_t *d;
+{
+ ipf_dstnode_t *node, *sel;
+ int connects;
+ u_32_t hash[4];
+ MD5_CTX ctx;
+ int family;
+ int x;
+
+ if (d->ipld_dests == NULL || *d->ipld_dests == NULL)
+ return NULL;
+
+ family = fin->fin_family;
+
+ MUTEX_ENTER(&d->ipld_lock);
+
+ switch (d->ipld_policy)
+ {
+ case IPLDP_ROUNDROBIN:
+ sel = d->ipld_selected;
+ if (sel == NULL) {
+ sel = *d->ipld_dests;
+ } else {
+ sel = sel->ipfd_next;
+ if (sel == NULL)
+ sel = *d->ipld_dests;
+ }
+ break;
+
+ case IPLDP_CONNECTION:
+ if (d->ipld_selected == NULL) {
+ sel = *d->ipld_dests;
+ break;
+ }
+
+ sel = d->ipld_selected;
+ connects = 0x7fffffff;
+ node = sel->ipfd_next;
+ if (node == NULL)
+ node = *d->ipld_dests;
+ while (node != d->ipld_selected) {
+ if (node->ipfd_states == 0) {
+ sel = node;
+ break;
+ }
+ if (node->ipfd_states < connects) {
+ sel = node;
+ connects = node->ipfd_states;
+ }
+ node = node->ipfd_next;
+ if (node == NULL)
+ node = *d->ipld_dests;
+ }
+ break;
+
+ case IPLDP_RANDOM :
+ x = ipf_random() % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ case IPLDP_HASHED :
+ MD5Init(&ctx);
+ MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+ MD5Update(&ctx, (u_char *)&fin->fin_src6,
+ sizeof(fin->fin_src6));
+ MD5Update(&ctx, (u_char *)&fin->fin_dst6,
+ sizeof(fin->fin_dst6));
+ MD5Final((u_char *)hash, &ctx);
+ x = hash[0] % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ case IPLDP_SRCHASH :
+ MD5Init(&ctx);
+ MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+ MD5Update(&ctx, (u_char *)&fin->fin_src6,
+ sizeof(fin->fin_src6));
+ MD5Final((u_char *)hash, &ctx);
+ x = hash[0] % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ case IPLDP_DSTHASH :
+ MD5Init(&ctx);
+ MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+ MD5Update(&ctx, (u_char *)&fin->fin_dst6,
+ sizeof(fin->fin_dst6));
+ MD5Final((u_char *)hash, &ctx);
+ x = hash[0] % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ default :
+ sel = NULL;
+ break;
+ }
+
+ if (sel->ipfd_dest.fd_addr.adf_family != family)
+ sel = NULL;
+ d->ipld_selected = sel;
+
+ MUTEX_EXIT(&d->ipld_lock);
+
+ return sel;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_select_node */
+/* Returns: int - -1 == failure, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* group(I) - destination pool to search */
+/* addr(I) - pointer to store selected address */
+/* pfdp(O) - pointer to storage for selected destination node */
+/* */
+/* This function is only responsible for obtaining the next IP address for */
+/* use and storing it in the caller's address space (addr). "addr" is only */
+/* used for storage if pfdp is NULL. No permanent reference is currently */
+/* kept on the node. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_dstlist_select_node(fin, group, addr, pfdp)
+ fr_info_t *fin;
+ void *group;
+ u_32_t *addr;
+ frdest_t *pfdp;
+{
+#ifdef USE_MUTEXES
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+#endif
+ ippool_dst_t *d = group;
+ ipf_dstnode_t *node;
+ frdest_t *fdp;
+
+ READ_ENTER(&softc->ipf_poolrw);
+
+ node = ipf_dstlist_select(fin, d);
+ if (node == NULL) {
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+ return -1;
+ }
+
+ if (pfdp != NULL) {
+ bcopy(&node->ipfd_dest, pfdp, sizeof(*pfdp));
+ } else {
+ if (fin->fin_family == AF_INET) {
+ addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
+ } else if (fin->fin_family == AF_INET6) {
+ addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
+ addr[1] = node->ipfd_dest.fd_addr.adf_addr.i6[1];
+ addr[2] = node->ipfd_dest.fd_addr.adf_addr.i6[2];
+ addr[3] = node->ipfd_dest.fd_addr.adf_addr.i6[3];
+ }
+ }
+
+ fdp = &node->ipfd_dest;
+ if (fdp->fd_ptr == NULL)
+ fdp->fd_ptr = fin->fin_ifp;
+
+ MUTEX_ENTER(&node->ipfd_lock);
+ node->ipfd_states++;
+ MUTEX_EXIT(&node->ipfd_lock);
+
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_expire */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* There are currently no objects to expire in destination lists. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_expire(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ return;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_sync */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* When a network interface appears or disappears, we need to revalidate */
+/* all of the network interface names that have been configured as a target */
+/* in a destination list. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_dstlist_sync(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstnode_t *node;
+ ippool_dst_t *list;
+ int i;
+ int j;
+
+ for (i = 0; i < IPL_LOGMAX; i++) {
+ for (list = softd->dstlist[i]; list != NULL;
+ list = list->ipld_next) {
+ for (j = 0; j < list->ipld_maxnodes; j++) {
+ node = list->ipld_dests[j];
+ if (node == NULL)
+ continue;
+ if (node->ipfd_dest.fd_name == -1)
+ continue;
+ (void) ipf_resolvedest(softc,
+ node->ipfd_names,
+ &node->ipfd_dest,
+ AF_INET);
+ }
+ }
+ }
+}
diff --git a/contrib/ipfilter/ip_dstlist.h b/contrib/ipfilter/ip_dstlist.h
new file mode 100644
index 0000000..e2885e5
--- /dev/null
+++ b/contrib/ipfilter/ip_dstlist.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: ip_dstlist.h,v 1.5.2.6 2012/07/22 08:04:23 darren_r Exp $
+ */
+
+#ifndef __IP_DSTLIST_H__
+#define __IP_DSTLIST_H__
+
+typedef struct ipf_dstnode {
+ struct ipf_dstnode *ipfd_next;
+ struct ipf_dstnode **ipfd_pnext;
+ ipfmutex_t ipfd_lock;
+ frdest_t ipfd_dest;
+ u_long ipfd_syncat;
+ int ipfd_flags;
+ int ipfd_size;
+ int ipfd_states;
+ int ipfd_ref;
+ int ipfd_uid;
+ char ipfd_names[1];
+} ipf_dstnode_t;
+
+typedef enum ippool_policy_e {
+ IPLDP_NONE = 0,
+ IPLDP_ROUNDROBIN,
+ IPLDP_CONNECTION,
+ IPLDP_RANDOM,
+ IPLDP_HASHED,
+ IPLDP_SRCHASH,
+ IPLDP_DSTHASH
+} ippool_policy_t;
+
+typedef struct ippool_dst {
+ struct ippool_dst *ipld_next;
+ struct ippool_dst **ipld_pnext;
+ ipfmutex_t ipld_lock;
+ int ipld_seed;
+ int ipld_unit;
+ int ipld_ref;
+ int ipld_flags;
+ int ipld_nodes;
+ int ipld_maxnodes;
+ ippool_policy_t ipld_policy;
+ ipf_dstnode_t **ipld_dests;
+ ipf_dstnode_t *ipld_selected;
+ char ipld_name[FR_GROUPLEN];
+} ippool_dst_t;
+
+#define IPDST_DELETE 0x01
+
+typedef struct dstlist_stat_s {
+ void *ipls_list[LOOKUP_POOL_SZ];
+ int ipls_numlists;
+ u_long ipls_nomem;
+ int ipls_numnodes;
+ int ipls_numdereflists;
+ int ipls_numderefnodes;
+} ipf_dstl_stat_t;
+
+extern ipf_lookup_t ipf_dstlist_backend;
+
+extern int ipf_dstlist_select_node __P((fr_info_t *, void *, u_32_t *,
+ frdest_t *));
+
+#endif /* __IP_DSTLIST_H__ */
diff --git a/contrib/ipfilter/ip_fil.c b/contrib/ipfilter/ip_fil.c
new file mode 100644
index 0000000..03e4093
--- /dev/null
+++ b/contrib/ipfilter/ip_fil.c
@@ -0,0 +1,884 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#include "ipf.h"
+#include "md5.h"
+#include "ipt.h"
+
+ipf_main_softc_t ipfmain;
+
+static struct ifnet **ifneta = NULL;
+static int nifs = 0;
+
+struct rtentry;
+
+static void ipf_setifpaddr __P((struct ifnet *, char *));
+void init_ifp __P((void));
+#if defined(__sgi) && (IRIX < 60500)
+static int no_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *));
+static int write_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *));
+#else
+# if TRU64 >= 1885
+static int no_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *, struct rtentry *, char *));
+static int write_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *, struct rtentry *, char *));
+# else
+static int no_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *, struct rtentry *));
+static int write_output __P((struct ifnet *, struct mbuf *,
+ struct sockaddr *, struct rtentry *));
+# endif
+#endif
+
+struct ifaddr {
+ struct sockaddr_storage ifa_addr;
+};
+
+int
+ipfattach(softc)
+ ipf_main_softc_t *softc;
+{
+ return 0;
+}
+
+
+int
+ipfdetach(softc)
+ ipf_main_softc_t *softc;
+{
+ return 0;
+}
+
+
+/*
+ * Filter ioctl interface.
+ */
+int
+ipfioctl(softc, dev, cmd, data, mode)
+ ipf_main_softc_t *softc;
+ int dev;
+ ioctlcmd_t cmd;
+ caddr_t data;
+ int mode;
+{
+ int error = 0, unit = 0, uid;
+
+ uid = getuid();
+ unit = dev;
+
+ SPL_NET(s);
+
+ error = ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, NULL);
+ if (error != -1) {
+ SPL_X(s);
+ return error;
+ }
+ SPL_X(s);
+ return error;
+}
+
+
+void
+ipf_forgetifp(softc, ifp)
+ ipf_main_softc_t *softc;
+ void *ifp;
+{
+ register frentry_t *f;
+
+ WRITE_ENTER(&softc->ipf_mutex);
+ for (f = softc->ipf_acct[0][softc->ipf_active]; (f != NULL);
+ f = f->fr_next)
+ if (f->fr_ifa == ifp)
+ f->fr_ifa = (void *)-1;
+ for (f = softc->ipf_acct[1][softc->ipf_active]; (f != NULL);
+ f = f->fr_next)
+ if (f->fr_ifa == ifp)
+ f->fr_ifa = (void *)-1;
+ for (f = softc->ipf_rules[0][softc->ipf_active]; (f != NULL);
+ f = f->fr_next)
+ if (f->fr_ifa == ifp)
+ f->fr_ifa = (void *)-1;
+ for (f = softc->ipf_rules[1][softc->ipf_active]; (f != NULL);
+ f = f->fr_next)
+ if (f->fr_ifa == ifp)
+ f->fr_ifa = (void *)-1;
+ RWLOCK_EXIT(&softc->ipf_mutex);
+ ipf_nat_sync(softc, ifp);
+ ipf_lookup_sync(softc, ifp);
+}
+
+
+static int
+#if defined(__sgi) && (IRIX < 60500)
+no_output(ifp, m, s)
+#else
+# if TRU64 >= 1885
+no_output (ifp, m, s, rt, cp)
+ char *cp;
+# else
+no_output(ifp, m, s, rt)
+# endif
+ struct rtentry *rt;
+#endif
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *s;
+{
+ return 0;
+}
+
+
+static int
+#if defined(__sgi) && (IRIX < 60500)
+write_output(ifp, m, s)
+#else
+# if TRU64 >= 1885
+write_output (ifp, m, s, rt, cp)
+ char *cp;
+# else
+write_output(ifp, m, s, rt)
+# endif
+ struct rtentry *rt;
+#endif
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *s;
+{
+ char fname[32];
+ mb_t *mb;
+ ip_t *ip;
+ int fd;
+
+ mb = (mb_t *)m;
+ ip = MTOD(mb, ip_t *);
+
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
+ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
+ sprintf(fname, "/tmp/%s", ifp->if_xname);
+#else
+ sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
+#endif
+ fd = open(fname, O_WRONLY|O_APPEND);
+ if (fd == -1) {
+ perror("open");
+ return -1;
+ }
+ write(fd, (char *)ip, ntohs(ip->ip_len));
+ close(fd);
+ return 0;
+}
+
+
+static void
+ipf_setifpaddr(ifp, addr)
+ struct ifnet *ifp;
+ char *addr;
+{
+#ifdef __sgi
+ struct in_ifaddr *ifa;
+#else
+ struct ifaddr *ifa;
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+ if (ifp->if_addrlist.tqh_first != NULL)
+#else
+# ifdef __sgi
+ if (ifp->in_ifaddr != NULL)
+# else
+ if (ifp->if_addrlist != NULL)
+# endif
+#endif
+ return;
+
+ ifa = (struct ifaddr *)malloc(sizeof(*ifa));
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+ ifp->if_addrlist.tqh_first = ifa;
+#else
+# ifdef __sgi
+ ifp->in_ifaddr = ifa;
+# else
+ ifp->if_addrlist = ifa;
+# endif
+#endif
+
+ if (ifa != NULL) {
+ struct sockaddr_in *sin;
+
+#ifdef __sgi
+ sin = (struct sockaddr_in *)&ifa->ia_addr;
+#else
+ sin = (struct sockaddr_in *)&ifa->ifa_addr;
+#endif
+#ifdef USE_INET6
+ if (index(addr, ':') != NULL) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
+ sin6->sin6_family = AF_INET6;
+ /* Abort if bad address. */
+ switch (inet_pton(AF_INET6, addr, &sin6->sin6_addr))
+ {
+ case 1:
+ break;
+ case -1:
+ perror("inet_pton");
+ abort();
+ break;
+ default:
+ abort();
+ break;
+ }
+ } else
+#endif
+ {
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = inet_addr(addr);
+ if (sin->sin_addr.s_addr == 0)
+ abort();
+ }
+ }
+}
+
+struct ifnet *
+get_unit(name, family)
+ char *name;
+ int family;
+{
+ struct ifnet *ifp, **ifpp, **old_ifneta;
+ char *addr;
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
+ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
+
+ if (!*name)
+ return NULL;
+
+ if (name == NULL)
+ name = "anon0";
+
+ addr = strchr(name, '=');
+ if (addr != NULL)
+ *addr++ = '\0';
+
+ for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
+ if (!strcmp(name, ifp->if_xname)) {
+ if (addr != NULL)
+ ipf_setifpaddr(ifp, addr);
+ return ifp;
+ }
+ }
+#else
+ char *s, ifname[LIFNAMSIZ+1];
+
+ if (name == NULL)
+ name = "anon0";
+
+ addr = strchr(name, '=');
+ if (addr != NULL)
+ *addr++ = '\0';
+
+ for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
+ COPYIFNAME(family, ifp, ifname);
+ if (!strcmp(name, ifname)) {
+ if (addr != NULL)
+ ipf_setifpaddr(ifp, addr);
+ return ifp;
+ }
+ }
+#endif
+
+ if (!ifneta) {
+ ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2);
+ if (!ifneta)
+ return NULL;
+ ifneta[1] = NULL;
+ ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp));
+ if (!ifneta[0]) {
+ free(ifneta);
+ return NULL;
+ }
+ nifs = 1;
+ } else {
+ old_ifneta = ifneta;
+ nifs++;
+ ifneta = (struct ifnet **)realloc(ifneta,
+ (nifs + 1) * sizeof(ifp));
+ if (!ifneta) {
+ free(old_ifneta);
+ nifs = 0;
+ return NULL;
+ }
+ ifneta[nifs] = NULL;
+ ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp));
+ if (!ifneta[nifs - 1]) {
+ nifs--;
+ return NULL;
+ }
+ }
+ ifp = ifneta[nifs - 1];
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+ TAILQ_INIT(&ifp->if_addrlist);
+#endif
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
+ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
+ (void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname));
+#else
+ s = name + strlen(name) - 1;
+ for (; s > name; s--) {
+ if (!ISDIGIT(*s)) {
+ s++;
+ break;
+ }
+ }
+
+ if ((s > name) && (*s != 0) && ISDIGIT(*s)) {
+ ifp->if_unit = atoi(s);
+ ifp->if_name = (char *)malloc(s - name + 1);
+ (void) strncpy(ifp->if_name, name, s - name);
+ ifp->if_name[s - name] = '\0';
+ } else {
+ ifp->if_name = strdup(name);
+ ifp->if_unit = -1;
+ }
+#endif
+ ifp->if_output = (void *)no_output;
+
+ if (addr != NULL) {
+ ipf_setifpaddr(ifp, addr);
+ }
+
+ return ifp;
+}
+
+
+char *
+get_ifname(ifp)
+ struct ifnet *ifp;
+{
+ static char ifname[LIFNAMSIZ];
+
+#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
+ sprintf(ifname, "%s", ifp->if_xname);
+#else
+ if (ifp->if_unit != -1)
+ sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
+ else
+ strcpy(ifname, ifp->if_name);
+#endif
+ return ifname;
+}
+
+
+
+void
+init_ifp()
+{
+ struct ifnet *ifp, **ifpp;
+ char fname[32];
+ int fd;
+
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
+ (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
+ for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
+ ifp->if_output = (void *)write_output;
+ sprintf(fname, "/tmp/%s", ifp->if_xname);
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
+ if (fd == -1)
+ perror("open");
+ else
+ close(fd);
+ }
+#else
+
+ for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) {
+ ifp->if_output = (void *)write_output;
+ sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit);
+ fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
+ if (fd == -1)
+ perror("open");
+ else
+ close(fd);
+ }
+#endif
+}
+
+
+int
+ipf_fastroute(m, mpp, fin, fdp)
+ mb_t *m, **mpp;
+ fr_info_t *fin;
+ frdest_t *fdp;
+{
+ struct ifnet *ifp;
+ ip_t *ip = fin->fin_ip;
+ frdest_t node;
+ int error = 0;
+ frentry_t *fr;
+ void *sifp;
+ int sout;
+
+ sifp = fin->fin_ifp;
+ sout = fin->fin_out;
+ fr = fin->fin_fr;
+ ip->ip_sum = 0;
+
+ if (!(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
+ (fdp->fd_type == FRD_DSTLIST)) {
+ bzero(&node, sizeof(node));
+ ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node);
+ fdp = &node;
+ }
+ ifp = fdp->fd_ptr;
+
+ if (ifp == NULL)
+ return 0; /* no routing table out here */
+
+ if (fin->fin_out == 0) {
+ fin->fin_ifp = ifp;
+ fin->fin_out = 1;
+ (void) ipf_acctpkt(fin, NULL);
+ fin->fin_fr = NULL;
+ if (!fr || !(fr->fr_flags & FR_RETMASK)) {
+ u_32_t pass;
+
+ (void) ipf_state_check(fin, &pass);
+ }
+
+ switch (ipf_nat_checkout(fin, NULL))
+ {
+ case 0 :
+ break;
+ case 1 :
+ ip->ip_sum = 0;
+ break;
+ case -1 :
+ error = -1;
+ goto done;
+ break;
+ }
+
+ }
+
+ m->mb_ifp = ifp;
+ printpacket(fin->fin_out, m);
+
+#if defined(__sgi) && (IRIX < 60500)
+ (*ifp->if_output)(ifp, (void *)ip, NULL);
+# if TRU64 >= 1885
+ (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
+# else
+ (*ifp->if_output)(ifp, (void *)m, NULL, 0);
+# endif
+#endif
+done:
+ fin->fin_ifp = sifp;
+ fin->fin_out = sout;
+ return error;
+}
+
+
+int
+ipf_send_reset(fin)
+ fr_info_t *fin;
+{
+ ipfkverbose("- TCP RST sent\n");
+ return 0;
+}
+
+
+int
+ipf_send_icmp_err(type, fin, dst)
+ int type;
+ fr_info_t *fin;
+ int dst;
+{
+ ipfkverbose("- ICMP unreachable sent\n");
+ return 0;
+}
+
+
+void
+m_freem(m)
+ mb_t *m;
+{
+ return;
+}
+
+
+void
+m_copydata(m, off, len, cp)
+ mb_t *m;
+ int off, len;
+ caddr_t cp;
+{
+ bcopy((char *)m + off, cp, len);
+}
+
+
+int
+ipfuiomove(buf, len, rwflag, uio)
+ caddr_t buf;
+ int len, rwflag;
+ struct uio *uio;
+{
+ int left, ioc, num, offset;
+ struct iovec *io;
+ char *start;
+
+ if (rwflag == UIO_READ) {
+ left = len;
+ ioc = 0;
+
+ offset = uio->uio_offset;
+
+ while ((left > 0) && (ioc < uio->uio_iovcnt)) {
+ io = uio->uio_iov + ioc;
+ num = io->iov_len;
+ if (num > left)
+ num = left;
+ start = (char *)io->iov_base + offset;
+ if (start > (char *)io->iov_base + io->iov_len) {
+ offset -= io->iov_len;
+ ioc++;
+ continue;
+ }
+ bcopy(buf, start, num);
+ uio->uio_resid -= num;
+ uio->uio_offset += num;
+ left -= num;
+ if (left > 0)
+ ioc++;
+ }
+ if (left > 0)
+ return EFAULT;
+ }
+ return 0;
+}
+
+
+u_32_t
+ipf_newisn(fin)
+ fr_info_t *fin;
+{
+ static int iss_seq_off = 0;
+ u_char hash[16];
+ u_32_t newiss;
+ MD5_CTX ctx;
+
+ /*
+ * Compute the base value of the ISS. It is a hash
+ * of (saddr, sport, daddr, dport, secret).
+ */
+ MD5Init(&ctx);
+
+ MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
+ sizeof(fin->fin_fi.fi_src));
+ MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
+ sizeof(fin->fin_fi.fi_dst));
+ MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
+
+ /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */
+
+ MD5Final(hash, &ctx);
+
+ memcpy(&newiss, hash, sizeof(newiss));
+
+ /*
+ * Now increment our "timer", and add it in to
+ * the computed value.
+ *
+ * XXX Use `addin'?
+ * XXX TCP_ISSINCR too large to use?
+ */
+ iss_seq_off += 0x00010000;
+ newiss += iss_seq_off;
+ return newiss;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nextipid */
+/* Returns: int - 0 == success, -1 == error (packet should be droppped) */
+/* Parameters: fin(I) - pointer to packet information */
+/* */
+/* Returns the next IPv4 ID to use for this packet. */
+/* ------------------------------------------------------------------------ */
+INLINE u_short
+ipf_nextipid(fin)
+ fr_info_t *fin;
+{
+ static u_short ipid = 0;
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ u_short id;
+
+ MUTEX_ENTER(&softc->ipf_rw);
+ if (fin->fin_pktnum != 0) {
+ /*
+ * The -1 is for aligned test results.
+ */
+ id = (fin->fin_pktnum - 1) & 0xffff;
+ } else {
+ }
+ id = ipid++;
+ MUTEX_EXIT(&softc->ipf_rw);
+
+ return id;
+}
+
+
+INLINE int
+ipf_checkv4sum(fin)
+ fr_info_t *fin;
+{
+
+ if (fin->fin_flx & FI_SHORT)
+ return 1;
+
+ if (ipf_checkl4sum(fin) == -1) {
+ fin->fin_flx |= FI_BAD;
+ return -1;
+ }
+ return 0;
+}
+
+
+#ifdef USE_INET6
+INLINE int
+ipf_checkv6sum(fin)
+ fr_info_t *fin;
+{
+ if (fin->fin_flx & FI_SHORT)
+ return 1;
+
+ if (ipf_checkl4sum(fin) == -1) {
+ fin->fin_flx |= FI_BAD;
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+
+#if 0
+/*
+ * See above for description, except that all addressing is in user space.
+ */
+int
+copyoutptr(softc, src, dst, size)
+ void *src, *dst;
+ size_t size;
+{
+ caddr_t ca;
+
+ bcopy(dst, (char *)&ca, sizeof(ca));
+ bcopy(src, ca, size);
+ return 0;
+}
+
+
+/*
+ * See above for description, except that all addressing is in user space.
+ */
+int
+copyinptr(src, dst, size)
+ void *src, *dst;
+ size_t size;
+{
+ caddr_t ca;
+
+ bcopy(src, (char *)&ca, sizeof(ca));
+ bcopy(ca, dst, size);
+ return 0;
+}
+#endif
+
+
+/*
+ * return the first IP Address associated with an interface
+ */
+int
+ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
+ ipf_main_softc_t *softc;
+ int v, atype;
+ void *ifptr;
+ i6addr_t *inp, *inpmask;
+{
+ struct ifnet *ifp = ifptr;
+#ifdef __sgi
+ struct in_ifaddr *ifa;
+#else
+ struct ifaddr *ifa;
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+ ifa = ifp->if_addrlist.tqh_first;
+#else
+# ifdef __sgi
+ ifa = (struct in_ifaddr *)ifp->in_ifaddr;
+# else
+ ifa = ifp->if_addrlist;
+# endif
+#endif
+ if (ifa != NULL) {
+ if (v == 4) {
+ struct sockaddr_in *sin, mask;
+
+ mask.sin_addr.s_addr = 0xffffffff;
+
+#ifdef __sgi
+ sin = (struct sockaddr_in *)&ifa->ia_addr;
+#else
+ sin = (struct sockaddr_in *)&ifa->ifa_addr;
+#endif
+
+ return ipf_ifpfillv4addr(atype, sin, &mask,
+ &inp->in4, &inpmask->in4);
+ }
+#ifdef USE_INET6
+ if (v == 6) {
+ struct sockaddr_in6 *sin6, mask;
+
+ sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr;
+ ((i6addr_t *)&mask.sin6_addr)->i6[0] = 0xffffffff;
+ ((i6addr_t *)&mask.sin6_addr)->i6[1] = 0xffffffff;
+ ((i6addr_t *)&mask.sin6_addr)->i6[2] = 0xffffffff;
+ ((i6addr_t *)&mask.sin6_addr)->i6[3] = 0xffffffff;
+ return ipf_ifpfillv6addr(atype, sin6, &mask,
+ inp, inpmask);
+ }
+#endif
+ }
+ return 0;
+}
+
+
+/*
+ * This function is not meant to be random, rather just produce a
+ * sequence of numbers that isn't linear to show "randomness".
+ */
+u_32_t
+ipf_random()
+{
+ static unsigned int last = 0xa5a5a5a5;
+ static int calls = 0;
+ int number;
+
+ calls++;
+
+ /*
+ * These are deliberately chosen to ensure that there is some
+ * attempt to test whether the output covers the range in test n18.
+ */
+ switch (calls)
+ {
+ case 1 :
+ number = 0;
+ break;
+ case 2 :
+ number = 4;
+ break;
+ case 3 :
+ number = 3999;
+ break;
+ case 4 :
+ number = 4000;
+ break;
+ case 5 :
+ number = 48999;
+ break;
+ case 6 :
+ number = 49000;
+ break;
+ default :
+ number = last;
+ last *= calls;
+ last++;
+ number ^= last;
+ break;
+ }
+ return number;
+}
+
+
+int
+ipf_verifysrc(fin)
+ fr_info_t *fin;
+{
+ return 1;
+}
+
+
+int
+ipf_inject(fin, m)
+ fr_info_t *fin;
+ mb_t *m;
+{
+ FREE_MB_T(m);
+
+ return 0;
+}
+
+
+u_int
+ipf_pcksum(fin, hlen, sum)
+ fr_info_t *fin;
+ int hlen;
+ u_int sum;
+{
+ u_short *sp;
+ u_int sum2;
+ int slen;
+
+ slen = fin->fin_plen - hlen;
+ sp = (u_short *)((u_char *)fin->fin_ip + hlen);
+
+ for (; slen > 1; slen -= 2)
+ sum += *sp++;
+ if (slen)
+ sum += ntohs(*(u_char *)sp << 8);
+ while (sum > 0xffff)
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum2 = (u_short)(~sum & 0xffff);
+
+ return sum2;
+}
+
+
+void *
+ipf_pullup(m, fin, plen)
+ mb_t *m;
+ fr_info_t *fin;
+ int plen;
+{
+ if (M_LEN(m) >= plen)
+ return fin->fin_ip;
+
+ /*
+ * Fake ipf_pullup failing
+ */
+ fin->fin_reason = FRB_PULLUP;
+ *fin->fin_mp = NULL;
+ fin->fin_m = NULL;
+ fin->fin_ip = NULL;
+ return NULL;
+}
diff --git a/contrib/ipfilter/ip_fil_compat.c b/contrib/ipfilter/ip_fil_compat.c
new file mode 100644
index 0000000..d0b356f
--- /dev/null
+++ b/contrib/ipfilter/ip_fil_compat.c
@@ -0,0 +1,4854 @@
+/*
+ * Copyright (C) 2002-2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define KERNEL 1
+# define _KERNEL 1
+#endif
+#if defined(__osf__)
+# define _PROTO_NET_H_
+#endif
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#if __FreeBSD_version >= 220000 && defined(_KERNEL)
+# include <sys/fcntl.h>
+# include <sys/filio.h>
+#else
+# include <sys/ioctl.h>
+#endif
+#if !defined(_KERNEL)
+# include <string.h>
+# define _KERNEL
+# ifdef __OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#endif
+#include <sys/socket.h>
+#if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
+# include "radix_ipf_local.h"
+# define _RADIX_H_
+#endif
+#include <net/if.h>
+#if defined(__FreeBSD__)
+# include <sys/cdefs.h>
+# include <sys/proc.h>
+#endif
+#if defined(_KERNEL)
+# include <sys/systm.h>
+# if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+# endif
+#endif
+#include <netinet/in.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_pool.h"
+#include "netinet/ip_htable.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_auth.h"
+/* END OF INCLUDES */
+
+/*
+ * NetBSD has moved to 64bit time_t for all architectures.
+ * For some, such as sparc64, there is no change because long is already
+ * 64bit, but for others (i386), there is...
+ */
+#ifdef IPFILTER_COMPAT
+
+# ifdef __NetBSD__
+typedef struct timeval_l {
+ long tv_sec;
+ long tv_usec;
+} timeval_l_t;
+# endif
+
+/* ------------------------------------------------------------------------ */
+
+typedef struct tcpinfo4 {
+ u_short ts_sport;
+ u_short ts_dport;
+ tcpdata_t ts_data[2];
+} tcpinfo4_t;
+
+static void ipf_v5tcpinfoto4 __P((tcpinfo_t *, tcpinfo4_t *));
+
+static void
+ipf_v5tcpinfoto4(v5, v4)
+ tcpinfo_t *v5;
+ tcpinfo4_t *v4;
+{
+ v4->ts_sport = v5->ts_sport;
+ v4->ts_dport = v5->ts_dport;
+ v4->ts_data[0] = v5->ts_data[0];
+ v4->ts_data[1] = v5->ts_data[1];
+}
+
+typedef struct fr_ip4 {
+ u_32_t fi_v:4;
+ u_32_t fi_xx:4;
+ u_32_t fi_tos:8;
+ u_32_t fi_ttl:8;
+ u_32_t fi_p:8;
+ u_32_t fi_optmsk;
+ i6addr_t fi_src;
+ i6addr_t fi_dst;
+ u_short ofi_secmsk;
+ u_short ofi_auth;
+ u_32_t fi_flx;
+ u_32_t fi_tcpmsk;
+ u_32_t fi_res1;
+} frip4_t;
+
+typedef struct frpcmp4 {
+ int frp_cmp;
+ u_short frp_port;
+ u_short frp_top;
+} frpcmp4_t;
+
+typedef struct frtuc4 {
+ u_char ftu_tcpfm;
+ u_char ftu_tcpf;
+ frpcmp4_t ftu_src;
+ frpcmp4_t ftu_dst;
+} frtuc4_t;
+
+typedef struct fripf4 {
+ frip4_t fri_ip;
+ frip4_t fri_mip;
+
+ u_short fri_icmpm;
+ u_short fri_icmp;
+
+ frtuc4_t fri_tuc;
+ int fri_satype;
+ int fri_datype;
+ int fri_sifpidx;
+ int fri_difpidx;
+} fripf4_t;
+
+typedef struct frdest_4 {
+ void *fd_ifp;
+ i6addr_t ofd_ip6;
+ char fd_ifname[LIFNAMSIZ];
+} frdest_4_t;
+
+/* ------------------------------------------------------------------------ */
+
+/* 5.1.0 new release (current)
+ * 4.1.34 changed the size of the time structure used for pps
+ * 4.1.16 moved the location of fr_flineno
+ * 4.1.0 base version
+ */
+typedef struct frentry_4_1_34 {
+ ipfmutex_t fr_lock;
+ struct frentry *fr_next;
+ struct frentry **fr_grp;
+ struct ipscan *fr_isc;
+ void *fr_ifas[4];
+ void *fr_ptr; /* for use with fr_arg */
+ char *fr_comment; /* text comment for rule */
+ int fr_ref; /* reference count - for grouping */
+ int fr_statecnt; /* state count - for limit rules */
+ int fr_flineno; /* line number from conf file */
+ U_QUAD_T fr_hits;
+ U_QUAD_T fr_bytes;
+ union {
+ struct timeval frp_lastpkt;
+ char frp_bytes[12];
+ } fr_lpu;
+ int fr_curpps;
+ union {
+ void *fru_data;
+ char *fru_caddr;
+ fripf4_t *fru_ipf;
+ frentfunc_t fru_func;
+ } fr_dun;
+ ipfunc_t fr_func; /* call this function */
+ int fr_dsize;
+ int fr_pps;
+ int fr_statemax; /* max reference count */
+ u_32_t fr_type;
+ u_32_t fr_flags; /* per-rule flags && options (see below) */
+ u_32_t fr_logtag; /* user defined log tag # */
+ u_32_t fr_collect; /* collection number */
+ u_int fr_arg; /* misc. numeric arg for rule */
+ u_int fr_loglevel; /* syslog log facility + priority */
+ u_int fr_age[2]; /* non-TCP timeouts */
+ u_char fr_v;
+ u_char fr_icode; /* return ICMP code */
+ char fr_group[FR_GROUPLEN]; /* group to which this rule belongs */
+ char fr_grhead[FR_GROUPLEN]; /* group # which this rule starts */
+ ipftag_t fr_nattag;
+ char fr_ifnames[4][LIFNAMSIZ];
+ char fr_isctag[16];
+ frdest_4_t fr_tifs[2]; /* "to"/"reply-to" interface */
+ frdest_4_t fr_dif; /* duplicate packet interface */
+ u_int fr_cksum; /* checksum on filter rules for performance */
+} frentry_4_1_34_t;
+
+typedef struct frentry_4_1_16 {
+ ipfmutex_t fr_lock;
+ struct frentry *fr_next;
+ struct frentry **fr_grp;
+ struct ipscan *fr_isc;
+ void *fr_ifas[4];
+ void *fr_ptr;
+ char *fr_comment;
+ int fr_ref;
+ int fr_statecnt;
+ int fr_flineno;
+ U_QUAD_T fr_hits;
+ U_QUAD_T fr_bytes;
+ union {
+#ifdef __NetBSD__
+ timeval_l_t frp_lastpkt;
+#else
+ struct timeval frp_lastpkt;
+#endif
+ } fr_lpu;
+ int fr_curpps;
+ union {
+ void *fru_data;
+ caddr_t fru_caddr;
+ fripf4_t *fru_ipf;
+ frentfunc_t fru_func;
+ } fr_dun;
+ ipfunc_t fr_func;
+ int fr_dsize;
+ int fr_pps;
+ int fr_statemax;
+ u_32_t fr_type;
+ u_32_t fr_flags;
+ u_32_t fr_logtag;
+ u_32_t fr_collect;
+ u_int fr_arg;
+ u_int fr_loglevel;
+ u_int fr_age[2];
+ u_char fr_v;
+ u_char fr_icode;
+ char fr_group[FR_GROUPLEN];
+ char fr_grhead[FR_GROUPLEN];
+ ipftag_t fr_nattag;
+ char fr_ifnames[4][LIFNAMSIZ];
+ char fr_isctag[16];
+ frdest_4_t fr_tifs[2];
+ frdest_4_t fr_dif;
+ u_int fr_cksum;
+} frentry_4_1_16_t;
+
+typedef struct frentry_4_1_0 {
+ ipfmutex_t fr_lock;
+ struct frentry *fr_next;
+ struct frentry **fr_grp;
+ struct ipscan *fr_isc;
+ void *fr_ifas[4];
+ void *fr_ptr;
+ char *fr_comment;
+ int fr_ref;
+ int fr_statecnt;
+ U_QUAD_T fr_hits;
+ U_QUAD_T fr_bytes;
+ union {
+#ifdef __NetBSD__
+ timeval_l_t frp_lastpkt;
+#else
+ struct timeval frp_lastpkt;
+#endif
+ } fr_lpu;
+ int fr_curpps;
+
+ union {
+ void *fru_data;
+ caddr_t fru_caddr;
+ fripf4_t *fru_ipf;
+ frentfunc_t fru_func;
+ } fr_dun;
+ /*
+ * Fields after this may not change whilst in the kernel.
+ */
+ ipfunc_t fr_func;
+ int fr_dsize;
+ int fr_pps;
+ int fr_statemax;
+ int fr_flineno;
+ u_32_t fr_type;
+ u_32_t fr_flags;
+ u_32_t fr_logtag;
+ u_32_t fr_collect;
+ u_int fr_arg;
+ u_int fr_loglevel;
+ u_int fr_age[2];
+ u_char fr_v;
+ u_char fr_icode;
+ char fr_group[FR_GROUPLEN];
+ char fr_grhead[FR_GROUPLEN];
+ ipftag_t fr_nattag;
+ char fr_ifnames[4][LIFNAMSIZ];
+ char fr_isctag[16];
+ frdest_4_t fr_tifs[2];
+ frdest_4_t fr_dif;
+ u_int fr_cksum;
+} frentry_4_1_0_t;
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * 5.1.0 new release (current)
+ * 4.1.32 removed both fin_state and fin_nat, added fin_pktnum
+ * 4.1.24 added fin_cksum
+ * 4.1.23 added fin_exthdr
+ * 4.1.11 added fin_ifname
+ * 4.1.4 added fin_hbuf
+ */
+typedef struct fr_info_4_1_32 {
+ void *fin_ifp; /* interface packet is `on' */
+ frip4_t fin_fi; /* IP Packet summary */
+ union {
+ u_short fid_16[2]; /* TCP/UDP ports, ICMP code/type */
+ u_32_t fid_32;
+ } fin_dat;
+ int fin_out; /* in or out ? 1 == out, 0 == in */
+ int fin_rev; /* state only: 1 = reverse */
+ u_short fin_hlen; /* length of IP header in bytes */
+ u_char ofin_tcpf; /* TCP header flags (SYN, ACK, etc) */
+ u_char fin_icode; /* ICMP error to return */
+ u_32_t fin_rule; /* rule # last matched */
+ char fin_group[FR_GROUPLEN]; /* group number, -1 for none */
+ struct frentry *fin_fr; /* last matching rule */
+ void *fin_dp; /* start of data past IP header */
+ int fin_dlen; /* length of data portion of packet */
+ int fin_plen;
+ int fin_ipoff; /* # bytes from buffer start to hdr */
+ u_short fin_id; /* IP packet id field */
+ u_short fin_off;
+ int fin_depth; /* Group nesting depth */
+ int fin_error; /* Error code to return */
+ int fin_cksum; /* -1 bad, 1 good, 0 not done */
+ u_int fin_pktnum;
+ void *fin_nattag;
+ void *fin_exthdr;
+ ip_t *ofin_ip;
+ mb_t **fin_mp; /* pointer to pointer to mbuf */
+ mb_t *fin_m; /* pointer to mbuf */
+#ifdef MENTAT
+ mb_t *fin_qfm; /* pointer to mblk where pkt starts */
+ void *fin_qpi;
+ char fin_ifname[LIFNAMSIZ];
+#endif
+#ifdef __sgi
+ void *fin_hbuf;
+#endif
+} fr_info_4_1_32_t;
+
+typedef struct fr_info_4_1_24 {
+ void *fin_ifp;
+ frip4_t fin_fi;
+ union {
+ u_short fid_16[2];
+ u_32_t fid_32;
+ } fin_dat;
+ int fin_out;
+ int fin_rev;
+ u_short fin_hlen;
+ u_char ofin_tcpf;
+ u_char fin_icode;
+ u_32_t fin_rule;
+ char fin_group[FR_GROUPLEN];
+ struct frentry *fin_fr;
+ void *fin_dp;
+ int fin_dlen;
+ int fin_plen;
+ int fin_ipoff;
+ u_short fin_id;
+ u_short fin_off;
+ int fin_depth;
+ int fin_error;
+ int fin_cksum;
+ void *fin_state;
+ void *fin_nat;
+ void *fin_nattag;
+ void *fin_exthdr;
+ ip_t *ofin_ip;
+ mb_t **fin_mp;
+ mb_t *fin_m;
+#ifdef MENTAT
+ mb_t *fin_qfm;
+ void *fin_qpi;
+ char fin_ifname[LIFNAMSIZ];
+#endif
+#ifdef __sgi
+ void *fin_hbuf;
+#endif
+} fr_info_4_1_24_t;
+
+typedef struct fr_info_4_1_23 {
+ void *fin_ifp;
+ frip4_t fin_fi;
+ union {
+ u_short fid_16[2];
+ u_32_t fid_32;
+ } fin_dat;
+ int fin_out;
+ int fin_rev;
+ u_short fin_hlen;
+ u_char ofin_tcpf;
+ u_char fin_icode;
+ u_32_t fin_rule;
+ char fin_group[FR_GROUPLEN];
+ struct frentry *fin_fr;
+ void *fin_dp;
+ int fin_dlen;
+ int fin_plen;
+ int fin_ipoff;
+ u_short fin_id;
+ u_short fin_off;
+ int fin_depth;
+ int fin_error;
+ void *fin_state;
+ void *fin_nat;
+ void *fin_nattag;
+ void *fin_exthdr;
+ ip_t *ofin_ip;
+ mb_t **fin_mp;
+ mb_t *fin_m;
+#ifdef MENTAT
+ mb_t *fin_qfm;
+ void *fin_qpi;
+ char fin_ifname[LIFNAMSIZ];
+#endif
+#ifdef __sgi
+ void *fin_hbuf;
+#endif
+} fr_info_4_1_23_t;
+
+typedef struct fr_info_4_1_11 {
+ void *fin_ifp;
+ frip4_t fin_fi;
+ union {
+ u_short fid_16[2];
+ u_32_t fid_32;
+ } fin_dat;
+ int fin_out;
+ int fin_rev;
+ u_short fin_hlen;
+ u_char ofin_tcpf;
+ u_char fin_icode;
+ u_32_t fin_rule;
+ char fin_group[FR_GROUPLEN];
+ struct frentry *fin_fr;
+ void *fin_dp;
+ int fin_dlen;
+ int fin_plen;
+ int fin_ipoff;
+ u_short fin_id;
+ u_short fin_off;
+ int fin_depth;
+ int fin_error;
+ void *fin_state;
+ void *fin_nat;
+ void *fin_nattag;
+ ip_t *ofin_ip;
+ mb_t **fin_mp;
+ mb_t *fin_m;
+#ifdef MENTAT
+ mb_t *fin_qfm;
+ void *fin_qpi;
+ char fin_ifname[LIFNAMSIZ];
+#endif
+#ifdef __sgi
+ void *fin_hbuf;
+#endif
+} fr_info_4_1_11_t;
+
+/* ------------------------------------------------------------------------ */
+
+typedef struct filterstats_4_1 {
+ 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_short; /* packets which are short */
+ 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_tcpbad; /* TCP checksum check failures */
+ u_long fr_pull[2]; /* good and bad pullup attempts */
+ u_long fr_badsrc; /* source received doesn't match route */
+ u_long fr_badttl; /* TTL in packet doesn't reach minimum */
+ u_long fr_bad; /* bad IP packets to the filter */
+ u_long fr_ipv6; /* IPv6 packets in/out */
+ u_long fr_ppshit; /* dropped because of pps ceiling */
+ u_long fr_ipud; /* IP id update failures */
+} filterstats_4_1_t;
+
+/*
+ * 5.1.0 new release (current)
+ * 4.1.33 changed the size of f_locks from IPL_LOGMAX to IPL_LOGSIZE
+ */
+typedef struct friostat_4_1_33 {
+ struct filterstats_4_1 of_st[2];
+ struct frentry *f_ipf[2][2];
+ struct frentry *f_acct[2][2];
+ struct frentry *f_ipf6[2][2];
+ struct frentry *f_acct6[2][2];
+ struct frentry *f_auth;
+ struct frgroup *f_groups[IPL_LOGSIZE][2];
+ u_long f_froute[2];
+ u_long f_ticks;
+ int f_locks[IPL_LOGSIZE];
+ size_t f_kmutex_sz;
+ size_t f_krwlock_sz;
+ int f_defpass; /* default pass - from fr_pass */
+ int f_active; /* 1 or 0 - active rule set */
+ int f_running; /* 1 if running, else 0 */
+ int f_logging; /* 1 if enabled, else 0 */
+ int f_features;
+ char f_version[32]; /* version string */
+} friostat_4_1_33_t;
+
+typedef struct friostat_4_1_0 {
+ struct filterstats_4_1 of_st[2];
+ struct frentry *f_ipf[2][2];
+ struct frentry *f_acct[2][2];
+ struct frentry *f_ipf6[2][2];
+ struct frentry *f_acct6[2][2];
+ struct frentry *f_auth;
+ struct frgroup *f_groups[IPL_LOGSIZE][2];
+ u_long f_froute[2];
+ u_long f_ticks;
+ int f_locks[IPL_LOGMAX];
+ size_t f_kmutex_sz;
+ size_t f_krwlock_sz;
+ int f_defpass;
+ int f_active;
+ int f_running;
+ int f_logging;
+ int f_features;
+ char f_version[32];
+} friostat_4_1_0_t;
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * 5.1.0 new release (current)
+ * 4.1.14 added in_lock
+ */
+typedef struct ipnat_4_1_14 {
+ ipfmutex_t in_lock;
+ struct ipnat *in_next; /* NAT rule list next */
+ struct ipnat *in_rnext; /* rdr rule hash next */
+ struct ipnat **in_prnext; /* prior rdr next ptr */
+ struct ipnat *in_mnext; /* map rule hash next */
+ struct ipnat **in_pmnext; /* prior map next ptr */
+ struct ipftq *in_tqehead[2];
+ void *in_ifps[2];
+ void *in_apr;
+ char *in_comment;
+ i6addr_t in_next6;
+ u_long in_space;
+ u_long in_hits;
+ u_int in_use;
+ u_int in_hv;
+ int in_flineno; /* conf. file line number */
+ u_short in_pnext;
+ u_char in_v;
+ u_char in_xxx;
+ /* From here to the end is covered by IPN_CMPSIZ */
+ u_32_t in_flags;
+ u_32_t in_mssclamp; /* if != 0 clamp MSS to this */
+ u_int in_age[2];
+ int in_redir; /* see below for values */
+ int in_p; /* protocol. */
+ i6addr_t in_in[2];
+ i6addr_t in_out[2];
+ i6addr_t in_src[2];
+ frtuc4_t in_tuc;
+ u_short in_port[2];
+ u_short in_ppip; /* ports per IP. */
+ u_short in_ippip; /* IP #'s per IP# */
+ char in_ifnames[2][LIFNAMSIZ];
+ char in_plabel[APR_LABELLEN]; /* proxy label. */
+ ipftag_t in_tag;
+} ipnat_4_1_14_t;
+
+typedef struct ipnat_4_1_0 {
+ struct ipnat *in_next;
+ struct ipnat *in_rnext;
+ struct ipnat **in_prnext;
+ struct ipnat *in_mnext;
+ struct ipnat **in_pmnext;
+ struct ipftq *in_tqehead[2];
+ void *in_ifps[2];
+ void *in_apr;
+ char *in_comment;
+ i6addr_t in_next6;
+ u_long in_space;
+ u_long in_hits;
+ u_int in_use;
+ u_int in_hv;
+ int in_flineno;
+ u_short in_pnext;
+ u_char in_v;
+ u_char in_xxx;
+ u_32_t in_flags;
+ u_32_t in_mssclamp;
+ u_int in_age[2];
+ int in_redir;
+ int in_p;
+ i6addr_t in_in[2];
+ i6addr_t in_out[2];
+ i6addr_t in_src[2];
+ frtuc4_t in_tuc;
+ u_short in_port[2];
+ u_short in_ppip;
+ u_short in_ippip;
+ char in_ifnames[2][LIFNAMSIZ];
+ char in_plabel[APR_LABELLEN];
+ ipftag_t in_tag;
+} ipnat_4_1_0_t;
+
+/* ------------------------------------------------------------------------ */
+
+typedef struct natlookup_4_1_1 {
+ struct in_addr onl_inip;
+ struct in_addr onl_outip;
+ struct in_addr onl_realip;
+ int nl_flags;
+ u_short nl_inport;
+ u_short nl_outport;
+ u_short nl_realport;
+} natlookup_4_1_1_t;
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * 4.1.25 added nat_seqnext (current)
+ * 4.1.14 added nat_redir
+ * 4.1.3 moved nat_rev
+ * 4.1.2 added nat_rev
+ */
+typedef struct nat_4_1_25 {
+ ipfmutex_t nat_lock;
+ struct nat_4_1_25 *nat_next;
+ struct nat_4_1_25 **nat_pnext;
+ struct nat_4_1_25 *nat_hnext[2];
+ struct nat_4_1_25 **nat_phnext[2];
+ struct hostmap *nat_hm;
+ void *nat_data;
+ struct nat_4_1_25 **nat_me;
+ struct ipstate *nat_state;
+ struct ap_session *nat_aps;
+ frentry_t *nat_fr;
+ struct ipnat_4_1_14 *nat_ptr;
+ void *nat_ifps[2];
+ void *nat_sync;
+ ipftqent_t nat_tqe;
+ u_32_t nat_flags;
+ u_32_t nat_sumd[2];
+ u_32_t nat_ipsumd;
+ u_32_t nat_mssclamp;
+ i6addr_t nat_inip6;
+ i6addr_t nat_outip6;
+ i6addr_t nat_oip6;
+ U_QUAD_T nat_pkts[2];
+ U_QUAD_T nat_bytes[2];
+ union {
+ udpinfo_t nat_unu;
+ tcpinfo4_t nat_unt;
+ icmpinfo_t nat_uni;
+ greinfo_t nat_ugre;
+ } nat_un;
+ u_short nat_oport;
+ u_short nat_use;
+ u_char nat_p;
+ int nat_dir;
+ int nat_ref;
+ int nat_hv[2];
+ char nat_ifnames[2][LIFNAMSIZ];
+ int nat_rev;
+ int nat_redir;
+ u_32_t nat_seqnext[2];
+} nat_4_1_25_t;
+
+typedef struct nat_4_1_14 {
+ ipfmutex_t nat_lock;
+ struct nat *nat_next;
+ struct nat **nat_pnext;
+ struct nat *nat_hnext[2];
+ struct nat **nat_phnext[2];
+ struct hostmap *nat_hm;
+ void *nat_data;
+ struct nat **nat_me;
+ struct ipstate *nat_state;
+ struct ap_session *nat_aps;
+ frentry_t *nat_fr;
+ struct ipnat *nat_ptr;
+ void *nat_ifps[2];
+ void *nat_sync;
+ ipftqent_t nat_tqe;
+ u_32_t nat_flags;
+ u_32_t nat_sumd[2];
+ u_32_t nat_ipsumd;
+ u_32_t nat_mssclamp;
+ i6addr_t nat_inip6;
+ i6addr_t nat_outip6;
+ i6addr_t nat_oip6;
+ U_QUAD_T nat_pkts[2];
+ U_QUAD_T nat_bytes[2];
+ union {
+ udpinfo_t nat_unu;
+ tcpinfo4_t nat_unt;
+ icmpinfo_t nat_uni;
+ greinfo_t nat_ugre;
+ } nat_un;
+ u_short nat_oport;
+ u_short nat_use;
+ u_char nat_p;
+ int nat_dir;
+ int nat_ref;
+ int nat_hv[2];
+ char nat_ifnames[2][LIFNAMSIZ];
+ int nat_rev;
+ int nat_redir;
+} nat_4_1_14_t;
+
+typedef struct nat_4_1_3 {
+ ipfmutex_t nat_lock;
+ struct nat *nat_next;
+ struct nat **nat_pnext;
+ struct nat *nat_hnext[2];
+ struct nat **nat_phnext[2];
+ struct hostmap *nat_hm;
+ void *nat_data;
+ struct nat **nat_me;
+ struct ipstate *nat_state;
+ struct ap_session *nat_aps;
+ frentry_t *nat_fr;
+ struct ipnat *nat_ptr;
+ void *nat_ifps[2];
+ void *nat_sync;
+ ipftqent_t nat_tqe;
+ u_32_t nat_flags;
+ u_32_t nat_sumd[2];
+ u_32_t nat_ipsumd;
+ u_32_t nat_mssclamp;
+ i6addr_t nat_inip6;
+ i6addr_t nat_outip6;
+ i6addr_t nat_oip6;
+ U_QUAD_T nat_pkts[2];
+ U_QUAD_T nat_bytes[2];
+ union {
+ udpinfo_t nat_unu;
+ tcpinfo4_t nat_unt;
+ icmpinfo_t nat_uni;
+ greinfo_t nat_ugre;
+ } nat_un;
+ u_short nat_oport;
+ u_short nat_use;
+ u_char nat_p;
+ int nat_dir;
+ int nat_ref;
+ int nat_hv[2];
+ char nat_ifnames[2][LIFNAMSIZ];
+ int nat_rev;
+} nat_4_1_3_t;
+
+
+
+typedef struct nat_save_4_1_34 {
+ void *ipn_next;
+ struct nat_4_1_25 ipn_nat;
+ struct ipnat_4_1_14 ipn_ipnat;
+ struct frentry_4_1_34 ipn_fr;
+ int ipn_dsize;
+ char ipn_data[4];
+} nat_save_4_1_34_t;
+
+typedef struct nat_save_4_1_16 {
+ void *ipn_next;
+ nat_4_1_14_t ipn_nat;
+ ipnat_t ipn_ipnat;
+ frentry_4_1_16_t ipn_fr;
+ int ipn_dsize;
+ char ipn_data[4];
+} nat_save_4_1_16_t;
+
+typedef struct nat_save_4_1_14 {
+ void *ipn_next;
+ nat_4_1_14_t ipn_nat;
+ ipnat_t ipn_ipnat;
+ frentry_4_1_0_t ipn_fr;
+ int ipn_dsize;
+ char ipn_data[4];
+} nat_save_4_1_14_t;
+
+typedef struct nat_save_4_1_3 {
+ void *ipn_next;
+ nat_4_1_3_t ipn_nat;
+ ipnat_4_1_0_t ipn_ipnat;
+ frentry_4_1_0_t ipn_fr;
+ int ipn_dsize;
+ char ipn_data[4];
+} nat_save_4_1_3_t;
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * 5.1.0 new release (current)
+ * 4.1.32 added ns_uncreate
+ * 4.1.27 added ns_orphans
+ * 4.1.16 added ns_ticks
+ */
+typedef struct natstat_4_1_32 {
+ u_long ns_mapped[2];
+ u_long ns_rules;
+ u_long ns_added;
+ u_long ns_expire;
+ u_long ns_inuse;
+ u_long ns_logged;
+ u_long ns_logfail;
+ u_long ns_memfail;
+ u_long ns_badnat;
+ u_long ns_addtrpnt;
+ nat_t **ns_table[2];
+ hostmap_t **ns_maptable;
+ ipnat_t *ns_list;
+ void *ns_apslist;
+ u_int ns_wilds;
+ u_int ns_nattab_sz;
+ u_int ns_nattab_max;
+ u_int ns_rultab_sz;
+ u_int ns_rdrtab_sz;
+ u_int ns_trpntab_sz;
+ u_int ns_hostmap_sz;
+ nat_t *ns_instances;
+ hostmap_t *ns_maplist;
+ u_long *ns_bucketlen[2];
+ u_long ns_ticks;
+ u_int ns_orphans;
+ u_long ns_uncreate[2][2];
+} natstat_4_1_32_t;
+
+typedef struct natstat_4_1_27 {
+ u_long ns_mapped[2];
+ u_long ns_rules;
+ u_long ns_added;
+ u_long ns_expire;
+ u_long ns_inuse;
+ u_long ns_logged;
+ u_long ns_logfail;
+ u_long ns_memfail;
+ u_long ns_badnat;
+ u_long ns_addtrpnt;
+ nat_t **ns_table[2];
+ hostmap_t **ns_maptable;
+ ipnat_t *ns_list;
+ void *ns_apslist;
+ u_int ns_wilds;
+ u_int ns_nattab_sz;
+ u_int ns_nattab_max;
+ u_int ns_rultab_sz;
+ u_int ns_rdrtab_sz;
+ u_int ns_trpntab_sz;
+ u_int ns_hostmap_sz;
+ nat_t *ns_instances;
+ hostmap_t *ns_maplist;
+ u_long *ns_bucketlen[2];
+ u_long ns_ticks;
+ u_int ns_orphans;
+} natstat_4_1_27_t;
+
+typedef struct natstat_4_1_16 {
+ u_long ns_mapped[2];
+ u_long ns_rules;
+ u_long ns_added;
+ u_long ns_expire;
+ u_long ns_inuse;
+ u_long ns_logged;
+ u_long ns_logfail;
+ u_long ns_memfail;
+ u_long ns_badnat;
+ u_long ns_addtrpnt;
+ nat_t **ns_table[2];
+ hostmap_t **ns_maptable;
+ ipnat_t *ns_list;
+ void *ns_apslist;
+ u_int ns_wilds;
+ u_int ns_nattab_sz;
+ u_int ns_nattab_max;
+ u_int ns_rultab_sz;
+ u_int ns_rdrtab_sz;
+ u_int ns_trpntab_sz;
+ u_int ns_hostmap_sz;
+ nat_t *ns_instances;
+ hostmap_t *ns_maplist;
+ u_long *ns_bucketlen[2];
+ u_long ns_ticks;
+} natstat_4_1_16_t;
+
+typedef struct natstat_4_1_0 {
+ u_long ns_mapped[2];
+ u_long ns_rules;
+ u_long ns_added;
+ u_long ns_expire;
+ u_long ns_inuse;
+ u_long ns_logged;
+ u_long ns_logfail;
+ u_long ns_memfail;
+ u_long ns_badnat;
+ u_long ns_addtrpnt;
+ nat_t **ns_table[2];
+ hostmap_t **ns_maptable;
+ ipnat_t *ns_list;
+ void *ns_apslist;
+ u_int ns_wilds;
+ u_int ns_nattab_sz;
+ u_int ns_nattab_max;
+ u_int ns_rultab_sz;
+ u_int ns_rdrtab_sz;
+ u_int ns_trpntab_sz;
+ u_int ns_hostmap_sz;
+ nat_t *ns_instances;
+ hostmap_t *ns_maplist;
+ u_long *ns_bucketlen[2];
+} natstat_4_1_0_t;
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * 5.1.0 new release (current)
+ * 4.1.32 fra_info:removed both fin_state & fin_nat, added fin_pktnum
+ * 4.1.29 added fra_flx
+ * 4.1.24 fra_info:added fin_cksum
+ * 4.1.23 fra_info:added fin_exthdr
+ * 4.1.11 fra_info:added fin_ifname
+ * 4.1.4 fra_info:added fin_hbuf
+ */
+
+typedef struct frauth_4_1_32 {
+ int fra_age;
+ int fra_len;
+ int fra_index;
+ u_32_t fra_pass;
+ fr_info_4_1_32_t fra_info;
+ char *fra_buf;
+ u_32_t fra_flx;
+#ifdef MENTAT
+ queue_t *fra_q;
+ mb_t *fra_m;
+#endif
+} frauth_4_1_32_t;
+
+typedef struct frauth_4_1_29 {
+ int fra_age;
+ int fra_len;
+ int fra_index;
+ u_32_t fra_pass;
+ fr_info_4_1_24_t fra_info;
+ char *fra_buf;
+ u_32_t fra_flx;
+#ifdef MENTAT
+ queue_t *fra_q;
+ mb_t *fra_m;
+#endif
+} frauth_4_1_29_t;
+
+typedef struct frauth_4_1_24 {
+ int fra_age;
+ int fra_len;
+ int fra_index;
+ u_32_t fra_pass;
+ fr_info_4_1_24_t fra_info;
+ char *fra_buf;
+#ifdef MENTAT
+ queue_t *fra_q;
+ mb_t *fra_m;
+#endif
+} frauth_4_1_24_t;
+
+typedef struct frauth_4_1_23 {
+ int fra_age;
+ int fra_len;
+ int fra_index;
+ u_32_t fra_pass;
+ fr_info_4_1_23_t fra_info;
+ char *fra_buf;
+#ifdef MENTAT
+ queue_t *fra_q;
+ mb_t *fra_m;
+#endif
+} frauth_4_1_23_t;
+
+typedef struct frauth_4_1_11 {
+ int fra_age;
+ int fra_len;
+ int fra_index;
+ u_32_t fra_pass;
+ fr_info_4_1_11_t fra_info;
+ char *fra_buf;
+#ifdef MENTAT
+ queue_t *fra_q;
+ mb_t *fra_m;
+#endif
+} frauth_4_1_11_t;
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * 5.1.0 new release (current)
+ * 4.1.16 removed is_nat
+ */
+typedef struct ipstate_4_1_16 {
+ ipfmutex_t is_lock;
+ struct ipstate *is_next;
+ struct ipstate **is_pnext;
+ struct ipstate *is_hnext;
+ struct ipstate **is_phnext;
+ struct ipstate **is_me;
+ void *is_ifp[4];
+ void *is_sync;
+ frentry_t *is_rule;
+ struct ipftq *is_tqehead[2];
+ struct ipscan *is_isc;
+ U_QUAD_T is_pkts[4];
+ U_QUAD_T is_bytes[4];
+ U_QUAD_T is_icmppkts[4];
+ struct ipftqent is_sti;
+ u_int is_frage[2];
+ int is_ref; /* reference count */
+ int is_isninc[2];
+ u_short is_sumd[2];
+ i6addr_t is_src;
+ i6addr_t is_dst;
+ u_int is_pass;
+ u_char is_p; /* Protocol */
+ u_char is_v;
+ u_32_t is_hv;
+ u_32_t is_tag;
+ u_32_t is_opt[2]; /* packet options set */
+ u_32_t is_optmsk[2]; /* " " mask */
+ u_short is_sec; /* security options set */
+ u_short is_secmsk; /* " " mask */
+ u_short is_auth; /* authentication options set */
+ u_short is_authmsk; /* " " mask */
+ union {
+ icmpinfo_t is_ics;
+ tcpinfo4_t is_ts;
+ udpinfo_t is_us;
+ greinfo_t is_ug;
+ } is_ps;
+ u_32_t is_flags;
+ int is_flx[2][2];
+ u_32_t is_rulen; /* rule number when created */
+ u_32_t is_s0[2];
+ u_short is_smsk[2];
+ char is_group[FR_GROUPLEN];
+ char is_sbuf[2][16];
+ char is_ifname[4][LIFNAMSIZ];
+} ipstate_4_1_16_t;
+
+typedef struct ipstate_4_1_0 {
+ ipfmutex_t is_lock;
+ struct ipstate *is_next;
+ struct ipstate **is_pnext;
+ struct ipstate *is_hnext;
+ struct ipstate **is_phnext;
+ struct ipstate **is_me;
+ void *is_ifp[4];
+ void *is_sync;
+ void *is_nat[2];
+ frentry_t *is_rule;
+ struct ipftq *is_tqehead[2];
+ struct ipscan *is_isc;
+ U_QUAD_T is_pkts[4];
+ U_QUAD_T is_bytes[4];
+ U_QUAD_T is_icmppkts[4];
+ struct ipftqent is_sti;
+ u_int is_frage[2];
+ int is_ref;
+ int is_isninc[2];
+ u_short is_sumd[2];
+ i6addr_t is_src;
+ i6addr_t is_dst;
+ u_int is_pass;
+ u_char is_p;
+ u_char is_v;
+ u_32_t is_hv;
+ u_32_t is_tag;
+ u_32_t is_opt[2];
+ u_32_t is_optmsk[2];
+ u_short is_sec;
+ u_short is_secmsk;
+ u_short is_auth;
+ u_short is_authmsk;
+ union {
+ icmpinfo_t is_ics;
+ tcpinfo4_t is_ts;
+ udpinfo_t is_us;
+ greinfo_t is_ug;
+ } is_ps;
+ u_32_t is_flags;
+ int is_flx[2][2];
+ u_32_t is_rulen;
+ u_32_t is_s0[2];
+ u_short is_smsk[2];
+ char is_group[FR_GROUPLEN];
+ char is_sbuf[2][16];
+ char is_ifname[4][LIFNAMSIZ];
+} ipstate_4_1_0_t;
+
+typedef struct ipstate_save_4_1_34 {
+ void *ips_next;
+ struct ipstate_4_1_16 ips_is;
+ struct frentry_4_1_34 ips_fr;
+} ipstate_save_4_1_34_t;
+
+typedef struct ipstate_save_4_1_16 {
+ void *ips_next;
+ ipstate_4_1_0_t ips_is;
+ frentry_4_1_16_t ips_fr;
+} ipstate_save_4_1_16_t;
+
+typedef struct ipstate_save_4_1_0 {
+ void *ips_next;
+ ipstate_4_1_0_t ips_is;
+ frentry_4_1_0_t ips_fr;
+} ipstate_save_4_1_0_t;
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * 5.1.0 new release (current)
+ * 4.1.21 added iss_tcptab
+ */
+typedef struct ips_stat_4_1_21 {
+ u_long iss_hits;
+ u_long iss_miss;
+ u_long iss_max;
+ u_long iss_maxref;
+ u_long iss_tcp;
+ u_long iss_udp;
+ u_long iss_icmp;
+ u_long iss_nomem;
+ u_long iss_expire;
+ u_long iss_fin;
+ u_long iss_active;
+ u_long iss_logged;
+ u_long iss_logfail;
+ u_long iss_inuse;
+ u_long iss_wild;
+ u_long iss_killed;
+ u_long iss_ticks;
+ u_long iss_bucketfull;
+ int iss_statesize;
+ int iss_statemax;
+ ipstate_t **iss_table;
+ ipstate_t *iss_list;
+ u_long *iss_bucketlen;
+ ipftq_t *iss_tcptab;
+} ips_stat_4_1_21_t;
+
+typedef struct ips_stat_4_1_0 {
+ u_long iss_hits;
+ u_long iss_miss;
+ u_long iss_max;
+ u_long iss_maxref;
+ u_long iss_tcp;
+ u_long iss_udp;
+ u_long iss_icmp;
+ u_long iss_nomem;
+ u_long iss_expire;
+ u_long iss_fin;
+ u_long iss_active;
+ u_long iss_logged;
+ u_long iss_logfail;
+ u_long iss_inuse;
+ u_long iss_wild;
+ u_long iss_killed;
+ u_long iss_ticks;
+ u_long iss_bucketfull;
+ int iss_statesize;
+ int iss_statemax;
+ ipstate_t **iss_table;
+ ipstate_t *iss_list;
+ u_long *iss_bucketlen;
+} ips_stat_4_1_0_t;
+
+/* ------------------------------------------------------------------------ */
+
+typedef struct ipfrstat_4_1_1 {
+ 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;
+ u_long ifs_retrans0;
+ u_long ifs_short;
+ struct ipfr **ifs_table;
+ struct ipfr **ifs_nattab;
+} ipfrstat_4_1_1_t;
+
+/* ------------------------------------------------------------------------ */
+static int ipf_addfrstr __P((char *, int, char *, int));
+static void ipf_v4iptov5 __P((frip4_t *, fr_ip_t *));
+static void ipf_v5iptov4 __P((fr_ip_t *, frip4_t *));
+static void ipfv4tuctov5 __P((frtuc4_t *, frtuc_t *));
+static void ipfv5tuctov4 __P((frtuc_t *, frtuc4_t *));
+static int ipf_v4fripftov5 __P((fripf4_t *, char *));
+static void ipf_v5fripftov4 __P((fripf_t *, fripf4_t *));
+static int fr_frflags4to5 __P((u_32_t));
+static int fr_frflags5to4 __P((u_32_t));
+
+static void friostat_current_to_4_1_0 __P((void *, friostat_4_1_0_t *, int));
+static void friostat_current_to_4_1_33 __P((void *, friostat_4_1_33_t *, int));
+static void ipstate_current_to_4_1_0 __P((void *, ipstate_4_1_0_t *));
+static void ipstate_current_to_4_1_16 __P((void *, ipstate_4_1_16_t *));
+static void ipnat_current_to_4_1_0 __P((void *, ipnat_4_1_0_t *));
+static void ipnat_current_to_4_1_14 __P((void *, ipnat_4_1_14_t *));
+static void frauth_current_to_4_1_11 __P((void *, frauth_4_1_11_t *));
+static void frauth_current_to_4_1_23 __P((void *, frauth_4_1_23_t *));
+static void frauth_current_to_4_1_24 __P((void *, frauth_4_1_24_t *));
+static void frauth_current_to_4_1_29 __P((void *, frauth_4_1_29_t *));
+static void frentry_current_to_4_1_0 __P((void *, frentry_4_1_0_t *));
+static void frentry_current_to_4_1_16 __P((void *, frentry_4_1_16_t *));
+static void frentry_current_to_4_1_34 __P((void *, frentry_4_1_34_t *));
+static void fr_info_current_to_4_1_11 __P((void *, fr_info_4_1_11_t *));
+static void fr_info_current_to_4_1_23 __P((void *, fr_info_4_1_23_t *));
+static void fr_info_current_to_4_1_24 __P((void *, fr_info_4_1_24_t *));
+static void nat_save_current_to_4_1_3 __P((void *, nat_save_4_1_3_t *));
+static void nat_save_current_to_4_1_14 __P((void *, nat_save_4_1_14_t *));
+static void nat_save_current_to_4_1_16 __P((void *, nat_save_4_1_16_t *));
+static void ipstate_save_current_to_4_1_0 __P((void *, ipstate_save_4_1_0_t *));
+static void ipstate_save_current_to_4_1_16 __P((void *, ipstate_save_4_1_16_t *));
+static void ips_stat_current_to_4_1_0 __P((void *, ips_stat_4_1_0_t *));
+static void ips_stat_current_to_4_1_21 __P((void *, ips_stat_4_1_21_t *));
+static void natstat_current_to_4_1_0 __P((void *, natstat_4_1_0_t *));
+static void natstat_current_to_4_1_16 __P((void *, natstat_4_1_16_t *));
+static void natstat_current_to_4_1_27 __P((void *, natstat_4_1_27_t *));
+static void natstat_current_to_4_1_32 __P((void *, natstat_4_1_32_t *));
+static void nat_current_to_4_1_3 __P((void *, nat_4_1_3_t *));
+static void nat_current_to_4_1_14 __P((void *, nat_4_1_14_t *));
+static void nat_current_to_4_1_25 __P((void *, nat_4_1_25_t *));
+
+static void friostat_4_1_0_to_current __P((friostat_4_1_0_t *, void *));
+static void friostat_4_1_33_to_current __P((friostat_4_1_33_t *, void *));
+static void ipnat_4_1_0_to_current __P((ipnat_4_1_0_t *, void *, int));
+static void ipnat_4_1_14_to_current __P((ipnat_4_1_14_t *, void *, int));
+static void frauth_4_1_11_to_current __P((frauth_4_1_11_t *, void *));
+static void frauth_4_1_23_to_current __P((frauth_4_1_23_t *, void *));
+static void frauth_4_1_24_to_current __P((frauth_4_1_24_t *, void *));
+static void frauth_4_1_29_to_current __P((frauth_4_1_29_t *, void *));
+static void frauth_4_1_32_to_current __P((frauth_4_1_32_t *, void *));
+static void frentry_4_1_0_to_current __P((ipf_main_softc_t *, frentry_4_1_0_t *, void *, int));
+static void frentry_4_1_16_to_current __P((ipf_main_softc_t *, frentry_4_1_16_t *, void *, int));
+static void frentry_4_1_34_to_current __P((ipf_main_softc_t *, frentry_4_1_34_t *, void *, int));
+static void fr_info_4_1_11_to_current __P((fr_info_4_1_11_t *, void *));
+static void fr_info_4_1_23_to_current __P((fr_info_4_1_23_t *, void *));
+static void fr_info_4_1_24_to_current __P((fr_info_4_1_24_t *, void *));
+static void fr_info_4_1_32_to_current __P((fr_info_4_1_32_t *, void *));
+static void nat_save_4_1_3_to_current __P((ipf_main_softc_t *, nat_save_4_1_3_t *, void *));
+static void nat_save_4_1_14_to_current __P((ipf_main_softc_t *, nat_save_4_1_14_t *, void *));
+static void nat_save_4_1_16_to_current __P((ipf_main_softc_t *, nat_save_4_1_16_t *, void *));
+
+/* ------------------------------------------------------------------------ */
+/* In this section is a series of short routines that deal with translating */
+/* the smaller data structures used above as their internal changes make */
+/* them inappropriate for simple assignment. */
+/* ------------------------------------------------------------------------ */
+
+
+static int
+ipf_addfrstr(char *names, int namelen, char *str, int maxlen)
+{
+ char *t;
+ int i;
+
+ for (i = maxlen, t = str; (*t != '\0') && (i > 0); i--) {
+ names[namelen++] = *t++;
+ }
+ names[namelen++] = '\0';
+ return namelen;
+}
+
+
+static void
+ipf_v4iptov5(v4, v5)
+ frip4_t *v4;
+ fr_ip_t *v5;
+{
+ v5->fi_v = v4->fi_v;
+ v5->fi_p = v4->fi_p;
+ v5->fi_xx = v4->fi_xx;
+ v5->fi_tos = v4->fi_tos;
+ v5->fi_ttl = v4->fi_ttl;
+ v5->fi_p = v4->fi_p;
+ v5->fi_optmsk = v4->fi_optmsk;
+ v5->fi_src = v4->fi_src;
+ v5->fi_dst = v4->fi_dst;
+ v5->fi_secmsk = v4->ofi_secmsk;
+ v5->fi_auth = v4->ofi_auth;
+ v5->fi_flx = v4->fi_flx;
+ v5->fi_tcpmsk = v4->fi_tcpmsk;
+}
+
+static void
+ipf_v5iptov4(v5, v4)
+ fr_ip_t *v5;
+ frip4_t *v4;
+{
+ v4->fi_v = v5->fi_v;
+ v4->fi_p = v5->fi_p;
+ v4->fi_xx = v5->fi_xx;
+ v4->fi_tos = v5->fi_tos;
+ v4->fi_ttl = v5->fi_ttl;
+ v4->fi_p = v5->fi_p;
+ v4->fi_optmsk = v5->fi_optmsk;
+ v4->fi_src = v5->fi_src;
+ v4->fi_dst = v5->fi_dst;
+ v4->ofi_secmsk = v5->fi_secmsk;
+ v4->ofi_auth = v5->fi_auth;
+ v4->fi_flx = v5->fi_flx;
+ v4->fi_tcpmsk = v5->fi_tcpmsk;
+}
+
+
+static void
+ipfv4tuctov5(v4, v5)
+ frtuc4_t *v4;
+ frtuc_t *v5;
+{
+ v5->ftu_src.frp_cmp = v4->ftu_src.frp_cmp;
+ v5->ftu_src.frp_port = v4->ftu_src.frp_port;
+ v5->ftu_src.frp_top = v4->ftu_src.frp_top;
+ v5->ftu_dst.frp_cmp = v4->ftu_dst.frp_cmp;
+ v5->ftu_dst.frp_port = v4->ftu_dst.frp_port;
+ v5->ftu_dst.frp_top = v4->ftu_dst.frp_top;
+}
+
+
+static void
+ipfv5tuctov4(v5, v4)
+ frtuc_t *v5;
+ frtuc4_t *v4;
+{
+ v4->ftu_src.frp_cmp = v5->ftu_src.frp_cmp;
+ v4->ftu_src.frp_port = v5->ftu_src.frp_port;
+ v4->ftu_src.frp_top = v5->ftu_src.frp_top;
+ v4->ftu_dst.frp_cmp = v5->ftu_dst.frp_cmp;
+ v4->ftu_dst.frp_port = v5->ftu_dst.frp_port;
+ v4->ftu_dst.frp_top = v5->ftu_dst.frp_top;
+}
+
+
+static int
+ipf_v4fripftov5(frp4, dst)
+ fripf4_t *frp4;
+ char *dst;
+{
+ fripf_t *frp;
+
+ frp = (fripf_t *)dst;
+
+ ipf_v4iptov5(&frp4->fri_ip, &frp->fri_ip);
+ ipf_v4iptov5(&frp4->fri_mip, &frp->fri_mip);
+ frp->fri_icmpm = frp4->fri_icmpm;
+ frp->fri_icmp = frp4->fri_icmp;
+ frp->fri_tuc.ftu_tcpfm = frp4->fri_tuc.ftu_tcpfm;
+ frp->fri_tuc.ftu_tcpf = frp4->fri_tuc.ftu_tcpf;
+ ipfv4tuctov5(&frp4->fri_tuc, &frp->fri_tuc);
+ frp->fri_satype = frp4->fri_satype;
+ frp->fri_datype = frp4->fri_datype;
+ frp->fri_sifpidx = frp4->fri_sifpidx;
+ frp->fri_difpidx = frp4->fri_difpidx;
+ return 0;
+}
+
+
+static void
+ipf_v5fripftov4(frp, frp4)
+ fripf_t *frp;
+ fripf4_t *frp4;
+{
+
+ ipf_v5iptov4(&frp->fri_ip, &frp4->fri_ip);
+ ipf_v5iptov4(&frp->fri_mip, &frp4->fri_mip);
+ frp4->fri_icmpm = frp->fri_icmpm;
+ frp4->fri_icmp = frp->fri_icmp;
+ frp4->fri_tuc.ftu_tcpfm = frp->fri_tuc.ftu_tcpfm;
+ frp4->fri_tuc.ftu_tcpf = frp->fri_tuc.ftu_tcpf;
+ ipfv5tuctov4(&frp->fri_tuc, &frp4->fri_tuc);
+ frp4->fri_satype = frp->fri_satype;
+ frp4->fri_datype = frp->fri_datype;
+ frp4->fri_sifpidx = frp->fri_sifpidx;
+ frp4->fri_difpidx = frp->fri_difpidx;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* ipf_in_compat is the first of two service routines. It is responsible for*/
+/* converting data structures from user space into what's required by the */
+/* kernel module. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_in_compat(softc, obj, ptr, size)
+ ipf_main_softc_t *softc;
+ ipfobj_t *obj;
+ void *ptr;
+ int size;
+{
+ int error;
+ int sz;
+
+ IPFERROR(140000);
+ error = EINVAL;
+
+ switch (obj->ipfo_type)
+ {
+ default :
+ break;
+
+ case IPFOBJ_FRENTRY :
+ if (obj->ipfo_rev >= 4013400) {
+ frentry_4_1_34_t *old;
+
+ KMALLOC(old, frentry_4_1_34_t *);
+ if (old == NULL) {
+ IPFERROR(140001);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ if (old->fr_type != FR_T_NONE &&
+ old->fr_type != FR_T_IPF) {
+ IPFERROR(140002);
+ error = EINVAL;
+ KFREE(old);
+ break;
+ }
+ frentry_4_1_34_to_current(softc, old,
+ ptr, size);
+ } else {
+ IPFERROR(140003);
+ }
+ KFREE(old);
+ } else if (obj->ipfo_rev >= 4011600) {
+ frentry_4_1_16_t *old;
+
+ KMALLOC(old, frentry_4_1_16_t *);
+ if (old == NULL) {
+ IPFERROR(140004);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ if (old->fr_type != FR_T_NONE &&
+ old->fr_type != FR_T_IPF) {
+ IPFERROR(140005);
+ error = EINVAL;
+ KFREE(old);
+ break;
+ }
+ frentry_4_1_16_to_current(softc, old,
+ ptr, size);
+ } else {
+ IPFERROR(140006);
+ }
+ KFREE(old);
+ } else {
+ frentry_4_1_0_t *old;
+
+ KMALLOC(old, frentry_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140007);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ if (old->fr_type != FR_T_NONE &&
+ old->fr_type != FR_T_IPF) {
+ IPFERROR(140008);
+ error = EINVAL;
+ KFREE(old);
+ break;
+ }
+ frentry_4_1_0_to_current(softc, old, ptr, size);
+ } else {
+ IPFERROR(140009);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_IPFSTAT :
+ if (obj->ipfo_rev >= 4013300) {
+ friostat_4_1_33_t *old;
+
+ KMALLOC(old, friostat_4_1_33_t *);
+ if (old == NULL) {
+ IPFERROR(140010);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ friostat_4_1_33_to_current(old, ptr);
+ } else {
+ IPFERROR(140011);
+ }
+ } else {
+ friostat_4_1_0_t *old;
+
+ KMALLOC(old, friostat_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140012);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ friostat_4_1_0_to_current(old, ptr);
+ } else {
+ IPFERROR(140013);
+ }
+ }
+ break;
+
+ case IPFOBJ_IPFINFO : /* unused */
+ break;
+
+ case IPFOBJ_IPNAT :
+ if (obj->ipfo_rev >= 4011400) {
+ ipnat_4_1_14_t *old;
+
+ KMALLOC(old, ipnat_4_1_14_t *);
+ if (old == NULL) {
+ IPFERROR(140014);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ ipnat_4_1_14_to_current(old, ptr, size);
+ } else {
+ IPFERROR(140015);
+ }
+ KFREE(old);
+ } else {
+ ipnat_4_1_0_t *old;
+
+ KMALLOC(old, ipnat_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140016);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ ipnat_4_1_0_to_current(old, ptr, size);
+ } else {
+ IPFERROR(140017);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_NATSTAT :
+ /*
+ * Statistics are not copied in.
+ */
+ break;
+
+ case IPFOBJ_NATSAVE :
+ if (obj->ipfo_rev >= 4011600) {
+ nat_save_4_1_16_t *old16;
+
+ KMALLOC(old16, nat_save_4_1_16_t *);
+ if (old16 == NULL) {
+ IPFERROR(140018);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old16, sizeof(*old16));
+ if (error == 0) {
+ nat_save_4_1_16_to_current(softc, old16, ptr);
+ } else {
+ IPFERROR(140019);
+ }
+ KFREE(old16);
+ } else if (obj->ipfo_rev >= 4011400) {
+ nat_save_4_1_14_t *old14;
+
+ KMALLOC(old14, nat_save_4_1_14_t *);
+ if (old14 == NULL) {
+ IPFERROR(140020);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old14, sizeof(*old14));
+ if (error == 0) {
+ nat_save_4_1_14_to_current(softc, old14, ptr);
+ } else {
+ IPFERROR(140021);
+ }
+ KFREE(old14);
+ } else if (obj->ipfo_rev >= 4010300) {
+ nat_save_4_1_3_t *old3;
+
+ KMALLOC(old3, nat_save_4_1_3_t *);
+ if (old3 == NULL) {
+ IPFERROR(140022);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old3, sizeof(*old3));
+ if (error == 0) {
+ nat_save_4_1_3_to_current(softc, old3, ptr);
+ } else {
+ IPFERROR(140023);
+ }
+ KFREE(old3);
+ }
+ break;
+
+ case IPFOBJ_STATESAVE :
+ if (obj->ipfo_rev >= 4013400) {
+ ipstate_save_4_1_34_t *old;
+
+ KMALLOC(old, ipstate_save_4_1_34_t *);
+ if (old == NULL) {
+ IPFERROR(140024);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140025);
+ }
+ KFREE(old);
+ } else if (obj->ipfo_rev >= 4011600) {
+ ipstate_save_4_1_16_t *old;
+
+ KMALLOC(old, ipstate_save_4_1_16_t *);
+ if (old == NULL) {
+ IPFERROR(140026);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140027);
+ }
+ KFREE(old);
+ } else {
+ ipstate_save_4_1_0_t *old;
+
+ KMALLOC(old, ipstate_save_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140028);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140029);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_IPSTATE :
+ /*
+ * This structure is not copied in by itself.
+ */
+ break;
+
+ case IPFOBJ_STATESTAT :
+ /*
+ * Statistics are not copied in.
+ */
+ break;
+
+ case IPFOBJ_FRAUTH :
+ if (obj->ipfo_rev >= 4013200) {
+ frauth_4_1_32_t *old32;
+
+ KMALLOC(old32, frauth_4_1_32_t *);
+ if (old32 == NULL) {
+ IPFERROR(140030);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old32, sizeof(*old32));
+ if (error == 0) {
+ frauth_4_1_32_to_current(old32, ptr);
+ } else {
+ IPFERROR(140031);
+ }
+ KFREE(old32);
+ } else if (obj->ipfo_rev >= 4012900) {
+ frauth_4_1_29_t *old29;
+
+ KMALLOC(old29, frauth_4_1_29_t *);
+ if (old29 == NULL) {
+ IPFERROR(140032);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old29, sizeof(*old29));
+ if (error == 0) {
+ frauth_4_1_29_to_current(old29, ptr);
+ } else {
+ IPFERROR(140033);
+ }
+ KFREE(old29);
+ } else if (obj->ipfo_rev >= 4012400) {
+ frauth_4_1_24_t *old24;
+
+ KMALLOC(old24, frauth_4_1_24_t *);
+ if (old24 == NULL) {
+ IPFERROR(140034);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old24, sizeof(*old24));
+ if (error == 0) {
+ frauth_4_1_24_to_current(old24, ptr);
+ } else {
+ IPFERROR(140035);
+ }
+ KFREE(old24);
+ } else if (obj->ipfo_rev >= 4012300) {
+ frauth_4_1_23_t *old23;
+
+ KMALLOC(old23, frauth_4_1_23_t *);
+ if (old23 == NULL) {
+ IPFERROR(140036);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old23, sizeof(*old23));
+ if (error == 0)
+ frauth_4_1_23_to_current(old23, ptr);
+ KFREE(old23);
+ } else if (obj->ipfo_rev >= 4011100) {
+ frauth_4_1_11_t *old11;
+
+ KMALLOC(old11, frauth_4_1_11_t *);
+ if (old11 == NULL) {
+ IPFERROR(140037);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old11, sizeof(*old11));
+ if (error == 0) {
+ frauth_4_1_11_to_current(old11, ptr);
+ } else {
+ IPFERROR(140038);
+ }
+ KFREE(old11);
+ }
+ break;
+
+ case IPFOBJ_NAT :
+ if (obj->ipfo_rev >= 4011400) {
+ sz = sizeof(nat_4_1_14_t);
+ } else if (obj->ipfo_rev >= 4010300) {
+ sz = sizeof(nat_4_1_3_t);
+ } else {
+ break;
+ }
+ bzero(ptr, sizeof(nat_t));
+ error = COPYIN(obj->ipfo_ptr, ptr, sz);
+ if (error != 0) {
+ IPFERROR(140039);
+ }
+ break;
+
+ case IPFOBJ_FRIPF :
+ if (obj->ipfo_rev < 5000000) {
+ fripf4_t *old;
+
+ KMALLOC(old, fripf4_t *);
+ if (old == NULL) {
+ IPFERROR(140040);
+ error = ENOMEM;
+ break;
+ }
+ error = COPYIN(obj->ipfo_ptr, old, sizeof(*old));
+ if (error == 0) {
+ ipf_v4fripftov5(old, ptr);
+ } else {
+ IPFERROR(140041);
+ }
+ KFREE(old);
+ }
+ break;
+ }
+
+ return error;
+}
+/* ------------------------------------------------------------------------ */
+
+
+/*
+ * flags is v4 flags, returns v5 flags.
+ */
+static int
+fr_frflags4to5(flags)
+ u_32_t flags;
+{
+ u_32_t nflags = 0;
+
+ switch (flags & 0xf) {
+ case 0x0 :
+ nflags |= FR_CALL;
+ break;
+ case 0x1 :
+ nflags |= FR_BLOCK;
+ break;
+ case 0x2 :
+ nflags |= FR_PASS;
+ break;
+ case 0x3 :
+ nflags |= FR_AUTH;
+ break;
+ case 0x4 :
+ nflags |= FR_PREAUTH;
+ break;
+ case 0x5 :
+ nflags |= FR_ACCOUNT;
+ break;
+ case 0x6 :
+ nflags |= FR_SKIP;
+ break;
+ default :
+ break;
+ }
+
+ if (flags & 0x00010)
+ nflags |= FR_LOG;
+ if (flags & 0x00020)
+ nflags |= FR_CALLNOW;
+ if (flags & 0x00080)
+ nflags |= FR_NOTSRCIP;
+ if (flags & 0x00040)
+ nflags |= FR_NOTDSTIP;
+ if (flags & 0x00100)
+ nflags |= FR_QUICK;
+ if (flags & 0x00200)
+ nflags |= FR_KEEPFRAG;
+ if (flags & 0x00400)
+ nflags |= FR_KEEPSTATE;
+ if (flags & 0x00800)
+ nflags |= FR_FASTROUTE;
+ if (flags & 0x01000)
+ nflags |= FR_RETRST;
+ if (flags & 0x02000)
+ nflags |= FR_RETICMP;
+ if (flags & 0x03000)
+ nflags |= FR_FAKEICMP;
+ if (flags & 0x04000)
+ nflags |= FR_OUTQUE;
+ if (flags & 0x08000)
+ nflags |= FR_INQUE;
+ if (flags & 0x10000)
+ nflags |= FR_LOGBODY;
+ if (flags & 0x20000)
+ nflags |= FR_LOGFIRST;
+ if (flags & 0x40000)
+ nflags |= FR_LOGORBLOCK;
+ if (flags & 0x100000)
+ nflags |= FR_FRSTRICT;
+ if (flags & 0x200000)
+ nflags |= FR_STSTRICT;
+ if (flags & 0x400000)
+ nflags |= FR_NEWISN;
+ if (flags & 0x800000)
+ nflags |= FR_NOICMPERR;
+ if (flags & 0x1000000)
+ nflags |= FR_STATESYNC;
+ if (flags & 0x8000000)
+ nflags |= FR_NOMATCH;
+ if (flags & 0x40000000)
+ nflags |= FR_COPIED;
+ if (flags & 0x80000000)
+ nflags |= FR_INACTIVE;
+
+ return nflags;
+}
+
+static void
+frentry_4_1_34_to_current(softc, old, current, size)
+ ipf_main_softc_t *softc;
+ frentry_4_1_34_t *old;
+ void *current;
+ int size;
+{
+ frentry_t *fr = (frentry_t *)current;
+
+ fr->fr_comment = -1;
+ fr->fr_ref = old->fr_ref;
+ fr->fr_statecnt = old->fr_statecnt;
+ fr->fr_hits = old->fr_hits;
+ fr->fr_bytes = old->fr_bytes;
+ fr->fr_lastpkt.tv_sec = old->fr_lastpkt.tv_sec;
+ fr->fr_lastpkt.tv_usec = old->fr_lastpkt.tv_usec;
+ bcopy(&old->fr_dun, &fr->fr_dun, sizeof(old->fr_dun));
+ fr->fr_func = old->fr_func;
+ fr->fr_dsize = old->fr_dsize;
+ fr->fr_pps = old->fr_pps;
+ fr->fr_statemax = old->fr_statemax;
+ fr->fr_flineno = old->fr_flineno;
+ fr->fr_type = old->fr_type;
+ fr->fr_flags = fr_frflags4to5(old->fr_flags);
+ fr->fr_logtag = old->fr_logtag;
+ fr->fr_collect = old->fr_collect;
+ fr->fr_arg = old->fr_arg;
+ fr->fr_loglevel = old->fr_loglevel;
+ fr->fr_age[0] = old->fr_age[0];
+ fr->fr_age[1] = old->fr_age[1];
+ fr->fr_tifs[0].fd_ip6 = old->fr_tifs[0].ofd_ip6;
+ fr->fr_tifs[0].fd_type = FRD_NORMAL;
+ fr->fr_tifs[1].fd_ip6 = old->fr_tifs[1].ofd_ip6;
+ fr->fr_tifs[1].fd_type = FRD_NORMAL;
+ fr->fr_dif.fd_ip6 = old->fr_dif.ofd_ip6;
+ fr->fr_dif.fd_type = FRD_NORMAL;
+ if (old->fr_v == 4)
+ fr->fr_family = AF_INET;
+ if (old->fr_v == 6)
+ fr->fr_family = AF_INET6;
+ fr->fr_icode = old->fr_icode;
+ fr->fr_cksum = old->fr_cksum;
+ fr->fr_namelen = 0;
+ fr->fr_ifnames[0] = -1;
+ fr->fr_ifnames[1] = -1;
+ fr->fr_ifnames[2] = -1;
+ fr->fr_ifnames[3] = -1;
+ fr->fr_dif.fd_name = -1;
+ fr->fr_tifs[0].fd_name = -1;
+ fr->fr_tifs[1].fd_name = -1;
+ fr->fr_group = -1;
+ fr->fr_grhead = -1;
+ fr->fr_icmphead = -1;
+ if (size == 0) {
+ fr->fr_size = sizeof(*fr) + LIFNAMSIZ * 7 + FR_GROUPLEN * 2;
+ fr->fr_size += sizeof(fripf_t) + 16;
+ fr->fr_size += 9; /* room for \0's */
+ } else {
+ char *names = fr->fr_names;
+ int nlen = fr->fr_namelen;
+
+ fr->fr_size = size;
+ if (old->fr_ifnames[0][0] != '\0') {
+ fr->fr_ifnames[0] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[0],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[1][0] != '\0') {
+ fr->fr_ifnames[1] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[1],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[2][0] != '\0') {
+ fr->fr_ifnames[2] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[2],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[3][0] != '\0') {
+ fr->fr_ifnames[3] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[3],
+ LIFNAMSIZ);
+ }
+ if (old->fr_tifs[0].fd_ifname[0] != '\0') {
+ fr->fr_tifs[0].fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_tifs[0].fd_ifname,
+ LIFNAMSIZ);
+ }
+ if (old->fr_tifs[1].fd_ifname[0] != '\0') {
+ fr->fr_tifs[1].fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_tifs[1].fd_ifname,
+ LIFNAMSIZ);
+ }
+ if (old->fr_dif.fd_ifname[0] != '\0') {
+ fr->fr_dif.fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_dif.fd_ifname, LIFNAMSIZ);
+ }
+ if (old->fr_group[0] != '\0') {
+ fr->fr_group = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_group, LIFNAMSIZ);
+ }
+ if (old->fr_grhead[0] != '\0') {
+ fr->fr_grhead = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_grhead, LIFNAMSIZ);
+ }
+ fr->fr_namelen = nlen;
+
+ if (old->fr_type == FR_T_IPF) {
+ int offset = fr->fr_namelen;
+ ipfobj_t obj;
+ int error;
+
+ obj.ipfo_type = IPFOBJ_FRIPF;
+ obj.ipfo_rev = 4010100;
+ obj.ipfo_ptr = old->fr_data;
+
+ if ((offset & 7) != 0)
+ offset += 8 - (offset & 7);
+ error = ipf_in_compat(softc, &obj,
+ fr->fr_names + offset, 0);
+ if (error == 0) {
+ fr->fr_data = fr->fr_names + offset;
+ fr->fr_dsize = sizeof(fripf_t);
+ }
+ }
+ }
+}
+
+static void
+frentry_4_1_16_to_current(softc, old, current, size)
+ ipf_main_softc_t *softc;
+ frentry_4_1_16_t *old;
+ void *current;
+ int size;
+{
+ frentry_t *fr = (frentry_t *)current;
+
+ fr->fr_comment = -1;
+ fr->fr_ref = old->fr_ref;
+ fr->fr_statecnt = old->fr_statecnt;
+ fr->fr_hits = old->fr_hits;
+ fr->fr_bytes = old->fr_bytes;
+ fr->fr_lastpkt.tv_sec = old->fr_lastpkt.tv_sec;
+ fr->fr_lastpkt.tv_usec = old->fr_lastpkt.tv_usec;
+ bcopy(&old->fr_dun, &fr->fr_dun, sizeof(old->fr_dun));
+ fr->fr_func = old->fr_func;
+ fr->fr_dsize = old->fr_dsize;
+ fr->fr_pps = old->fr_pps;
+ fr->fr_statemax = old->fr_statemax;
+ fr->fr_flineno = old->fr_flineno;
+ fr->fr_type = old->fr_type;
+ fr->fr_flags = fr_frflags4to5(old->fr_flags);
+ fr->fr_logtag = old->fr_logtag;
+ fr->fr_collect = old->fr_collect;
+ fr->fr_arg = old->fr_arg;
+ fr->fr_loglevel = old->fr_loglevel;
+ fr->fr_age[0] = old->fr_age[0];
+ fr->fr_age[1] = old->fr_age[1];
+ fr->fr_tifs[0].fd_ip6 = old->fr_tifs[0].ofd_ip6;
+ fr->fr_tifs[0].fd_type = FRD_NORMAL;
+ fr->fr_tifs[1].fd_ip6 = old->fr_tifs[1].ofd_ip6;
+ fr->fr_tifs[1].fd_type = FRD_NORMAL;
+ fr->fr_dif.fd_ip6 = old->fr_dif.ofd_ip6;
+ fr->fr_dif.fd_type = FRD_NORMAL;
+ if (old->fr_v == 4)
+ fr->fr_family = AF_INET;
+ if (old->fr_v == 6)
+ fr->fr_family = AF_INET6;
+ fr->fr_icode = old->fr_icode;
+ fr->fr_cksum = old->fr_cksum;
+ fr->fr_namelen = 0;
+ fr->fr_ifnames[0] = -1;
+ fr->fr_ifnames[1] = -1;
+ fr->fr_ifnames[2] = -1;
+ fr->fr_ifnames[3] = -1;
+ fr->fr_dif.fd_name = -1;
+ fr->fr_tifs[0].fd_name = -1;
+ fr->fr_tifs[1].fd_name = -1;
+ fr->fr_group = -1;
+ fr->fr_grhead = -1;
+ fr->fr_icmphead = -1;
+ if (size == 0) {
+ fr->fr_size = sizeof(*fr) + LIFNAMSIZ * 7 + FR_GROUPLEN * 2;
+ fr->fr_size += 9; /* room for \0's */
+ } else {
+ char *names = fr->fr_names;
+ int nlen = fr->fr_namelen;
+
+ fr->fr_size = size;
+ if (old->fr_ifnames[0][0] != '\0') {
+ fr->fr_ifnames[0] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[0],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[1][0] != '\0') {
+ fr->fr_ifnames[1] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[1],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[2][0] != '\0') {
+ fr->fr_ifnames[2] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[2],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[3][0] != '\0') {
+ fr->fr_ifnames[3] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[3],
+ LIFNAMSIZ);
+ }
+ if (old->fr_tifs[0].fd_ifname[0] != '\0') {
+ fr->fr_tifs[0].fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_tifs[0].fd_ifname,
+ LIFNAMSIZ);
+ }
+ if (old->fr_tifs[1].fd_ifname[0] != '\0') {
+ fr->fr_tifs[1].fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_tifs[1].fd_ifname,
+ LIFNAMSIZ);
+ }
+ if (old->fr_dif.fd_ifname[0] != '\0') {
+ fr->fr_dif.fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_dif.fd_ifname, LIFNAMSIZ);
+ }
+ if (old->fr_group[0] != '\0') {
+ fr->fr_group = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_group, LIFNAMSIZ);
+ }
+ if (old->fr_grhead[0] != '\0') {
+ fr->fr_grhead = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_grhead, LIFNAMSIZ);
+ }
+ fr->fr_namelen = nlen;
+
+ if (old->fr_type == FR_T_IPF) {
+ int offset = fr->fr_namelen;
+ ipfobj_t obj;
+ int error;
+
+ obj.ipfo_type = IPFOBJ_FRIPF;
+ obj.ipfo_rev = 4010100;
+ obj.ipfo_ptr = old->fr_data;
+
+ if ((offset & 7) != 0)
+ offset += 8 - (offset & 7);
+ error = ipf_in_compat(softc, &obj,
+ fr->fr_names + offset, 0);
+ if (error == 0) {
+ fr->fr_data = fr->fr_names + offset;
+ fr->fr_dsize = sizeof(fripf_t);
+ }
+ }
+ }
+}
+
+
+static void
+frentry_4_1_0_to_current(softc, old, current, size)
+ ipf_main_softc_t *softc;
+ frentry_4_1_0_t *old;
+ void *current;
+ int size;
+{
+ frentry_t *fr = (frentry_t *)current;
+
+ fr->fr_size = sizeof(*fr);
+ fr->fr_comment = -1;
+ fr->fr_ref = old->fr_ref;
+ fr->fr_statecnt = old->fr_statecnt;
+ fr->fr_hits = old->fr_hits;
+ fr->fr_bytes = old->fr_bytes;
+ fr->fr_lastpkt.tv_sec = old->fr_lastpkt.tv_sec;
+ fr->fr_lastpkt.tv_usec = old->fr_lastpkt.tv_usec;
+ bcopy(&old->fr_dun, &fr->fr_dun, sizeof(old->fr_dun));
+ fr->fr_func = old->fr_func;
+ fr->fr_dsize = old->fr_dsize;
+ fr->fr_pps = old->fr_pps;
+ fr->fr_statemax = old->fr_statemax;
+ fr->fr_flineno = old->fr_flineno;
+ fr->fr_type = old->fr_type;
+ fr->fr_flags = fr_frflags4to5(old->fr_flags);
+ fr->fr_logtag = old->fr_logtag;
+ fr->fr_collect = old->fr_collect;
+ fr->fr_arg = old->fr_arg;
+ fr->fr_loglevel = old->fr_loglevel;
+ fr->fr_age[0] = old->fr_age[0];
+ fr->fr_age[1] = old->fr_age[1];
+ fr->fr_tifs[0].fd_ip6 = old->fr_tifs[0].ofd_ip6;
+ fr->fr_tifs[0].fd_type = FRD_NORMAL;
+ fr->fr_tifs[1].fd_ip6 = old->fr_tifs[1].ofd_ip6;
+ fr->fr_tifs[1].fd_type = FRD_NORMAL;
+ fr->fr_dif.fd_ip6 = old->fr_dif.ofd_ip6;
+ fr->fr_dif.fd_type = FRD_NORMAL;
+ if (old->fr_v == 4)
+ fr->fr_family = AF_INET;
+ if (old->fr_v == 6)
+ fr->fr_family = AF_INET6;
+ fr->fr_icode = old->fr_icode;
+ fr->fr_cksum = old->fr_cksum;
+ fr->fr_namelen = 0;
+ fr->fr_ifnames[0] = -1;
+ fr->fr_ifnames[1] = -1;
+ fr->fr_ifnames[2] = -1;
+ fr->fr_ifnames[3] = -1;
+ fr->fr_dif.fd_name = -1;
+ fr->fr_tifs[0].fd_name = -1;
+ fr->fr_tifs[1].fd_name = -1;
+ fr->fr_group = -1;
+ fr->fr_grhead = -1;
+ fr->fr_icmphead = -1;
+ if (size == 0) {
+ fr->fr_size = sizeof(*fr) + LIFNAMSIZ * 7 + FR_GROUPLEN * 2;
+ fr->fr_size += 9; /* room for \0's */
+ } else {
+ char *names = fr->fr_names;
+ int nlen = fr->fr_namelen;
+
+ fr->fr_size = size;
+ if (old->fr_ifnames[0][0] != '\0') {
+ fr->fr_ifnames[0] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[0],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[1][0] != '\0') {
+ fr->fr_ifnames[1] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[1],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[2][0] != '\0') {
+ fr->fr_ifnames[2] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[2],
+ LIFNAMSIZ);
+ }
+ if (old->fr_ifnames[3][0] != '\0') {
+ fr->fr_ifnames[3] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[3],
+ LIFNAMSIZ);
+ }
+ if (old->fr_tifs[0].fd_ifname[0] != '\0') {
+ fr->fr_tifs[0].fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_tifs[0].fd_ifname,
+ LIFNAMSIZ);
+ }
+ if (old->fr_tifs[1].fd_ifname[0] != '\0') {
+ fr->fr_tifs[1].fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_tifs[1].fd_ifname,
+ LIFNAMSIZ);
+ }
+ if (old->fr_dif.fd_ifname[0] != '\0') {
+ fr->fr_dif.fd_name = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_dif.fd_ifname, LIFNAMSIZ);
+ }
+ if (old->fr_group[0] != '\0') {
+ fr->fr_group = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_group, LIFNAMSIZ);
+ }
+ if (old->fr_grhead[0] != '\0') {
+ fr->fr_grhead = nlen;
+ nlen = ipf_addfrstr(names, nlen,
+ old->fr_grhead, LIFNAMSIZ);
+ }
+ fr->fr_namelen = nlen;
+
+ if (old->fr_type == FR_T_IPF) {
+ int offset = fr->fr_namelen;
+ ipfobj_t obj;
+ int error;
+
+ obj.ipfo_type = IPFOBJ_FRIPF;
+ obj.ipfo_rev = 4010100;
+ obj.ipfo_ptr = old->fr_data;
+
+ if ((offset & 7) != 0)
+ offset += 8 - (offset & 7);
+ offset += 8 - (offset & 7);
+ error = ipf_in_compat(softc, &obj,
+ fr->fr_names + offset, 0);
+ if (error == 0) {
+ fr->fr_data = fr->fr_names + offset;
+ fr->fr_dsize = sizeof(fripf_t);
+ }
+ }
+ }
+}
+
+
+static void
+friostat_4_1_33_to_current(old, current)
+ friostat_4_1_33_t *old;
+ void *current;
+{
+ friostat_t *fiop = (friostat_t *)current;
+
+ bcopy(&old->of_st[0], &fiop->f_st[0].fr_pass, sizeof(old->of_st[0]));
+ bcopy(&old->of_st[1], &fiop->f_st[1].fr_pass, sizeof(old->of_st[1]));
+
+ fiop->f_ipf[0][0] = old->f_ipf[0][0];
+ fiop->f_ipf[0][1] = old->f_ipf[0][1];
+ fiop->f_ipf[1][0] = old->f_ipf[1][0];
+ fiop->f_ipf[1][1] = old->f_ipf[1][1];
+ fiop->f_acct[0][0] = old->f_acct[0][0];
+ fiop->f_acct[0][1] = old->f_acct[0][1];
+ fiop->f_acct[1][0] = old->f_acct[1][0];
+ fiop->f_acct[1][1] = old->f_acct[1][1];
+ fiop->f_auth = fiop->f_auth;
+ bcopy(&old->f_groups, &fiop->f_groups, sizeof(old->f_groups));
+ bcopy(&old->f_froute, &fiop->f_froute, sizeof(old->f_froute));
+ fiop->f_ticks = old->f_ticks;
+ bcopy(&old->f_locks, &fiop->f_locks, sizeof(old->f_locks));
+ fiop->f_defpass = old->f_defpass;
+ fiop->f_active = old->f_active;
+ fiop->f_running = old->f_running;
+ fiop->f_logging = old->f_logging;
+ fiop->f_features = old->f_features;
+ bcopy(old->f_version, fiop->f_version, sizeof(old->f_version));
+}
+
+
+static void
+friostat_4_1_0_to_current(old, current)
+ friostat_4_1_0_t *old;
+ void *current;
+{
+ friostat_t *fiop = (friostat_t *)current;
+
+ bcopy(&old->of_st[0], &fiop->f_st[0].fr_pass, sizeof(old->of_st[0]));
+ bcopy(&old->of_st[1], &fiop->f_st[1].fr_pass, sizeof(old->of_st[1]));
+
+ fiop->f_ipf[0][0] = old->f_ipf[0][0];
+ fiop->f_ipf[0][1] = old->f_ipf[0][1];
+ fiop->f_ipf[1][0] = old->f_ipf[1][0];
+ fiop->f_ipf[1][1] = old->f_ipf[1][1];
+ fiop->f_acct[0][0] = old->f_acct[0][0];
+ fiop->f_acct[0][1] = old->f_acct[0][1];
+ fiop->f_acct[1][0] = old->f_acct[1][0];
+ fiop->f_acct[1][1] = old->f_acct[1][1];
+ fiop->f_auth = fiop->f_auth;
+ bcopy(&old->f_groups, &fiop->f_groups, sizeof(old->f_groups));
+ bcopy(&old->f_froute, &fiop->f_froute, sizeof(old->f_froute));
+ fiop->f_ticks = old->f_ticks;
+ bcopy(&old->f_locks, &fiop->f_locks, sizeof(old->f_locks));
+ fiop->f_defpass = old->f_defpass;
+ fiop->f_active = old->f_active;
+ fiop->f_running = old->f_running;
+ fiop->f_logging = old->f_logging;
+ fiop->f_features = old->f_features;
+ bcopy(old->f_version, fiop->f_version, sizeof(old->f_version));
+}
+
+
+static void
+ipnat_4_1_14_to_current(old, current, size)
+ ipnat_4_1_14_t *old;
+ void *current;
+ int size;
+{
+ ipnat_t *np = (ipnat_t *)current;
+
+ np->in_space = old->in_space;
+ np->in_hv[0] = old->in_hv;
+ np->in_hv[1] = old->in_hv;
+ np->in_flineno = old->in_flineno;
+ if (old->in_redir == NAT_REDIRECT)
+ np->in_dpnext = old->in_pnext;
+ else
+ np->in_spnext = old->in_pnext;
+ np->in_v[0] = old->in_v;
+ np->in_v[1] = old->in_v;
+ np->in_flags = old->in_flags;
+ np->in_mssclamp = old->in_mssclamp;
+ np->in_age[0] = old->in_age[0];
+ np->in_age[1] = old->in_age[1];
+ np->in_redir = old->in_redir;
+ np->in_pr[0] = old->in_p;
+ np->in_pr[1] = old->in_p;
+ if (np->in_redir == NAT_REDIRECT) {
+ np->in_ndst.na_nextaddr = old->in_next6;
+ np->in_ndst.na_addr[0] = old->in_in[0];
+ np->in_ndst.na_addr[1] = old->in_in[1];
+ np->in_ndst.na_atype = FRI_NORMAL;
+ np->in_odst.na_addr[0] = old->in_out[0];
+ np->in_odst.na_addr[1] = old->in_out[1];
+ np->in_odst.na_atype = FRI_NORMAL;
+ np->in_osrc.na_addr[0] = old->in_src[0];
+ np->in_osrc.na_addr[1] = old->in_src[1];
+ np->in_osrc.na_atype = FRI_NORMAL;
+ } else {
+ np->in_nsrc.na_nextaddr = old->in_next6;
+ np->in_nsrc.na_addr[0] = old->in_out[0];
+ np->in_nsrc.na_addr[1] = old->in_out[1];
+ np->in_nsrc.na_atype = FRI_NORMAL;
+ np->in_osrc.na_addr[0] = old->in_in[0];
+ np->in_osrc.na_addr[1] = old->in_in[1];
+ np->in_osrc.na_atype = FRI_NORMAL;
+ np->in_odst.na_addr[0] = old->in_src[0];
+ np->in_odst.na_addr[1] = old->in_src[1];
+ np->in_odst.na_atype = FRI_NORMAL;
+ }
+ ipfv4tuctov5(&old->in_tuc, &np->in_tuc);
+ if (np->in_redir == NAT_REDIRECT) {
+ np->in_dpmin = old->in_port[0];
+ np->in_dpmax = old->in_port[1];
+ } else {
+ np->in_spmin = old->in_port[0];
+ np->in_spmax = old->in_port[1];
+ }
+ np->in_ppip = old->in_ppip;
+ np->in_ippip = old->in_ippip;
+ np->in_tag = old->in_tag;
+
+ np->in_namelen = 0;
+ np->in_plabel = -1;
+ np->in_ifnames[0] = -1;
+ np->in_ifnames[1] = -1;
+
+ if (size == 0) {
+ np->in_size = sizeof(*np);
+ np->in_size += LIFNAMSIZ * 2 + APR_LABELLEN;
+ np->in_size += 3;
+ } else {
+ int nlen = np->in_namelen;
+ char *names = np->in_names;
+
+ if (old->in_ifnames[0][0] != '\0') {
+ np->in_ifnames[0] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->in_ifnames[0],
+ LIFNAMSIZ);
+ }
+ if (old->in_ifnames[1][0] != '\0') {
+ np->in_ifnames[0] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->in_ifnames[1],
+ LIFNAMSIZ);
+ }
+ if (old->in_plabel[0] != '\0') {
+ np->in_plabel = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->in_plabel,
+ LIFNAMSIZ);
+ }
+ np->in_namelen = nlen;
+ np->in_size = size;
+ }
+}
+
+
+static void
+ipnat_4_1_0_to_current(old, current, size)
+ ipnat_4_1_0_t *old;
+ void *current;
+ int size;
+{
+ ipnat_t *np = (ipnat_t *)current;
+
+ np->in_space = old->in_space;
+ np->in_hv[0] = old->in_hv;
+ np->in_hv[1] = old->in_hv;
+ np->in_flineno = old->in_flineno;
+ if (old->in_redir == NAT_REDIRECT)
+ np->in_dpnext = old->in_pnext;
+ else
+ np->in_spnext = old->in_pnext;
+ np->in_v[0] = old->in_v;
+ np->in_v[1] = old->in_v;
+ np->in_flags = old->in_flags;
+ np->in_mssclamp = old->in_mssclamp;
+ np->in_age[0] = old->in_age[0];
+ np->in_age[1] = old->in_age[1];
+ np->in_redir = old->in_redir;
+ np->in_pr[0] = old->in_p;
+ np->in_pr[1] = old->in_p;
+ if (np->in_redir == NAT_REDIRECT) {
+ np->in_ndst.na_nextaddr = old->in_next6;
+ bcopy(&old->in_in, &np->in_ndst.na_addr, sizeof(old->in_in));
+ bcopy(&old->in_out, &np->in_odst.na_addr, sizeof(old->in_out));
+ bcopy(&old->in_src, &np->in_osrc.na_addr, sizeof(old->in_src));
+ } else {
+ np->in_nsrc.na_nextaddr = old->in_next6;
+ bcopy(&old->in_in, &np->in_osrc.na_addr, sizeof(old->in_in));
+ bcopy(&old->in_out, &np->in_nsrc.na_addr, sizeof(old->in_out));
+ bcopy(&old->in_src, &np->in_odst.na_addr, sizeof(old->in_src));
+ }
+ ipfv4tuctov5(&old->in_tuc, &np->in_tuc);
+ if (np->in_redir == NAT_REDIRECT) {
+ np->in_dpmin = old->in_port[0];
+ np->in_dpmax = old->in_port[1];
+ } else {
+ np->in_spmin = old->in_port[0];
+ np->in_spmax = old->in_port[1];
+ }
+ np->in_ppip = old->in_ppip;
+ np->in_ippip = old->in_ippip;
+ bcopy(&old->in_tag, &np->in_tag, sizeof(np->in_tag));
+
+ np->in_namelen = 0;
+ np->in_plabel = -1;
+ np->in_ifnames[0] = -1;
+ np->in_ifnames[1] = -1;
+
+ if (size == 0) {
+ np->in_size = sizeof(*np);
+ np->in_size += LIFNAMSIZ * 2 + APR_LABELLEN;
+ np->in_size += 3;
+ } else {
+ int nlen = np->in_namelen;
+ char *names = np->in_names;
+
+ if (old->in_ifnames[0][0] != '\0') {
+ np->in_ifnames[0] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->in_ifnames[0],
+ LIFNAMSIZ);
+ }
+ if (old->in_ifnames[1][0] != '\0') {
+ np->in_ifnames[0] = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->in_ifnames[1],
+ LIFNAMSIZ);
+ }
+ if (old->in_plabel[0] != '\0') {
+ np->in_plabel = nlen;
+ nlen = ipf_addfrstr(names, nlen, old->in_plabel,
+ LIFNAMSIZ);
+ }
+ np->in_namelen = nlen;
+ np->in_size = size;
+ }
+}
+
+
+static void
+frauth_4_1_32_to_current(old, current)
+ frauth_4_1_32_t *old;
+ void *current;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ fra->fra_age = old->fra_age;
+ fra->fra_len = old->fra_len;
+ fra->fra_index = old->fra_index;
+ fra->fra_pass = old->fra_pass;
+ fr_info_4_1_32_to_current(&old->fra_info, &fra->fra_info);
+ fra->fra_buf = old->fra_buf;
+ fra->fra_flx = old->fra_flx;
+#ifdef MENTAT
+ fra->fra_q = old->fra_q;
+ fra->fra_m = old->fra_m;
+#endif
+}
+
+
+static void
+frauth_4_1_29_to_current(old, current)
+ frauth_4_1_29_t *old;
+ void *current;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ fra->fra_age = old->fra_age;
+ fra->fra_len = old->fra_len;
+ fra->fra_index = old->fra_index;
+ fra->fra_pass = old->fra_pass;
+ fr_info_4_1_24_to_current(&old->fra_info, &fra->fra_info);
+ fra->fra_buf = old->fra_buf;
+ fra->fra_flx = old->fra_flx;
+#ifdef MENTAT
+ fra->fra_q = old->fra_q;
+ fra->fra_m = old->fra_m;
+#endif
+}
+
+
+static void
+frauth_4_1_24_to_current(old, current)
+ frauth_4_1_24_t *old;
+ void *current;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ fra->fra_age = old->fra_age;
+ fra->fra_len = old->fra_len;
+ fra->fra_index = old->fra_index;
+ fra->fra_pass = old->fra_pass;
+ fr_info_4_1_24_to_current(&old->fra_info, &fra->fra_info);
+ fra->fra_buf = old->fra_buf;
+#ifdef MENTAT
+ fra->fra_q = old->fra_q;
+ fra->fra_m = old->fra_m;
+#endif
+}
+
+
+static void
+frauth_4_1_23_to_current(old, current)
+ frauth_4_1_23_t *old;
+ void *current;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ fra->fra_age = old->fra_age;
+ fra->fra_len = old->fra_len;
+ fra->fra_index = old->fra_index;
+ fra->fra_pass = old->fra_pass;
+ fr_info_4_1_23_to_current(&old->fra_info, &fra->fra_info);
+ fra->fra_buf = old->fra_buf;
+#ifdef MENTAT
+ fra->fra_q = old->fra_q;
+ fra->fra_m = old->fra_m;
+#endif
+}
+
+
+static void
+frauth_4_1_11_to_current(old, current)
+ frauth_4_1_11_t *old;
+ void *current;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ fra->fra_age = old->fra_age;
+ fra->fra_len = old->fra_len;
+ fra->fra_index = old->fra_index;
+ fra->fra_pass = old->fra_pass;
+ fr_info_4_1_11_to_current(&old->fra_info, &fra->fra_info);
+ fra->fra_buf = old->fra_buf;
+#ifdef MENTAT
+ fra->fra_q = old->fra_q;
+ fra->fra_m = old->fra_m;
+#endif
+}
+
+
+static void
+fr_info_4_1_32_to_current(old, current)
+ fr_info_4_1_32_t *old;
+ void *current;
+{
+ fr_info_t *fin = (fr_info_t *)current;
+
+ fin->fin_ifp = old->fin_ifp;
+ ipf_v4iptov5(&old->fin_fi, &fin->fin_fi);
+ bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat));
+ fin->fin_out = old->fin_out;
+ fin->fin_rev = old->fin_rev;
+ fin->fin_hlen = old->fin_hlen;
+ fin->fin_tcpf = old->ofin_tcpf;
+ fin->fin_icode = old->fin_icode;
+ fin->fin_rule = old->fin_rule;
+ bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group));
+ fin->fin_fr = old->fin_fr;
+ fin->fin_dp = old->fin_dp;
+ fin->fin_dlen = old->fin_dlen;
+ fin->fin_plen = old->fin_plen;
+ fin->fin_ipoff = old->fin_ipoff;
+ fin->fin_id = old->fin_id;
+ fin->fin_off = old->fin_off;
+ fin->fin_depth = old->fin_depth;
+ fin->fin_error = old->fin_error;
+ fin->fin_cksum = old->fin_cksum;
+ fin->fin_nattag = old->fin_nattag;
+ fin->fin_ip = old->ofin_ip;
+ fin->fin_mp = old->fin_mp;
+ fin->fin_m = old->fin_m;
+#ifdef MENTAT
+ fin->fin_qfm = old->fin_qfm;
+ fin->fin_qpi = old->fin_qpi;
+#endif
+#ifdef __sgi
+ fin->fin_hbuf = old->fin_hbuf;
+#endif
+}
+
+
+static void
+fr_info_4_1_24_to_current(old, current)
+ fr_info_4_1_24_t *old;
+ void *current;
+{
+ fr_info_t *fin = (fr_info_t *)current;
+
+ fin->fin_ifp = old->fin_ifp;
+ ipf_v4iptov5(&old->fin_fi, &fin->fin_fi);
+ bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat));
+ fin->fin_out = old->fin_out;
+ fin->fin_rev = old->fin_rev;
+ fin->fin_hlen = old->fin_hlen;
+ fin->fin_tcpf = old->ofin_tcpf;
+ fin->fin_icode = old->fin_icode;
+ fin->fin_rule = old->fin_rule;
+ bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group));
+ fin->fin_fr = old->fin_fr;
+ fin->fin_dp = old->fin_dp;
+ fin->fin_dlen = old->fin_dlen;
+ fin->fin_plen = old->fin_plen;
+ fin->fin_ipoff = old->fin_ipoff;
+ fin->fin_id = old->fin_id;
+ fin->fin_off = old->fin_off;
+ fin->fin_depth = old->fin_depth;
+ fin->fin_error = old->fin_error;
+ fin->fin_cksum = old->fin_cksum;
+ fin->fin_nattag = old->fin_nattag;
+ fin->fin_ip = old->ofin_ip;
+ fin->fin_mp = old->fin_mp;
+ fin->fin_m = old->fin_m;
+#ifdef MENTAT
+ fin->fin_qfm = old->fin_qfm;
+ fin->fin_qpi = old->fin_qpi;
+#endif
+#ifdef __sgi
+ fin->fin_hbuf = old->fin_hbuf;
+#endif
+}
+
+
+static void
+fr_info_4_1_23_to_current(old, current)
+ fr_info_4_1_23_t *old;
+ void *current;
+{
+ fr_info_t *fin = (fr_info_t *)current;
+
+ fin->fin_ifp = old->fin_ifp;
+ ipf_v4iptov5(&old->fin_fi, &fin->fin_fi);
+ bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat));
+ fin->fin_out = old->fin_out;
+ fin->fin_rev = old->fin_rev;
+ fin->fin_hlen = old->fin_hlen;
+ fin->fin_tcpf = old->ofin_tcpf;
+ fin->fin_icode = old->fin_icode;
+ fin->fin_rule = old->fin_rule;
+ bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group));
+ fin->fin_fr = old->fin_fr;
+ fin->fin_dp = old->fin_dp;
+ fin->fin_dlen = old->fin_dlen;
+ fin->fin_plen = old->fin_plen;
+ fin->fin_ipoff = old->fin_ipoff;
+ fin->fin_id = old->fin_id;
+ fin->fin_off = old->fin_off;
+ fin->fin_depth = old->fin_depth;
+ fin->fin_error = old->fin_error;
+ fin->fin_nattag = old->fin_nattag;
+ fin->fin_ip = old->ofin_ip;
+ fin->fin_mp = old->fin_mp;
+ fin->fin_m = old->fin_m;
+#ifdef MENTAT
+ fin->fin_qfm = old->fin_qfm;
+ fin->fin_qpi = old->fin_qpi;
+#endif
+#ifdef __sgi
+ fin->fin_hbuf = fin->fin_hbuf;
+#endif
+}
+
+
+static void
+fr_info_4_1_11_to_current(old, current)
+ fr_info_4_1_11_t *old;
+ void *current;
+{
+ fr_info_t *fin = (fr_info_t *)current;
+
+ fin->fin_ifp = old->fin_ifp;
+ ipf_v4iptov5(&old->fin_fi, &fin->fin_fi);
+ bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat));
+ fin->fin_out = old->fin_out;
+ fin->fin_rev = old->fin_rev;
+ fin->fin_hlen = old->fin_hlen;
+ fin->fin_tcpf = old->ofin_tcpf;
+ fin->fin_icode = old->fin_icode;
+ fin->fin_rule = old->fin_rule;
+ bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group));
+ fin->fin_fr = old->fin_fr;
+ fin->fin_dp = old->fin_dp;
+ fin->fin_dlen = old->fin_dlen;
+ fin->fin_plen = old->fin_plen;
+ fin->fin_ipoff = old->fin_ipoff;
+ fin->fin_id = old->fin_id;
+ fin->fin_off = old->fin_off;
+ fin->fin_depth = old->fin_depth;
+ fin->fin_error = old->fin_error;
+ fin->fin_nattag = old->fin_nattag;
+ fin->fin_ip = old->ofin_ip;
+ fin->fin_mp = old->fin_mp;
+ fin->fin_m = old->fin_m;
+#ifdef MENTAT
+ fin->fin_qfm = old->fin_qfm;
+ fin->fin_qpi = old->fin_qpi;
+#endif
+#ifdef __sgi
+ fin->fin_hbuf = fin->fin_hbuf;
+#endif
+}
+
+
+static void
+nat_4_1_3_to_current(nat_4_1_3_t *old, nat_t *current)
+{
+ bzero((void *)current, sizeof(*current));
+ bcopy((void *)old, (void *)current, sizeof(*old));
+}
+
+
+static void
+nat_4_1_14_to_current(nat_4_1_14_t *old, nat_t *current)
+{
+ bzero((void *)current, sizeof(*current));
+ bcopy((void *)old, (void *)current, sizeof(*old));
+}
+
+
+static void
+nat_save_4_1_16_to_current(softc, old, current)
+ ipf_main_softc_t *softc;
+ nat_save_4_1_16_t *old;
+ void *current;
+{
+ nat_save_t *nats = (nat_save_t *)current;
+
+ nats->ipn_next = old->ipn_next;
+ nat_4_1_14_to_current(&old->ipn_nat, &nats->ipn_nat);
+ bcopy(&old->ipn_ipnat, &nats->ipn_ipnat, sizeof(old->ipn_ipnat));
+ frentry_4_1_16_to_current(softc, &old->ipn_fr, &nats->ipn_fr, 0);
+ nats->ipn_dsize = old->ipn_dsize;
+ bcopy(old->ipn_data, nats->ipn_data, sizeof(nats->ipn_data));
+}
+
+
+static void
+nat_save_4_1_14_to_current(softc, old, current)
+ ipf_main_softc_t *softc;
+ nat_save_4_1_14_t *old;
+ void *current;
+{
+ nat_save_t *nats = (nat_save_t *)current;
+
+ nats->ipn_next = old->ipn_next;
+ nat_4_1_14_to_current(&old->ipn_nat, &nats->ipn_nat);
+ bcopy(&old->ipn_ipnat, &nats->ipn_ipnat, sizeof(old->ipn_ipnat));
+ frentry_4_1_0_to_current(softc, &old->ipn_fr, &nats->ipn_fr, 0);
+ nats->ipn_dsize = old->ipn_dsize;
+ bcopy(old->ipn_data, nats->ipn_data, sizeof(nats->ipn_data));
+}
+
+
+static void
+nat_save_4_1_3_to_current(softc, old, current)
+ ipf_main_softc_t *softc;
+ nat_save_4_1_3_t *old;
+ void *current;
+{
+ nat_save_t *nats = (nat_save_t *)current;
+
+ nats->ipn_next = old->ipn_next;
+ nat_4_1_3_to_current(&old->ipn_nat, &nats->ipn_nat);
+ ipnat_4_1_0_to_current(&old->ipn_ipnat, &nats->ipn_ipnat, 0);
+ frentry_4_1_0_to_current(softc, &old->ipn_fr, &nats->ipn_fr, 0);
+ nats->ipn_dsize = old->ipn_dsize;
+ bcopy(old->ipn_data, nats->ipn_data, sizeof(nats->ipn_data));
+}
+
+
+static void
+natstat_current_to_4_1_32(current, old)
+ void *current;
+ natstat_4_1_32_t *old;
+{
+ natstat_t *ns = (natstat_t *)current;
+
+ old->ns_mapped[0] = ns->ns_side[0].ns_translated;
+ old->ns_mapped[1] = ns->ns_side[1].ns_translated;
+ old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added;
+ old->ns_expire = ns->ns_expire;
+ old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_logged = ns->ns_log_ok;
+ old->ns_logfail = ns->ns_log_fail;
+ old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail;
+ old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat;
+ old->ns_addtrpnt = ns->ns_addtrpnt;
+ old->ns_table[0] = ns->ns_side[0].ns_table;
+ old->ns_table[1] = ns->ns_side[1].ns_table;
+ old->ns_maptable = NULL;
+ old->ns_list = ns->ns_list;
+ old->ns_apslist = NULL;
+ old->ns_wilds = ns->ns_wilds;
+ old->ns_nattab_sz = ns->ns_nattab_sz;
+ old->ns_nattab_max = ns->ns_nattab_max;
+ old->ns_rultab_sz = ns->ns_rultab_sz;
+ old->ns_rdrtab_sz = ns->ns_rdrtab_sz;
+ old->ns_trpntab_sz = ns->ns_trpntab_sz;
+ old->ns_hostmap_sz = 0;
+ old->ns_instances = ns->ns_instances;
+ old->ns_maplist = ns->ns_maplist;
+ old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen;
+ old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen;
+ old->ns_ticks = ns->ns_ticks;
+ old->ns_orphans = ns->ns_orphans;
+ old->ns_uncreate[0][0] = ns->ns_side[0].ns_uncreate[0];
+ old->ns_uncreate[0][1] = ns->ns_side[0].ns_uncreate[1];
+ old->ns_uncreate[1][0] = ns->ns_side[1].ns_uncreate[0];
+ old->ns_uncreate[1][1] = ns->ns_side[1].ns_uncreate[1];
+}
+
+
+static void
+natstat_current_to_4_1_27(current, old)
+ void *current;
+ natstat_4_1_27_t *old;
+{
+ natstat_t *ns = (natstat_t *)current;
+
+ old->ns_mapped[0] = ns->ns_side[0].ns_translated;
+ old->ns_mapped[1] = ns->ns_side[1].ns_translated;
+ old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added;
+ old->ns_expire = ns->ns_expire;
+ old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_logged = ns->ns_log_ok;
+ old->ns_logfail = ns->ns_log_fail;
+ old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail;
+ old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat;
+ old->ns_addtrpnt = ns->ns_addtrpnt;
+ old->ns_table[0] = ns->ns_side[0].ns_table;
+ old->ns_table[1] = ns->ns_side[1].ns_table;
+ old->ns_maptable = NULL;
+ old->ns_list = ns->ns_list;
+ old->ns_apslist = NULL;
+ old->ns_wilds = ns->ns_wilds;
+ old->ns_nattab_sz = ns->ns_nattab_sz;
+ old->ns_nattab_max = ns->ns_nattab_max;
+ old->ns_rultab_sz = ns->ns_rultab_sz;
+ old->ns_rdrtab_sz = ns->ns_rdrtab_sz;
+ old->ns_trpntab_sz = ns->ns_trpntab_sz;
+ old->ns_hostmap_sz = 0;
+ old->ns_instances = ns->ns_instances;
+ old->ns_maplist = ns->ns_maplist;
+ old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen;
+ old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen;
+ old->ns_ticks = ns->ns_ticks;
+ old->ns_orphans = ns->ns_orphans;
+}
+
+
+static void
+natstat_current_to_4_1_16(current, old)
+ void *current;
+ natstat_4_1_16_t *old;
+{
+ natstat_t *ns = (natstat_t *)current;
+
+ old->ns_mapped[0] = ns->ns_side[0].ns_translated;
+ old->ns_mapped[1] = ns->ns_side[1].ns_translated;
+ old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added;
+ old->ns_expire = ns->ns_expire;
+ old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_logged = ns->ns_log_ok;
+ old->ns_logfail = ns->ns_log_fail;
+ old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail;
+ old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat;
+ old->ns_addtrpnt = ns->ns_addtrpnt;
+ old->ns_table[0] = ns->ns_side[0].ns_table;
+ old->ns_table[1] = ns->ns_side[1].ns_table;
+ old->ns_maptable = NULL;
+ old->ns_list = ns->ns_list;
+ old->ns_apslist = NULL;
+ old->ns_wilds = ns->ns_wilds;
+ old->ns_nattab_sz = ns->ns_nattab_sz;
+ old->ns_nattab_max = ns->ns_nattab_max;
+ old->ns_rultab_sz = ns->ns_rultab_sz;
+ old->ns_rdrtab_sz = ns->ns_rdrtab_sz;
+ old->ns_trpntab_sz = ns->ns_trpntab_sz;
+ old->ns_hostmap_sz = 0;
+ old->ns_instances = ns->ns_instances;
+ old->ns_maplist = ns->ns_maplist;
+ old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen;
+ old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen;
+ old->ns_ticks = ns->ns_ticks;
+}
+
+
+static void
+natstat_current_to_4_1_0(current, old)
+ void *current;
+ natstat_4_1_0_t *old;
+{
+ natstat_t *ns = (natstat_t *)current;
+
+ old->ns_mapped[0] = ns->ns_side[0].ns_translated;
+ old->ns_mapped[1] = ns->ns_side[1].ns_translated;
+ old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added;
+ old->ns_expire = ns->ns_expire;
+ old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse;
+ old->ns_logged = ns->ns_log_ok;
+ old->ns_logfail = ns->ns_log_fail;
+ old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail;
+ old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat;
+ old->ns_addtrpnt = ns->ns_addtrpnt;
+ old->ns_table[0] = ns->ns_side[0].ns_table;
+ old->ns_table[1] = ns->ns_side[1].ns_table;
+ old->ns_maptable = NULL;
+ old->ns_list = ns->ns_list;
+ old->ns_apslist = NULL;
+ old->ns_wilds = ns->ns_wilds;
+ old->ns_nattab_sz = ns->ns_nattab_sz;
+ old->ns_nattab_max = ns->ns_nattab_max;
+ old->ns_rultab_sz = ns->ns_rultab_sz;
+ old->ns_rdrtab_sz = ns->ns_rdrtab_sz;
+ old->ns_trpntab_sz = ns->ns_trpntab_sz;
+ old->ns_hostmap_sz = 0;
+ old->ns_instances = ns->ns_instances;
+ old->ns_maplist = ns->ns_maplist;
+ old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen;
+ old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen;
+}
+
+
+static void
+ipstate_save_current_to_4_1_16(current, old)
+ void *current;
+ ipstate_save_4_1_16_t *old;
+{
+ ipstate_save_t *ips = (ipstate_save_t *)current;
+
+ old->ips_next = ips->ips_next;
+ ipstate_current_to_4_1_0(&ips->ips_is, &old->ips_is);
+ frentry_current_to_4_1_16(&ips->ips_fr, &old->ips_fr);
+}
+
+
+static void
+ipstate_save_current_to_4_1_0(current, old)
+ void *current;
+ ipstate_save_4_1_0_t *old;
+{
+ ipstate_save_t *ips = (ipstate_save_t *)current;
+
+ old->ips_next = ips->ips_next;
+ ipstate_current_to_4_1_0(&ips->ips_is, &old->ips_is);
+ frentry_current_to_4_1_0(&ips->ips_fr, &old->ips_fr);
+}
+
+
+int
+ipf_out_compat(softc, obj, ptr)
+ ipf_main_softc_t *softc;
+ ipfobj_t *obj;
+ void *ptr;
+{
+ frentry_t *fr;
+ int error;
+
+ IPFERROR(140042);
+ error = EINVAL;
+
+ switch (obj->ipfo_type)
+ {
+ default :
+ break;
+
+ case IPFOBJ_FRENTRY :
+ if (obj->ipfo_rev >= 4013400) {
+ frentry_4_1_34_t *old;
+
+ KMALLOC(old, frentry_4_1_34_t *);
+ if (old == NULL) {
+ IPFERROR(140043);
+ error = ENOMEM;
+ break;
+ }
+ frentry_current_to_4_1_34(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error == 0 && old->fr_dsize > 0) {
+ char *dst = obj->ipfo_ptr;
+
+ fr = ptr;
+ dst += sizeof(*old);
+ error = COPYOUT(fr->fr_data, dst,
+ old->fr_dsize);
+ if (error != 0) {
+ IPFERROR(140044);
+ }
+ }
+ KFREE(old);
+ obj->ipfo_size = sizeof(*old);
+ } else if (obj->ipfo_rev >= 4011600) {
+ frentry_4_1_16_t *old;
+
+ KMALLOC(old, frentry_4_1_16_t *);
+ if (old == NULL) {
+ IPFERROR(140045);
+ error = ENOMEM;
+ break;
+ }
+ frentry_current_to_4_1_16(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140046);
+ }
+ KFREE(old);
+ obj->ipfo_size = sizeof(*old);
+ } else {
+ frentry_4_1_0_t *old;
+
+ KMALLOC(old, frentry_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140047);
+ error = ENOMEM;
+ break;
+ }
+ frentry_current_to_4_1_0(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140048);
+ }
+ KFREE(old);
+ obj->ipfo_size = sizeof(*old);
+ }
+ break;
+
+ case IPFOBJ_IPFSTAT :
+ if (obj->ipfo_rev >= 4013300) {
+ friostat_4_1_33_t *old;
+
+ KMALLOC(old, friostat_4_1_33_t *);
+ if (old == NULL) {
+ IPFERROR(140049);
+ error = ENOMEM;
+ break;
+ }
+ friostat_current_to_4_1_33(ptr, old, obj->ipfo_rev);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140050);
+ }
+ KFREE(old);
+ } else {
+ friostat_4_1_0_t *old;
+
+ KMALLOC(old, friostat_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140051);
+ error = ENOMEM;
+ break;
+ }
+ friostat_current_to_4_1_0(ptr, old, obj->ipfo_rev);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140052);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_IPFINFO : /* unused */
+ break;
+
+ case IPFOBJ_IPNAT :
+ if (obj->ipfo_rev >= 4011400) {
+ ipnat_4_1_14_t *old;
+
+ KMALLOC(old, ipnat_4_1_14_t *);
+ if (old == NULL) {
+ IPFERROR(140053);
+ error = ENOMEM;
+ break;
+ }
+ ipnat_current_to_4_1_14(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140054);
+ }
+ KFREE(old);
+ } else {
+ ipnat_4_1_0_t *old;
+
+ KMALLOC(old, ipnat_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140055);
+ error = ENOMEM;
+ break;
+ }
+ ipnat_current_to_4_1_0(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140056);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_NATSTAT :
+ if (obj->ipfo_rev >= 4013200) {
+ natstat_4_1_32_t *old;
+
+ KMALLOC(old, natstat_4_1_32_t *);
+ if (old == NULL) {
+ IPFERROR(140057);
+ error = ENOMEM;
+ break;
+ }
+ natstat_current_to_4_1_32(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140058);
+ }
+ KFREE(old);
+ } else if (obj->ipfo_rev >= 4012700) {
+ natstat_4_1_27_t *old;
+
+ KMALLOC(old, natstat_4_1_27_t *);
+ if (old == NULL) {
+ IPFERROR(140059);
+ error = ENOMEM;
+ break;
+ }
+ natstat_current_to_4_1_27(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140060);
+ }
+ KFREE(old);
+ } else if (obj->ipfo_rev >= 4011600) {
+ natstat_4_1_16_t *old;
+
+ KMALLOC(old, natstat_4_1_16_t *);
+ if (old == NULL) {
+ IPFERROR(140061);
+ error = ENOMEM;
+ break;
+ }
+ natstat_current_to_4_1_16(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140062);
+ }
+ KFREE(old);
+ } else {
+ natstat_4_1_0_t *old;
+
+ KMALLOC(old, natstat_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140063);
+ error = ENOMEM;
+ break;
+ }
+ natstat_current_to_4_1_0(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140064);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_STATESAVE :
+ if (obj->ipfo_rev >= 4011600) {
+ ipstate_save_4_1_16_t *old;
+
+ KMALLOC(old, ipstate_save_4_1_16_t *);
+ if (old == NULL) {
+ IPFERROR(140065);
+ error = ENOMEM;
+ break;
+ }
+ ipstate_save_current_to_4_1_16(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140066);
+ }
+ KFREE(old);
+ } else {
+ ipstate_save_4_1_0_t *old;
+
+ KMALLOC(old, ipstate_save_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140067);
+ error = ENOMEM;
+ break;
+ }
+ ipstate_save_current_to_4_1_0(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140068);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_NATSAVE :
+ if (obj->ipfo_rev >= 4011600) {
+ nat_save_4_1_16_t *old16;
+
+ KMALLOC(old16, nat_save_4_1_16_t *);
+ if (old16 == NULL) {
+ IPFERROR(140069);
+ error = ENOMEM;
+ break;
+ }
+ nat_save_current_to_4_1_16(ptr, old16);
+ error = COPYOUT(&old16, obj->ipfo_ptr, sizeof(*old16));
+ if (error != 0) {
+ IPFERROR(140070);
+ }
+ KFREE(old16);
+ } else if (obj->ipfo_rev >= 4011400) {
+ nat_save_4_1_14_t *old14;
+
+ KMALLOC(old14, nat_save_4_1_14_t *);
+ if (old14 == NULL) {
+ IPFERROR(140071);
+ error = ENOMEM;
+ break;
+ }
+ nat_save_current_to_4_1_14(ptr, old14);
+ error = COPYOUT(&old14, obj->ipfo_ptr, sizeof(*old14));
+ if (error != 0) {
+ IPFERROR(140072);
+ }
+ KFREE(old14);
+ } else if (obj->ipfo_rev >= 4010300) {
+ nat_save_4_1_3_t *old3;
+
+ KMALLOC(old3, nat_save_4_1_3_t *);
+ if (old3 == NULL) {
+ IPFERROR(140073);
+ error = ENOMEM;
+ break;
+ }
+ nat_save_current_to_4_1_3(ptr, old3);
+ error = COPYOUT(&old3, obj->ipfo_ptr, sizeof(*old3));
+ if (error != 0) {
+ IPFERROR(140074);
+ }
+ KFREE(old3);
+ }
+ break;
+
+ case IPFOBJ_IPSTATE :
+ if (obj->ipfo_rev >= 4011600) {
+ ipstate_4_1_16_t *old;
+
+ KMALLOC(old, ipstate_4_1_16_t *);
+ if (old == NULL) {
+ IPFERROR(140075);
+ error = ENOMEM;
+ break;
+ }
+ ipstate_current_to_4_1_16(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140076);
+ }
+ KFREE(old);
+ } else {
+ ipstate_4_1_0_t *old;
+
+ KMALLOC(old, ipstate_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140077);
+ error = ENOMEM;
+ break;
+ }
+ ipstate_current_to_4_1_0(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140078);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_STATESTAT :
+ if (obj->ipfo_rev >= 4012100) {
+ ips_stat_4_1_21_t *old;
+
+ KMALLOC(old, ips_stat_4_1_21_t *);
+ if (old == NULL) {
+ IPFERROR(140079);
+ error = ENOMEM;
+ break;
+ }
+ ips_stat_current_to_4_1_21(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140080);
+ }
+ KFREE(old);
+ } else {
+ ips_stat_4_1_0_t *old;
+
+ KMALLOC(old, ips_stat_4_1_0_t *);
+ if (old == NULL) {
+ IPFERROR(140081);
+ error = ENOMEM;
+ break;
+ }
+ ips_stat_current_to_4_1_0(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140082);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_FRAUTH :
+ if (obj->ipfo_rev >= 4012900) {
+ frauth_4_1_29_t *old29;
+
+ KMALLOC(old29, frauth_4_1_29_t *);
+ if (old29 == NULL) {
+ IPFERROR(140083);
+ error = ENOMEM;
+ break;
+ }
+ frauth_current_to_4_1_29(ptr, old29);
+ error = COPYOUT(old29, obj->ipfo_ptr, sizeof(*old29));
+ if (error != 0) {
+ IPFERROR(140084);
+ }
+ KFREE(old29);
+ } else if (obj->ipfo_rev >= 4012400) {
+ frauth_4_1_24_t *old24;
+
+ KMALLOC(old24, frauth_4_1_24_t *);
+ if (old24 == NULL) {
+ IPFERROR(140085);
+ error = ENOMEM;
+ break;
+ }
+ frauth_current_to_4_1_24(ptr, old24);
+ error = COPYOUT(old24, obj->ipfo_ptr, sizeof(*old24));
+ if (error != 0) {
+ IPFERROR(140086);
+ }
+ KFREE(old24);
+ } else if (obj->ipfo_rev >= 4012300) {
+ frauth_4_1_23_t *old23;
+
+ KMALLOC(old23, frauth_4_1_23_t *);
+ if (old23 == NULL) {
+ IPFERROR(140087);
+ error = ENOMEM;
+ break;
+ }
+ frauth_current_to_4_1_23(ptr, old23);
+ error = COPYOUT(old23, obj->ipfo_ptr, sizeof(*old23));
+ if (error != 0) {
+ IPFERROR(140088);
+ }
+ KFREE(old23);
+ } else if (obj->ipfo_rev >= 4011100) {
+ frauth_4_1_11_t *old11;
+
+ KMALLOC(old11, frauth_4_1_11_t *);
+ if (old11 == NULL) {
+ IPFERROR(140089);
+ error = ENOMEM;
+ break;
+ }
+ frauth_current_to_4_1_11(ptr, old11);
+ error = COPYOUT(old11, obj->ipfo_ptr, sizeof(*old11));
+ if (error != 0) {
+ IPFERROR(140090);
+ }
+ KFREE(old11);
+ }
+ break;
+
+ case IPFOBJ_NAT :
+ if (obj->ipfo_rev >= 4012500) {
+ nat_4_1_25_t *old;
+
+ KMALLOC(old, nat_4_1_25_t *);
+ if (old == NULL) {
+ IPFERROR(140091);
+ error = ENOMEM;
+ break;
+ }
+ nat_current_to_4_1_25(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140092);
+ }
+ KFREE(old);
+ } else if (obj->ipfo_rev >= 4011400) {
+ nat_4_1_14_t *old;
+
+ KMALLOC(old, nat_4_1_14_t *);
+ if (old == NULL) {
+ IPFERROR(140093);
+ error = ENOMEM;
+ break;
+ }
+ nat_current_to_4_1_14(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140094);
+ }
+ KFREE(old);
+ } else if (obj->ipfo_rev >= 4010300) {
+ nat_4_1_3_t *old;
+
+ KMALLOC(old, nat_4_1_3_t *);
+ if (old == NULL) {
+ IPFERROR(140095);
+ error = ENOMEM;
+ break;
+ }
+ nat_current_to_4_1_3(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140096);
+ }
+ KFREE(old);
+ }
+ break;
+
+ case IPFOBJ_FRIPF :
+ if (obj->ipfo_rev < 5000000) {
+ fripf4_t *old;
+
+ KMALLOC(old, fripf4_t *);
+ if (old == NULL) {
+ IPFERROR(140097);
+ error = ENOMEM;
+ break;
+ }
+ ipf_v5fripftov4(ptr, old);
+ error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old));
+ if (error != 0) {
+ IPFERROR(140098);
+ }
+ KFREE(old);
+ }
+ break;
+ }
+ return error;
+}
+
+
+static void
+friostat_current_to_4_1_33(current, old, rev)
+ void *current;
+ friostat_4_1_33_t *old;
+ int rev;
+{
+ friostat_t *fiop = (friostat_t *)current;
+
+ bcopy(&fiop->f_st[0].fr_pass, &old->of_st[0], sizeof(old->of_st[0]));
+ bcopy(&fiop->f_st[1].fr_pass, &old->of_st[1], sizeof(old->of_st[1]));
+
+ old->f_ipf[0][0] = fiop->f_ipf[0][0];
+ old->f_ipf[0][1] = fiop->f_ipf[0][1];
+ old->f_ipf[1][0] = fiop->f_ipf[1][0];
+ old->f_ipf[1][1] = fiop->f_ipf[1][1];
+ old->f_acct[0][0] = fiop->f_acct[0][0];
+ old->f_acct[0][1] = fiop->f_acct[0][1];
+ old->f_acct[1][0] = fiop->f_acct[1][0];
+ old->f_acct[1][1] = fiop->f_acct[1][1];
+ old->f_ipf6[0][0] = NULL;
+ old->f_ipf6[0][1] = NULL;
+ old->f_ipf6[1][0] = NULL;
+ old->f_ipf6[1][1] = NULL;
+ old->f_acct6[0][0] = NULL;
+ old->f_acct6[0][1] = NULL;
+ old->f_acct6[1][0] = NULL;
+ old->f_acct6[1][1] = NULL;
+ old->f_auth = fiop->f_auth;
+ bcopy(&fiop->f_groups, &old->f_groups, sizeof(old->f_groups));
+ bcopy(&fiop->f_froute, &old->f_froute, sizeof(old->f_froute));
+ old->f_ticks = fiop->f_ticks;
+ bcopy(&fiop->f_locks, &old->f_locks, sizeof(old->f_locks));
+ old->f_kmutex_sz = 0;
+ old->f_krwlock_sz = 0;
+ old->f_defpass = fiop->f_defpass;
+ old->f_active = fiop->f_active;
+ old->f_running = fiop->f_running;
+ old->f_logging = fiop->f_logging;
+ old->f_features = fiop->f_features;
+ sprintf(old->f_version, "IP Filter: v%d.%d.%d",
+ (rev / 1000000) % 100,
+ (rev / 10000) % 100,
+ (rev / 100) % 100);
+}
+
+
+static void
+friostat_current_to_4_1_0(current, old, rev)
+ void *current;
+ friostat_4_1_0_t *old;
+ int rev;
+{
+ friostat_t *fiop = (friostat_t *)current;
+
+ bcopy(&fiop->f_st[0].fr_pass, &old->of_st[0], sizeof(old->of_st[0]));
+ bcopy(&fiop->f_st[1].fr_pass, &old->of_st[1], sizeof(old->of_st[1]));
+
+ old->f_ipf[0][0] = fiop->f_ipf[0][0];
+ old->f_ipf[0][1] = fiop->f_ipf[0][1];
+ old->f_ipf[1][0] = fiop->f_ipf[1][0];
+ old->f_ipf[1][1] = fiop->f_ipf[1][1];
+ old->f_acct[0][0] = fiop->f_acct[0][0];
+ old->f_acct[0][1] = fiop->f_acct[0][1];
+ old->f_acct[1][0] = fiop->f_acct[1][0];
+ old->f_acct[1][1] = fiop->f_acct[1][1];
+ old->f_ipf6[0][0] = NULL;
+ old->f_ipf6[0][1] = NULL;
+ old->f_ipf6[1][0] = NULL;
+ old->f_ipf6[1][1] = NULL;
+ old->f_acct6[0][0] = NULL;
+ old->f_acct6[0][1] = NULL;
+ old->f_acct6[1][0] = NULL;
+ old->f_acct6[1][1] = NULL;
+ old->f_auth = fiop->f_auth;
+ bcopy(&fiop->f_groups, &old->f_groups, sizeof(old->f_groups));
+ bcopy(&fiop->f_froute, &old->f_froute, sizeof(old->f_froute));
+ old->f_ticks = fiop->f_ticks;
+ old->f_ipf[0][0] = fiop->f_ipf[0][0];
+ old->f_ipf[0][1] = fiop->f_ipf[0][1];
+ old->f_ipf[1][0] = fiop->f_ipf[1][0];
+ old->f_ipf[1][1] = fiop->f_ipf[1][1];
+ old->f_acct[0][0] = fiop->f_acct[0][0];
+ old->f_acct[0][1] = fiop->f_acct[0][1];
+ old->f_acct[1][0] = fiop->f_acct[1][0];
+ old->f_acct[1][1] = fiop->f_acct[1][1];
+ old->f_ipf6[0][0] = NULL;
+ old->f_ipf6[0][1] = NULL;
+ old->f_ipf6[1][0] = NULL;
+ old->f_ipf6[1][1] = NULL;
+ old->f_acct6[0][0] = NULL;
+ old->f_acct6[0][1] = NULL;
+ old->f_acct6[1][0] = NULL;
+ old->f_acct6[1][1] = NULL;
+ old->f_auth = fiop->f_auth;
+ bcopy(&fiop->f_groups, &old->f_groups, sizeof(old->f_groups));
+ bcopy(&fiop->f_froute, &old->f_froute, sizeof(old->f_froute));
+ old->f_ticks = fiop->f_ticks;
+ bcopy(&fiop->f_locks, &old->f_locks, sizeof(old->f_locks));
+ old->f_kmutex_sz = 0;
+ old->f_krwlock_sz = 0;
+ old->f_defpass = fiop->f_defpass;
+ old->f_active = fiop->f_active;
+ old->f_running = fiop->f_running;
+ old->f_logging = fiop->f_logging;
+ old->f_features = fiop->f_features;
+ sprintf(old->f_version, "IP Filter: v%d.%d.%d",
+ (rev / 1000000) % 100,
+ (rev / 10000) % 100,
+ (rev / 100) % 100);
+}
+
+
+/*
+ * nflags is v5 flags, returns v4 flags.
+ */
+static int
+fr_frflags5to4(nflags)
+ u_32_t nflags;
+{
+ u_32_t oflags = 0;
+
+ switch (nflags & FR_CMDMASK) {
+ case FR_CALL :
+ oflags = 0x0;
+ break;
+ case FR_BLOCK :
+ oflags = 0x1;
+ break;
+ case FR_PASS :
+ oflags = 0x2;
+ break;
+ case FR_AUTH :
+ oflags = 0x3;
+ break;
+ case FR_PREAUTH :
+ oflags = 0x4;
+ break;
+ case FR_ACCOUNT :
+ oflags = 0x5;
+ break;
+ case FR_SKIP :
+ oflags = 0x6;
+ break;
+ default :
+ break;
+ }
+
+ if (nflags & FR_LOG)
+ oflags |= 0x00010;
+ if (nflags & FR_CALLNOW)
+ oflags |= 0x00020;
+ if (nflags & FR_NOTSRCIP)
+ oflags |= 0x00080;
+ if (nflags & FR_NOTDSTIP)
+ oflags |= 0x00040;
+ if (nflags & FR_QUICK)
+ oflags |= 0x00100;
+ if (nflags & FR_KEEPFRAG)
+ oflags |= 0x00200;
+ if (nflags & FR_KEEPSTATE)
+ oflags |= 0x00400;
+ if (nflags & FR_FASTROUTE)
+ oflags |= 0x00800;
+ if (nflags & FR_RETRST)
+ oflags |= 0x01000;
+ if (nflags & FR_RETICMP)
+ oflags |= 0x02000;
+ if (nflags & FR_FAKEICMP)
+ oflags |= 0x03000;
+ if (nflags & FR_OUTQUE)
+ oflags |= 0x04000;
+ if (nflags & FR_INQUE)
+ oflags |= 0x08000;
+ if (nflags & FR_LOGBODY)
+ oflags |= 0x10000;
+ if (nflags & FR_LOGFIRST)
+ oflags |= 0x20000;
+ if (nflags & FR_LOGORBLOCK)
+ oflags |= 0x40000;
+ if (nflags & FR_FRSTRICT)
+ oflags |= 0x100000;
+ if (nflags & FR_STSTRICT)
+ oflags |= 0x200000;
+ if (nflags & FR_NEWISN)
+ oflags |= 0x400000;
+ if (nflags & FR_NOICMPERR)
+ oflags |= 0x800000;
+ if (nflags & FR_STATESYNC)
+ oflags |= 0x1000000;
+ if (nflags & FR_NOMATCH)
+ oflags |= 0x8000000;
+ if (nflags & FR_COPIED)
+ oflags |= 0x40000000;
+ if (nflags & FR_INACTIVE)
+ oflags |= 0x80000000;
+
+ return oflags;
+}
+
+
+static void
+frentry_current_to_4_1_34(current, old)
+ void *current;
+ frentry_4_1_34_t *old;
+{
+ frentry_t *fr = (frentry_t *)current;
+
+ old->fr_lock = fr->fr_lock;
+ old->fr_next = fr->fr_next;
+ old->fr_grp = (void *)fr->fr_grp;
+ old->fr_isc = fr->fr_isc;
+ old->fr_ifas[0] = fr->fr_ifas[0];
+ old->fr_ifas[1] = fr->fr_ifas[1];
+ old->fr_ifas[2] = fr->fr_ifas[2];
+ old->fr_ifas[3] = fr->fr_ifas[3];
+ old->fr_ptr = fr->fr_ptr;
+ old->fr_comment = NULL;
+ old->fr_ref = fr->fr_ref;
+ old->fr_statecnt = fr->fr_statecnt;
+ old->fr_hits = fr->fr_hits;
+ old->fr_bytes = fr->fr_bytes;
+ old->fr_lastpkt.tv_sec = fr->fr_lastpkt.tv_sec;
+ old->fr_lastpkt.tv_usec = fr->fr_lastpkt.tv_usec;
+ old->fr_curpps = fr->fr_curpps;
+ old->fr_dun.fru_data = fr->fr_dun.fru_data;
+ old->fr_func = fr->fr_func;
+ old->fr_dsize = fr->fr_dsize;
+ old->fr_pps = fr->fr_pps;
+ old->fr_statemax = fr->fr_statemax;
+ old->fr_flineno = fr->fr_flineno;
+ old->fr_type = fr->fr_type;
+ old->fr_flags = fr_frflags5to4(fr->fr_flags);
+ old->fr_logtag = fr->fr_logtag;
+ old->fr_collect = fr->fr_collect;
+ old->fr_arg = fr->fr_arg;
+ old->fr_loglevel = fr->fr_loglevel;
+ old->fr_age[0] = fr->fr_age[0];
+ old->fr_age[1] = fr->fr_age[1];
+ if (fr->fr_family == AF_INET)
+ old->fr_v = 4;
+ if (fr->fr_family == AF_INET6)
+ old->fr_v = 6;
+ old->fr_icode = fr->fr_icode;
+ old->fr_cksum = fr->fr_cksum;
+ old->fr_tifs[0].ofd_ip6 = fr->fr_tifs[0].fd_ip6;
+ old->fr_tifs[1].ofd_ip6 = fr->fr_tifs[0].fd_ip6;
+ old->fr_dif.ofd_ip6 = fr->fr_dif.fd_ip6;
+ if (fr->fr_ifnames[0] >= 0) {
+ strncpy(old->fr_ifnames[0], fr->fr_names + fr->fr_ifnames[0],
+ LIFNAMSIZ);
+ old->fr_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[1] >= 0) {
+ strncpy(old->fr_ifnames[1], fr->fr_names + fr->fr_ifnames[1],
+ LIFNAMSIZ);
+ old->fr_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[2] >= 0) {
+ strncpy(old->fr_ifnames[2], fr->fr_names + fr->fr_ifnames[2],
+ LIFNAMSIZ);
+ old->fr_ifnames[2][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[3] >= 0) {
+ strncpy(old->fr_ifnames[3], fr->fr_names + fr->fr_ifnames[3],
+ LIFNAMSIZ);
+ old->fr_ifnames[3][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_tifs[0].fd_name >= 0) {
+ strncpy(old->fr_tifs[0].fd_ifname,
+ fr->fr_names + fr->fr_tifs[0].fd_name, LIFNAMSIZ);
+ old->fr_tifs[0].fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_tifs[1].fd_name >= 0) {
+ strncpy(old->fr_tifs[1].fd_ifname,
+ fr->fr_names + fr->fr_tifs[1].fd_name, LIFNAMSIZ);
+ old->fr_tifs[1].fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_dif.fd_name >= 0) {
+ strncpy(old->fr_dif.fd_ifname,
+ fr->fr_names + fr->fr_dif.fd_name, LIFNAMSIZ);
+ old->fr_dif.fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_group >= 0) {
+ strncpy(old->fr_group, fr->fr_names + fr->fr_group,
+ FR_GROUPLEN);
+ old->fr_group[FR_GROUPLEN - 1] = '\0';
+ }
+ if (fr->fr_grhead >= 0) {
+ strncpy(old->fr_grhead, fr->fr_names + fr->fr_grhead,
+ FR_GROUPLEN);
+ old->fr_grhead[FR_GROUPLEN - 1] = '\0';
+ }
+}
+
+
+static void
+frentry_current_to_4_1_16(current, old)
+ void *current;
+ frentry_4_1_16_t *old;
+{
+ frentry_t *fr = (frentry_t *)current;
+
+ old->fr_lock = fr->fr_lock;
+ old->fr_next = fr->fr_next;
+ old->fr_grp = (void *)fr->fr_grp;
+ old->fr_isc = fr->fr_isc;
+ old->fr_ifas[0] = fr->fr_ifas[0];
+ old->fr_ifas[1] = fr->fr_ifas[1];
+ old->fr_ifas[2] = fr->fr_ifas[2];
+ old->fr_ifas[3] = fr->fr_ifas[3];
+ old->fr_ptr = fr->fr_ptr;
+ old->fr_comment = NULL;
+ old->fr_ref = fr->fr_ref;
+ old->fr_statecnt = fr->fr_statecnt;
+ old->fr_hits = fr->fr_hits;
+ old->fr_bytes = fr->fr_bytes;
+ old->fr_lastpkt.tv_sec = fr->fr_lastpkt.tv_sec;
+ old->fr_lastpkt.tv_usec = fr->fr_lastpkt.tv_usec;
+ old->fr_curpps = fr->fr_curpps;
+ old->fr_dun.fru_data = fr->fr_dun.fru_data;
+ old->fr_func = fr->fr_func;
+ old->fr_dsize = fr->fr_dsize;
+ old->fr_pps = fr->fr_pps;
+ old->fr_statemax = fr->fr_statemax;
+ old->fr_flineno = fr->fr_flineno;
+ old->fr_type = fr->fr_type;
+ old->fr_flags = fr_frflags5to4(fr->fr_flags);
+ old->fr_logtag = fr->fr_logtag;
+ old->fr_collect = fr->fr_collect;
+ old->fr_arg = fr->fr_arg;
+ old->fr_loglevel = fr->fr_loglevel;
+ old->fr_age[0] = fr->fr_age[0];
+ old->fr_age[1] = fr->fr_age[1];
+ if (old->fr_v == 4)
+ fr->fr_family = AF_INET;
+ if (old->fr_v == 6)
+ fr->fr_family = AF_INET6;
+ old->fr_icode = fr->fr_icode;
+ old->fr_cksum = fr->fr_cksum;
+ old->fr_tifs[0].ofd_ip6 = fr->fr_tifs[0].fd_ip6;
+ old->fr_tifs[1].ofd_ip6 = fr->fr_tifs[0].fd_ip6;
+ old->fr_dif.ofd_ip6 = fr->fr_dif.fd_ip6;
+ if (fr->fr_ifnames[0] >= 0) {
+ strncpy(old->fr_ifnames[0], fr->fr_names + fr->fr_ifnames[0],
+ LIFNAMSIZ);
+ old->fr_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[1] >= 0) {
+ strncpy(old->fr_ifnames[1], fr->fr_names + fr->fr_ifnames[1],
+ LIFNAMSIZ);
+ old->fr_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[2] >= 0) {
+ strncpy(old->fr_ifnames[2], fr->fr_names + fr->fr_ifnames[2],
+ LIFNAMSIZ);
+ old->fr_ifnames[2][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[3] >= 0) {
+ strncpy(old->fr_ifnames[3], fr->fr_names + fr->fr_ifnames[3],
+ LIFNAMSIZ);
+ old->fr_ifnames[3][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_tifs[0].fd_name >= 0) {
+ strncpy(old->fr_tifs[0].fd_ifname,
+ fr->fr_names + fr->fr_tifs[0].fd_name, LIFNAMSIZ);
+ old->fr_tifs[0].fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_tifs[1].fd_name >= 0) {
+ strncpy(old->fr_tifs[1].fd_ifname,
+ fr->fr_names + fr->fr_tifs[1].fd_name, LIFNAMSIZ);
+ old->fr_tifs[1].fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_dif.fd_name >= 0) {
+ strncpy(old->fr_dif.fd_ifname,
+ fr->fr_names + fr->fr_dif.fd_name, LIFNAMSIZ);
+ old->fr_dif.fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_group >= 0) {
+ strncpy(old->fr_group, fr->fr_names + fr->fr_group,
+ FR_GROUPLEN);
+ old->fr_group[FR_GROUPLEN - 1] = '\0';
+ }
+ if (fr->fr_grhead >= 0) {
+ strncpy(old->fr_grhead, fr->fr_names + fr->fr_grhead,
+ FR_GROUPLEN);
+ old->fr_grhead[FR_GROUPLEN - 1] = '\0';
+ }
+}
+
+
+static void
+frentry_current_to_4_1_0(current, old)
+ void *current;
+ frentry_4_1_0_t *old;
+{
+ frentry_t *fr = (frentry_t *)current;
+
+ old->fr_lock = fr->fr_lock;
+ old->fr_next = fr->fr_next;
+ old->fr_grp = (void *)fr->fr_grp;
+ old->fr_isc = fr->fr_isc;
+ old->fr_ifas[0] = fr->fr_ifas[0];
+ old->fr_ifas[1] = fr->fr_ifas[1];
+ old->fr_ifas[2] = fr->fr_ifas[2];
+ old->fr_ifas[3] = fr->fr_ifas[3];
+ old->fr_ptr = fr->fr_ptr;
+ old->fr_comment = NULL;
+ old->fr_ref = fr->fr_ref;
+ old->fr_statecnt = fr->fr_statecnt;
+ old->fr_hits = fr->fr_hits;
+ old->fr_bytes = fr->fr_bytes;
+ old->fr_lastpkt.tv_sec = fr->fr_lastpkt.tv_sec;
+ old->fr_lastpkt.tv_usec = fr->fr_lastpkt.tv_usec;
+ old->fr_curpps = fr->fr_curpps;
+ old->fr_dun.fru_data = fr->fr_dun.fru_data;
+ old->fr_func = fr->fr_func;
+ old->fr_dsize = fr->fr_dsize;
+ old->fr_pps = fr->fr_pps;
+ old->fr_statemax = fr->fr_statemax;
+ old->fr_flineno = fr->fr_flineno;
+ old->fr_type = fr->fr_type;
+ old->fr_flags = fr_frflags5to4(fr->fr_flags);
+ old->fr_logtag = fr->fr_logtag;
+ old->fr_collect = fr->fr_collect;
+ old->fr_arg = fr->fr_arg;
+ old->fr_loglevel = fr->fr_loglevel;
+ old->fr_age[0] = fr->fr_age[0];
+ old->fr_age[1] = fr->fr_age[1];
+ if (old->fr_v == 4)
+ fr->fr_family = AF_INET;
+ if (old->fr_v == 6)
+ fr->fr_family = AF_INET6;
+ old->fr_icode = fr->fr_icode;
+ old->fr_cksum = fr->fr_cksum;
+ old->fr_tifs[0].ofd_ip6 = fr->fr_tifs[0].fd_ip6;
+ old->fr_tifs[1].ofd_ip6 = fr->fr_tifs[0].fd_ip6;
+ old->fr_dif.ofd_ip6 = fr->fr_dif.fd_ip6;
+ if (fr->fr_ifnames[0] >= 0) {
+ strncpy(old->fr_ifnames[0], fr->fr_names + fr->fr_ifnames[0],
+ LIFNAMSIZ);
+ old->fr_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[1] >= 0) {
+ strncpy(old->fr_ifnames[1], fr->fr_names + fr->fr_ifnames[1],
+ LIFNAMSIZ);
+ old->fr_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[2] >= 0) {
+ strncpy(old->fr_ifnames[2], fr->fr_names + fr->fr_ifnames[2],
+ LIFNAMSIZ);
+ old->fr_ifnames[2][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_ifnames[3] >= 0) {
+ strncpy(old->fr_ifnames[3], fr->fr_names + fr->fr_ifnames[3],
+ LIFNAMSIZ);
+ old->fr_ifnames[3][LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_tifs[0].fd_name >= 0) {
+ strncpy(old->fr_tifs[0].fd_ifname,
+ fr->fr_names + fr->fr_tifs[0].fd_name, LIFNAMSIZ);
+ old->fr_tifs[0].fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_tifs[1].fd_name >= 0) {
+ strncpy(old->fr_tifs[1].fd_ifname,
+ fr->fr_names + fr->fr_tifs[1].fd_name, LIFNAMSIZ);
+ old->fr_tifs[1].fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_dif.fd_name >= 0) {
+ strncpy(old->fr_dif.fd_ifname,
+ fr->fr_names + fr->fr_dif.fd_name, LIFNAMSIZ);
+ old->fr_dif.fd_ifname[LIFNAMSIZ - 1] = '\0';
+ }
+ if (fr->fr_group >= 0) {
+ strncpy(old->fr_group, fr->fr_names + fr->fr_group,
+ FR_GROUPLEN);
+ old->fr_group[FR_GROUPLEN - 1] = '\0';
+ }
+ if (fr->fr_grhead >= 0) {
+ strncpy(old->fr_grhead, fr->fr_names + fr->fr_grhead,
+ FR_GROUPLEN);
+ old->fr_grhead[FR_GROUPLEN - 1] = '\0';
+ }
+}
+
+
+static void
+fr_info_current_to_4_1_24(current, old)
+ void *current;
+ fr_info_4_1_24_t *old;
+{
+ fr_info_t *fin = (fr_info_t *)current;
+
+ old->fin_ifp = fin->fin_ifp;
+ ipf_v5iptov4(&fin->fin_fi, &old->fin_fi);
+ bcopy(&fin->fin_dat, &old->fin_dat, sizeof(fin->fin_dat));
+ old->fin_out = fin->fin_out;
+ old->fin_rev = fin->fin_rev;
+ old->fin_hlen = fin->fin_hlen;
+ old->ofin_tcpf = fin->fin_tcpf;
+ old->fin_icode = fin->fin_icode;
+ old->fin_rule = fin->fin_rule;
+ bcopy(fin->fin_group, old->fin_group, sizeof(fin->fin_group));
+ old->fin_fr = fin->fin_fr;
+ old->fin_dp = fin->fin_dp;
+ old->fin_dlen = fin->fin_dlen;
+ old->fin_plen = fin->fin_plen;
+ old->fin_ipoff = fin->fin_ipoff;
+ old->fin_id = fin->fin_id;
+ old->fin_off = fin->fin_off;
+ old->fin_depth = fin->fin_depth;
+ old->fin_error = fin->fin_error;
+ old->fin_cksum = fin->fin_cksum;
+ old->fin_state = NULL;
+ old->fin_nat = NULL;
+ old->fin_nattag = fin->fin_nattag;
+ old->fin_exthdr = NULL;
+ old->ofin_ip = fin->fin_ip;
+ old->fin_mp = fin->fin_mp;
+ old->fin_m = fin->fin_m;
+#ifdef MENTAT
+ old->fin_qfm = fin->fin_qfm;
+ old->fin_qpi = fin->fin_qpi;
+ old->fin_ifname[0] = '\0';
+#endif
+#ifdef __sgi
+ old->fin_hbuf = fin->fin_hbuf;
+#endif
+}
+
+
+static void
+fr_info_current_to_4_1_23(current, old)
+ void *current;
+ fr_info_4_1_23_t *old;
+{
+ fr_info_t *fin = (fr_info_t *)current;
+
+ old->fin_ifp = fin->fin_ifp;
+ ipf_v5iptov4(&fin->fin_fi, &old->fin_fi);
+ bcopy(&fin->fin_dat, &old->fin_dat, sizeof(fin->fin_dat));
+ old->fin_out = fin->fin_out;
+ old->fin_rev = fin->fin_rev;
+ old->fin_hlen = fin->fin_hlen;
+ old->ofin_tcpf = fin->fin_tcpf;
+ old->fin_icode = fin->fin_icode;
+ old->fin_rule = fin->fin_rule;
+ bcopy(fin->fin_group, old->fin_group, sizeof(fin->fin_group));
+ old->fin_fr = fin->fin_fr;
+ old->fin_dp = fin->fin_dp;
+ old->fin_dlen = fin->fin_dlen;
+ old->fin_plen = fin->fin_plen;
+ old->fin_ipoff = fin->fin_ipoff;
+ old->fin_id = fin->fin_id;
+ old->fin_off = fin->fin_off;
+ old->fin_depth = fin->fin_depth;
+ old->fin_error = fin->fin_error;
+ old->fin_state = NULL;
+ old->fin_nat = NULL;
+ old->fin_nattag = fin->fin_nattag;
+ old->ofin_ip = fin->fin_ip;
+ old->fin_mp = fin->fin_mp;
+ old->fin_m = fin->fin_m;
+#ifdef MENTAT
+ old->fin_qfm = fin->fin_qfm;
+ old->fin_qpi = fin->fin_qpi;
+ old->fin_ifname[0] = '\0';
+#endif
+#ifdef __sgi
+ old->fin_hbuf = fin->fin_hbuf;
+#endif
+}
+
+
+static void
+fr_info_current_to_4_1_11(current, old)
+ void *current;
+ fr_info_4_1_11_t *old;
+{
+ fr_info_t *fin = (fr_info_t *)current;
+
+ old->fin_ifp = fin->fin_ifp;
+ ipf_v5iptov4(&fin->fin_fi, &old->fin_fi);
+ bcopy(&fin->fin_dat, &old->fin_dat, sizeof(fin->fin_dat));
+ old->fin_out = fin->fin_out;
+ old->fin_rev = fin->fin_rev;
+ old->fin_hlen = fin->fin_hlen;
+ old->ofin_tcpf = fin->fin_tcpf;
+ old->fin_icode = fin->fin_icode;
+ old->fin_rule = fin->fin_rule;
+ bcopy(fin->fin_group, old->fin_group, sizeof(fin->fin_group));
+ old->fin_fr = fin->fin_fr;
+ old->fin_dp = fin->fin_dp;
+ old->fin_dlen = fin->fin_dlen;
+ old->fin_plen = fin->fin_plen;
+ old->fin_ipoff = fin->fin_ipoff;
+ old->fin_id = fin->fin_id;
+ old->fin_off = fin->fin_off;
+ old->fin_depth = fin->fin_depth;
+ old->fin_error = fin->fin_error;
+ old->fin_state = NULL;
+ old->fin_nat = NULL;
+ old->fin_nattag = fin->fin_nattag;
+ old->ofin_ip = fin->fin_ip;
+ old->fin_mp = fin->fin_mp;
+ old->fin_m = fin->fin_m;
+#ifdef MENTAT
+ old->fin_qfm = fin->fin_qfm;
+ old->fin_qpi = fin->fin_qpi;
+ old->fin_ifname[0] = '\0';
+#endif
+#ifdef __sgi
+ old->fin_hbuf = fin->fin_hbuf;
+#endif
+}
+
+
+static void
+frauth_current_to_4_1_29(current, old)
+ void *current;
+ frauth_4_1_29_t *old;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ old->fra_age = fra->fra_age;
+ old->fra_len = fra->fra_len;
+ old->fra_index = fra->fra_index;
+ old->fra_pass = fra->fra_pass;
+ fr_info_current_to_4_1_24(&fra->fra_info, &old->fra_info);
+ old->fra_buf = fra->fra_buf;
+ old->fra_flx = fra->fra_flx;
+#ifdef MENTAT
+ old->fra_q = fra->fra_q;
+ old->fra_m = fra->fra_m;
+#endif
+}
+
+
+static void
+frauth_current_to_4_1_24(current, old)
+ void *current;
+ frauth_4_1_24_t *old;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ old->fra_age = fra->fra_age;
+ old->fra_len = fra->fra_len;
+ old->fra_index = fra->fra_index;
+ old->fra_pass = fra->fra_pass;
+ fr_info_current_to_4_1_24(&fra->fra_info, &old->fra_info);
+ old->fra_buf = fra->fra_buf;
+#ifdef MENTAT
+ old->fra_q = fra->fra_q;
+ old->fra_m = fra->fra_m;
+#endif
+}
+
+
+static void
+frauth_current_to_4_1_23(current, old)
+ void *current;
+ frauth_4_1_23_t *old;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ old->fra_age = fra->fra_age;
+ old->fra_len = fra->fra_len;
+ old->fra_index = fra->fra_index;
+ old->fra_pass = fra->fra_pass;
+ fr_info_current_to_4_1_23(&fra->fra_info, &old->fra_info);
+ old->fra_buf = fra->fra_buf;
+#ifdef MENTAT
+ old->fra_q = fra->fra_q;
+ old->fra_m = fra->fra_m;
+#endif
+}
+
+
+static void
+frauth_current_to_4_1_11(current, old)
+ void *current;
+ frauth_4_1_11_t *old;
+{
+ frauth_t *fra = (frauth_t *)current;
+
+ old->fra_age = fra->fra_age;
+ old->fra_len = fra->fra_len;
+ old->fra_index = fra->fra_index;
+ old->fra_pass = fra->fra_pass;
+ fr_info_current_to_4_1_11(&fra->fra_info, &old->fra_info);
+ old->fra_buf = fra->fra_buf;
+#ifdef MENTAT
+ old->fra_q = fra->fra_q;
+ old->fra_m = fra->fra_m;
+#endif
+}
+
+
+static void
+ipnat_current_to_4_1_14(current, old)
+ void *current;
+ ipnat_4_1_14_t *old;
+{
+ ipnat_t *np = (ipnat_t *)current;
+
+ old->in_next = np->in_next;
+ old->in_rnext = np->in_rnext;
+ old->in_prnext = np->in_prnext;
+ old->in_mnext = np->in_mnext;
+ old->in_pmnext = np->in_pmnext;
+ old->in_tqehead[0] = np->in_tqehead[0];
+ old->in_tqehead[1] = np->in_tqehead[1];
+ old->in_ifps[0] = np->in_ifps[0];
+ old->in_ifps[1] = np->in_ifps[1];
+ old->in_apr = np->in_apr;
+ old->in_comment = np->in_comment;
+ old->in_space = np->in_space;
+ old->in_hits = np->in_hits;
+ old->in_use = np->in_use;
+ old->in_hv = np->in_hv[0];
+ old->in_flineno = np->in_flineno;
+ if (old->in_redir == NAT_REDIRECT)
+ old->in_pnext = np->in_dpnext;
+ else
+ old->in_pnext = np->in_spnext;
+ old->in_v = np->in_v[0];
+ old->in_flags = np->in_flags;
+ old->in_mssclamp = np->in_mssclamp;
+ old->in_age[0] = np->in_age[0];
+ old->in_age[1] = np->in_age[1];
+ old->in_redir = np->in_redir;
+ old->in_p = np->in_pr[0];
+ if (np->in_redir == NAT_REDIRECT) {
+ old->in_next6 = np->in_ndst.na_nextaddr;
+ old->in_in[0] = np->in_ndst.na_addr[0];
+ old->in_in[1] = np->in_ndst.na_addr[1];
+ old->in_out[0] = np->in_odst.na_addr[0];
+ old->in_out[1] = np->in_odst.na_addr[1];
+ old->in_src[0] = np->in_osrc.na_addr[0];
+ old->in_src[1] = np->in_osrc.na_addr[1];
+ } else {
+ old->in_next6 = np->in_nsrc.na_nextaddr;
+ old->in_out[0] = np->in_nsrc.na_addr[0];
+ old->in_out[1] = np->in_nsrc.na_addr[1];
+ old->in_in[0] = np->in_osrc.na_addr[0];
+ old->in_in[1] = np->in_osrc.na_addr[1];
+ old->in_src[0] = np->in_odst.na_addr[0];
+ old->in_src[1] = np->in_odst.na_addr[1];
+ }
+ ipfv5tuctov4(&np->in_tuc, &old->in_tuc);
+ if (np->in_redir == NAT_REDIRECT) {
+ old->in_port[0] = np->in_dpmin;
+ old->in_port[1] = np->in_dpmax;
+ } else {
+ old->in_port[0] = np->in_spmin;
+ old->in_port[1] = np->in_spmax;
+ }
+ old->in_ppip = np->in_ppip;
+ old->in_ippip = np->in_ippip;
+ bcopy(&np->in_tag, &old->in_tag, sizeof(np->in_tag));
+
+ if (np->in_ifnames[0] >= 0) {
+ strncpy(old->in_ifnames[0], np->in_names + np->in_ifnames[0],
+ LIFNAMSIZ);
+ old->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ }
+ if (np->in_ifnames[1] >= 0) {
+ strncpy(old->in_ifnames[1], np->in_names + np->in_ifnames[1],
+ LIFNAMSIZ);
+ old->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ }
+ if (np->in_plabel >= 0) {
+ strncpy(old->in_plabel, np->in_names + np->in_plabel,
+ APR_LABELLEN);
+ old->in_plabel[APR_LABELLEN - 1] = '\0';
+ }
+}
+
+
+static void
+ipnat_current_to_4_1_0(current, old)
+ void *current;
+ ipnat_4_1_0_t *old;
+{
+ ipnat_t *np = (ipnat_t *)current;
+
+ old->in_next = np->in_next;
+ old->in_rnext = np->in_rnext;
+ old->in_prnext = np->in_prnext;
+ old->in_mnext = np->in_mnext;
+ old->in_pmnext = np->in_pmnext;
+ old->in_tqehead[0] = np->in_tqehead[0];
+ old->in_tqehead[1] = np->in_tqehead[1];
+ old->in_ifps[0] = np->in_ifps[0];
+ old->in_ifps[1] = np->in_ifps[1];
+ old->in_apr = np->in_apr;
+ old->in_comment = np->in_comment;
+ old->in_space = np->in_space;
+ old->in_hits = np->in_hits;
+ old->in_use = np->in_use;
+ old->in_hv = np->in_hv[0];
+ old->in_flineno = np->in_flineno;
+ if (old->in_redir == NAT_REDIRECT)
+ old->in_pnext = np->in_dpnext;
+ else
+ old->in_pnext = np->in_spnext;
+ old->in_v = np->in_v[0];
+ old->in_flags = np->in_flags;
+ old->in_mssclamp = np->in_mssclamp;
+ old->in_age[0] = np->in_age[0];
+ old->in_age[1] = np->in_age[1];
+ old->in_redir = np->in_redir;
+ old->in_p = np->in_pr[0];
+ if (np->in_redir == NAT_REDIRECT) {
+ old->in_next6 = np->in_ndst.na_nextaddr;
+ old->in_in[0] = np->in_ndst.na_addr[0];
+ old->in_in[1] = np->in_ndst.na_addr[1];
+ old->in_out[0] = np->in_odst.na_addr[0];
+ old->in_out[1] = np->in_odst.na_addr[1];
+ old->in_src[0] = np->in_osrc.na_addr[0];
+ old->in_src[1] = np->in_osrc.na_addr[1];
+ } else {
+ old->in_next6 = np->in_nsrc.na_nextaddr;
+ old->in_out[0] = np->in_nsrc.na_addr[0];
+ old->in_out[1] = np->in_nsrc.na_addr[1];
+ old->in_in[0] = np->in_osrc.na_addr[0];
+ old->in_in[1] = np->in_osrc.na_addr[1];
+ old->in_src[0] = np->in_odst.na_addr[0];
+ old->in_src[1] = np->in_odst.na_addr[1];
+ }
+ ipfv5tuctov4(&np->in_tuc, &old->in_tuc);
+ if (np->in_redir == NAT_REDIRECT) {
+ old->in_port[0] = np->in_dpmin;
+ old->in_port[1] = np->in_dpmax;
+ } else {
+ old->in_port[0] = np->in_spmin;
+ old->in_port[1] = np->in_spmax;
+ }
+ old->in_ppip = np->in_ppip;
+ old->in_ippip = np->in_ippip;
+ bcopy(&np->in_tag, &old->in_tag, sizeof(np->in_tag));
+
+ if (np->in_ifnames[0] >= 0) {
+ strncpy(old->in_ifnames[0], np->in_names + np->in_ifnames[0],
+ LIFNAMSIZ);
+ old->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ }
+ if (np->in_ifnames[1] >= 0) {
+ strncpy(old->in_ifnames[1], np->in_names + np->in_ifnames[1],
+ LIFNAMSIZ);
+ old->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ }
+ if (np->in_plabel >= 0) {
+ strncpy(old->in_plabel, np->in_names + np->in_plabel,
+ APR_LABELLEN);
+ old->in_plabel[APR_LABELLEN - 1] = '\0';
+ }
+}
+
+
+static void
+ipstate_current_to_4_1_16(current, old)
+ void *current;
+ ipstate_4_1_16_t *old;
+{
+ ipstate_t *is = (ipstate_t *)current;
+
+ old->is_lock = is->is_lock;
+ old->is_next = is->is_next;
+ old->is_pnext = is->is_pnext;
+ old->is_hnext = is->is_hnext;
+ old->is_phnext = is->is_phnext;
+ old->is_me = is->is_me;
+ old->is_ifp[0] = is->is_ifp[0];
+ old->is_ifp[1] = is->is_ifp[1];
+ old->is_sync = is->is_sync;
+ old->is_rule = is->is_rule;
+ old->is_tqehead[0] = is->is_tqehead[0];
+ old->is_tqehead[1] = is->is_tqehead[1];
+ old->is_isc = is->is_isc;
+ old->is_pkts[0] = is->is_pkts[0];
+ old->is_pkts[1] = is->is_pkts[1];
+ old->is_pkts[2] = is->is_pkts[2];
+ old->is_pkts[3] = is->is_pkts[3];
+ old->is_bytes[0] = is->is_bytes[0];
+ old->is_bytes[1] = is->is_bytes[1];
+ old->is_bytes[2] = is->is_bytes[2];
+ old->is_bytes[3] = is->is_bytes[3];
+ old->is_icmppkts[0] = is->is_icmppkts[0];
+ old->is_icmppkts[1] = is->is_icmppkts[1];
+ old->is_icmppkts[2] = is->is_icmppkts[2];
+ old->is_icmppkts[3] = is->is_icmppkts[3];
+ old->is_sti = is->is_sti;
+ old->is_frage[0] = is->is_frage[0];
+ old->is_frage[1] = is->is_frage[1];
+ old->is_ref = is->is_ref;
+ old->is_isninc[0] = is->is_isninc[0];
+ old->is_isninc[1] = is->is_isninc[1];
+ old->is_sumd[0] = is->is_sumd[0];
+ old->is_sumd[1] = is->is_sumd[1];
+ old->is_src = is->is_src;
+ old->is_dst = is->is_dst;
+ old->is_pass = is->is_pass;
+ old->is_p = is->is_p;
+ old->is_v = is->is_v;
+ old->is_hv = is->is_hv;
+ old->is_tag = is->is_tag;
+ old->is_opt[0] = is->is_opt[0];
+ old->is_opt[1] = is->is_opt[1];
+ old->is_optmsk[0] = is->is_optmsk[0];
+ old->is_optmsk[1] = is->is_optmsk[1];
+ old->is_sec = is->is_sec;
+ old->is_secmsk = is->is_secmsk;
+ old->is_auth = is->is_auth;
+ old->is_authmsk = is->is_authmsk;
+ ipf_v5tcpinfoto4(&is->is_tcp, &old->is_tcp);
+ old->is_flags = is->is_flags;
+ old->is_flx[0][0] = is->is_flx[0][0];
+ old->is_flx[0][1] = is->is_flx[0][1];
+ old->is_flx[1][0] = is->is_flx[1][0];
+ old->is_flx[1][1] = is->is_flx[1][1];
+ old->is_rulen = is->is_rulen;
+ old->is_s0[0] = is->is_s0[0];
+ old->is_s0[1] = is->is_s0[1];
+ old->is_smsk[0] = is->is_smsk[0];
+ old->is_smsk[1] = is->is_smsk[1];
+ bcopy(is->is_group, old->is_group, sizeof(is->is_group));
+ bcopy(is->is_sbuf, old->is_sbuf, sizeof(is->is_sbuf));
+ bcopy(is->is_ifname, old->is_ifname, sizeof(is->is_ifname));
+}
+
+
+static void
+ipstate_current_to_4_1_0(current, old)
+ void *current;
+ ipstate_4_1_0_t *old;
+{
+ ipstate_t *is = (ipstate_t *)current;
+
+ old->is_lock = is->is_lock;
+ old->is_next = is->is_next;
+ old->is_pnext = is->is_pnext;
+ old->is_hnext = is->is_hnext;
+ old->is_phnext = is->is_phnext;
+ old->is_me = is->is_me;
+ old->is_ifp[0] = is->is_ifp[0];
+ old->is_ifp[1] = is->is_ifp[1];
+ old->is_sync = is->is_sync;
+ bzero(&old->is_nat, sizeof(old->is_nat));
+ old->is_rule = is->is_rule;
+ old->is_tqehead[0] = is->is_tqehead[0];
+ old->is_tqehead[1] = is->is_tqehead[1];
+ old->is_isc = is->is_isc;
+ old->is_pkts[0] = is->is_pkts[0];
+ old->is_pkts[1] = is->is_pkts[1];
+ old->is_pkts[2] = is->is_pkts[2];
+ old->is_pkts[3] = is->is_pkts[3];
+ old->is_bytes[0] = is->is_bytes[0];
+ old->is_bytes[1] = is->is_bytes[1];
+ old->is_bytes[2] = is->is_bytes[2];
+ old->is_bytes[3] = is->is_bytes[3];
+ old->is_icmppkts[0] = is->is_icmppkts[0];
+ old->is_icmppkts[1] = is->is_icmppkts[1];
+ old->is_icmppkts[2] = is->is_icmppkts[2];
+ old->is_icmppkts[3] = is->is_icmppkts[3];
+ old->is_sti = is->is_sti;
+ old->is_frage[0] = is->is_frage[0];
+ old->is_frage[1] = is->is_frage[1];
+ old->is_ref = is->is_ref;
+ old->is_isninc[0] = is->is_isninc[0];
+ old->is_isninc[1] = is->is_isninc[1];
+ old->is_sumd[0] = is->is_sumd[0];
+ old->is_sumd[1] = is->is_sumd[1];
+ old->is_src = is->is_src;
+ old->is_dst = is->is_dst;
+ old->is_pass = is->is_pass;
+ old->is_p = is->is_p;
+ old->is_v = is->is_v;
+ old->is_hv = is->is_hv;
+ old->is_tag = is->is_tag;
+ old->is_opt[0] = is->is_opt[0];
+ old->is_opt[1] = is->is_opt[1];
+ old->is_optmsk[0] = is->is_optmsk[0];
+ old->is_optmsk[1] = is->is_optmsk[1];
+ old->is_sec = is->is_sec;
+ old->is_secmsk = is->is_secmsk;
+ old->is_auth = is->is_auth;
+ old->is_authmsk = is->is_authmsk;
+ ipf_v5tcpinfoto4(&is->is_tcp, &old->is_tcp);
+ old->is_flags = is->is_flags;
+ old->is_flx[0][0] = is->is_flx[0][0];
+ old->is_flx[0][1] = is->is_flx[0][1];
+ old->is_flx[1][0] = is->is_flx[1][0];
+ old->is_flx[1][1] = is->is_flx[1][1];
+ old->is_rulen = is->is_rulen;
+ old->is_s0[0] = is->is_s0[0];
+ old->is_s0[1] = is->is_s0[1];
+ old->is_smsk[0] = is->is_smsk[0];
+ old->is_smsk[1] = is->is_smsk[1];
+ bcopy(is->is_group, old->is_group, sizeof(is->is_group));
+ bcopy(is->is_sbuf, old->is_sbuf, sizeof(is->is_sbuf));
+ bcopy(is->is_ifname, old->is_ifname, sizeof(is->is_ifname));
+}
+
+
+static void
+ips_stat_current_to_4_1_21(current, old)
+ void *current;
+ ips_stat_4_1_21_t *old;
+{
+ ips_stat_t *st = (ips_stat_t *)current;
+
+ old->iss_hits = st->iss_hits;
+ old->iss_miss = st->iss_check_miss;
+ old->iss_max = st->iss_max;
+ old->iss_maxref = st->iss_max_ref;
+ old->iss_tcp = st->iss_proto[IPPROTO_TCP];
+ old->iss_udp = st->iss_proto[IPPROTO_UDP];
+ old->iss_icmp = st->iss_proto[IPPROTO_ICMP];
+ old->iss_nomem = st->iss_nomem;
+ old->iss_expire = st->iss_expire;
+ old->iss_fin = st->iss_fin;
+ old->iss_active = st->iss_active;
+ old->iss_logged = st->iss_log_ok;
+ old->iss_logfail = st->iss_log_fail;
+ old->iss_inuse = st->iss_inuse;
+ old->iss_wild = st->iss_wild;
+ old->iss_ticks = st->iss_ticks;
+ old->iss_bucketfull = st->iss_bucket_full;
+ old->iss_statesize = st->iss_state_size;
+ old->iss_statemax = st->iss_state_max;
+ old->iss_table = st->iss_table;
+ old->iss_list = st->iss_list;
+ old->iss_bucketlen = (void *)st->iss_bucketlen;
+ old->iss_tcptab = st->iss_tcptab;
+}
+
+
+static void
+ips_stat_current_to_4_1_0(current, old)
+ void *current;
+ ips_stat_4_1_0_t *old;
+{
+ ips_stat_t *st = (ips_stat_t *)current;
+
+ old->iss_hits = st->iss_hits;
+ old->iss_miss = st->iss_check_miss;
+ old->iss_max = st->iss_max;
+ old->iss_maxref = st->iss_max_ref;
+ old->iss_tcp = st->iss_proto[IPPROTO_TCP];
+ old->iss_udp = st->iss_proto[IPPROTO_UDP];
+ old->iss_icmp = st->iss_proto[IPPROTO_ICMP];
+ old->iss_nomem = st->iss_nomem;
+ old->iss_expire = st->iss_expire;
+ old->iss_fin = st->iss_fin;
+ old->iss_active = st->iss_active;
+ old->iss_logged = st->iss_log_ok;
+ old->iss_logfail = st->iss_log_fail;
+ old->iss_inuse = st->iss_inuse;
+ old->iss_wild = st->iss_wild;
+ old->iss_ticks = st->iss_ticks;
+ old->iss_bucketfull = st->iss_bucket_full;
+ old->iss_statesize = st->iss_state_size;
+ old->iss_statemax = st->iss_state_max;
+ old->iss_table = st->iss_table;
+ old->iss_list = st->iss_list;
+ old->iss_bucketlen = (void *)st->iss_bucketlen;
+}
+
+
+static void
+nat_save_current_to_4_1_16(current, old)
+ void *current;
+ nat_save_4_1_16_t *old;
+{
+ nat_save_t *nats = (nat_save_t *)current;
+
+ old->ipn_next = nats->ipn_next;
+ bcopy(&nats->ipn_nat, &old->ipn_nat, sizeof(old->ipn_nat));
+ bcopy(&nats->ipn_ipnat, &old->ipn_ipnat, sizeof(old->ipn_ipnat));
+ frentry_current_to_4_1_16(&nats->ipn_fr, &old->ipn_fr);
+ old->ipn_dsize = nats->ipn_dsize;
+ bcopy(nats->ipn_data, old->ipn_data, sizeof(nats->ipn_data));
+}
+
+
+static void
+nat_save_current_to_4_1_14(current, old)
+ void *current;
+ nat_save_4_1_14_t *old;
+{
+ nat_save_t *nats = (nat_save_t *)current;
+
+ old->ipn_next = nats->ipn_next;
+ bcopy(&nats->ipn_nat, &old->ipn_nat, sizeof(old->ipn_nat));
+ bcopy(&nats->ipn_ipnat, &old->ipn_ipnat, sizeof(old->ipn_ipnat));
+ frentry_current_to_4_1_0(&nats->ipn_fr, &old->ipn_fr);
+ old->ipn_dsize = nats->ipn_dsize;
+ bcopy(nats->ipn_data, old->ipn_data, sizeof(nats->ipn_data));
+}
+
+
+static void
+nat_save_current_to_4_1_3(current, old)
+ void *current;
+ nat_save_4_1_3_t *old;
+{
+ nat_save_t *nats = (nat_save_t *)current;
+
+ old->ipn_next = nats->ipn_next;
+ bcopy(&nats->ipn_nat, &old->ipn_nat, sizeof(old->ipn_nat));
+ bcopy(&nats->ipn_ipnat, &old->ipn_ipnat, sizeof(old->ipn_ipnat));
+ frentry_current_to_4_1_0(&nats->ipn_fr, &old->ipn_fr);
+ old->ipn_dsize = nats->ipn_dsize;
+ bcopy(nats->ipn_data, old->ipn_data, sizeof(nats->ipn_data));
+}
+
+
+static void
+nat_current_to_4_1_25(current, old)
+ void *current;
+ nat_4_1_25_t *old;
+{
+ nat_t *nat = (nat_t *)current;
+
+ old->nat_lock = nat->nat_lock;
+ old->nat_next = (void *)nat->nat_next;
+ old->nat_pnext = (void *)nat->nat_pnext;
+ old->nat_hnext[0] = (void *)nat->nat_hnext[0];
+ old->nat_hnext[1] = (void *)nat->nat_hnext[1];
+ old->nat_phnext[0] = (void *)nat->nat_phnext[0];
+ old->nat_phnext[1] = (void *)nat->nat_phnext[1];
+ old->nat_hm = nat->nat_hm;
+ old->nat_data = nat->nat_data;
+ old->nat_me = (void *)nat->nat_me;
+ old->nat_state = nat->nat_state;
+ old->nat_aps = nat->nat_aps;
+ old->nat_fr = nat->nat_fr;
+ old->nat_ptr = (void *)nat->nat_ptr;
+ old->nat_ifps[0] = nat->nat_ifps[0];
+ old->nat_ifps[1] = nat->nat_ifps[1];
+ old->nat_sync = nat->nat_sync;
+ old->nat_tqe = nat->nat_tqe;
+ old->nat_flags = nat->nat_flags;
+ old->nat_sumd[0] = nat->nat_sumd[0];
+ old->nat_sumd[1] = nat->nat_sumd[1];
+ old->nat_ipsumd = nat->nat_ipsumd;
+ old->nat_mssclamp = nat->nat_mssclamp;
+ old->nat_pkts[0] = nat->nat_pkts[0];
+ old->nat_pkts[1] = nat->nat_pkts[1];
+ old->nat_bytes[0] = nat->nat_bytes[0];
+ old->nat_bytes[1] = nat->nat_bytes[1];
+ old->nat_ref = nat->nat_ref;
+ old->nat_dir = nat->nat_dir;
+ old->nat_p = nat->nat_pr[0];
+ old->nat_use = nat->nat_use;
+ old->nat_hv[0] = nat->nat_hv[0];
+ old->nat_hv[1] = nat->nat_hv[1];
+ old->nat_rev = nat->nat_rev;
+ old->nat_redir = nat->nat_redir;
+ bcopy(nat->nat_ifnames[0], old->nat_ifnames[0], LIFNAMSIZ);
+ bcopy(nat->nat_ifnames[1], old->nat_ifnames[1], LIFNAMSIZ);
+
+ if (nat->nat_redir == NAT_REDIRECT) {
+ old->nat_inip6 = nat->nat_ndst6;
+ old->nat_outip6 = nat->nat_odst6;
+ old->nat_oip6 = nat->nat_osrc6;
+ old->nat_un.nat_unt.ts_sport = nat->nat_ndport;
+ old->nat_un.nat_unt.ts_dport = nat->nat_odport;
+ } else {
+ old->nat_inip6 = nat->nat_osrc6;
+ old->nat_outip6 = nat->nat_nsrc6;
+ old->nat_oip6 = nat->nat_odst6;
+ old->nat_un.nat_unt.ts_sport = nat->nat_osport;
+ old->nat_un.nat_unt.ts_dport = nat->nat_nsport;
+ }
+}
+
+
+static void
+nat_current_to_4_1_14(current, old)
+ void *current;
+ nat_4_1_14_t *old;
+{
+ nat_t *nat = (nat_t *)current;
+
+ old->nat_lock = nat->nat_lock;
+ old->nat_next = nat->nat_next;
+ old->nat_pnext = NULL;
+ old->nat_hnext[0] = NULL;
+ old->nat_hnext[1] = NULL;
+ old->nat_phnext[0] = NULL;
+ old->nat_phnext[1] = NULL;
+ old->nat_hm = nat->nat_hm;
+ old->nat_data = nat->nat_data;
+ old->nat_me = (void *)nat->nat_me;
+ old->nat_state = nat->nat_state;
+ old->nat_aps = nat->nat_aps;
+ old->nat_fr = nat->nat_fr;
+ old->nat_ptr = nat->nat_ptr;
+ old->nat_ifps[0] = nat->nat_ifps[0];
+ old->nat_ifps[1] = nat->nat_ifps[1];
+ old->nat_sync = nat->nat_sync;
+ old->nat_tqe = nat->nat_tqe;
+ old->nat_flags = nat->nat_flags;
+ old->nat_sumd[0] = nat->nat_sumd[0];
+ old->nat_sumd[1] = nat->nat_sumd[1];
+ old->nat_ipsumd = nat->nat_ipsumd;
+ old->nat_mssclamp = nat->nat_mssclamp;
+ old->nat_pkts[0] = nat->nat_pkts[0];
+ old->nat_pkts[1] = nat->nat_pkts[1];
+ old->nat_bytes[0] = nat->nat_bytes[0];
+ old->nat_bytes[1] = nat->nat_bytes[1];
+ old->nat_ref = nat->nat_ref;
+ old->nat_dir = nat->nat_dir;
+ old->nat_p = nat->nat_pr[0];
+ old->nat_use = nat->nat_use;
+ old->nat_hv[0] = nat->nat_hv[0];
+ old->nat_hv[1] = nat->nat_hv[1];
+ old->nat_rev = nat->nat_rev;
+ bcopy(nat->nat_ifnames[0], old->nat_ifnames[0], LIFNAMSIZ);
+ bcopy(nat->nat_ifnames[1], old->nat_ifnames[1], LIFNAMSIZ);
+
+ if (nat->nat_redir == NAT_REDIRECT) {
+ old->nat_inip6 = nat->nat_ndst6;
+ old->nat_outip6 = nat->nat_odst6;
+ old->nat_oip6 = nat->nat_osrc6;
+ old->nat_un.nat_unt.ts_sport = nat->nat_ndport;
+ old->nat_un.nat_unt.ts_dport = nat->nat_odport;
+ } else {
+ old->nat_inip6 = nat->nat_osrc6;
+ old->nat_outip6 = nat->nat_nsrc6;
+ old->nat_oip6 = nat->nat_odst6;
+ old->nat_un.nat_unt.ts_sport = nat->nat_osport;
+ old->nat_un.nat_unt.ts_dport = nat->nat_nsport;
+ }
+}
+
+
+static void
+nat_current_to_4_1_3(current, old)
+ void *current;
+ nat_4_1_3_t *old;
+{
+ nat_t *nat = (nat_t *)current;
+
+ old->nat_lock = nat->nat_lock;
+ old->nat_next = nat->nat_next;
+ old->nat_pnext = NULL;
+ old->nat_hnext[0] = NULL;
+ old->nat_hnext[1] = NULL;
+ old->nat_phnext[0] = NULL;
+ old->nat_phnext[1] = NULL;
+ old->nat_hm = nat->nat_hm;
+ old->nat_data = nat->nat_data;
+ old->nat_me = (void *)nat->nat_me;
+ old->nat_state = nat->nat_state;
+ old->nat_aps = nat->nat_aps;
+ old->nat_fr = nat->nat_fr;
+ old->nat_ptr = nat->nat_ptr;
+ old->nat_ifps[0] = nat->nat_ifps[0];
+ old->nat_ifps[1] = nat->nat_ifps[1];
+ old->nat_sync = nat->nat_sync;
+ old->nat_tqe = nat->nat_tqe;
+ old->nat_flags = nat->nat_flags;
+ old->nat_sumd[0] = nat->nat_sumd[0];
+ old->nat_sumd[1] = nat->nat_sumd[1];
+ old->nat_ipsumd = nat->nat_ipsumd;
+ old->nat_mssclamp = nat->nat_mssclamp;
+ old->nat_pkts[0] = nat->nat_pkts[0];
+ old->nat_pkts[1] = nat->nat_pkts[1];
+ old->nat_bytes[0] = nat->nat_bytes[0];
+ old->nat_bytes[1] = nat->nat_bytes[1];
+ old->nat_ref = nat->nat_ref;
+ old->nat_dir = nat->nat_dir;
+ old->nat_p = nat->nat_pr[0];
+ old->nat_use = nat->nat_use;
+ old->nat_hv[0] = nat->nat_hv[0];
+ old->nat_hv[1] = nat->nat_hv[1];
+ old->nat_rev = nat->nat_rev;
+ bcopy(nat->nat_ifnames[0], old->nat_ifnames[0], LIFNAMSIZ);
+ bcopy(nat->nat_ifnames[1], old->nat_ifnames[1], LIFNAMSIZ);
+
+ if (nat->nat_redir == NAT_REDIRECT) {
+ old->nat_inip6 = nat->nat_ndst6;
+ old->nat_outip6 = nat->nat_odst6;
+ old->nat_oip6 = nat->nat_osrc6;
+ old->nat_un.nat_unt.ts_sport = nat->nat_ndport;
+ old->nat_un.nat_unt.ts_dport = nat->nat_odport;
+ } else {
+ old->nat_inip6 = nat->nat_osrc6;
+ old->nat_outip6 = nat->nat_nsrc6;
+ old->nat_oip6 = nat->nat_odst6;
+ old->nat_un.nat_unt.ts_sport = nat->nat_osport;
+ old->nat_un.nat_unt.ts_dport = nat->nat_nsport;
+ }
+}
+
+#endif /* IPFILTER_COMPAT */
diff --git a/contrib/ipfilter/ip_msnrpc_pxy.c b/contrib/ipfilter/ip_msnrpc_pxy.c
new file mode 100644
index 0000000..40bc084
--- /dev/null
+++ b/contrib/ipfilter/ip_msnrpc_pxy.c
@@ -0,0 +1,328 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2000-2003 by Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Simple DCE transparent proxy for MSN RPC.
+ *
+ * ******* NOTE: THIS PROXY DOES NOT DO ADDRESS TRANSLATION ********
+ *
+ * Id: ip_msnrpc_pxy.c,v 2.17.2.1 2005/02/04 10:22:55 darrenr Exp
+ */
+
+#define IPF_MSNRPC_PROXY
+
+#define IPF_MINMSNRPCLEN 24
+#define IPF_MSNRPCSKIP (2 + 19 + 2 + 2 + 2 + 19 + 2 + 2)
+
+
+typedef struct msnrpchdr {
+ u_char mrh_major; /* major # == 5 */
+ u_char mrh_minor; /* minor # == 0 */
+ u_char mrh_type;
+ u_char mrh_flags;
+ u_32_t mrh_endian;
+ u_short mrh_dlen; /* data size */
+ u_short mrh_alen; /* authentication length */
+ u_32_t mrh_cid; /* call identifier */
+ u_32_t mrh_hint; /* allocation hint */
+ u_short mrh_ctxt; /* presentation context hint */
+ u_char mrh_ccnt; /* cancel count */
+ u_char mrh_ans;
+} msnrpchdr_t;
+
+int ippr_msnrpc_init __P((void));
+void ippr_msnrpc_fini __P((void));
+int ippr_msnrpc_new __P((fr_info_t *, ap_session_t *, nat_t *));
+int ippr_msnrpc_out __P((fr_info_t *, ap_session_t *, nat_t *));
+int ippr_msnrpc_in __P((fr_info_t *, ap_session_t *, nat_t *));
+int ippr_msnrpc_check __P((ip_t *, msnrpchdr_t *));
+
+static frentry_t msnfr;
+
+int msn_proxy_init = 0;
+
+/*
+ * Initialize local structures.
+ */
+int ippr_msnrpc_init()
+{
+ bzero((char *)&msnfr, sizeof(msnfr));
+ msnfr.fr_ref = 1;
+ msnfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
+ MUTEX_INIT(&msnfr.fr_lock, "MSN RPC proxy rule lock");
+ msn_proxy_init = 1;
+
+ return 0;
+}
+
+
+void ippr_msnrpc_fini()
+{
+ if (msn_proxy_init == 1) {
+ MUTEX_DESTROY(&msnfr.fr_lock);
+ msn_proxy_init = 0;
+ }
+}
+
+
+int ippr_msnrpc_new(fin, aps, nat)
+fr_info_t *fin;
+ap_session_t *aps;
+nat_t *nat;
+{
+ msnrpcinfo_t *mri;
+
+ KMALLOC(mri, msnrpcinfo_t *);
+ if (mri == NULL)
+ return -1;
+ aps->aps_data = mri;
+ aps->aps_psiz = sizeof(msnrpcinfo_t);
+
+ bzero((char *)mri, sizeof(*mri));
+ mri->mri_cmd[0] = 0xff;
+ mri->mri_cmd[1] = 0xff;
+ return 0;
+}
+
+
+int ippr_msnrpc_check(ip, mrh)
+ip_t *ip;
+msnrpchdr_t *mrh;
+{
+ if (mrh->mrh_major != 5)
+ return -1;
+ if (mrh->mrh_minor != 0)
+ return -1;
+ if (mrh->mrh_alen != 0)
+ return -1;
+ if (mrh->mrh_endian == 0x10) {
+ /* Both gateway and packet match endian */
+ if (mrh->mrh_dlen > ip->ip_len)
+ return -1;
+ if (mrh->mrh_type == 0 || mrh->mrh_type == 2)
+ if (mrh->mrh_hint > ip->ip_len)
+ return -1;
+ } else if (mrh->mrh_endian == 0x10000000) {
+ /* XXX - Endian mismatch - should be swapping! */
+ return -1;
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+
+int ippr_msnrpc_out(fin, ip, aps, nat)
+fr_info_t *fin;
+ip_t *ip;
+ap_session_t *aps;
+nat_t *nat;
+{
+ msnrpcinfo_t *mri;
+ msnrpchdr_t *mrh;
+ tcphdr_t *tcp;
+ int dlen;
+
+ mri = aps->aps_data;
+ if (mri == NULL)
+ return 0;
+
+ tcp = (tcphdr_t *)fin->fin_dp;
+ dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
+ if (dlen < IPF_MINMSNRPCLEN)
+ return 0;
+
+ mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2));
+ if (ippr_msnrpc_check(ip, mrh))
+ return 0;
+
+ mri->mri_valid++;
+
+ switch (mrh->mrh_type)
+ {
+ case 0x0b : /* BIND */
+ case 0x00 : /* REQUEST */
+ break;
+ case 0x0c : /* BIND ACK */
+ case 0x02 : /* RESPONSE */
+ default:
+ return 0;
+ }
+ mri->mri_cmd[1] = mrh->mrh_type;
+ return 0;
+}
+
+
+int ippr_msnrpc_in(fin, ip, aps, nat)
+fr_info_t *fin;
+ip_t *ip;
+ap_session_t *aps;
+nat_t *nat;
+{
+ tcphdr_t *tcp, tcph, *tcp2 = &tcph;
+ int dlen, sz, sz2, i;
+ msnrpcinfo_t *mri;
+ msnrpchdr_t *mrh;
+ fr_info_t fi;
+ u_short len;
+ char *s;
+
+ mri = aps->aps_data;
+ if (mri == NULL)
+ return 0;
+ tcp = (tcphdr_t *)fin->fin_dp;
+ dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
+ if (dlen < IPF_MINMSNRPCLEN)
+ return 0;
+
+ mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2));
+ if (ippr_msnrpc_check(ip, mrh))
+ return 0;
+
+ mri->mri_valid++;
+
+ switch (mrh->mrh_type)
+ {
+ case 0x0c : /* BIND ACK */
+ if (mri->mri_cmd[1] != 0x0b)
+ return 0;
+ break;
+ case 0x02 : /* RESPONSE */
+ if (mri->mri_cmd[1] != 0x00)
+ return 0;
+ break;
+ case 0x0b : /* BIND */
+ case 0x00 : /* REQUEST */
+ default:
+ return 0;
+ }
+ mri->mri_cmd[0] = mrh->mrh_type;
+ dlen -= sizeof(*mrh);
+
+ /*
+ * Only processes RESPONSE's
+ */
+ if (mrh->mrh_type != 0x02)
+ return 0;
+
+ /*
+ * Skip over some bytes...what are these really ?
+ */
+ if (dlen <= 44)
+ return 0;
+ s = (char *)(mrh + 1) + 20;
+ dlen -= 20;
+ bcopy(s, (char *)&len, sizeof(len));
+ if (len == 1) {
+ s += 20;
+ dlen -= 20;
+ } else if (len == 2) {
+ s += 24;
+ dlen -= 24;
+ } else
+ return 0;
+
+ if (dlen <= 10)
+ return 0;
+ dlen -= 10;
+ bcopy(s, (char *)&sz, sizeof(sz));
+ s += sizeof(sz);
+ bcopy(s, (char *)&sz2, sizeof(sz2));
+ s += sizeof(sz2);
+ if (sz2 != sz)
+ return 0;
+ if (sz > dlen)
+ return 0;
+ if (*s++ != 5)
+ return 0;
+ if (*s++ != 0)
+ return 0;
+ sz -= IPF_MSNRPCSKIP;
+ s += IPF_MSNRPCSKIP;
+ dlen -= IPF_MSNRPCSKIP;
+
+ do {
+ if (sz < 7 || dlen < 7)
+ break;
+ bcopy(s, (char *)&len, sizeof(len));
+ if (dlen < len)
+ break;
+ if (sz < len)
+ break;
+
+ if (len != 1)
+ break;
+ sz -= 3;
+ i = *(s + 2);
+ s += 3;
+ dlen -= 3;
+
+ bcopy(s, (char *)&len, sizeof(len));
+ if (dlen < len)
+ break;
+ if (sz < len)
+ break;
+ s += sizeof(len);
+
+ switch (i)
+ {
+ case 7 :
+ if (len == 2) {
+ bcopy(s, (char *)&mri->mri_rport, 2);
+ mri->mri_flags |= 1;
+ }
+ break;
+ case 9 :
+ if (len == 4) {
+ bcopy(s, (char *)&mri->mri_raddr, 4);
+ mri->mri_flags |= 2;
+ }
+ break;
+ default :
+ break;
+ }
+ sz -= len;
+ s += len;
+ dlen -= len;
+ } while (sz > 0);
+
+ if (mri->mri_flags == 3) {
+ int slen;
+
+ bcopy((char *)fin, (char *)&fi, sizeof(fi));
+ bzero((char *)tcp2, sizeof(*tcp2));
+
+ slen = ip->ip_len;
+ ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
+ bcopy((char *)fin, (char *)&fi, sizeof(fi));
+ bzero((char *)tcp2, sizeof(*tcp2));
+ tcp2->th_win = htons(8192);
+ TCP_OFF_A(tcp2, 5);
+ fi.fin_data[0] = htons(mri->mri_rport);
+ tcp2->th_sport = mri->mri_rport;
+ fi.fin_data[1] = 0;
+ tcp2->th_dport = 0;
+ fi.fin_state = NULL;
+ fi.fin_nat = NULL;
+ fi.fin_dlen = sizeof(*tcp2);
+ fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
+ fi.fin_dp = (char *)tcp2;
+ fi.fin_fi.fi_daddr = ip->ip_dst.s_addr;
+ fi.fin_fi.fi_saddr = mri->mri_raddr.s_addr;
+ if (!fi.fin_fr)
+ fi.fin_fr = &msnfr;
+ if (fr_stlookup(&fi, NULL, NULL)) {
+ RWLOCK_EXIT(&ipf_state);
+ } else {
+ (void) fr_addstate(&fi, NULL, SI_W_DPORT|SI_CLONE);
+ if (fi.fin_state != NULL)
+ fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
+ }
+ ip->ip_len = slen;
+ }
+ mri->mri_flags = 0;
+ return 0;
+}
diff --git a/contrib/ipfilter/ipf.h b/contrib/ipfilter/ipf.h
new file mode 100644
index 0000000..dfae008
--- /dev/null
+++ b/contrib/ipfilter/ipf.h
@@ -0,0 +1,403 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * @(#)ipf.h 1.12 6/5/96
+ * $Id$
+ */
+
+#ifndef __IPF_H__
+#define __IPF_H__
+
+#if defined(__osf__)
+# define radix_mask ipf_radix_mask
+# define radix_node ipf_radix_node
+# define radix_node_head ipf_radix_node_head
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+/*
+ * This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD.
+ * Needed here because on some systems <sys/uio.h> gets included by things
+ * like <sys/socket.h>
+ */
+#ifndef _KERNEL
+# define ADD_KERNEL
+# define _KERNEL
+# define KERNEL
+#endif
+#ifdef __OpenBSD__
+struct file;
+#endif
+#include <sys/uio.h>
+#ifdef ADD_KERNEL
+# undef _KERNEL
+# undef KERNEL
+#endif
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#ifndef TCP_PAWS_IDLE /* IRIX */
+# include <netinet/tcp.h>
+#endif
+#include <netinet/udp.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#if !defined(__SVR4) && !defined(__svr4__) && defined(sun)
+# include <strings.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_auth.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+#include "netinet/ip_scan.h"
+#include "netinet/ip_htable.h"
+#include "netinet/ip_sync.h"
+#include "netinet/ip_dstlist.h"
+
+#include "opts.h"
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+#ifndef __STDC__
+# undef const
+# define const
+#endif
+
+#ifndef U_32_T
+# define U_32_T 1
+# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
+ defined(__sgi)
+typedef u_int32_t u_32_t;
+# else
+# if defined(__alpha__) || defined(__alpha) || defined(_LP64)
+typedef unsigned int u_32_t;
+# else
+# if SOLARIS2 >= 6
+typedef uint32_t u_32_t;
+# else
+typedef unsigned int u_32_t;
+# endif
+# endif
+# endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */
+#endif /* U_32_T */
+
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN 256
+#endif
+
+#define MAX_ICMPCODE 16
+#define MAX_ICMPTYPE 19
+
+#define PRINTF (void)printf
+#define FPRINTF (void)fprintf
+
+
+struct ipopt_names {
+ int on_value;
+ int on_bit;
+ int on_siz;
+ char *on_name;
+};
+
+
+typedef struct alist_s {
+ struct alist_s *al_next;
+ int al_not;
+ int al_family;
+ i6addr_t al_i6addr;
+ i6addr_t al_i6mask;
+} alist_t;
+
+#define al_addr al_i6addr.in4_addr
+#define al_mask al_i6mask.in4_addr
+#define al_1 al_addr
+#define al_2 al_mask
+
+
+typedef struct plist_s {
+ struct plist_s *pl_next;
+ int pl_compare;
+ u_short pl_port1;
+ u_short pl_port2;
+} plist_t;
+
+
+typedef struct {
+ u_short fb_c;
+ u_char fb_t;
+ u_char fb_f;
+ u_32_t fb_k;
+} fakebpf_t;
+
+
+typedef struct {
+ char *it_name;
+ int it_v4;
+ int it_v6;
+} icmptype_t;
+
+
+typedef struct wordtab {
+ char *w_word;
+ int w_value;
+} wordtab_t;
+
+
+typedef struct namelist {
+ struct namelist *na_next;
+ char *na_name;
+ int na_value;
+} namelist_t;
+
+
+typedef struct proxyrule {
+ struct proxyrule *pr_next;
+ char *pr_proxy;
+ char *pr_conf;
+ namelist_t *pr_names;
+ int pr_proto;
+} proxyrule_t;
+
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || \
+ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
+ SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux)
+# include <stdarg.h>
+typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...));
+#else
+typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *));
+#endif
+typedef int (* addfunc_t) __P((int, ioctlfunc_t, void *));
+typedef int (* copyfunc_t) __P((void *, void *, size_t));
+
+
+/*
+ * SunOS4
+ */
+#if defined(sun) && !defined(__SVR4) && !defined(__svr4__)
+extern int ioctl __P((int, int, void *));
+#endif
+
+extern char thishost[];
+extern char flagset[];
+extern u_char flags[];
+extern struct ipopt_names ionames[];
+extern struct ipopt_names secclass[];
+extern char *icmpcodes[MAX_ICMPCODE + 1];
+extern char *icmptypes[MAX_ICMPTYPE + 1];
+extern int use_inet6;
+extern int lineNum;
+extern int debuglevel;
+extern struct ipopt_names v6ionames[];
+extern icmptype_t icmptypelist[];
+extern wordtab_t statefields[];
+extern wordtab_t natfields[];
+extern wordtab_t poolfields[];
+
+
+extern int addicmp __P((char ***, struct frentry *, int));
+extern int addipopt __P((char *, struct ipopt_names *, int, char *));
+extern int addkeep __P((char ***, struct frentry *, int));
+extern alist_t *alist_new __P((int, char *));
+extern void alist_free __P((alist_t *));
+extern void assigndefined __P((char *));
+extern void binprint __P((void *, size_t));
+extern u_32_t buildopts __P((char *, char *, int));
+extern int checkrev __P((char *));
+extern int connecttcp __P((char *, int));
+extern int count6bits __P((u_32_t *));
+extern int count4bits __P((u_32_t));
+extern char *fac_toname __P((int));
+extern int fac_findname __P((char *));
+extern const char *familyname __P((const int));
+extern void fill6bits __P((int, u_int *));
+extern wordtab_t *findword __P((wordtab_t *, char *));
+extern int ftov __P((int));
+extern char *ipf_geterror __P((int, ioctlfunc_t *));
+extern int genmask __P((int, char *, i6addr_t *));
+extern int gethost __P((int, char *, i6addr_t *));
+extern int geticmptype __P((int, char *));
+extern int getport __P((struct frentry *, char *, u_short *, char *));
+extern int getportproto __P((char *, int));
+extern int getproto __P((char *));
+extern char *getnattype __P((struct nat *));
+extern char *getsumd __P((u_32_t));
+extern u_32_t getoptbyname __P((char *));
+extern u_32_t getoptbyvalue __P((int));
+extern u_32_t getv6optbyname __P((char *));
+extern u_32_t getv6optbyvalue __P((int));
+extern char *icmptypename __P((int, int));
+extern void initparse __P((void));
+extern void ipf_dotuning __P((int, char *, ioctlfunc_t));
+extern int ipf_addrule __P((int, ioctlfunc_t, void *));
+extern void ipf_mutex_clean __P((void));
+extern int ipf_parsefile __P((int, addfunc_t, ioctlfunc_t *, char *));
+extern int ipf_parsesome __P((int, addfunc_t, ioctlfunc_t *, FILE *));
+extern void ipf_perror __P((int, char *));
+extern int ipf_perror_fd __P(( int, ioctlfunc_t, char *));
+extern void ipf_rwlock_clean __P((void));
+extern char *ipf_strerror __P((int));
+extern void ipferror __P((int, char *));
+extern int ipmon_parsefile __P((char *));
+extern int ipmon_parsesome __P((FILE *));
+extern int ipnat_addrule __P((int, ioctlfunc_t, void *));
+extern int ipnat_parsefile __P((int, addfunc_t, ioctlfunc_t, char *));
+extern int ipnat_parsesome __P((int, addfunc_t, ioctlfunc_t, FILE *));
+extern int ippool_parsefile __P((int, char *, ioctlfunc_t));
+extern int ippool_parsesome __P((int, FILE *, ioctlfunc_t));
+extern int kmemcpywrap __P((void *, void *, size_t));
+extern char *kvatoname __P((ipfunc_t, ioctlfunc_t));
+extern int load_dstlist __P((struct ippool_dst *, ioctlfunc_t,
+ ipf_dstnode_t *));
+extern int load_dstlistnode __P((int, char *, struct ipf_dstnode *,
+ ioctlfunc_t));
+extern alist_t *load_file __P((char *));
+extern int load_hash __P((struct iphtable_s *, struct iphtent_s *,
+ ioctlfunc_t));
+extern int load_hashnode __P((int, char *, struct iphtent_s *, int,
+ ioctlfunc_t));
+extern alist_t *load_http __P((char *));
+extern int load_pool __P((struct ip_pool_s *list, ioctlfunc_t));
+extern int load_poolnode __P((int, char *, ip_pool_node_t *, int, ioctlfunc_t));
+extern alist_t *load_url __P((char *));
+extern alist_t *make_range __P((int, struct in_addr, struct in_addr));
+extern void mb_hexdump __P((mb_t *, FILE *));
+extern ipfunc_t nametokva __P((char *, ioctlfunc_t));
+extern void nat_setgroupmap __P((struct ipnat *));
+extern int ntomask __P((int, int, u_32_t *));
+extern u_32_t optname __P((char ***, u_short *, int));
+extern wordtab_t *parsefields __P((wordtab_t *, char *));
+extern int *parseipfexpr __P((char *, char **));
+extern int parsewhoisline __P((char *, addrfamily_t *, addrfamily_t *));
+extern void pool_close __P((void));
+extern int pool_fd __P((void));
+extern int pool_ioctl __P((ioctlfunc_t, ioctlcmd_t, void *));
+extern int pool_open __P((void));
+extern char *portname __P((int, int));
+extern int pri_findname __P((char *));
+extern char *pri_toname __P((int));
+extern void print_toif __P((int, char *, char *, struct frdest *));
+extern void printaps __P((ap_session_t *, int, int));
+extern void printaddr __P((int, int, char *, int, u_32_t *, u_32_t *));
+extern void printbuf __P((char *, int, int));
+extern void printfieldhdr __P((wordtab_t *, wordtab_t *));
+extern void printfr __P((struct frentry *, ioctlfunc_t));
+extern struct iphtable_s *printhash __P((struct iphtable_s *, copyfunc_t,
+ char *, int, wordtab_t *));
+extern struct iphtable_s *printhash_live __P((iphtable_t *, int, char *,
+ int, wordtab_t *));
+extern ippool_dst_t *printdstl_live __P((ippool_dst_t *, int, char *,
+ int, wordtab_t *));
+extern void printhashdata __P((iphtable_t *, int));
+extern struct iphtent_s *printhashnode __P((struct iphtable_s *,
+ struct iphtent_s *,
+ copyfunc_t, int, wordtab_t *));
+extern void printhost __P((int, u_32_t *));
+extern void printhostmask __P((int, u_32_t *, u_32_t *));
+extern void printip __P((int, u_32_t *));
+extern void printlog __P((struct frentry *));
+extern void printlookup __P((char *, i6addr_t *addr, i6addr_t *mask));
+extern void printmask __P((int, u_32_t *));
+extern void printnataddr __P((int, char *, nat_addr_t *, int));
+extern void printnatfield __P((nat_t *, int));
+extern void printnatside __P((char *, nat_stat_side_t *));
+extern void printpacket __P((int, mb_t *));
+extern void printpacket6 __P((int, mb_t *));
+extern struct ippool_dst *printdstlist __P((struct ippool_dst *, copyfunc_t,
+ char *, int, ipf_dstnode_t *,
+ wordtab_t *));
+extern void printdstlistdata __P((ippool_dst_t *, int));
+extern ipf_dstnode_t *printdstlistnode __P((ipf_dstnode_t *, copyfunc_t,
+ int, wordtab_t *));
+extern void printdstlistpolicy __P((ippool_policy_t));
+extern struct ip_pool_s *printpool __P((struct ip_pool_s *, copyfunc_t,
+ char *, int, wordtab_t *));
+extern struct ip_pool_s *printpool_live __P((struct ip_pool_s *, int,
+ char *, int, wordtab_t *));
+extern void printpooldata __P((ip_pool_t *, int));
+extern void printpoolfield __P((void *, int, int));
+extern struct ip_pool_node *printpoolnode __P((struct ip_pool_node *,
+ int, wordtab_t *));
+extern void printproto __P((struct protoent *, int, struct ipnat *));
+extern void printportcmp __P((int, struct frpcmp *));
+extern void printstatefield __P((ipstate_t *, int));
+extern void printtqtable __P((ipftq_t *));
+extern void printtunable __P((ipftune_t *));
+extern void printunit __P((int));
+extern void optprint __P((u_short *, u_long, u_long));
+#ifdef USE_INET6
+extern void optprintv6 __P((u_short *, u_long, u_long));
+#endif
+extern int remove_hash __P((struct iphtable_s *, ioctlfunc_t));
+extern int remove_hashnode __P((int, char *, struct iphtent_s *, ioctlfunc_t));
+extern int remove_pool __P((ip_pool_t *, ioctlfunc_t));
+extern int remove_poolnode __P((int, char *, ip_pool_node_t *, ioctlfunc_t));
+extern u_char tcpflags __P((char *));
+extern void printc __P((struct frentry *));
+extern void printC __P((int));
+extern void emit __P((int, int, void *, struct frentry *));
+extern u_char secbit __P((int));
+extern u_char seclevel __P((char *));
+extern void printfraginfo __P((char *, struct ipfr *));
+extern void printifname __P((char *, char *, void *));
+extern char *hostname __P((int, void *));
+extern struct ipstate *printstate __P((struct ipstate *, int, u_long));
+extern void printsbuf __P((char *));
+extern void printnat __P((struct ipnat *, int));
+extern void printactiveaddress __P((int, char *, i6addr_t *, char *));
+extern void printactivenat __P((struct nat *, int, u_long));
+extern void printhostmap __P((struct hostmap *, u_int));
+extern void printtcpflags __P((u_32_t, u_32_t));
+extern void printipfexpr __P((int *));
+extern void printstatefield __P((ipstate_t *, int));
+extern void printstatefieldhdr __P((int));
+extern int sendtrap_v1_0 __P((int, char *, char *, int, time_t));
+extern int sendtrap_v2_0 __P((int, char *, char *, int));
+extern int vtof __P((int));
+
+extern void set_variable __P((char *, char *));
+extern char *get_variable __P((char *, char **, int));
+extern void resetlexer __P((void));
+
+extern void debug __P((int, char *, ...));
+extern void verbose __P((int, char *, ...));
+extern void ipfkdebug __P((char *, ...));
+extern void ipfkverbose __P((char *, ...));
+
+#if SOLARIS
+extern int gethostname __P((char *, int ));
+extern void sync __P((void));
+#endif
+
+#endif /* __IPF_H__ */
diff --git a/contrib/ipfilter/ipf_rb.h b/contrib/ipfilter/ipf_rb.h
new file mode 100644
index 0000000..3d7a59d
--- /dev/null
+++ b/contrib/ipfilter/ipf_rb.h
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+typedef enum rbcolour_e {
+ C_BLACK = 0,
+ C_RED = 1
+} rbcolour_t;
+
+#define RBI_LINK(_n, _t) \
+ struct _n##_rb_link { \
+ struct _t *left; \
+ struct _t *right; \
+ struct _t *parent; \
+ rbcolour_t colour; \
+ }
+
+#define RBI_HEAD(_n, _t) \
+struct _n##_rb_head { \
+ struct _t top; \
+ int count; \
+ int (* compare)(struct _t *, struct _t *); \
+}
+
+#define RBI_CODE(_n, _t, _f, _cmp) \
+ \
+typedef void (*_n##_rb_walker_t)(_t *, void *); \
+ \
+_t * _n##_rb_delete(struct _n##_rb_head *, _t *); \
+void _n##_rb_init(struct _n##_rb_head *); \
+void _n##_rb_insert(struct _n##_rb_head *, _t *); \
+_t * _n##_rb_search(struct _n##_rb_head *, void *); \
+void _n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\
+ \
+static void \
+rotate_left(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *parent, *tmp1, *tmp2; \
+ \
+ parent = node->_f.parent; \
+ tmp1 = node->_f.right; \
+ tmp2 = tmp1->_f.left; \
+ node->_f.right = tmp2; \
+ if (tmp2 != & _n##_rb_zero) \
+ tmp2->_f.parent = node; \
+ if (parent == & _n##_rb_zero) \
+ head->top._f.right = tmp1; \
+ else if (parent->_f.right == node) \
+ parent->_f.right = tmp1; \
+ else \
+ parent->_f.left = tmp1; \
+ tmp1->_f.left = node; \
+ tmp1->_f.parent = parent; \
+ node->_f.parent = tmp1; \
+} \
+ \
+static void \
+rotate_right(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *parent, *tmp1, *tmp2; \
+ \
+ parent = node->_f.parent; \
+ tmp1 = node->_f.left; \
+ tmp2 = tmp1->_f.right; \
+ node->_f.left = tmp2; \
+ if (tmp2 != &_n##_rb_zero) \
+ tmp2->_f.parent = node; \
+ if (parent == &_n##_rb_zero) \
+ head->top._f.right = tmp1; \
+ else if (parent->_f.right == node) \
+ parent->_f.right = tmp1; \
+ else \
+ parent->_f.left = tmp1; \
+ tmp1->_f.right = node; \
+ tmp1->_f.parent = parent; \
+ node->_f.parent = tmp1; \
+} \
+ \
+void \
+_n##_rb_insert(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *n, *parent, **p, *tmp1, *gparent; \
+ \
+ parent = &head->top; \
+ node->_f.left = &_n##_rb_zero; \
+ node->_f.right = &_n##_rb_zero; \
+ p = &head->top._f.right; \
+ while ((n = *p) != &_n##_rb_zero) { \
+ if (_cmp(node, n) < 0) \
+ p = &n->_f.left; \
+ else \
+ p = &n->_f.right; \
+ parent = n; \
+ } \
+ *p = node; \
+ node->_f.colour = C_RED; \
+ node->_f.parent = parent; \
+ \
+ while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\
+ gparent = parent->_f.parent; \
+ if (parent == gparent->_f.left) { \
+ tmp1 = gparent->_f.right; \
+ if (tmp1->_f.colour == C_RED) { \
+ parent->_f.colour = C_BLACK; \
+ tmp1->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ node = gparent; \
+ } else { \
+ if (node == parent->_f.right) { \
+ node = parent; \
+ rotate_left(head, node); \
+ parent = node->_f.parent; \
+ } \
+ parent->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ rotate_right(head, gparent); \
+ } \
+ } else { \
+ tmp1 = gparent->_f.left; \
+ if (tmp1->_f.colour == C_RED) { \
+ parent->_f.colour = C_BLACK; \
+ tmp1->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ node = gparent; \
+ } else { \
+ if (node == parent->_f.left) { \
+ node = parent; \
+ rotate_right(head, node); \
+ parent = node->_f.parent; \
+ } \
+ parent->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ rotate_left(head, parent->_f.parent); \
+ } \
+ } \
+ parent = node->_f.parent; \
+ } \
+ head->top._f.right->_f.colour = C_BLACK; \
+ head->count++; \
+} \
+ \
+static void \
+deleteblack(struct _n##_rb_head *head, _t *parent, _t *node) \
+{ \
+ _t *tmp; \
+ \
+ while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) && \
+ node != &head->top) { \
+ if (parent->_f.left == node) { \
+ tmp = parent->_f.right; \
+ if (tmp->_f.colour == C_RED) { \
+ tmp->_f.colour = C_BLACK; \
+ parent->_f.colour = C_RED; \
+ rotate_left(head, parent); \
+ tmp = parent->_f.right; \
+ } \
+ if ((tmp->_f.left == &_n##_rb_zero || \
+ tmp->_f.left->_f.colour == C_BLACK) && \
+ (tmp->_f.right == &_n##_rb_zero || \
+ tmp->_f.right->_f.colour == C_BLACK)) { \
+ tmp->_f.colour = C_RED; \
+ node = parent; \
+ parent = node->_f.parent; \
+ } else { \
+ if (tmp->_f.right == &_n##_rb_zero || \
+ tmp->_f.right->_f.colour == C_BLACK) {\
+ _t *tmp2 = tmp->_f.left; \
+ \
+ if (tmp2 != &_n##_rb_zero) \
+ tmp2->_f.colour = C_BLACK;\
+ tmp->_f.colour = C_RED; \
+ rotate_right(head, tmp); \
+ tmp = parent->_f.right; \
+ } \
+ tmp->_f.colour = parent->_f.colour; \
+ parent->_f.colour = C_BLACK; \
+ if (tmp->_f.right != &_n##_rb_zero) \
+ tmp->_f.right->_f.colour = C_BLACK;\
+ rotate_left(head, parent); \
+ node = head->top._f.right; \
+ } \
+ } else { \
+ tmp = parent->_f.left; \
+ if (tmp->_f.colour == C_RED) { \
+ tmp->_f.colour = C_BLACK; \
+ parent->_f.colour = C_RED; \
+ rotate_right(head, parent); \
+ tmp = parent->_f.left; \
+ } \
+ if ((tmp->_f.left == &_n##_rb_zero || \
+ tmp->_f.left->_f.colour == C_BLACK) && \
+ (tmp->_f.right == &_n##_rb_zero || \
+ tmp->_f.right->_f.colour == C_BLACK)) { \
+ tmp->_f.colour = C_RED; \
+ node = parent; \
+ parent = node->_f.parent; \
+ } else { \
+ if (tmp->_f.left == &_n##_rb_zero || \
+ tmp->_f.left->_f.colour == C_BLACK) {\
+ _t *tmp2 = tmp->_f.right; \
+ \
+ if (tmp2 != &_n##_rb_zero) \
+ tmp2->_f.colour = C_BLACK;\
+ tmp->_f.colour = C_RED; \
+ rotate_left(head, tmp); \
+ tmp = parent->_f.left; \
+ } \
+ tmp->_f.colour = parent->_f.colour; \
+ parent->_f.colour = C_BLACK; \
+ if (tmp->_f.left != &_n##_rb_zero) \
+ tmp->_f.left->_f.colour = C_BLACK;\
+ rotate_right(head, parent); \
+ node = head->top._f.right; \
+ break; \
+ } \
+ } \
+ } \
+ if (node != &_n##_rb_zero) \
+ node->_f.colour = C_BLACK; \
+} \
+ \
+_t * \
+_n##_rb_delete(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *child, *parent, *old = node, *left; \
+ rbcolour_t color; \
+ \
+ if (node->_f.left == &_n##_rb_zero) { \
+ child = node->_f.right; \
+ } else if (node->_f.right == &_n##_rb_zero) { \
+ child = node->_f.left; \
+ } else { \
+ node = node->_f.right; \
+ while ((left = node->_f.left) != &_n##_rb_zero) \
+ node = left; \
+ child = node->_f.right; \
+ parent = node->_f.parent; \
+ color = node->_f.colour; \
+ if (child != &_n##_rb_zero) \
+ child->_f.parent = parent; \
+ if (parent != &_n##_rb_zero) { \
+ if (parent->_f.left == node) \
+ parent->_f.left = child; \
+ else \
+ parent->_f.right = child; \
+ } else { \
+ head->top._f.right = child; \
+ } \
+ if (node->_f.parent == old) \
+ parent = node; \
+ *node = *old; \
+ if (old->_f.parent != &_n##_rb_zero) { \
+ if (old->_f.parent->_f.left == old) \
+ old->_f.parent->_f.left = node; \
+ else \
+ old->_f.parent->_f.right = node; \
+ } else { \
+ head->top._f.right = child; \
+ } \
+ old->_f.left->_f.parent = node; \
+ if (old->_f.right != &_n##_rb_zero) \
+ old->_f.right->_f.parent = node; \
+ if (parent != &_n##_rb_zero) { \
+ left = parent; \
+ } \
+ goto colour; \
+ } \
+ parent = node->_f.parent; \
+ color= node->_f.colour; \
+ if (child != &_n##_rb_zero) \
+ child->_f.parent = parent; \
+ if (parent != &_n##_rb_zero) { \
+ if (parent->_f.left == node) \
+ parent->_f.left = child; \
+ else \
+ parent->_f.right = child; \
+ } else { \
+ head->top._f.right = child; \
+ } \
+colour: \
+ if (color == C_BLACK) \
+ deleteblack(head, parent, node); \
+ head->count--; \
+ return old; \
+} \
+ \
+void \
+_n##_rb_init(struct _n##_rb_head *head) \
+{ \
+ memset(head, 0, sizeof(*head)); \
+ memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero)); \
+ head->top._f.left = &_n##_rb_zero; \
+ head->top._f.right = &_n##_rb_zero; \
+ head->top._f.parent = &head->top; \
+ _n##_rb_zero._f.left = &_n##_rb_zero; \
+ _n##_rb_zero._f.right = &_n##_rb_zero; \
+ _n##_rb_zero._f.parent = &_n##_rb_zero; \
+} \
+ \
+void \
+_n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\
+{ \
+ _t *prev; \
+ _t *next; \
+ _t *node = head->top._f.right; \
+ _t *base; \
+ \
+ while (node != &_n##_rb_zero) \
+ node = node->_f.left; \
+ \
+ for (;;) { \
+ base = node; \
+ prev = node; \
+ while ((node->_f.parent->_f.right == node) && \
+ (node != &_n##_rb_zero)) { \
+ prev = node; \
+ node = node->_f.parent; \
+ } \
+ \
+ node = prev; \
+ for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\
+ node = node->_f.left) \
+ prev = node; \
+ next = prev; \
+ \
+ if (node != &_n##_rb_zero) \
+ func(node, arg); \
+ \
+ node = next; \
+ if (node == &_n##_rb_zero) \
+ break; \
+ } \
+} \
+ \
+_t * \
+_n##_rb_search(struct _n##_rb_head *head, void *key) \
+{ \
+ int match; \
+ _t *node; \
+ node = head->top._f.right; \
+ while (node != &_n##_rb_zero) { \
+ match = _cmp(key, node); \
+ if (match == 0) \
+ break; \
+ if (match< 0) \
+ node = node->_f.left; \
+ else \
+ node = node->_f.right; \
+ } \
+ if (node == &_n##_rb_zero || match != 0) \
+ return (NULL); \
+ return (node); \
+}
+
+#define RBI_DELETE(_n, _h, _v) _n##_rb_delete(_h, _v)
+#define RBI_FIELD(_n) struct _n##_rb_link
+#define RBI_INIT(_n, _h) _n##_rb_init(_h)
+#define RBI_INSERT(_n, _h, _v) _n##_rb_insert(_h, _v)
+#define RBI_ISEMPTY(_h) ((_h)->count == 0)
+#define RBI_SEARCH(_n, _h, _k) _n##_rb_search(_h, _k)
+#define RBI_WALK(_n, _h, _w, _a) _n##_rb_walktree(_h, _w, _a)
+#define RBI_ZERO(_n) _n##_rb_zero
diff --git a/contrib/ipfilter/iplang/BNF b/contrib/ipfilter/iplang/BNF
new file mode 100644
index 0000000..b5fb8d0
--- /dev/null
+++ b/contrib/ipfilter/iplang/BNF
@@ -0,0 +1,69 @@
+line ::= iface | arp | send | defrouter | ipv4line .
+
+iface ::= ifhdr "{" ifaceopts "}" ";" .
+ifhdr ::= "interface" | "iface" .
+ifaceopts ::= "ifname" name | "mtu" mtu | "v4addr" ipaddr |
+ "eaddr" eaddr .
+
+send ::= "send" ";" | "send" "{" sendbodyopts "}" ";" .
+sendbodyopts ::= sendbody [ sendbodyopts ] .
+sendbody ::= "ifname" name | "via" ipaddr .
+
+defrouter ::= "router" ipaddr .
+
+arp ::= "arp" "{" arpbodyopts "}" ";" .
+arpbodyopts ::= arpbody [ arpbodyopts ] .
+arpbody ::= "v4addr" ipaddr | "eaddr" eaddr .
+
+bodyline ::= ipv4line | tcpline | udpline | icmpline | dataline .
+
+ipv4line ::= "ipv4" "{" ipv4bodyopts "}" ";" .
+ipv4bodyopts ::= ipv4body [ ipv4bodyopts ] | bodyline .
+ipv4body ::= "proto" protocol | "src" ipaddr | "dst" ipaddr |
+ "off" number | "v" number | "hl" number| "id" number |
+ "ttl" number | "tos" number | "sum" number | "len" number |
+ "opt" "{" ipv4optlist "}" ";" .
+ipv4optlist ::= ipv4option [ ipv4optlist ] .
+ipv4optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" |
+ "tr" | "sec" | "lsrr" | "e-sec" | "cipso" | "satid" |
+ "ssrr" | "addext" | "visa" | "imitd" | "eip" | "finn" |
+ "secclass" ipv4secclass.
+ipv4secclass := "unclass" | "confid" | "reserv-1" | "reserv-2" |
+ "reserv-3" | "reserv-4" | "secret" | "topsecret" .
+
+tcpline ::= "tcp" "{" tcpbodyopts "}" ";" .
+tcpbodyopts ::= tcpbody [ tcpbodyopts ] | bodyline .
+tcpbody ::= "sport" port | "dport" port | "seq" number | "ack" number |
+ "off" number | "urp" number | "win" number | "sum" number |
+ "flags" tcpflags | data .
+
+udpline ::= "udp" "{" udpbodyopts "}" ";" .
+udpbodyopts ::= udpbody [ udpbodyopts ] | bodyline .
+udpbody ::= "sport" port | "dport" port | "len" number | "sum" number |
+ data .
+
+icmpline ::= "icmp" "{" icmpbodyopts "}" ";" .
+icmpbodyopts ::= icmpbody [ icmpbodyopts ] | bodyline .
+icmpbody ::= "type" icmptype [ "code" icmpcode ] .
+icmptype ::= "echorep" | "echorep" "{" echoopts "}" ";" | "unreach" |
+ "unreach" "{" unreachtype "}" ";" | "squench" | "redir" |
+ "redir" "{" redirtype "}" ";" | "echo" "{" echoopts "}" ";" |
+ "echo" | "routerad" | "routersol" | "timex" |
+ "timex" "{" timextype "}" ";" | "paramprob" |
+ "paramprob" "{" parapptype "}" ";" | "timest" | "timestrep" |
+ "inforeq" | "inforep" | "maskreq" | "maskrep" .
+
+echoopts ::= echoopts [ icmpechoopts ] .
+unreachtype ::= "net-unr" | "host-unr" | "proto-unr" | "port-unr" |
+ "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
+ "net-prohib" | "host-prohib" | "net-tos" | "host-tos" |
+ "filter-prohib" | "host-preced" | "cutoff-preced" .
+redirtype ::= "net-redir" | "host-redir" | "tos-net-redir" |
+ "tos-host-redir" .
+timextype ::= "intrans" | "reass" .
+paramptype ::= "optabsent" .
+
+data ::= "data" "{" databodyopts "}" ";" .
+databodyopts ::= "len" number | "value" string | "file" filename .
+
+icmpechoopts ::= "icmpseq" number | "icmpid" number .
diff --git a/contrib/ipfilter/iplang/Makefile b/contrib/ipfilter/iplang/Makefile
new file mode 100644
index 0000000..5b53e9a
--- /dev/null
+++ b/contrib/ipfilter/iplang/Makefile
@@ -0,0 +1,31 @@
+#
+# See the IPFILTER.LICENCE file for details on licencing.
+#
+#CC=gcc -Wuninitialized -Wstrict-prototypes -Werror -O
+CFLAGS=-I..
+
+all: $(DESTDIR)/iplang_y.o $(DESTDIR)/iplang_l.o
+
+$(DESTDIR)/iplang_y.o: $(DESTDIR)/iplang_y.c
+ $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_y.c -o $@
+
+$(DESTDIR)/iplang_l.o: $(DESTDIR)/iplang_l.c
+ $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_l.c -o $@
+
+iplang_y.o: iplang_y.c
+ $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@
+
+iplang_l.o: iplang_l.c
+ $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@
+
+$(DESTDIR)/iplang_l.c: iplang_l.l $(DESTDIR)/iplang_y.h
+ lex iplang_l.l
+ mv lex.yy.c $(DESTDIR)/iplang_l.c
+
+$(DESTDIR)/iplang_y.c $(DESTDIR)/iplang_y.h: iplang_y.y
+ yacc -d iplang_y.y
+ mv y.tab.c $(DESTDIR)/iplang_y.c
+ mv y.tab.h $(DESTDIR)/iplang_y.h
+
+clean:
+ /bin/rm -f *.o lex.yy.c y.tab.c y.tab.h
diff --git a/contrib/ipfilter/iplang/iplang.h b/contrib/ipfilter/iplang/iplang.h
new file mode 100644
index 0000000..63cc078
--- /dev/null
+++ b/contrib/ipfilter/iplang/iplang.h
@@ -0,0 +1,54 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+typedef struct iface {
+ int if_MTU;
+ char *if_name;
+ struct in_addr if_addr;
+ struct ether_addr if_eaddr;
+ struct iface *if_next;
+ int if_fd;
+} iface_t;
+
+
+typedef struct send {
+ struct iface *snd_if;
+ struct in_addr snd_gw;
+} send_t;
+
+
+typedef struct arp {
+ struct in_addr arp_addr;
+ struct ether_addr arp_eaddr;
+ struct arp *arp_next;
+} arp_t;
+
+
+typedef struct aniphdr {
+ union {
+ ip_t *ahu_ip;
+ char *ahu_data;
+ tcphdr_t *ahu_tcp;
+ udphdr_t *ahu_udp;
+ icmphdr_t *ahu_icmp;
+ } ah_un;
+ int ah_optlen;
+ int ah_lastopt;
+ int ah_p;
+ size_t ah_len;
+ struct aniphdr *ah_next;
+ struct aniphdr *ah_prev;
+} aniphdr_t;
+
+#define ah_ip ah_un.ahu_ip
+#define ah_data ah_un.ahu_data
+#define ah_tcp ah_un.ahu_tcp
+#define ah_udp ah_un.ahu_udp
+#define ah_icmp ah_un.ahu_icmp
+
+extern int get_arpipv4 __P((char *, char *));
+
diff --git a/contrib/ipfilter/iplang/iplang.tst b/contrib/ipfilter/iplang/iplang.tst
new file mode 100644
index 0000000..841c3ae
--- /dev/null
+++ b/contrib/ipfilter/iplang/iplang.tst
@@ -0,0 +1,11 @@
+#
+interface { ifname le0; mtu 1500; } ;
+
+ipv4 {
+ src 1.1.1.1; dst 2.2.2.2;
+ tcp {
+ seq 12345; ack 0; sport 9999; dport 23; flags S;
+ data { value "abcdef"; } ;
+ } ;
+} ;
+send { via 10.1.1.1; } ;
diff --git a/contrib/ipfilter/iplang/iplang_l.l b/contrib/ipfilter/iplang/iplang_l.l
new file mode 100644
index 0000000..029a417
--- /dev/null
+++ b/contrib/ipfilter/iplang/iplang_l.l
@@ -0,0 +1,322 @@
+/* $FreeBSD$ */
+
+%{
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#if defined(__SVR4) || defined(__sysv__)
+#include <sys/stream.h>
+#endif
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include "iplang_y.h"
+#include "ipf.h"
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+extern int opts;
+
+int lineNum = 0, ipproto = 0, oldipproto = 0, next = -1, laststate = 0;
+int *prstack = NULL, numpr = 0, state = 0, token = 0;
+
+void yyerror __P((char *));
+void push_proto __P((void));
+void pop_proto __P((void));
+int next_state __P((int, int));
+int next_item __P((int));
+int save_token __P((void));
+void swallow __P((void));
+int yylex __P((void));
+
+struct lwordtab {
+ char *word;
+ int state;
+ int next;
+};
+
+struct lwordtab words[] = {
+ { "interface", IL_INTERFACE, -1 },
+ { "iface", IL_INTERFACE, -1 },
+ { "name", IL_IFNAME, IL_TOKEN },
+ { "ifname", IL_IFNAME, IL_TOKEN },
+ { "router", IL_DEFROUTER, IL_TOKEN },
+ { "mtu", IL_MTU, IL_NUMBER },
+ { "eaddr", IL_EADDR, IL_TOKEN },
+ { "v4addr", IL_V4ADDR, IL_TOKEN },
+ { "ipv4", IL_IPV4, -1 },
+ { "v", IL_V4V, IL_TOKEN },
+ { "proto", IL_V4PROTO, IL_TOKEN },
+ { "hl", IL_V4HL, IL_TOKEN },
+ { "id", IL_V4ID, IL_TOKEN },
+ { "ttl", IL_V4TTL, IL_TOKEN },
+ { "tos", IL_V4TOS, IL_TOKEN },
+ { "src", IL_V4SRC, IL_TOKEN },
+ { "dst", IL_V4DST, IL_TOKEN },
+ { "opt", IL_OPT, -1 },
+ { "len", IL_LEN, IL_TOKEN },
+ { "off", IL_OFF, IL_TOKEN },
+ { "sum", IL_SUM, IL_TOKEN },
+ { "tcp", IL_TCP, -1 },
+ { "sport", IL_SPORT, IL_TOKEN },
+ { "dport", IL_DPORT, IL_TOKEN },
+ { "seq", IL_TCPSEQ, IL_TOKEN },
+ { "ack", IL_TCPACK, IL_TOKEN },
+ { "flags", IL_TCPFL, IL_TOKEN },
+ { "urp", IL_TCPURP, IL_TOKEN },
+ { "win", IL_TCPWIN, IL_TOKEN },
+ { "udp", IL_UDP, -1 },
+ { "send", IL_SEND, -1 },
+ { "via", IL_VIA, IL_TOKEN },
+ { "arp", IL_ARP, -1 },
+ { "data", IL_DATA, -1 },
+ { "value", IL_DVALUE, IL_TOKEN },
+ { "file", IL_DFILE, IL_TOKEN },
+ { "nop", IL_IPO_NOP, -1 },
+ { "eol", IL_IPO_EOL, -1 },
+ { "rr", IL_IPO_RR, -1 },
+ { "zsu", IL_IPO_ZSU, -1 },
+ { "mtup", IL_IPO_MTUP, -1 },
+ { "mtur", IL_IPO_MTUR, -1 },
+ { "encode", IL_IPO_ENCODE, -1 },
+ { "ts", IL_IPO_TS, -1 },
+ { "tr", IL_IPO_TR, -1 },
+ { "sec", IL_IPO_SEC, -1 },
+ { "secclass", IL_IPO_SECCLASS, IL_TOKEN },
+ { "lsrr", IL_IPO_LSRR, -1 },
+ { "esec", IL_IPO_ESEC, -1 },
+ { "cipso", IL_IPO_CIPSO, -1 },
+ { "satid", IL_IPO_SATID, -1 },
+ { "ssrr", IL_IPO_SSRR, -1 },
+ { "addext", IL_IPO_ADDEXT, -1 },
+ { "visa", IL_IPO_VISA, -1 },
+ { "imitd", IL_IPO_IMITD, -1 },
+ { "eip", IL_IPO_EIP, -1 },
+ { "finn", IL_IPO_FINN, -1 },
+ { "mss", IL_TCPO_MSS, IL_TOKEN },
+ { "wscale", IL_TCPO_WSCALE, IL_TOKEN },
+ { "reserv-4", IL_IPS_RESERV4, -1 },
+ { "topsecret", IL_IPS_TOPSECRET, -1 },
+ { "secret", IL_IPS_SECRET, -1 },
+ { "reserv-3", IL_IPS_RESERV3, -1 },
+ { "confid", IL_IPS_CONFID, -1 },
+ { "unclass", IL_IPS_UNCLASS, -1 },
+ { "reserv-2", IL_IPS_RESERV2, -1 },
+ { "reserv-1", IL_IPS_RESERV1, -1 },
+ { "icmp", IL_ICMP, -1 },
+ { "type", IL_ICMPTYPE, -1 },
+ { "code", IL_ICMPCODE, -1 },
+ { "echorep", IL_ICMP_ECHOREPLY, -1 },
+ { "unreach", IL_ICMP_UNREACH, -1 },
+ { "squench", IL_ICMP_SOURCEQUENCH, -1 },
+ { "redir", IL_ICMP_REDIRECT, -1 },
+ { "echo", IL_ICMP_ECHO, -1 },
+ { "routerad", IL_ICMP_ROUTERADVERT, -1 },
+ { "routersol", IL_ICMP_ROUTERSOLICIT, -1 },
+ { "timex", IL_ICMP_TIMXCEED, -1 },
+ { "paramprob", IL_ICMP_PARAMPROB, -1 },
+ { "timest", IL_ICMP_TSTAMP, -1 },
+ { "timestrep", IL_ICMP_TSTAMPREPLY, -1 },
+ { "inforeq", IL_ICMP_IREQ, -1 },
+ { "inforep", IL_ICMP_IREQREPLY, -1 },
+ { "maskreq", IL_ICMP_MASKREQ, -1 },
+ { "maskrep", IL_ICMP_MASKREPLY, -1 },
+ { "net-unr", IL_ICMP_UNREACH_NET, -1 },
+ { "host-unr", IL_ICMP_UNREACH_HOST, -1 },
+ { "proto-unr", IL_ICMP_UNREACH_PROTOCOL, -1 },
+ { "port-unr", IL_ICMP_UNREACH_PORT, -1 },
+ { "needfrag", IL_ICMP_UNREACH_NEEDFRAG, -1 },
+ { "srcfail", IL_ICMP_UNREACH_SRCFAIL, -1 },
+ { "net-unk", IL_ICMP_UNREACH_NET_UNKNOWN, -1 },
+ { "host-unk", IL_ICMP_UNREACH_HOST_UNKNOWN, -1 },
+ { "isolate", IL_ICMP_UNREACH_ISOLATED, -1 },
+ { "net-prohib", IL_ICMP_UNREACH_NET_PROHIB, -1 },
+ { "host-prohib", IL_ICMP_UNREACH_HOST_PROHIB, -1 },
+ { "net-tos", IL_ICMP_UNREACH_TOSNET, -1 },
+ { "host-tos", IL_ICMP_UNREACH_TOSHOST, -1 },
+ { "filter-prohib", IL_ICMP_UNREACH_FILTER_PROHIB, -1 },
+ { "host-preced", IL_ICMP_UNREACH_HOST_PRECEDENCE, -1 },
+ { "cutoff-preced", IL_ICMP_UNREACH_PRECEDENCE_CUTOFF, -1 },
+ { "net-redir", IL_ICMP_REDIRECT_NET, -1 },
+ { "host-redir", IL_ICMP_REDIRECT_HOST, -1 },
+ { "tos-net-redir", IL_ICMP_REDIRECT_TOSNET, -1 },
+ { "tos-host-redir", IL_ICMP_REDIRECT_TOSHOST, -1 },
+ { "intrans", IL_ICMP_TIMXCEED_INTRANS, -1 },
+ { "reass", IL_ICMP_TIMXCEED_REASS, -1 },
+ { "optabsent", IL_ICMP_PARAMPROB_OPTABSENT, -1 },
+ { "otime", IL_ICMP_OTIME, -1 },
+ { "rtime", IL_ICMP_RTIME, -1 },
+ { "ttime", IL_ICMP_TTIME, -1 },
+ { "icmpseq", IL_ICMP_SEQ, -1 },
+ { "icmpid", IL_ICMP_SEQ, -1 },
+ { ".", IL_DOT, -1 },
+ { NULL, 0, 0 }
+};
+%}
+white [ \t\r]+
+%%
+{white} ;
+\n { lineNum++; swallow(); }
+\{ { push_proto(); return next_item('{'); }
+\} { pop_proto(); return next_item('}'); }
+; { return next_item(';'); }
+[0-9]+ { return next_item(IL_NUMBER); }
+[0-9a-fA-F] { return next_item(IL_HEXDIGIT); }
+: { return next_item(IL_COLON); }
+#[^\n]* { return next_item(IL_COMMENT); }
+[^ \{\}\n\t;:{}]* { return next_item(IL_TOKEN); }
+\"[^\"]*\" { return next_item(IL_TOKEN); }
+%%
+void yyerror(msg)
+char *msg;
+{
+ fprintf(stderr, "%s error at \"%s\", line %d\n", msg, yytext,
+ lineNum + 1);
+ exit(1);
+}
+
+
+void push_proto()
+{
+ numpr++;
+ if (!prstack)
+ prstack = (int *)malloc(sizeof(int));
+ else
+ prstack = (int *)realloc((char *)prstack, numpr * sizeof(int));
+ prstack[numpr - 1] = oldipproto;
+}
+
+
+void pop_proto()
+{
+ numpr--;
+ ipproto = prstack[numpr];
+ if (!numpr) {
+ free(prstack);
+ prstack = NULL;
+ return;
+ }
+ prstack = (int *)realloc((char *)prstack, numpr * sizeof(int));
+}
+
+
+int save_token()
+{
+
+ yylval.str = strdup((char *)yytext);
+ return IL_TOKEN;
+}
+
+
+int next_item(nstate)
+int nstate;
+{
+ struct lwordtab *wt;
+
+ if (opts & OPT_DEBUG)
+ printf("text=[%s] id=%d next=%d\n", yytext, nstate, next);
+ if (next == IL_TOKEN) {
+ next = -1;
+ return save_token();
+ }
+ token++;
+
+ for (wt = words; wt->word; wt++)
+ if (!strcasecmp(wt->word, (char *)yytext))
+ return next_state(wt->state, wt->next);
+ if (opts & OPT_DEBUG)
+ printf("unknown keyword=[%s]\n", yytext);
+ next = -1;
+ if (nstate == IL_NUMBER)
+ yylval.num = atoi((char *)yytext);
+ token++;
+ return nstate;
+}
+
+
+int next_state(nstate, fornext)
+int nstate, fornext;
+{
+ next = fornext;
+
+ switch (nstate)
+ {
+ case IL_IPV4 :
+ case IL_TCP :
+ case IL_UDP :
+ case IL_ICMP :
+ case IL_DATA :
+ case IL_INTERFACE :
+ case IL_ARP :
+ oldipproto = ipproto;
+ ipproto = nstate;
+ break;
+ case IL_SUM :
+ if (ipproto == IL_IPV4)
+ nstate = IL_V4SUM;
+ else if (ipproto == IL_TCP)
+ nstate = IL_TCPSUM;
+ else if (ipproto == IL_UDP)
+ nstate = IL_UDPSUM;
+ break;
+ case IL_OPT :
+ if (ipproto == IL_IPV4)
+ nstate = IL_V4OPT;
+ else if (ipproto == IL_TCP)
+ nstate = IL_TCPOPT;
+ break;
+ case IL_IPO_NOP :
+ if (ipproto == IL_TCP)
+ nstate = IL_TCPO_NOP;
+ break;
+ case IL_IPO_EOL :
+ if (ipproto == IL_TCP)
+ nstate = IL_TCPO_EOL;
+ break;
+ case IL_IPO_TS :
+ if (ipproto == IL_TCP)
+ nstate = IL_TCPO_TS;
+ break;
+ case IL_OFF :
+ if (ipproto == IL_IPV4)
+ nstate = IL_V4OFF;
+ else if (ipproto == IL_TCP)
+ nstate = IL_TCPOFF;
+ break;
+ case IL_LEN :
+ if (ipproto == IL_IPV4)
+ nstate = IL_V4LEN;
+ else if (ipproto == IL_UDP)
+ nstate = IL_UDPLEN;
+ break;
+ }
+ return nstate;
+}
+
+
+void swallow()
+{
+ int c;
+
+ c = input();
+
+ if (c == '#') {
+ while ((c != '\n') && (c != EOF))
+ c = input();
+ }
+ if (c != EOF)
+ unput(c);
+}
diff --git a/contrib/ipfilter/iplang/iplang_y.y b/contrib/ipfilter/iplang/iplang_y.y
new file mode 100644
index 0000000..98c8f1a
--- /dev/null
+++ b/contrib/ipfilter/iplang/iplang_y.y
@@ -0,0 +1,1858 @@
+/* $FreeBSD$ */
+
+%{
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Id: iplang_y.y,v 2.9.2.4 2006/03/17 12:11:29 darrenr Exp $
+ * $FreeBSD$
+ */
+
+#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/stat.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifndef linux
+# include <netinet/ip_var.h>
+# include <net/route.h>
+# include <netinet/if_ether.h>
+#endif
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <ctype.h>
+#include "ipsend.h"
+#include "ip_compat.h"
+#include "ipf.h"
+#include "iplang.h"
+
+#if !defined(__NetBSD__) && (!defined(__FreeBSD_version) && \
+ __FreeBSD_version < 400020) && (!SOLARIS || SOLARIS2 < 10)
+extern struct ether_addr *ether_aton __P((char *));
+#endif
+
+extern int opts;
+extern struct ipopt_names ionames[];
+extern int state, state, lineNum, token;
+extern int yylineno;
+extern char yytext[];
+extern FILE *yyin;
+int yylex __P((void));
+#define YYDEBUG 1
+#if !defined(ultrix) && !defined(hpux)
+int yydebug = 1;
+#else
+extern int yydebug;
+#endif
+
+iface_t *iflist = NULL, **iftail = &iflist;
+iface_t *cifp = NULL;
+arp_t *arplist = NULL, **arptail = &arplist, *carp = NULL;
+struct in_addr defrouter;
+send_t sending;
+char *sclass = NULL;
+u_short c_chksum __P((u_short *, u_int, u_long));
+u_long p_chksum __P((u_short *, u_int));
+
+u_long ipbuffer[67584/sizeof(u_long)]; /* 66K */
+aniphdr_t *aniphead = NULL, *canip = NULL, **aniptail = &aniphead;
+ip_t *ip = NULL;
+udphdr_t *udp = NULL;
+tcphdr_t *tcp = NULL;
+icmphdr_t *icmp = NULL;
+
+struct statetoopt {
+ int sto_st;
+ int sto_op;
+};
+
+struct in_addr getipv4addr __P((char *arg));
+u_short getportnum __P((char *, char *));
+struct ether_addr *geteaddr __P((char *, struct ether_addr *));
+void *new_header __P((int));
+void free_aniplist __P((void));
+void inc_anipheaders __P((int));
+void new_data __P((void));
+void set_datalen __P((char **));
+void set_datafile __P((char **));
+void set_data __P((char **));
+void new_packet __P((void));
+void set_ipv4proto __P((char **));
+void set_ipv4src __P((char **));
+void set_ipv4dst __P((char **));
+void set_ipv4off __P((char **));
+void set_ipv4v __P((char **));
+void set_ipv4hl __P((char **));
+void set_ipv4ttl __P((char **));
+void set_ipv4tos __P((char **));
+void set_ipv4id __P((char **));
+void set_ipv4sum __P((char **));
+void set_ipv4len __P((char **));
+void new_tcpheader __P((void));
+void set_tcpsport __P((char **));
+void set_tcpdport __P((char **));
+void set_tcpseq __P((char **));
+void set_tcpack __P((char **));
+void set_tcpoff __P((char **));
+void set_tcpurp __P((char **));
+void set_tcpwin __P((char **));
+void set_tcpsum __P((char **));
+void set_tcpflags __P((char **));
+void set_tcpopt __P((int, char **));
+void end_tcpopt __P((void));
+void new_udpheader __P((void));
+void set_udplen __P((char **));
+void set_udpsum __P((char **));
+void prep_packet __P((void));
+void packet_done __P((void));
+void new_interface __P((void));
+void check_interface __P((void));
+void set_ifname __P((char **));
+void set_ifmtu __P((int));
+void set_ifv4addr __P((char **));
+void set_ifeaddr __P((char **));
+void new_arp __P((void));
+void set_arpeaddr __P((char **));
+void set_arpv4addr __P((char **));
+void reset_send __P((void));
+void set_sendif __P((char **));
+void set_sendvia __P((char **));
+void set_defaultrouter __P((char **));
+void new_icmpheader __P((void));
+void set_icmpcode __P((int));
+void set_icmptype __P((int));
+void set_icmpcodetok __P((char **));
+void set_icmptypetok __P((char **));
+void set_icmpid __P((int));
+void set_icmpseq __P((int));
+void set_icmpotime __P((int));
+void set_icmprtime __P((int));
+void set_icmpttime __P((int));
+void set_icmpmtu __P((int));
+void set_redir __P((int, char **));
+void new_ipv4opt __P((void));
+void set_icmppprob __P((int));
+void add_ipopt __P((int, void *));
+void end_ipopt __P((void));
+void set_secclass __P((char **));
+void free_anipheader __P((void));
+void end_ipv4 __P((void));
+void end_icmp __P((void));
+void end_udp __P((void));
+void end_tcp __P((void));
+void end_data __P((void));
+void yyerror __P((char *));
+void iplang __P((FILE *));
+int arp_getipv4 __P((char *, char *));
+int yyparse __P((void));
+%}
+%union {
+ char *str;
+ int num;
+}
+%token <num> IL_NUMBER
+%type <num> number digits optnumber
+%token <str> IL_TOKEN
+%type <str> token optoken
+%token IL_HEXDIGIT IL_COLON IL_DOT IL_EOF IL_COMMENT
+%token IL_INTERFACE IL_IFNAME IL_MTU IL_EADDR
+%token IL_IPV4 IL_V4PROTO IL_V4SRC IL_V4DST IL_V4OFF IL_V4V IL_V4HL IL_V4TTL
+%token IL_V4TOS IL_V4SUM IL_V4LEN IL_V4OPT IL_V4ID
+%token IL_TCP IL_SPORT IL_DPORT IL_TCPFL IL_TCPSEQ IL_TCPACK IL_TCPOFF
+%token IL_TCPWIN IL_TCPSUM IL_TCPURP IL_TCPOPT IL_TCPO_NOP IL_TCPO_EOL
+%token IL_TCPO_MSS IL_TCPO_WSCALE IL_TCPO_TS
+%token IL_UDP IL_UDPLEN IL_UDPSUM
+%token IL_ICMP IL_ICMPTYPE IL_ICMPCODE
+%token IL_SEND IL_VIA
+%token IL_ARP
+%token IL_DEFROUTER
+%token IL_SUM IL_OFF IL_LEN IL_V4ADDR IL_OPT
+%token IL_DATA IL_DLEN IL_DVALUE IL_DFILE
+%token IL_IPO_NOP IL_IPO_RR IL_IPO_ZSU IL_IPO_MTUP IL_IPO_MTUR IL_IPO_EOL
+%token IL_IPO_TS IL_IPO_TR IL_IPO_SEC IL_IPO_LSRR IL_IPO_ESEC
+%token IL_IPO_SATID IL_IPO_SSRR IL_IPO_ADDEXT IL_IPO_VISA IL_IPO_IMITD
+%token IL_IPO_EIP IL_IPO_FINN IL_IPO_SECCLASS IL_IPO_CIPSO IL_IPO_ENCODE
+%token <str> IL_IPS_RESERV4 IL_IPS_TOPSECRET IL_IPS_SECRET IL_IPS_RESERV3
+%token <str> IL_IPS_CONFID IL_IPS_UNCLASS IL_IPS_RESERV2 IL_IPS_RESERV1
+%token IL_ICMP_ECHOREPLY IL_ICMP_UNREACH IL_ICMP_UNREACH_NET
+%token IL_ICMP_UNREACH_HOST IL_ICMP_UNREACH_PROTOCOL IL_ICMP_UNREACH_PORT
+%token IL_ICMP_UNREACH_NEEDFRAG IL_ICMP_UNREACH_SRCFAIL
+%token IL_ICMP_UNREACH_NET_UNKNOWN IL_ICMP_UNREACH_HOST_UNKNOWN
+%token IL_ICMP_UNREACH_ISOLATED IL_ICMP_UNREACH_NET_PROHIB
+%token IL_ICMP_UNREACH_HOST_PROHIB IL_ICMP_UNREACH_TOSNET
+%token IL_ICMP_UNREACH_TOSHOST IL_ICMP_UNREACH_FILTER_PROHIB
+%token IL_ICMP_UNREACH_HOST_PRECEDENCE IL_ICMP_UNREACH_PRECEDENCE_CUTOFF
+%token IL_ICMP_SOURCEQUENCH IL_ICMP_REDIRECT IL_ICMP_REDIRECT_NET
+%token IL_ICMP_REDIRECT_HOST IL_ICMP_REDIRECT_TOSNET
+%token IL_ICMP_REDIRECT_TOSHOST IL_ICMP_ECHO IL_ICMP_ROUTERADVERT
+%token IL_ICMP_ROUTERSOLICIT IL_ICMP_TIMXCEED IL_ICMP_TIMXCEED_INTRANS
+%token IL_ICMP_TIMXCEED_REASS IL_ICMP_PARAMPROB IL_ICMP_PARAMPROB_OPTABSENT
+%token IL_ICMP_TSTAMP IL_ICMP_TSTAMPREPLY IL_ICMP_IREQ IL_ICMP_IREQREPLY
+%token IL_ICMP_MASKREQ IL_ICMP_MASKREPLY IL_ICMP_SEQ IL_ICMP_ID
+%token IL_ICMP_OTIME IL_ICMP_RTIME IL_ICMP_TTIME
+
+%%
+file: line
+ | line file
+ | IL_COMMENT
+ | IL_COMMENT file
+ ;
+
+line: iface
+ | arp
+ | send
+ | defrouter
+ | ipline
+ ;
+
+iface: ifhdr '{' ifaceopts '}' ';' { check_interface(); }
+ ;
+
+ifhdr: IL_INTERFACE { new_interface(); }
+ ;
+
+ifaceopts:
+ ifaceopt
+ | ifaceopt ifaceopts
+ ;
+
+ifaceopt:
+ IL_IFNAME token { set_ifname(&$2); }
+ | IL_MTU number { set_ifmtu($2); }
+ | IL_V4ADDR token { set_ifv4addr(&$2); }
+ | IL_EADDR token { set_ifeaddr(&$2); }
+ ;
+
+send: sendhdr '{' sendbody '}' ';' { packet_done(); }
+ | sendhdr ';' { packet_done(); }
+ ;
+
+sendhdr:
+ IL_SEND { reset_send(); }
+ ;
+
+sendbody:
+ sendopt
+ | sendbody sendopt
+ ;
+
+sendopt:
+ IL_IFNAME token { set_sendif(&$2); }
+ | IL_VIA token { set_sendvia(&$2); }
+ ;
+
+arp: arphdr '{' arpbody '}' ';'
+ ;
+
+arphdr: IL_ARP { new_arp(); }
+ ;
+
+arpbody:
+ arpopt
+ | arpbody arpopt
+ ;
+
+arpopt: IL_V4ADDR token { set_arpv4addr(&$2); }
+ | IL_EADDR token { set_arpeaddr(&$2); }
+ ;
+
+defrouter:
+ IL_DEFROUTER token { set_defaultrouter(&$2); }
+ ;
+
+bodyline:
+ ipline
+ | tcp tcpline
+ | udp udpline
+ | icmp icmpline
+ | data dataline
+ ;
+
+ipline: ipv4 '{' ipv4body '}' ';' { end_ipv4(); }
+ ;
+
+ipv4: IL_IPV4 { new_packet(); }
+
+ipv4body:
+ ipv4type
+ | ipv4type ipv4body
+ | bodyline
+ ;
+
+ipv4type:
+ IL_V4PROTO token { set_ipv4proto(&$2); }
+ | IL_V4SRC token { set_ipv4src(&$2); }
+ | IL_V4DST token { set_ipv4dst(&$2); }
+ | IL_V4OFF token { set_ipv4off(&$2); }
+ | IL_V4V token { set_ipv4v(&$2); }
+ | IL_V4HL token { set_ipv4hl(&$2); }
+ | IL_V4ID token { set_ipv4id(&$2); }
+ | IL_V4TTL token { set_ipv4ttl(&$2); }
+ | IL_V4TOS token { set_ipv4tos(&$2); }
+ | IL_V4SUM token { set_ipv4sum(&$2); }
+ | IL_V4LEN token { set_ipv4len(&$2); }
+ | ipv4opt '{' ipv4optlist '}' ';' { end_ipopt(); }
+ ;
+
+tcp: IL_TCP { new_tcpheader(); }
+ ;
+
+tcpline:
+ '{' tcpheader '}' ';' { end_tcp(); }
+ ;
+
+tcpheader:
+ tcpbody
+ | tcpbody tcpheader
+ | bodyline
+ ;
+
+tcpbody:
+ IL_SPORT token { set_tcpsport(&$2); }
+ | IL_DPORT token { set_tcpdport(&$2); }
+ | IL_TCPSEQ token { set_tcpseq(&$2); }
+ | IL_TCPACK token { set_tcpack(&$2); }
+ | IL_TCPOFF token { set_tcpoff(&$2); }
+ | IL_TCPURP token { set_tcpurp(&$2); }
+ | IL_TCPWIN token { set_tcpwin(&$2); }
+ | IL_TCPSUM token { set_tcpsum(&$2); }
+ | IL_TCPFL token { set_tcpflags(&$2); }
+ | IL_TCPOPT '{' tcpopts '}' ';' { end_tcpopt(); }
+ ;
+
+tcpopts:
+ | tcpopt tcpopts
+ ;
+
+tcpopt: IL_TCPO_NOP ';' { set_tcpopt(IL_TCPO_NOP, NULL); }
+ | IL_TCPO_EOL ';' { set_tcpopt(IL_TCPO_EOL, NULL); }
+ | IL_TCPO_MSS optoken { set_tcpopt(IL_TCPO_MSS,&$2);}
+ | IL_TCPO_WSCALE optoken { set_tcpopt(IL_TCPO_WSCALE,&$2);}
+ | IL_TCPO_TS optoken { set_tcpopt(IL_TCPO_TS, &$2);}
+ ;
+
+udp: IL_UDP { new_udpheader(); }
+ ;
+
+udpline:
+ '{' udpheader '}' ';' { end_udp(); }
+ ;
+
+
+udpheader:
+ udpbody
+ | udpbody udpheader
+ | bodyline
+ ;
+
+udpbody:
+ IL_SPORT token { set_tcpsport(&$2); }
+ | IL_DPORT token { set_tcpdport(&$2); }
+ | IL_UDPLEN token { set_udplen(&$2); }
+ | IL_UDPSUM token { set_udpsum(&$2); }
+ ;
+
+icmp: IL_ICMP { new_icmpheader(); }
+ ;
+
+icmpline:
+ '{' icmpbody '}' ';' { end_icmp(); }
+ ;
+
+icmpbody:
+ icmpheader
+ | icmpheader bodyline
+ ;
+
+icmpheader:
+ IL_ICMPTYPE icmptype
+ | IL_ICMPTYPE icmptype icmpcode
+ ;
+
+icmpcode:
+ IL_ICMPCODE token { set_icmpcodetok(&$2); }
+ ;
+
+icmptype:
+ IL_ICMP_ECHOREPLY ';' { set_icmptype(ICMP_ECHOREPLY); }
+ | IL_ICMP_ECHOREPLY '{' icmpechoopts '}' ';'
+ | unreach
+ | IL_ICMP_SOURCEQUENCH ';' { set_icmptype(ICMP_SOURCEQUENCH); }
+ | redirect
+ | IL_ICMP_ROUTERADVERT ';' { set_icmptype(ICMP_ROUTERADVERT); }
+ | IL_ICMP_ROUTERSOLICIT ';' { set_icmptype(ICMP_ROUTERSOLICIT); }
+ | IL_ICMP_ECHO ';' { set_icmptype(ICMP_ECHO); }
+ | IL_ICMP_ECHO '{' icmpechoopts '}' ';'
+ | IL_ICMP_TIMXCEED ';' { set_icmptype(ICMP_TIMXCEED); }
+ | IL_ICMP_TIMXCEED '{' exceed '}' ';'
+ | IL_ICMP_TSTAMP ';' { set_icmptype(ICMP_TSTAMP); }
+ | IL_ICMP_TSTAMPREPLY ';' { set_icmptype(ICMP_TSTAMPREPLY); }
+ | IL_ICMP_TSTAMPREPLY '{' icmptsopts '}' ';'
+ | IL_ICMP_IREQ ';' { set_icmptype(ICMP_IREQ); }
+ | IL_ICMP_IREQREPLY ';' { set_icmptype(ICMP_IREQREPLY); }
+ | IL_ICMP_IREQREPLY '{' data dataline '}' ';'
+ | IL_ICMP_MASKREQ ';' { set_icmptype(ICMP_MASKREQ); }
+ | IL_ICMP_MASKREPLY ';' { set_icmptype(ICMP_MASKREPLY); }
+ | IL_ICMP_MASKREPLY '{' token '}' ';'
+ | IL_ICMP_PARAMPROB ';' { set_icmptype(ICMP_PARAMPROB); }
+ | IL_ICMP_PARAMPROB '{' paramprob '}' ';'
+ | IL_TOKEN ';' { set_icmptypetok(&$1); }
+ ;
+
+icmpechoopts:
+ | icmpechoopts icmpecho
+ ;
+
+icmpecho:
+ IL_ICMP_SEQ number { set_icmpseq($2); }
+ | IL_ICMP_ID number { set_icmpid($2); }
+ ;
+
+icmptsopts:
+ | icmptsopts icmpts ';'
+ ;
+
+icmpts: IL_ICMP_OTIME number { set_icmpotime($2); }
+ | IL_ICMP_RTIME number { set_icmprtime($2); }
+ | IL_ICMP_TTIME number { set_icmpttime($2); }
+ ;
+
+unreach:
+ IL_ICMP_UNREACH
+ | IL_ICMP_UNREACH '{' unreachopts '}' ';'
+ ;
+
+unreachopts:
+ IL_ICMP_UNREACH_NET line
+ | IL_ICMP_UNREACH_HOST line
+ | IL_ICMP_UNREACH_PROTOCOL line
+ | IL_ICMP_UNREACH_PORT line
+ | IL_ICMP_UNREACH_NEEDFRAG number ';' { set_icmpmtu($2); }
+ | IL_ICMP_UNREACH_SRCFAIL line
+ | IL_ICMP_UNREACH_NET_UNKNOWN line
+ | IL_ICMP_UNREACH_HOST_UNKNOWN line
+ | IL_ICMP_UNREACH_ISOLATED line
+ | IL_ICMP_UNREACH_NET_PROHIB line
+ | IL_ICMP_UNREACH_HOST_PROHIB line
+ | IL_ICMP_UNREACH_TOSNET line
+ | IL_ICMP_UNREACH_TOSHOST line
+ | IL_ICMP_UNREACH_FILTER_PROHIB line
+ | IL_ICMP_UNREACH_HOST_PRECEDENCE line
+ | IL_ICMP_UNREACH_PRECEDENCE_CUTOFF line
+ ;
+
+redirect:
+ IL_ICMP_REDIRECT
+ | IL_ICMP_REDIRECT '{' redirectopts '}' ';'
+ ;
+
+redirectopts:
+ | IL_ICMP_REDIRECT_NET token { set_redir(0, &$2); }
+ | IL_ICMP_REDIRECT_HOST token { set_redir(1, &$2); }
+ | IL_ICMP_REDIRECT_TOSNET token { set_redir(2, &$2); }
+ | IL_ICMP_REDIRECT_TOSHOST token { set_redir(3, &$2); }
+ ;
+
+exceed:
+ IL_ICMP_TIMXCEED_INTRANS line
+ | IL_ICMP_TIMXCEED_REASS line
+ ;
+
+paramprob:
+ IL_ICMP_PARAMPROB_OPTABSENT
+ | IL_ICMP_PARAMPROB_OPTABSENT paraprobarg
+
+paraprobarg:
+ '{' number '}' ';' { set_icmppprob($2); }
+ ;
+
+ipv4opt: IL_V4OPT { new_ipv4opt(); }
+ ;
+
+ipv4optlist:
+ | ipv4opts ipv4optlist
+ ;
+
+ipv4opts:
+ IL_IPO_NOP ';' { add_ipopt(IL_IPO_NOP, NULL); }
+ | IL_IPO_RR optnumber { add_ipopt(IL_IPO_RR, &$2); }
+ | IL_IPO_ZSU ';' { add_ipopt(IL_IPO_ZSU, NULL); }
+ | IL_IPO_MTUP ';' { add_ipopt(IL_IPO_MTUP, NULL); }
+ | IL_IPO_MTUR ';' { add_ipopt(IL_IPO_MTUR, NULL); }
+ | IL_IPO_ENCODE ';' { add_ipopt(IL_IPO_ENCODE, NULL); }
+ | IL_IPO_TS ';' { add_ipopt(IL_IPO_TS, NULL); }
+ | IL_IPO_TR ';' { add_ipopt(IL_IPO_TR, NULL); }
+ | IL_IPO_SEC ';' { add_ipopt(IL_IPO_SEC, NULL); }
+ | IL_IPO_SECCLASS secclass { add_ipopt(IL_IPO_SECCLASS, sclass); }
+ | IL_IPO_LSRR token { add_ipopt(IL_IPO_LSRR,&$2); }
+ | IL_IPO_ESEC ';' { add_ipopt(IL_IPO_ESEC, NULL); }
+ | IL_IPO_CIPSO ';' { add_ipopt(IL_IPO_CIPSO, NULL); }
+ | IL_IPO_SATID optnumber { add_ipopt(IL_IPO_SATID,&$2);}
+ | IL_IPO_SSRR token { add_ipopt(IL_IPO_SSRR,&$2); }
+ | IL_IPO_ADDEXT ';' { add_ipopt(IL_IPO_ADDEXT, NULL); }
+ | IL_IPO_VISA ';' { add_ipopt(IL_IPO_VISA, NULL); }
+ | IL_IPO_IMITD ';' { add_ipopt(IL_IPO_IMITD, NULL); }
+ | IL_IPO_EIP ';' { add_ipopt(IL_IPO_EIP, NULL); }
+ | IL_IPO_FINN ';' { add_ipopt(IL_IPO_FINN, NULL); }
+ ;
+
+secclass:
+ IL_IPS_RESERV4 ';' { set_secclass(&$1); }
+ | IL_IPS_TOPSECRET ';' { set_secclass(&$1); }
+ | IL_IPS_SECRET ';' { set_secclass(&$1); }
+ | IL_IPS_RESERV3 ';' { set_secclass(&$1); }
+ | IL_IPS_CONFID ';' { set_secclass(&$1); }
+ | IL_IPS_UNCLASS ';' { set_secclass(&$1); }
+ | IL_IPS_RESERV2 ';' { set_secclass(&$1); }
+ | IL_IPS_RESERV1 ';' { set_secclass(&$1); }
+ ;
+
+data: IL_DATA { new_data(); }
+ ;
+
+dataline:
+ '{' databody '}' ';' { end_data(); }
+ ;
+
+databody: dataopts
+ | dataopts databody
+ ;
+
+dataopts:
+ IL_DLEN token { set_datalen(&$2); }
+ | IL_DVALUE token { set_data(&$2); }
+ | IL_DFILE token { set_datafile(&$2); }
+ ;
+
+token: IL_TOKEN ';'
+ ;
+
+optoken: ';' { $$ = ""; }
+ | token
+ ;
+
+number: digits ';'
+ ;
+
+optnumber: ';' { $$ = 0; }
+ | number
+ ;
+
+digits: IL_NUMBER
+ | digits IL_NUMBER
+ ;
+%%
+
+struct statetoopt toipopts[] = {
+ { IL_IPO_NOP, IPOPT_NOP },
+ { IL_IPO_RR, IPOPT_RR },
+ { IL_IPO_ZSU, IPOPT_ZSU },
+ { IL_IPO_MTUP, IPOPT_MTUP },
+ { IL_IPO_MTUR, IPOPT_MTUR },
+ { IL_IPO_ENCODE, IPOPT_ENCODE },
+ { IL_IPO_TS, IPOPT_TS },
+ { IL_IPO_TR, IPOPT_TR },
+ { IL_IPO_SEC, IPOPT_SECURITY },
+ { IL_IPO_SECCLASS, IPOPT_SECURITY },
+ { IL_IPO_LSRR, IPOPT_LSRR },
+ { IL_IPO_ESEC, IPOPT_E_SEC },
+ { IL_IPO_CIPSO, IPOPT_CIPSO },
+ { IL_IPO_SATID, IPOPT_SATID },
+ { IL_IPO_SSRR, IPOPT_SSRR },
+ { IL_IPO_ADDEXT, IPOPT_ADDEXT },
+ { IL_IPO_VISA, IPOPT_VISA },
+ { IL_IPO_IMITD, IPOPT_IMITD },
+ { IL_IPO_EIP, IPOPT_EIP },
+ { IL_IPO_FINN, IPOPT_FINN },
+ { 0, 0 }
+};
+
+struct statetoopt tosecopts[] = {
+ { IL_IPS_RESERV4, IPSO_CLASS_RES4 },
+ { IL_IPS_TOPSECRET, IPSO_CLASS_TOPS },
+ { IL_IPS_SECRET, IPSO_CLASS_SECR },
+ { IL_IPS_RESERV3, IPSO_CLASS_RES3 },
+ { IL_IPS_CONFID, IPSO_CLASS_CONF },
+ { IL_IPS_UNCLASS, IPSO_CLASS_UNCL },
+ { IL_IPS_RESERV2, IPSO_CLASS_RES2 },
+ { IL_IPS_RESERV1, IPSO_CLASS_RES1 },
+ { 0, 0 }
+};
+
+#ifdef bsdi
+struct ether_addr *
+ether_aton(s)
+ char *s;
+{
+ static struct ether_addr n;
+ u_int i[6];
+
+ if (sscanf(s, " %x:%x:%x:%x:%x:%x ", &i[0], &i[1],
+ &i[2], &i[3], &i[4], &i[5]) == 6) {
+ n.ether_addr_octet[0] = (u_char)i[0];
+ n.ether_addr_octet[1] = (u_char)i[1];
+ n.ether_addr_octet[2] = (u_char)i[2];
+ n.ether_addr_octet[3] = (u_char)i[3];
+ n.ether_addr_octet[4] = (u_char)i[4];
+ n.ether_addr_octet[5] = (u_char)i[5];
+ return &n;
+ }
+ return NULL;
+}
+#endif
+
+
+struct in_addr getipv4addr(arg)
+char *arg;
+{
+ struct hostent *hp;
+ struct in_addr in;
+
+ in.s_addr = 0xffffffff;
+
+ if ((hp = gethostbyname(arg)))
+ bcopy(hp->h_addr, &in.s_addr, sizeof(struct in_addr));
+ else
+ in.s_addr = inet_addr(arg);
+ return in;
+}
+
+
+u_short getportnum(pr, name)
+char *pr, *name;
+{
+ struct servent *sp;
+
+ if (!(sp = getservbyname(name, pr)))
+ return htons(atoi(name));
+ return sp->s_port;
+}
+
+
+struct ether_addr *geteaddr(arg, buf)
+char *arg;
+struct ether_addr *buf;
+{
+ struct ether_addr *e;
+
+#if !defined(hpux) && !defined(linux)
+ e = ether_aton(arg);
+ if (!e)
+ fprintf(stderr, "Invalid ethernet address: %s\n", arg);
+ else
+# ifdef __FreeBSD__
+ bcopy(e->octet, buf->octet, sizeof(e->octet));
+# else
+ bcopy(e->ether_addr_octet, buf->ether_addr_octet,
+ sizeof(e->ether_addr_octet));
+# endif
+ return e;
+#else
+ return NULL;
+#endif
+}
+
+
+void *new_header(type)
+int type;
+{
+ aniphdr_t *aip, *oip = canip;
+ int sz = 0;
+
+ aip = (aniphdr_t *)calloc(1, sizeof(*aip));
+ *aniptail = aip;
+ aniptail = &aip->ah_next;
+ aip->ah_p = type;
+ aip->ah_prev = oip;
+ canip = aip;
+
+ if (type == IPPROTO_UDP)
+ sz = sizeof(udphdr_t);
+ else if (type == IPPROTO_TCP)
+ sz = sizeof(tcphdr_t);
+ else if (type == IPPROTO_ICMP)
+ sz = sizeof(icmphdr_t);
+ else if (type == IPPROTO_IP)
+ sz = sizeof(ip_t);
+
+ if (oip)
+ canip->ah_data = oip->ah_data + oip->ah_len;
+ else
+ canip->ah_data = (char *)ipbuffer;
+
+ /*
+ * Increase the size fields in all wrapping headers.
+ */
+ for (aip = aniphead; aip; aip = aip->ah_next) {
+ aip->ah_len += sz;
+ if (aip->ah_p == IPPROTO_IP)
+ aip->ah_ip->ip_len += sz;
+ else if (aip->ah_p == IPPROTO_UDP)
+ aip->ah_udp->uh_ulen += sz;
+ }
+ return (void *)canip->ah_data;
+}
+
+
+void free_aniplist()
+{
+ aniphdr_t *aip, **aipp = &aniphead;
+
+ while ((aip = *aipp)) {
+ *aipp = aip->ah_next;
+ free(aip);
+ }
+ aniptail = &aniphead;
+}
+
+
+void inc_anipheaders(inc)
+int inc;
+{
+ aniphdr_t *aip;
+
+ for (aip = aniphead; aip; aip = aip->ah_next) {
+ aip->ah_len += inc;
+ if (aip->ah_p == IPPROTO_IP)
+ aip->ah_ip->ip_len += inc;
+ else if (aip->ah_p == IPPROTO_UDP)
+ aip->ah_udp->uh_ulen += inc;
+ }
+}
+
+
+void new_data()
+{
+ (void) new_header(-1);
+ canip->ah_len = 0;
+}
+
+
+void set_datalen(arg)
+char **arg;
+{
+ int len;
+
+ len = strtol(*arg, NULL, 0);
+ inc_anipheaders(len);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_data(arg)
+char **arg;
+{
+ u_char *s = (u_char *)*arg, *t = (u_char *)canip->ah_data, c;
+ int len = 0, todo = 0, quote = 0, val = 0;
+
+ while ((c = *s++)) {
+ if (todo) {
+ if (ISDIGIT(c)) {
+ todo--;
+ if (c > '7') {
+ fprintf(stderr, "octal with %c!\n", c);
+ break;
+ }
+ val <<= 3;
+ val |= (c - '0');
+ }
+ if (!ISDIGIT(c) || !todo) {
+ *t++ = (u_char)(val & 0xff);
+ todo = 0;
+ }
+ if (todo)
+ continue;
+ }
+ if (quote) {
+ if (ISDIGIT(c)) {
+ todo = 2;
+ if (c > '7') {
+ fprintf(stderr, "octal with %c!\n", c);
+ break;
+ }
+ val = (c - '0');
+ } else {
+ switch (c)
+ {
+ case '\"' :
+ *t++ = '\"';
+ break;
+ case '\\' :
+ *t++ = '\\';
+ break;
+ case 'n' :
+ *t++ = '\n';
+ break;
+ case 'r' :
+ *t++ = '\r';
+ break;
+ case 't' :
+ *t++ = '\t';
+ break;
+ }
+ }
+ quote = 0;
+ continue;
+ }
+
+ if (c == '\\')
+ quote = 1;
+ else
+ *t++ = c;
+ }
+ if (todo)
+ *t++ = (u_char)(val & 0xff);
+ if (quote)
+ *t++ = '\\';
+ len = t - (u_char *)canip->ah_data;
+ inc_anipheaders(len - canip->ah_len);
+ canip->ah_len = len;
+}
+
+
+void set_datafile(arg)
+char **arg;
+{
+ struct stat sb;
+ char *file = *arg;
+ int fd, len;
+
+ if ((fd = open(file, O_RDONLY)) == -1) {
+ perror("open");
+ exit(-1);
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ perror("fstat");
+ exit(-1);
+ }
+
+ if ((sb.st_size + aniphead->ah_len ) > 65535) {
+ fprintf(stderr, "data file %s too big to include.\n", file);
+ close(fd);
+ return;
+ }
+ if ((len = read(fd, canip->ah_data, sb.st_size)) == -1) {
+ perror("read");
+ close(fd);
+ return;
+ }
+ inc_anipheaders(len);
+ canip->ah_len += len;
+ close(fd);
+}
+
+
+void new_packet()
+{
+ static u_short id = 0;
+
+ if (!aniphead)
+ bzero((char *)ipbuffer, sizeof(ipbuffer));
+
+ ip = (ip_t *)new_header(IPPROTO_IP);
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(ip_t) >> 2;
+ ip->ip_len = sizeof(ip_t);
+ ip->ip_ttl = 63;
+ ip->ip_id = htons(id++);
+}
+
+
+void set_ipv4proto(arg)
+char **arg;
+{
+ struct protoent *pr;
+
+ if ((pr = getprotobyname(*arg)))
+ ip->ip_p = pr->p_proto;
+ else
+ if (!(ip->ip_p = atoi(*arg)))
+ fprintf(stderr, "unknown protocol %s\n", *arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4src(arg)
+char **arg;
+{
+ ip->ip_src = getipv4addr(*arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4dst(arg)
+char **arg;
+{
+ ip->ip_dst = getipv4addr(*arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4off(arg)
+char **arg;
+{
+ ip->ip_off = htons(strtol(*arg, NULL, 0));
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4v(arg)
+char **arg;
+{
+ ip->ip_v = strtol(*arg, NULL, 0);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4hl(arg)
+char **arg;
+{
+ int newhl, inc;
+
+ newhl = strtol(*arg, NULL, 0);
+ inc = (newhl - ip->ip_hl) << 2;
+ ip->ip_len += inc;
+ ip->ip_hl = newhl;
+ canip->ah_len += inc;
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4ttl(arg)
+char **arg;
+{
+ ip->ip_ttl = strtol(*arg, NULL, 0);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4tos(arg)
+char **arg;
+{
+ ip->ip_tos = strtol(*arg, NULL, 0);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4id(arg)
+char **arg;
+{
+ ip->ip_id = htons(strtol(*arg, NULL, 0));
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4sum(arg)
+char **arg;
+{
+ ip->ip_sum = strtol(*arg, NULL, 0);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ipv4len(arg)
+char **arg;
+{
+ int len;
+
+ len = strtol(*arg, NULL, 0);
+ inc_anipheaders(len - ip->ip_len);
+ ip->ip_len = len;
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void new_tcpheader()
+{
+
+ if ((ip->ip_p) && (ip->ip_p != IPPROTO_TCP)) {
+ fprintf(stderr, "protocol %d specified with TCP!\n", ip->ip_p);
+ return;
+ }
+ ip->ip_p = IPPROTO_TCP;
+
+ tcp = (tcphdr_t *)new_header(IPPROTO_TCP);
+ tcp->th_win = htons(4096);
+ tcp->th_off = sizeof(*tcp) >> 2;
+}
+
+
+void set_tcpsport(arg)
+char **arg;
+{
+ u_short *port;
+ char *pr;
+
+ if (ip->ip_p == IPPROTO_UDP) {
+ port = &udp->uh_sport;
+ pr = "udp";
+ } else {
+ port = &tcp->th_sport;
+ pr = "udp";
+ }
+
+ *port = getportnum(pr, *arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpdport(arg)
+char **arg;
+{
+ u_short *port;
+ char *pr;
+
+ if (ip->ip_p == IPPROTO_UDP) {
+ port = &udp->uh_dport;
+ pr = "udp";
+ } else {
+ port = &tcp->th_dport;
+ pr = "udp";
+ }
+
+ *port = getportnum(pr, *arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpseq(arg)
+char **arg;
+{
+ tcp->th_seq = htonl(strtol(*arg, NULL, 0));
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpack(arg)
+char **arg;
+{
+ tcp->th_ack = htonl(strtol(*arg, NULL, 0));
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpoff(arg)
+char **arg;
+{
+ int off;
+
+ off = strtol(*arg, NULL, 0);
+ inc_anipheaders((off - tcp->th_off) << 2);
+ tcp->th_off = off;
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpurp(arg)
+char **arg;
+{
+ tcp->th_urp = htons(strtol(*arg, NULL, 0));
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpwin(arg)
+char **arg;
+{
+ tcp->th_win = htons(strtol(*arg, NULL, 0));
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpsum(arg)
+char **arg;
+{
+ tcp->th_sum = strtol(*arg, NULL, 0);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpflags(arg)
+char **arg;
+{
+ static char flags[] = "ASURPF";
+ static int flagv[] = { TH_ACK, TH_SYN, TH_URG, TH_RST, TH_PUSH,
+ TH_FIN } ;
+ char *s, *t;
+
+ for (s = *arg; *s; s++)
+ if (!(t = strchr(flags, *s))) {
+ if (s - *arg) {
+ fprintf(stderr, "unknown TCP flag %c\n", *s);
+ break;
+ }
+ tcp->th_flags = strtol(*arg, NULL, 0);
+ break;
+ } else
+ tcp->th_flags |= flagv[t - flags];
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_tcpopt(state, arg)
+int state;
+char **arg;
+{
+ u_char *s;
+ int val, len, val2, pad, optval;
+
+ if (arg && *arg)
+ val = atoi(*arg);
+ else
+ val = 0;
+
+ s = (u_char *)tcp + sizeof(*tcp) + canip->ah_optlen;
+ switch (state)
+ {
+ case IL_TCPO_EOL :
+ optval = 0;
+ len = 1;
+ break;
+ case IL_TCPO_NOP :
+ optval = 1;
+ len = 1;
+ break;
+ case IL_TCPO_MSS :
+ optval = 2;
+ len = 4;
+ break;
+ case IL_TCPO_WSCALE :
+ optval = 3;
+ len = 3;
+ break;
+ case IL_TCPO_TS :
+ optval = 8;
+ len = 10;
+ break;
+ default :
+ optval = 0;
+ len = 0;
+ break;
+ }
+
+ if (len > 1) {
+ /*
+ * prepend padding - if required.
+ */
+ if (len & 3)
+ for (pad = 4 - (len & 3); pad; pad--) {
+ *s++ = 1;
+ canip->ah_optlen++;
+ }
+ /*
+ * build tcp option
+ */
+ *s++ = (u_char)optval;
+ *s++ = (u_char)len;
+ if (len > 2) {
+ if (len == 3) { /* 1 byte - char */
+ *s++ = (u_char)val;
+ } else if (len == 4) { /* 2 bytes - short */
+ *s++ = (u_char)((val >> 8) & 0xff);
+ *s++ = (u_char)(val & 0xff);
+ } else if (len >= 6) { /* 4 bytes - long */
+ val2 = htonl(val);
+ bcopy((char *)&val2, s, 4);
+ }
+ s += (len - 2);
+ }
+ } else
+ *s++ = (u_char)optval;
+
+ canip->ah_lastopt = optval;
+ canip->ah_optlen += len;
+
+ if (arg && *arg) {
+ free(*arg);
+ *arg = NULL;
+ }
+}
+
+
+void end_tcpopt()
+{
+ int pad;
+ char *s = (char *)tcp;
+
+ s += sizeof(*tcp) + canip->ah_optlen;
+ /*
+ * pad out so that we have a multiple of 4 bytes in size fo the
+ * options. make sure last byte is EOL.
+ */
+ if (canip->ah_optlen & 3) {
+ if (canip->ah_lastopt != 1) {
+ for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
+ *s++ = 1;
+ canip->ah_optlen++;
+ }
+ canip->ah_optlen++;
+ } else {
+ s -= 1;
+
+ for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
+ *s++ = 1;
+ canip->ah_optlen++;
+ }
+ }
+ *s++ = 0;
+ }
+ tcp->th_off = (sizeof(*tcp) + canip->ah_optlen) >> 2;
+ inc_anipheaders(canip->ah_optlen);
+}
+
+
+void new_udpheader()
+{
+ if ((ip->ip_p) && (ip->ip_p != IPPROTO_UDP)) {
+ fprintf(stderr, "protocol %d specified with UDP!\n", ip->ip_p);
+ return;
+ }
+ ip->ip_p = IPPROTO_UDP;
+
+ udp = (udphdr_t *)new_header(IPPROTO_UDP);
+ udp->uh_ulen = sizeof(*udp);
+}
+
+
+void set_udplen(arg)
+char **arg;
+{
+ int len;
+
+ len = strtol(*arg, NULL, 0);
+ inc_anipheaders(len - udp->uh_ulen);
+ udp->uh_ulen = len;
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_udpsum(arg)
+char **arg;
+{
+ udp->uh_sum = strtol(*arg, NULL, 0);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void prep_packet()
+{
+ iface_t *ifp;
+ struct in_addr gwip;
+
+ ifp = sending.snd_if;
+ if (!ifp) {
+ fprintf(stderr, "no interface defined for sending!\n");
+ return;
+ }
+ if (ifp->if_fd == -1)
+ ifp->if_fd = initdevice(ifp->if_name, 5);
+ gwip = sending.snd_gw;
+ if (!gwip.s_addr) {
+ if (aniphead == NULL) {
+ fprintf(stderr,
+ "no destination address defined for sending\n");
+ return;
+ }
+ gwip = aniphead->ah_ip->ip_dst;
+ }
+ (void) send_ip(ifp->if_fd, ifp->if_MTU, (ip_t *)ipbuffer, gwip, 2);
+}
+
+
+void packet_done()
+{
+ char outline[80];
+ int i, j, k;
+ u_char *s = (u_char *)ipbuffer, *t = (u_char *)outline;
+
+ if (opts & OPT_VERBOSE) {
+ ip->ip_len = htons(ip->ip_len);
+ for (i = ntohs(ip->ip_len), j = 0; i; i--, j++, s++) {
+ if (j && !(j & 0xf)) {
+ *t++ = '\n';
+ *t = '\0';
+ fputs(outline, stdout);
+ fflush(stdout);
+ t = (u_char *)outline;
+ *t = '\0';
+ }
+ sprintf((char *)t, "%02x", *s & 0xff);
+ t += 2;
+ if (!((j + 1) & 0xf)) {
+ s -= 15;
+ sprintf((char *)t, " ");
+ t += 8;
+ for (k = 16; k; k--, s++)
+ *t++ = (isprint(*s) ? *s : '.');
+ s--;
+ }
+
+ if ((j + 1) & 0xf)
+ *t++ = ' ';;
+ }
+
+ if (j & 0xf) {
+ for (k = 16 - (j & 0xf); k; k--) {
+ *t++ = ' ';
+ *t++ = ' ';
+ *t++ = ' ';
+ }
+ sprintf((char *)t, " ");
+ t += 7;
+ s -= j & 0xf;
+ for (k = j & 0xf; k; k--, s++)
+ *t++ = (isprint(*s) ? *s : '.');
+ *t++ = '\n';
+ *t = '\0';
+ }
+ fputs(outline, stdout);
+ fflush(stdout);
+ ip->ip_len = ntohs(ip->ip_len);
+ }
+
+ prep_packet();
+ free_aniplist();
+}
+
+
+void new_interface()
+{
+ cifp = (iface_t *)calloc(1, sizeof(iface_t));
+ *iftail = cifp;
+ iftail = &cifp->if_next;
+ cifp->if_fd = -1;
+}
+
+
+void check_interface()
+{
+ if (!cifp->if_name || !*cifp->if_name)
+ fprintf(stderr, "No interface name given!\n");
+ if (!cifp->if_MTU || !*cifp->if_name)
+ fprintf(stderr, "Interface %s has an MTU of 0!\n",
+ cifp->if_name);
+}
+
+
+void set_ifname(arg)
+char **arg;
+{
+ cifp->if_name = *arg;
+ *arg = NULL;
+}
+
+
+void set_ifmtu(arg)
+int arg;
+{
+ cifp->if_MTU = arg;
+}
+
+
+void set_ifv4addr(arg)
+char **arg;
+{
+ cifp->if_addr = getipv4addr(*arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_ifeaddr(arg)
+char **arg;
+{
+ (void) geteaddr(*arg, &cifp->if_eaddr);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void new_arp()
+{
+ carp = (arp_t *)calloc(1, sizeof(arp_t));
+ *arptail = carp;
+ arptail = &carp->arp_next;
+}
+
+
+void set_arpeaddr(arg)
+char **arg;
+{
+ (void) geteaddr(*arg, &carp->arp_eaddr);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_arpv4addr(arg)
+char **arg;
+{
+ carp->arp_addr = getipv4addr(*arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+int arp_getipv4(ip, addr)
+char *ip;
+char *addr;
+{
+ arp_t *a;
+
+ for (a = arplist; a; a = a->arp_next)
+ if (!bcmp(ip, (char *)&a->arp_addr, 4)) {
+ bcopy((char *)&a->arp_eaddr, addr, 6);
+ return 0;
+ }
+ return -1;
+}
+
+
+void reset_send()
+{
+ sending.snd_if = iflist;
+ sending.snd_gw = defrouter;
+}
+
+
+void set_sendif(arg)
+char **arg;
+{
+ iface_t *ifp;
+
+ for (ifp = iflist; ifp; ifp = ifp->if_next)
+ if (ifp->if_name && !strcmp(ifp->if_name, *arg))
+ break;
+ sending.snd_if = ifp;
+ if (!ifp)
+ fprintf(stderr, "couldn't find interface %s\n", *arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_sendvia(arg)
+char **arg;
+{
+ sending.snd_gw = getipv4addr(*arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_defaultrouter(arg)
+char **arg;
+{
+ defrouter = getipv4addr(*arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void new_icmpheader()
+{
+ if ((ip->ip_p) && (ip->ip_p != IPPROTO_ICMP)) {
+ fprintf(stderr, "protocol %d specified with ICMP!\n",
+ ip->ip_p);
+ return;
+ }
+ ip->ip_p = IPPROTO_ICMP;
+ icmp = (icmphdr_t *)new_header(IPPROTO_ICMP);
+}
+
+
+void set_icmpcode(code)
+int code;
+{
+ icmp->icmp_code = code;
+}
+
+
+void set_icmptype(type)
+int type;
+{
+ icmp->icmp_type = type;
+}
+
+
+void set_icmpcodetok(code)
+char **code;
+{
+ char *s;
+ int i;
+
+ for (i = 0; (s = icmpcodes[i]); i++)
+ if (!strcmp(s, *code)) {
+ icmp->icmp_code = i;
+ break;
+ }
+ if (!s)
+ fprintf(stderr, "unknown ICMP code %s\n", *code);
+ free(*code);
+ *code = NULL;
+}
+
+
+void set_icmptypetok(type)
+char **type;
+{
+ char *s;
+ int i, done = 0;
+
+ for (i = 0; !(s = icmptypes[i]) || strcmp(s, "END"); i++)
+ if (s && !strcmp(s, *type)) {
+ icmp->icmp_type = i;
+ done = 1;
+ break;
+ }
+ if (!done)
+ fprintf(stderr, "unknown ICMP type %s\n", *type);
+ free(*type);
+ *type = NULL;
+}
+
+
+void set_icmpid(arg)
+int arg;
+{
+ icmp->icmp_id = htons(arg);
+}
+
+
+void set_icmpseq(arg)
+int arg;
+{
+ icmp->icmp_seq = htons(arg);
+}
+
+
+void set_icmpotime(arg)
+int arg;
+{
+ icmp->icmp_otime = htonl(arg);
+}
+
+
+void set_icmprtime(arg)
+int arg;
+{
+ icmp->icmp_rtime = htonl(arg);
+}
+
+
+void set_icmpttime(arg)
+int arg;
+{
+ icmp->icmp_ttime = htonl(arg);
+}
+
+
+void set_icmpmtu(arg)
+int arg;
+{
+#if BSD >= 199306
+ icmp->icmp_nextmtu = htons(arg);
+#endif
+}
+
+
+void set_redir(redir, arg)
+int redir;
+char **arg;
+{
+ icmp->icmp_code = redir;
+ icmp->icmp_gwaddr = getipv4addr(*arg);
+ free(*arg);
+ *arg = NULL;
+}
+
+
+void set_icmppprob(num)
+int num;
+{
+ icmp->icmp_pptr = num;
+}
+
+
+void new_ipv4opt()
+{
+ new_header(-2);
+}
+
+
+void add_ipopt(state, ptr)
+int state;
+void *ptr;
+{
+ struct ipopt_names *io;
+ struct statetoopt *sto;
+ char numbuf[16], *arg, **param = ptr;
+ int inc, hlen;
+
+ if (state == IL_IPO_RR || state == IL_IPO_SATID) {
+ if (param)
+ sprintf(numbuf, "%d", *(int *)param);
+ else
+ strcpy(numbuf, "0");
+ arg = numbuf;
+ } else
+ arg = param ? *param : NULL;
+
+ if (canip->ah_next) {
+ fprintf(stderr, "cannot specify options after data body\n");
+ return;
+ }
+ for (sto = toipopts; sto->sto_st; sto++)
+ if (sto->sto_st == state)
+ break;
+ if (!sto->sto_st) {
+ fprintf(stderr, "No mapping for state %d to IP option\n",
+ state);
+ return;
+ }
+
+ hlen = sizeof(ip_t) + canip->ah_optlen;
+ for (io = ionames; io->on_name; io++)
+ if (io->on_value == sto->sto_op)
+ break;
+ canip->ah_lastopt = io->on_value;
+
+ if (io->on_name) {
+ inc = addipopt((char *)ip + hlen, io, hlen - sizeof(ip_t),arg);
+ if (inc > 0) {
+ while (inc & 3) {
+ ((char *)ip)[sizeof(*ip) + inc] = IPOPT_NOP;
+ canip->ah_lastopt = IPOPT_NOP;
+ inc++;
+ }
+ hlen += inc;
+ }
+ }
+
+ canip->ah_optlen = hlen - sizeof(ip_t);
+
+ if (state != IL_IPO_RR && state != IL_IPO_SATID)
+ if (param && *param) {
+ free(*param);
+ *param = NULL;
+ }
+ sclass = NULL;
+}
+
+
+void end_ipopt()
+{
+ int pad;
+ char *s, *buf = (char *)ip;
+
+ /*
+ * pad out so that we have a multiple of 4 bytes in size fo the
+ * options. make sure last byte is EOL.
+ */
+ if (canip->ah_lastopt == IPOPT_NOP) {
+ buf[sizeof(*ip) + canip->ah_optlen - 1] = IPOPT_EOL;
+ } else if (canip->ah_lastopt != IPOPT_EOL) {
+ s = buf + sizeof(*ip) + canip->ah_optlen;
+
+ for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
+ *s++ = IPOPT_NOP;
+ *s = IPOPT_EOL;
+ canip->ah_optlen++;
+ }
+ canip->ah_optlen++;
+ } else {
+ s = buf + sizeof(*ip) + canip->ah_optlen - 1;
+
+ for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) {
+ *s++ = IPOPT_NOP;
+ *s = IPOPT_EOL;
+ canip->ah_optlen++;
+ }
+ }
+ ip->ip_hl = (sizeof(*ip) + canip->ah_optlen) >> 2;
+ inc_anipheaders(canip->ah_optlen);
+ free_anipheader();
+}
+
+
+void set_secclass(arg)
+char **arg;
+{
+ sclass = *arg;
+ *arg = NULL;
+}
+
+
+void free_anipheader()
+{
+ aniphdr_t *aip;
+
+ aip = canip;
+ if ((canip = aip->ah_prev)) {
+ canip->ah_next = NULL;
+ aniptail = &canip->ah_next;
+ }
+
+ if (canip)
+ free(aip);
+}
+
+
+void end_ipv4()
+{
+ aniphdr_t *aip;
+
+ ip->ip_sum = 0;
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2);
+ ip->ip_len = ntohs(ip->ip_len);
+ free_anipheader();
+ for (aip = aniphead, ip = NULL; aip; aip = aip->ah_next)
+ if (aip->ah_p == IPPROTO_IP)
+ ip = aip->ah_ip;
+}
+
+
+void end_icmp()
+{
+ aniphdr_t *aip;
+
+ icmp->icmp_cksum = 0;
+ icmp->icmp_cksum = chksum((u_short *)icmp, canip->ah_len);
+ free_anipheader();
+ for (aip = aniphead, icmp = NULL; aip; aip = aip->ah_next)
+ if (aip->ah_p == IPPROTO_ICMP)
+ icmp = aip->ah_icmp;
+}
+
+
+void end_udp()
+{
+ u_long sum;
+ aniphdr_t *aip;
+ ip_t iptmp;
+
+ bzero((char *)&iptmp, sizeof(iptmp));
+ iptmp.ip_p = ip->ip_p;
+ iptmp.ip_src = ip->ip_src;
+ iptmp.ip_dst = ip->ip_dst;
+ iptmp.ip_len = htons(ip->ip_len - (ip->ip_hl << 2));
+ sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp));
+ udp->uh_ulen = htons(udp->uh_ulen);
+ udp->uh_sum = c_chksum((u_short *)udp, (u_int)ntohs(iptmp.ip_len), sum);
+ free_anipheader();
+ for (aip = aniphead, udp = NULL; aip; aip = aip->ah_next)
+ if (aip->ah_p == IPPROTO_UDP)
+ udp = aip->ah_udp;
+}
+
+
+void end_tcp()
+{
+ u_long sum;
+ aniphdr_t *aip;
+ ip_t iptmp;
+
+ bzero((char *)&iptmp, sizeof(iptmp));
+ iptmp.ip_p = ip->ip_p;
+ iptmp.ip_src = ip->ip_src;
+ iptmp.ip_dst = ip->ip_dst;
+ iptmp.ip_len = htons(ip->ip_len - (ip->ip_hl << 2));
+ sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp));
+ tcp->th_sum = 0;
+ tcp->th_sum = c_chksum((u_short *)tcp, (u_int)ntohs(iptmp.ip_len), sum);
+ free_anipheader();
+ for (aip = aniphead, tcp = NULL; aip; aip = aip->ah_next)
+ if (aip->ah_p == IPPROTO_TCP)
+ tcp = aip->ah_tcp;
+}
+
+
+void end_data()
+{
+ free_anipheader();
+}
+
+
+void iplang(fp)
+FILE *fp;
+{
+ yyin = fp;
+
+ yydebug = (opts & OPT_DEBUG) ? 1 : 0;
+
+ while (!feof(fp))
+ yyparse();
+}
+
+
+u_short c_chksum(buf, len, init)
+u_short *buf;
+u_int len;
+u_long init;
+{
+ u_long sum = init;
+ int nwords = len >> 1;
+
+ for(; nwords > 0; nwords--)
+ sum += *buf++;
+ sum = (sum>>16) + (sum & 0xffff);
+ sum += (sum >>16);
+ return (~sum);
+}
+
+
+u_long p_chksum(buf,len)
+u_short *buf;
+u_int len;
+{
+ u_long sum = 0;
+ int nwords = len >> 1;
+
+ for(; nwords > 0; nwords--)
+ sum += *buf++;
+ return sum;
+}
diff --git a/contrib/ipfilter/ipmon.h b/contrib/ipfilter/ipmon.h
new file mode 100644
index 0000000..b469cc8
--- /dev/null
+++ b/contrib/ipfilter/ipmon.h
@@ -0,0 +1,142 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * @(#)ip_fil.h 1.35 6/5/96
+ * $Id$
+ */
+
+typedef struct ipmon_msg_s {
+ int imm_msglen;
+ char *imm_msg;
+ int imm_dsize;
+ void *imm_data;
+ time_t imm_when;
+ int imm_loglevel;
+} ipmon_msg_t;
+
+typedef void (*ims_destroy_func_t)(void *);
+typedef void *(*ims_dup_func_t)(void *);
+typedef int (*ims_match_func_t)(void *, void *);
+typedef void *(*ims_parse_func_t)(char **);
+typedef void (*ims_print_func_t)(void *);
+typedef int (*ims_store_func_t)(void *, ipmon_msg_t *);
+
+typedef struct ipmon_saver_s {
+ char *ims_name;
+ ims_destroy_func_t ims_destroy;
+ ims_dup_func_t ims_dup;
+ ims_match_func_t ims_match;
+ ims_parse_func_t ims_parse;
+ ims_print_func_t ims_print;
+ ims_store_func_t ims_store;
+} ipmon_saver_t;
+
+typedef struct ipmon_saver_int_s {
+ struct ipmon_saver_int_s *imsi_next;
+ ipmon_saver_t *imsi_stor;
+ void *imsi_handle;
+} ipmon_saver_int_t;
+
+typedef struct ipmon_doing_s {
+ struct ipmon_doing_s *ipmd_next;
+ void *ipmd_token;
+ ipmon_saver_t *ipmd_saver;
+ /*
+ * ipmd_store is "cached" in this structure to avoid a double
+ * deref when doing saves....
+ */
+ int (*ipmd_store)(void *, ipmon_msg_t *);
+} ipmon_doing_t;
+
+
+typedef struct ipmon_action {
+ struct ipmon_action *ac_next;
+ int ac_mflag; /* collection of things to compare */
+ int ac_dflag; /* flags to compliment the doing fields */
+ int ac_logpri;
+ int ac_direction;
+ char ac_group[FR_GROUPLEN];
+ char ac_nattag[16];
+ u_32_t ac_logtag;
+ int ac_type; /* nat/state/ipf */
+ int ac_proto;
+ int ac_rule;
+ int ac_packet;
+ int ac_second;
+ int ac_result;
+ u_32_t ac_sip;
+ u_32_t ac_smsk;
+ u_32_t ac_dip;
+ u_32_t ac_dmsk;
+ u_short ac_sport;
+ u_short ac_dport;
+ char *ac_iface;
+ /*
+ * used with ac_packet/ac_second
+ */
+ struct timeval ac_last;
+ int ac_pktcnt;
+ /*
+ * What to do with matches
+ */
+ ipmon_doing_t *ac_doing;
+} ipmon_action_t;
+
+#define ac_lastsec ac_last.tv_sec
+#define ac_lastusec ac_last.tv_usec
+
+/*
+ * Flags indicating what fields to do matching upon (ac_mflag).
+ */
+#define IPMAC_DIRECTION 0x0001
+#define IPMAC_DSTIP 0x0002
+#define IPMAC_DSTPORT 0x0004
+#define IPMAC_EVERY 0x0008
+#define IPMAC_GROUP 0x0010
+#define IPMAC_INTERFACE 0x0020
+#define IPMAC_LOGTAG 0x0040
+#define IPMAC_NATTAG 0x0080
+#define IPMAC_PROTOCOL 0x0100
+#define IPMAC_RESULT 0x0200
+#define IPMAC_RULE 0x0400
+#define IPMAC_SRCIP 0x0800
+#define IPMAC_SRCPORT 0x1000
+#define IPMAC_TYPE 0x2000
+#define IPMAC_WITH 0x4000
+
+#define IPMR_BLOCK 1
+#define IPMR_PASS 2
+#define IPMR_NOMATCH 3
+#define IPMR_LOG 4
+
+#define IPMON_SYSLOG 0x001
+#define IPMON_RESOLVE 0x002
+#define IPMON_HEXBODY 0x004
+#define IPMON_HEXHDR 0x010
+#define IPMON_TAIL 0x020
+#define IPMON_VERBOSE 0x040
+#define IPMON_NAT 0x080
+#define IPMON_STATE 0x100
+#define IPMON_FILTER 0x200
+#define IPMON_PORTNUM 0x400
+#define IPMON_LOGALL (IPMON_NAT|IPMON_STATE|IPMON_FILTER)
+#define IPMON_LOGBODY 0x800
+
+#define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b))
+
+#ifndef LOGFAC
+#define LOGFAC LOG_LOCAL0
+#endif
+
+extern void dump_config __P((void));
+extern int load_config __P((char *));
+extern void unload_config __P((void));
+extern void dumphex __P((FILE *, int, char *, int));
+extern int check_action __P((char *, char *, int, int));
+extern char *getword __P((int));
+extern void *add_doing __P((ipmon_saver_t *));
+
diff --git a/contrib/ipfilter/ipsd/Celler/ip_compat.h b/contrib/ipfilter/ipsd/Celler/ip_compat.h
new file mode 100644
index 0000000..5793776
--- /dev/null
+++ b/contrib/ipfilter/ipsd/Celler/ip_compat.h
@@ -0,0 +1,203 @@
+/* $FreeBSD$ */
+
+/*
+ * (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/Makefile b/contrib/ipfilter/ipsd/Makefile
new file mode 100644
index 0000000..d5dde8e
--- /dev/null
+++ b/contrib/ipfilter/ipsd/Makefile
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2012 by Darren Reed.
+#
+# See the IPFILTER.LICENCE file for details on licencing.
+#
+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.. -I../ipsend
+
+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..eb6b798
--- /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@pobox.com
diff --git a/contrib/ipfilter/ipsd/ipsd.c b/contrib/ipfilter/ipsd/ipsd.c
new file mode 100644
index 0000000..ce51c1b
--- /dev/null
+++ b/contrib/ipfilter/ipsd/ipsd.c
@@ -0,0 +1,296 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1995-1998 Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#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 const char sccsid[] = "@(#)ipsd.c 1.3 12/3/95 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#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 *name = argv[0], *dev = NULL;
+ int fd, writeafter = 10000, angelic = 0, c;
+
+ 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..f898c99
--- /dev/null
+++ b/contrib/ipfilter/ipsd/ipsd.h
@@ -0,0 +1,28 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1995-1998 Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * @(#)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..e1c0c0a
--- /dev/null
+++ b/contrib/ipfilter/ipsd/ipsdr.c
@@ -0,0 +1,314 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1995-1998 Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#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 const char sccsid[] = "@(#)ipsdr.c 1.3 12/3/95 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#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..f00ea53
--- /dev/null
+++ b/contrib/ipfilter/ipsd/linux.h
@@ -0,0 +1,17 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * @(#)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..74ba197
--- /dev/null
+++ b/contrib/ipfilter/ipsd/sbpf.c
@@ -0,0 +1,210 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1995-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#ifdef __NetBSD__
+# include <paths.h>
+#endif
+#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;
+#ifdef _PATH_BPF
+ char *bpfname = _PATH_BPF;
+ int fd;
+
+ if ((fd = open(bpfname, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "no bpf devices available as /dev/bpfxx\n");
+ return -1;
+ }
+#else
+ char bpfname[16];
+ int fd = -1, 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;
+ }
+#endif
+
+ 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..00c197b
--- /dev/null
+++ b/contrib/ipfilter/ipsd/sdlpi.c
@@ -0,0 +1,261 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1992-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#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..95ad8e5
--- /dev/null
+++ b/contrib/ipfilter/ipsd/slinux.c
@@ -0,0 +1,118 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1992-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#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 const 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..855afd5
--- /dev/null
+++ b/contrib/ipfilter/ipsd/snit.c
@@ -0,0 +1,228 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1992-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#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/.OLD/ip_compat.h b/contrib/ipfilter/ipsend/.OLD/ip_compat.h
new file mode 100644
index 0000000..b5b8f07
--- /dev/null
+++ b/contrib/ipfilter/ipsend/.OLD/ip_compat.h
@@ -0,0 +1,244 @@
+/* $FreeBSD$ */
+
+/*
+ * (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/44arp.c b/contrib/ipfilter/ipsend/44arp.c
new file mode 100644
index 0000000..9215959
--- /dev/null
+++ b/contrib/ipfilter/ipsend/44arp.c
@@ -0,0 +1,120 @@
+/* $FreeBSD$ */
+
+/*
+ * Based upon 4.4BSD's /usr/sbin/arp
+ */
+#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>
+#ifndef __osf__
+# include <net/route.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <errno.h>
+#include <nlist.h>
+#include <stdio.h>
+#include "ipsend.h"
+#include "iplang/iplang.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 *lim, *buf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_in *sin;
+ struct sockaddr_dl *sdl;
+
+#ifdef IPSEND
+ if (arp_getipv4(addr, ether) == 0)
+ return 0;
+#endif
+
+ if (!addr)
+ return -1;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_FLAGS;
+#ifdef RTF_LLINFO
+ mib[5] = RTF_LLINFO;
+#else
+ mib[5] = 0;
+#endif
+
+ 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_in *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(sin + 1);
+ if (!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..c7ffcde
--- /dev/null
+++ b/contrib/ipfilter/ipsend/Crashable
@@ -0,0 +1,21 @@
+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
+ MacOS 7.x, 8.x
+
+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..34485ef
--- /dev/null
+++ b/contrib/ipfilter/ipsend/Makefile
@@ -0,0 +1,183 @@
+#
+# Copyright (C) 2012 by Darren Reed.
+#
+# See the IPFILTER.LICENCE file for details on licencing.
+#
+IPFT=ipft_ef.o ipft_hx.o ipft_pc.o ipft_sn.o ipft_td.o ipft_tx.o opt.o
+OBJS=ipsend.o ip.o ipsopt.o y.tab.o lex.yy.o
+ROBJS=ipresend.o ip.o resend.o $(IPFT)
+TOBJS=iptest.o iptests.o ip.o
+BPF=sbpf.o
+NIT=snit.o
+SUNOS4=sock.o arp.o inet_addr.o
+BSD=sock.o 44arp.o
+LINUX=lsock.o slinux.o larp.o
+LINUXK=
+TOP=..
+SUNOS5=dlcommon.o sdlpi.o arp.o inet_addr.o
+ULTRIX=ultrix.o sock.o arp.o inet_addr.o
+HPUX=hpux.o sock.o arp.o inet_addr.o
+
+#CC=gcc
+DEBUG=-g
+CFLAGS=$(DEBUG) -I. -Iipf
+#
+MFLAGS="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" \
+ "IPFLKM=$(IPFLKM)" \
+ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \
+ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \
+ "CPUDIR=$(CPUDIR)"
+#
+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 " linux12 (Linux 1.2 kernels)"
+ @echo " linux20 (Linux 2.0 kernels)"
+ @echo " sunos5 (Solaris 2.x)"
+
+ipf:
+ -if [ ! -d iplang ] ; then ln -s ../iplang iplang; fi
+ -if [ ! -d netinet ] ; then ln -s ../netinet netinet; fi
+ -if [ ! -d ipf ] ; then ln -s .. ipf; fi
+
+y.tab.o: iplang/iplang_y.y
+ -if [ -h iplang ] ; then \
+ (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=../ipsend' ) \
+ else \
+ (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=..' ) \
+ fi
+
+lex.yy.o: iplang/iplang_l.l
+ -if [ -h iplang ] ; then \
+ (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=../ipsend' ) \
+ else \
+ (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=..' ) \
+ fi
+
+.c.o:
+ $(CC) $(CFLAGS) $(LINUXK) -c $< -o $@
+
+install:
+ -$(INSTALL) -cs -g wheel -m 755 -o root ipsend ipresend iptest $(BINDEST)
+
+bpf sunos4-bpf :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \
+ "CFLAGS=$(CFLAGS) -DDOSOCKET -DIPSEND" "LLIB=-ll"
+ 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 -DIPSEND" "LLIB=-ll"
+ 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 -DIPSEND" "LIBS=-lsocket -lnsl" \
+ "LLIB=-ll"
+ 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 -DIPSEND" "LLIB=-ll"
+ 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) $(INC) -DDOSOCKET -DIPSEND" $(LINUXK)
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) $(INC) -DDOSOCKET" $(LINUXK)
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) $(INC) -DDOSOCKET" $(LINUXK)
+
+linux10:
+ make linuxrev 'LINUXK="LINUXK=-DLINUX=0100"' \
+ "INC=-I/usr/src/linux/include" "LLIB=-lfl"
+
+linux12:
+ make linuxrev 'LINUXK="LINUXK=-DLINUX=0102"' "INC=-I/usr/src/linux" \
+ "LLIB=-lfl"
+
+linux20:
+ make linuxrev 'LINUXK="LINUXK=-DLINUX=0200"' \
+ "INC=-I/usr/src/linux/include" "LLIB=-lfl" "ELIB=-lelf"
+
+ultrix :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(ULTRIX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -DIPSEND" "LIBS=" "LLIB=-ll"
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(ULTRIX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS)" "LIBS="
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(ULTRIX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS)" "LIBS="
+
+hpux9 :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -DIPSEND" "LIBS="
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS)" "LIBS="
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS)" "LIBS="
+
+hpux11 :
+ make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS) -DIPSEND" "LIBS="
+ make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS)" "LIBS="
+ make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \
+ CFLAGS="$(CFLAGS)" "LIBS="
+
+ipsend: ipf $(OBJS) $(UNIXOBJS)
+ $(CC) $(OBJS) $(UNIXOBJS) -o $@ $(LIBS) $(LLIB) $(ELIB)
+
+ipresend: $(ROBJS) $(UNIXOBJS)
+ $(CC) $(ROBJS) $(UNIXOBJS) -o $@ $(LIBS) $(ELIB)
+
+iptest: $(TOBJS) $(UNIXOBJS)
+ $(CC) $(TOBJS) $(UNIXOBJS) -o $@ $(LIBS) $(ELIB)
+
+ipft_ef.o: ipf/ipft_ef.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_ef.c -o $@
+
+ipft_hx.o: ipf/ipft_hx.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_hx.c -o $@
+
+ipft_pc.o: ipf/ipft_pc.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_pc.c -o $@
+
+ipft_sn.o: ipf/ipft_sn.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_sn.c -o $@
+
+ipft_td.o: ipf/ipft_td.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_td.c -o $@
+
+ipft_tx.o: ipf/ipft_tx.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_tx.c -o $@
+
+opt.o: ipf/opt.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/opt.c -o $@
+
+inet_addr.o: ipf/inet_addr.c
+ $(CC) $(CFLAGS) $(LINUXK) -c ipf/inet_addr.c -o $@
+
+clean:
+ rm -rf *.o *core a.out ipsend ipresend iptest
+ if [ -d iplang ]; then (cd iplang; $(MAKE) $(MFLAGS) clean); fi
+ if [ -d $(TOP)/iplang ]; then (cd $(TOP)/iplang; $(MAKE) $(MFLAGS) clean); fi
+
+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/ipsend/arp.c b/contrib/ipfilter/ipsend/arp.c
new file mode 100644
index 0000000..58a1523
--- /dev/null
+++ b/contrib/ipfilter/ipsend/arp.c
@@ -0,0 +1,141 @@
+/* $FreeBSD$ */
+
+/*
+ * arp.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)arp.c 1.4 1/11/96 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#if !defined(ultrix) && !defined(hpux) && !defined(__hpux) && !defined(__osf__) && !defined(_AIX51)
+# include <sys/sockio.h>
+#endif
+#include <sys/ioctl.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#ifndef ultrix
+# include <net/if_arp.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <errno.h>
+#include <netdb.h>
+#include "ipsend.h"
+#include "iplang/iplang.h"
+
+
+/*
+ * 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;
+ int fd;
+
+#ifdef IPSEND
+ if (arp_getipv4(ip, ether) == 0)
+ return 0;
+#endif
+ 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);
+#ifndef hpux
+ if ((hp = gethostbyaddr(ip, 4, AF_INET)))
+# if SOLARIS && (SOLARIS2 >= 10)
+ if (!(ether_hostton(hp->h_name, (struct ether_addr *)ether)))
+# else
+ if (!(ether_hostton(hp->h_name, ether)))
+# endif
+ goto savearp;
+#endif
+
+ 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;
+ }
+
+ if ((ar.arp_ha.sa_data[0] == 0) && (ar.arp_ha.sa_data[1] == 0) &&
+ (ar.arp_ha.sa_data[2] == 0) && (ar.arp_ha.sa_data[3] == 0) &&
+ (ar.arp_ha.sa_data[4] == 0) && (ar.arp_ha.sa_data[5] == 0)) {
+ fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr));
+ return -1;
+ }
+
+ bcopy(ar.arp_ha.sa_data, ether, 6);
+savearp:
+ bcopy(ether, ethersave, 6);
+ 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..55bc942
--- /dev/null
+++ b/contrib/ipfilter/ipsend/dlcommon.c
@@ -0,0 +1,1383 @@
+/* $FreeBSD$ */
+
+/*
+ * 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>
+#ifdef __osf__
+# include <sys/dlpihdr.h>
+#else
+# include <sys/dlpi.h>
+#endif
+#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();
+
+
+void
+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");
+}
+
+void
+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);
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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");
+
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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");
+}
+
+void
+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);
+}
+
+void
+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);
+}
+
+void
+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);
+}
+
+void
+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: %s\n",
+ dlprim(dlp->error_ack.dl_error_primitive),
+ dlerrno(dlp->error_ack.dl_errno),
+ dlp->error_ack.dl_unix_errno,
+ strerror(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..086782c
--- /dev/null
+++ b/contrib/ipfilter/ipsend/dltest.h
@@ -0,0 +1,34 @@
+/* $FreeBSD$ */
+
+/*
+ * 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/ip.c b/contrib/ipfilter/ipsend/ip.c
new file mode 100644
index 0000000..fc76170
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ip.c
@@ -0,0 +1,364 @@
+/* $FreeBSD$ */
+
+/*
+ * ip.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "%W% %G% (C)1995";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <netinet/in_systm.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <sys/param.h>
+#ifndef linux
+# include <net/route.h>
+# include <netinet/if_ether.h>
+# include <netinet/ip_var.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "ipsend.h"
+
+
+static char *ipbuf = NULL, *ethbuf = NULL;
+
+
+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 *)A_A eh->ether_dhost, 6);
+ }
+ else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
+ {
+ perror("arp");
+ return -2;
+ }
+ eh->ether_type = htons(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, local_ip;
+ static char local_arp[6] = { 0, 0, 0, 0, 0, 0};
+ static char last_arp[6] = { 0, 0, 0, 0, 0, 0};
+ static u_short id = 0;
+ ether_header_t *eh;
+ ip_t ipsv;
+ int err, iplen;
+
+ if (!ipbuf)
+ {
+ ipbuf = (char *)malloc(65536);
+ if (!ipbuf)
+ {
+ perror("malloc failed");
+ return -2;
+ }
+ }
+
+ eh = (ether_header_t *)ipbuf;
+
+ bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost));
+ if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr))
+ {
+ bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
+ }
+ else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
+ {
+ perror("arp");
+ return -2;
+ }
+ bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp));
+ eh->ether_type = htons(ETHERTYPE_IP);
+
+ bcopy((char *)ip, (char *)&ipsv, sizeof(*ip));
+ last_gw.s_addr = gwip.s_addr;
+ iplen = ip->ip_len;
+ ip->ip_len = htons(iplen);
+ if (!(frag & 2)) {
+ if (!IP_V(ip))
+ IP_V_A(ip, IPVERSION);
+ if (!ip->ip_id)
+ ip->ip_id = htons(id++);
+ if (!ip->ip_ttl)
+ ip->ip_ttl = 60;
+ }
+
+ if (ip->ip_src.s_addr != local_ip.s_addr) {
+ (void) arp((char *)&ip->ip_src, (char *)A_A local_arp);
+ bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp));
+ local_ip = ip->ip_src;
+ } else
+ bcopy(local_arp, (char *)A_A eh->ether_shost, 6);
+
+ if (!frag || (sizeof(*eh) + iplen < mtu))
+ {
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2);
+
+ bcopy((char *)ip, ipbuf + sizeof(*eh), iplen);
+ err = sendip(nfd, ipbuf, sizeof(*eh) + iplen);
+ }
+ 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, sent = 0, ts, hlen, olen;
+
+ hlen = IP_HL(ip) << 2;
+ if (mtu < (hlen + 8)) {
+ fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n",
+ mtu, hlen);
+ fprintf(stderr, "can't fragment data\n");
+ return -2;
+ }
+ ol = (IP_HL(ip) << 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((u_short *)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_HL_A(ip, (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;
+ tcphdr_t *t, *t2;
+ int thlen, i, iplen, hlen;
+ u_32_t lbuf[20];
+ ip_t *ip2;
+
+ iplen = ip->ip_len;
+ hlen = IP_HL(ip) << 2;
+ t = (tcphdr_t *)((char *)ip + hlen);
+ ip2 = (struct ip *)lbuf;
+ t2 = (tcphdr_t *)((char *)ip2 + hlen);
+ thlen = TCP_OFF(t) << 2;
+ if (!thlen)
+ thlen = sizeof(tcphdr_t);
+ bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2));
+ ip->ip_p = IPPROTO_TCP;
+ ip2->ip_p = ip->ip_p;
+ ip2->ip_src = ip->ip_src;
+ ip2->ip_dst = ip->ip_dst;
+ bcopy((char *)ip + hlen, (char *)t2, thlen);
+
+ if (!t2->th_win)
+ t2->th_win = htons(4096);
+ iss += 63;
+
+ i = sizeof(struct tcpiphdr) / sizeof(long);
+
+ if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) &&
+ (lbuf[i] != htonl(0x020405b4))) {
+ lbuf[i] = htonl(0x020405b4);
+ bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4,
+ iplen - thlen - hlen);
+ thlen += 4;
+ }
+ TCP_OFF_A(t2, thlen >> 2);
+ ip2->ip_len = htons(thlen);
+ ip->ip_len = hlen + thlen;
+ t2->th_sum = 0;
+ t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t));
+
+ bcopy((char *)t2, (char *)ip + hlen, 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_HL(ip) << 2),
+ (char *)&ti->ti_sport, sizeof(udphdr_t));
+
+ ti->ti_len = htons(thlen);
+ ip->ip_len = (IP_HL(ip) << 2) + thlen;
+ ti->ti_sum = 0;
+ ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t));
+
+ bcopy((char *)&ti->ti_sport,
+ (char *)ip + (IP_HL(ip) << 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_HL(ip) << 2));
+
+ ic->icmp_cksum = 0;
+ ic->icmp_cksum = chksum((u_short *)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/ipresend.1 b/contrib/ipfilter/ipsend/ipresend.1
new file mode 100644
index 0000000..6761a18
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipresend.1
@@ -0,0 +1,108 @@
+.\" $FreeBSD$
+.\"
+.TH IPRESEND 1
+.SH NAME
+ipresend \- resend IP packets out to network
+.SH SYNOPSIS
+.B ipresend
+[
+.B \-EHPRSTX
+] [
+.B \-d
+<device>
+] [
+.B \-g
+<\fIgateway\fP>
+] [
+.B \-m
+<\fIMTU\fP>
+] [
+.B \-r
+<\fIfilename\fP>
+]
+.SH DESCRIPTION
+.PP
+\fBipresend\fP was designed to allow packets to be resent, once captured,
+back out onto the network for use in testing. \fIipresend\fP supports a
+number of different file formats as input, including saved snoop/tcpdump
+binary data.
+.SH OPTIONS
+.TP
+.BR \-d \0<interface>
+Set the interface name 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
+.BR \-g \0<gateway>
+Specify the hostname of the gateway through which to route packets. This
+is required whenever the destination host isn't directly attached to the
+same network as the host from which you're sending.
+.TP
+.BR \-m \0<MTU>
+Specify the MTU to be used when sending out packets. This option allows you
+to set a fake MTU, allowing the simulation of network interfaces with small
+MTU's without setting them so.
+.TP
+.BR \-r \0<filename>
+Specify the filename from which to take input. Default is stdin.
+.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
+.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 \-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).
+.TP
+.B \-R
+When sending packets out, send them out "raw" (the way they came in). The
+only real significance here is that it will expect the link layer (i.e.
+ethernet) headers to be prepended to the IP packet being output.
+.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 \-X
+The input file is composed of text descriptions of IP packets.
+.DT
+.SH SEE ALSO
+snoop(1m), tcpdump(8), etherfind(8c), ipftest(1), ipresend(1), iptest(1), bpf(4), dlpi(7p)
+.SH DIAGNOSTICS
+.PP
+Needs to be run as root.
+.SH BUGS
+.PP
+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.
+If you find any, please send email to me at darrenr@pobox.com
+
diff --git a/contrib/ipfilter/ipsend/ipresend.c b/contrib/ipfilter/ipsend/ipresend.c
new file mode 100644
index 0000000..7520a0e
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipresend.c
@@ -0,0 +1,151 @@
+/* $FreeBSD$ */
+
+/*
+ * ipresend.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "%W% %G% (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifndef linux
+#include <netinet/ip_var.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include "ipsend.h"
+
+
+extern char *optarg;
+extern int optind;
+#ifndef NO_IPF
+extern struct ipread pcap, iphex, iptext;
+#endif
+
+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
+# ifdef __sgi
+char default_device[] = "ec0";
+# else
+char default_device[] = "lan0";
+# endif
+# endif
+# endif
+# endif
+# endif
+#else
+char default_device[] = DEFAULT_DEVICE;
+#endif
+
+
+static void usage __P((char *));
+int main __P((int, char **));
+
+
+static 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 *resend = NULL;
+ int mtu = 1500, c;
+
+ while ((c = getopt(argc, argv, "EHPRSTXd: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;
+ case 'R' :
+ opts |= OPT_RAW;
+ break;
+#ifndef NO_IPF
+ case 'H' :
+ ipr = &iphex;
+ break;
+ case 'P' :
+ ipr = &pcap;
+ 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.1 b/contrib/ipfilter/ipsend/ipsend.1
new file mode 100644
index 0000000..7f0a8e3
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipsend.1
@@ -0,0 +1,111 @@
+.\" $FreeBSD$
+.\"
+.TH IPSEND 1
+.SH NAME
+ipsend \- sends IP packets
+.SH SYNOPSIS
+.B ipsend
+[
+.B \-dITUv
+] [
+.B \-i
+<interface>
+] [
+.B \-f
+<\fIoffset\fP>
+] [
+.B \-g
+<\fIgateway\fP>
+] [
+.B \-m
+<\fIMTU\fP>
+] [
+.B \-o
+<\fIoption\fP>
+] [
+.B \-P
+<protocol>
+] [
+.B \-s
+<\fIsource\fP>
+] [
+.B \-t
+<\fIdest. port\fP>
+] [
+.B \-w
+<\fIwindow\fP>
+] <destination> [TCP-flags]
+.SH DESCRIPTION
+.PP
+\fBipsend\fP can be compiled in two ways. The first is used to send one-off
+packets to a destination host, using command line options to specify various
+attributes present in the headers. The \fIdestination\fP must be given as
+the last command line option, except for when TCP flags are specified as
+a combination of A, S, F, U, P and R, last.
+.PP
+The other way it may be compiled, with DOSOCKET defined, is to allow an
+attempt at making a TCP connection using a with ipsend resending the SYN
+packet as per the command line options.
+.SH OPTIONS
+.TP
+.BR \-d
+enable debugging mode.
+.TP
+.BR \-f \0<offset>
+The \fI-f\fP allows the IP offset field in the IP header to be set to an
+arbitrary value, which can be specified in decimal or hexadecimal.
+.TP
+.BR \-g \0<gateway>
+Specify the hostname of the gateway through which to route packets. This
+is required whenever the destination host isn't directly attached to the
+same network as the host from which you're sending.
+.TP
+.BR \-i \0<interface>
+Set the interface name to be the name supplied.
+.TP
+.TP
+.BR \-m \0<MTU>
+Specify the MTU to be used when sending out packets. This option allows you
+to set a fake MTU, allowing the simulation of network interfaces with small
+MTU's without setting them so.
+.TP
+.BR \-o \0<option>
+Specify options to be included at the end of the IP header. An EOL option
+is automatically appended and need not be given. If an option would also
+have data associated with it (source as an IP# for a lsrr option), then
+this will not be initialised.
+.TP
+.BR \-s \0<source>
+Set the source address in the packet to that provided - maybe either a
+hostname or IP#.
+.TP
+.BR \-t \0<dest. port>
+Set the destination port for TCP/UDP packets.
+.TP
+.BR \-w \0<window>
+Set the window size for TCP packets.
+.TP
+.B \-I
+Set the protocol to ICMP.
+.TP
+.B \-P <protocol>
+Set the protocol to the value given. If the parameter is a name, the name
+is looked up in the \fI/etc/protocols\fP file.
+.TP
+.B \-T
+Set the protocol to TCP.
+.TP
+.B \-U
+Set the protocol to UDP.
+.TP
+.BR \-v
+enable verbose mode.
+.DT
+.SH SEE ALSO
+ipsend(1), ipresend(1), iptest(1), protocols(4), bpf(4), dlpi(7p)
+.SH DIAGNOSTICS
+.PP
+Needs to be run as root.
+.SH BUGS
+.PP
+If you find any, please send email to me at darrenr@pobox.com
diff --git a/contrib/ipfilter/ipsend/ipsend.5 b/contrib/ipfilter/ipsend/ipsend.5
new file mode 100644
index 0000000..fc86911
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipsend.5
@@ -0,0 +1,402 @@
+.\" $FreeBSD$
+.TH IPSEND 5
+.SH NAME
+ipsend \- IP packet description language
+.SH DESCRIPTION
+The \fBipsend\fP program expects, with the \fB-L\fP option, input to be a
+text file which fits the grammar described below. The purpose of this
+grammar is to allow IP packets to be described in an arbitary way which
+also allows encapsulation to be so done to an arbitary level.
+.SH GRAMMAR
+.LP
+.nf
+line ::= iface | arp | send | defrouter | ipv4line .
+
+iface ::= ifhdr "{" ifaceopts "}" ";" .
+ifhdr ::= "interface" | "iface" .
+ifaceopts ::= "ifname" name | "mtu" mtu | "v4addr" ipaddr |
+ "eaddr" eaddr .
+
+send ::= "send" ";" | "send" "{" sendbodyopts "}" ";" .
+sendbodyopts ::= sendbody [ sendbodyopts ] .
+sendbody ::= "ifname" name | "via" ipaddr .
+
+defrouter ::= "router" ipaddr .
+
+arp ::= "arp" "{" arpbodyopts "}" ";" .
+arpbodyopts ::= arpbody [ arpbodyopts ] .
+arpbody ::= "v4addr" ipaddr | "eaddr" eaddr .
+
+bodyline ::= ipv4line | tcpline | udpline | icmpline | dataline .
+
+ipv4line ::= "ipv4" "{" ipv4bodyopts "}" ";" .
+ipv4bodyopts ::= ipv4body [ ipv4bodyopts ] | bodyline .
+ipv4body ::= "proto" protocol | "src" ipaddr | "dst" ipaddr |
+ "off" number | "v" number | "hl" number| "id" number |
+ "ttl" number | "tos" number | "sum" number | "len" number |
+ "opt" "{" ipv4optlist "}" ";" .
+ipv4optlist ::= ipv4option [ ipv4optlist ] .
+ipv4optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" |
+ "tr" | "sec" | "lsrr" | "e-sec" | "cipso" | "satid" |
+ "ssrr" | "addext" | "visa" | "imitd" | "eip" | "finn" |
+ "secclass" ipv4secclass.
+ipv4secclass := "unclass" | "confid" | "reserv-1" | "reserv-2" |
+ "reserv-3" | "reserv-4" | "secret" | "topsecret" .
+
+tcpline ::= "tcp" "{" tcpbodyopts "}" ";" .
+tcpbodyopts ::= tcpbody [ tcpbodyopts ] | bodyline .
+tcpbody ::= "sport" port | "dport" port | "seq" number | "ack" number |
+ "off" number | "urp" number | "win" number | "sum" number |
+ "flags" tcpflags | data .
+
+udpline ::= "udp" "{" udpbodyopts "}" ";" .
+udpbodyopts ::= udpbody [ udpbodyopts ] | bodyline .
+udpbody ::= "sport" port | "dport" port | "len" number | "sum" number |
+ data .
+
+icmpline ::= "icmp" "{" icmpbodyopts "}" ";" .
+icmpbodyopts ::= icmpbody [ icmpbodyopts ] | bodyline .
+icmpbody ::= "type" icmptype [ "code" icmpcode ] .
+icmptype ::= "echorep" | "echorep" "{" echoopts "}" ";" | "unreach" |
+ "unreach" "{" unreachtype "}" ";" | "squench" | "redir" |
+ "redir" "{" redirtype "}" ";" | "echo" "{" echoopts "}" ";" |
+ "echo" | "routerad" | "routersol" | "timex" |
+ "timex" "{" timextype "}" ";" | "paramprob" |
+ "paramprob" "{" parapptype "}" ";" | "timest" | "timestrep" |
+ "inforeq" | "inforep" | "maskreq" | "maskrep" .
+
+echoopts ::= echoopts [ icmpechoopts ] .
+unreachtype ::= "net-unr" | "host-unr" | "proto-unr" | "port-unr" |
+ "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
+ "net-prohib" | "host-prohib" | "net-tos" | "host-tos" |
+ "filter-prohib" | "host-preced" | "cutoff-preced" .
+redirtype ::= "net-redir" | "host-redir" | "tos-net-redir" |
+ "tos-host-redir" .
+timextype ::= "intrans" | "reass" .
+paramptype ::= "optabsent" .
+
+data ::= "data" "{" databodyopts "}" ";" .
+databodyopts ::= "len" number | "value" string | "file" filename .
+
+icmpechoopts ::= "icmpseq" number | "icmpid" number .
+.fi
+.SH COMMANDS
+.PP
+Before sending any packets or defining any packets, it is necessary to
+describe the interface(s) which will be used to send packets out.
+.TP
+.B interface
+is used to describe a network interface. The description included need
+not match the actual configuration currently employed by the operating
+system.
+.TP
+.B send
+is used to actually send out a packet across the network. If the
+destination is not specified, it will attempt to send the packet
+directly out on the network to the destination without routing it.
+.TP
+.B router
+configures the default router for ipsend, as distinct from the default
+route installed in the kernel.
+.TP
+.B ipv4
+is used to describe an IP (version 4) packet. IP header fields can be
+specified, including options, followed by a data section which may contain
+further protocol headers.
+.SH IPv4
+.TP
+.B hl <number>
+manually specifies the IP header length (automatically adjusts with the
+presence of IP options and defaults to 5);
+.TP
+.B v <number>
+set the IP version. Default is 4.
+.TP
+.B tos <number>
+set the type of service (TOS) field in the IP header. Default is 0.
+.TP
+.B len <number>
+manually specifies the length of the IP packet. The length will automatically
+be adjusted to accommodate data or further protocol headers.
+.TP
+.B off <number>
+sets the fragment offset field of the IP packet. Default is 0.
+.TP
+.B ttl <number>
+sets the time to live (TTL) field of the IP header. Default is 60.
+.TP
+.B proto <protocol>
+sets the protocol field of the IP header. The protocol can either be a
+number or a name found in \fB/etc/protocols\fP.
+.TP
+.B sum
+manually specifies the checksum for the IP header. If left unset (0), it
+will be calculated prior to being sent.
+.TP
+.B src
+manually specifies the source address of the IP header. If left unset, it
+will default to the host's IP address.
+.TP
+.B dst
+sets the destination of the IP packet. The default is 0.0.0.0.
+.TP
+.B opt
+is used to include IP options in the IP header.
+.TP
+.B tcp
+is used to indicate the a TCP protocol header is to follow. See the \fBTCP\fP
+section for TCP header options.
+.TP
+.B udp
+is used to indicate the a UDP protocol header is to follow. See the \fBUDP\fP
+section for UDP header options.
+.TP
+.B icmp
+is used to indicate the a ICMP protocol header is to follow. See the
+\fBICMP\fP section for ICMP header options.
+.TP
+.B data
+is used to indicate that raw data is to be included in the IP packet. See the
+\fBDATA\fP section for details on options available.
+.SH "IPv4 Options"
+these keywords indicate that the relevant IP option should be added to the
+IP header (the header length field will be adjusted appropriately).
+.TP
+.B nop
+No Operation [RFC 791] (space filler).
+.TP
+.B rr <number>
+Record Router [RFC 791]. The number given specifies the number of
+\fBbytes\fP to be used for storage. This should be a multiple of 4 for
+proper operation.
+.TP
+.B zsu
+Experimental Measurement.
+.TP
+.B mtup [RFC 1191].
+MTU Probe.
+.TP
+.B mtur [RFC 1191].
+MTU Ready.
+.TP
+.B encode
+.TP
+.B ts
+Timestamp [RFC 791].
+.TP
+.B tr
+Traceroute [RFC 1393].
+.TP
+.B "sec-class <security-level>, sec"
+Security [RFC 1108]. This option specifies the security label for the packet.
+Using \fBsec\fP sets up the framework of the security option but unless
+\fBsec-class\fP is given, the level may not be set.
+.TP
+.B "lsrr <ip-address>"
+Loose Source Route [RFC 791].
+.TP
+.B e-sec
+Extended Security [RFC 1108].
+.TP
+.B cipso
+Commercial Security.
+.TP
+.B satid
+Stream ID [RFC 791].
+.TP
+.B "ssrr <ip-address>"
+Strict Source Route [RFC 791].
+.TP
+.B addext
+Address Extension
+.TP
+.B visa
+Experimental Access Control.
+.TP
+.B imitd
+IMI Traffic Descriptor.
+.TP
+.B eip
+[RFC 1358].
+.TP
+.B finn
+Experimental Flow Control.
+.SH TCP
+.TP
+.B sport <port>
+sets the source port to the number/name given. Default is 0.
+.TP
+.B dport <port>
+sets the destination port to the number/name given. Default is 0.
+.TP
+.B seq <number>
+sets the sequence number to the number specified. Default is 0.
+.TP
+.B ack <number>
+sets the acknowledge number to the number specified. Default is 0.
+.TP
+.B off <number>
+sets the offset value for the start of data to the number specified. This
+implies the size of the TCP header. It is automatically adjusted if TCP
+options are included and defaults to 5.
+.TP
+.B urp <number>
+sets the value of the urgent data pointer to the number specified. Default
+is 0.
+.TP
+.B win <number>
+sets the size of the TCP window to the number specified. Default is 4096.
+.TP
+.B sum <number>
+manually specifies the checksum for the TCP pseudo-header and data. If left
+unset, it defaults to 0 and is automatically calculated.
+.TP
+.B flags <tcp-flags>
+sets the TCP flags field to match the flags specified. Valid flags are
+"S" (SYN), "A" (ACK), "R" (RST), "F" (FIN), "U" (URG), "P" (PUSH).
+.TP
+.B opt
+indicates that TCP header options follow. As TCP options are added to the
+TCP header, the \fBoff\fP field is updated to match.
+.TP
+.B data
+indicates that a data section is to follow and is to be included as raw
+data, being appended to the header.
+.SH "TCP options"
+With a TCP header, it is possible to append a number of header options.
+The TCP header offset will be updated automatically to reflect the change
+in size. The valid options are: \fBnop\fP No Operation,
+\fBeol\fP End Of (option) List, \fBmss [ size ]\fP Maximum Segment Size - this
+sets the maximum receivable size of a packet containing data,
+\fBwscale\fP Window Scale, \fBts\fP Timestamp.
+.SH UDP
+.TP
+.B sport <port>
+sets the source port to the number/name given. Default is 0.
+.TP
+.B dport <port>
+sets the destination port to the number/name given. Default is 0.
+.TP
+.B len <number>
+manually specifies the length of the UDP header and data. If left unset,
+it is automatically adjusted to match the header presence and any data if
+present.
+.TP
+.B sum <number>
+manually specifies the checksum for the UDP pseudo-header and data. If left
+unset, it defaults to 0 and is automatically calculated.
+.TP
+.B data
+indicates that a data section is to follow and is to be included as raw
+data, being appended to the header.
+.SH ICMP
+.TP
+.B type <icmptype>
+sets the ICMP type according the to the icmptype tag. This may either be
+a number or one of the recognised tags (see the \fBICMP TYPES\fP section for a
+list of names recognised).
+.TP
+.B code <icmpcode>
+sets the ICMP code.
+.TP
+.B data
+indicates that a data section is to follow and is to be included as raw
+data, being appended to the header.
+.SH DATA
+Each of the following extend the packet in a different way. \fBLen\fP just
+increases the length (without adding any content), \fBvalue\fP uses a string
+and \fBfile\fP a file.
+.TP
+.B len <number>
+extend the length of the packet by \fBnumber\fP bytes (without filling those
+bytes with any particular data).
+.TP
+.B value <string>
+indicates that the string provided should be added to the current packet as
+data. A string may be a consecutive list of characters and numbers (with
+no white spaces) or bounded by "'s (may not contain them, even if \\'d).
+The \\ character is recognised with the appropriate C escaped values, including
+octal numbers.
+.TP
+.B file <filename>
+reads data in from the specified file and appends it to the current packet.
+If the new total length would exceed 64k, an error will be reported.
+.SH "ICMP TYPES"
+.TP
+.B echorep
+Echo Reply.
+.TP
+.B "unreach [ unreachable-code ]"
+Generic Unreachable error. This is used to indicate that an error has
+occurred whilst trying to send the packet across the network and that the
+destination cannot be reached. The unreachable code names are:
+\fBnet-unr\fP network unreachable, \fBhost-unr\fP host unreachable,
+\fBproto-unr\fP protocol unreachable, \fBport-unr\fP port unreachable,
+\fBneedfrag\fP, \fBsrcfail\fP source route failed,
+\fBnet-unk\fP network unknown, \fBhost-unk\fP host unknown,
+\fBisolate\fP, \fBnet-prohib\fP administratively prohibited contact with
+network,
+\fBhost-prohib\fP administratively prohibited contact with host,
+\fBnet-tos\fP network unreachable with given TOS,
+\fBhost-tos\fP host unreachable with given TOS,
+\fBfilter-prohib\fP packet prohibited by packet filter,
+\fBhost-preced\fP,
+\fBcutoff-preced\fP.
+.TP
+.B squench
+Source Quence.
+.TP
+.B "redir [ redirect-code ]"
+Redirect (routing). This is used to indicate that the route being chosen
+for forwarding the packet is suboptimal and that the sender of the packet
+should be routing packets via another route. The redirect code names are:
+\fBnet-redir\fP redirect packets for a network,
+\fBhost-redir\fP redirect packets for a host,
+\fBtos-net-redir\fP redirect packets for a network with a given TOS,
+\fBtos-host-redir\fP redirect packets for a host with a given TOS.
+.TP
+.B echo
+Echo.
+.TP
+.B routerad
+Router Advertisement.
+.TP
+.B routersol
+Router solicitation.
+.TP
+.B "timex [ timexceed-code ]"
+Time Exceeded. This is used to indicate that the packet failed to reach the
+destination because it was in transit too long (i.e. ttl reached 0). The
+valid code names are: \fBintrans\fP,
+\fBreass\fP could not reassemble packet from fragments within a given time.
+.TP
+.B "paramprob [ paramprob-code ]"
+Parameter problem. There is only one available parameter problem code name:
+\fBoptabsent\fP.
+.TP
+.B timest
+Time stamp request.
+.TP
+.B "timestrep [ { timestamp-code } ]"
+Time stamp reply. In a timestamp reply, it is possible to supply the
+following values: \fBrtime\fP, \fBotime\fP, \fBttime\fP.
+.TP
+.B inforeq
+Information request.
+.TP
+.B inforep
+Information reply.
+.TP
+.B maskreq
+Address mask request.
+.TP
+.B maskrep
+Address mask reply.
+.SH FILES
+/etc/hosts
+.br
+/etc/protocols
+.br
+/etc/services
+.SH SEE ALSO
+ipsend(1), iptest(1), hosts(5), protocols(5), services(5)
diff --git a/contrib/ipfilter/ipsend/ipsend.c b/contrib/ipfilter/ipsend/ipsend.c
new file mode 100644
index 0000000..3df5c07
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipsend.c
@@ -0,0 +1,440 @@
+/* $FreeBSD$ */
+/*
+ * ipsend.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/ip.h>
+#ifndef linux
+# include <netinet/ip_var.h>
+#endif
+#include "ipsend.h"
+#include "ipf.h"
+#ifndef linux
+# include <netinet/udp_var.h>
+#endif
+
+
+extern char *optarg;
+extern int optind;
+extern void iplang __P((FILE *));
+
+char options[68];
+int opts;
+#ifdef linux
+char default_device[] = "eth0";
+#else
+# ifdef ultrix
+char default_device[] = "ln0";
+# else
+# ifdef __bsdi__
+char default_device[] = "ef0";
+# else
+# ifdef __sgi
+char default_device[] = "ec0";
+# else
+# ifdef __hpux
+char default_device[] = "lan0";
+# else
+char default_device[] = "le0";
+# endif /* __hpux */
+# endif /* __sgi */
+# endif /* __bsdi__ */
+# endif /* ultrix */
+#endif /* linux */
+
+
+static void usage __P((char *));
+static void do_icmp __P((ip_t *, char *));
+void udpcksum(ip_t *, struct udphdr *, int);
+int main __P((int, char **));
+
+
+static void usage(prog)
+ char *prog;
+{
+ fprintf(stderr, "Usage: %s [options] dest [flags]\n\
+\toptions:\n\
+\t\t-d\tdebug mode\n\
+\t\t-i 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\
+\t\t-v\tverbose mode\n\
+\t\t-w <window>\tSet the TCP window size\n\
+", prog);
+ fprintf(stderr, "Usage: %s [-dv] -L <filename>\n\
+\toptions:\n\
+\t\t-d\tdebug mode\n\
+\t\t-L filename\tUse IP language for sending packets\n\
+\t\t-v\tverbose mode\n\
+", prog);
+ exit(1);
+}
+
+
+static 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;
+{
+ int wfd;
+
+ wfd = initdevice(dev, 5);
+ if (wfd == -1)
+ return -1;
+ return send_packet(wfd, mtu, ip, gwip);
+}
+
+void
+udpcksum(ip_t *ip, struct udphdr *udp, int len)
+{
+ union pseudoh {
+ struct hdr {
+ u_short len;
+ u_char ttl;
+ u_char proto;
+ u_32_t src;
+ u_32_t dst;
+ } h;
+ u_short w[6];
+ } ph;
+ u_32_t temp32;
+ u_short *opts;
+
+ ph.h.len = htons(len);
+ ph.h.ttl = 0;
+ ph.h.proto = IPPROTO_UDP;
+ ph.h.src = ip->ip_src.s_addr;
+ ph.h.dst = ip->ip_dst.s_addr;
+ temp32 = 0;
+ opts = &ph.w[0];
+ temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5];
+ temp32 = (temp32 >> 16) + (temp32 & 65535);
+ temp32 += (temp32 >> 16);
+ udp->uh_sum = temp32 & 65535;
+ udp->uh_sum = chksum((u_short *)udp, len);
+ if (udp->uh_sum == 0)
+ udp->uh_sum = 0xffff;
+}
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *langfile = NULL;
+ struct in_addr gwip;
+ tcphdr_t *tcp;
+ udphdr_t *udp;
+ ip_t *ip;
+ char *name = argv[0], host[MAXHOSTNAMELEN + 1];
+ char *gateway = NULL, *dev = NULL;
+ char *src = NULL, *dst, *s;
+ int mtu = 1500, olen = 0, c, nonl = 0;
+
+ /*
+ * 65535 is maximum packet size...you never know...
+ */
+ ip = (ip_t *)calloc(1, 65536);
+ tcp = (tcphdr_t *)(ip + 1);
+ udp = (udphdr_t *)tcp;
+ ip->ip_len = sizeof(*ip);
+ IP_HL_A(ip, sizeof(*ip) >> 2);
+
+ while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) {
+ switch (c)
+ {
+ case 'I' :
+ nonl++;
+ if (ip->ip_p)
+ {
+ fprintf(stderr, "Protocol already set: %d\n",
+ ip->ip_p);
+ break;
+ }
+ do_icmp(ip, optarg);
+ break;
+ case 'L' :
+ if (nonl) {
+ fprintf(stderr,
+ "Incorrect usage of -L option.\n");
+ usage(name);
+ }
+ if (!strcmp(optarg, "-"))
+ langfile = stdin;
+ else if (!(langfile = fopen(optarg, "r"))) {
+ fprintf(stderr, "can't open file %s\n",
+ optarg);
+ exit(1);
+ }
+ iplang(langfile);
+ return 0;
+ case 'P' :
+ {
+ struct protoent *p;
+
+ nonl++;
+ 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' :
+ nonl++;
+ 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' :
+ nonl++;
+ 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' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'f' :
+ nonl++;
+ ip->ip_off = strtol(optarg, NULL, 0);
+ break;
+ case 'g' :
+ nonl++;
+ gateway = optarg;
+ break;
+ case 'i' :
+ nonl++;
+ dev = optarg;
+ break;
+ case 'm' :
+ nonl++;
+ mtu = atoi(optarg);
+ if (mtu < 28)
+ {
+ fprintf(stderr, "mtu must be > 28\n");
+ exit(1);
+ }
+ break;
+ case 'o' :
+ nonl++;
+ olen = buildopts(optarg, options, (IP_HL(ip) - 5) << 2);
+ break;
+ case 's' :
+ nonl++;
+ src = optarg;
+ break;
+ case 't' :
+ nonl++;
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ tcp->th_dport = htons(atoi(optarg));
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ case 'w' :
+ nonl++;
+ 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 < 1)
+ 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 (olen)
+ {
+ int hlen;
+ char *p;
+
+ printf("Options: %d\n", olen);
+ hlen = sizeof(*ip) + olen;
+ IP_HL_A(ip, hlen >> 2);
+ ip->ip_len += olen;
+ p = (char *)malloc(65536);
+ if (p == NULL)
+ {
+ fprintf(stderr, "malloc failed\n");
+ exit(2);
+ }
+
+ bcopy(ip, p, sizeof(*ip));
+ bcopy(options, p + sizeof(*ip), olen);
+ bcopy(ip + 1, p + hlen, ip->ip_len - hlen);
+ ip = (ip_t *)p;
+
+ if (ip->ip_p == IPPROTO_TCP) {
+ tcp = (tcphdr_t *)(p + hlen);
+ } else if (ip->ip_p == IPPROTO_UDP) {
+ udp = (udphdr_t *)(p + hlen);
+ }
+ }
+
+ if (ip->ip_p == IPPROTO_TCP)
+ for (s = argv[optind]; s && (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 (ip->ip_p == IPPROTO_UDP) {
+ udp->uh_sum = 0;
+ udpcksum(ip, udp, ip->ip_len - (IP_HL(ip) << 2));
+ }
+#ifdef DOSOCKET
+ if (ip->ip_p == IPPROTO_TCP && tcp->th_dport)
+ return do_socket(dev, mtu, ip, gwip);
+#endif
+ return send_packets(dev, mtu, ip, gwip);
+}
diff --git a/contrib/ipfilter/ipsend/ipsend.h b/contrib/ipfilter/ipsend/ipsend.h
new file mode 100644
index 0000000..75a0496
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipsend.h
@@ -0,0 +1,73 @@
+/* $FreeBSD$ */
+
+/*
+ * ipsend.h (C) 1997-1998 Darren Reed
+ *
+ * This was written to test what size TCP fragments would get through
+ * various TCP/IP packet filters, as used in IP firewalls. In certain
+ * conditions, enough of the TCP header is missing for unpredictable
+ * results unless the filter is aware that this can happen.
+ *
+ * The author provides this program as-is, with no gaurantee for its
+ * suitability for any specific purpose. The author takes no responsibility
+ * for the misuse/abuse of this program and provides it for the sole purpose
+ * of testing packet filter policies. This file maybe distributed freely
+ * providing it is not modified and that this notice remains in tact.
+ *
+ */
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+#include <net/if.h>
+
+#include "ipf.h"
+#ifdef linux
+#include <linux/sockios.h>
+#endif
+/* XXX: The following is needed by tcpip.h */
+#include <netinet/ip_var.h>
+#include "netinet/tcpip.h"
+#include "ipt.h"
+
+extern int resolve __P((char *, char *));
+extern int arp __P((char *, char *));
+extern u_short chksum __P((u_short *, int));
+extern int send_ether __P((int, char *, int, struct in_addr));
+extern int send_ip __P((int, int, ip_t *, struct in_addr, int));
+extern int send_tcp __P((int, int, ip_t *, struct in_addr));
+extern int send_udp __P((int, int, ip_t *, struct in_addr));
+extern int send_icmp __P((int, int, ip_t *, struct in_addr));
+extern int send_packet __P((int, int, ip_t *, struct in_addr));
+extern int send_packets __P((char *, int, ip_t *, struct in_addr));
+extern u_short ipseclevel __P((char *));
+extern u_32_t buildopts __P((char *, char *, int));
+extern int addipopt __P((char *, struct ipopt_names *, int, char *));
+extern int initdevice __P((char *, int));
+extern int sendip __P((int, char *, int));
+#ifdef linux
+extern struct sock *find_tcp __P((int, struct tcpiphdr *));
+#else
+extern struct tcpcb *find_tcp __P((int, struct tcpiphdr *));
+#endif
+extern int ip_resend __P((char *, int, struct ipread *, struct in_addr, char *));
+
+extern void ip_test1 __P((char *, int, ip_t *, struct in_addr, int));
+extern void ip_test2 __P((char *, int, ip_t *, struct in_addr, int));
+extern void ip_test3 __P((char *, int, ip_t *, struct in_addr, int));
+extern void ip_test4 __P((char *, int, ip_t *, struct in_addr, int));
+extern void ip_test5 __P((char *, int, ip_t *, struct in_addr, int));
+extern void ip_test6 __P((char *, int, ip_t *, struct in_addr, int));
+extern void ip_test7 __P((char *, int, ip_t *, struct in_addr, int));
+extern int do_socket __P((char *, int, struct tcpiphdr *, struct in_addr));
+extern int kmemcpy __P((char *, void *, int));
+
+#define KMCPY(a,b,c) kmemcpy((char *)(a), (void *)(b), (int)(c))
+
+#ifndef OPT_RAW
+#define OPT_RAW 0x80000
+#endif
diff --git a/contrib/ipfilter/ipsend/ipsopt.c b/contrib/ipfilter/ipsend/ipsopt.c
new file mode 100644
index 0000000..a2cc4d0
--- /dev/null
+++ b/contrib/ipfilter/ipsend/ipsopt.c
@@ -0,0 +1,200 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifndef linux
+#include <netinet/ip_var.h>
+#endif
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include "ipsend.h"
+
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+
+struct ipopt_names ionames[] = {
+ { IPOPT_EOL, 0x01, 1, "eol" },
+ { IPOPT_NOP, 0x02, 1, "nop" },
+ { IPOPT_RR, 0x04, 3, "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 ipseclevel(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;
+}
+
+
+int addipopt(op, io, len, class)
+ char *op;
+ struct ipopt_names *io;
+ int len;
+ char *class;
+{
+ struct in_addr ipadr;
+ int olen = len, srr = 0;
+ u_short val;
+ u_char lvl;
+ char *s = op, *t;
+
+ 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) {
+ /*
+ * Allow option to specify RR buffer length in bytes.
+ */
+ if (io->on_value == IPOPT_RR) {
+ val = (class && *class) ? atoi(class) : 4;
+ *op++ = val + io->on_siz;
+ len += val;
+ } else
+ *op++ = io->on_siz;
+ if (io->on_value == IPOPT_TS)
+ *op++ = IPOPT_MINOFF + 1;
+ else
+ *op++ = IPOPT_MINOFF;
+
+ while (class && *class) {
+ t = NULL;
+ switch (io->on_value)
+ {
+ case IPOPT_SECURITY :
+ lvl = ipseclevel(class);
+ *(op - 1) = lvl;
+ break;
+ case IPOPT_LSRR :
+ case IPOPT_SSRR :
+ if ((t = strchr(class, ',')))
+ *t = '\0';
+ ipadr.s_addr = inet_addr(class);
+ srr++;
+ bcopy((char *)&ipadr, op, sizeof(ipadr));
+ op += sizeof(ipadr);
+ break;
+ case IPOPT_SATID :
+ val = atoi(class);
+ bcopy((char *)&val, op, 2);
+ break;
+ }
+
+ if (t)
+ *t++ = ',';
+ class = t;
+ }
+ if (srr)
+ s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr;
+ if (io->on_value == IPOPT_RR)
+ op += val;
+ else
+ op += io->on_siz - 3;
+ }
+ return len - olen;
+}
+
+
+u_32_t buildopts(cp, op, len)
+ char *cp, *op;
+ int len;
+{
+ struct ipopt_names *io;
+ u_32_t msk = 0;
+ char *s, *t;
+ int inc, lastop = -1;
+
+ 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;
+ lastop = io->on_value;
+ if ((inc = addipopt(op, io, len, t))) {
+ op += inc;
+ len += inc;
+ }
+ msk |= io->on_bit;
+ break;
+ }
+ if (!io->on_name) {
+ fprintf(stderr, "unknown IP option name %s\n", s);
+ return 0;
+ }
+ }
+
+ if (len & 3) {
+ while (len & 3) {
+ *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP;
+ len++;
+ }
+ } else {
+ if (lastop != IPOPT_EOL) {
+ if (lastop == IPOPT_NOP)
+ *(op - 1) = IPOPT_EOL;
+ else {
+ *op++ = IPOPT_NOP;
+ *op++ = IPOPT_NOP;
+ *op++ = IPOPT_NOP;
+ *op = IPOPT_EOL;
+ len += 4;
+ }
+ }
+ }
+ return len;
+}
diff --git a/contrib/ipfilter/ipsend/iptest.1 b/contrib/ipfilter/ipsend/iptest.1
new file mode 100644
index 0000000..8f25f4a
--- /dev/null
+++ b/contrib/ipfilter/ipsend/iptest.1
@@ -0,0 +1,103 @@
+.\" $FreeBSD$
+.\"
+.TH IPTEST 1
+.SH NAME
+iptest \- automatically generate a packets to test IP functionality
+.SH SYNOPSIS
+.B iptest
+[
+.B \-1234567
+] [
+.B \-d
+<device>
+] [
+.B \-g
+<gateway>
+] [
+.B \-m
+<\fIMTU\fP>
+] [
+.B \-p
+<\fIpointtest\fP>
+] [
+.B \-s
+<\fIsource\fP>
+] <destination>
+.SH DESCRIPTION
+.PP
+\fBiptest\fP ...
+.SH OPTIONS
+.TP
+.B \-1
+Run IP test group #1. This group of tests generates packets with the IP
+header fields set to invalid values given other packet characteristics.
+The point tests are: 1 (ip_hl < ip_len), 2 (ip_hl > ip_len),
+3 (ip_v < 4), 4 (ip_v > 4), 5 (ip_len < packetsize, long packets),
+6 (ip_len > packet size, short packets), 7 (Zero length fragments),
+8 (packet > 64k after reassembly), 9 (IP offset with MSB set), 10 (ttl
+variations).
+.TP
+.B \-2
+Run IP test group #2. This group of tests generates packets with the IP
+options constructed with invalid values given other packet characteristics.
+The point tests are: 1 (option length > packet length), 2 (option length = 0).
+.TP
+.B \-3
+Run IP test group #3. This group of tests generates packets with the ICMP
+header fields set to non-standard values. The point tests are: 1 (ICMP types
+0-31 & 255), 2 (type 3 & code 0 - 31), 3 (type 4 & code 0, 127, 128, 255),
+4 (type 5 & code 0, 127, 128, 255), 5 (types 8-10,13-18 with codes 0, 127,
+128 and 255), 6 (type 12 & code 0, 127, 128, 129, 255) and 7 (type 3 & codes
+9-10, 13-14 and 17-18 - shortened packets).
+.TP
+.B \-4
+Run IP test group #4. This group of tests generates packets with the UDP
+header fields set to non-standard values. The point tests are: 1 (UDP length
+> packet size), 2 (UDP length < packetsize), 3 (sport = 0, 1, 32767, 32768,
+65535), 4 (dport = 0, 1, 32767, 32768, 65535) and 5 (sizeof(struct ip) <= MTU
+<= sizeof(struct udphdr) + sizeof(struct ip)).
+.TP
+.B \-5
+Run IP test group #5. This group of tests generates packets with the TCP
+header fields set to non-standard values. The point tests are: 1 (TCP flags
+variations, all combinations), 2 (seq = 0, 0x7fffffff, 0x8000000, 0xa0000000,
+0xffffffff), 3 (ack = 0, 0x7fffffff, 0x8000000, 0xa0000000, 0xffffffff),
+4 (SYN packet with window of 0, 32768, 65535), 5 (set urgent pointer to 1,
+0x7fff, 0x8000, 0xffff), 6 (data offset), 7 (sport = 0, 1, 32767, 32768,
+65535) and 8 (dport = 0, 1, 32767, 32768, 65535).
+.TP
+.B \-6
+Run IP test group #6. This test generates a large number of fragments in
+an attempt to exhaust the network buffers used for holding packets for later
+reassembly. WARNING: this may crash or cause serious performance degradation
+to the target host.
+.TP
+.B \-7
+Run IP test group #7. This test generates 1024 random IP packets with only
+the IP version, checksum, length and IP offset field correct.
+.TP
+.BR \-d \0<interface>
+Set the interface name to be the name supplied.
+.TP
+.BR \-g \0<gateway>
+Specify the hostname of the gateway through which to route packets. This
+is required whenever the destination host isn't directly attached to the
+same network as the host from which you're sending.
+.TP
+.BR \-m \0<MTU>
+Specify the MTU to be used when sending out packets. This option allows you
+to set a fake MTU, allowing the simulation of network interfaces with small
+MTU's without setting them so.
+.TP
+.B \-p <test>
+Run a...
+.DT
+.SH SEE ALSO
+ipsend(1), ipresend(1), bpf(4), ipsend(5), dlpi(7p)
+.SH DIAGNOSTICS
+Only one of the numeric test options may be given when \fIiptest\fP is run.
+.PP
+Needs to be run as root.
+.SH BUGS
+.PP
+If you find any, please send email to me at darrenr@pobox.com
diff --git a/contrib/ipfilter/ipsend/iptest.c b/contrib/ipfilter/ipsend/iptest.c
new file mode 100644
index 0000000..c6cfb1c
--- /dev/null
+++ b/contrib/ipfilter/ipsend/iptest.c
@@ -0,0 +1,218 @@
+/* $FreeBSD$ */
+
+/*
+ * ipsend.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "%W% %G% (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifndef linux
+#include <netinet/ip_var.h>
+#endif
+#ifdef linux
+#include <linux/sockios.h>
+#endif
+#include <stdio.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ipsend.h"
+
+
+extern char *optarg;
+extern int optind;
+
+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
+# ifdef __sgi
+char default_device[] = "ec0";
+# else
+char default_device[] = "lan0";
+# endif
+# endif
+# endif
+# endif
+#endif
+
+static void usage __P((char *));
+int main __P((int, char **));
+
+
+static 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[MAXHOSTNAMELEN + 1];
+ char *gateway = NULL, *dev = NULL;
+ char *src = NULL, *dst;
+ int mtu = 1500, tests = 0, pointtest = 0, c;
+
+ /*
+ * 65535 is maximum packet size...you never know...
+ */
+ ip = (ip_t *)calloc(1, 65536);
+ ti = (struct tcpiphdr *)ip;
+ ip->ip_len = sizeof(*ip);
+ IP_HL_A(ip, sizeof(*ip) >> 2);
+
+ while ((c = getopt(argc, argv, "1234567d:g:m:p:s:")) != -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) || !argv[optind])
+ usage(name);
+ dst = argv[optind++];
+
+ if (!src)
+ {
+ gethostname(host, sizeof(host));
+ host[sizeof(host) - 1] = '\0';
+ 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 :
+ ip_test1(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ case 2 :
+ ip_test2(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ case 3 :
+ ip_test3(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ case 4 :
+ ip_test4(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ case 5 :
+ ip_test5(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ case 6 :
+ ip_test6(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ case 7 :
+ ip_test7(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ default :
+ ip_test1(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ ip_test2(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ ip_test3(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ ip_test4(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ ip_test5(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ ip_test6(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ ip_test7(dev, mtu, (ip_t *)ti, gwip, pointtest);
+ break;
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/iptests.c b/contrib/ipfilter/ipsend/iptests.c
new file mode 100644
index 0000000..0ca02db
--- /dev/null
+++ b/contrib/ipfilter/ipsend/iptests.c
@@ -0,0 +1,1426 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "%W% %G% (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#if defined(__NetBSD__) && defined(__vax__)
+/*
+ * XXX need to declare boolean_t for _KERNEL <sys/files.h>
+ * which ends up including <sys/device.h> for vax. See PR#32907
+ * for further details.
+ */
+typedef int boolean_t;
+#endif
+#include <sys/time.h>
+#if !defined(__osf__)
+# ifdef __NetBSD__
+# include <machine/lock.h>
+# include <machine/mutex.h>
+# endif
+# define _KERNEL
+# define KERNEL
+# if !defined(solaris) && !defined(linux) && !defined(__sgi) && !defined(hpux)
+# include <sys/file.h>
+# else
+# ifdef solaris
+# include <sys/dditypes.h>
+# endif
+# endif
+# undef _KERNEL
+# undef KERNEL
+#endif
+#if !defined(solaris) && !defined(linux) && !defined(__sgi)
+# include <nlist.h>
+# include <sys/user.h>
+# include <sys/proc.h>
+#endif
+#if !defined(ultrix) && !defined(hpux) && !defined(linux) && \
+ !defined(__sgi) && !defined(__osf__) && !defined(_AIX51)
+# include <kvm.h>
+#endif
+#ifndef ultrix
+# include <sys/socket.h>
+#endif
+#if defined(solaris)
+# include <sys/stream.h>
+#else
+# include <sys/socketvar.h>
+#endif
+#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>
+#ifdef __hpux
+# define _NET_ROUTE_INCLUDED
+#endif
+#include <net/if.h>
+#if defined(linux) && (LINUX >= 0200)
+# include <asm/atomic.h>
+#endif
+#if !defined(linux)
+# if defined(__FreeBSD__)
+# include "radix_ipf.h"
+# endif
+# if !defined(solaris)
+# include <net/route.h>
+# endif
+#else
+# define __KERNEL__ /* because there's a macro not wrapped by this */
+# include <net/route.h> /* in this file :-/ */
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+#if defined(__SVR4) || defined(__svr4__) || defined(__sgi)
+# include <sys/sysmacros.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __hpux
+# undef _NET_ROUTE_INCLUDED
+#endif
+#if !defined(linux)
+# include <netinet/ip_var.h>
+# if !defined(__hpux) && !defined(solaris)
+# include <netinet/in_pcb.h>
+# endif
+#endif
+#include "ipsend.h"
+#if !defined(linux) && !defined(__hpux)
+# include <netinet/tcp_timer.h>
+# include <netinet/tcp_var.h>
+#endif
+#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000000)
+# define USE_NANOSLEEP
+#endif
+
+
+#ifdef USE_NANOSLEEP
+# define PAUSE() ts.tv_sec = 0; ts.tv_nsec = 10000000; \
+ (void) nanosleep(&ts, NULL)
+#else
+# define PAUSE() tv.tv_sec = 0; tv.tv_usec = 10000; \
+ (void) select(0, NULL, NULL, NULL, &tv)
+#endif
+
+
+void ip_test1(dev, mtu, ip, gwip, ptest)
+ char *dev;
+ int mtu;
+ ip_t *ip;
+ struct in_addr gwip;
+ int ptest;
+{
+#ifdef USE_NANOSLEEP
+ struct timespec ts;
+#else
+ struct timeval tv;
+#endif
+ udphdr_t *u;
+ int nfd, i = 0, len, id = getpid();
+
+ IP_HL_A(ip, sizeof(*ip) >> 2);
+ IP_V_A(ip, IPVERSION);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_ttl = 60;
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_sum = 0;
+ u = (udphdr_t *)(ip + 1);
+ u->uh_sport = htons(1);
+ u->uh_dport = htons(9);
+ u->uh_sum = 0;
+ u->uh_ulen = htons(sizeof(*u) + 4);
+ ip->ip_len = sizeof(*ip) + ntohs(u->uh_ulen);
+ len = ip->ip_len;
+
+ nfd = initdevice(dev, 1);
+ if (nfd == -1)
+ return;
+
+ 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) + ntohs(u->uh_ulen)) >> 2); i++) {
+ IP_HL_A(ip, 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 + ntohs(u->uh_ulen)) >> 2); i++) {
+ IP_HL_A(ip, 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_HL_A(ip, sizeof(*ip) >> 2);
+ for (i = 0; i < 4; i++) {
+ IP_V_A(ip, 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_V_A(ip, 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_V_A(ip, IPVERSION);
+ i = ip->ip_len + 1;
+ printf("1.5.0 ip_len < packet size (size++, long packets)\n");
+ for (; i < (ip->ip_len * 2); i++) {
+ ip->ip_id = htons(id++);
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2);
+ (void) send_ether(nfd, (char *)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 = i;
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2);
+ (void) send_ether(nfd, (char *)ip, len, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ 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 = i;
+ ip->ip_sum = 0;
+ ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2);
+ (void) send_ether(nfd, (char *)ip, len, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ ip->ip_len = 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((u_short *)ip, IP_HL(ip) << 2);
+ (void) send_ether(nfd, (char *)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 = htons(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 = htons(IP_MF | (i >> 3));
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ ip->ip_len = 896 + 20;
+ ip->ip_off = htons(i >> 3);
+ (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 = htons(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 = htons(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 = htons(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 = htons(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 = htons(IP_MF | (i >> 3));
+ (void) send_ip(nfd, mtu, ip, gwip, 1);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ ip->ip_len = 896 + 20;
+ ip->ip_off = htons(i >> 3);
+ (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 = htons(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;
+{
+#ifdef USE_NANOSLEEP
+ struct timespec ts;
+#else
+ struct timeval tv;
+#endif
+ int nfd;
+ u_char *s;
+
+
+ nfd = initdevice(dev, 1);
+ if (nfd == -1)
+ return;
+
+ IP_HL_A(ip, 6);
+ ip->ip_len = IP_HL(ip) << 2;
+ s = (u_char *)(ip + 1);
+ 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_HL_A(ip, 7);
+ ip->ip_len = IP_HL(ip) << 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 };
+#ifdef USE_NANOSLEEP
+ struct timespec ts;
+#else
+ struct timeval tv;
+#endif
+ struct icmp *icp;
+ int nfd, i;
+
+ IP_HL_A(ip, sizeof(*ip) >> 2);
+ IP_V_A(ip, IPVERSION);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_ttl = 60;
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_sum = 0;
+ ip->ip_len = sizeof(*ip) + sizeof(*icp);
+ icp = (struct icmp *)((char *)ip + (IP_HL(ip) << 2));
+
+ nfd = initdevice(dev, 1);
+ if (nfd == -1)
+ return;
+
+ 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;
+{
+#ifdef USE_NANOSLEEP
+ struct timespec ts;
+#else
+ struct timeval tv;
+#endif
+ udphdr_t *u;
+ int nfd, i;
+
+
+ IP_HL_A(ip, sizeof(*ip) >> 2);
+ IP_V_A(ip, IPVERSION);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_ttl = 60;
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_sum = 0;
+ u = (udphdr_t *)((char *)ip + (IP_HL(ip) << 2));
+ u->uh_sport = htons(1);
+ u->uh_dport = htons(1);
+ u->uh_ulen = htons(sizeof(*u) + 4);
+
+ nfd = initdevice(dev, 1);
+ if (nfd == -1)
+ return;
+
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Test 1. ulen > packet
+ */
+ u->uh_ulen = htons(sizeof(*u) + 4);
+ ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen);
+ printf("4.1 UDP uh_ulen > packet size - short packets\n");
+ for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) {
+ u->uh_ulen = htons(i);
+ (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 = htons(sizeof(*u) + 4);
+ ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen);
+ printf("4.2 UDP uh_ulen < packet size - short packets\n");
+ for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) {
+ ip->ip_len = i;
+ (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_HL(ip) << 2) + ntohs(u->uh_ulen);
+ printf("4.3.1 UDP sport = 0\n");
+ u->uh_sport = 0;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("0\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.3.2 UDP sport = 1\n");
+ u->uh_sport = htons(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 = htons(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 = htons(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 = htons(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 = ntohs(sizeof(*u) + 4);
+ u->uh_sport = htons(1);
+ ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen);
+ printf("4.4.1 UDP dport = 0\n");
+ u->uh_dport = 0;
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("0\n");
+ fflush(stdout);
+ PAUSE();
+ printf("4.4.2 UDP dport = 1\n");
+ u->uh_dport = htons(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 = htons(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 = htons(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 = htons(65535);
+ (void) send_udp(nfd, 1500, ip, gwip);
+ printf("65535\n");
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 5)) {
+ /*
+ * Test 5: sizeof(ip_t) <= MTU <= sizeof(udphdr_t) +
+ * sizeof(ip_t)
+ */
+ printf("4.5 UDP 20 <= MTU <= 32\n");
+ for (i = sizeof(*ip); i <= ntohs(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;
+{
+#ifdef USE_NANOSLEEP
+ struct timespec ts;
+#else
+ struct timeval tv;
+#endif
+ tcphdr_t *t;
+ int nfd, i;
+
+ t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
+#if !defined(linux) && !defined(__osf__)
+ t->th_x2 = 0;
+#endif
+ TCP_OFF_A(t, 0);
+ t->th_sport = htons(1);
+ t->th_dport = htons(1);
+ t->th_win = htons(4096);
+ t->th_urp = 0;
+ t->th_sum = 0;
+ t->th_seq = htonl(1);
+ t->th_ack = 0;
+ ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t);
+
+ nfd = initdevice(dev, 1);
+ if (nfd == -1)
+ return;
+
+ if (!ptest || (ptest == 1)) {
+ /*
+ * Test 1: flags variations, 0 - 3f
+ */
+ TCP_OFF_A(t, sizeof(*t) >> 2);
+ printf("5.1 Test TCP flag combinations\n");
+ for (i = 0; i <= (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN);
+ i++) {
+ 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 = htonl(0);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.2 TCP seq = 1\n");
+ t->th_seq = htonl(1);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.3 TCP seq = 0x7fffffff\n");
+ t->th_seq = htonl(0x7fffffff);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.4 TCP seq = 0x80000000\n");
+ t->th_seq = htonl(0x80000000);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.5 TCP seq = 0xc0000000\n");
+ t->th_seq = htonl(0xc0000000);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.2.6 TCP seq = 0xffffffff\n");
+ t->th_seq = htonl(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 = htonl(1);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.3 TCP ack = 0x7fffffff\n");
+ t->th_ack = htonl(0x7fffffff);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.4 TCP ack = 0x80000000\n");
+ t->th_ack = htonl(0x80000000);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.5 TCP ack = 0xc0000000\n");
+ t->th_ack = htonl(0xc0000000);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.3.6 TCP ack = 0xffffffff\n");
+ t->th_ack = htonl(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 = htonl(0);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.4.2 TCP win = 32768\n");
+ t->th_seq = htonl(0x7fff);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.4.3 TCP win = 65535\n");
+ t->th_win = htons(0xffff);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+
+#if !defined(linux) && !defined(__SVR4) && !defined(__svr4__) && \
+ !defined(__sgi) && !defined(__hpux) && !defined(__osf__)
+ {
+ struct tcpcb *tcbp, tcb;
+ struct tcpiphdr ti;
+ struct sockaddr_in sin;
+ int fd;
+ socklen_t slen;
+
+ bzero((char *)&sin, sizeof(sin));
+
+ for (i = 1; i < 63; i++) {
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_addr.s_addr = ip->ip_dst.s_addr;
+ sin.sin_port = htons(i);
+ sin.sin_family = AF_INET;
+ if (!connect(fd, (struct sockaddr *)&sin, sizeof(sin)))
+ break;
+ close(fd);
+ }
+
+ 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));
+ t->th_dport = htons(i);
+ slen = sizeof(sin);
+ if (!getsockname(fd, (struct sockaddr *)&sin, &slen))
+ t->th_sport = sin.sin_port;
+ if (!(tcbp = find_tcp(fd, &ti))) {
+ printf("Can't find PCB\n");
+ goto skip_five_and_six;
+ }
+ KMCPY(&tcb, tcbp, sizeof(tcb));
+ ti.ti_win = tcb.rcv_adv;
+ ti.ti_seq = htonl(tcb.snd_nxt - 1);
+ ti.ti_ack = tcb.rcv_nxt;
+
+ if (!ptest || (ptest == 5)) {
+ /*
+ * Test 5: urp
+ */
+ t->th_flags = TH_ACK|TH_URG;
+ printf("5.5.1 TCP Urgent pointer, sport %hu dport %hu\n",
+ ntohs(t->th_sport), ntohs(t->th_dport));
+ t->th_urp = htons(1);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+
+ t->th_seq = htonl(tcb.snd_nxt);
+ ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t) + 1;
+ t->th_urp = htons(0x7fff);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+ t->th_urp = htons(0x8000);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+ t->th_urp = htons(0xffff);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ PAUSE();
+ t->th_urp = 0;
+ t->th_flags &= ~TH_URG;
+ ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t);
+ }
+
+ if (!ptest || (ptest == 6)) {
+ /*
+ * Test 6: data offset, off = 0, off is inside, off is outside
+ */
+ t->th_flags = TH_ACK;
+ printf("5.6.1 TCP off = 1-15, len = 40\n");
+ for (i = 1; i < 16; i++) {
+ TCP_OFF_A(t, ntohs(i));
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ printf("%d\r", i);
+ fflush(stdout);
+ PAUSE();
+ }
+ putchar('\n');
+ ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t);
+ }
+
+ (void) close(fd);
+ }
+skip_five_and_six:
+#endif
+ t->th_seq = htonl(1);
+ t->th_ack = htonl(1);
+ TCP_OFF_A(t, 0);
+
+ if (!ptest || (ptest == 7)) {
+ 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 = htons(1);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.7.3 TCP sport = 32767\n");
+ t->th_sport = htons(32767);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.7.4 TCP sport = 32768\n");
+ t->th_sport = htons(32768);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.7.5 TCP sport = 65535\n");
+ t->th_sport = htons(65535);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ if (!ptest || (ptest == 8)) {
+ t->th_sport = htons(1);
+ t->th_flags = TH_SYN;
+ /*
+ * 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 = htons(1);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.8.3 TCP dport = 32767\n");
+ t->th_dport = htons(32767);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.8.4 TCP dport = 32768\n");
+ t->th_dport = htons(32768);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+
+ printf("5.8.5 TCP dport = 65535\n");
+ t->th_dport = htons(65535);
+ (void) send_tcp(nfd, mtu, ip, gwip);
+ fflush(stdout);
+ PAUSE();
+ }
+
+ /* LAND attack - self connect, so make src & dst ip/port the same */
+ if (!ptest || (ptest == 9)) {
+ printf("5.9 TCP LAND attack. sport = 25, dport = 25\n");
+ /* chose SMTP port 25 */
+ t->th_sport = htons(25);
+ t->th_dport = htons(25);
+ t->th_flags = TH_SYN;
+ ip->ip_src = ip->ip_dst;
+ (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;
+{
+#ifdef USE_NANOSLEEP
+ struct timespec ts;
+#else
+ struct timeval tv;
+#endif
+ udphdr_t *u;
+ int nfd, i, j, k;
+
+ IP_V_A(ip, IPVERSION);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_ttl = 60;
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_sum = 0;
+ u = (udphdr_t *)(ip + 1);
+ u->uh_sport = htons(1);
+ u->uh_dport = htons(9);
+ u->uh_sum = 0;
+
+ nfd = initdevice(dev, 1);
+ if (nfd == -1)
+ return;
+
+ u->uh_ulen = htons(7168);
+
+ printf("6. Exhaustive mbuf test.\n");
+ printf(" Send 7k packet in 768 & 128 byte fragments, 128 times.\n");
+ printf(" Total of around 8,900 packets\n");
+ for (i = 0; i < 128; i++) {
+ /*
+ * First send the entire packet in 768 byte chunks.
+ */
+ ip->ip_len = sizeof(*ip) + 768 + sizeof(*u);
+ IP_HL_A(ip, sizeof(*ip) >> 2);
+ ip->ip_off = htons(IP_MF);
+ (void) send_ip(nfd, 1500, ip, gwip, 1);
+ printf("%d %d\r", i, 0);
+ fflush(stdout);
+ PAUSE();
+ /*
+ * And again using 128 byte chunks.
+ */
+ ip->ip_len = sizeof(*ip) + 128 + sizeof(*u);
+ ip->ip_off = htons(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 = htons(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 = htons(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;
+#ifdef USE_NANOSLEEP
+ struct timespec ts;
+#else
+ struct timeval tv;
+#endif
+ int nfd, i, j;
+ u_char *s;
+
+ nfd = initdevice(dev, 1);
+ if (nfd == -1)
+ return;
+
+ 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;
+ IP_V_A(pip, 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;
+ IP_V_A(pip, IPVERSION);
+ pip->ip_off &= htons(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..5b79f73
--- /dev/null
+++ b/contrib/ipfilter/ipsend/larp.c
@@ -0,0 +1,93 @@
+/* $FreeBSD$ */
+
+/*
+ * larp.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)larp.c 1.1 8/19/95 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include "ip_compat.h"
+#include "iplang/iplang.h"
+
+/*
+ * 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();
+
+#ifdef IP_SEND
+ if (arp_getipv4(ip, ether) == 0)
+ return 0;
+#endif
+ 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..e738f3b
--- /dev/null
+++ b/contrib/ipfilter/ipsend/linux.h
@@ -0,0 +1,19 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 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..5cf2bf7
--- /dev/null
+++ b/contrib/ipfilter/ipsend/lsock.c
@@ -0,0 +1,259 @@
+/* $FreeBSD$ */
+
+/*
+ * lsock.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)lsock.c 1.2 1/11/96 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#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 < 0200
+#include <net/inet/sock.h>
+#endif
+#include "ipsend.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 (KMCPY(&nproc, 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 (KMCPY(&v, 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 (KMCPY(pp, 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 (KMCPY((proc + n), 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 (KMCPY(o, 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 (KMCPY(f, 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 (KMCPY(i, 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)
+ char *dev;
+ int mtu;
+ struct tcpiphdr *ti;
+ struct in_addr gwip;
+{
+ 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, 0);
+ if (nfd == -1)
+ return -1;
+
+ 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;
+ }
+ KMCPY(&sk, s, sizeof(sk));
+ ti->ti_win = sk.window;
+ ti->ti_seq = sk.sent_seq - 1;
+ ti->ti_ack = sk.rcv_ack_seq;
+ ti->ti_flags = TH_SYN;
+
+ if (send_tcp(nfd, mtu, (ip_t *)ti, gwip) == -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..45159bf
--- /dev/null
+++ b/contrib/ipfilter/ipsend/resend.c
@@ -0,0 +1,143 @@
+/* $FreeBSD$ */
+
+/*
+ * resend.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.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>
+#ifndef linux
+# include <netinet/ip_var.h>
+# include <netinet/if_ether.h>
+#endif
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "ipsend.h"
+
+extern int opts;
+
+void dumppacket __P((ip_t *));
+
+
+void dumppacket(ip)
+ ip_t *ip;
+{
+ tcphdr_t *t;
+ int i, j;
+
+ t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 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, 5), len, i;
+ mb_t mb;
+
+ if (wfd == -1)
+ return -1;
+
+ if (datain)
+ fd = (*r->r_open)(datain);
+ else
+ fd = (*r->r_open)("-");
+
+ if (fd < 0)
+ exit(-1);
+
+ ip = (struct ip *)mb.mb_buf;
+ eh = (ether_header_t *)malloc(sizeof(*eh));
+ if(!eh)
+ {
+ perror("malloc failed");
+ return -2;
+ }
+
+ bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost));
+ if (gwip.s_addr && (arp((char *)&gwip, dhost) == -1))
+ {
+ perror("arp");
+ free(eh);
+ return -2;
+ }
+
+ while ((i = (*r->r_readip)(&mb, NULL, NULL)) > 0)
+ {
+ if (!(opts & OPT_RAW)) {
+ 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 *)A_A eh->ether_dhost) == -1) {
+ perror("arp");
+ continue;
+ }
+ } else
+ bcopy(dhost, (char *)A_A eh->ether_dhost,
+ sizeof(dhost));
+ if (!ip->ip_sum)
+ ip->ip_sum = chksum((u_short *)ip,
+ IP_HL(ip) << 2);
+ bcopy(ip, (char *)(eh + 1), len);
+ len += sizeof(*eh);
+ dumppacket(ip);
+ } else {
+ eh = (ether_header_t *)mb.mb_buf;
+ len = i;
+ }
+
+ if (sendip(wfd, (char *)eh, len) == -1)
+ {
+ perror("send_packet");
+ break;
+ }
+ }
+ (*r->r_close)();
+ free(eh);
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/sbpf.c b/contrib/ipfilter/ipsend/sbpf.c
new file mode 100644
index 0000000..fcb66bc
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sbpf.c
@@ -0,0 +1,153 @@
+/* $FreeBSD$ */
+/*
+ * (C)opyright 1995-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mbuf.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if BSD < 199103
+#include <sys/fcntlcom.h>
+#endif
+#if (__FreeBSD_version >= 300000)
+# include <sys/dirent.h>
+#else
+# include <sys/dir.h>
+#endif
+#include <net/bpf.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef __NetBSD__
+# include <paths.h>
+#endif
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "ipsend.h"
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)sbpf.c 1.3 8/25/95 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+/*
+ * the code herein is dervied from libpcap.
+ */
+static u_char *buf = NULL;
+static int bufsize = 0, timeout = 1;
+
+
+int initdevice(device, tout)
+ char *device;
+ int tout;
+{
+ struct bpf_version bv;
+ struct timeval to;
+ struct ifreq ifr;
+#ifdef _PATH_BPF
+ char *bpfname = _PATH_BPF;
+ int fd;
+
+ if ((fd = open(bpfname, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "no bpf devices available as /dev/bpfxx\n");
+ return -1;
+ }
+#else
+ char bpfname[16];
+ int fd = 0, 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;
+ }
+#endif
+
+ 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..1aee2e4
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sdlpi.c
@@ -0,0 +1,173 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1992-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#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>
+
+#ifdef sun
+# include <sys/pfmod.h>
+# include <sys/bufmod.h>
+#endif
+#ifdef __osf__
+# include <sys/dlpihdr.h>
+#else
+# include <sys/dlpi.h>
+#endif
+#ifdef __hpux
+# include <sys/dlpi_ext.h>
+#endif
+
+#include <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 "ipsend.h"
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)sdlpi.c 1.3 10/30/95 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#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, tout)
+ char *device;
+ int tout;
+{
+ char devname[16], *s, buf[256];
+ int i, fd;
+
+ (void) strcpy(devname, "/dev/");
+ (void) strncat(devname, device, sizeof(devname) - strlen(devname));
+
+ 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)
+ {
+ fprintf(stderr, "dlattachreq: DLPI error\n");
+ exit(-1);
+ }
+ else if (dlokack(fd, buf) == -1)
+ {
+ fprintf(stderr, "dlokack(attach): DLPI error\n");
+ exit(-1);
+ }
+#ifdef DL_HP_RAWDLS
+ if (dlpromisconreq(fd, DL_PROMISC_SAP) < 0)
+ {
+ fprintf(stderr, "dlpromisconreq: DL_PROMISC_PHYS error\n");
+ exit(-1);
+ }
+ else if (dlokack(fd, buf) < 0)
+ {
+ fprintf(stderr, "dlokack(promisc): DLPI error\n");
+ exit(-1);
+ }
+ /* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */
+
+ dlbindreq(fd, 22, 1, DL_HP_RAWDLS, 0, 0);
+#else
+ dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0);
+#endif
+ dlbindack(fd, buf);
+ /*
+ * write full headers
+ */
+#ifdef DLIOCRAW /* we require RAW DLPI mode, which is a Sun extension */
+ if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1)
+ {
+ fprintf(stderr, "DLIOCRAW error\n");
+ exit(-1);
+ }
+#endif
+ 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, *cp = NULL;
+ int pri = 0;
+#ifdef DL_HP_RAWDLS
+ struct strbuf cbuf;
+ dl_hp_rawdata_req_t raw;
+
+ cp = &cbuf;
+ raw.dl_primitive = DL_HP_RAWDATA_REQ;
+ cp->len = sizeof(raw);
+ cp->buf = (char *)&raw;
+ cp->maxlen = cp->len;
+ pri = MSG_HIPRI;
+#endif
+ /*
+ * construct NIT STREAMS messages, first control then data.
+ */
+ dp->buf = pkt;
+ dp->len = len;
+ dp->maxlen = dp->len;
+
+ if (putmsg(fd, cp, dp, pri) == -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/sirix.c b/contrib/ipfilter/ipsend/sirix.c
new file mode 100644
index 0000000..3b565b1
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sirix.c
@@ -0,0 +1,93 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1992-1998 Darren Reed.
+ * (C)opyright 1997 Marc Boucher.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/raw.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 "ipsend.h"
+#include <netinet/udp_var.h>
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sirix[] = "@(#)sirix.c 1.0 10/9/97 (C)1997 Marc Boucher";
+#endif
+
+
+int initdevice(char *device, int tout)
+{
+ int fd;
+ struct sockaddr_raw sr;
+
+ if ((fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN)) < 0)
+ {
+ perror("socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN)");
+ return -1;
+ }
+
+ memset(&sr, 0, sizeof(sr));
+ sr.sr_family = AF_RAW;
+ sr.sr_port = ETHERTYPE_IP;
+ strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname));
+ if (bind(fd, &sr, sizeof(sr)) < 0)
+ {
+ perror("bind AF_RAW");
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+
+/*
+ * output an IP packet
+ */
+int sendip(int fd, char *pkt, int len)
+{
+ struct sockaddr_raw sr;
+ int srlen = sizeof(sr);
+ struct ifreq ifr;
+ struct ether_header *eh = (struct ether_header *)pkt;
+
+ if (getsockname(fd, &sr, &srlen) == -1)
+ {
+ perror("getsockname");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, sr.sr_ifname, sizeof ifr.ifr_name);
+
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == -1)
+ {
+ perror("ioctl SIOCGIFADDR");
+ return -1;
+ }
+
+ memcpy(eh->ether_shost, ifr.ifr_addr.sa_data, sizeof(eh->ether_shost));
+
+ if (write(fd, pkt, len) == -1)
+ {
+ perror("send");
+ return -1;
+ }
+
+ return len;
+}
diff --git a/contrib/ipfilter/ipsend/slinux.c b/contrib/ipfilter/ipsend/slinux.c
new file mode 100644
index 0000000..7405d5e
--- /dev/null
+++ b/contrib/ipfilter/ipsend/slinux.c
@@ -0,0 +1,92 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1992-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#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 "ipsend.h"
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)slinux.c 1.2 8/25/95";
+static const char rcsid[] = "@(#)$Id$";
+#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, spare)
+ char *dev;
+ int spare;
+{
+ 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..0d75b4e
--- /dev/null
+++ b/contrib/ipfilter/ipsend/snit.c
@@ -0,0 +1,160 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 1992-1998 Darren Reed. (from tcplog)
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#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 "ipsend.h"
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)snit.c 1.5 1/11/96 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#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, tout)
+ char *device;
+ int 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..6d0f3db
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sock.c
@@ -0,0 +1,457 @@
+/* $FreeBSD$ */
+/*
+ * sock.c (C) 1995-1998 Darren Reed
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)sock.c 1.2 1/11/96 (C)1995 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#if defined(__NetBSD__) && defined(__vax__)
+/*
+ * XXX need to declare boolean_t for _KERNEL <sys/files.h>
+ * which ends up including <sys/device.h> for vax. See PR#32907
+ * for further details.
+ */
+typedef int boolean_t;
+#endif
+#ifndef ultrix
+#include <fcntl.h>
+#endif
+#if (__FreeBSD_version >= 300000)
+# include <sys/dirent.h>
+#else
+# include <sys/dir.h>
+#endif
+#if !defined(__osf__)
+# ifdef __NetBSD__
+# include <machine/lock.h>
+# endif
+# ifdef __FreeBSD__
+# define _WANT_FILE
+# else
+# define _KERNEL
+# define KERNEL
+# endif
+# ifdef ultrix
+# undef LOCORE
+# include <sys/smp_lock.h>
+# endif
+# include <sys/file.h>
+# ifdef __FreeBSD__
+# undef _WANT_FILE
+# else
+# undef _KERNEL
+# undef KERNEL
+# endif
+#endif
+#include <nlist.h>
+#include <sys/user.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/proc.h>
+#if !defined(ultrix) && !defined(hpux) && !defined(__osf__)
+# include <kvm.h>
+#endif
+#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>
+#ifndef __osf__
+# include <net/route.h>
+#endif
+#include <netinet/ip_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <pwd.h>
+#include "ipsend.h"
+
+
+int nproc;
+struct proc *proc;
+
+#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
+
+
+#if BSD < 199103
+static struct proc *getproc __P((void));
+#else
+static struct kinfo_proc *getproc __P((void));
+#endif
+
+
+int kmemcpy(buf, pos, n)
+ char *buf;
+ void *pos;
+ int n;
+{
+ static int kfd = -1;
+ off_t offset = (u_long)pos;
+
+ if (kfd == -1)
+ kfd = open(KMEM, O_RDONLY);
+
+ if (lseek(kfd, offset, SEEK_SET) == -1)
+ {
+ perror("lseek");
+ return -1;
+ }
+ if (read(kfd, buf, n) == -1)
+ {
+ perror("read");
+ return -1;
+ }
+ return n;
+}
+
+struct nlist names[4] = {
+ { "_proc" },
+ { "_nproc" },
+#ifdef ultrix
+ { "_u" },
+#else
+ { NULL },
+#endif
+ { NULL }
+ };
+
+#if BSD < 199103
+static 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 (KMCPY(&nproc, 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 (KMCPY(&p, 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 (KMCPY(proc, 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));
+#ifndef ultrix
+ if (KMCPY(up, p->p_uarea, sizeof(*up)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x) failed\n", p, p->p_uarea);
+ return NULL;
+ }
+#else
+ if (KMCPY(up, names[2].n_value, sizeof(*up)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x) failed\n", p, names[2].n_value);
+ return NULL;
+ }
+#endif
+
+ o = (struct file **)calloc(1, sizeof(*o) * (up->u_lastfile + 1));
+ if (KMCPY(o, up->u_ofile, (up->u_lastfile + 1) * sizeof(*o)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - u_ofile - failed\n",
+ up->u_ofile, o, sizeof(*o));
+ return NULL;
+ }
+ f = (struct file *)calloc(1, sizeof(*f));
+ if (KMCPY(f, o[fd], sizeof(*f)) == -1)
+ {
+ fprintf(stderr, "read(%#x,%#x,%d) - o[fd] - failed\n",
+ up->u_ofile[fd], f, sizeof(*f));
+ return NULL;
+ }
+
+ s = (struct socket *)calloc(1, sizeof(*s));
+ if (KMCPY(s, 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 (KMCPY(i, 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 (KMCPY(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
+static struct kinfo_proc *getproc()
+{
+ static struct kinfo_proc kp;
+ pid_t pid = getpid();
+ int mib[4];
+ size_t n;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = pid;
+
+ n = sizeof(kp);
+ 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 (fd == NULL)
+ return NULL;
+#if defined( __FreeBSD_version) && __FreeBSD_version >= 500013
+ if (KMCPY(fd, p->ki_fd, sizeof(*fd)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx) failed\n",
+ (u_long)p, (u_long)p->ki_fd);
+ free(fd);
+ return NULL;
+ }
+#else
+ if (KMCPY(fd, 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);
+ free(fd);
+ return NULL;
+ }
+#endif
+
+ o = NULL;
+ f = NULL;
+ s = NULL;
+ i = NULL;
+ t = NULL;
+
+ o = (struct file **)calloc(1, sizeof(*o) * (fd->fd_lastfile + 1));
+ if (KMCPY(o, fd->fd_ofiles, (fd->fd_lastfile + 1) * sizeof(*o)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%lu) - u_ofile - failed\n",
+ (u_long)fd->fd_ofiles, (u_long)o, (u_long)sizeof(*o));
+ goto finderror;
+ }
+ f = (struct file *)calloc(1, sizeof(*f));
+ if (KMCPY(f, o[tfd], sizeof(*f)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%lu) - o[tfd] - failed\n",
+ (u_long)o[tfd], (u_long)f, (u_long)sizeof(*f));
+ goto finderror;
+ }
+
+ s = (struct socket *)calloc(1, sizeof(*s));
+ if (KMCPY(s, f->f_data, sizeof(*s)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%lu) - f_data - failed\n",
+ (u_long)f->f_data, (u_long)s, (u_long)sizeof(*s));
+ goto finderror;
+ }
+
+ i = (struct inpcb *)calloc(1, sizeof(*i));
+ if (KMCPY(i, s->so_pcb, sizeof(*i)) == -1)
+ {
+ fprintf(stderr, "kvm_read(%#lx,%#lx,%lu) - so_pcb - failed\n",
+ (u_long)s->so_pcb, (u_long)i, (u_long)sizeof(*i));
+ goto finderror;
+ }
+
+ t = (struct tcpcb *)calloc(1, sizeof(*t));
+ if (KMCPY(t, i->inp_ppcb, sizeof(*t)) == -1)
+ {
+ fprintf(stderr, "read(%#lx,%#lx,%lu) - inp_ppcb - failed\n",
+ (u_long)i->inp_ppcb, (u_long)t, (u_long)sizeof(*t));
+ goto finderror;
+ }
+ return (struct tcpcb *)i->inp_ppcb;
+
+finderror:
+ if (o != NULL)
+ free(o);
+ if (f != NULL)
+ free(f);
+ if (s != NULL)
+ free(s);
+ if (i != NULL)
+ free(i);
+ if (t != NULL)
+ free(t);
+ return NULL;
+}
+#endif /* BSD < 199301 */
+
+int do_socket(dev, mtu, ti, gwip)
+ char *dev;
+ int mtu;
+ struct tcpiphdr *ti;
+ struct in_addr gwip;
+{
+ struct sockaddr_in rsin, lsin;
+ struct tcpcb *t, tcb;
+ int fd, nfd;
+ socklen_t 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, 1);
+ if (nfd == -1)
+ return -1;
+
+ 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;
+ }
+ KMCPY(&tcb, 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, (ip_t *)ti, gwip) == -1)
+ return -1;
+ (void)write(fd, "Hello World\n", 12);
+ sleep(2);
+ close(fd);
+ return 0;
+}
diff --git a/contrib/ipfilter/ipsend/sockraw.c b/contrib/ipfilter/ipsend/sockraw.c
new file mode 100644
index 0000000..c923227
--- /dev/null
+++ b/contrib/ipfilter/ipsend/sockraw.c
@@ -0,0 +1,89 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)opyright 2000 Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * WARNING: Attempting to use this .c file on HP-UX 11.00 will cause the
+ * system to crash.
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "ipsend.h"
+
+#if !defined(lint) && defined(LIBC_SCCS)
+static char sirix[] = "@(#)sirix.c 1.0 10/9/97 (C)1997 Marc Boucher";
+#endif
+
+
+int initdevice(char *device, int tout)
+{
+ struct sockaddr s;
+ struct ifreq ifr;
+ int fd;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
+
+ if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
+ {
+ perror("socket(AF_INET, SOCK_RAW, IPPROTO_RAW)");
+ return -1;
+ }
+
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == -1)
+ {
+ perror("ioctl SIOCGIFADDR");
+ return -1;
+ }
+
+ bzero((char *)&s, sizeof(s));
+ s.sa_family = AF_INET;
+ bcopy(&ifr.ifr_addr, s.sa_data, 4);
+ if (bind(fd, &s, sizeof(s)) == -1)
+ perror("bind");
+ return fd;
+}
+
+
+/*
+ * output an IP packet
+ */
+int sendip(int fd, char *pkt, int len)
+{
+ struct ether_header *eh;
+ struct sockaddr_in sin;
+
+ eh = (struct ether_header *)pkt;
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ pkt += 14;
+ len -= 14;
+ bcopy(pkt + 12, (char *)&sin.sin_addr, 4);
+
+ if (sendto(fd, pkt, len, 0, &sin, sizeof(sin)) == -1)
+ {
+ perror("send");
+ return -1;
+ }
+
+ return len;
+}
diff --git a/contrib/ipfilter/ipt.h b/contrib/ipfilter/ipt.h
new file mode 100644
index 0000000..16d88df
--- /dev/null
+++ b/contrib/ipfilter/ipt.h
@@ -0,0 +1,40 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#ifndef __IPT_H__
+#define __IPT_H__
+
+#ifndef __P
+# define P_DEF
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+#include <fcntl.h>
+
+
+struct ipread {
+ int (*r_open) __P((char *));
+ int (*r_close) __P((void));
+ int (*r_readip) __P((mb_t *, char **, int *));
+ int r_flags;
+};
+
+#define R_DO_CKSUM 0x01
+
+#ifdef P_DEF
+# undef __P
+# undef P_DEF
+#endif
+
+#endif /* __IPT_H__ */
diff --git a/contrib/ipfilter/kmem.h b/contrib/ipfilter/kmem.h
new file mode 100644
index 0000000..ce6ad56
--- /dev/null
+++ b/contrib/ipfilter/kmem.h
@@ -0,0 +1,34 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ * $Id$
+ */
+
+#ifndef __KMEM_H__
+#define __KMEM_H__
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+extern int openkmem __P((char *, char *));
+extern int kmemcpy __P((char *, long, int));
+extern int kstrncpy __P((char *, long, int));
+
+#if defined(__NetBSD__) || defined(__OpenBSD)
+# include <paths.h>
+#endif
+
+#ifdef _PATH_KMEM
+# define KMEM _PATH_KMEM
+#else
+# define KMEM "/dev/kmem"
+#endif
+
+#endif /* __KMEM_H__ */
diff --git a/contrib/ipfilter/l4check/Makefile b/contrib/ipfilter/l4check/Makefile
new file mode 100644
index 0000000..e7366b6
--- /dev/null
+++ b/contrib/ipfilter/l4check/Makefile
@@ -0,0 +1,10 @@
+# For Solaris
+#LIBS=-lsocket -lnsl
+
+all: l4check
+
+l4check: l4check.c
+ $(CC) -g -I.. $(CFLAGS) $(LIBS) l4check.c -o $@
+
+clean:
+ /bin/rm -f l4check
diff --git a/contrib/ipfilter/l4check/http.check b/contrib/ipfilter/l4check/http.check
new file mode 100644
index 0000000..56d93d9
--- /dev/null
+++ b/contrib/ipfilter/l4check/http.check
@@ -0,0 +1,2 @@
+GET /
+
diff --git a/contrib/ipfilter/l4check/http.ok b/contrib/ipfilter/l4check/http.ok
new file mode 100644
index 0000000..2b5d2c1
--- /dev/null
+++ b/contrib/ipfilter/l4check/http.ok
@@ -0,0 +1 @@
+<HTML> \ No newline at end of file
diff --git a/contrib/ipfilter/l4check/l4check.c b/contrib/ipfilter/l4check/l4check.c
new file mode 100644
index 0000000..014446d
--- /dev/null
+++ b/contrib/ipfilter/l4check/l4check.c
@@ -0,0 +1,807 @@
+/* $FreeBSD$ */
+
+/*
+ * (C)Copyright (C) 2012 by Darren Reed.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <net/if.h>
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_nat.h"
+
+#include "ipf.h"
+
+extern char *optarg;
+
+
+typedef struct l4cfg {
+ struct l4cfg *l4_next;
+ struct ipnat l4_nat; /* NAT rule */
+ struct sockaddr_in l4_sin; /* remote socket to connect */
+ time_t l4_last; /* when we last connected */
+ int l4_alive; /* 1 = remote alive */
+ int l4_fd;
+ int l4_rw; /* 0 = reading, 1 = writing */
+ char *l4_rbuf; /* read buffer */
+ int l4_rsize; /* size of buffer */
+ int l4_rlen; /* how much used */
+ char *l4_wptr; /* next byte to write */
+ int l4_wlen; /* length yet to be written */
+} l4cfg_t;
+
+
+l4cfg_t *l4list = NULL;
+char *response = NULL;
+char *probe = NULL;
+l4cfg_t template;
+int frequency = 20;
+int ctimeout = 1;
+int rtimeout = 1;
+size_t plen = 0;
+size_t rlen = 0;
+int natfd = -1;
+int opts = 0;
+
+#if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
+# define strerror(x) sys_errlist[x]
+#endif
+
+
+char *copystr(dst, src)
+ char *dst, *src;
+{
+ register char *s, *t, c;
+ register int esc = 0;
+
+ for (s = src, t = dst; s && t && (c = *s++); )
+ if (esc) {
+ esc = 0;
+ switch (c)
+ {
+ case 'n' :
+ *t++ = '\n';
+ break;
+ case 'r' :
+ *t++ = '\r';
+ break;
+ case 't' :
+ *t++ = '\t';
+ break;
+ }
+ } else if (c != '\\')
+ *t++ = c;
+ else
+ esc = 1;
+ *t = '\0';
+ return dst;
+}
+
+void addnat(l4)
+ l4cfg_t *l4;
+{
+ ipnat_t *ipn = &l4->l4_nat;
+
+ printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]),
+ ipn->in_outmsk, ntohs(ipn->in_pmin));
+ printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext));
+ if (!(opts & OPT_DONOTHING)) {
+ if (ioctl(natfd, SIOCADNAT, &ipn) == -1)
+ perror("ioctl(SIOCADNAT)");
+ }
+}
+
+
+void delnat(l4)
+ l4cfg_t *l4;
+{
+ ipnat_t *ipn = &l4->l4_nat;
+
+ printf("Remove NAT rule for %s/%#x,%u -> ",
+ inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin);
+ printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext);
+ if (!(opts & OPT_DONOTHING)) {
+ if (ioctl(natfd, SIOCRMNAT, &ipn) == -1)
+ perror("ioctl(SIOCRMNAT)");
+ }
+}
+
+
+void connectl4(l4)
+ l4cfg_t *l4;
+{
+ l4->l4_rw = 1;
+ l4->l4_rlen = 0;
+ l4->l4_wlen = plen;
+ if (!l4->l4_wlen) {
+ l4->l4_alive = 1;
+ addnat(l4);
+ } else
+ l4->l4_wptr = probe;
+}
+
+
+void closel4(l4, dead)
+ l4cfg_t *l4;
+ int dead;
+{
+ close(l4->l4_fd);
+ l4->l4_fd = -1;
+ l4->l4_rw = -1;
+ if (dead && l4->l4_alive) {
+ l4->l4_alive = 0;
+ delnat(l4);
+ }
+}
+
+
+void connectfd(l4)
+ l4cfg_t *l4;
+{
+ if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin,
+ sizeof(l4->l4_sin)) == -1) {
+ if (errno == EISCONN) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Connected fd %d\n",
+ l4->l4_fd);
+ connectl4(l4);
+ return;
+ }
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Connect failed fd %d: %s\n",
+ l4->l4_fd, strerror(errno));
+ closel4(l4, 1);
+ return;
+ }
+ l4->l4_rw = 1;
+}
+
+
+void writefd(l4)
+ l4cfg_t *l4;
+{
+ char buf[80], *ptr;
+ int n, i, fd;
+
+ fd = l4->l4_fd;
+
+ if (l4->l4_rw == -2) {
+ connectfd(l4);
+ return;
+ }
+
+ n = l4->l4_wlen;
+
+ i = send(fd, l4->l4_wptr, n, 0);
+ if (i == 0 || i == -1) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Send on fd %d failed: %s\n",
+ fd, strerror(errno));
+ closel4(l4, 1);
+ } else {
+ l4->l4_wptr += i;
+ l4->l4_wlen -= i;
+ if (l4->l4_wlen == 0)
+ l4->l4_rw = 0;
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd);
+ }
+}
+
+
+void readfd(l4)
+ l4cfg_t *l4;
+{
+ char buf[80], *ptr;
+ int n, i, fd;
+
+ fd = l4->l4_fd;
+
+ if (l4->l4_rw == -2) {
+ connectfd(l4);
+ return;
+ }
+
+ if (l4->l4_rsize) {
+ n = l4->l4_rsize - l4->l4_rlen;
+ ptr = l4->l4_rbuf + l4->l4_rlen;
+ } else {
+ n = sizeof(buf) - 1;
+ ptr = buf;
+ }
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Read %d bytes on fd %d to %p\n",
+ n, fd, ptr);
+ i = recv(fd, ptr, n, 0);
+ if (i == 0 || i == -1) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Read error on fd %d: %s\n",
+ fd, (i == 0) ? "EOF" : strerror(errno));
+ closel4(l4, 1);
+ } else {
+ if (ptr == buf)
+ ptr[i] = '\0';
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "%d: Read %d bytes [%*.*s]\n",
+ fd, i, i, i, ptr);
+ if (ptr != buf) {
+ l4->l4_rlen += i;
+ if (l4->l4_rlen >= l4->l4_rsize) {
+ if (!strncmp(response, l4->l4_rbuf,
+ l4->l4_rsize)) {
+ printf("%d: Good response\n",
+ fd);
+ if (!l4->l4_alive) {
+ l4->l4_alive = 1;
+ addnat(l4);
+ }
+ closel4(l4, 0);
+ } else {
+ if (opts & OPT_VERBOSE)
+ printf("%d: Bad response\n",
+ fd);
+ closel4(l4, 1);
+ }
+ }
+ } else if (!l4->l4_alive) {
+ l4->l4_alive = 1;
+ addnat(l4);
+ closel4(l4, 0);
+ }
+ }
+}
+
+
+int runconfig()
+{
+ int fd, opt, res, mfd, i;
+ struct timeval tv;
+ time_t now, now1;
+ fd_set rfd, wfd;
+ l4cfg_t *l4;
+
+ mfd = 0;
+ opt = 1;
+ now = time(NULL);
+
+ /*
+ * First, initiate connections that are closed, as required.
+ */
+ for (l4 = l4list; l4; l4 = l4->l4_next) {
+ if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) {
+ l4->l4_last = now;
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ continue;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt,
+ sizeof(opt));
+#ifdef O_NONBLOCK
+ if ((res = fcntl(fd, F_GETFL, 0)) != -1)
+ fcntl(fd, F_SETFL, res | O_NONBLOCK);
+#endif
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Connecting to %s,%d (fd %d)...",
+ inet_ntoa(l4->l4_sin.sin_addr),
+ ntohs(l4->l4_sin.sin_port), fd);
+ if (connect(fd, (struct sockaddr *)&l4->l4_sin,
+ sizeof(l4->l4_sin)) == -1) {
+ if (errno != EINPROGRESS) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "failed\n");
+ perror("connect");
+ close(fd);
+ fd = -1;
+ } else {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "waiting\n");
+ l4->l4_rw = -2;
+ }
+ } else {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "connected\n");
+ connectl4(l4);
+ }
+ l4->l4_fd = fd;
+ }
+ }
+
+ /*
+ * Now look for fd's which we're expecting to read/write from.
+ */
+ FD_ZERO(&rfd);
+ FD_ZERO(&wfd);
+ tv.tv_sec = MIN(rtimeout, ctimeout);
+ tv.tv_usec = 0;
+
+ for (l4 = l4list; l4; l4 = l4->l4_next)
+ if (l4->l4_rw == 0) {
+ if (now - l4->l4_last > rtimeout) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "%d: Read timeout\n",
+ l4->l4_fd);
+ closel4(l4, 1);
+ continue;
+ }
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Wait for read on fd %d\n",
+ l4->l4_fd);
+ FD_SET(l4->l4_fd, &rfd);
+ if (l4->l4_fd > mfd)
+ mfd = l4->l4_fd;
+ } else if ((l4->l4_rw == 1 && l4->l4_wlen) ||
+ l4->l4_rw == -2) {
+ if ((l4->l4_rw == -2) &&
+ (now - l4->l4_last > ctimeout)) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "%d: connect timeout\n",
+ l4->l4_fd);
+ closel4(l4);
+ continue;
+ }
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Wait for write on fd %d\n",
+ l4->l4_fd);
+ FD_SET(l4->l4_fd, &wfd);
+ if (l4->l4_fd > mfd)
+ mfd = l4->l4_fd;
+ }
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1,
+ tv.tv_sec);
+ i = select(mfd + 1, &rfd, &wfd, NULL, &tv);
+ if (i == -1) {
+ perror("select");
+ return -1;
+ }
+
+ now1 = time(NULL);
+
+ for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) {
+ if (l4->l4_fd < 0)
+ continue;
+ if (FD_ISSET(l4->l4_fd, &rfd)) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Ready to read on fd %d\n",
+ l4->l4_fd);
+ readfd(l4);
+ i--;
+ }
+
+ if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Ready to write on fd %d\n",
+ l4->l4_fd);
+ writefd(l4);
+ i--;
+ }
+ }
+ return 0;
+}
+
+
+int gethostport(str, lnum, ipp, portp)
+ char *str;
+ int lnum;
+ u_32_t *ipp;
+ u_short *portp;
+{
+ struct servent *sp;
+ struct hostent *hp;
+ char *host, *port;
+ struct in_addr ip;
+
+ host = str;
+ port = strchr(host, ',');
+ if (port)
+ *port++ = '\0';
+
+#ifdef HAVE_INET_ATON
+ if (ISDIGIT(*host) && inet_aton(host, &ip))
+ *ipp = ip.s_addr;
+#else
+ if (ISDIGIT(*host))
+ *ipp = inet_addr(host);
+#endif
+ else {
+ if (!(hp = gethostbyname(host))) {
+ fprintf(stderr, "%d: can't resolve hostname: %s\n",
+ lnum, host);
+ return 0;
+ }
+ *ipp = *(u_32_t *)hp->h_addr;
+ }
+
+ if (port) {
+ if (ISDIGIT(*port))
+ *portp = htons(atoi(port));
+ else {
+ sp = getservbyname(port, "tcp");
+ if (sp)
+ *portp = sp->s_port;
+ else {
+ fprintf(stderr, "%d: unknown service %s\n",
+ lnum, port);
+ return 0;
+ }
+ }
+ } else
+ *portp = 0;
+ return 1;
+}
+
+
+char *mapfile(file, sizep)
+ char *file;
+ size_t *sizep;
+{
+ struct stat sb;
+ caddr_t addr;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ perror("open(mapfile)");
+ return NULL;
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ perror("fstat(mapfile)");
+ close(fd);
+ return NULL;
+ }
+
+ addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (addr == (caddr_t)-1) {
+ perror("mmap(mapfile)");
+ close(fd);
+ return NULL;
+ }
+ close(fd);
+ *sizep = sb.st_size;
+ return (char *)addr;
+}
+
+
+int readconfig(filename)
+ char *filename;
+{
+ char c, buf[512], *s, *t, *errtxt = NULL, *line;
+ int num, err = 0;
+ ipnat_t *ipn;
+ l4cfg_t *l4;
+ FILE *fp;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ perror("open(configfile)");
+ return -1;
+ }
+
+ bzero((char *)&template, sizeof(template));
+ template.l4_fd = -1;
+ template.l4_rw = -1;
+ template.l4_sin.sin_family = AF_INET;
+ ipn = &template.l4_nat;
+ ipn->in_flags = IPN_TCP|IPN_ROUNDR;
+ ipn->in_redir = NAT_REDIRECT;
+
+ for (num = 1; fgets(buf, sizeof(buf), fp); num++) {
+ s = strchr(buf, '\n');
+ if (!s) {
+ fprintf(stderr, "%d: line too long\n", num);
+ fclose(fp);
+ return -1;
+ }
+
+ *s = '\0';
+
+ /*
+ * lines which are comments
+ */
+ s = strchr(buf, '#');
+ if (s)
+ *s = '\0';
+
+ /*
+ * Skip leading whitespace
+ */
+ for (line = buf; (c = *line) && ISSPACE(c); line++)
+ ;
+ if (!*line)
+ continue;
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Parsing: [%s]\n", line);
+ t = strtok(line, " \t");
+ if (!t)
+ continue;
+ if (!strcasecmp(t, "interface")) {
+ s = strtok(NULL, " \t");
+ if (s)
+ t = strtok(NULL, "\t");
+ if (!s || !t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+
+ if (!strchr(t, ',')) {
+ fprintf(stderr,
+ "%d: local address,port missing\n",
+ num);
+ err = -1;
+ break;
+ }
+
+ strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname));
+ if (!gethostport(t, num, &ipn->in_outip,
+ &ipn->in_pmin)) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ ipn->in_outmsk = 0xffffffff;
+ ipn->in_pmax = ipn->in_pmin;
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Interface %s %s/%#x port %u\n",
+ ipn->in_ifname,
+ inet_ntoa(ipn->in_out[0]),
+ ipn->in_outmsk, ipn->in_pmin);
+ } else if (!strcasecmp(t, "remote")) {
+ if (!*ipn->in_ifname) {
+ fprintf(stderr,
+ "%d: ifname not set prior to remote\n",
+ num);
+ err = -1;
+ break;
+ }
+ s = strtok(NULL, " \t");
+ if (s)
+ t = strtok(NULL, "");
+ if (!s || !t || strcasecmp(s, "server")) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+
+ ipn->in_pnext = 0;
+ if (!gethostport(t, num, &ipn->in_inip,
+ &ipn->in_pnext)) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ ipn->in_inmsk = 0xffffffff;
+ if (ipn->in_pnext == 0)
+ ipn->in_pnext = ipn->in_pmin;
+
+ l4 = (l4cfg_t *)malloc(sizeof(*l4));
+ if (!l4) {
+ fprintf(stderr, "%d: out of memory (%d)\n",
+ num, sizeof(*l4));
+ err = -1;
+ break;
+ }
+ bcopy((char *)&template, (char *)l4, sizeof(*l4));
+ l4->l4_sin.sin_addr = ipn->in_in[0];
+ l4->l4_sin.sin_port = ipn->in_pnext;
+ l4->l4_next = l4list;
+ l4list = l4;
+ } else if (!strcasecmp(t, "connect")) {
+ s = strtok(NULL, " \t");
+ if (s)
+ t = strtok(NULL, "\t");
+ if (!s || !t) {
+ errtxt = line;
+ err = -1;
+ break;
+ } else if (!strcasecmp(s, "timeout")) {
+ ctimeout = atoi(t);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "connect timeout %d\n",
+ ctimeout);
+ } else if (!strcasecmp(s, "frequency")) {
+ frequency = atoi(t);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "connect frequency %d\n",
+ frequency);
+ } else {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ } else if (!strcasecmp(t, "probe")) {
+ s = strtok(NULL, " \t");
+ if (!s) {
+ errtxt = line;
+ err = -1;
+ break;
+ } else if (!strcasecmp(s, "string")) {
+ if (probe) {
+ fprintf(stderr,
+ "%d: probe already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ t = strtok(NULL, "");
+ if (!t) {
+ fprintf(stderr,
+ "%d: No probe string\n", num);
+ err = -1;
+ break;
+ }
+
+ probe = malloc(strlen(t));
+ copystr(probe, t);
+ plen = strlen(probe);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Probe string [%s]\n",
+ probe);
+ } else if (!strcasecmp(s, "file")) {
+ t = strtok(NULL, " \t");
+ if (!t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ if (probe) {
+ fprintf(stderr,
+ "%d: probe already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ probe = mapfile(t, &plen);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Probe file %s len %u@%p\n",
+ t, plen, probe);
+ }
+ } else if (!strcasecmp(t, "response")) {
+ s = strtok(NULL, " \t");
+ if (!s) {
+ errtxt = line;
+ err = -1;
+ break;
+ } else if (!strcasecmp(s, "timeout")) {
+ t = strtok(NULL, " \t");
+ if (!t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ rtimeout = atoi(t);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "response timeout %d\n",
+ rtimeout);
+ } else if (!strcasecmp(s, "string")) {
+ if (response) {
+ fprintf(stderr,
+ "%d: response already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ response = strdup(strtok(NULL, ""));
+ rlen = strlen(response);
+ template.l4_rsize = rlen;
+ template.l4_rbuf = malloc(rlen);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Response string [%s]\n",
+ response);
+ } else if (!strcasecmp(s, "file")) {
+ t = strtok(NULL, " \t");
+ if (!t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ if (response) {
+ fprintf(stderr,
+ "%d: response already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ response = mapfile(t, &rlen);
+ template.l4_rsize = rlen;
+ template.l4_rbuf = malloc(rlen);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Response file %s len %u@%p\n",
+ t, rlen, response);
+ }
+ } else {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ }
+
+ if (errtxt)
+ fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt);
+ fclose(fp);
+ return err;
+}
+
+
+void usage(prog)
+ char *prog;
+{
+ fprintf(stderr, "Usage: %s -f <configfile>\n", prog);
+ exit(1);
+}
+
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *config = NULL;
+ int c;
+
+ while ((c = getopt(argc, argv, "f:nv")) != -1)
+ switch (c)
+ {
+ case 'f' :
+ config = optarg;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (config == NULL)
+ usage(argv[0]);
+
+ if (readconfig(config))
+ exit(1);
+
+ if (!l4list) {
+ fprintf(stderr, "No remote servers, exiting.");
+ exit(1);
+ }
+
+ if (!(opts & OPT_DONOTHING)) {
+ natfd = open(IPL_NAT, O_RDWR);
+ if (natfd == -1) {
+ perror("open(IPL_NAT)");
+ exit(1);
+ }
+ }
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Starting...\n");
+ while (runconfig() == 0)
+ ;
+}
diff --git a/contrib/ipfilter/l4check/l4check.conf b/contrib/ipfilter/l4check/l4check.conf
new file mode 100644
index 0000000..d000e9f
--- /dev/null
+++ b/contrib/ipfilter/l4check/l4check.conf
@@ -0,0 +1,31 @@
+#
+# NOTE: ORDER IS IMPORTANT IN THIS FILE
+#
+# Interface to do the redirections on and the IP address which will be
+# targeted.
+#
+interface nf0 192.168.1.1,2100
+#
+connect timeout 1
+connect frequency 20
+#
+# If no probe string is specified, a successful connection implies the
+# server is still alive.
+#
+probe string GET /\n\n
+#probe file http.check
+#
+response timeout 4
+response string <HTML>
+#response file http.ok
+#
+# Here we have multiple servers, listed because that's what happens to be
+# used for testing of connect timeoutes, read timeouts, success and things
+# which don't connect.
+#
+remote server 192.168.1.2,23
+remote server 192.168.1.2,2101
+remote server 192.168.1.3,25
+remote server 192.168.1.254,8000
+remote server 192.168.1.1,9
+#
diff --git a/contrib/ipfilter/lib/Makefile b/contrib/ipfilter/lib/Makefile
new file mode 100644
index 0000000..fdda78e
--- /dev/null
+++ b/contrib/ipfilter/lib/Makefile
@@ -0,0 +1,443 @@
+#
+# Copyright (C) 2012 by Darren Reed.
+#
+# See the IPFILTER.LICENCE file for details on licencing.
+#
+# $Id$
+#
+INCDEP=$(TOP)/ip_compat.h $(TOP)/ip_fil.h $(TOP)/ipf.h
+
+LIBOBJS=$(DEST)/addicmp.o \
+ $(DEST)/addipopt.o \
+ $(DEST)/alist_free.o \
+ $(DEST)/alist_new.o \
+ $(DEST)/allocmbt.o \
+ $(DEST)/assigndefined.o \
+ $(DEST)/bcopywrap.o \
+ $(DEST)/binprint.o \
+ $(DEST)/buildopts.o \
+ $(DEST)/checkrev.o \
+ $(DEST)/connecttcp.o \
+ $(DEST)/count6bits.o \
+ $(DEST)/count4bits.o \
+ $(DEST)/debug.o \
+ $(DEST)/dupmbt.o \
+ $(DEST)/familyname.o \
+ $(DEST)/facpri.o \
+ $(DEST)/fill6bits.o \
+ $(DEST)/findword.o \
+ $(DEST)/flags.o \
+ $(DEST)/freembt.o \
+ $(DEST)/ftov.o \
+ $(DEST)/genmask.o \
+ $(DEST)/gethost.o \
+ $(DEST)/geticmptype.o \
+ $(DEST)/getifname.o \
+ $(DEST)/getnattype.o \
+ $(DEST)/getport.o \
+ $(DEST)/getportproto.o \
+ $(DEST)/getproto.o \
+ $(DEST)/getsumd.o \
+ $(DEST)/hostname.o \
+ $(DEST)/icmpcode.o \
+ $(DEST)/icmptypename.o \
+ $(DEST)/icmptypes.o \
+ $(DEST)/initparse.o \
+ $(DEST)/interror.o \
+ $(DEST)/ionames.o \
+ $(DEST)/ipf_dotuning.o \
+ $(DEST)/ipf_perror.o \
+ $(DEST)/ipft_hx.o \
+ $(DEST)/ipft_pc.o \
+ $(DEST)/ipft_tx.o \
+ $(DEST)/ipoptsec.o \
+ $(DEST)/kmem.o \
+ $(DEST)/kmemcpywrap.o \
+ $(DEST)/kvatoname.o \
+ $(DEST)/load_file.o \
+ $(DEST)/load_dstlist.o \
+ $(DEST)/load_dstlistnode.o \
+ $(DEST)/load_hash.o \
+ $(DEST)/load_hashnode.o \
+ $(DEST)/load_http.o \
+ $(DEST)/load_pool.o \
+ $(DEST)/load_poolnode.o \
+ $(DEST)/load_url.o \
+ $(DEST)/msgdsize.o \
+ $(DEST)/mutex_emul.o \
+ $(DEST)/nametokva.o \
+ $(DEST)/nat_setgroupmap.o \
+ $(DEST)/ntomask.o \
+ $(DEST)/optname.o \
+ $(DEST)/optprint.o \
+ $(DEST)/optprintv6.o \
+ $(DEST)/optvalue.o \
+ $(DEST)/parsefields.o \
+ $(DEST)/parseipfexpr.o \
+ $(DEST)/parsewhoisline.o \
+ $(DEST)/poolio.o \
+ $(DEST)/portname.o \
+ $(DEST)/print_toif.o \
+ $(DEST)/printactiveaddr.o \
+ $(DEST)/printactivenat.o \
+ $(DEST)/printaddr.o \
+ $(DEST)/printaps.o \
+ $(DEST)/printbuf.o \
+ $(DEST)/printdstlist.o \
+ $(DEST)/printdstlistdata.o \
+ $(DEST)/printdstlistnode.o \
+ $(DEST)/printdstlistpolicy.o \
+ $(DEST)/printdstl_live.o \
+ $(DEST)/printfieldhdr.o \
+ $(DEST)/printfr.o \
+ $(DEST)/printfraginfo.o \
+ $(DEST)/printhash.o \
+ $(DEST)/printhashdata.o \
+ $(DEST)/printhashnode.o \
+ $(DEST)/printhash_live.o \
+ $(DEST)/printhost.o \
+ $(DEST)/printhostmap.o \
+ $(DEST)/printhostmask.o \
+ $(DEST)/printifname.o \
+ $(DEST)/printip.o \
+ $(DEST)/printipfexpr.o \
+ $(DEST)/printlog.o \
+ $(DEST)/printlookup.o \
+ $(DEST)/printmask.o \
+ $(DEST)/printnat.o \
+ $(DEST)/printnataddr.o \
+ $(DEST)/printnatfield.o \
+ $(DEST)/printnatside.o \
+ $(DEST)/printpool.o \
+ $(DEST)/printpooldata.o \
+ $(DEST)/printpoolfield.o \
+ $(DEST)/printpoolnode.o \
+ $(DEST)/printpool_live.o \
+ $(DEST)/printproto.o \
+ $(DEST)/printportcmp.o \
+ $(DEST)/printpacket.o \
+ $(DEST)/printpacket6.o \
+ $(DEST)/printsbuf.o \
+ $(DEST)/printstate.o \
+ $(DEST)/printstatefields.o \
+ $(DEST)/printtcpflags.o \
+ $(DEST)/printtqtable.o \
+ $(DEST)/printtunable.o \
+ $(DEST)/printunit.o \
+ $(DEST)/remove_hash.o \
+ $(DEST)/remove_hashnode.o \
+ $(DEST)/remove_pool.o \
+ $(DEST)/remove_poolnode.o \
+ $(DEST)/resetlexer.o \
+ $(DEST)/rwlock_emul.o \
+ $(DEST)/save_execute.o \
+ $(DEST)/save_file.o \
+ $(DEST)/save_nothing.o \
+ $(DEST)/save_syslog.o \
+ $(DEST)/save_v1trap.o \
+ $(DEST)/save_v2trap.o \
+ $(DEST)/tcpflags.o \
+ $(DEST)/var.o \
+ $(DEST)/verbose.o \
+ $(DEST)/vtof.o \
+ $(DEST)/v6ionames.o \
+ $(DEST)/v6optvalue.o
+
+$(DEST)/libipf.a: $(LIBOBJS)
+ /bin/rm -f $@
+ ar $(AROPTS) $@ $(LIBOBJS)
+ $(RANLIB) $@
+
+$(DEST)/addicmp.o: $(LIBSRC)/addicmp.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/addicmp.c -o $@
+$(DEST)/addipopt.o: $(LIBSRC)/addipopt.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/addipopt.c -o $@
+$(DEST)/alist_free.o: $(LIBSRC)/alist_free.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/alist_free.c -o $@
+$(DEST)/alist_new.o: $(LIBSRC)/alist_new.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/alist_new.c -o $@
+$(DEST)/allocmbt.o: $(LIBSRC)/allocmbt.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/allocmbt.c -o $@
+$(DEST)/assigndefined.o: $(LIBSRC)/assigndefined.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/assigndefined.c -o $@
+$(DEST)/bcopywrap.o: $(LIBSRC)/bcopywrap.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/bcopywrap.c -o $@
+$(DEST)/binprint.o: $(LIBSRC)/binprint.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/binprint.c -o $@
+$(DEST)/buildopts.o: $(LIBSRC)/buildopts.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/buildopts.c -o $@
+$(DEST)/connecttcp.o: $(LIBSRC)/connecttcp.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/connecttcp.c -o $@
+$(DEST)/count6bits.o: $(LIBSRC)/count6bits.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/count6bits.c -o $@
+$(DEST)/checkrev.o: $(LIBSRC)/checkrev.c $(INCDEP) $(TOP)/ipl.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/checkrev.c -o $@
+$(DEST)/count4bits.o: $(LIBSRC)/count4bits.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/count4bits.c -o $@
+$(DEST)/debug.o: $(LIBSRC)/debug.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/debug.c -o $@
+$(DEST)/dupmbt.o: $(LIBSRC)/dupmbt.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/dupmbt.c -o $@
+$(DEST)/facpri.o: $(LIBSRC)/facpri.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/facpri.c -o $@
+$(DEST)/familyname.o: $(LIBSRC)/familyname.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/familyname.c -o $@
+$(DEST)/fill6bits.o: $(LIBSRC)/fill6bits.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/fill6bits.c -o $@
+$(DEST)/findword.o: $(LIBSRC)/findword.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/findword.c -o $@
+$(DEST)/flags.o: $(LIBSRC)/flags.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/flags.c -o $@
+$(DEST)/freembt.o: $(LIBSRC)/freembt.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/freembt.c -o $@
+$(DEST)/ftov.o: $(LIBSRC)/ftov.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ftov.c -o $@
+$(DEST)/genmask.o: $(LIBSRC)/genmask.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/genmask.c -o $@
+$(DEST)/gethost.o: $(LIBSRC)/gethost.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/gethost.c -o $@
+$(DEST)/geticmptype.o: $(LIBSRC)/geticmptype.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/geticmptype.c -o $@
+$(DEST)/getifname.o: $(LIBSRC)/getifname.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/getifname.c -o $@
+$(DEST)/getnattype.o: $(LIBSRC)/getnattype.c $(INCDEP) $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/getnattype.c -o $@
+$(DEST)/getport.o: $(LIBSRC)/getport.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/getport.c -o $@
+$(DEST)/getportproto.o: $(LIBSRC)/getportproto.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/getportproto.c -o $@
+$(DEST)/getproto.o: $(LIBSRC)/getproto.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/getproto.c -o $@
+$(DEST)/getsumd.o: $(LIBSRC)/getsumd.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/getsumd.c -o $@
+$(DEST)/hostname.o: $(LIBSRC)/hostname.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/hostname.c -o $@
+$(DEST)/icmpcode.o: $(LIBSRC)/icmpcode.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/icmpcode.c -o $@
+$(DEST)/icmptypename.o: $(LIBSRC)/icmptypename.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/icmptypename.c -o $@
+$(DEST)/icmptypes.o: $(LIBSRC)/icmptypes.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/icmptypes.c -o $@
+$(DEST)/interror.o: $(LIBSRC)/interror.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/interror.c -o $@
+$(DEST)/ipoptsec.o: $(LIBSRC)/ipoptsec.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ipoptsec.c -o $@
+$(DEST)/initparse.o: $(LIBSRC)/initparse.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/initparse.c -o $@
+$(DEST)/ionames.o: $(LIBSRC)/ionames.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ionames.c -o $@
+$(DEST)/ipf_dotuning.o: $(LIBSRC)/ipf_dotuning.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ipf_dotuning.c -o $@
+$(DEST)/ipf_perror.o: $(LIBSRC)/ipf_perror.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ipf_perror.c -o $@
+$(DEST)/ipft_hx.o: $(LIBSRC)/ipft_hx.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ipft_hx.c -o $@
+$(DEST)/ipft_pc.o: $(LIBSRC)/ipft_pc.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ipft_pc.c -o $@
+$(DEST)/ipft_tx.o: $(LIBSRC)/ipft_tx.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/ipft_tx.c -o $@
+$(DEST)/kmem.o: $(LIBSRC)/kmem.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/kmem.c -o $@
+$(DEST)/kmemcpywrap.o: $(LIBSRC)/kmemcpywrap.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/kmemcpywrap.c -o $@
+$(DEST)/kvatoname.o: $(LIBSRC)/kvatoname.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/kvatoname.c -o $@
+$(DEST)/load_file.o: $(LIBSRC)/load_file.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_file.c -o $@
+$(DEST)/load_dstlist.o: $(LIBSRC)/load_dstlist.c $(INCDEP) $(TOP)/ip_dstlist.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_dstlist.c -o $@
+$(DEST)/load_dstlistnode.o: $(LIBSRC)/load_dstlistnode.c $(INCDEP) \
+ $(TOP)/ip_dstlist.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_dstlistnode.c -o $@
+$(DEST)/load_hash.o: $(LIBSRC)/load_hash.c $(INCDEP) $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_hash.c -o $@
+$(DEST)/load_hashnode.o: $(LIBSRC)/load_hashnode.c $(INCDEP) $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_hashnode.c -o $@
+$(DEST)/load_http.o: $(LIBSRC)/load_http.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_http.c -o $@
+$(DEST)/load_pool.o: $(LIBSRC)/load_pool.c $(INCDEP) $(TOP)/ip_pool.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_pool.c -o $@
+$(DEST)/load_poolnode.o: $(LIBSRC)/load_poolnode.c $(INCDEP) $(TOP)/ip_pool.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_poolnode.c -o $@
+$(DEST)/load_url.o: $(LIBSRC)/load_url.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/load_url.c -o $@
+$(DEST)/msgdsize.o: $(LIBSRC)/msgdsize.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/msgdsize.c -o $@
+$(DEST)/mutex_emul.o: $(LIBSRC)/mutex_emul.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/mutex_emul.c -o $@
+$(DEST)/nametokva.o: $(LIBSRC)/nametokva.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/nametokva.c -o $@
+$(DEST)/nat_setgroupmap.o: $(LIBSRC)/nat_setgroupmap.c $(TOP)/ip_compat.h \
+ $(TOP)/ipf.h $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/nat_setgroupmap.c -o $@
+$(DEST)/ntomask.o: $(LIBSRC)/ntomask.c $(TOP)/ip_compat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/ntomask.c -o $@
+$(DEST)/optname.o: $(LIBSRC)/optname.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/optname.c -o $@
+$(DEST)/optprint.o: $(LIBSRC)/optprint.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/optprint.c -o $@
+$(DEST)/optprintv6.o: $(LIBSRC)/optprintv6.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/optprintv6.c -o $@
+$(DEST)/optvalue.o: $(LIBSRC)/optvalue.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/optvalue.c -o $@
+$(DEST)/parsefields.o: $(LIBSRC)/parsefields.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/parsefields.c -o $@
+$(DEST)/parseipfexpr.o: $(LIBSRC)/parseipfexpr.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/parseipfexpr.c -o $@
+$(DEST)/parsewhoisline.o: $(LIBSRC)/parsewhoisline.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/parsewhoisline.c -o $@
+$(DEST)/poolio.o: $(LIBSRC)/poolio.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/poolio.c -o $@
+$(DEST)/portname.o: $(LIBSRC)/portname.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/portname.c -o $@
+$(DEST)/print_toif.o: $(LIBSRC)/print_toif.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/print_toif.c -o $@
+$(DEST)/printactiveaddr.o: $(LIBSRC)/printactiveaddr.c $(INCDEP) $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printactiveaddr.c -o $@
+$(DEST)/printactivenat.o: $(LIBSRC)/printactivenat.c $(INCDEP) $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printactivenat.c -o $@
+$(DEST)/printaddr.o: $(LIBSRC)/printaddr.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printaddr.c -o $@
+$(DEST)/printaps.o: $(LIBSRC)/printaps.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printaps.c -o $@
+$(DEST)/printbuf.o: $(LIBSRC)/printbuf.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printbuf.c -o $@
+$(DEST)/printdstlist.o: $(LIBSRC)/printdstlist.c $(INCDEP) $(TOP)/ip_dstlist.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printdstlist.c -o $@
+$(DEST)/printdstlistdata.o: $(LIBSRC)/printdstlistdata.c $(INCDEP) \
+ $(TOP)/ip_dstlist.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printdstlistdata.c -o $@
+$(DEST)/printdstlistnode.o: $(LIBSRC)/printdstlistnode.c $(INCDEP) \
+ $(TOP)/ip_dstlist.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printdstlistnode.c -o $@
+$(DEST)/printdstlistpolicy.o: $(LIBSRC)/printdstlistpolicy.c $(INCDEP) \
+ $(TOP)/ip_dstlist.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printdstlistpolicy.c -o $@
+$(DEST)/printfieldhdr.o: $(LIBSRC)/printfieldhdr.c $(TOP)/ip_fil.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printfieldhdr.c -o $@
+$(DEST)/printfr.o: $(LIBSRC)/printfr.c $(TOP)/ip_fil.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printfr.c -o $@
+$(DEST)/printfraginfo.o: $(LIBSRC)/printfraginfo.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_frag.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printfraginfo.c -o $@
+$(DEST)/printhash.o: $(LIBSRC)/printhash.c $(TOP)/ip_fil.h $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printhash.c -o $@
+$(DEST)/printhashdata.o: $(LIBSRC)/printhashdata.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printhashdata.c -o $@
+$(DEST)/printhashnode.o: $(LIBSRC)/printhashnode.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_htable.h $(TOP)/ip_lookup.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printhashnode.c -o $@
+$(DEST)/printhash_live.o: $(LIBSRC)/printhash_live.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printhash_live.c -o $@
+$(DEST)/printdstl_live.o: $(LIBSRC)/printdstl_live.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_dstlist.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printdstl_live.c -o $@
+$(DEST)/printip.o: $(LIBSRC)/printip.c $(TOP)/ip_fil.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printip.c -o $@
+$(DEST)/printipfexpr.o: $(LIBSRC)/printipfexpr.c $(TOP)/ip_fil.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printipfexpr.c -o $@
+$(DEST)/printlookup.o: $(LIBSRC)/printlookup.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printlookup.c -o $@
+$(DEST)/printnataddr.o: $(LIBSRC)/printnataddr.c $(INCDEP) $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printnataddr.c -o $@
+$(DEST)/printnatside.o: $(LIBSRC)/printnatside.c $(INCDEP) $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printnatside.c -o $@
+$(DEST)/printpool.o: $(LIBSRC)/printpool.c $(TOP)/ip_fil.h $(TOP)/ip_pool.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printpool.c -o $@
+$(DEST)/printpooldata.o: $(LIBSRC)/printpooldata.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_pool.h $(TOP)/ip_lookup.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printpooldata.c -o $@
+$(DEST)/printpoolfield.o: $(LIBSRC)/printpoolfield.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_pool.h $(TOP)/ip_lookup.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printpoolfield.c -o $@
+$(DEST)/printpoolnode.o: $(LIBSRC)/printpoolnode.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_pool.h $(TOP)/ip_lookup.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printpoolnode.c -o $@
+$(DEST)/printpool_live.o: $(LIBSRC)/printpool_live.c $(TOP)/ip_fil.h \
+ $(TOP)/ip_pool.h $(TOP)/ip_lookup.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printpool_live.c -o $@
+$(DEST)/printproto.o: $(LIBSRC)/printproto.c $(TOP)/ip_fil.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printproto.c -o $@
+$(DEST)/printhost.o: $(LIBSRC)/printhost.c $(TOP)/ip_fil.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printhost.c -o $@
+$(DEST)/printhostmap.o: $(LIBSRC)/printhostmap.c $(TOP)/ip_fil.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printhostmap.c -o $@
+$(DEST)/printifname.o: $(LIBSRC)/printifname.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printifname.c -o $@
+$(DEST)/printmask.o: $(LIBSRC)/printmask.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printmask.c -o $@
+$(DEST)/printnat.o: $(LIBSRC)/printnat.c $(INCDEP) $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printnat.c -o $@
+$(DEST)/printnatfield.o: $(LIBSRC)/printnatfield.c $(INCDEP) $(TOP)/ip_nat.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printnatfield.c -o $@
+$(DEST)/printhostmask.o: $(LIBSRC)/printhostmask.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printhostmask.c -o $@
+$(DEST)/printlog.o: $(LIBSRC)/printlog.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printlog.c -o $@
+$(DEST)/printpacket.o: $(LIBSRC)/printpacket.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printpacket.c -o $@
+$(DEST)/printpacket6.o: $(LIBSRC)/printpacket6.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printpacket6.c -o $@
+$(DEST)/printportcmp.o: $(LIBSRC)/printportcmp.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printportcmp.c -o $@
+$(DEST)/printsbuf.o: $(LIBSRC)/printsbuf.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printsbuf.c -o $@
+$(DEST)/printstate.o: $(LIBSRC)/printstate.c $(INCDEP) $(TOP)/ip_state.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printstate.c -o $@
+$(DEST)/printstatefields.o: $(LIBSRC)/printstatefields.c $(INCDEP) $(TOP)/ip_state.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/printstatefields.c -o $@
+$(DEST)/printtcpflags.o: $(LIBSRC)/printtcpflags.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printtcpflags.c -o $@
+$(DEST)/printtqtable.o: $(LIBSRC)/printtqtable.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printtqtable.c -o $@
+$(DEST)/printtunable.o: $(LIBSRC)/printtunable.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printtunable.c -o $@
+$(DEST)/printunit.o: $(LIBSRC)/printunit.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/printunit.c -o $@
+$(DEST)/remove_hash.o: $(LIBSRC)/remove_hash.c $(INCDEP) \
+ $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/remove_hash.c -o $@
+$(DEST)/remove_hashnode.o: $(LIBSRC)/remove_hashnode.c $(INCDEP) \
+ $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/remove_hashnode.c -o $@
+$(DEST)/remove_pool.o: $(LIBSRC)/remove_pool.c $(INCDEP) \
+ $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/remove_pool.c -o $@
+$(DEST)/remove_poolnode.o: $(LIBSRC)/remove_poolnode.c $(INCDEP) \
+ $(TOP)/ip_htable.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/remove_poolnode.c -o $@
+$(DEST)/resetlexer.o: $(LIBSRC)/resetlexer.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/resetlexer.c -o $@
+$(DEST)/rwlock_emul.o: $(LIBSRC)/rwlock_emul.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/rwlock_emul.c -o $@
+$(DEST)/tcpflags.o: $(LIBSRC)/tcpflags.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/tcpflags.c -o $@
+$(DEST)/tcp_flags.o: $(LIBSRC)/tcp_flags.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/tcp_flags.c -o $@
+$(DEST)/var.o: $(LIBSRC)/var.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/var.c -o $@
+$(DEST)/verbose.o: $(LIBSRC)/verbose.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/verbose.c -o $@
+$(DEST)/save_execute.o: $(LIBSRC)/save_execute.c $(TOP)/ipl.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/save_execute.c -o $@
+$(DEST)/save_file.o: $(LIBSRC)/save_file.c $(TOP)/ipl.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/save_file.c -o $@
+$(DEST)/save_nothing.o: $(LIBSRC)/save_nothing.c $(TOP)/ipl.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/save_nothing.c -o $@
+$(DEST)/save_syslog.o: $(LIBSRC)/save_syslog.c $(TOP)/ipl.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/save_syslog.c -o $@
+$(DEST)/vtof.o: $(LIBSRC)/vtof.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/vtof.c -o $@
+$(DEST)/save_v1trap.o: $(LIBSRC)/save_v1trap.c $(TOP)/ipl.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/save_v1trap.c -o $@
+$(DEST)/save_v2trap.o: $(LIBSRC)/save_v2trap.c $(TOP)/ipl.h
+ $(CC) $(CCARGS) -c $(LIBSRC)/save_v2trap.c -o $@
+$(DEST)/v6ionames.o: $(LIBSRC)/v6ionames.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/v6ionames.c -o $@
+$(DEST)/v6optvalue.o: $(LIBSRC)/v6optvalue.c $(INCDEP)
+ $(CC) $(CCARGS) -c $(LIBSRC)/v6optvalue.c -o $@
+
+clean-lib:
+ /bin/rm -f ${LIBOBJS} ${LIB}
diff --git a/contrib/ipfilter/lib/addicmp.c b/contrib/ipfilter/lib/addicmp.c
new file mode 100644
index 0000000..da52f1c
--- /dev/null
+++ b/contrib/ipfilter/lib/addicmp.c
@@ -0,0 +1,21 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <ctype.h>
+
+#include "ipf.h"
+
+
+char *icmptypes[MAX_ICMPTYPE + 1] = {
+ "echorep", (char *)NULL, (char *)NULL, "unreach", "squench",
+ "redir", (char *)NULL, (char *)NULL, "echo", "routerad",
+ "routersol", "timex", "paramprob", "timest", "timestrep",
+ "inforeq", "inforep", "maskreq", "maskrep", "END"
+};
diff --git a/contrib/ipfilter/lib/addipopt.c b/contrib/ipfilter/lib/addipopt.c
new file mode 100644
index 0000000..26aff83
--- /dev/null
+++ b/contrib/ipfilter/lib/addipopt.c
@@ -0,0 +1,65 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+int addipopt(op, io, len, class)
+ char *op;
+ struct ipopt_names *io;
+ int len;
+ char *class;
+{
+ int olen = len;
+ struct in_addr ipadr;
+ u_short val;
+ u_char lvl;
+ char *s;
+
+ if ((len + io->on_siz) > 48) {
+ fprintf(stderr, "options too long\n");
+ return 0;
+ }
+ len += io->on_siz;
+ *op++ = io->on_value;
+ if (io->on_siz > 1) {
+ s = op;
+ *op++ = io->on_siz;
+ *op++ = IPOPT_MINOFF;
+
+ if (class) {
+ switch (io->on_value)
+ {
+ case IPOPT_SECURITY :
+ lvl = seclevel(class);
+ *(op - 1) = lvl;
+ break;
+ case IPOPT_RR :
+ case IPOPT_TS :
+ s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4;
+ break;
+ case IPOPT_LSRR :
+ case IPOPT_SSRR :
+ ipadr.s_addr = inet_addr(class);
+ s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4;
+ bcopy((char *)&ipadr, op, sizeof(ipadr));
+ break;
+ case IPOPT_SATID :
+ val = atoi(class);
+ bcopy((char *)&val, op, 2);
+ break;
+ }
+ }
+ }
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "bo: %s %d %#x: %d\n",
+ io->on_name, io->on_value, io->on_bit, len);
+ return len - olen;
+}
diff --git a/contrib/ipfilter/lib/alist_free.c b/contrib/ipfilter/lib/alist_free.c
new file mode 100644
index 0000000..44dea13
--- /dev/null
+++ b/contrib/ipfilter/lib/alist_free.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: alist_free.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+#include "ipf.h"
+
+void
+alist_free(hosts)
+ alist_t *hosts;
+{
+ alist_t *a, *next;
+
+ for (a = hosts; a != NULL; a = next) {
+ next = a->al_next;
+ free(a);
+ }
+}
diff --git a/contrib/ipfilter/lib/alist_new.c b/contrib/ipfilter/lib/alist_new.c
new file mode 100644
index 0000000..73bc030
--- /dev/null
+++ b/contrib/ipfilter/lib/alist_new.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: alist_new.c,v 1.5.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+alist_t *
+alist_new(int family, char *host)
+{
+ int a, b, c, d, bits;
+ char *slash;
+ alist_t *al;
+ u_int mask;
+
+ if (family == AF_UNSPEC) {
+ if (strchr(host, ':') != NULL)
+ family = AF_INET6;
+ else
+ family = AF_INET;
+ }
+ if (family != AF_INET && family != AF_INET6)
+ return NULL;
+
+ al = calloc(1, sizeof(*al));
+ if (al == NULL) {
+ fprintf(stderr, "alist_new out of memory\n");
+ return NULL;
+ }
+
+ while (ISSPACE(*host))
+ host++;
+
+ if (*host == '!') {
+ al->al_not = 1;
+ host++;
+ while (ISSPACE(*host))
+ host++;
+ }
+
+ bits = -1;
+ slash = strchr(host, '/');
+ if (slash != NULL) {
+ *slash = '\0';
+ bits = atoi(slash + 1);
+ }
+
+ if (family == AF_INET) {
+ if (bits > 32)
+ goto bad;
+
+ a = b = c = d = -1;
+ sscanf(host, "%d.%d.%d.%d", &a, &b, &c, &d);
+
+ if (bits > 0 && bits < 33) {
+ mask = 0xffffffff << (32 - bits);
+ } else if (b == -1) {
+ mask = 0xff000000;
+ b = c = d = 0;
+ } else if (c == -1) {
+ mask = 0xffff0000;
+ c = d = 0;
+ } else if (d == -1) {
+ mask = 0xffffff00;
+ d = 0;
+ } else {
+ mask = 0xffffffff;
+ }
+ al->al_mask = htonl(mask);
+ } else {
+ if (bits > 128)
+ goto bad;
+ fill6bits(bits, al->al_i6mask.i6);
+ }
+
+ if (gethost(family, host, &al->al_i6addr) == -1) {
+ if (slash != NULL)
+ *slash = '/';
+ fprintf(stderr, "Cannot parse hostname\n");
+ goto bad;
+ }
+ al->al_family = family;
+ if (slash != NULL)
+ *slash = '/';
+ return al;
+bad:
+ free(al);
+ return NULL;
+}
diff --git a/contrib/ipfilter/lib/allocmbt.c b/contrib/ipfilter/lib/allocmbt.c
new file mode 100644
index 0000000..df77684
--- /dev/null
+++ b/contrib/ipfilter/lib/allocmbt.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: allocmbt.c,v 1.1.4.1 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+mb_t *allocmbt(size_t len)
+{
+ mb_t *m;
+
+ m = (mb_t *)malloc(sizeof(mb_t));
+ if (m == NULL)
+ return NULL;
+ m->mb_len = len;
+ m->mb_next = NULL;
+ m->mb_data = (char *)m->mb_buf;
+ return m;
+}
diff --git a/contrib/ipfilter/lib/assigndefined.c b/contrib/ipfilter/lib/assigndefined.c
new file mode 100644
index 0000000..34f8d9a
--- /dev/null
+++ b/contrib/ipfilter/lib/assigndefined.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: assigndefined.c,v 1.4.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+void assigndefined(env)
+ char *env;
+{
+ char *s, *t;
+
+ if (env == NULL)
+ return;
+
+ for (s = strtok(env, ";"); s != NULL; s = strtok(NULL, ";")) {
+ t = strchr(s, '=');
+ if (t == NULL)
+ continue;
+ *t++ = '\0';
+ set_variable(s, t);
+ *--t = '=';
+ }
+}
diff --git a/contrib/ipfilter/lib/bcopywrap.c b/contrib/ipfilter/lib/bcopywrap.c
new file mode 100644
index 0000000..453c046
--- /dev/null
+++ b/contrib/ipfilter/lib/bcopywrap.c
@@ -0,0 +1,20 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+int bcopywrap(from, to, size)
+ void *from, *to;
+ size_t size;
+{
+ bcopy((caddr_t)from, (caddr_t)to, size);
+ return 0;
+}
+
diff --git a/contrib/ipfilter/lib/binprint.c b/contrib/ipfilter/lib/binprint.c
new file mode 100644
index 0000000..f826721
--- /dev/null
+++ b/contrib/ipfilter/lib/binprint.c
@@ -0,0 +1,31 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void binprint(ptr, size)
+ void *ptr;
+ size_t size;
+{
+ u_char *s;
+ int i, j;
+
+ for (i = size, j = 0, s = (u_char *)ptr; i; i--, s++) {
+ j++;
+ printf("%02x ", *s);
+ if (j == 16) {
+ printf("\n");
+ j = 0;
+ }
+ }
+ putchar('\n');
+ (void)fflush(stdout);
+}
diff --git a/contrib/ipfilter/lib/buildopts.c b/contrib/ipfilter/lib/buildopts.c
new file mode 100644
index 0000000..1d1de8c
--- /dev/null
+++ b/contrib/ipfilter/lib/buildopts.c
@@ -0,0 +1,50 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+u_32_t buildopts(cp, op, len)
+ char *cp, *op;
+ int len;
+{
+ struct ipopt_names *io;
+ u_32_t msk = 0;
+ char *s, *t;
+ int inc;
+
+ for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) {
+ if ((t = strchr(s, '=')))
+ *t++ = '\0';
+ else
+ t = "";
+ for (io = ionames; io->on_name; io++) {
+ if (strcasecmp(s, io->on_name) || (msk & io->on_bit))
+ continue;
+ if ((inc = addipopt(op, io, len, t))) {
+ op += inc;
+ len += inc;
+ }
+ msk |= io->on_bit;
+ break;
+ }
+ if (!io->on_name) {
+ fprintf(stderr, "unknown IP option name %s\n", s);
+ return 0;
+ }
+ }
+ while ((len & 3) != 3) {
+ *op++ = IPOPT_NOP;
+ len++;
+ }
+ *op++ = IPOPT_EOL;
+ len++;
+ return len;
+}
diff --git a/contrib/ipfilter/lib/checkrev.c b/contrib/ipfilter/lib/checkrev.c
new file mode 100644
index 0000000..b6f8eee
--- /dev/null
+++ b/contrib/ipfilter/lib/checkrev.c
@@ -0,0 +1,46 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include "ipf.h"
+#include "netinet/ipl.h"
+
+int checkrev(ipfname)
+ char *ipfname;
+{
+ static int vfd = -1;
+ struct friostat fio;
+ ipfobj_t obj;
+
+ bzero((caddr_t)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(fio);
+ obj.ipfo_ptr = (void *)&fio;
+ obj.ipfo_type = IPFOBJ_IPFSTAT;
+
+ if ((vfd == -1) && ((vfd = open(ipfname, O_RDONLY)) == -1)) {
+ perror("open device");
+ return -1;
+ }
+
+ if (ioctl(vfd, SIOCGETFS, &obj)) {
+ ipferror(vfd, "ioctl(SIOCGETFS)");
+ close(vfd);
+ vfd = -1;
+ return -1;
+ }
+
+ if (strncmp(IPL_VERSION, fio.f_version, sizeof(fio.f_version))) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/connecttcp.c b/contrib/ipfilter/lib/connecttcp.c
new file mode 100644
index 0000000..2bab2af
--- /dev/null
+++ b/contrib/ipfilter/lib/connecttcp.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: connecttcp.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+/*
+ * Format expected is one addres per line, at the start of each line.
+ */
+int
+connecttcp(char *server, int port)
+{
+ struct sockaddr_in sin;
+ struct hostent *host;
+ int fd;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port & 65535);
+
+ if (ISDIGIT(*server)) {
+ if (inet_aton(server, &sin.sin_addr) == -1) {
+ return -1;
+ }
+ } else {
+ host = gethostbyname(server);
+ if (host == NULL)
+ return -1;
+ memcpy(&sin.sin_addr, host->h_addr_list[0],
+ sizeof(sin.sin_addr));
+ }
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ return -1;
+
+ if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
diff --git a/contrib/ipfilter/lib/count4bits.c b/contrib/ipfilter/lib/count4bits.c
new file mode 100644
index 0000000..a847388
--- /dev/null
+++ b/contrib/ipfilter/lib/count4bits.c
@@ -0,0 +1,40 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+/*
+ * count consecutive 1's in bit mask. If the mask generated by counting
+ * consecutive 1's is different to that passed, return -1, else return #
+ * of bits.
+ */
+int count4bits(ip)
+ u_int ip;
+{
+ int cnt = 0, i, j;
+ u_int ipn;
+
+ ip = ipn = ntohl(ip);
+ for (i = 32; i; i--, ipn *= 2)
+ if (ipn & 0x80000000)
+ cnt++;
+ else
+ break;
+ ipn = 0;
+ for (i = 32, j = cnt; i; i--, j--) {
+ ipn *= 2;
+ if (j > 0)
+ ipn++;
+ }
+ if (ipn == ip)
+ return cnt;
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/count6bits.c b/contrib/ipfilter/lib/count6bits.c
new file mode 100644
index 0000000..b8f4320
--- /dev/null
+++ b/contrib/ipfilter/lib/count6bits.c
@@ -0,0 +1,29 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+int count6bits(msk)
+ u_32_t *msk;
+{
+ int i = 0, k;
+ u_32_t j;
+
+ for (k = 3; k >= 0; k--)
+ if (msk[k] == 0xffffffff)
+ i += 32;
+ else {
+ for (j = msk[k]; j; j <<= 1)
+ if (j & 0x80000000)
+ i++;
+ }
+ return i;
+}
diff --git a/contrib/ipfilter/lib/debug.c b/contrib/ipfilter/lib/debug.c
new file mode 100644
index 0000000..02e5f5b
--- /dev/null
+++ b/contrib/ipfilter/lib/debug.c
@@ -0,0 +1,58 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#if defined(__STDC__)
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+#include <stdio.h>
+
+#include "ipf.h"
+#include "opts.h"
+
+int debuglevel = 0;
+
+
+#ifdef __STDC__
+void debug(int level, char *fmt, ...)
+#else
+void debug(level, fmt, va_alist)
+ int level;
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list pvar;
+
+ va_start(pvar, fmt);
+
+ if ((debuglevel > 0) && (level <= debuglevel))
+ vfprintf(stderr, fmt, pvar);
+ va_end(pvar);
+}
+
+
+#ifdef __STDC__
+void ipfkdebug(char *fmt, ...)
+#else
+void ipfkdebug(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list pvar;
+
+ va_start(pvar, fmt);
+
+ if (opts & OPT_DEBUG)
+ debug(0x1fffffff, fmt, pvar);
+ va_end(pvar);
+}
diff --git a/contrib/ipfilter/lib/dupmbt.c b/contrib/ipfilter/lib/dupmbt.c
new file mode 100644
index 0000000..0929eeb
--- /dev/null
+++ b/contrib/ipfilter/lib/dupmbt.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: dupmbt.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+mb_t *dupmbt(orig)
+ mb_t *orig;
+{
+ mb_t *m;
+
+ m = (mb_t *)malloc(sizeof(mb_t));
+ if (m == NULL)
+ return NULL;
+ m->mb_len = orig->mb_len;
+ m->mb_next = NULL;
+ m->mb_data = (char *)m->mb_buf + (orig->mb_data - (char *)orig->mb_buf);
+ bcopy(orig->mb_data, m->mb_data, m->mb_len);
+ return m;
+}
diff --git a/contrib/ipfilter/lib/facpri.c b/contrib/ipfilter/lib/facpri.c
new file mode 100644
index 0000000..c9b4774
--- /dev/null
+++ b/contrib/ipfilter/lib/facpri.c
@@ -0,0 +1,153 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <syslog.h>
+#include "facpri.h"
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+typedef struct table {
+ char *name;
+ int value;
+} table_t;
+
+table_t facs[] = {
+ { "kern", LOG_KERN }, { "user", LOG_USER },
+ { "mail", LOG_MAIL }, { "daemon", LOG_DAEMON },
+ { "auth", LOG_AUTH }, { "syslog", LOG_SYSLOG },
+ { "lpr", LOG_LPR }, { "news", LOG_NEWS },
+ { "uucp", LOG_UUCP },
+#if LOG_CRON == LOG_CRON2
+ { "cron2", LOG_CRON1 },
+#else
+ { "cron", LOG_CRON1 },
+#endif
+#ifdef LOG_FTP
+ { "ftp", LOG_FTP },
+#endif
+#ifdef LOG_AUTHPRIV
+ { "authpriv", LOG_AUTHPRIV },
+#endif
+#ifdef LOG_AUDIT
+ { "audit", LOG_AUDIT },
+#endif
+#ifdef LOG_LFMT
+ { "logalert", LOG_LFMT },
+#endif
+#if LOG_CRON == LOG_CRON1
+ { "cron", LOG_CRON2 },
+#else
+ { "cron2", LOG_CRON2 },
+#endif
+#ifdef LOG_SECURITY
+ { "security", LOG_SECURITY },
+#endif
+ { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 },
+ { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 },
+ { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 },
+ { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 },
+ { NULL, 0 }
+};
+
+
+/*
+ * map a facility number to its name
+ */
+char *
+fac_toname(facpri)
+ int facpri;
+{
+ int i, j, fac;
+
+ fac = facpri & LOG_FACMASK;
+ j = fac >> 3;
+ if (j < (sizeof(facs)/sizeof(facs[0]))) {
+ if (facs[j].value == fac)
+ return facs[j].name;
+ }
+ for (i = 0; facs[i].name; i++)
+ if (fac == facs[i].value)
+ return facs[i].name;
+
+ return NULL;
+}
+
+
+/*
+ * map a facility name to its number
+ */
+int
+fac_findname(name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; facs[i].name; i++)
+ if (!strcmp(facs[i].name, name))
+ return facs[i].value;
+ return -1;
+}
+
+
+table_t pris[] = {
+ { "emerg", LOG_EMERG }, { "alert", LOG_ALERT },
+ { "crit", LOG_CRIT }, { "err", LOG_ERR },
+ { "warn", LOG_WARNING }, { "notice", LOG_NOTICE },
+ { "info", LOG_INFO }, { "debug", LOG_DEBUG },
+ { NULL, 0 }
+};
+
+
+/*
+ * map a facility name to its number
+ */
+int
+pri_findname(name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; pris[i].name; i++)
+ if (!strcmp(pris[i].name, name))
+ return pris[i].value;
+ return -1;
+}
+
+
+/*
+ * map a priority number to its name
+ */
+char *
+pri_toname(facpri)
+ int facpri;
+{
+ int i, pri;
+
+ pri = facpri & LOG_PRIMASK;
+ if (pris[pri].value == pri)
+ return pris[pri].name;
+ for (i = 0; pris[i].name; i++)
+ if (pri == pris[i].value)
+ return pris[i].name;
+ return NULL;
+}
diff --git a/contrib/ipfilter/lib/facpri.h b/contrib/ipfilter/lib/facpri.h
new file mode 100644
index 0000000..54ecabd
--- /dev/null
+++ b/contrib/ipfilter/lib/facpri.h
@@ -0,0 +1,43 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#ifndef __FACPRI_H__
+#define __FACPRI_H__
+
+#ifndef __P
+# define P_DEF
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+extern char *fac_toname __P((int));
+extern int fac_findname __P((char *));
+
+extern char *pri_toname __P((int));
+extern int pri_findname __P((char *));
+
+#ifdef P_DEF
+# undef __P
+# undef P_DEF
+#endif
+
+#if LOG_CRON == (9<<3)
+# define LOG_CRON1 LOG_CRON
+# define LOG_CRON2 (15<<3)
+#endif
+#if LOG_CRON == (15<<3)
+# define LOG_CRON1 (9<<3)
+# define LOG_CRON2 LOG_CRON
+#endif
+
+#endif /* __FACPRI_H__ */
diff --git a/contrib/ipfilter/lib/familyname.c b/contrib/ipfilter/lib/familyname.c
new file mode 100644
index 0000000..35bb975
--- /dev/null
+++ b/contrib/ipfilter/lib/familyname.c
@@ -0,0 +1,12 @@
+#include "ipf.h"
+
+const char *familyname(int family)
+{
+ if (family == AF_INET)
+ return "inet";
+#ifdef AF_INET6
+ if (family == AF_INET6)
+ return "inet6";
+#endif
+ return "unknown";
+}
diff --git a/contrib/ipfilter/lib/fill6bits.c b/contrib/ipfilter/lib/fill6bits.c
new file mode 100644
index 0000000..39ec735
--- /dev/null
+++ b/contrib/ipfilter/lib/fill6bits.c
@@ -0,0 +1,48 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void fill6bits(bits, msk)
+ int bits;
+ u_int *msk;
+{
+ if (bits == 0) {
+ msk[0] = 0;
+ msk[1] = 0;
+ msk[2] = 0;
+ msk[3] = 0;
+ return;
+ }
+
+ msk[0] = 0xffffffff;
+ msk[1] = 0xffffffff;
+ msk[2] = 0xffffffff;
+ msk[3] = 0xffffffff;
+
+ if (bits == 128)
+ return;
+ if (bits > 96) {
+ msk[3] = htonl(msk[3] << (128 - bits));
+ } else if (bits > 64) {
+ msk[3] = 0;
+ msk[2] = htonl(msk[2] << (96 - bits));
+ } else if (bits > 32) {
+ msk[3] = 0;
+ msk[2] = 0;
+ msk[1] = htonl(msk[1] << (64 - bits));
+ } else {
+ msk[3] = 0;
+ msk[2] = 0;
+ msk[1] = 0;
+ msk[0] = htonl(msk[0] << (32 - bits));
+ }
+}
diff --git a/contrib/ipfilter/lib/findword.c b/contrib/ipfilter/lib/findword.c
new file mode 100644
index 0000000..e06f213
--- /dev/null
+++ b/contrib/ipfilter/lib/findword.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: findword.c,v 1.3.4.1 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+
+wordtab_t *findword(words, name)
+ wordtab_t *words;
+ char *name;
+{
+ wordtab_t *w;
+
+ for (w = words; w->w_word != NULL; w++)
+ if (!strcmp(name, w->w_word))
+ break;
+ if (w->w_word == NULL)
+ return NULL;
+
+ return w;
+}
diff --git a/contrib/ipfilter/lib/flags.c b/contrib/ipfilter/lib/flags.c
new file mode 100644
index 0000000..05fcc98
--- /dev/null
+++ b/contrib/ipfilter/lib/flags.c
@@ -0,0 +1,25 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+/*
+ * ECN is a new addition to TCP - RFC 2481
+ */
+#ifndef TH_ECN
+# define TH_ECN 0x40
+#endif
+#ifndef TH_CWR
+# define TH_CWR 0x80
+#endif
+
+char flagset[] = "FSRPAUEC";
+u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG,
+ TH_ECN, TH_CWR };
diff --git a/contrib/ipfilter/lib/freembt.c b/contrib/ipfilter/lib/freembt.c
new file mode 100644
index 0000000..0fc748d
--- /dev/null
+++ b/contrib/ipfilter/lib/freembt.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: freembt.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+void freembt(m)
+ mb_t *m;
+{
+
+ free(m);
+}
diff --git a/contrib/ipfilter/lib/ftov.c b/contrib/ipfilter/lib/ftov.c
new file mode 100644
index 0000000..cb9715d
--- /dev/null
+++ b/contrib/ipfilter/lib/ftov.c
@@ -0,0 +1,16 @@
+#include "ipf.h"
+
+int
+ftov(version)
+ int version;
+{
+#ifdef USE_INET6
+ if (version == AF_INET6)
+ return 6;
+#endif
+ if (version == AF_INET)
+ return 4;
+ if (version == AF_UNSPEC)
+ return 0;
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/gethost.c b/contrib/ipfilter/lib/gethost.c
new file mode 100644
index 0000000..14099e2
--- /dev/null
+++ b/contrib/ipfilter/lib/gethost.c
@@ -0,0 +1,76 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+int gethost(family, name, hostp)
+ int family;
+ char *name;
+ i6addr_t *hostp;
+{
+ struct hostent *h;
+ struct netent *n;
+ u_32_t addr;
+
+ bzero(hostp, sizeof(*hostp));
+ if (!strcmp(name, "test.host.dots")) {
+ if (family == AF_INET) {
+ hostp->in4.s_addr = htonl(0xfedcba98);
+ }
+#ifdef USE_INET6
+ if (family == AF_INET6) {
+ hostp->i6[0] = htonl(0xfe80aa55);
+ hostp->i6[1] = htonl(0x12345678);
+ hostp->i6[2] = htonl(0x5a5aa5a5);
+ hostp->i6[3] = htonl(0xfedcba98);
+ }
+#endif
+ return 0;
+ }
+
+ if (!strcmp(name, "<thishost>"))
+ name = thishost;
+
+ if (family == AF_INET) {
+ h = gethostbyname(name);
+ if (h != NULL) {
+ if ((h->h_addr != NULL) &&
+ (h->h_length == sizeof(addr))) {
+ bcopy(h->h_addr, (char *)&addr, sizeof(addr));
+ hostp->in4.s_addr = addr;
+ return 0;
+ }
+ }
+
+ n = getnetbyname(name);
+ if (n != NULL) {
+ hostp->in4.s_addr = htonl(n->n_net & 0xffffffff);
+ return 0;
+ }
+ }
+#ifdef USE_INET6
+ if (family == AF_INET6) {
+ struct addrinfo hints, *res;
+ struct sockaddr_in6 *sin6;
+
+ bzero((char *)&hints, sizeof(hints));
+ hints.ai_family = PF_INET6;
+
+ getaddrinfo(name, NULL, &hints, &res);
+ if (res != NULL) {
+ sin6 = (struct sockaddr_in6 *)res->ai_addr;
+ hostp->in6 = sin6->sin6_addr;
+ freeaddrinfo(res);
+ return 0;
+ }
+ }
+#endif
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/geticmptype.c b/contrib/ipfilter/lib/geticmptype.c
new file mode 100644
index 0000000..5c962e9
--- /dev/null
+++ b/contrib/ipfilter/lib/geticmptype.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+int geticmptype(family, name)
+ int family;
+ char *name;
+{
+ icmptype_t *i;
+
+ for (i = icmptypelist; i->it_name != NULL; i++) {
+ if (!strcmp(name, i->it_name)) {
+ if (family == AF_INET)
+ return i->it_v4;
+#ifdef USE_INET6
+ if (family == AF_INET6)
+ return i->it_v6;
+#endif
+ return -1;
+ }
+ }
+
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/getifname.c b/contrib/ipfilter/lib/getifname.c
new file mode 100644
index 0000000..88cad32
--- /dev/null
+++ b/contrib/ipfilter/lib/getifname.c
@@ -0,0 +1,95 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+#include "kmem.h"
+
+/*
+ * Given a pointer to an interface in the kernel, return a pointer to a
+ * string which is the interface name.
+ */
+#if 0
+char *getifname(ptr)
+ struct ifnet *ptr;
+{
+#if SOLARIS || defined(__hpux)
+# if SOLARIS
+# include <sys/mutex.h>
+# include <sys/condvar.h>
+# endif
+# ifdef __hpux
+# include "compat.h"
+# endif
+# include "../pfil/qif.h"
+ char *ifname;
+ qif_t qif;
+
+ if ((void *)ptr == (void *)-1)
+ return "!";
+ if (ptr == NULL)
+ return "-";
+
+ if (kmemcpy((char *)&qif, (u_long)ptr, sizeof(qif)) == -1)
+ return "X";
+ ifname = strdup(qif.qf_name);
+ if ((ifname != NULL) && (*ifname == '\0')) {
+ free(ifname);
+ return "!";
+ }
+ return ifname;
+#else
+# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \
+ defined(__OpenBSD__) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
+#else
+ char buf[LIFNAMSIZ];
+ int len;
+# endif
+ struct ifnet netif;
+
+ if ((void *)ptr == (void *)-1)
+ return "!";
+ if (ptr == NULL)
+ return "-";
+
+ if (kmemcpy((char *)&netif, (u_long)ptr, sizeof(netif)) == -1)
+ return "X";
+# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \
+ defined(__OpenBSD__) || defined(linux) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113))
+ return strdup(netif.if_xname);
+# else
+ if (kstrncpy(buf, (u_long)netif.if_name, sizeof(buf)) == -1)
+ return "X";
+ if (netif.if_unit < 10)
+ len = 2;
+ else if (netif.if_unit < 1000)
+ len = 3;
+ else if (netif.if_unit < 10000)
+ len = 4;
+ else
+ len = 5;
+ buf[sizeof(buf) - len] = '\0';
+ sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000);
+ return strdup(buf);
+# endif
+#endif
+}
+#else
+char *getifname(ptr)
+ struct ifnet *ptr;
+{
+#if 0
+ ptr = ptr;
+#endif
+ return "X";
+}
+#endif
diff --git a/contrib/ipfilter/lib/getnattype.c b/contrib/ipfilter/lib/getnattype.c
new file mode 100644
index 0000000..ef7ffd4
--- /dev/null
+++ b/contrib/ipfilter/lib/getnattype.c
@@ -0,0 +1,70 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+#include "ipf.h"
+#include "kmem.h"
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+/*
+ * Get a nat filter type given its kernel address.
+ */
+char *
+getnattype(nat)
+ nat_t *nat;
+{
+ static char unknownbuf[20];
+ char *which;
+
+ if (!nat)
+ return "???";
+
+ switch (nat->nat_redir)
+ {
+ case NAT_MAP :
+ which = "MAP";
+ break;
+ case NAT_MAPBLK :
+ which = "MAP-BLOCK";
+ break;
+ case NAT_REDIRECT :
+ which = "RDR";
+ break;
+ case NAT_MAP|NAT_REWRITE :
+ which = "RWR-MAP";
+ break;
+ case NAT_REDIRECT|NAT_REWRITE :
+ which = "RWR-RDR";
+ break;
+ case NAT_BIMAP :
+ which = "BIMAP";
+ break;
+ case NAT_REDIRECT|NAT_DIVERTUDP :
+ which = "DIV-RDR";
+ break;
+ case NAT_MAP|NAT_DIVERTUDP :
+ which = "DIV-MAP";
+ break;
+ case NAT_REDIRECT|NAT_ENCAP :
+ which = "ENC-RDR";
+ break;
+ case NAT_MAP|NAT_ENCAP :
+ which = "ENC-MAP";
+ break;
+ default :
+ sprintf(unknownbuf, "unknown(%04x)",
+ nat->nat_redir & 0xffffffff);
+ which = unknownbuf;
+ break;
+ }
+ return which;
+}
diff --git a/contrib/ipfilter/lib/getport.c b/contrib/ipfilter/lib/getport.c
new file mode 100644
index 0000000..0981ff1
--- /dev/null
+++ b/contrib/ipfilter/lib/getport.c
@@ -0,0 +1,90 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+int getport(fr, name, port, proto)
+ frentry_t *fr;
+ char *name, *proto;
+ u_short *port;
+{
+ struct protoent *p;
+ struct servent *s;
+ u_short p1;
+
+ if (fr == NULL || fr->fr_type != FR_T_IPF) {
+ s = getservbyname(name, proto);
+ if (s != NULL) {
+ *port = s->s_port;
+ return 0;
+ }
+
+ if (ISDIGIT(*name)) {
+ int portval = atoi(name);
+ if (portval < 0 || portval > 65535)
+ return -1;
+ *port = htons((u_short)portval);
+ return 0;
+ }
+ return -1;
+ }
+
+ /*
+ * Some people will use port names in rules without specifying
+ * either TCP or UDP because it is implied by the group head.
+ * If we don't know the protocol, then the best we can do here is
+ * to take either only the TCP or UDP mapping (if one or the other
+ * is missing) or make sure both of them agree.
+ */
+ if (fr->fr_proto == 0) {
+ s = getservbyname(name, "tcp");
+ if (s != NULL)
+ p1 = s->s_port;
+ else
+ p1 = 0;
+ s = getservbyname(name, "udp");
+ if (s != NULL) {
+ if (p1 != s->s_port)
+ return -1;
+ }
+ if ((p1 == 0) && (s == NULL))
+ return -1;
+ if (p1)
+ *port = p1;
+ else
+ *port = s->s_port;
+ return 0;
+ }
+
+ if ((fr->fr_flx & FI_TCPUDP) != 0) {
+ /*
+ * If a rule is "tcp/udp" then check that both TCP and UDP
+ * mappings for this protocol name match ports.
+ */
+ s = getservbyname(name, "tcp");
+ if (s == NULL)
+ return -1;
+ p1 = s->s_port;
+ s = getservbyname(name, "udp");
+ if (s == NULL || s->s_port != p1)
+ return -1;
+ *port = p1;
+ return 0;
+ }
+
+ p = getprotobynumber(fr->fr_proto);
+ s = getservbyname(name, p ? p->p_name : NULL);
+ if (s != NULL) {
+ *port = s->s_port;
+ return 0;
+ }
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/getportproto.c b/contrib/ipfilter/lib/getportproto.c
new file mode 100644
index 0000000..69fecff
--- /dev/null
+++ b/contrib/ipfilter/lib/getportproto.c
@@ -0,0 +1,40 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <ctype.h>
+#include "ipf.h"
+
+int getportproto(name, proto)
+ char *name;
+ int proto;
+{
+ struct servent *s;
+ struct protoent *p;
+
+ if (ISDIGIT(*name)) {
+ int number;
+ char *s;
+
+ for (s = name; *s != '\0'; s++)
+ if (!ISDIGIT(*s))
+ return -1;
+
+ number = atoi(name);
+ if (number < 0 || number > 65535)
+ return -1;
+ return htons(number);
+ }
+
+ p = getprotobynumber(proto);
+ s = getservbyname(name, p ? p->p_name : NULL);
+ if (s != NULL)
+ return s->s_port;
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/getproto.c b/contrib/ipfilter/lib/getproto.c
new file mode 100644
index 0000000..6c52cd3
--- /dev/null
+++ b/contrib/ipfilter/lib/getproto.c
@@ -0,0 +1,41 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+int getproto(name)
+ char *name;
+{
+ struct protoent *p;
+ char *s;
+
+ for (s = name; *s != '\0'; s++)
+ if (!ISDIGIT(*s))
+ break;
+ if (*s == '\0')
+ return atoi(name);
+
+#ifdef _AIX51
+ /*
+ * For some bogus reason, "ip" is 252 in /etc/protocols on AIX 5
+ * The IANA has doubled up on the definition of 0 - it is now also
+ * used for IPv6 hop-opts, so we can no longer rely on /etc/protocols
+ * providing the correct name->number mapping
+ */
+#endif
+ if (!strcasecmp(name, "ip"))
+ return 0;
+
+ p = getprotobyname(name);
+ if (p != NULL)
+ return p->p_proto;
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/getsumd.c b/contrib/ipfilter/lib/getsumd.c
new file mode 100644
index 0000000..84acc7a
--- /dev/null
+++ b/contrib/ipfilter/lib/getsumd.c
@@ -0,0 +1,23 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+char *getsumd(sum)
+ u_32_t sum;
+{
+ static char sumdbuf[17];
+
+ if (sum & NAT_HW_CKSUM)
+ sprintf(sumdbuf, "hw(%#0x)", sum & 0xffff);
+ else
+ sprintf(sumdbuf, "%#0x", sum);
+ return sumdbuf;
+}
diff --git a/contrib/ipfilter/lib/hostname.c b/contrib/ipfilter/lib/hostname.c
new file mode 100644
index 0000000..28ead89
--- /dev/null
+++ b/contrib/ipfilter/lib/hostname.c
@@ -0,0 +1,60 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+char *hostname(family, ip)
+ int family;
+ void *ip;
+{
+ static char hostbuf[MAXHOSTNAMELEN+1];
+ struct hostent *hp;
+ struct in_addr ipa;
+ struct netent *np;
+
+ memset(&ipa, 0, sizeof(ipa)); /* XXX gcc */
+
+ if (family == AF_INET) {
+ ipa.s_addr = *(u_32_t *)ip;
+ if (ipa.s_addr == htonl(0xfedcba98))
+ return "test.host.dots";
+ }
+
+ if ((opts & OPT_NORESOLVE) == 0) {
+ if (family == AF_INET) {
+ hp = gethostbyaddr(ip, 4, AF_INET);
+ if (hp != NULL && hp->h_name != NULL &&
+ *hp->h_name != '\0') {
+ strncpy(hostbuf, hp->h_name, sizeof(hostbuf));
+ hostbuf[sizeof(hostbuf) - 1] = '\0';
+ return hostbuf;
+ }
+
+ np = getnetbyaddr(ipa.s_addr, AF_INET);
+ if (np != NULL && np->n_name != NULL &&
+ *np->n_name != '\0') {
+ strncpy(hostbuf, np->n_name, sizeof(hostbuf));
+ hostbuf[sizeof(hostbuf) - 1] = '\0';
+ return hostbuf;
+ }
+ }
+ }
+
+ if (family == AF_INET) {
+ return inet_ntoa(ipa);
+ }
+#ifdef USE_INET6
+ (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1);
+ hostbuf[MAXHOSTNAMELEN] = '\0';
+ return hostbuf;
+#else
+ return "IPv6";
+#endif
+}
diff --git a/contrib/ipfilter/lib/icmpcode.c b/contrib/ipfilter/lib/icmpcode.c
new file mode 100644
index 0000000..e898ebf
--- /dev/null
+++ b/contrib/ipfilter/lib/icmpcode.c
@@ -0,0 +1,24 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <ctype.h>
+
+#include "ipf.h"
+
+#ifndef MIN
+# define MIN(a,b) ((a) > (b) ? (b) : (a))
+#endif
+
+
+char *icmpcodes[MAX_ICMPCODE + 1] = {
+ "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail",
+ "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib",
+ "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff",
+ NULL };
diff --git a/contrib/ipfilter/lib/icmptypename.c b/contrib/ipfilter/lib/icmptypename.c
new file mode 100644
index 0000000..d7eb3bd
--- /dev/null
+++ b/contrib/ipfilter/lib/icmptypename.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+char *icmptypename(family, type)
+ int family, type;
+{
+ icmptype_t *i;
+
+ if ((type < 0) || (type > 255))
+ return NULL;
+
+ for (i = icmptypelist; i->it_name != NULL; i++) {
+ if ((family == AF_INET) && (i->it_v4 == type))
+ return i->it_name;
+#ifdef USE_INET6
+ if ((family == AF_INET6) && (i->it_v6 == type))
+ return i->it_name;
+#endif
+ }
+
+ return NULL;
+}
diff --git a/contrib/ipfilter/lib/icmptypes.c b/contrib/ipfilter/lib/icmptypes.c
new file mode 100644
index 0000000..c1123ff
--- /dev/null
+++ b/contrib/ipfilter/lib/icmptypes.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+#ifndef USE_INET6
+# undef ICMP6_ECHO_REQUEST
+# define ICMP6_ECHO_REQUEST 0
+# undef ICMP6_ECHO_REPLY
+# define ICMP6_ECHO_REPLY 0
+# undef ICMP6_NI_QUERY
+# define ICMP6_NI_QUERY 0
+# undef ICMP6_NI_REPLY
+# define ICMP6_NI_REPLY 0
+# undef ICMP6_PARAM_PROB
+# define ICMP6_PARAM_PROB 0
+# undef ND_ROUTER_ADVERT
+# define ND_ROUTER_ADVERT 0
+# undef ND_ROUTER_SOLICIT
+# define ND_ROUTER_SOLICIT 0
+# undef ICMP6_TIME_EXCEEDED
+# define ICMP6_TIME_EXCEEDED 0
+# undef ICMP6_DST_UNREACH
+# define ICMP6_DST_UNREACH 0
+# undef ICMP6_PACKET_TOO_BIG
+# define ICMP6_PACKET_TOO_BIG 0
+# undef MLD_LISTENER_QUERY
+# define MLD_LISTENER_QUERY 0
+# undef MLD_LISTENER_REPORT
+# define MLD_LISTENER_REPORT 0
+# undef MLD_LISTENER_DONE
+# define MLD_LISTENER_DONE 0
+# undef ICMP6_MEMBERSHIP_QUERY
+# define ICMP6_MEMBERSHIP_QUERY 0
+# undef ICMP6_MEMBERSHIP_REPORT
+# define ICMP6_MEMBERSHIP_REPORT 0
+# undef ICMP6_MEMBERSHIP_REDUCTION
+# define ICMP6_MEMBERSHIP_REDUCTION 0
+# undef ND_NEIGHBOR_ADVERT
+# define ND_NEIGHBOR_ADVERT 0
+# undef ND_NEIGHBOR_SOLICIT
+# define ND_NEIGHBOR_SOLICIT 0
+# undef ICMP6_ROUTER_RENUMBERING
+# define ICMP6_ROUTER_RENUMBERING 0
+# undef ICMP6_WRUREQUEST
+# define ICMP6_WRUREQUEST 0
+# undef ICMP6_WRUREPLY
+# define ICMP6_WRUREPLY 0
+# undef ICMP6_FQDN_QUERY
+# define ICMP6_FQDN_QUERY 0
+# undef ICMP6_FQDN_REPLY
+# define ICMP6_FQDN_REPLY 0
+#else
+# if !defined(MLD_LISTENER_QUERY)
+# define MLD_LISTENER_QUERY 130
+# endif
+# if !defined(MLD_LISTENER_REPORT)
+# define MLD_LISTENER_REPORT 131
+# endif
+# if !defined(MLD_LISTENER_DONE)
+# define MLD_LISTENER_DONE 132
+# endif
+# if defined(MLD_LISTENER_REDUCTION) && !defined(MLD_LISTENER_DONE)
+# define MLD_LISTENER_DONE MLD_LISTENER_REDUCTION
+# endif
+#endif
+
+icmptype_t icmptypelist[] = {
+ { "echo", ICMP_ECHO, ICMP6_ECHO_REQUEST },
+ { "echorep", ICMP_ECHOREPLY, ICMP6_ECHO_REPLY },
+ { "fqdnquery", -1, ICMP6_FQDN_QUERY },
+ { "fqdnreply", -1, ICMP6_FQDN_REPLY },
+ { "infoqry", -1, ICMP6_NI_QUERY },
+ { "inforeq", ICMP_IREQ, ICMP6_NI_QUERY },
+ { "inforep", ICMP_IREQREPLY, ICMP6_NI_REPLY },
+ { "listendone", -1, MLD_LISTENER_DONE },
+ { "listenqry", -1, MLD_LISTENER_QUERY },
+ { "listenrep", -1, MLD_LISTENER_REPORT },
+ { "maskrep", ICMP_MASKREPLY, -1 },
+ { "maskreq", ICMP_MASKREQ, -1 },
+ { "memberqry", -1, ICMP6_MEMBERSHIP_QUERY },
+ { "memberred", -1, ICMP6_MEMBERSHIP_REDUCTION },
+ { "memberreply",-1, ICMP6_MEMBERSHIP_REPORT },
+ { "neighadvert", -1, ND_NEIGHBOR_ADVERT },
+ { "neighborsol", -1, ND_NEIGHBOR_SOLICIT },
+ { "neighborsolicit", -1, ND_NEIGHBOR_SOLICIT },
+ { "paramprob", ICMP_PARAMPROB, ICMP6_PARAM_PROB },
+ { "redir", ICMP_REDIRECT, ND_REDIRECT },
+ { "renumber", -1, ICMP6_ROUTER_RENUMBERING },
+ { "routerad", ICMP_ROUTERADVERT, ND_ROUTER_ADVERT },
+ { "routeradvert",ICMP_ROUTERADVERT, ND_ROUTER_ADVERT },
+ { "routersol", ICMP_ROUTERSOLICIT, ND_ROUTER_SOLICIT },
+ { "routersolcit",ICMP_ROUTERSOLICIT, ND_ROUTER_SOLICIT },
+ { "squench", ICMP_SOURCEQUENCH, -1 },
+ { "timest", ICMP_TSTAMP, -1 },
+ { "timestrep", ICMP_TSTAMPREPLY, -1 },
+ { "timex", ICMP_TIMXCEED, ICMP6_TIME_EXCEEDED },
+ { "toobig", -1, ICMP6_PACKET_TOO_BIG },
+ { "unreach", ICMP_UNREACH, ICMP6_DST_UNREACH },
+ { "whorep", -1, ICMP6_WRUREPLY },
+ { "whoreq", -1, ICMP6_WRUREQUEST },
+ { NULL, -1, -1 }
+};
diff --git a/contrib/ipfilter/lib/inet_addr.c b/contrib/ipfilter/lib/inet_addr.c
new file mode 100644
index 0000000..c7ae443
--- /dev/null
+++ b/contrib/ipfilter/lib/inet_addr.c
@@ -0,0 +1,210 @@
+/* $FreeBSD$ */
+
+/*
+ * ++Copyright++ 1983, 1990, 1993
+ * -
+ * Copyright (c) 1983, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
+static const char rcsid[] = "@(#)$Id: inet_addr.c,v 1.8.2.3 2004/12/09 19:41:20 darrenr Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+#ifndef linux
+int inet_aton __P((const char *, struct in_addr *));
+
+/*
+ * Because the ctype(3) posix definition, if used "safely" in code everywhere,
+ * would mean all normal code that walks through strings needed casts. Yuck.
+ */
+#define ISALNUM(x) isalnum((u_char)(x))
+#define ISALPHA(x) isalpha((u_char)(x))
+#define ISASCII(x) isascii((u_char)(x))
+#define ISDIGIT(x) isdigit((u_char)(x))
+#define ISPRINT(x) isprint((u_char)(x))
+#define ISSPACE(x) isspace((u_char)(x))
+#define ISUPPER(x) isupper((u_char)(x))
+#define ISXDIGIT(x) isxdigit((u_char)(x))
+#define ISLOWER(x) islower((u_char)(x))
+
+/*
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inet_aton(cp, addr)
+ register const char *cp;
+ struct in_addr *addr;
+{
+ register u_long val;
+ register int base, n;
+ register char c;
+ u_int parts[4];
+ register u_int *pp = parts;
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!ISDIGIT(c))
+ return (0);
+ val = 0; base = 10;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X')
+ base = 16, c = *++cp;
+ else
+ base = 8;
+ }
+ for (;;) {
+ if (ISASCII(c) && ISDIGIT(c)) {
+ val = (val * base) + (c - '0');
+ c = *++cp;
+ } else if (base == 16 && ISASCII(c) && ISXDIGIT(c)) {
+ val = (val << 4) |
+ (c + 10 - (ISLOWER(c) ? 'a' : 'A'));
+ c = *++cp;
+ } else
+ break;
+ }
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3)
+ return (0);
+ *pp++ = val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!ISASCII(c) || !ISSPACE(c)))
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+
+ case 0:
+ return (0); /* initial nondigit */
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+#endif
+
+/* these are compatibility routines, not needed on recent BSD releases */
+
+/*
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+#if 0
+inet_addr(cp)
+ const char *cp;
+{
+ struct in_addr val;
+
+ if (inet_aton(cp, &val))
+ return (val.s_addr);
+ return (0xffffffff);
+}
+#endif
diff --git a/contrib/ipfilter/lib/initparse.c b/contrib/ipfilter/lib/initparse.c
new file mode 100644
index 0000000..a16ac0f
--- /dev/null
+++ b/contrib/ipfilter/lib/initparse.c
@@ -0,0 +1,20 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+char thishost[MAXHOSTNAMELEN];
+
+
+void initparse __P((void))
+{
+ gethostname(thishost, sizeof(thishost));
+ thishost[sizeof(thishost) - 1] = '\0';
+}
diff --git a/contrib/ipfilter/lib/interror.c b/contrib/ipfilter/lib/interror.c
new file mode 100644
index 0000000..c13f5f8
--- /dev/null
+++ b/contrib/ipfilter/lib/interror.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: interror.c,v 1.9.2.12 2012/07/22 08:03:39 darren_r Exp $
+ */
+
+#include "ipf.h"
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+typedef struct {
+ int iee_number;
+ char *iee_text;
+} ipf_error_entry_t;
+
+static ipf_error_entry_t *find_error __P((int));
+
+#define IPF_NUM_ERRORS 475
+
+/*
+ * NO REUSE OF NUMBERS!
+ *
+ * IF YOU WANT TO ADD AN ERROR TO THIS TABLE, _ADD_ A NEW NUMBER.
+ * DO _NOT_ USE AN EMPTY NUMBER OR FILL IN A GAP.
+ */
+static ipf_error_entry_t ipf_errors[IPF_NUM_ERRORS] = {
+ { 1, "auth table locked/full" },
+ { 2, "" },
+ { 3, "copyinptr received bad address" },
+ { 4, "copyoutptr received bad address" },
+ { 5, "" },
+ { 6, "cannot load a rule with FR_T_BUILTIN flag set" },
+ { 7, "internal rule without FR_T_BUILDINT flag set" },
+ { 8, "no data provided with filter rule" },
+ { 9, "invalid ioctl for rule" },
+ { 10, "rule protocol is not 4 or 6" },
+ { 11, "cannot find rule function" },
+ { 12, "cannot find rule group" },
+ { 13, "group in/out does not match rule in/out" },
+ { 14, "rule without in/out does not belong to a group" },
+ { 15, "cannot determine where to append rule" },
+ { 16, "malloc for rule data failed" },
+ { 17, "copyin for rule data failed" },
+ { 18, "" },
+ { 19, "zero data size for BPF rule" },
+ { 20, "BPF validation failed" },
+ { 21, "incorrect data size for IPF rule" },
+ { 22, "'keep state' rule included 'with oow'" },
+ { 23, "bad interface index with dynamic source address" },
+ { 24, "bad interface index with dynamic dest. address" },
+ { 25, "match array verif failed for filter rule" },
+ { 26, "bad filter rule type" },
+ { 27, "rule not found for zero'stats" },
+ { 28, "copyout failed for zero'ing stats" },
+ { 29, "rule not found for removing" },
+ { 30, "cannot remove internal rule" },
+ { 31, "rule in use" },
+ { 32, "rule already exists" },
+ { 33, "no memory for another rule" },
+ { 34, "could not find function" },
+ { 35, "copyout failed for resolving function name -> addr" },
+ { 36, "copyout failed for resolving function addr -> name" },
+ { 37, "function name/addr resolving search failed" },
+ { 38, "group map cannot find it's hash table" },
+ { 39, "group map hash-table in/out do not match rule" },
+ { 40, "bcopyout failed for SIOCIPFINTERROR" },
+ { 41, "" },
+ { 42, "ipfilter not enabled for NAT ioctl" },
+ { 43, "ipfilter not enabled for state ioctl" },
+ { 44, "ipfilter not enabled for auth ioctl" },
+ { 45, "ipfilter not enbaled for sync ioctl" },
+ { 46, "ipfilter not enabled for scan ioctl" },
+ { 47, "ipfilter not enabled for lookup ioctl" },
+ { 48, "unrecognised device minor number for ioctl" },
+ { 49, "unrecognised object type for copying in ipfobj" },
+ { 50, "mismatching object type for copying in ipfobj" },
+ { 51, "object size too small for copying in ipfobj" },
+ { 52, "object size mismatch for copying in ipfobj" },
+ { 53, "compat object size too small for copying in ipfobj" },
+ { 54, "compat object size mismatch for copying in ipfobj" },
+ { 55, "error doing copyin of data for in ipfobj" },
+ { 56, "unrecognised object type for size copy in ipfobj" },
+ { 57, "object size too small for size copy in ipfobj" },
+ { 58, "mismatching object type for size copy in ipfobj" },
+ { 59, "object size mismatch for size copy in ipfobj" },
+ { 60, "compat object size mismatch for size copy in ipfobj" },
+ { 61, "error doing size copyin of data for in ipfobj" },
+ { 62, "bad object type for size copy out ipfobj" },
+ { 63, "mismatching object type for size copy out ipfobj" },
+ { 64, "object size mismatch for size copy out ipfobj" },
+ { 65, "compat object size wrong for size copy out ipfobj" },
+ { 66, "error doing size copyout of data for out ipfobj" },
+ { 67, "unrecognised object type for copying out ipfobj" },
+ { 68, "mismatching object type for copying out ipfobj" },
+ { 69, "object size too small for copying out ipfobj" },
+ { 70, "object size mismatch for copying out ipfobj" },
+ { 71, "compat object size too small for copying out ipfobj" },
+ { 72, "compat object size mismatch for copying out ipfobj" },
+ { 73, "error doing copyout of data for out ipfobj" },
+ { 74, "attempt to add existing tunable name" },
+ { 75, "cannot find tunable name to delete" },
+ { 76, "internal data too big for next tunable" },
+ { 77, "could not find tunable" },
+ { 78, "tunable can only be changed when ipfilter disabled" },
+ { 79, "new tunable value outside accepted range" },
+ { 80, "ipftune called for unrecognised ioctl" },
+ { 81, "" },
+ { 82, "could not find token to delete" },
+ { 83, "" },
+ { 84, "attempt to get next rule when no more exist" },
+ { 85, "value for iri_inout outside accepted range" },
+ { 86, "value for iri_active outside accepted range" },
+ { 87, "value for iri_nrules is 0" },
+ { 88, "NULL pointer specified for where to copy rule to" },
+ { 89, "copyout of rule failed" },
+ { 90, "" },
+ { 91, "could not get token for rule iteration" },
+ { 92, "unrecognised generic iterator" },
+ { 93, "could not find token for generic iterator" },
+ { 94, "need write permissions to disable/enable ipfilter" },
+ { 95, "error copying in enable/disable value" },
+ { 96, "need write permissions to set ipf tunable" },
+ { 97, "need write permissions to set ipf flags" },
+ { 98, "error doing copyin of ipf flags" },
+ { 99, "error doing copyout of ipf flags" },
+ { 100, "need write permissions to add another rule" },
+ { 101, "need write permissions to insert another rule" },
+ { 102, "need write permissions to swap active rule set" },
+ { 103, "error copying out current active rule set" },
+ { 104, "need write permissions to zero ipf stats" },
+ { 105, "need write permissions to flush ipf v4 rules" },
+ { 106, "error copying out v4 flush results" },
+ { 107, "error copying in v4 flush command" },
+ { 108, "need write permissions to flush ipf v6 rules" },
+ { 109, "error copying out v6 flush results" },
+ { 110, "error copying in v6 flush command" },
+ { 111, "error copying in new lock state for ipfilter" },
+ { 112, "need write permissions to flush ipf logs" },
+ { 113, "error copying out results of log flush" },
+ { 114, "need write permissions to resync ipf" },
+ { 115, "unrecognised ipf ioctl" },
+ { 116, "error copying in match array" },
+ { 117, "match array type is not IPFOBJ_IPFEXPR" },
+ { 118, "bad size for match array" },
+ { 119, "cannot allocate memory for match aray" },
+ { 120, "error copying in match array" },
+ { 121, "error verifying contents of match array" },
+ { 122, "need write permissions to set ipf lock status" },
+ { 123, "error copying in data for function resolution" },
+ { 124, "error copying in ipfobj structure" },
+ { 125, "error copying in ipfobj structure" },
+ { 126, "error copying in ipfobj structure" },
+ { 127, "error copying in ipfobj structure" },
+ { 128, "no memory for filter rule comment" },
+ { 129, "error copying in filter rule comment" },
+ { 130, "error copying out filter rule comment" },
+ { 131, "no memory for new rule alloc buffer" },
+ { 132, "cannot find source lookup pool" },
+ { 133, "unknown source address type" },
+ { 134, "cannot find destination lookup pool" },
+ { 135, "unknown destination address type" },
+ { 136, "icmp head group name index incorrect" },
+ { 137, "group head name index incorrect" },
+ { 138, "group name index incorrect" },
+ { 139, "to interface name index incorrect" },
+ { 140, "dup-to interface name index incorrect" },
+ { 141, "reply-to interface name index incorrect" },
+ { 142, "could not initialise call now function" },
+ { 143, "could not initialise call function" },
+ { 144, "could not find destination list" },
+ { 145, "auth rules cannot have dup/to/fastroute" },
+ { 146, "incorrect size for object to copy out" },
+ { 147, "object type out of bounds for kernel copyout" },
+ { 148, "object size too small for kernel copyout" },
+ { 149, "object size validation failed for kernel copyout" },
+ { 150, "error copying data out for kernel copyout" },
+ { 151, "version mismatch for kernel copyout" },
+/* -------------------------------------------------------------------------- */
+ { 10001, "could not find token for auth iterator" },
+ { 10002, "write permissions require to add/remove auth rule" },
+ { 10003, "need write permissions to set auth lock" },
+ { 10004, "error copying out results of auth flush" },
+ { 10005, "unknown auth ioctl" },
+ { 10006, "can only append or remove preauth rules" },
+ { 10007, "NULL pointers passed in for preauth remove" },
+ { 10008, "preauth rule not found to remove" },
+ { 10009, "could not malloc memory for preauth entry" },
+ { 10010, "unrecognised preauth rule ioctl command" },
+ { 10011, "iterator data supplied with NULL pointer" },
+ { 10012, "unknown auth iterator type" },
+ { 10013, "iterator error copying out auth data" },
+ { 10014, "sleep waiting for auth packet interrupted" },
+ { 10015, "bad index supplied in auth reply" },
+ { 10016, "error injecting outbound packet back into kernel" },
+ { 10017, "error injecting inbound packet back into kernel" },
+ { 10018, "could not attempt to inject packet back into kernel" },
+ { 10019, "packet id does not match" },
+/* -------------------------------------------------------------------------- */
+ { 20001, "invalid frag token data pointer supplied" },
+ { 20002, "error copying out frag token data" },
+ { 20003, "can only copy one fragment state entry at a time" },
+/* -------------------------------------------------------------------------- */
+ { 30001, "incorrect object size to get hash table stats" },
+ { 30002, "could not malloc memory for new hash table" },
+ { 30003, "error coping in hash table structure" },
+ { 30004, "hash table already exists" },
+ { 30005, "mismach between new hash table and operation unit" },
+ { 30006, "could not malloc memory for hash table base" },
+ { 30007, "could not find hash table" },
+ { 30008, "mismatch between hash table and operation unit" },
+ { 30009, "could not find hash table for iterators next node" },
+ { 30010, "unknown iterator tpe" },
+ { 30011, "iterator error copying out hash table" },
+ { 30012, "iterator error copying out hash table entry" },
+ { 30013, "error copying out hash table statistics" },
+ { 30014, "table node delete structure wrong size" },
+ { 30015, "error copying in node to delete" },
+ { 30016, "table to delete node from does not exist" },
+ { 30017, "could not find table to remove node from" },
+ { 30018, "table node add structure wrong size" },
+ { 30019, "error copying in node to add" },
+ { 30020, "could not find table to add node to" },
+ { 30021, "node already exists in the table" },
+ { 30022, "could not find node to delete in table" },
+ { 30023, "uid mismatch on node to delete" },
+ { 30024, "object size incorrect for hash table" },
+ { 30025, "hash table size must be at least 1"},
+ { 30026, "cannot allocate memory for hash table context" },
+/* -------------------------------------------------------------------------- */
+ { 40001, "invalid minor device numebr for log read" },
+ { 40002, "read size too small" },
+ { 40003, "interrupted waiting for log data to read" },
+ { 40004, "interrupted waiting for log data to read" },
+ { 40005, "read size too large" },
+ { 40006, "uiomove for read operation failed" },
+/* -------------------------------------------------------------------------- */
+ { 50001, "unknown lookup ioctl" },
+ { 50002, "error copying in object data for add node" },
+ { 50003, "invalid unit for lookup add node" },
+ { 50004, "incorrect size for adding a pool node" },
+ { 50005, "error copying in pool node structure" },
+ { 50006, "mismatch in pool node address/mask families" },
+ { 50007, "could not find pool name" },
+ { 50008, "node already exists in pool" },
+ { 50009, "incorrect size for adding a hash node" },
+ { 50010, "error copying in hash node structure" },
+ { 50011, "could not find hash table name" },
+ { 50012, "unrecognised object type for lookup add node" },
+ { 50013, "invalid unit for lookup delete node" },
+ { 50014, "incorrect size for deleting a pool node" },
+ { 50015, "error copying in pool node structure" },
+ { 50016, "could not find pool name" },
+ { 50017, "could not find pool node" },
+ { 50018, "incorrect size for removing a hash node" },
+ { 50019, "error copying in hash node structure" },
+ { 50020, "could not find hash table name" },
+ { 50021, "unrecognised object type for lookup delete node" },
+ { 50022, "error copying in add table data" },
+ { 50023, "invalid unit for lookup add table" },
+ { 50024, "pool name already exists" },
+ { 50025, "hash table name already exists" },
+ { 50026, "unrecognised object type for lookup add table" },
+ { 50027, "error copying table data back out" },
+ { 50028, "error copying in remove table data" },
+ { 50029, "invalid unit for lookup remove table" },
+ { 50030, "unrecognised object type for lookup remove table" },
+ { 50031, "error copying in lookup stats structure" },
+ { 50032, "invalid unit for lookup stats" },
+ { 50033, "unrecognised object type for lookup stats" },
+ { 50034, "error copying in flush lookup data" },
+ { 50035, "invalid unit for lookup flush" },
+ { 50036, "incorrect table type for lookup flush" },
+ { 50037, "error copying out lookup flush results" },
+ { 50038, "invalid unit for lookup iterator" },
+ { 50039, "invalid unit for lookup iterator" },
+ { 50040, "could not find token for lookup iterator" },
+ { 50041, "unrecognised object type for lookup interator" },
+ { 50042, "error copying in lookup delete node operation" },
+/* -------------------------------------------------------------------------- */
+ { 60001, "insufficient privilege for NAT write operation" },
+ { 60002, "need write permissions to flush NAT logs" },
+ { 60003, "need write permissions to turn NAT logging on/off" },
+ { 60004, "error copying out current NAT log setting" },
+ { 60005, "error copying out bytes waiting to be read in NAT \
+log" },
+ { 60006, "need write permissions to add NAT rule" },
+ { 60007, "NAT rule already exists" },
+ { 60008, "could not allocate memory for NAT rule" },
+ { 60009, "need write permissions to remove NAT rule" },
+ { 60010, "NAT rule could not be found" },
+ { 60011, "could not find NAT entry for redirect lookup" },
+ { 60012, "need write permissions to flush NAT table" },
+ { 60013, "error copying in NAT flush command" },
+ { 60014, "need write permissions to do matching NAT flush" },
+ { 60015, "need write permissions to set NAT lock" },
+ { 60016, "need write permissions to add entry to NAT table" },
+ { 60017, "NAT not locked for size retrieval" },
+ { 60018, "NAT not locked for fetching NAT table entry" },
+ { 60019, "error copying in NAT token data for deletion" },
+ { 60020, "unknown NAT ioctl" },
+ { 60021, "" },
+ { 60022, "resolving proxy name in NAT rule failed" },
+ { 60023, "only reply age specified in NAT rule" },
+ { 60024, "error doing copyin to determine NAT entry size" },
+ { 60025, "error copying out NAT size of 0" },
+ { 60026, "NAT entry not found" },
+ { 60027, "error doing copyout of NAT entry size" },
+ { 60028, "invalid data size for getting NAT entry" },
+ { 60029, "could not malloc temporary space for NAT entry" },
+ { 60030, "no NAT table entries present" },
+ { 60031, "NAT entry to get next from not found" },
+ { 60032, "not enough space for proxy structure" },
+ { 60033, "not enough space for private proxy data" },
+ { 60034, "NAT entry size is too large" },
+ { 60035, "could not malloc memory for NAT entry sratch space" },
+ { 60036, "" },
+ { 60037, "could not malloc memory for NAT entry" },
+ { 60038, "could not malloc memory for NAT entry rule" },
+ { 60039, "could not resolve NAT entry rule's proxy" },
+ { 60040, "cannot add outbound duplicate NAT entry" },
+ { 60041, "cannot add inbound duplicate NAT entry" },
+ { 60042, "cannot add NAT entry that is neither IN nor OUT" },
+ { 60043, "could not malloc memory for NAT proxy data" },
+ { 60044, "proxy data size too big" },
+ { 60045, "could not malloc proxy private data for NAT entry" },
+ { 60046, "could not malloc memory for new NAT filter rule" },
+ { 60047, "could not find existing filter rule for NAT entry" },
+ { 60048, "insertion into NAT table failed" },
+ { 60049, "iterator error copying out hostmap data" },
+ { 60050, "iterator error copying out NAT rule data" },
+ { 60051, "iterator error copying out NAT entry data" },
+ { 60052, "iterator data supplied with NULL pointer" },
+ { 60053, "unknown NAT iterator type" },
+ { 60054, "unknwon next address type" },
+ { 60055, "iterator suppled with unknown type for get-next" },
+ { 60056, "unknown lookup group for next address" },
+ { 60057, "error copying out NAT log flush results" },
+ { 60058, "bucket table type is incorrect" },
+ { 60059, "error copying out NAT bucket table" },
+ { 60060, "function not found for lookup" },
+ { 60061, "address family not supported with SIOCSTPUT" },
+ { 60062, "unknown timeout name" },
+ { 60063, "cannot allocate new inbound NAT entry table" },
+ { 60064, "cannot allocate new outbound NAT entry table" },
+ { 60065, "cannot allocate new inbound NAT bucketlen table" },
+ { 60066, "cannot allocate new outbound NAT bucketlen table" },
+ { 60067, "cannot allocate new NAT rules table" },
+ { 60068, "cannot allocate new NAT hostmap table" },
+ { 60069, "new source lookup type is not dstlist" },
+ { 60070, "cannot allocate NAT rule scratch space" },
+ { 60071, "new destination lookup type is not dstlist" },
+ { 60072, "function not found for lookup (ipv6)" },
+ { 60073, "unknown lookup group for next address (ipv6)" },
+ { 60074, "unknown next address type (ipv6)" },
+ { 60075, "one object at a time must be copied" },
+/* -------------------------------------------------------------------------- */
+ { 70001, "incorrect object size to get pool stats" },
+ { 70002, "could not malloc memory for new pool node" },
+ { 70003, "invalid addresss length for new pool node" },
+ { 70004, "invalid mask length for new pool node" },
+ { 70005, "error adding node to pool" },
+ { 70006, "pool already exists" },
+ { 70007, "could not malloc memory for new pool" },
+ { 70008, "could not allocate radix tree for new pool" },
+ { 70009, "could not find pool" },
+ { 70010, "unknown pool name for iteration" },
+ { 70011, "unknown pool iterator" },
+ { 70012, "error copying out pool head" },
+ { 70013, "error copying out pool node" },
+ { 70014, "add node size incorrect" },
+ { 70015, "error copying in pool node" },
+ { 70016, "" },
+ { 70017, "cannot find pool for node" },
+ { 70018, "node entry already present in pool" },
+ { 70019, "delete node size incorrect" },
+ { 70020, "error copying in node to delete" },
+ { 70021, "cannot find pool to delete node from" },
+ { 70022, "cannot find node to delete in pool" },
+ { 70023, "pool name already exists" },
+ { 70024, "uid mismatch for node removal" },
+ { 70025, "stats device unit is invalid" },
+ { 70026, "error copying out statistics" },
+ { 70027, "could not remove node from radix tree" },
+ { 70028, "incorrect address length in pool node add" },
+ { 70029, "incorrect mask length in pool node add" },
+ { 70030, "incorrect address length in pool node remove" },
+ { 70031, "incorrect mask length in pool node remove" },
+ { 70032, "cannot allocate memory for pool context" },
+ { 70033, "cannot allocate memory for radix tree context" },
+ { 70034, "adding IPv6 node with incorrect address length" },
+ { 70035, "IPv4 address not masked" },
+ { 70036, "IPv6 address not masked" },
+ { 70037, "removing IPv6 node with incorrect address length" },
+/* -------------------------------------------------------------------------- */
+ { 80001, "could not find proxy" },
+ { 80002, "proxy does not support control operations" },
+ { 80003, "could not allocate data to hold proxy operation" },
+ { 80004, "unknown proxy ioctl" },
+ { 80005, "could not copyin proxy control structure" },
+ { 80006, "DNS proxy could not find rule to delete" },
+ { 80007, "DNS proxy found existing matching rule" },
+ { 80008, "DNS proxy could not allocate memory for new rule" },
+ { 80009, "DNS proxy unknown command request" },
+/* -------------------------------------------------------------------------- */
+ { 90001, "could not malloc space for new scan structure" },
+ { 90002, "scan tag already exists" },
+ { 90003, "scan structure in use" },
+ { 90004, "could not find matching scan tag for filter rule" },
+ { 90005, "could not copyout scan statistics" },
+/* -------------------------------------------------------------------------- */
+ { 100001, "cannot find matching state entry to remove" },
+ { 100002, "error copying in v4 state flush command" },
+ { 100003, "error copying out v4 state flush results" },
+ { 100004, "error copying in v6 state flush command" },
+ { 100005, "error copying out v6 state flush results" },
+ { 100006, "" },
+ { 100007, "" },
+ { 100008, "need write permissions to flush state log" },
+ { 100009, "erorr copyout results of flushing state log" },
+ { 100010, "need write permissions to turn state logging on/off" },
+ { 100011, "error copying in new state logging state" },
+ { 100012, "error copying out current state logging state" },
+ { 100013, "error copying out bytes waiting to be read in state \
+log" },
+ { 100014, "need write permissions to set state lock" },
+ { 100015, "need write permissions to add entry to state table" },
+ { 100016, "state not locked for size retrieval" },
+ { 100017, "error copying out hash table bucket lengths" },
+ { 100018, "could not find token for state iterator" },
+ { 100019, "error copying in state token data for deletion" },
+ { 100020, "unknown state ioctl" },
+ { 100021, "no state table entries present" },
+ { 100022, "state entry to get next from not found" },
+ { 100023, "could not malloc memory for state entry" },
+ { 100024, "could not malloc memory for state entry rule" },
+ { 100025, "could not copy back state entry to user space" },
+ { 100026, "iterator data supplied with NULL pointer" },
+ { 100027, "iterator supplied with 0 item count" },
+ { 100028, "iterator type is incorrect" },
+ { 100029, "invalid state token data pointer supplied" },
+ { 100030, "error copying out next state entry" },
+ { 100031, "unrecognised table request" },
+ { 100032, "error copying out bucket length data" },
+ { 100033, "could not find existing filter rule for state entry" },
+ { 100034, "could not find timeout name" },
+ { 100035, "could not allocate new state table" },
+ { 100036, "could not allocate new state bucket length table" },
+/* -------------------------------------------------------------------------- */
+ { 110001, "sync write header magic number is incorrect" },
+ { 110002, "sync write header protocol is incorrect" },
+ { 110003, "sync write header command is incorrect" },
+ { 110004, "sync write header table number is incorrect" },
+ { 110005, "data structure too small for sync write operation" },
+ { 110006, "zero length data with sync write header" },
+ { 110007, "insufficient data for sync write" },
+ { 110008, "bad sync read size" },
+ { 110009, "interrupted sync read (solaris)" },
+ { 110010, "interrupted sync read (hpux)" },
+ { 110011, "interrupted sync read (osf)" },
+ { 110012, "interrupted sync read" },
+ { 110013, "could not malloc memory for sync'd state" },
+ { 110014, "could not malloc memory for sync-state list item" },
+ { 110015, "sync update could not find state" },
+ { 110016, "unrecognised sync state command" },
+ { 110017, "could not malloc memory for new sync'd NAT entry" },
+ { 110018, "could not malloc memory for sync-NAT list item" },
+ { 110019, "sync update could not find NAT entry" },
+ { 110020, "unrecognised sync NAT command" },
+ { 110021, "ioctls are not handled with sync" },
+/* -------------------------------------------------------------------------- */
+ { 120001, "null data pointer for iterator" },
+ { 120002, "unit outside of acceptable range" },
+ { 120003, "unknown iterator subtype" },
+ { 120004, "cannot find dest. list for iteration" },
+ { 120005, "error copying out destination iteration list" },
+ { 120006, "error copying out destination iteration node" },
+ { 120007, "wrong size for frdest_t structure" },
+ { 120008, "cannot allocate memory for new destination node" },
+ { 120009, "error copying in destination node to add" },
+ { 120010, "could not find destination list to add node to" },
+ { 120011, "error copying in destination node to remove" },
+ { 120012, "could not find dest. list to remove node from" },
+ { 120013, "destination list already exists" },
+ { 120014, "could not allocate new destination table" },
+ { 120015, "could not find destination list to remove" },
+ { 120016, "destination list cannot be removed - it is busy" },
+ { 120017, "error copying in names for destination" },
+ { 120018, "destination name is too long/short" },
+ { 120019, "unrecognised address family in destination" },
+ { 120020, "" },
+ { 120021, "error copying in new destination table" },
+ { 120022, "cannot allocate memory for node table" },
+ { 120023, "stats object size is incorrect for dest. lists" },
+ { 120024, "stats device unit is invalid for dest. lists" },
+ { 120025, "error copying out dest. list statistics" },
+ { 120026, "cannot allocate memory for destination node" },
+ { 120027, "error copying in destination node" },
+ { 120028, "cannot allocate memory for destination context " },
+/* -------------------------------------------------------------------------- */
+ { 130001, "ioctl denied by system security level" },
+ { 130002, "ioctl operation on invalid minor device" },
+ { 130003, "ioctl on device denied, ipfitler is disabled" },
+ { 130004, "ioctl command not allowed when disabled" },
+ { 130005, "ioctl denied due to insufficient authorisation" },
+ { 130006, "cannot read while ipfilter is disabled" },
+ { 130007, "read on minor device not supported" },
+ { 130008, "cannot write while ipfilter is disabled" },
+ { 130009, "write on minor device not supported" },
+ { 130010, "poll on minor device is not supported" },
+ { 130011, "error removing IPv4 filter hooks" },
+ { 130012, "error removing IPv6 filter hooks" },
+ { 130013, "attaching IPv4 hook failed" },
+ { 130014, "attaching IPv6 hook failed" },
+ { 130015, "ipf_init_all failed" },
+ { 130016, "finding pfil head failed" },
+ { 130017, "ipfilter is already initialised and running" },
+};
+
+
+static ipf_error_entry_t *
+find_error(errnum)
+ int errnum;
+{
+ ipf_error_entry_t *ie;
+
+ int l = -1, r = IPF_NUM_ERRORS + 1, step;
+ step = (r - l) / 2;;
+
+ while (step != 0) {
+ ie = ipf_errors + l + step;
+ if (ie->iee_number == errnum)
+ return ie;
+ step = l + step;
+ if (ie->iee_number > errnum)
+ r = step;
+ else
+ l = step;
+ step = (r - l) / 2;;
+ }
+
+ return NULL;
+}
+
+char *
+ipf_geterror(fd, func)
+ int fd;
+ ioctlfunc_t *func;
+{
+ static char text[80];
+ ipf_error_entry_t *ie;
+ int errnum;
+
+ if ((*func)(fd, SIOCIPFINTERROR, &errnum) == 0) {
+
+ ie = find_error(errnum);
+ if (ie != NULL)
+ return ie->iee_text;
+ sprintf(text, "unknown error %d", errnum);
+ } else {
+ sprintf(text, "retrieving error number failed (%d)", errno);
+ }
+ return text;
+}
+
+
+char *
+ipf_strerror(errnum)
+ int errnum;
+{
+ static char text[80];
+ ipf_error_entry_t *ie;
+
+
+ ie = find_error(errnum);
+ if (ie != NULL)
+ return ie->iee_text;
+
+ sprintf(text, "unknown error %d", errnum);
+ return text;
+}
diff --git a/contrib/ipfilter/lib/ionames.c b/contrib/ipfilter/lib/ionames.c
new file mode 100644
index 0000000..9b58642
--- /dev/null
+++ b/contrib/ipfilter/lib/ionames.c
@@ -0,0 +1,41 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+struct ipopt_names ionames[] ={
+ { IPOPT_NOP, 0x000001, 1, "nop" }, /* RFC791 */
+ { IPOPT_RR, 0x000002, 8, "rr" }, /* 1 route */
+ { IPOPT_ZSU, 0x000004, 4, "zsu" }, /* size ?? */
+ { IPOPT_MTUP, 0x000008, 4, "mtup" }, /* RFC1191 */
+ { IPOPT_MTUR, 0x000010, 4, "mtur" }, /* RFC1191 */
+ { IPOPT_ENCODE, 0x000020, 4, "encode" }, /* size ?? */
+ { IPOPT_TS, 0x000040, 8, "ts" }, /* 1 TS */
+ { IPOPT_TR, 0x000080, 4, "tr" }, /* RFC1393 */
+ { IPOPT_SECURITY,0x000100, 12, "sec" }, /* RFC1108 */
+ { IPOPT_SECURITY,0x000100, 12, "sec-class" }, /* RFC1108 */
+ { IPOPT_LSRR, 0x000200, 8, "lsrr" }, /* 1 route */
+ { IPOPT_E_SEC, 0x000400, 8, "e-sec" }, /* RFC1108 */
+ { IPOPT_CIPSO, 0x000800, 8, "cipso" }, /* size ?? */
+ { IPOPT_SATID, 0x001000, 4, "satid" }, /* RFC791 */
+ { IPOPT_SSRR, 0x002000, 8, "ssrr" }, /* 1 route */
+ { IPOPT_ADDEXT, 0x004000, 4, "addext" }, /* IPv7 ?? */
+ { IPOPT_VISA, 0x008000, 4, "visa" }, /* size ?? */
+ { IPOPT_IMITD, 0x010000, 4, "imitd" }, /* size ?? */
+ { IPOPT_EIP, 0x020000, 4, "eip" }, /* RFC1385 */
+ { IPOPT_FINN, 0x040000, 4, "finn" }, /* size ?? */
+ { IPOPT_DPS, 0x080000, 4, "dps" }, /* size ?? */
+ { IPOPT_SDB, 0x100000, 4, "sdb" }, /* size ?? */
+ { IPOPT_NSAPA, 0x200000, 4, "nsapa" }, /* size ?? */
+ { IPOPT_RTRALRT,0x400000, 4, "rtralrt" }, /* RFC2113 */
+ { IPOPT_UMP, 0x800000, 4, "ump" }, /* size ?? */
+ { IPOPT_AH, 0x1000000, 0, "ah" }, /* IPPROTO_AH */
+ { 0, 0, 0, (char *)NULL } /* must be last */
+};
diff --git a/contrib/ipfilter/lib/ipf_dotuning.c b/contrib/ipfilter/lib/ipf_dotuning.c
new file mode 100644
index 0000000..b0ac8b4
--- /dev/null
+++ b/contrib/ipfilter/lib/ipf_dotuning.c
@@ -0,0 +1,74 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include <sys/ioctl.h>
+
+void ipf_dotuning(fd, tuneargs, iocfn)
+ int fd;
+ char *tuneargs;
+ ioctlfunc_t iocfn;
+{
+ ipfobj_t obj;
+ ipftune_t tu;
+ char *s, *t;
+
+ bzero((char *)&tu, sizeof(tu));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(tu);;
+ obj.ipfo_ptr = (void *)&tu;
+ obj.ipfo_type = IPFOBJ_TUNEABLE;
+
+ for (s = strtok(tuneargs, ","); s != NULL; s = strtok(NULL, ",")) {
+ if (!strcmp(s, "list")) {
+ while (1) {
+ if ((*iocfn)(fd, SIOCIPFGETNEXT, &obj) == -1) {
+ ipf_perror_fd(fd, iocfn,
+ "ioctl(SIOCIPFGETNEXT)");
+ break;
+ }
+ if (tu.ipft_cookie == NULL)
+ break;
+
+ tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
+ printtunable(&tu);
+ }
+ } else if ((t = strchr(s, '=')) != NULL) {
+ tu.ipft_cookie = NULL;
+ *t++ = '\0';
+ strncpy(tu.ipft_name, s, sizeof(tu.ipft_name));
+ if (sscanf(t, "%lu", &tu.ipft_vlong) == 1) {
+ if ((*iocfn)(fd, SIOCIPFSET, &obj) == -1) {
+ ipf_perror_fd(fd, iocfn,
+ "ioctl(SIOCIPFSET)");
+ return;
+ }
+ } else {
+ fprintf(stderr, "invalid value '%s'\n", s);
+ return;
+ }
+ } else {
+ tu.ipft_cookie = NULL;
+ strncpy(tu.ipft_name, s, sizeof(tu.ipft_name));
+ if ((*iocfn)(fd, SIOCIPFGET, &obj) == -1) {
+ ipf_perror_fd(fd, iocfn, "ioctl(SIOCIPFGET)");
+ return;
+ }
+ if (tu.ipft_cookie == NULL) {
+ fprintf(stderr, "Null cookie for %s\n", s);
+ return;
+ }
+
+ tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0';
+ printtunable(&tu);
+ }
+ }
+}
diff --git a/contrib/ipfilter/lib/ipf_perror.c b/contrib/ipfilter/lib/ipf_perror.c
new file mode 100644
index 0000000..85a1b1d
--- /dev/null
+++ b/contrib/ipfilter/lib/ipf_perror.c
@@ -0,0 +1,47 @@
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+
+void
+ipf_perror(err, string)
+ int err;
+ char *string;
+{
+ if (err == 0)
+ fprintf(stderr, "%s\n", string);
+ else
+ fprintf(stderr, "%s %s\n", string, ipf_strerror(err));
+}
+
+int
+ipf_perror_fd(fd, iocfunc, string)
+ int fd;
+ ioctlfunc_t iocfunc;
+ char *string;
+{
+ int save;
+ int realerr;
+
+ save = errno;
+ if ((*iocfunc)(fd, SIOCIPFINTERROR, &realerr) == -1)
+ realerr = 0;
+
+ errno = save;
+ fprintf(stderr, "%d:", realerr);
+ ipf_perror(realerr, string);
+ return realerr ? realerr : save;
+
+}
+
+void
+ipferror(fd, msg)
+ int fd;
+ char *msg;
+{
+ if (fd >= 0) {
+ ipf_perror_fd(fd, ioctl, msg);
+ } else {
+ fprintf(stderr, "0:");
+ perror(msg);
+ }
+}
diff --git a/contrib/ipfilter/lib/ipft_hx.c b/contrib/ipfilter/lib/ipft_hx.c
new file mode 100644
index 0000000..15002ea
--- /dev/null
+++ b/contrib/ipfilter/lib/ipft_hx.c
@@ -0,0 +1,185 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#include <ctype.h>
+
+#include "ipf.h"
+#include "ipt.h"
+
+
+extern int opts;
+
+static int hex_open __P((char *));
+static int hex_close __P((void));
+static int hex_readip __P((mb_t *, char **, int *));
+static char *readhex __P((char *, char *));
+
+struct ipread iphex = { hex_open, hex_close, hex_readip, 0 };
+static FILE *tfp = NULL;
+static int tfd = -1;
+
+static int hex_open(fname)
+ char *fname;
+{
+ if (tfp && tfd != -1) {
+ rewind(tfp);
+ return tfd;
+ }
+
+ if (!strcmp(fname, "-")) {
+ tfd = 0;
+ tfp = stdin;
+ } else {
+ tfd = open(fname, O_RDONLY);
+ if (tfd != -1)
+ tfp = fdopen(tfd, "r");
+ }
+ return tfd;
+}
+
+
+static int hex_close()
+{
+ int cfd = tfd;
+
+ tfd = -1;
+ return close(cfd);
+}
+
+
+static int hex_readip(mb, ifn, dir)
+ mb_t *mb;
+ char **ifn;
+ int *dir;
+{
+ register char *s, *t, *u;
+ char line[513];
+ ip_t *ip;
+ char *buf;
+ int cnt;
+
+ buf = (char *)mb->mb_buf;
+ cnt = sizeof(mb->mb_buf);
+ /*
+ * interpret start of line as possibly "[ifname]" or
+ * "[in/out,ifname]".
+ */
+ if (ifn)
+ *ifn = NULL;
+ if (dir)
+ *dir = 0;
+ ip = (ip_t *)buf;
+ while (fgets(line, sizeof(line)-1, tfp)) {
+ if ((s = strchr(line, '\n'))) {
+ if (s == line) {
+ mb->mb_len = (char *)ip - buf;
+ return mb->mb_len;
+ }
+ *s = '\0';
+ }
+ if ((s = strchr(line, '#')))
+ *s = '\0';
+ if (!*line)
+ continue;
+ if ((opts & OPT_DEBUG) != 0) {
+ printf("input: %s", line);
+ }
+
+ if ((*line == '[') && (s = strchr(line, ']'))) {
+ t = line + 1;
+ if (s - t > 0) {
+ *s++ = '\0';
+ if ((u = strchr(t, ',')) && (u < s)) {
+ u++;
+ if (ifn)
+ *ifn = strdup(u);
+ if (dir) {
+ if (*t == 'i')
+ *dir = 0;
+ else if (*t == 'o')
+ *dir = 1;
+ }
+ } else if (ifn)
+ *ifn = t;
+ }
+
+ while (*s++ == '+') {
+ if (!strncasecmp(s, "mcast", 5)) {
+ mb->mb_flags |= M_MCAST;
+ s += 5;
+ }
+ if (!strncasecmp(s, "bcast", 5)) {
+ mb->mb_flags |= M_BCAST;
+ s += 5;
+ }
+ if (!strncasecmp(s, "mbcast", 6)) {
+ mb->mb_flags |= M_MBCAST;
+ s += 6;
+ }
+ }
+ while (ISSPACE(*s))
+ s++;
+ } else
+ s = line;
+ t = (char *)ip;
+ ip = (ip_t *)readhex(s, (char *)ip);
+ if ((opts & OPT_DEBUG) != 0) {
+ if (opts & OPT_ASCII) {
+ int c = *t;
+ if (t < (char *)ip)
+ putchar('\t');
+ while (t < (char *)ip) {
+ if (isprint(c) && isascii(c))
+ putchar(c);
+ else
+ putchar('.');
+ t++;
+ }
+ }
+ putchar('\n');
+ fflush(stdout);
+ }
+ }
+ if (feof(tfp))
+ return 0;
+ return -1;
+}
+
+
+static char *readhex(src, dst)
+register char *src, *dst;
+{
+ int state = 0;
+ char c;
+
+ while ((c = *src++)) {
+ if (ISSPACE(c)) {
+ if (state) {
+ dst++;
+ state = 0;
+ }
+ continue;
+ } else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F')) {
+ c = ISDIGIT(c) ? (c - '0') : (TOUPPER(c) - 55);
+ if (state == 0) {
+ *dst = (c << 4);
+ state++;
+ } else {
+ *dst++ |= c;
+ state = 0;
+ }
+ } else
+ break;
+ }
+ return dst;
+}
diff --git a/contrib/ipfilter/lib/ipft_pc.c b/contrib/ipfilter/lib/ipft_pc.c
new file mode 100644
index 0000000..3a264bd
--- /dev/null
+++ b/contrib/ipfilter/lib/ipft_pc.c
@@ -0,0 +1,254 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+#include "ipt.h"
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+struct llc {
+ int lc_type;
+ int lc_sz; /* LLC header length */
+ int lc_to; /* LLC Type offset */
+ int lc_tl; /* LLC Type length */
+};
+
+/*
+ * While many of these maybe the same, some do have different header formats
+ * which make this useful.
+ */
+
+static struct llc llcs[] = {
+ { 0, 0, 0, 0 }, /* DLT_NULL */
+ { 1, 14, 12, 2 }, /* DLT_Ethernet */
+ { 10, 0, 0, 0 }, /* DLT_FDDI */
+ { 12, 0, 0, 0 }, /* DLT_RAW */
+ { -1, -1, -1, -1 }
+};
+
+typedef struct {
+ u_int id;
+ u_short major;
+ u_short minor;
+ u_int timezone;
+ u_int sigfigs;
+ u_int snaplen;
+ u_int type;
+} fileheader_t;
+
+typedef struct {
+ u_32_t seconds;
+ u_32_t microseconds;
+ u_32_t caplen;
+ u_32_t wirelen;
+} packetheader_t;
+
+static int ipcap_open __P((char *));
+static int ipcap_close __P((void));
+static int ipcap_readip __P((mb_t *, char **, int *));
+static int ipcap_read_rec __P((packetheader_t *));
+static void iswap_hdr __P((fileheader_t *));
+
+static int pfd = -1, swapped = 0;
+static struct llc *llcp = NULL;
+
+struct ipread pcap = { ipcap_open, ipcap_close, ipcap_readip, 0 };
+
+#define SWAPLONG(y) \
+ ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
+#define SWAPSHORT(y) \
+ ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) )
+
+static void iswap_hdr(p)
+ fileheader_t *p;
+{
+ p->major = SWAPSHORT(p->major);
+ p->minor = SWAPSHORT(p->minor);
+ p->timezone = SWAPLONG(p->timezone);
+ p->sigfigs = SWAPLONG(p->sigfigs);
+ p->snaplen = SWAPLONG(p->snaplen);
+ p->type = SWAPLONG(p->type);
+}
+
+static int ipcap_open(fname)
+ char *fname;
+{
+ fileheader_t ph;
+ int fd, i;
+
+ if (pfd != -1)
+ return pfd;
+
+ if (!strcmp(fname, "-"))
+ fd = 0;
+ else if ((fd = open(fname, O_RDONLY)) == -1)
+ return -1;
+
+ if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph))
+ return -2;
+
+ if (ph.id != 0xa1b2c3d4) {
+ if (SWAPLONG(ph.id) != 0xa1b2c3d4) {
+ (void) close(fd);
+ return -2;
+ }
+ swapped = 1;
+ iswap_hdr(&ph);
+ }
+
+ for (i = 0; llcs[i].lc_type != -1; i++)
+ if (llcs[i].lc_type == ph.type) {
+ llcp = llcs + i;
+ break;
+ }
+
+ if (llcp == NULL) {
+ (void) close(fd);
+ return -2;
+ }
+
+ pfd = fd;
+ printf("opened pcap file %s:\n", fname);
+ printf("\tid: %08x version: %d.%d type: %d snap %d\n",
+ ph.id, ph.major, ph.minor, ph.type, ph.snaplen);
+
+ return fd;
+}
+
+
+static int ipcap_close()
+{
+ return close(pfd);
+}
+
+
+/*
+ * read in the header (and validate) which should be the first record
+ * in a pcap file.
+ */
+static int ipcap_read_rec(rec)
+ packetheader_t *rec;
+{
+ int n, p, i;
+ char *s;
+
+ s = (char *)rec;
+ n = sizeof(*rec);
+
+ while (n > 0) {
+ i = read(pfd, (char *)rec, sizeof(*rec));
+ if (i <= 0)
+ return -2;
+ s += i;
+ n -= i;
+ }
+
+ if (swapped) {
+ rec->caplen = SWAPLONG(rec->caplen);
+ rec->wirelen = SWAPLONG(rec->wirelen);
+ rec->seconds = SWAPLONG(rec->seconds);
+ rec->microseconds = SWAPLONG(rec->microseconds);
+ }
+ p = rec->caplen;
+ n = MIN(p, rec->wirelen);
+ if (!n || n < 0)
+ return -3;
+
+ if (p < 0 || p > 65536)
+ return -4;
+ 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 ipcap_read(buf, cnt)
+ char *buf;
+ int cnt;
+{
+ packetheader_t rec;
+ static char *bufp = NULL;
+ int i, n;
+
+ if ((i = ipcap_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 ipcap_readip(mb, ifn, dir)
+ mb_t *mb;
+ char **ifn;
+ int *dir;
+{
+ static char *bufp = NULL;
+ packetheader_t rec;
+ struct llc *l;
+ char *s, ty[4];
+ int i, j, n;
+ char *buf;
+ int cnt;
+
+#if 0
+ ifn = ifn; /* gcc -Wextra */
+ dir = dir; /* gcc -Wextra */
+#endif
+ buf = (char *)mb->mb_buf;
+ cnt = sizeof(mb->mb_buf);
+ l = llcp;
+
+ /* do { */
+ if ((i = ipcap_read_rec(&rec)) <= 0)
+ return i;
+
+ if (!bufp)
+ bufp = malloc(i);
+ else
+ bufp = realloc(bufp, i);
+ s = bufp;
+
+ for (j = i, n = 0; j > 0; ) {
+ n = read(pfd, s, j);
+ if (n <= 0)
+ return -2;
+ j -= n;
+ s += n;
+ }
+ s = bufp;
+
+ 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);
+ mb->mb_len = n;
+ return n;
+}
diff --git a/contrib/ipfilter/lib/ipft_tx.c b/contrib/ipfilter/lib/ipft_tx.c
new file mode 100644
index 0000000..a996c5b
--- /dev/null
+++ b/contrib/ipfilter/lib/ipft_tx.c
@@ -0,0 +1,510 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#include <ctype.h>
+
+#include "ipf.h"
+#include "ipt.h"
+
+extern int opts;
+
+static char *tx_proto = "";
+
+static int text_open __P((char *)), text_close __P((void));
+static int text_readip __P((mb_t *, char **, int *));
+static int parseline __P((char *, ip_t *, char **, int *));
+
+static char myflagset[] = "FSRPAUEC";
+static u_char myflags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH,
+ TH_ACK, TH_URG, TH_ECN, TH_CWR };
+
+struct ipread iptext = { text_open, text_close, text_readip, R_DO_CKSUM };
+static FILE *tfp = NULL;
+static int tfd = -1;
+
+static u_32_t tx_hostnum __P((char *, int *));
+static u_short tx_portnum __P((char *));
+
+#ifdef USE_INET6
+int parseipv6 __P((char **, ip6_t *, char **, int *));
+#endif
+
+/*
+ * returns an ip address as a long var as a result of either a DNS lookup or
+ * straight inet_addr() call
+ */
+static u_32_t tx_hostnum(host, resolved)
+ char *host;
+ int *resolved;
+{
+ i6addr_t ipa;
+
+ *resolved = 0;
+ if (!strcasecmp("any", host))
+ return 0L;
+ if (ISDIGIT(*host))
+ return inet_addr(host);
+
+ if (gethost(AF_INET, host, &ipa) == -1) {
+ *resolved = -1;
+ fprintf(stderr, "can't resolve hostname: %s\n", host);
+ return 0;
+ }
+ return ipa.in4.s_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;
+
+ if (ISDIGIT(*name))
+ return (u_short)atoi(name);
+ sp = getservbyname(name, tx_proto);
+ if (sp)
+ return ntohs(sp->s_port);
+ (void) fprintf(stderr, "unknown service \"%s\".\n", name);
+ return 0;
+}
+
+
+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(mb, ifn, dir)
+ mb_t *mb;
+ char **ifn;
+ int *dir;
+{
+ register char *s;
+ char line[513];
+ ip_t *ip;
+ char *buf;
+ int cnt;
+
+ buf = (char *)mb->mb_buf;
+ cnt = sizeof(mb->mb_buf);
+
+ *ifn = NULL;
+ while (fgets(line, sizeof(line)-1, tfp)) {
+ if ((s = strchr(line, '\n')))
+ *s = '\0';
+ if ((s = strchr(line, '\r')))
+ *s = '\0';
+ if ((s = strchr(line, '#')))
+ *s = '\0';
+ if (!*line)
+ continue;
+ if ((opts & OPT_DEBUG) != 0)
+ printf("input: %s\n", line);
+ *ifn = NULL;
+ *dir = 0;
+ if (!parseline(line, (ip_t *)buf, ifn, dir)) {
+ ip = (ip_t *)buf;
+ if (IP_V(ip) == 6) {
+#ifdef USE_INET6
+ mb->mb_len = ntohs(((ip6_t *)ip)->ip6_plen) +
+ sizeof(ip6_t);
+#else
+ mb->mb_len = 0;
+#endif
+ } else {
+ mb->mb_len = ntohs(ip->ip_len);
+ }
+ return mb->mb_len;
+ }
+ }
+ if (feof(tfp))
+ return 0;
+ return -1;
+}
+
+static int parseline(line, ip, ifn, out)
+ char *line;
+ ip_t *ip;
+ char **ifn;
+ int *out;
+{
+ tcphdr_t th, *tcp = &th;
+ struct icmp icmp, *ic = &icmp;
+ char *cps[20], **cpp, c, ipopts[68];
+ int i, r;
+
+ if (*ifn)
+ free(*ifn);
+ bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip));
+ bzero((char *)tcp, sizeof(*tcp));
+ bzero((char *)ic, sizeof(*ic));
+ bzero(ipopts, sizeof(ipopts));
+ IP_HL_A(ip, sizeof(*ip) >> 2);
+ IP_V_A(ip, IPVERSION);
+ ip->ip_ttl = 63;
+ for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; )
+ cps[++i] = strtok(NULL, " \b\t\r\n");
+
+ cpp = cps;
+ if (!*cpp)
+ return 1;
+
+ c = **cpp;
+ if (!ISALPHA(c) || (TOLOWER(c) != 'o' && TOLOWER(c) != 'i')) {
+ fprintf(stderr, "bad direction \"%s\"\n", *cpp);
+ return 1;
+ }
+
+#ifdef USE_INET6
+ if (!strcasecmp(*cpp, "out6") || !strcasecmp(*cpp, "in6")) {
+ return parseipv6(cpp, (ip6_t *)ip, ifn, out);
+ }
+#endif
+
+ *out = (TOLOWER(c) == 'o') ? 1 : 0;
+ cpp++;
+ if (!*cpp)
+ return 1;
+
+ if (!strcasecmp(*cpp, "on")) {
+ cpp++;
+ if (!*cpp)
+ return 1;
+ *ifn = strdup(*cpp++);
+ if (!*cpp)
+ return 1;
+ }
+
+ c = **cpp;
+ ip->ip_len = sizeof(ip_t);
+ if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") ||
+ !strcasecmp(*cpp, "icmp")) {
+ if (c == 't') {
+ ip->ip_p = IPPROTO_TCP;
+ ip->ip_len += sizeof(struct tcphdr);
+ tx_proto = "tcp";
+ } else if (c == 'u') {
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_len += sizeof(struct udphdr);
+ tx_proto = "udp";
+ } else {
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_len += ICMPERR_IPICMPHLEN;
+ tx_proto = "icmp";
+ }
+ cpp++;
+ } else if (ISDIGIT(**cpp) && !index(*cpp, '.')) {
+ ip->ip_p = atoi(*cpp);
+ cpp++;
+ } else
+ ip->ip_p = IPPROTO_IP;
+
+ if (!*cpp)
+ return 1;
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
+ char *last;
+
+ last = strchr(*cpp, ',');
+ if (!last) {
+ fprintf(stderr, "tcp/udp with no source port\n");
+ return 1;
+ }
+ *last++ = '\0';
+ tcp->th_sport = htons(tx_portnum(last));
+ if (ip->ip_p == IPPROTO_TCP) {
+ tcp->th_win = htons(4096);
+ TCP_OFF_A(tcp, sizeof(*tcp) >> 2);
+ }
+ }
+ ip->ip_src.s_addr = tx_hostnum(*cpp, &r);
+ cpp++;
+ if (!*cpp)
+ return 1;
+
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
+ char *last;
+
+ last = strchr(*cpp, ',');
+ if (!last) {
+ fprintf(stderr, "tcp/udp with no destination port\n");
+ return 1;
+ }
+ *last++ = '\0';
+ tcp->th_dport = htons(tx_portnum(last));
+ }
+ ip->ip_dst.s_addr = tx_hostnum(*cpp, &r);
+ cpp++;
+ if (ip->ip_p == IPPROTO_TCP) {
+ if (*cpp != NULL) {
+ char *s, *t;
+
+ tcp->th_flags = 0;
+ for (s = *cpp; *s; s++)
+ if ((t = strchr(myflagset, *s)))
+ tcp->th_flags |= myflags[t-myflagset];
+ if (tcp->th_flags)
+ cpp++;
+ }
+
+ if (tcp->th_flags & TH_URG)
+ tcp->th_urp = htons(1);
+
+ if (*cpp && !strncasecmp(*cpp, "seq=", 4)) {
+ tcp->th_seq = htonl(atoi(*cpp + 4));
+ cpp++;
+ }
+
+ if (*cpp && !strncasecmp(*cpp, "ack=", 4)) {
+ tcp->th_ack = htonl(atoi(*cpp + 4));
+ cpp++;
+ }
+ } else if (*cpp && ip->ip_p == IPPROTO_ICMP) {
+ char *t;
+
+ t = strchr(*cpp, ',');
+ if (t != NULL)
+ *t = '\0';
+
+ ic->icmp_type = geticmptype(AF_INET, *cpp);
+ if (t != NULL)
+ ic->icmp_code = atoi(t + 1);
+ cpp++;
+
+ if (ic->icmp_type == ICMP_ECHO ||
+ ic->icmp_type == ICMP_ECHOREPLY)
+ ic->icmp_id = htons(getpid());
+ if (t != NULL)
+ *t = ',';
+ }
+
+ if (*cpp && !strcasecmp(*cpp, "opt")) {
+ u_long olen;
+
+ cpp++;
+ olen = buildopts(*cpp, ipopts, (IP_HL(ip) - 5) << 2);
+ if (olen) {
+ bcopy(ipopts, (char *)(ip + 1), olen);
+ IP_HL_A(ip, IP_HL(ip) + (olen >> 2));
+ ip->ip_len += olen;
+ }
+ }
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ bcopy((char *)tcp, ((char *)ip) + (IP_HL(ip) << 2),
+ sizeof(*tcp));
+ else if (ip->ip_p == IPPROTO_ICMP)
+ bcopy((char *)ic, ((char *)ip) + (IP_HL(ip) << 2),
+ sizeof(*ic));
+ ip->ip_len = htons(ip->ip_len);
+ return 0;
+}
+
+
+#ifdef USE_INET6
+int parseipv6(cpp, ip6, ifn, out)
+ char **cpp;
+ ip6_t *ip6;
+ char **ifn;
+ int *out;
+{
+ tcphdr_t th, *tcp = &th;
+ struct icmp6_hdr icmp, *ic6 = &icmp;
+
+ bzero((char *)ip6, MAX(sizeof(*tcp), sizeof(*ic6)) + sizeof(*ip6));
+ bzero((char *)tcp, sizeof(*tcp));
+ bzero((char *)ic6, sizeof(*ic6));
+ ip6->ip6_vfc = 0x60;
+
+ *out = (**cpp == 'o') ? 1 : 0;
+ cpp++;
+ if (!*cpp)
+ return 1;
+
+ if (!strcasecmp(*cpp, "on")) {
+ cpp++;
+ if (!*cpp)
+ return 1;
+ *ifn = strdup(*cpp++);
+ if (!*cpp)
+ return 1;
+ }
+
+ if (!strcasecmp(*cpp, "tcp")) {
+ ip6->ip6_nxt = IPPROTO_TCP;
+ tx_proto = "tcp";
+ cpp++;
+ } else if (!strcasecmp(*cpp, "udp")) {
+ ip6->ip6_nxt = IPPROTO_UDP;
+ tx_proto = "udp";
+ cpp++;
+ } else if (!strcasecmp(*cpp, "icmpv6")) {
+ ip6->ip6_nxt = IPPROTO_ICMPV6;
+ tx_proto = "icmpv6";
+ cpp++;
+ } else if (ISDIGIT(**cpp) && !index(*cpp, ':')) {
+ ip6->ip6_nxt = atoi(*cpp);
+ cpp++;
+ } else
+ ip6->ip6_nxt = IPPROTO_IPV6;
+
+ if (!*cpp)
+ return 1;
+
+ switch (ip6->ip6_nxt)
+ {
+ case IPPROTO_TCP :
+ ip6->ip6_plen = sizeof(struct tcphdr);
+ break;
+ case IPPROTO_UDP :
+ ip6->ip6_plen = sizeof(struct udphdr);
+ break;
+ case IPPROTO_ICMPV6 :
+ ip6->ip6_plen = ICMP6ERR_IPICMPHLEN;
+ break;
+ default :
+ break;
+ }
+
+ if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) {
+ char *last;
+
+ last = strchr(*cpp, ',');
+ if (!last) {
+ fprintf(stderr, "tcp/udp with no source port\n");
+ return 1;
+ }
+ *last++ = '\0';
+ tcp->th_sport = htons(tx_portnum(last));
+ if (ip6->ip6_nxt == IPPROTO_TCP) {
+ tcp->th_win = htons(4096);
+ TCP_OFF_A(tcp, sizeof(*tcp) >> 2);
+ }
+ }
+
+ if (inet_pton(AF_INET6, *cpp, &ip6->ip6_src) != 1) {
+ fprintf(stderr, "cannot parse source address '%s'\n", *cpp);
+ return 1;
+ }
+
+ cpp++;
+ if (!*cpp)
+ return 1;
+
+ if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) {
+ char *last;
+
+ last = strchr(*cpp, ',');
+ if (!last) {
+ fprintf(stderr, "tcp/udp with no destination port\n");
+ return 1;
+ }
+ *last++ = '\0';
+ tcp->th_dport = htons(tx_portnum(last));
+ }
+
+ if (inet_pton(AF_INET6, *cpp, &ip6->ip6_dst) != 1) {
+ fprintf(stderr, "cannot parse destination address '%s'\n",
+ *cpp);
+ return 1;
+ }
+
+ cpp++;
+ if (ip6->ip6_nxt == IPPROTO_TCP) {
+ if (*cpp != NULL) {
+ char *s, *t;
+
+ tcp->th_flags = 0;
+ for (s = *cpp; *s; s++)
+ if ((t = strchr(myflagset, *s)))
+ tcp->th_flags |= myflags[t-myflagset];
+ if (tcp->th_flags)
+ cpp++;
+ }
+
+ if (tcp->th_flags & TH_URG)
+ tcp->th_urp = htons(1);
+
+ if (*cpp && !strncasecmp(*cpp, "seq=", 4)) {
+ tcp->th_seq = htonl(atoi(*cpp + 4));
+ cpp++;
+ }
+
+ if (*cpp && !strncasecmp(*cpp, "ack=", 4)) {
+ tcp->th_ack = htonl(atoi(*cpp + 4));
+ cpp++;
+ }
+ } else if (*cpp && ip6->ip6_nxt == IPPROTO_ICMPV6) {
+ char *t;
+
+ t = strchr(*cpp, ',');
+ if (t != NULL)
+ *t = '\0';
+
+ ic6->icmp6_type = geticmptype(AF_INET6, *cpp);
+ if (t != NULL)
+ ic6->icmp6_code = atoi(t + 1);
+
+ if (ic6->icmp6_type == ICMP6_ECHO_REQUEST ||
+ ic6->icmp6_type == ICMP6_ECHO_REPLY)
+ ic6->icmp6_id = htons(getpid());
+
+ if (t != NULL)
+ *t = ',';
+ }
+
+ if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) {
+ bcopy((char *)tcp, (char *)ip6 + sizeof(*ip6),
+ sizeof(*tcp));
+ } else if (ip6->ip6_nxt == IPPROTO_ICMPV6) {
+ bcopy((char *)ic6, (char *)ip6 + sizeof(*ip6),
+ sizeof(*ic6));
+ }
+
+ /*
+ * Because a length of 0 == jumbo gram...
+ */
+ if (ip6->ip6_plen == 0) {
+ ip6->ip6_plen++;
+ }
+ ip6->ip6_plen = htons(ip6->ip6_plen);
+ return 0;
+}
+#endif
diff --git a/contrib/ipfilter/lib/ipoptsec.c b/contrib/ipfilter/lib/ipoptsec.c
new file mode 100644
index 0000000..5e585ba
--- /dev/null
+++ b/contrib/ipfilter/lib/ipoptsec.c
@@ -0,0 +1,61 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+struct ipopt_names secclass[] = {
+ { IPSO_CLASS_RES4, 0x01, 0, "reserv-4" },
+ { IPSO_CLASS_TOPS, 0x02, 0, "topsecret" },
+ { IPSO_CLASS_SECR, 0x04, 0, "secret" },
+ { IPSO_CLASS_RES3, 0x08, 0, "reserv-3" },
+ { IPSO_CLASS_CONF, 0x10, 0, "confid" },
+ { IPSO_CLASS_UNCL, 0x20, 0, "unclass" },
+ { IPSO_CLASS_RES2, 0x40, 0, "reserv-2" },
+ { IPSO_CLASS_RES1, 0x80, 0, "reserv-1" },
+ { 0, 0, 0, NULL } /* must be last */
+};
+
+
+u_char seclevel(slevel)
+ char *slevel;
+{
+ struct ipopt_names *so;
+
+ if (slevel == NULL || *slevel == '\0')
+ return 0;
+
+ for (so = secclass; so->on_name; so++)
+ if (!strcasecmp(slevel, so->on_name))
+ break;
+
+ if (!so->on_name) {
+ fprintf(stderr, "no such security level: '%s'\n", slevel);
+ return 0;
+ }
+ return (u_char)so->on_value;
+}
+
+
+u_char secbit(class)
+ int class;
+{
+ struct ipopt_names *so;
+
+ for (so = secclass; so->on_name; so++)
+ if (so->on_value == class)
+ break;
+
+ if (!so->on_name) {
+ fprintf(stderr, "no such security class: %d.\n", class);
+ return 0;
+ }
+ return (u_char)so->on_bit;
+}
diff --git a/contrib/ipfilter/lib/kmem.c b/contrib/ipfilter/lib/kmem.c
new file mode 100644
index 0000000..d895baf
--- /dev/null
+++ b/contrib/ipfilter/lib/kmem.c
@@ -0,0 +1,201 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+/*
+ * kmemcpy() - copies n bytes from kernel memory into user buffer.
+ * returns 0 on success, -1 on error.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(_AIX51)
+#include <kvm.h>
+#endif
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/if.h>
+#if defined(linux) || defined(__osf__) || defined(__sgi) || defined(__hpux)
+# include <stdlib.h>
+#endif
+
+#include "kmem.h"
+
+#ifndef __STDC__
+# define const
+#endif
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+
+#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && \
+ !defined(linux) && !defined(_AIX51)
+/*
+ * For all platforms where there is a libkvm and a kvm_t, we use that...
+ */
+static kvm_t *kvm_f = NULL;
+
+#else
+/*
+ *...and for the others (HP-UX, IRIX, Tru64), we have to provide our own.
+ */
+
+typedef int * kvm_t;
+
+static kvm_t kvm_f = NULL;
+static char *kvm_errstr = NULL;
+
+kvm_t kvm_open __P((char *, char *, char *, int, char *));
+int kvm_read __P((kvm_t, u_long, char *, size_t));
+
+kvm_t kvm_open(kernel, core, swap, mode, errstr)
+ char *kernel, *core, *swap;
+ int mode;
+ char *errstr;
+{
+ kvm_t k;
+ int fd;
+
+ kvm_errstr = errstr;
+
+ if (core == NULL)
+ core = "/dev/kmem";
+
+ fd = open(core, mode);
+ if (fd == -1)
+ return NULL;
+ k = malloc(sizeof(*k));
+ if (k == NULL)
+ return NULL;
+ *k = fd;
+ return k;
+}
+
+int kvm_read(kvm, pos, buffer, size)
+ kvm_t kvm;
+ u_long pos;
+ char *buffer;
+ size_t size;
+{
+ int r = 0, left;
+ char *bufp;
+
+ if (lseek(*kvm, pos, 0) == -1) {
+ if (kvm_errstr != NULL) {
+ fprintf(stderr, "%s", kvm_errstr);
+ perror("lseek");
+ }
+ return -1;
+ }
+
+ for (bufp = buffer, left = size; left > 0; bufp += r, left -= r) {
+ r = read(*kvm, bufp, left);
+#ifdef __osf__
+ /*
+ * Tru64 returns "0" for successful operation, not the number
+ * of bytes read.
+ */
+ if (r == 0)
+ r = left;
+#endif
+ if (r <= 0)
+ return -1;
+ }
+ return r;
+}
+#endif /* !defined(__sgi) && !defined(__hpux) && !defined(__osf__) */
+
+int openkmem(kern, core)
+ char *kern, *core;
+{
+ kvm_f = kvm_open(kern, core, NULL, O_RDONLY, NULL);
+ if (kvm_f == NULL)
+ {
+ perror("openkmem:open");
+ return -1;
+ }
+ return kvm_f != NULL;
+}
+
+int kmemcpy(buf, pos, n)
+ register char *buf;
+ long pos;
+ register int n;
+{
+ register int r;
+
+ if (!n)
+ return 0;
+
+ if (kvm_f == NULL)
+ if (openkmem(NULL, NULL) == -1)
+ return -1;
+
+ while ((r = kvm_read(kvm_f, pos, buf, n)) < n)
+ if (r <= 0)
+ {
+ fprintf(stderr, "pos=0x%lx ", (u_long)pos);
+ perror("kmemcpy:read");
+ return -1;
+ }
+ else
+ {
+ buf += r;
+ pos += r;
+ n -= r;
+ }
+ return 0;
+}
+
+int kstrncpy(buf, pos, n)
+ register char *buf;
+ long pos;
+ register int n;
+{
+ register int r;
+
+ if (!n)
+ return 0;
+
+ if (kvm_f == NULL)
+ if (openkmem(NULL, NULL) == -1)
+ return -1;
+
+ while (n > 0)
+ {
+ r = kvm_read(kvm_f, pos, buf, 1);
+ if (r <= 0)
+ {
+ fprintf(stderr, "pos=0x%lx ", (u_long)pos);
+ perror("kmemcpy:read");
+ return -1;
+ }
+ else
+ {
+ if (*buf == '\0')
+ break;
+ buf++;
+ pos++;
+ n--;
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/kmem.h b/contrib/ipfilter/lib/kmem.h
new file mode 100644
index 0000000..ce6ad56
--- /dev/null
+++ b/contrib/ipfilter/lib/kmem.h
@@ -0,0 +1,34 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ * $Id$
+ */
+
+#ifndef __KMEM_H__
+#define __KMEM_H__
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+extern int openkmem __P((char *, char *));
+extern int kmemcpy __P((char *, long, int));
+extern int kstrncpy __P((char *, long, int));
+
+#if defined(__NetBSD__) || defined(__OpenBSD)
+# include <paths.h>
+#endif
+
+#ifdef _PATH_KMEM
+# define KMEM _PATH_KMEM
+#else
+# define KMEM "/dev/kmem"
+#endif
+
+#endif /* __KMEM_H__ */
diff --git a/contrib/ipfilter/lib/kmemcpywrap.c b/contrib/ipfilter/lib/kmemcpywrap.c
new file mode 100644
index 0000000..6c398d6
--- /dev/null
+++ b/contrib/ipfilter/lib/kmemcpywrap.c
@@ -0,0 +1,23 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+#include "kmem.h"
+
+int kmemcpywrap(from, to, size)
+ void *from, *to;
+ size_t size;
+{
+ int ret;
+
+ ret = kmemcpy((caddr_t)to, (u_long)from, size);
+ return ret;
+}
+
diff --git a/contrib/ipfilter/lib/kvatoname.c b/contrib/ipfilter/lib/kvatoname.c
new file mode 100644
index 0000000..65b5240
--- /dev/null
+++ b/contrib/ipfilter/lib/kvatoname.c
@@ -0,0 +1,39 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+char *kvatoname(func, iocfunc)
+ ipfunc_t func;
+ ioctlfunc_t iocfunc;
+{
+ static char funcname[40];
+ ipfunc_resolve_t res;
+ int fd;
+
+ res.ipfu_addr = func;
+ res.ipfu_name[0] = '\0';
+ fd = -1;
+
+ if ((opts & OPT_DONTOPEN) == 0) {
+ fd = open(IPL_NAME, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ }
+ (void) (*iocfunc)(fd, SIOCFUNCL, &res);
+ if (fd >= 0)
+ close(fd);
+ strncpy(funcname, res.ipfu_name, sizeof(funcname));
+ funcname[sizeof(funcname) - 1] = '\0';
+ return funcname;
+}
diff --git a/contrib/ipfilter/lib/load_dstlist.c b/contrib/ipfilter/lib/load_dstlist.c
new file mode 100644
index 0000000..760699d
--- /dev/null
+++ b/contrib/ipfilter/lib/load_dstlist.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: load_dstlist.c,v 1.1.2.5 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
+
+
+int
+load_dstlist(dst, iocfunc, nodes)
+ ippool_dst_t *dst;
+ ioctlfunc_t iocfunc;
+ ipf_dstnode_t *nodes;
+{
+ iplookupop_t op;
+ ipf_dstnode_t *a;
+ ippool_dst_t dest;
+
+ if (dst->ipld_name[0] == '\0')
+ return -1;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_unit = dst->ipld_unit;
+ op.iplo_type = IPLT_DSTLIST;
+ op.iplo_arg = 0;
+ strncpy(op.iplo_name, dst->ipld_name, sizeof(op.iplo_name));
+ op.iplo_size = sizeof(dest);
+ op.iplo_struct = &dest;
+ bzero((char *)&dest, sizeof(dest));
+ dest.ipld_unit = dst->ipld_unit;
+ dest.ipld_policy = dst->ipld_policy;
+ dest.ipld_flags = dst->ipld_flags;
+ strncpy(dest.ipld_name, dst->ipld_name, sizeof(dest.ipld_name));
+
+ if ((opts & OPT_REMOVE) == 0) {
+ if (pool_ioctl(iocfunc, SIOCLOOKUPADDTABLE, &op))
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "add destination list table");
+ }
+ }
+
+ if ((opts & OPT_VERBOSE) != 0) {
+ dest.ipld_dests = dst->ipld_dests;
+ printdstlist(&dest, bcopywrap, dest.ipld_name, opts, nodes, NULL);
+ dest.ipld_dests = NULL;
+ }
+
+ for (a = nodes; a != NULL; a = a->ipfd_next)
+ load_dstlistnode(dst->ipld_unit, dest.ipld_name, a, iocfunc);
+
+ if ((opts & OPT_REMOVE) != 0) {
+ if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op))
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "delete destination list table");
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/load_dstlistnode.c b/contrib/ipfilter/lib/load_dstlistnode.c
new file mode 100644
index 0000000..e1ec001
--- /dev/null
+++ b/contrib/ipfilter/lib/load_dstlistnode.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: load_dstlistnode.c,v 1.1.2.5 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+
+
+int
+load_dstlistnode(role, name, node, iocfunc)
+ int role;
+ char *name;
+ ipf_dstnode_t *node;
+ ioctlfunc_t iocfunc;
+{
+ iplookupop_t op;
+ frdest_t *dst;
+ char *what;
+ int err;
+
+ if (pool_open() == -1)
+ return -1;
+
+ dst = calloc(1, sizeof(*dst) + node->ipfd_dest.fd_name);
+ if (dst == NULL)
+ return -1;
+
+ op.iplo_unit = role;
+ op.iplo_type = IPLT_DSTLIST;
+ op.iplo_arg = 0;
+ op.iplo_struct = dst;
+ op.iplo_size = sizeof(*dst);
+ if (node->ipfd_dest.fd_name >= 0)
+ op.iplo_size += node->ipfd_dest.fd_name;
+ (void) strncpy(op.iplo_name, name, sizeof(op.iplo_name));
+
+ dst->fd_addr = node->ipfd_dest.fd_addr;
+ dst->fd_type = node->ipfd_dest.fd_type;
+ dst->fd_name = node->ipfd_dest.fd_name;
+ if (node->ipfd_dest.fd_name >= 0)
+ bcopy(node->ipfd_names, (char *)dst + sizeof(*dst),
+ node->ipfd_dest.fd_name);
+
+ if ((opts & OPT_REMOVE) == 0) {
+ what = "add";
+ err = pool_ioctl(iocfunc, SIOCLOOKUPADDNODE, &op);
+ } else {
+ what = "delete";
+ err = pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op);
+ }
+ free(dst);
+
+ if (err != 0) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ (void) sprintf(msg, "%s lookup node", what);
+ return ipf_perror_fd(pool_fd(), iocfunc, msg);
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/load_file.c b/contrib/ipfilter/lib/load_file.c
new file mode 100644
index 0000000..a1d1f70
--- /dev/null
+++ b/contrib/ipfilter/lib/load_file.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: load_file.c,v 1.6.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+alist_t *
+load_file(char *filename)
+{
+ alist_t *a, *rtop, *rbot;
+ char *s, line[1024], *t;
+ int linenum, not;
+ FILE *fp;
+
+ fp = fopen(filename + 7, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "load_file cannot open '%s'\n", filename);
+ return NULL;
+ }
+
+ a = NULL;
+ rtop = NULL;
+ rbot = NULL;
+ linenum = 0;
+
+ while (fgets(line, sizeof(line) - 1, fp)) {
+ line[sizeof(line) - 1] = '\0';
+ linenum++;
+ /*
+ * Hunt for CR/LF. If no LF, stop processing.
+ */
+ s = strchr(line, '\n');
+ if (s == NULL) {
+ fprintf(stderr, "%d:%s: line too long\n",
+ linenum, filename);
+ fclose(fp);
+ alist_free(rtop);
+ return NULL;
+ }
+
+ /*
+ * Remove trailing spaces
+ */
+ for (; ISSPACE(*s); s--)
+ *s = '\0';
+
+ s = strchr(line, '\r');
+ if (s != NULL)
+ *s = '\0';
+ for (t = line; ISSPACE(*t); t++)
+ ;
+ if (*t == '!') {
+ not = 1;
+ t++;
+ } else
+ not = 0;
+
+ /*
+ * Remove comment markers
+ */
+ s = strchr(t, '#');
+ if (s != NULL) {
+ *s = '\0';
+ if (s == t)
+ continue;
+ }
+
+ /*
+ * Trim off tailing white spaces
+ */
+ s = strlen(t) + t - 1;
+ while (ISSPACE(*s))
+ *s-- = '\0';
+
+ a = alist_new(AF_UNSPEC, t);
+ if (a != NULL) {
+ a->al_not = not;
+ if (rbot != NULL)
+ rbot->al_next = a;
+ else
+ rtop = a;
+ rbot = a;
+ } else {
+ fprintf(stderr, "%s:%d unrecognised content :%s\n",
+ filename, linenum, t);
+ }
+ }
+ fclose(fp);
+
+ return rtop;
+}
diff --git a/contrib/ipfilter/lib/load_hash.c b/contrib/ipfilter/lib/load_hash.c
new file mode 100644
index 0000000..7ec79a9
--- /dev/null
+++ b/contrib/ipfilter/lib/load_hash.c
@@ -0,0 +1,103 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_htable.h"
+
+
+int
+load_hash(iphp, list, iocfunc)
+ iphtable_t *iphp;
+ iphtent_t *list;
+ ioctlfunc_t iocfunc;
+{
+ iplookupop_t op;
+ iphtable_t iph;
+ iphtent_t *a;
+ size_t size;
+ int n;
+
+ if (pool_open() == -1)
+ return -1;
+
+ for (n = 0, a = list; a != NULL; a = a->ipe_next)
+ n++;
+
+ bzero((char *)&iph, sizeof(iph));
+ op.iplo_arg = 0;
+ op.iplo_type = IPLT_HASH;
+ op.iplo_unit = iphp->iph_unit;
+ strncpy(op.iplo_name, iphp->iph_name, sizeof(op.iplo_name));
+ if (*op.iplo_name == '\0')
+ op.iplo_arg = IPHASH_ANON;
+ op.iplo_size = sizeof(iph);
+ op.iplo_struct = &iph;
+ iph = *iphp;
+ if (n <= 0)
+ n = 1;
+ if (iphp->iph_size == 0)
+ size = n * 2 - 1;
+ else
+ size = iphp->iph_size;
+ if ((list == NULL) && (size == 1)) {
+ fprintf(stderr,
+ "WARNING: empty hash table %s, recommend setting %s\n",
+ iphp->iph_name, "size to match expected use");
+ }
+ iph.iph_size = size;
+ iph.iph_table = NULL;
+ iph.iph_list = NULL;
+ iph.iph_ref = 0;
+
+ if ((opts & OPT_REMOVE) == 0) {
+ if (pool_ioctl(iocfunc, SIOCLOOKUPADDTABLE, &op))
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "add lookup hash table");
+ }
+ }
+
+ strncpy(iph.iph_name, op.iplo_name, sizeof(op.iplo_name));
+ strncpy(iphp->iph_name, op.iplo_name, sizeof(op.iplo_name));
+
+ if (opts & OPT_VERBOSE) {
+ iph.iph_table = calloc(size, sizeof(*iph.iph_table));
+ if (iph.iph_table == NULL) {
+ perror("calloc(size, sizeof(*iph.iph_table))");
+ return -1;
+ }
+ iph.iph_list = list;
+ printhash(&iph, bcopywrap, iph.iph_name, opts, NULL);
+ free(iph.iph_table);
+
+ for (a = list; a != NULL; a = a->ipe_next) {
+ a->ipe_addr.in4_addr = htonl(a->ipe_addr.in4_addr);
+ a->ipe_mask.in4_addr = htonl(a->ipe_mask.in4_addr);
+ }
+ }
+
+ if (opts & OPT_DEBUG)
+ printf("Hash %s:\n", iph.iph_name);
+
+ for (a = list; a != NULL; a = a->ipe_next)
+ load_hashnode(iphp->iph_unit, iph.iph_name, a, 0, iocfunc);
+
+ if ((opts & OPT_REMOVE) != 0) {
+ if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op))
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "delete lookup hash table");
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/load_hashnode.c b/contrib/ipfilter/lib/load_hashnode.c
new file mode 100644
index 0000000..2aac433
--- /dev/null
+++ b/contrib/ipfilter/lib/load_hashnode.c
@@ -0,0 +1,67 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_htable.h"
+
+
+int
+load_hashnode(unit, name, node, ttl, iocfunc)
+ int unit;
+ char *name;
+ iphtent_t *node;
+ int ttl;
+ ioctlfunc_t iocfunc;
+{
+ iplookupop_t op;
+ iphtent_t ipe;
+ char *what;
+ int err;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_type = IPLT_HASH;
+ op.iplo_unit = unit;
+ op.iplo_arg = 0;
+ op.iplo_size = sizeof(ipe);
+ op.iplo_struct = &ipe;
+ strncpy(op.iplo_name, name, sizeof(op.iplo_name));
+
+ bzero((char *)&ipe, sizeof(ipe));
+ ipe.ipe_family = node->ipe_family;
+ ipe.ipe_die = ttl;
+ bcopy((char *)&node->ipe_addr, (char *)&ipe.ipe_addr,
+ sizeof(ipe.ipe_addr));
+ bcopy((char *)&node->ipe_mask, (char *)&ipe.ipe_mask,
+ sizeof(ipe.ipe_mask));
+ bcopy((char *)&node->ipe_group, (char *)&ipe.ipe_group,
+ sizeof(ipe.ipe_group));
+
+ if ((opts & OPT_REMOVE) == 0) {
+ what = "add";
+ err = pool_ioctl(iocfunc, SIOCLOOKUPADDNODE, &op);
+ } else {
+ what = "delete";
+ err = pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op);
+ }
+
+ if (err != 0)
+ if (!(opts & OPT_DONOTHING)) {
+ char msg[80];
+
+ sprintf(msg, "%s node from lookup hash table", what);
+ return ipf_perror_fd(pool_fd(), iocfunc, msg);
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/load_http.c b/contrib/ipfilter/lib/load_http.c
new file mode 100644
index 0000000..88fc1e3
--- /dev/null
+++ b/contrib/ipfilter/lib/load_http.c
@@ -0,0 +1,208 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: load_http.c,v 1.5.2.5 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+/*
+ * Because the URL can be included twice into the buffer, once as the
+ * full path for the "GET" and once as the "Host:", the buffer it is
+ * put in needs to be larger than 512*2 to make room for the supporting
+ * text. Why not just use snprintf and truncate? The warning about the
+ * URL being too long tells you something is wrong and does not fetch
+ * any data - just truncating the URL (with snprintf, etc) and sending
+ * that to the server is allowing an unknown and unintentioned action
+ * to happen.
+ */
+#define MAX_URL_LEN 512
+#define LOAD_BUFSIZE (MAX_URL_LEN * 2 + 128)
+
+/*
+ * Format expected is one addres per line, at the start of each line.
+ */
+alist_t *
+load_http(char *url)
+{
+ int fd, len, left, port, endhdr, removed, linenum = 0;
+ char *s, *t, *u, buffer[LOAD_BUFSIZE], *myurl;
+ alist_t *a, *rtop, *rbot;
+ size_t avail;
+ int error;
+
+ /*
+ * More than this would just be absurd.
+ */
+ if (strlen(url) > MAX_URL_LEN) {
+ fprintf(stderr, "load_http has a URL > %d bytes?!\n",
+ MAX_URL_LEN);
+ return NULL;
+ }
+
+ fd = -1;
+ rtop = NULL;
+ rbot = NULL;
+
+ avail = sizeof(buffer);
+ error = snprintf(buffer, avail, "GET %s HTTP/1.0\r\n", url);
+
+ /*
+ * error is always less then avail due to the constraint on
+ * the url length above.
+ */
+ avail -= error;
+
+ myurl = strdup(url);
+ if (myurl == NULL)
+ goto done;
+
+ s = myurl + 7; /* http:// */
+ t = strchr(s, '/');
+ if (t == NULL) {
+ fprintf(stderr, "load_http has a malformed URL '%s'\n", url);
+ free(myurl);
+ return NULL;
+ }
+ *t++ = '\0';
+
+ /*
+ * 10 is the length of 'Host: \r\n\r\n' below.
+ */
+ if (strlen(s) + strlen(buffer) + 10 > sizeof(buffer)) {
+ fprintf(stderr, "load_http has a malformed URL '%s'\n", url);
+ free(myurl);
+ return NULL;
+ }
+
+ u = strchr(s, '@');
+ if (u != NULL)
+ s = u + 1; /* AUTH */
+
+ error = snprintf(buffer + strlen(buffer), avail, "Host: %s\r\n\r\n", s);
+ if (error >= avail) {
+ fprintf(stderr, "URL is too large: %s\n", url);
+ goto done;
+ }
+
+ u = strchr(s, ':');
+ if (u != NULL) {
+ *u++ = '\0';
+ port = atoi(u);
+ if (port < 0 || port > 65535)
+ goto done;
+ } else {
+ port = 80;
+ }
+
+
+ fd = connecttcp(s, port);
+ if (fd == -1)
+ goto done;
+
+
+ len = strlen(buffer);
+ if (write(fd, buffer, len) != len)
+ goto done;
+
+ s = buffer;
+ endhdr = 0;
+ left = sizeof(buffer) - 1;
+
+ while ((len = read(fd, s, left)) > 0) {
+ s[len] = '\0';
+ left -= len;
+ s += len;
+
+ if (endhdr >= 0) {
+ if (endhdr == 0) {
+ t = strchr(buffer, ' ');
+ if (t == NULL)
+ continue;
+ t++;
+ if (*t != '2')
+ break;
+ }
+
+ u = buffer;
+ while ((t = strchr(u, '\r')) != NULL) {
+ if (t == u) {
+ if (*(t + 1) == '\n') {
+ u = t + 2;
+ endhdr = -1;
+ break;
+ } else
+ t++;
+ } else if (*(t + 1) == '\n') {
+ endhdr++;
+ u = t + 2;
+ } else
+ u = t + 1;
+ }
+ if (endhdr >= 0)
+ continue;
+ removed = (u - buffer) + 1;
+ memmove(buffer, u, (sizeof(buffer) - left) - removed);
+ s -= removed;
+ left += removed;
+ }
+
+ do {
+ t = strchr(buffer, '\n');
+ if (t == NULL)
+ break;
+
+ linenum++;
+ *t = '\0';
+
+ /*
+ * Remove comment and continue to the next line if
+ * the comment is at the start of the line.
+ */
+ u = strchr(buffer, '#');
+ if (u != NULL) {
+ *u = '\0';
+ if (u == buffer)
+ continue;
+ }
+
+ /*
+ * Trim off tailing white spaces, will include \r
+ */
+ for (u = t - 1; (u >= buffer) && ISSPACE(*u); u--)
+ *u = '\0';
+
+ a = alist_new(AF_UNSPEC, buffer);
+ if (a != NULL) {
+ if (rbot != NULL)
+ rbot->al_next = a;
+ else
+ rtop = a;
+ rbot = a;
+ } else {
+ fprintf(stderr,
+ "%s:%d unrecognised content:%s\n",
+ url, linenum, buffer);
+ }
+
+ t++;
+ removed = t - buffer;
+ memmove(buffer, t, sizeof(buffer) - left - removed);
+ s -= removed;
+ left += removed;
+
+ } while (1);
+ }
+
+done:
+ if (myurl != NULL)
+ free(myurl);
+ if (fd != -1)
+ close(fd);
+ return rtop;
+}
diff --git a/contrib/ipfilter/lib/load_pool.c b/contrib/ipfilter/lib/load_pool.c
new file mode 100644
index 0000000..190a2df
--- /dev/null
+++ b/contrib/ipfilter/lib/load_pool.c
@@ -0,0 +1,72 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+
+
+int
+load_pool(plp, iocfunc)
+ ip_pool_t *plp;
+ ioctlfunc_t iocfunc;
+{
+ iplookupop_t op;
+ ip_pool_node_t *a;
+ ip_pool_t pool;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_unit = plp->ipo_unit;
+ op.iplo_type = IPLT_POOL;
+ op.iplo_arg = 0;
+ strncpy(op.iplo_name, plp->ipo_name, sizeof(op.iplo_name));
+ op.iplo_size = sizeof(pool);
+ op.iplo_struct = &pool;
+ bzero((char *)&pool, sizeof(pool));
+ pool.ipo_unit = plp->ipo_unit;
+ strncpy(pool.ipo_name, plp->ipo_name, sizeof(pool.ipo_name));
+ if (plp->ipo_name[0] == '\0')
+ op.iplo_arg |= IPOOL_ANON;
+
+ if ((opts & OPT_REMOVE) == 0) {
+ if (pool_ioctl(iocfunc, SIOCLOOKUPADDTABLE, &op)) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "add lookup table");
+ }
+ }
+ }
+
+ if (op.iplo_arg & IPOOL_ANON)
+ strncpy(pool.ipo_name, op.iplo_name, sizeof(pool.ipo_name));
+
+ if ((opts & OPT_VERBOSE) != 0) {
+ pool.ipo_list = plp->ipo_list;
+ (void) printpool(&pool, bcopywrap, pool.ipo_name, opts, NULL);
+ pool.ipo_list = NULL;
+ }
+
+ for (a = plp->ipo_list; a != NULL; a = a->ipn_next)
+ load_poolnode(plp->ipo_unit, pool.ipo_name,
+ a, 0, iocfunc);
+
+ if ((opts & OPT_REMOVE) != 0) {
+ if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op))
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "delete lookup table");
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/load_poolnode.c b/contrib/ipfilter/lib/load_poolnode.c
new file mode 100644
index 0000000..5afca84
--- /dev/null
+++ b/contrib/ipfilter/lib/load_poolnode.c
@@ -0,0 +1,70 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+
+
+int
+load_poolnode(role, name, node, ttl, iocfunc)
+ int role;
+ char *name;
+ ip_pool_node_t *node;
+ int ttl;
+ ioctlfunc_t iocfunc;
+{
+ ip_pool_node_t pn;
+ iplookupop_t op;
+ char *what;
+ int err;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_unit = role;
+ op.iplo_type = IPLT_POOL;
+ op.iplo_arg = 0;
+ op.iplo_struct = &pn;
+ op.iplo_size = sizeof(pn);
+ strncpy(op.iplo_name, name, sizeof(op.iplo_name));
+
+ bzero((char *)&pn, sizeof(pn));
+ bcopy((char *)&node->ipn_addr, (char *)&pn.ipn_addr,
+ sizeof(pn.ipn_addr));
+ bcopy((char *)&node->ipn_mask, (char *)&pn.ipn_mask,
+ sizeof(pn.ipn_mask));
+ pn.ipn_info = node->ipn_info;
+ pn.ipn_die = ttl;
+ strncpy(pn.ipn_name, node->ipn_name, sizeof(pn.ipn_name));
+
+ if ((opts & OPT_REMOVE) == 0) {
+ what = "add";
+ err = pool_ioctl(iocfunc, SIOCLOOKUPADDNODE, &op);
+ } else {
+ what = "delete";
+ err = pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op);
+ }
+
+ if (err != 0) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%s pool node(%s/", what,
+ inet_ntoa(pn.ipn_addr.adf_addr.in4));
+ strcat(msg, inet_ntoa(pn.ipn_mask.adf_addr.in4));
+ return ipf_perror_fd(pool_fd(), iocfunc, msg);
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/load_url.c b/contrib/ipfilter/lib/load_url.c
new file mode 100644
index 0000000..dcda4c0
--- /dev/null
+++ b/contrib/ipfilter/lib/load_url.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: load_url.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+alist_t *
+load_url(char *url)
+{
+ alist_t *hosts = NULL;
+
+ if (strncmp(url, "file://", 7) == 0) {
+ /*
+ * file:///etc/passwd
+ * ^------------s
+ */
+ hosts = load_file(url);
+
+ } else if (*url == '/' || *url == '.') {
+ hosts = load_file(url);
+
+ } else if (strncmp(url, "http://", 7) == 0) {
+ hosts = load_http(url);
+ }
+
+ return hosts;
+}
diff --git a/contrib/ipfilter/lib/mb_hexdump.c b/contrib/ipfilter/lib/mb_hexdump.c
new file mode 100644
index 0000000..6da6563
--- /dev/null
+++ b/contrib/ipfilter/lib/mb_hexdump.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: mb_hexdump.c,v 1.1.2.3 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+void
+mb_hexdump(m, fp)
+ mb_t *m;
+ FILE *fp;
+{
+ u_char *s;
+ int len;
+ int i;
+
+ for (; m != NULL; m = m->mb_next) {
+ len = m->mb_len;
+ for (s = (u_char *)m->mb_data, i = 0; i < len; i++) {
+ fprintf(fp, "%02x", *s++ & 0xff);
+ if (len - i > 1) {
+ i++;
+ fprintf(fp, "%02x", *s++ & 0xff);
+ }
+ fputc(' ', fp);
+ }
+ }
+ fputc('\n', fp);
+}
diff --git a/contrib/ipfilter/lib/msgdsize.c b/contrib/ipfilter/lib/msgdsize.c
new file mode 100644
index 0000000..9bdc584
--- /dev/null
+++ b/contrib/ipfilter/lib/msgdsize.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: msgdsize.c,v 1.2.4.3 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+size_t msgdsize(orig)
+ mb_t *orig;
+{
+ size_t sz = 0;
+ mb_t *m;
+
+ for (m = orig; m != NULL; m = m->mb_next)
+ sz += m->mb_len;
+ return sz;
+}
diff --git a/contrib/ipfilter/lib/mutex_emul.c b/contrib/ipfilter/lib/mutex_emul.c
new file mode 100644
index 0000000..1846701
--- /dev/null
+++ b/contrib/ipfilter/lib/mutex_emul.c
@@ -0,0 +1,133 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+#define EMM_MAGIC 0x9d7adba3
+
+static int mutex_debug = 0;
+static FILE *mutex_file = NULL;
+static int initcount = 0;
+
+void
+eMmutex_enter(mtx, file, line)
+ eMmutex_t *mtx;
+ char *file;
+ int line;
+{
+ if (mutex_debug & 2)
+ fprintf(mutex_file, "%s:%d:eMmutex_enter(%s)\n", file, line,
+ mtx->eMm_owner);
+ if (mtx->eMm_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMmutex_enter(%p): bad magic: %#x\n",
+ mtx->eMm_owner, mtx, mtx->eMm_magic);
+ abort();
+ }
+ if (mtx->eMm_held != 0) {
+ fprintf(stderr, "%s:eMmutex_enter(%p): already locked: %d\n",
+ mtx->eMm_owner, mtx, mtx->eMm_held);
+ abort();
+ }
+ mtx->eMm_held++;
+ mtx->eMm_heldin = file;
+ mtx->eMm_heldat = line;
+}
+
+
+void
+eMmutex_exit(mtx, file, line)
+ eMmutex_t *mtx;
+ char *file;
+ int line;
+{
+ if (mutex_debug & 2)
+ fprintf(mutex_file, "%s:%d:eMmutex_exit(%s)\n", file, line,
+ mtx->eMm_owner);
+ if (mtx->eMm_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMmutex_exit(%p): bad magic: %#x\n",
+ mtx->eMm_owner, mtx, mtx->eMm_magic);
+ abort();
+ }
+ if (mtx->eMm_held != 1) {
+ fprintf(stderr, "%s:eMmutex_exit(%p): not locked: %d\n",
+ mtx->eMm_owner, mtx, mtx->eMm_held);
+ abort();
+ }
+ mtx->eMm_held--;
+ mtx->eMm_heldin = NULL;
+ mtx->eMm_heldat = 0;
+}
+
+
+void
+eMmutex_init(mtx, who, file, line)
+ eMmutex_t *mtx;
+ char *who;
+ char *file;
+ int line;
+{
+ if (mutex_file == NULL && mutex_debug)
+ mutex_file = fopen("ipf_mutex_log", "w");
+ if (mutex_debug & 1)
+ fprintf(mutex_file, "%s:%d:eMmutex_init(%p,%s)\n",
+ file, line, mtx, who);
+ if (mtx->eMm_magic == EMM_MAGIC) { /* safe bet ? */
+ fprintf(stderr,
+ "%s:eMmutex_init(%p): already initialised?: %#x\n",
+ mtx->eMm_owner, mtx, mtx->eMm_magic);
+ abort();
+ }
+ mtx->eMm_magic = EMM_MAGIC;
+ mtx->eMm_held = 0;
+ if (who != NULL)
+ mtx->eMm_owner = strdup(who);
+ else
+ mtx->eMm_owner = NULL;
+ initcount++;
+}
+
+
+void
+eMmutex_destroy(mtx, file, line)
+ eMmutex_t *mtx;
+ char *file;
+ int line;
+{
+ if (mutex_debug & 1)
+ fprintf(mutex_file,
+ "%s:%d:eMmutex_destroy(%p,%s)\n", file, line,
+ mtx, mtx->eMm_owner);
+ if (mtx->eMm_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMmutex_destroy(%p): bad magic: %#x\n",
+ mtx->eMm_owner, mtx, mtx->eMm_magic);
+ abort();
+ }
+ if (mtx->eMm_held != 0) {
+ fprintf(stderr,
+ "%s:eMmutex_enter(%p): still locked: %d\n",
+ mtx->eMm_owner, mtx, mtx->eMm_held);
+ abort();
+ }
+ if (mtx->eMm_owner != NULL)
+ free(mtx->eMm_owner);
+ memset(mtx, 0xa5, sizeof(*mtx));
+ initcount--;
+}
+
+
+void
+ipf_mutex_clean()
+{
+ if (initcount != 0) {
+ if (mutex_file)
+ fprintf(mutex_file, "initcount %d\n", initcount);
+ abort();
+ }
+}
diff --git a/contrib/ipfilter/lib/nametokva.c b/contrib/ipfilter/lib/nametokva.c
new file mode 100644
index 0000000..8e7af94
--- /dev/null
+++ b/contrib/ipfilter/lib/nametokva.c
@@ -0,0 +1,38 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+ipfunc_t nametokva(name, iocfunc)
+ char *name;
+ ioctlfunc_t iocfunc;
+{
+ ipfunc_resolve_t res;
+ int fd;
+
+ strncpy(res.ipfu_name, name, sizeof(res.ipfu_name));
+ res.ipfu_addr = NULL;
+ fd = -1;
+
+ if ((opts & OPT_DONTOPEN) == 0) {
+ fd = open(IPL_NAME, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ }
+ (void) (*iocfunc)(fd, SIOCFUNCL, &res);
+ if (fd >= 0)
+ close(fd);
+ if (res.ipfu_addr == NULL)
+ res.ipfu_addr = (ipfunc_t)-1;
+ return res.ipfu_addr;
+}
diff --git a/contrib/ipfilter/lib/nat_setgroupmap.c b/contrib/ipfilter/lib/nat_setgroupmap.c
new file mode 100644
index 0000000..15c21f6
--- /dev/null
+++ b/contrib/ipfilter/lib/nat_setgroupmap.c
@@ -0,0 +1,34 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#include "ipf.h"
+
+void nat_setgroupmap(n)
+ ipnat_t *n;
+{
+ if (n->in_nsrcmsk == n->in_osrcmsk)
+ n->in_ippip = 1;
+ else if (n->in_flags & IPN_AUTOPORTMAP) {
+ n->in_ippip = ~ntohl(n->in_osrcmsk);
+ if (n->in_nsrcmsk != 0xffffffff)
+ n->in_ippip /= (~ntohl(n->in_nsrcmsk) + 1);
+ n->in_ippip++;
+ if (n->in_ippip == 0)
+ n->in_ippip = 1;
+ n->in_ppip = USABLE_PORTS / n->in_ippip;
+ } else {
+ n->in_space = USABLE_PORTS * ~ntohl(n->in_nsrcmsk);
+ n->in_snip = 0;
+ if (!(n->in_ppip = n->in_spmin))
+ n->in_ppip = 1;
+ n->in_ippip = USABLE_PORTS / n->in_ppip;
+ }
+}
diff --git a/contrib/ipfilter/lib/ntomask.c b/contrib/ipfilter/lib/ntomask.c
new file mode 100644
index 0000000..98e3b26
--- /dev/null
+++ b/contrib/ipfilter/lib/ntomask.c
@@ -0,0 +1,47 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+int ntomask(family, nbits, ap)
+ int family, nbits;
+ u_32_t *ap;
+{
+ u_32_t mask;
+
+ if (nbits < 0)
+ return -1;
+
+ switch (family)
+ {
+ case AF_INET :
+ if (nbits > 32 || use_inet6 == 1)
+ return -1;
+ if (nbits == 0) {
+ mask = 0;
+ } else {
+ mask = 0xffffffff;
+ mask <<= (32 - nbits);
+ }
+ *ap = htonl(mask);
+ break;
+
+ case 0 :
+ case AF_INET6 :
+ if ((nbits > 128) || (use_inet6 == -1))
+ return -1;
+ fill6bits(nbits, ap);
+ break;
+
+ default :
+ return -1;
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/optname.c b/contrib/ipfilter/lib/optname.c
new file mode 100644
index 0000000..2bc811b
--- /dev/null
+++ b/contrib/ipfilter/lib/optname.c
@@ -0,0 +1,65 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+u_32_t optname(cp, sp, linenum)
+ char ***cp;
+ u_short *sp;
+ int linenum;
+{
+ struct ipopt_names *io, *so;
+ u_long msk = 0;
+ u_short smsk = 0;
+ char *s;
+ int sec = 0;
+
+ for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
+ for (io = ionames; io->on_name; io++)
+ if (!strcasecmp(s, io->on_name)) {
+ msk |= io->on_bit;
+ break;
+ }
+ if (!io->on_name) {
+ fprintf(stderr, "%d: unknown IP option name %s\n",
+ linenum, s);
+ return 0;
+ }
+ if (!strcasecmp(s, "sec-class"))
+ sec = 1;
+ }
+
+ if (sec && !*(*cp + 1)) {
+ fprintf(stderr, "%d: missing security level after sec-class\n",
+ linenum);
+ return 0;
+ }
+
+ if (sec) {
+ (*cp)++;
+ for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
+ for (so = secclass; so->on_name; so++)
+ if (!strcasecmp(s, so->on_name)) {
+ smsk |= so->on_bit;
+ break;
+ }
+ if (!so->on_name) {
+ fprintf(stderr,
+ "%d: no such security level: %s\n",
+ linenum, s);
+ return 0;
+ }
+ }
+ if (smsk)
+ *sp = smsk;
+ }
+ return msk;
+}
diff --git a/contrib/ipfilter/lib/optprint.c b/contrib/ipfilter/lib/optprint.c
new file mode 100644
index 0000000..8b1f5cd
--- /dev/null
+++ b/contrib/ipfilter/lib/optprint.c
@@ -0,0 +1,83 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+void optprint(sec, optmsk, optbits)
+ u_short *sec;
+ u_long optmsk, optbits;
+{
+ u_short secmsk = sec[0], secbits = sec[1];
+ struct ipopt_names *io, *so;
+ char *s;
+
+ s = " opt ";
+ for (io = ionames; io->on_name; io++)
+ if ((io->on_bit & optmsk) &&
+ ((io->on_bit & optmsk) == (io->on_bit & optbits))) {
+ if ((io->on_value != IPOPT_SECURITY) ||
+ (!secmsk && !secbits)) {
+ printf("%s%s", s, io->on_name);
+ /*
+ * Because the ionames table has this entry
+ * twice.
+ */
+ if (io->on_value == IPOPT_SECURITY)
+ io++;
+ s = ",";
+ }
+ }
+
+
+ if (secmsk & secbits) {
+ printf("%ssec-class", s);
+ s = " ";
+ for (so = secclass; so->on_name; so++)
+ if ((secmsk & so->on_bit) &&
+ ((so->on_bit & secmsk) == (so->on_bit & secbits))) {
+ printf("%s%s", s, so->on_name);
+ s = ",";
+ }
+ }
+
+ if ((optmsk && (optmsk != optbits)) ||
+ (secmsk && (secmsk != secbits))) {
+ s = " ";
+ printf(" not opt");
+ if (optmsk != optbits) {
+ for (io = ionames; io->on_name; io++)
+ if ((io->on_bit & optmsk) &&
+ ((io->on_bit & optmsk) !=
+ (io->on_bit & optbits))) {
+ if ((io->on_value != IPOPT_SECURITY) ||
+ (!secmsk && !secbits)) {
+ printf("%s%s", s, io->on_name);
+ s = ",";
+ if (io->on_value ==
+ IPOPT_SECURITY)
+ io++;
+ } else
+ io++;
+ }
+ }
+
+ if (secmsk != secbits) {
+ printf("%ssec-class", s);
+ s = " ";
+ for (so = secclass; so->on_name; so++)
+ if ((so->on_bit & secmsk) &&
+ ((so->on_bit & secmsk) !=
+ (so->on_bit & secbits))) {
+ printf("%s%s", s, so->on_name);
+ s = ",";
+ }
+ }
+ }
+}
diff --git a/contrib/ipfilter/lib/optprintv6.c b/contrib/ipfilter/lib/optprintv6.c
new file mode 100644
index 0000000..752d1b3
--- /dev/null
+++ b/contrib/ipfilter/lib/optprintv6.c
@@ -0,0 +1,47 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+#ifdef USE_INET6
+
+void optprintv6(sec, optmsk, optbits)
+ u_short *sec;
+ u_long optmsk, optbits;
+{
+ u_short secmsk = sec[0], secbits = sec[1];
+ struct ipopt_names *io;
+ char *s;
+
+ s = " v6hdr ";
+ for (io = v6ionames; io->on_name; io++)
+ if ((io->on_bit & optmsk) &&
+ ((io->on_bit & optmsk) == (io->on_bit & optbits))) {
+ printf("%s%s", s, io->on_name);
+ s = ",";
+ }
+
+ if ((optmsk && (optmsk != optbits)) ||
+ (secmsk && (secmsk != secbits))) {
+ s = " ";
+ printf(" not v6hdrs");
+ if (optmsk != optbits) {
+ for (io = v6ionames; io->on_name; io++)
+ if ((io->on_bit & optmsk) &&
+ ((io->on_bit & optmsk) !=
+ (io->on_bit & optbits))) {
+ printf("%s%s", s, io->on_name);
+ s = ",";
+ }
+ }
+
+ }
+}
+#endif
diff --git a/contrib/ipfilter/lib/optvalue.c b/contrib/ipfilter/lib/optvalue.c
new file mode 100644
index 0000000..5bc1f42
--- /dev/null
+++ b/contrib/ipfilter/lib/optvalue.c
@@ -0,0 +1,34 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+u_32_t getoptbyname(optname)
+ char *optname;
+{
+ struct ipopt_names *io;
+
+ for (io = ionames; io->on_name; io++)
+ if (!strcasecmp(optname, io->on_name))
+ return io->on_bit;
+ return -1;
+}
+
+
+u_32_t getoptbyvalue(optval)
+ int optval;
+{
+ struct ipopt_names *io;
+
+ for (io = ionames; io->on_name; io++)
+ if (io->on_value == optval)
+ return io->on_bit;
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/parsefields.c b/contrib/ipfilter/lib/parsefields.c
new file mode 100644
index 0000000..241496c
--- /dev/null
+++ b/contrib/ipfilter/lib/parsefields.c
@@ -0,0 +1,48 @@
+#include "ipf.h"
+
+extern int nohdrfields;
+
+wordtab_t *parsefields(table, arg)
+ wordtab_t *table;
+ char *arg;
+{
+ wordtab_t *f, *fields;
+ char *s, *t;
+ int num;
+
+ fields = NULL;
+ num = 0;
+
+ for (s = strtok(arg, ","); s != NULL; s = strtok(NULL, ",")) {
+ t = strchr(s, '=');
+ if (t != NULL) {
+ *t++ = '\0';
+ if (*t == '\0')
+ nohdrfields = 1;
+ }
+
+ f = findword(table, s);
+ if (f == NULL) {
+ fprintf(stderr, "Unknown field '%s'\n", s);
+ exit(1);
+ }
+
+ num++;
+ if (fields == NULL) {
+ fields = malloc(2 * sizeof(*fields));
+ } else {
+ fields = realloc(fields, (num + 1) * sizeof(*fields));
+ }
+
+ if (t == NULL) {
+ fields[num - 1].w_word = f->w_word;
+ } else {
+ fields[num - 1].w_word = t;
+ }
+ fields[num - 1].w_value = f->w_value;
+ fields[num].w_word = NULL;
+ fields[num].w_value = 0;
+ }
+
+ return fields;
+}
diff --git a/contrib/ipfilter/lib/parseipfexpr.c b/contrib/ipfilter/lib/parseipfexpr.c
new file mode 100644
index 0000000..9a2a207
--- /dev/null
+++ b/contrib/ipfilter/lib/parseipfexpr.c
@@ -0,0 +1,283 @@
+#include "ipf.h"
+#include <ctype.h>
+
+
+typedef struct ipfopentry {
+ int ipoe_cmd;
+ int ipoe_nbasearg;
+ int ipoe_maxarg;
+ int ipoe_argsize;
+ char *ipoe_word;
+} ipfopentry_t;
+
+static ipfopentry_t opwords[17] = {
+ { IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" },
+ { IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" },
+ { IPF_EXP_IP_PR, 1, 0, 1, "ip.p" },
+ { IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" },
+ { IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" },
+ { IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" },
+ { IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" },
+ { IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" },
+ { IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" },
+ { IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" },
+ { IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" },
+ { IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" },
+ { IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" },
+ { IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" },
+ { IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" },
+ { IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" },
+ { -1, 0, 0, 0, NULL }
+};
+
+
+int *
+parseipfexpr(line, errorptr)
+ char *line;
+ char **errorptr;
+{
+ int not, items, asize, *oplist, osize, i;
+ char *temp, *arg, *s, *t, *ops, *error;
+ ipfopentry_t *e;
+ ipfexp_t *ipfe;
+
+ asize = 0;
+ error = NULL;
+ oplist = NULL;
+
+ temp = strdup(line);
+ if (temp == NULL) {
+ error = "strdup failed";
+ goto parseerror;
+ }
+
+ /*
+ * Eliminate any white spaces to make parsing easier.
+ */
+ for (s = temp; *s != '\0'; ) {
+ if (ISSPACE(*s))
+ strcpy(s, s + 1);
+ else
+ s++;
+ }
+
+ /*
+ * Parse the string.
+ * It should be sets of "ip.dst=1.2.3.4/32;" things.
+ * There must be a "=" or "!=" and it must end in ";".
+ */
+ if (temp[strlen(temp) - 1] != ';') {
+ error = "last character not ';'";
+ goto parseerror;
+ }
+
+ /*
+ * Work through the list of complete operands present.
+ */
+ for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) {
+ arg = strchr(ops, '=');
+ if ((arg < ops + 2) || (arg == NULL)) {
+ error = "bad 'arg' vlaue";
+ goto parseerror;
+ }
+
+ if (*(arg - 1) == '!') {
+ *(arg - 1) = '\0';
+ not = 1;
+ } else {
+ not = 0;
+ }
+ *arg++ = '\0';
+
+
+ for (e = opwords; e->ipoe_word; e++) {
+ if (strcmp(ops, e->ipoe_word) == 0)
+ break;
+ }
+ if (e->ipoe_word == NULL) {
+ error = malloc(32);
+ if (error != NULL) {
+ sprintf(error, "keyword (%.10s) not found",
+ ops);
+ }
+ goto parseerror;
+ }
+
+ /*
+ * Count the number of commas so we know how big to
+ * build the array
+ */
+ for (s = arg, items = 1; *s != '\0'; s++)
+ if (*s == ',')
+ items++;
+
+ if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) {
+ error = "too many items";
+ goto parseerror;
+ }
+
+ /*
+ * osize will mark the end of where we have filled up to
+ * and is thus where we start putting new data.
+ */
+ osize = asize;
+ asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize);
+ if (oplist == NULL)
+ oplist = calloc(1, sizeof(int) * (asize + 2));
+ else
+ oplist = realloc(oplist, sizeof(int) * (asize + 2));
+ if (oplist == NULL) {
+ error = "oplist alloc failed";
+ goto parseerror;
+ }
+ ipfe = (ipfexp_t *)(oplist + osize);
+ osize += 4;
+ ipfe->ipfe_cmd = e->ipoe_cmd;
+ ipfe->ipfe_not = not;
+ ipfe->ipfe_narg = items * e->ipoe_nbasearg;
+ ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize;
+ ipfe->ipfe_size += 4;
+
+ for (s = arg; (*s != '\0') && (osize < asize); s = t) {
+ /*
+ * Look for the end of this arg or the ',' to say
+ * there is another following.
+ */
+ for (t = s; (*t != '\0') && (*t != ','); t++)
+ ;
+ if (*t == ',')
+ *t++ = '\0';
+
+ if (!strcasecmp(ops, "ip.addr") ||
+ !strcasecmp(ops, "ip.src") ||
+ !strcasecmp(ops, "ip.dst")) {
+ i6addr_t mask, addr;
+ char *delim;
+
+ delim = strchr(s, '/');
+ if (delim != NULL) {
+ *delim++ = '\0';
+ if (genmask(AF_INET, delim,
+ &mask) == -1) {
+ error = "genmask failed";
+ goto parseerror;
+ }
+ } else {
+ mask.in4.s_addr = 0xffffffff;
+ }
+ if (gethost(AF_INET, s, &addr) == -1) {
+ error = "gethost failed";
+ goto parseerror;
+ }
+
+ oplist[osize++] = addr.in4.s_addr;
+ oplist[osize++] = mask.in4.s_addr;
+
+#ifdef USE_INET6
+ } else if (!strcasecmp(ops, "ip6.addr") ||
+ !strcasecmp(ops, "ip6.src") ||
+ !strcasecmp(ops, "ip6.dst")) {
+ i6addr_t mask, addr;
+ char *delim;
+
+ delim = strchr(s, '/');
+ if (delim != NULL) {
+ *delim++ = '\0';
+ if (genmask(AF_INET6, delim,
+ &mask) == -1) {
+ error = "genmask failed";
+ goto parseerror;
+ }
+ } else {
+ mask.i6[0] = 0xffffffff;
+ mask.i6[1] = 0xffffffff;
+ mask.i6[2] = 0xffffffff;
+ mask.i6[3] = 0xffffffff;
+ }
+ if (gethost(AF_INET6, s, &addr) == -1) {
+ error = "gethost failed";
+ goto parseerror;
+ }
+
+ oplist[osize++] = addr.i6[0];
+ oplist[osize++] = addr.i6[1];
+ oplist[osize++] = addr.i6[2];
+ oplist[osize++] = addr.i6[3];
+ oplist[osize++] = mask.i6[0];
+ oplist[osize++] = mask.i6[1];
+ oplist[osize++] = mask.i6[2];
+ oplist[osize++] = mask.i6[3];
+#endif
+
+ } else if (!strcasecmp(ops, "ip.p")) {
+ int p;
+
+ p = getproto(s);
+ if (p == -1)
+ goto parseerror;
+ oplist[osize++] = p;
+
+ } else if (!strcasecmp(ops, "tcp.flags")) {
+ u_32_t mask, flags;
+ char *delim;
+
+ delim = strchr(s, '/');
+ if (delim != NULL) {
+ *delim++ = '\0';
+ mask = tcpflags(delim);
+ } else {
+ mask = 0xff;
+ }
+ flags = tcpflags(s);
+
+ oplist[osize++] = flags;
+ oplist[osize++] = mask;
+
+
+ } else if (!strcasecmp(ops, "tcp.port") ||
+ !strcasecmp(ops, "tcp.sport") ||
+ !strcasecmp(ops, "tcp.dport") ||
+ !strcasecmp(ops, "udp.port") ||
+ !strcasecmp(ops, "udp.sport") ||
+ !strcasecmp(ops, "udp.dport")) {
+ char proto[4];
+ u_short port;
+
+ strncpy(proto, ops, 3);
+ proto[3] = '\0';
+ if (getport(NULL, s, &port, proto) == -1)
+ goto parseerror;
+ oplist[osize++] = port;
+
+ } else if (!strcasecmp(ops, "tcp.state")) {
+ oplist[osize++] = atoi(s);
+
+ } else {
+ error = "unknown word";
+ goto parseerror;
+ }
+ }
+ }
+
+ free(temp);
+
+ if (errorptr != NULL)
+ *errorptr = NULL;
+
+ for (i = asize; i > 0; i--)
+ oplist[i] = oplist[i - 1];
+
+ oplist[0] = asize + 2;
+ oplist[asize + 1] = IPF_EXP_END;
+
+ return oplist;
+
+parseerror:
+ if (errorptr != NULL)
+ *errorptr = error;
+ if (oplist != NULL)
+ free(oplist);
+ if (temp != NULL)
+ free(temp);
+ return NULL;
+}
diff --git a/contrib/ipfilter/lib/parsewhoisline.c b/contrib/ipfilter/lib/parsewhoisline.c
new file mode 100644
index 0000000..526935c
--- /dev/null
+++ b/contrib/ipfilter/lib/parsewhoisline.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: parsewhoisline.c,v 1.2.2.5 2012/07/22 08:04:24 darren_r Exp $
+ */
+#include "ipf.h"
+
+/*
+Microsoft Corp MICROSOFT19 (NET-198-136-97-0-1) 198.137.97.0 - 198.137.97.255
+Microsoft Corp SAVV-S233053-6 (NET-206-79-74-32-1) 206.79.74.32 - 206.79.74.47
+ */
+int
+parsewhoisline(line, addrp, maskp)
+ char *line;
+ addrfamily_t *addrp;
+ addrfamily_t *maskp;
+{
+ struct in_addr a1, a2;
+ char *src = line;
+ char *s = NULL;
+
+ if (line == NULL)
+ return -1;
+
+ while (*src != '\0') {
+ s = strchr(src, '(');
+ if (s == NULL)
+ break;
+
+ if (strncmp(s, "(NET", 4)) {
+ src = s + 1;
+ }
+ break;
+ }
+
+ if (s == NULL)
+ return -1;
+
+ memset(addrp, 0x00, sizeof(*maskp));
+ memset(maskp, 0x00, sizeof(*maskp));
+
+ if (*(s + 4) == '6') {
+#ifdef USE_INET6
+ i6addr_t a61, a62;
+
+ s = strchr(s, ')');
+ if (s == NULL || *++s != ' ')
+ return -1;
+ /*
+ * Parse the IPv6
+ */
+ if (inet_pton(AF_INET6, s, &a61.in6) != 1)
+ return -1;
+
+ s = strchr(s, ' ');
+ if (s == NULL || strncmp(s, " - ", 3))
+ return -1;
+
+ s += 3;
+ if (inet_pton(AF_INET6, s, &a62) != 1)
+ return -1;
+
+ addrp->adf_addr = a61;
+ addrp->adf_family = AF_INET6;
+ addrp->adf_len = offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in6_addr);
+
+ maskp->adf_addr.i6[0] = ~(a62.i6[0] ^ a61.i6[0]);
+ maskp->adf_addr.i6[1] = ~(a62.i6[1] ^ a61.i6[1]);
+ maskp->adf_addr.i6[2] = ~(a62.i6[2] ^ a61.i6[2]);
+ maskp->adf_addr.i6[3] = ~(a62.i6[3] ^ a61.i6[3]);
+
+ /*
+ * If the mask that's been generated isn't a consecutive mask
+ * then we can't add it into a pool.
+ */
+ if (count6bits(maskp->adf_addr.i6) == -1)
+ return -1;
+
+ maskp->adf_family = AF_INET6;
+ maskp->adf_len = addrp->adf_len;
+
+ if (IP6_MASKNEQ(&addrp->adf_addr.in6, &maskp->adf_addr.in6,
+ &addrp->adf_addr.in6)) {
+ return -1;
+ }
+ return 0;
+#else
+ return -1;
+#endif
+ }
+
+ s = strchr(s, ')');
+ if (s == NULL || *++s != ' ')
+ return -1;
+
+ s++;
+
+ if (inet_aton(s, &a1) != 1)
+ return -1;
+
+ s = strchr(s, ' ');
+ if (s == NULL || strncmp(s, " - ", 3))
+ return -1;
+
+ s += 3;
+ if (inet_aton(s, &a2) != 1)
+ return -1;
+
+ addrp->adf_addr.in4 = a1;
+ addrp->adf_family = AF_INET;
+ addrp->adf_len = offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in_addr);
+ maskp->adf_addr.in4.s_addr = ~(a2.s_addr ^ a1.s_addr);
+
+ /*
+ * If the mask that's been generated isn't a consecutive mask then
+ * we can't add it into a pool.
+ */
+ if (count4bits(maskp->adf_addr.in4.s_addr) == -1)
+ return -1;
+
+ maskp->adf_family = AF_INET;
+ maskp->adf_len = addrp->adf_len;
+ bzero((char *)maskp + maskp->adf_len, sizeof(*maskp) - maskp->adf_len);
+ if ((addrp->adf_addr.in4.s_addr & maskp->adf_addr.in4.s_addr) !=
+ addrp->adf_addr.in4.s_addr)
+ return -1;
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/poolio.c b/contrib/ipfilter/lib/poolio.c
new file mode 100644
index 0000000..18cf698
--- /dev/null
+++ b/contrib/ipfilter/lib/poolio.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: poolio.c,v 1.1.2.3 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+
+static int poolfd = -1;
+
+
+int
+pool_open()
+{
+
+ if ((opts & OPT_DONTOPEN) != 0)
+ return 0;
+
+ if (poolfd == -1)
+ poolfd = open(IPLOOKUP_NAME, O_RDWR);
+ return poolfd;
+}
+
+int
+pool_ioctl(iocfunc, cmd, ptr)
+ ioctlfunc_t iocfunc;
+ ioctlcmd_t cmd;
+ void *ptr;
+{
+ return (*iocfunc)(poolfd, cmd, ptr);
+}
+
+
+void
+pool_close()
+{
+ if (poolfd != -1) {
+ close(poolfd);
+ poolfd = -1;
+ }
+}
+
+int
+pool_fd()
+{
+ return poolfd;
+}
diff --git a/contrib/ipfilter/lib/portname.c b/contrib/ipfilter/lib/portname.c
new file mode 100644
index 0000000..59345f4
--- /dev/null
+++ b/contrib/ipfilter/lib/portname.c
@@ -0,0 +1,43 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+char *portname(pr, port)
+ int pr, port;
+{
+ static char buf[32];
+ struct protoent *p = NULL;
+ struct servent *sv = NULL;
+ struct servent *sv1 = NULL;
+
+ if ((opts & OPT_NORESOLVE) == 0) {
+ if (pr == -1) {
+ if ((sv = getservbyport(htons(port), "tcp"))) {
+ strncpy(buf, sv->s_name, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ sv1 = getservbyport(htons(port), "udp");
+ sv = strncasecmp(buf, sv->s_name, strlen(buf)) ?
+ NULL : sv1;
+ }
+ if (sv)
+ return buf;
+ } else if ((pr != -2) && (p = getprotobynumber(pr))) {
+ if ((sv = getservbyport(htons(port), p->p_name))) {
+ strncpy(buf, sv->s_name, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ return buf;
+ }
+ }
+ }
+
+ (void) sprintf(buf, "%d", port);
+ return buf;
+}
diff --git a/contrib/ipfilter/lib/prependmbt.c b/contrib/ipfilter/lib/prependmbt.c
new file mode 100644
index 0000000..4f7220b
--- /dev/null
+++ b/contrib/ipfilter/lib/prependmbt.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: prependmbt.c,v 1.3.2.3 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+int prependmbt(fin, m)
+ fr_info_t *fin;
+ mb_t *m;
+{
+ m->mb_next = *fin->fin_mp;
+ *fin->fin_mp = m;
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/print_toif.c b/contrib/ipfilter/lib/print_toif.c
new file mode 100644
index 0000000..fb4a266
--- /dev/null
+++ b/contrib/ipfilter/lib/print_toif.c
@@ -0,0 +1,50 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void
+print_toif(family, tag, base, fdp)
+ int family;
+ char *tag;
+ char *base;
+ frdest_t *fdp;
+{
+ switch (fdp->fd_type)
+ {
+ case FRD_NORMAL :
+ PRINTF("%s %s%s", tag, base + fdp->fd_name,
+ (fdp->fd_ptr || (long)fdp->fd_ptr == -1) ? "" : "(!)");
+#ifdef USE_INET6
+ if (family == AF_INET6) {
+ if (IP6_NOTZERO(&fdp->fd_ip6)) {
+ char ipv6addr[80];
+
+ inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr,
+ sizeof(fdp->fd_ip6));
+ PRINTF(":%s", ipv6addr);
+ }
+ } else
+#endif
+ if (fdp->fd_ip.s_addr)
+ PRINTF(":%s", inet_ntoa(fdp->fd_ip));
+ putchar(' ');
+ break;
+
+ case FRD_DSTLIST :
+ PRINTF("%s dstlist/%s ", tag, base + fdp->fd_name);
+ break;
+
+ default :
+ PRINTF("%s <%d>", tag, fdp->fd_type);
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printactiveaddr.c b/contrib/ipfilter/lib/printactiveaddr.c
new file mode 100644
index 0000000..531cdc1
--- /dev/null
+++ b/contrib/ipfilter/lib/printactiveaddr.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+
+#include "ipf.h"
+
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: printactiveaddr.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $";
+#endif
+
+
+void
+printactiveaddress(v, fmt, addr, ifname)
+ int v;
+ char *fmt, *ifname;
+ i6addr_t *addr;
+{
+ switch (v)
+ {
+ case 4 :
+ PRINTF(fmt, inet_ntoa(addr->in4));
+ break;
+#ifdef USE_INET6
+ case 6 :
+ printaddr(AF_INET6, FRI_NORMAL, ifname, 0,
+ (u_32_t *)&addr->in6, NULL);
+ break;
+#endif
+ default :
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printactivenat.c b/contrib/ipfilter/lib/printactivenat.c
new file mode 100644
index 0000000..c696c0b
--- /dev/null
+++ b/contrib/ipfilter/lib/printactivenat.c
@@ -0,0 +1,149 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+
+#include "ipf.h"
+
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+void
+printactivenat(nat, opts, ticks)
+ nat_t *nat;
+ int opts;
+ u_long ticks;
+{
+
+ PRINTF("%s", getnattype(nat));
+
+ if (nat->nat_flags & SI_CLONE)
+ PRINTF(" CLONE");
+ if (nat->nat_phnext[0] == NULL && nat->nat_phnext[1] == NULL)
+ PRINTF(" ORPHAN");
+
+ putchar(' ');
+ if (nat->nat_redir & NAT_REWRITE) {
+ printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_osrc6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_osport));
+
+ putchar(' ');
+ printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_odst6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_odport));
+
+ PRINTF("<- -> ");
+ printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_nsrc6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_nsport));
+
+ putchar(' ');
+ printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_ndst6,
+ nat->nat_ifnames[0]);
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_ndport));
+
+ } else if (nat->nat_dir == NAT_OUTBOUND) {
+ printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_osrc6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_osport));
+
+ PRINTF(" <- -> ");
+ printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_nsrc6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_nsport));
+
+ PRINTF(" [");
+ printactiveaddress(nat->nat_v[0], "%s", &nat->nat_odst6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %hu", ntohs(nat->nat_odport));
+ PRINTF("]");
+ } else {
+ printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_ndst6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_ndport));
+
+ PRINTF(" <- -> ");
+ printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_odst6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %-5hu", ntohs(nat->nat_odport));
+
+ PRINTF(" [");
+ printactiveaddress(nat->nat_v[0], "%s", &nat->nat_osrc6,
+ nat->nat_ifnames[0]);
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0)
+ PRINTF(" %hu", ntohs(nat->nat_osport));
+ PRINTF("]");
+ }
+
+ if (opts & OPT_VERBOSE) {
+ PRINTF("\n\tttl %lu use %hu sumd %s/",
+ nat->nat_age - ticks, nat->nat_use,
+ getsumd(nat->nat_sumd[0]));
+ PRINTF("%s pr %u/%u hash %u/%u flags %x\n",
+ getsumd(nat->nat_sumd[1]),
+ nat->nat_pr[0], nat->nat_pr[1],
+ nat->nat_hv[0], nat->nat_hv[1], nat->nat_flags);
+ PRINTF("\tifp %s", getifname(nat->nat_ifps[0]));
+ PRINTF(",%s ", getifname(nat->nat_ifps[1]));
+#ifdef USE_QUAD_T
+ PRINTF("bytes %"PRIu64"/%"PRIu64" pkts %"PRIu64"/%"PRIu64"",
+ (unsigned long long)nat->nat_bytes[0],
+ (unsigned long long)nat->nat_bytes[1],
+ (unsigned long long)nat->nat_pkts[0],
+ (unsigned long long)nat->nat_pkts[1]);
+#else
+ PRINTF("bytes %lu/%lu pkts %lu/%lu", nat->nat_bytes[0],
+ nat->nat_bytes[1], nat->nat_pkts[0], nat->nat_pkts[1]);
+#endif
+ PRINTF(" ipsumd %x", nat->nat_ipsumd);
+ }
+
+ if (opts & OPT_DEBUG) {
+ PRINTF("\n\tnat_next %p _pnext %p _hm %p\n",
+ nat->nat_next, nat->nat_pnext, nat->nat_hm);
+ PRINTF("\t_hnext %p/%p _phnext %p/%p\n",
+ nat->nat_hnext[0], nat->nat_hnext[1],
+ nat->nat_phnext[0], nat->nat_phnext[1]);
+ PRINTF("\t_data %p _me %p _state %p _aps %p\n",
+ nat->nat_data, nat->nat_me, nat->nat_state,
+ nat->nat_aps);
+ PRINTF("\tfr %p ptr %p ifps %p/%p sync %p\n",
+ nat->nat_fr, nat->nat_ptr, nat->nat_ifps[0],
+ nat->nat_ifps[1], nat->nat_sync);
+ PRINTF("\ttqe:pnext %p next %p ifq %p parent %p/%p\n",
+ nat->nat_tqe.tqe_pnext, nat->nat_tqe.tqe_next,
+ nat->nat_tqe.tqe_ifq, nat->nat_tqe.tqe_parent, nat);
+ PRINTF("\ttqe:die %d touched %d flags %x state %d/%d\n",
+ nat->nat_tqe.tqe_die, nat->nat_tqe.tqe_touched,
+ nat->nat_tqe.tqe_flags, nat->nat_tqe.tqe_state[0],
+ nat->nat_tqe.tqe_state[1]);
+ }
+ putchar('\n');
+}
diff --git a/contrib/ipfilter/lib/printaddr.c b/contrib/ipfilter/lib/printaddr.c
new file mode 100644
index 0000000..03fbacb
--- /dev/null
+++ b/contrib/ipfilter/lib/printaddr.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+void
+printaddr(family, type, base, ifidx, addr, mask)
+ int family, type, ifidx;
+ char *base;
+ u_32_t *addr, *mask;
+{
+ char *suffix;
+
+ switch (type)
+ {
+ case FRI_BROADCAST :
+ suffix = "bcast";
+ break;
+
+ case FRI_DYNAMIC :
+ PRINTF("%s", base + ifidx);
+ printmask(family, mask);
+ suffix = NULL;
+ break;
+
+ case FRI_NETWORK :
+ suffix = "net";
+ break;
+
+ case FRI_NETMASKED :
+ suffix = "netmasked";
+ break;
+
+ case FRI_PEERADDR :
+ suffix = "peer";
+ break;
+
+ case FRI_LOOKUP :
+ suffix = NULL;
+ printlookup(base, (i6addr_t *)addr, (i6addr_t *)mask);
+ break;
+
+ case FRI_NONE :
+ case FRI_NORMAL :
+ printhostmask(family, addr, mask);
+ suffix = NULL;
+ break;
+ case FRI_RANGE :
+ printhost(family, addr);
+ putchar('-');
+ printhost(family, mask);
+ suffix = NULL;
+ break;
+ case FRI_SPLIT :
+ printhost(family, addr);
+ putchar(',');
+ printhost(family, mask);
+ suffix = NULL;
+ break;
+ default :
+ PRINTF("<%d>", type);
+ printmask(family, mask);
+ suffix = NULL;
+ break;
+ }
+
+ if (suffix != NULL) {
+ PRINTF("%s/%s", base + ifidx, suffix);
+ }
+}
diff --git a/contrib/ipfilter/lib/printaps.c b/contrib/ipfilter/lib/printaps.c
new file mode 100644
index 0000000..0304f34
--- /dev/null
+++ b/contrib/ipfilter/lib/printaps.c
@@ -0,0 +1,113 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+
+#include "ipf.h"
+#include "kmem.h"
+
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+void
+printaps(aps, opts, proto)
+ ap_session_t *aps;
+ int opts, proto;
+{
+ ipsec_pxy_t ipsec;
+ ap_session_t ap;
+ ftpinfo_t ftp;
+ aproxy_t apr;
+ raudio_t ra;
+
+ if (kmemcpy((char *)&ap, (long)aps, sizeof(ap)))
+ return;
+ if (kmemcpy((char *)&apr, (long)ap.aps_apr, sizeof(apr)))
+ return;
+ PRINTF("\tproxy %s/%d use %d flags %x\n", apr.apr_label,
+ apr.apr_p, apr.apr_ref, apr.apr_flags);
+#ifdef USE_QUAD_T
+ PRINTF("\tbytes %"PRIu64" pkts %"PRIu64"",
+ (unsigned long long)ap.aps_bytes,
+ (unsigned long long)ap.aps_pkts);
+#else
+ PRINTF("\tbytes %lu pkts %lu", ap.aps_bytes, ap.aps_pkts);
+#endif
+ PRINTF(" data %s\n", ap.aps_data ? "YES" : "NO");
+ if ((proto == IPPROTO_TCP) && (opts & OPT_VERBOSE)) {
+ PRINTF("\t\tstate[%u,%u], sel[%d,%d]\n",
+ ap.aps_state[0], ap.aps_state[1],
+ ap.aps_sel[0], ap.aps_sel[1]);
+#if (defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011)) || \
+ (__FreeBSD_version >= 300000) || defined(OpenBSD)
+ PRINTF("\t\tseq: off %hd/%hd min %x/%x\n",
+ ap.aps_seqoff[0], ap.aps_seqoff[1],
+ ap.aps_seqmin[0], ap.aps_seqmin[1]);
+ PRINTF("\t\tack: off %hd/%hd min %x/%x\n",
+ ap.aps_ackoff[0], ap.aps_ackoff[1],
+ ap.aps_ackmin[0], ap.aps_ackmin[1]);
+#else
+ PRINTF("\t\tseq: off %hd/%hd min %lx/%lx\n",
+ ap.aps_seqoff[0], ap.aps_seqoff[1],
+ ap.aps_seqmin[0], ap.aps_seqmin[1]);
+ PRINTF("\t\tack: off %hd/%hd min %lx/%lx\n",
+ ap.aps_ackoff[0], ap.aps_ackoff[1],
+ ap.aps_ackmin[0], ap.aps_ackmin[1]);
+#endif
+ }
+
+ if (!strcmp(apr.apr_label, "raudio") && ap.aps_psiz == sizeof(ra)) {
+ if (kmemcpy((char *)&ra, (long)ap.aps_data, sizeof(ra)))
+ return;
+ PRINTF("\tReal Audio Proxy:\n");
+ PRINTF("\t\tSeen PNA: %d\tVersion: %d\tEOS: %d\n",
+ ra.rap_seenpna, ra.rap_version, ra.rap_eos);
+ PRINTF("\t\tMode: %#x\tSBF: %#x\n", ra.rap_mode, ra.rap_sbf);
+ PRINTF("\t\tPorts:pl %hu, pr %hu, sr %hu\n",
+ ra.rap_plport, ra.rap_prport, ra.rap_srport);
+ } else if (!strcmp(apr.apr_label, "ftp") &&
+ (ap.aps_psiz == sizeof(ftp))) {
+ if (kmemcpy((char *)&ftp, (long)ap.aps_data, sizeof(ftp)))
+ return;
+ PRINTF("\tFTP Proxy:\n");
+ PRINTF("\t\tpassok: %d\n", ftp.ftp_passok);
+ ftp.ftp_side[0].ftps_buf[FTP_BUFSZ - 1] = '\0';
+ ftp.ftp_side[1].ftps_buf[FTP_BUFSZ - 1] = '\0';
+ PRINTF("\tClient:\n");
+ PRINTF("\t\tseq %x (ack %x) len %d junk %d cmds %d\n",
+ ftp.ftp_side[0].ftps_seq[0],
+ ftp.ftp_side[0].ftps_seq[1],
+ ftp.ftp_side[0].ftps_len, ftp.ftp_side[0].ftps_junk,
+ ftp.ftp_side[0].ftps_cmds);
+ PRINTF("\t\tbuf [");
+ printbuf(ftp.ftp_side[0].ftps_buf, FTP_BUFSZ, 1);
+ PRINTF("]\n\tServer:\n");
+ PRINTF("\t\tseq %x (ack %x) len %d junk %d cmds %d\n",
+ ftp.ftp_side[1].ftps_seq[0],
+ ftp.ftp_side[1].ftps_seq[1],
+ ftp.ftp_side[1].ftps_len, ftp.ftp_side[1].ftps_junk,
+ ftp.ftp_side[1].ftps_cmds);
+ PRINTF("\t\tbuf [");
+ printbuf(ftp.ftp_side[1].ftps_buf, FTP_BUFSZ, 1);
+ PRINTF("]\n");
+ } else if (!strcmp(apr.apr_label, "ipsec") &&
+ (ap.aps_psiz == sizeof(ipsec))) {
+ if (kmemcpy((char *)&ipsec, (long)ap.aps_data, sizeof(ipsec)))
+ return;
+ PRINTF("\tIPSec Proxy:\n");
+ PRINTF("\t\tICookie %08x%08x RCookie %08x%08x %s\n",
+ (u_int)ntohl(ipsec.ipsc_icookie[0]),
+ (u_int)ntohl(ipsec.ipsc_icookie[1]),
+ (u_int)ntohl(ipsec.ipsc_rcookie[0]),
+ (u_int)ntohl(ipsec.ipsc_rcookie[1]),
+ ipsec.ipsc_rckset ? "(Set)" : "(Not set)");
+ }
+}
diff --git a/contrib/ipfilter/lib/printbuf.c b/contrib/ipfilter/lib/printbuf.c
new file mode 100644
index 0000000..4e9236f0
--- /dev/null
+++ b/contrib/ipfilter/lib/printbuf.c
@@ -0,0 +1,34 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <ctype.h>
+
+#include "ipf.h"
+
+
+void
+printbuf(buf, len, zend)
+ char *buf;
+ int len, zend;
+{
+ char *s;
+ int c;
+ int i;
+
+ for (s = buf, i = len; i; i--) {
+ c = *s++;
+ if (isprint(c))
+ putchar(c);
+ else
+ PRINTF("\\%03o", c);
+ if ((c == '\0') && zend)
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printdstl_live.c b/contrib/ipfilter/lib/printdstl_live.c
new file mode 100644
index 0000000..c8741ed
--- /dev/null
+++ b/contrib/ipfilter/lib/printdstl_live.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+
+
+/*
+ * Because the ipf_dstnode_t can vary in size because of the interface name,
+ * the size may be larger than just sizeof().
+ */
+ippool_dst_t *
+printdstl_live(d, fd, name, opts, fields)
+ ippool_dst_t *d;
+ int fd;
+ char *name;
+ int opts;
+ wordtab_t *fields;
+{
+ ipf_dstnode_t *entry, *zero;
+ ipflookupiter_t iter;
+ int printed, last;
+ ipfobj_t obj;
+
+ if ((name != NULL) && strncmp(name, d->ipld_name, FR_GROUPLEN))
+ return d->ipld_next;
+
+ entry = calloc(1, sizeof(*entry) + 64);
+ if (entry == NULL)
+ return d->ipld_next;
+ zero = calloc(1, sizeof(*zero) + 64);
+ if (zero == NULL) {
+ free(entry);
+ return d->ipld_next;
+ }
+
+ if (fields == NULL)
+ printdstlistdata(d, opts);
+
+ if ((d->ipld_flags & IPHASH_DELETE) != 0)
+ PRINTF("# ");
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF("\t{");
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_ptr = &iter;
+ obj.ipfo_size = sizeof(iter);
+
+ iter.ili_data = entry;
+ iter.ili_type = IPLT_DSTLIST;
+ iter.ili_otype = IPFLOOKUPITER_NODE;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_unit = d->ipld_unit;
+ strncpy(iter.ili_name, d->ipld_name, FR_GROUPLEN);
+
+ last = 0;
+ printed = 0;
+
+ while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) {
+ if (entry->ipfd_next == NULL)
+ last = 1;
+ if (bcmp((char *)zero, (char *)entry, sizeof(*zero)) == 0)
+ break;
+ (void) printdstlistnode(entry, bcopywrap, opts, fields);
+ printed++;
+ }
+
+ (void) ioctl(fd, SIOCIPFDELTOK, &iter.ili_key);
+ free(entry);
+ free(zero);
+
+ if (printed == 0)
+ putchar(';');
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF(" };\n");
+ return d->ipld_next;
+}
diff --git a/contrib/ipfilter/lib/printdstlist.c b/contrib/ipfilter/lib/printdstlist.c
new file mode 100644
index 0000000..829a1d2
--- /dev/null
+++ b/contrib/ipfilter/lib/printdstlist.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+ippool_dst_t *
+printdstlist(pp, copyfunc, name, opts, nodes, fields)
+ ippool_dst_t *pp;
+ copyfunc_t copyfunc;
+ char *name;
+ int opts;
+ ipf_dstnode_t *nodes;
+ wordtab_t *fields;
+{
+ ipf_dstnode_t *node;
+ ippool_dst_t dst;
+
+ if ((*copyfunc)(pp, &dst, sizeof(dst)))
+ return NULL;
+
+ if ((name != NULL) && strncmp(name, dst.ipld_name, FR_GROUPLEN))
+ return dst.ipld_next;
+
+ if (fields == NULL)
+ printdstlistdata(&dst, opts);
+
+ if ((dst.ipld_flags & IPDST_DELETE) != 0)
+ PRINTF("# ");
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF("\t{");
+
+ if (nodes == NULL) {
+ putchar(';');
+ } else {
+ for (node = nodes; node != NULL; ) {
+ ipf_dstnode_t *n;
+
+ n = calloc(1, node->ipfd_size);
+ if (n == NULL)
+ break;
+ if ((*copyfunc)(node, n, node->ipfd_size)) {
+ free(n);
+ return NULL;
+ }
+
+ node = printdstlistnode(n, bcopywrap, opts, fields);
+
+ free(n);
+ }
+ }
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF(" };\n");
+
+ return dst.ipld_next;
+}
diff --git a/contrib/ipfilter/lib/printdstlistdata.c b/contrib/ipfilter/lib/printdstlistdata.c
new file mode 100644
index 0000000..8b55afd
--- /dev/null
+++ b/contrib/ipfilter/lib/printdstlistdata.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+
+void
+printdstlistdata(pool, opts)
+ ippool_dst_t *pool;
+ int opts;
+{
+
+ if ((opts & OPT_DEBUG) == 0) {
+ if ((pool->ipld_flags & IPDST_DELETE) != 0)
+ PRINTF("# ");
+ PRINTF("pool ");
+ } else {
+ if ((pool->ipld_flags & IPDST_DELETE) != 0)
+ PRINTF("# ");
+ PRINTF("Name: %s\tRole: ", pool->ipld_name);
+ }
+
+ printunit(pool->ipld_unit);
+
+ if ((opts & OPT_DEBUG) == 0) {
+ PRINTF("/dstlist (name %s;", pool->ipld_name);
+ if (pool->ipld_policy != IPLDP_NONE) {
+ PRINTF(" policy ");
+ printdstlistpolicy(pool->ipld_policy);
+ putchar(';');
+ }
+ PRINTF(")\n");
+ } else {
+ putchar(' ');
+
+ PRINTF("\tReferences: %d\n", pool->ipld_ref);
+ if ((pool->ipld_flags & IPDST_DELETE) != 0)
+ PRINTF("# ");
+ PRINTF("Policy: \n");
+ printdstlistpolicy(pool->ipld_policy);
+ PRINTF("\n\tNodes Starting at %p\n", pool->ipld_dests);
+ }
+}
diff --git a/contrib/ipfilter/lib/printdstlistnode.c b/contrib/ipfilter/lib/printdstlistnode.c
new file mode 100644
index 0000000..898986d
--- /dev/null
+++ b/contrib/ipfilter/lib/printdstlistnode.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+ipf_dstnode_t *
+printdstlistnode(inp, copyfunc, opts, fields)
+ ipf_dstnode_t *inp;
+ copyfunc_t copyfunc;
+ int opts;
+ wordtab_t *fields;
+{
+ ipf_dstnode_t node, *np;
+ int i;
+#ifdef USE_INET6
+ char buf[INET6_ADDRSTRLEN+1];
+ const char *str;
+#endif
+
+ if ((*copyfunc)(inp, &node, sizeof(node)))
+ return NULL;
+
+ np = calloc(1, node.ipfd_size);
+ if (np == NULL)
+ return node.ipfd_next;
+ if ((*copyfunc)(inp, np, node.ipfd_size))
+ return NULL;
+
+ if (fields != NULL) {
+ for (i = 0; fields[i].w_value != 0; i++) {
+ printpoolfield(np, IPLT_DSTLIST, i);
+ if (fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ } else if ((opts & OPT_DEBUG) == 0) {
+ putchar(' ');
+ if (np->ipfd_dest.fd_name >= 0)
+ PRINTF("%s:", np->ipfd_names);
+ if (np->ipfd_dest.fd_addr.adf_family == AF_INET) {
+ printip(AF_INET, (u_32_t *)&np->ipfd_dest.fd_ip);
+ } else {
+#ifdef USE_INET6
+ str = inet_ntop(AF_INET6, &np->ipfd_dest.fd_ip6,
+ buf, sizeof(buf) - 1);
+ if (str != NULL)
+ PRINTF("%s", str);
+#endif
+ }
+ putchar(';');
+ } else {
+ PRINTF("Interface: [%s]/%d\n", np->ipfd_names,
+ np->ipfd_dest.fd_name);
+#ifdef USE_INET6
+ str = inet_ntop(np->ipfd_dest.fd_addr.adf_family,
+ &np->ipfd_dest.fd_ip6, buf, sizeof(buf) - 1);
+ if (str != NULL) {
+ PRINTF("\tAddress: %s\n", str);
+ }
+#else
+ PRINTF("\tAddress: %s\n", inet_ntoa(np->ipfd_dest.fd_ip));
+#endif
+ PRINTF(
+#ifdef USE_QUAD_T
+ "\t\tStates %d\tRef %d\tName [%s]\tUid %d\n",
+#else
+ "\t\tStates %d\tRef %d\tName [%s]\tUid %d\n",
+#endif
+ np->ipfd_states, np->ipfd_ref,
+ np->ipfd_names, np->ipfd_uid);
+ }
+ free(np);
+ return node.ipfd_next;
+}
diff --git a/contrib/ipfilter/lib/printdstlistpolicy.c b/contrib/ipfilter/lib/printdstlistpolicy.c
new file mode 100644
index 0000000..4873b95
--- /dev/null
+++ b/contrib/ipfilter/lib/printdstlistpolicy.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+void
+printdstlistpolicy(policy)
+ ippool_policy_t policy;
+{
+ switch (policy)
+ {
+ case IPLDP_NONE :
+ PRINTF("none");
+ break;
+ case IPLDP_ROUNDROBIN :
+ PRINTF("round-robin");
+ break;
+ case IPLDP_CONNECTION :
+ PRINTF("weighting connection");
+ break;
+ case IPLDP_RANDOM :
+ PRINTF("random");
+ break;
+ default :
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printfieldhdr.c b/contrib/ipfilter/lib/printfieldhdr.c
new file mode 100644
index 0000000..3cc22a6
--- /dev/null
+++ b/contrib/ipfilter/lib/printfieldhdr.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: printfieldhdr.c,v 1.5.2.3 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+
+void
+printfieldhdr(words, field)
+ wordtab_t *words, *field;
+{
+ wordtab_t *w;
+ char *s, *t;
+ int i;
+
+ if (field->w_value == -2) {
+ for (i = 0, w = words; w->w_word != NULL; ) {
+ if (w->w_value > 0) {
+ printfieldhdr(words, w);
+ w++;
+ if (w->w_value > 0)
+ putchar('\t');
+ } else {
+ w++;
+ }
+ }
+ return;
+ }
+
+ for (w = words; w->w_word != NULL; w++) {
+ if (w->w_value == field->w_value) {
+ if (w->w_word == field->w_word) {
+ s = strdup(w->w_word);
+ } else {
+ s = NULL;
+ }
+
+ if ((w->w_word != field->w_word) || (s == NULL)) {
+ PRINTF("%s", field->w_word);
+ } else {
+ for (t = s; *t != '\0'; t++) {
+ if (ISALPHA(*t) && ISLOWER(*t))
+ *t = TOUPPER(*t);
+ }
+ PRINTF("%s", s);
+ free(s);
+ }
+ }
+ }
+}
diff --git a/contrib/ipfilter/lib/printfr.c b/contrib/ipfilter/lib/printfr.c
new file mode 100644
index 0000000..9883df4
--- /dev/null
+++ b/contrib/ipfilter/lib/printfr.c
@@ -0,0 +1,473 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+/*
+ * print the filter structure in a useful way
+ */
+void
+printfr(fp, iocfunc)
+ struct frentry *fp;
+ ioctlfunc_t iocfunc;
+{
+ struct protoent *p;
+ u_short sec[2];
+ u_32_t type;
+ int pr, af;
+ char *s;
+ int hash;
+
+ pr = -2;
+ type = fp->fr_type & ~FR_T_BUILTIN;
+
+ if ((fp->fr_type & FR_T_BUILTIN) != 0)
+ PRINTF("# Builtin: ");
+
+ if (fp->fr_collect != 0)
+ PRINTF("%u ", fp->fr_collect);
+
+ if (fp->fr_type == FR_T_CALLFUNC) {
+ ;
+ } else if (fp->fr_func != NULL) {
+ PRINTF("call");
+ if ((fp->fr_flags & FR_CALLNOW) != 0)
+ PRINTF(" now");
+ s = kvatoname(fp->fr_func, iocfunc);
+ PRINTF(" %s/%u", s ? s : "?", fp->fr_arg);
+ } else if (FR_ISPASS(fp->fr_flags))
+ PRINTF("pass");
+ else if (FR_ISBLOCK(fp->fr_flags)) {
+ PRINTF("block");
+ } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
+ printlog(fp);
+ } else if (FR_ISACCOUNT(fp->fr_flags))
+ PRINTF("count");
+ else if (FR_ISAUTH(fp->fr_flags))
+ PRINTF("auth");
+ else if (FR_ISPREAUTH(fp->fr_flags))
+ PRINTF("preauth");
+ else if (FR_ISNOMATCH(fp->fr_flags))
+ PRINTF("nomatch");
+ else if (FR_ISDECAPS(fp->fr_flags))
+ PRINTF("decapsulate");
+ else if (FR_ISSKIP(fp->fr_flags))
+ PRINTF("skip %u", fp->fr_arg);
+ else {
+ PRINTF("%x", fp->fr_flags);
+ }
+ if (fp->fr_flags & FR_RETICMP) {
+ if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP)
+ PRINTF(" return-icmp-as-dest");
+ else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP)
+ PRINTF(" return-icmp");
+ if (fp->fr_icode) {
+ if (fp->fr_icode <= MAX_ICMPCODE)
+ PRINTF("(%s)",
+ icmpcodes[(int)fp->fr_icode]);
+ else
+ PRINTF("(%d)", fp->fr_icode);
+ }
+ } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
+ PRINTF(" return-rst");
+
+ if (fp->fr_flags & FR_OUTQUE)
+ PRINTF(" out ");
+ else if (fp->fr_flags & FR_INQUE)
+ PRINTF(" in ");
+
+ if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
+ ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
+ printlog(fp);
+ putchar(' ');
+ }
+
+ if (fp->fr_flags & FR_QUICK)
+ PRINTF("quick ");
+
+ if (fp->fr_ifnames[0] != -1) {
+ printifname("on ", fp->fr_names + fp->fr_ifnames[0],
+ fp->fr_ifa);
+ if (fp->fr_ifnames[1] != -1 &&
+ strcmp(fp->fr_names + fp->fr_ifnames[1], "*"))
+ printifname(",", fp->fr_names + fp->fr_ifnames[1],
+ fp->fr_ifas[1]);
+ putchar(' ');
+ }
+
+ if (fp->fr_tif.fd_name != -1)
+ print_toif(fp->fr_family, "to", fp->fr_names, &fp->fr_tif);
+ if (fp->fr_dif.fd_name != -1)
+ print_toif(fp->fr_family, "dup-to", fp->fr_names,
+ &fp->fr_dif);
+ if (fp->fr_rif.fd_name != -1)
+ print_toif(fp->fr_family, "reply-to", fp->fr_names,
+ &fp->fr_rif);
+ if (fp->fr_flags & FR_FASTROUTE)
+ PRINTF("fastroute ");
+
+ if ((fp->fr_ifnames[2] != -1 &&
+ strcmp(fp->fr_names + fp->fr_ifnames[2], "*")) ||
+ (fp->fr_ifnames[3] != -1 &&
+ strcmp(fp->fr_names + fp->fr_ifnames[3], "*"))) {
+ if (fp->fr_flags & FR_OUTQUE)
+ PRINTF("in-via ");
+ else
+ PRINTF("out-via ");
+
+ if (fp->fr_ifnames[2] != -1) {
+ printifname("", fp->fr_names + fp->fr_ifnames[2],
+ fp->fr_ifas[2]);
+ if (fp->fr_ifnames[3] != -1) {
+ printifname(",",
+ fp->fr_names + fp->fr_ifnames[3],
+ fp->fr_ifas[3]);
+ }
+ putchar(' ');
+ }
+ }
+
+ if (fp->fr_family == AF_INET) {
+ PRINTF("inet ");
+ af = AF_INET;
+#ifdef USE_INET6
+ } else if (fp->fr_family == AF_INET6) {
+ PRINTF("inet6 ");
+ af = AF_INET6;
+#endif
+ } else {
+ af = -1;
+ }
+
+ if (type == FR_T_IPF) {
+ if (fp->fr_mip.fi_tos)
+ PRINTF("tos %#x ", fp->fr_tos);
+ if (fp->fr_mip.fi_ttl)
+ PRINTF("ttl %d ", fp->fr_ttl);
+ if (fp->fr_flx & FI_TCPUDP) {
+ PRINTF("proto tcp/udp ");
+ pr = -1;
+ } else if (fp->fr_mip.fi_p) {
+ pr = fp->fr_ip.fi_p;
+ p = getprotobynumber(pr);
+ PRINTF("proto ");
+ printproto(p, pr, NULL);
+ putchar(' ');
+ }
+ }
+
+ switch (type)
+ {
+ case FR_T_NONE :
+ PRINTF("all");
+ break;
+
+ case FR_T_IPF :
+ PRINTF("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : "");
+ printaddr(af, fp->fr_satype, fp->fr_names, fp->fr_ifnames[0],
+ &fp->fr_src.s_addr, &fp->fr_smsk.s_addr);
+ if (fp->fr_scmp)
+ printportcmp(pr, &fp->fr_tuc.ftu_src);
+
+ PRINTF(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : "");
+ printaddr(af, fp->fr_datype, fp->fr_names, fp->fr_ifnames[0],
+ &fp->fr_dst.s_addr, &fp->fr_dmsk.s_addr);
+ if (fp->fr_dcmp)
+ printportcmp(pr, &fp->fr_tuc.ftu_dst);
+
+ if (((fp->fr_proto == IPPROTO_ICMP) ||
+ (fp->fr_proto == IPPROTO_ICMPV6)) && fp->fr_icmpm) {
+ int type = fp->fr_icmp, code;
+ char *name;
+
+ type = ntohs(fp->fr_icmp);
+ code = type & 0xff;
+ type /= 256;
+ name = icmptypename(fp->fr_family, type);
+ if (name == NULL)
+ PRINTF(" icmp-type %d", type);
+ else
+ PRINTF(" icmp-type %s", name);
+ if (ntohs(fp->fr_icmpm) & 0xff)
+ PRINTF(" code %d", code);
+ }
+ if ((fp->fr_proto == IPPROTO_TCP) &&
+ (fp->fr_tcpf || fp->fr_tcpfm)) {
+ PRINTF(" flags ");
+ printtcpflags(fp->fr_tcpf, fp->fr_tcpfm);
+ }
+ break;
+
+ case FR_T_BPFOPC :
+ {
+ fakebpf_t *fb;
+ int i;
+
+ PRINTF("bpf-v%d { \"", fp->fr_family);
+ i = fp->fr_dsize / sizeof(*fb);
+
+ for (fb = fp->fr_data, s = ""; i; i--, fb++, s = " ")
+ PRINTF("%s%#x %#x %#x %#x", s, fb->fb_c, fb->fb_t,
+ fb->fb_f, fb->fb_k);
+
+ PRINTF("\" }");
+ break;
+ }
+
+ case FR_T_COMPIPF :
+ break;
+
+ case FR_T_CALLFUNC :
+ PRINTF("call function at %p", fp->fr_data);
+ break;
+
+ case FR_T_IPFEXPR :
+ PRINTF("exp { \"");
+ printipfexpr(fp->fr_data);
+ PRINTF("\" } ");
+ break;
+
+ default :
+ PRINTF("[unknown filter type %#x]", fp->fr_type);
+ break;
+ }
+
+ if ((type == FR_T_IPF) &&
+ ((fp->fr_flx & FI_WITH) || (fp->fr_mflx & FI_WITH) ||
+ fp->fr_optbits || fp->fr_optmask ||
+ fp->fr_secbits || fp->fr_secmask)) {
+ char *comma = " ";
+
+ PRINTF(" with");
+ if (fp->fr_optbits || fp->fr_optmask ||
+ fp->fr_secbits || fp->fr_secmask) {
+ sec[0] = fp->fr_secmask;
+ sec[1] = fp->fr_secbits;
+ if (fp->fr_family == AF_INET)
+ optprint(sec, fp->fr_optmask, fp->fr_optbits);
+#ifdef USE_INET6
+ else
+ optprintv6(sec, fp->fr_optmask,
+ fp->fr_optbits);
+#endif
+ } else if (fp->fr_mflx & FI_OPTIONS) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_OPTIONS))
+ PRINTF("not ");
+ PRINTF("ipopts");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_SHORT) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_SHORT))
+ PRINTF("not ");
+ PRINTF("short");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_FRAG) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_FRAG))
+ PRINTF("not ");
+ PRINTF("frag");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_FRAGBODY) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_FRAGBODY))
+ PRINTF("not ");
+ PRINTF("frag-body");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_NATED) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_NATED))
+ PRINTF("not ");
+ PRINTF("nat");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_LOWTTL) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_LOWTTL))
+ PRINTF("not ");
+ PRINTF("lowttl");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_BAD) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_BAD))
+ PRINTF("not ");
+ PRINTF("bad");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_BADSRC) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_BADSRC))
+ PRINTF("not ");
+ PRINTF("bad-src");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_BADNAT) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_BADNAT))
+ PRINTF("not ");
+ PRINTF("bad-nat");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_OOW) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_OOW))
+ PRINTF("not ");
+ PRINTF("oow");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_MBCAST) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_MBCAST))
+ PRINTF("not ");
+ PRINTF("mbcast");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_BROADCAST) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_BROADCAST))
+ PRINTF("not ");
+ PRINTF("bcast");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_MULTICAST) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_MULTICAST))
+ PRINTF("not ");
+ PRINTF("mcast");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_STATE) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_STATE))
+ PRINTF("not ");
+ PRINTF("state");
+ comma = ",";
+ }
+ if (fp->fr_mflx & FI_V6EXTHDR) {
+ fputs(comma, stdout);
+ if (!(fp->fr_flx & FI_V6EXTHDR))
+ PRINTF("not ");
+ PRINTF("v6hdrs");
+ comma = ",";
+ }
+ }
+
+ if (fp->fr_flags & FR_KEEPSTATE) {
+ host_track_t *src = &fp->fr_srctrack;
+ PRINTF(" keep state");
+ if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN|
+ FR_NOICMPERR|FR_STATESYNC)) ||
+ (fp->fr_statemax != 0) || (fp->fr_age[0] != 0) ||
+ (src->ht_max_nodes != 0)) {
+ char *comma = "";
+ PRINTF(" (");
+ if (fp->fr_statemax != 0) {
+ PRINTF("limit %u", fp->fr_statemax);
+ comma = ",";
+ }
+ if (src->ht_max_nodes != 0) {
+ PRINTF("%smax-nodes %d", comma,
+ src->ht_max_nodes);
+ if (src->ht_max_per_node)
+ PRINTF(", max-per-src %d/%d",
+ src->ht_max_per_node,
+ src->ht_netmask);
+ comma = ",";
+ }
+ if (fp->fr_flags & FR_STSTRICT) {
+ PRINTF("%sstrict", comma);
+ comma = ",";
+ }
+ if (fp->fr_flags & FR_STLOOSE) {
+ PRINTF("%sloose", comma);
+ comma = ",";
+ }
+ if (fp->fr_flags & FR_NEWISN) {
+ PRINTF("%snewisn", comma);
+ comma = ",";
+ }
+ if (fp->fr_flags & FR_NOICMPERR) {
+ PRINTF("%sno-icmp-err", comma);
+ comma = ",";
+ }
+ if (fp->fr_flags & FR_STATESYNC) {
+ PRINTF("%ssync", comma);
+ comma = ",";
+ }
+ if (fp->fr_age[0] || fp->fr_age[1])
+ PRINTF("%sage %d/%d", comma, fp->fr_age[0],
+ fp->fr_age[1]);
+ PRINTF(")");
+ }
+ }
+ if (fp->fr_flags & FR_KEEPFRAG) {
+ PRINTF(" keep frags");
+ if (fp->fr_flags & (FR_FRSTRICT)) {
+ PRINTF(" (");
+ if (fp->fr_flags & FR_FRSTRICT)
+ PRINTF("strict");
+ PRINTF(")");
+
+ }
+ }
+ if (fp->fr_isc != (struct ipscan *)-1) {
+ if (fp->fr_isctag != -1)
+ PRINTF(" scan %s", fp->fr_isctag + fp->fr_names);
+ else
+ PRINTF(" scan *");
+ }
+ if (fp->fr_grhead != -1)
+ PRINTF(" head %s", fp->fr_names + fp->fr_grhead);
+ if (fp->fr_group != -1)
+ PRINTF(" group %s", fp->fr_names + fp->fr_group);
+ if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) {
+ char *s = "";
+
+ PRINTF(" set-tag(");
+ if (fp->fr_logtag != FR_NOLOGTAG) {
+ PRINTF("log=%u", fp->fr_logtag);
+ s = ", ";
+ }
+ if (*fp->fr_nattag.ipt_tag) {
+ PRINTF("%snat=%-.*s", s, IPFTAG_LEN,
+ fp->fr_nattag.ipt_tag);
+ }
+ PRINTF(")");
+ }
+
+ if (fp->fr_pps)
+ PRINTF(" pps %d", fp->fr_pps);
+
+ if (fp->fr_comment != -1)
+ PRINTF(" comment \"%s\"", fp->fr_names + fp->fr_comment);
+
+ hash = 0;
+ if ((fp->fr_flags & FR_KEEPSTATE) && (opts & OPT_VERBOSE)) {
+ PRINTF(" # count %d", fp->fr_statecnt);
+ if (fp->fr_die != 0)
+ PRINTF(" rule-ttl %u", fp->fr_die);
+ hash = 1;
+ } else if (fp->fr_die != 0) {
+ PRINTF(" # rule-ttl %u", fp->fr_die);
+ hash = 1;
+ }
+ if (opts & OPT_DEBUG) {
+ if (hash == 0)
+ putchar('#');
+ PRINTF(" ref %d", fp->fr_ref);
+ }
+ (void)putchar('\n');
+}
diff --git a/contrib/ipfilter/lib/printfraginfo.c b/contrib/ipfilter/lib/printfraginfo.c
new file mode 100644
index 0000000..dd2966f
--- /dev/null
+++ b/contrib/ipfilter/lib/printfraginfo.c
@@ -0,0 +1,42 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+#include "kmem.h"
+
+
+void
+printfraginfo(prefix, ifr)
+ char *prefix;
+ struct ipfr *ifr;
+{
+ frentry_t fr;
+ int family;
+
+ PRINTF("%s", prefix);
+ if (ifr->ipfr_v == 6) {
+ PRINTF("inet6");
+ family = AF_INET6;
+ } else {
+ PRINTF("inet");
+ family = AF_INET;
+ }
+ fr.fr_flags = 0xffffffff;
+
+ PRINTF(" %s -> ", hostname(family, &ifr->ipfr_src));
+/*
+ if (kmemcpy((char *)&fr, (u_long)ifr->ipfr_rule,
+ sizeof(fr)) == -1)
+ return;
+ */
+ PRINTF("%s id %x ttl %lu pr %d pkts %u bytes %u seen0 %d ref %d\n",
+ hostname(family, &ifr->ipfr_dst), ifr->ipfr_id,
+ ifr->ipfr_ttl, ifr->ipfr_p, ifr->ipfr_pkts, ifr->ipfr_bytes,
+ ifr->ipfr_seen0, ifr->ipfr_ref);
+}
diff --git a/contrib/ipfilter/lib/printhash.c b/contrib/ipfilter/lib/printhash.c
new file mode 100644
index 0000000..3779662
--- /dev/null
+++ b/contrib/ipfilter/lib/printhash.c
@@ -0,0 +1,58 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+iphtable_t *
+printhash(hp, copyfunc, name, opts, fields)
+ iphtable_t *hp;
+ copyfunc_t copyfunc;
+ char *name;
+ int opts;
+ wordtab_t *fields;
+{
+ iphtent_t *ipep, **table;
+ iphtable_t iph;
+ int printed;
+ size_t sz;
+
+ if ((*copyfunc)((char *)hp, (char *)&iph, sizeof(iph)))
+ return NULL;
+
+ if ((name != NULL) && strncmp(name, iph.iph_name, FR_GROUPLEN))
+ return iph.iph_next;
+
+ if (fields == NULL)
+ printhashdata(hp, opts);
+
+ if ((hp->iph_flags & IPHASH_DELETE) != 0)
+ PRINTF("# ");
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF("\t{");
+
+ sz = iph.iph_size * sizeof(*table);
+ table = malloc(sz);
+ if ((*copyfunc)((char *)iph.iph_table, (char *)table, sz))
+ return NULL;
+
+ for (printed = 0, ipep = iph.iph_list; ipep != NULL; ) {
+ ipep = printhashnode(&iph, ipep, copyfunc, opts, fields);
+ printed++;
+ }
+ if (printed == 0)
+ putchar(';');
+
+ free(table);
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF(" };\n");
+
+ return iph.iph_next;
+}
diff --git a/contrib/ipfilter/lib/printhash_live.c b/contrib/ipfilter/lib/printhash_live.c
new file mode 100644
index 0000000..53159b1
--- /dev/null
+++ b/contrib/ipfilter/lib/printhash_live.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+
+
+iphtable_t *
+printhash_live(hp, fd, name, opts, fields)
+ iphtable_t *hp;
+ int fd;
+ char *name;
+ int opts;
+ wordtab_t *fields;
+{
+ iphtent_t entry, zero;
+ ipflookupiter_t iter;
+ int last, printed;
+ ipfobj_t obj;
+
+ if ((name != NULL) && strncmp(name, hp->iph_name, FR_GROUPLEN))
+ return hp->iph_next;
+
+ if (fields == NULL)
+ printhashdata(hp, opts);
+
+ if ((hp->iph_flags & IPHASH_DELETE) != 0)
+ PRINTF("# ");
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF("\t{");
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_ptr = &iter;
+ obj.ipfo_size = sizeof(iter);
+
+ iter.ili_data = &entry;
+ iter.ili_type = IPLT_HASH;
+ iter.ili_otype = IPFLOOKUPITER_NODE;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_unit = hp->iph_unit;
+ strncpy(iter.ili_name, hp->iph_name, FR_GROUPLEN);
+
+ last = 0;
+ printed = 0;
+ bzero((char *)&zero, sizeof(zero));
+
+ while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) {
+ if (entry.ipe_next == NULL)
+ last = 1;
+ if (bcmp(&zero, &entry, sizeof(zero)) == 0)
+ break;
+ (void) printhashnode(hp, &entry, bcopywrap, opts, fields);
+ printed++;
+ }
+ if (last == 0)
+ ipferror(fd, "walking hash nodes:");
+
+ if (printed == 0)
+ putchar(';');
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF(" };\n");
+ return hp->iph_next;
+}
diff --git a/contrib/ipfilter/lib/printhashdata.c b/contrib/ipfilter/lib/printhashdata.c
new file mode 100644
index 0000000..ea2d416
--- /dev/null
+++ b/contrib/ipfilter/lib/printhashdata.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+
+void
+printhashdata(hp, opts)
+ iphtable_t *hp;
+ int opts;
+{
+
+ if ((opts & OPT_DEBUG) == 0) {
+ if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON)
+ PRINTF("# 'anonymous' table refs %d\n", hp->iph_ref);
+ if ((hp->iph_flags & IPHASH_DELETE) == IPHASH_DELETE)
+ PRINTF("# ");
+ switch (hp->iph_type & ~IPHASH_ANON)
+ {
+ case IPHASH_LOOKUP :
+ PRINTF("table");
+ break;
+ case IPHASH_GROUPMAP :
+ PRINTF("group-map");
+ if (hp->iph_flags & FR_INQUE)
+ PRINTF(" in");
+ else if (hp->iph_flags & FR_OUTQUE)
+ PRINTF(" out");
+ else
+ PRINTF(" ???");
+ break;
+ default :
+ PRINTF("%#x", hp->iph_type);
+ break;
+ }
+ PRINTF(" role=");
+ } else {
+ PRINTF("Hash Table %s: %s",
+ ISDIGIT(*hp->iph_name) ? "Number" : "Name",
+ hp->iph_name);
+ if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON)
+ PRINTF("(anon)");
+ putchar(' ');
+ PRINTF("Role: ");
+ }
+
+ printunit(hp->iph_unit);
+
+ if ((opts & OPT_DEBUG) == 0) {
+ if ((hp->iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP)
+ PRINTF(" type=hash");
+ PRINTF(" %s=%s size=%lu",
+ ISDIGIT(*hp->iph_name) ? "number" : "name",
+ hp->iph_name, (u_long)hp->iph_size);
+ if (hp->iph_seed != 0)
+ PRINTF(" seed=%lu", hp->iph_seed);
+ putchar('\n');
+ } else {
+ PRINTF(" Type: ");
+ switch (hp->iph_type & ~IPHASH_ANON)
+ {
+ case IPHASH_LOOKUP :
+ PRINTF("lookup");
+ break;
+ case IPHASH_GROUPMAP :
+ PRINTF("groupmap Group. %s", hp->iph_name);
+ break;
+ default :
+ break;
+ }
+
+ putchar('\n');
+ PRINTF("\t\tSize: %lu\tSeed: %lu",
+ (u_long)hp->iph_size, hp->iph_seed);
+ PRINTF("\tRef. Count: %d\tMasks: %#x\n", hp->iph_ref,
+ hp->iph_maskset[0]);
+ }
+
+ if ((opts & OPT_DEBUG) != 0) {
+ struct in_addr m;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if ((1 << i) & hp->iph_maskset[0]) {
+ ntomask(AF_INET, i, &m.s_addr);
+ PRINTF("\t\tMask: %s\n", inet_ntoa(m));
+ }
+ }
+ }
+}
diff --git a/contrib/ipfilter/lib/printhashnode.c b/contrib/ipfilter/lib/printhashnode.c
new file mode 100644
index 0000000..e245535
--- /dev/null
+++ b/contrib/ipfilter/lib/printhashnode.c
@@ -0,0 +1,69 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+iphtent_t *
+printhashnode(iph, ipep, copyfunc, opts, fields)
+ iphtable_t *iph;
+ iphtent_t *ipep;
+ copyfunc_t copyfunc;
+ int opts;
+ wordtab_t *fields;
+{
+ iphtent_t ipe;
+ u_int hv;
+ int i;
+
+ if ((*copyfunc)(ipep, &ipe, sizeof(ipe)))
+ return NULL;
+
+ hv = IPE_V4_HASH_FN(ipe.ipe_addr.i6[0], ipe.ipe_mask.i6[0],
+ iph->iph_size);
+
+ if (fields != NULL) {
+ for (i = 0; fields[i].w_value != 0; i++) {
+ printpoolfield(&ipe, IPLT_HASH, i);
+ if (fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ } else if ((opts & OPT_DEBUG) != 0) {
+ PRINTF("\t%d\tAddress: %s", hv,
+ inet_ntoa(ipe.ipe_addr.in4));
+ printmask(ipe.ipe_family, (u_32_t *)&ipe.ipe_mask.in4_addr);
+ PRINTF("\tRef. Count: %d\tGroup: %s\n", ipe.ipe_ref,
+ ipe.ipe_group);
+#ifdef USE_QUAD_T
+ PRINTF("\tHits: %"PRIu64"\tBytes: %"PRIu64"\n",
+ ipe.ipe_hits, ipe.ipe_bytes);
+#else
+ PRINTF("\tHits: %lu\tBytes: %lu\n",
+ ipe.ipe_hits, ipe.ipe_bytes);
+#endif
+ } else {
+ putchar(' ');
+ printip(ipe.ipe_family, (u_32_t *)&ipe.ipe_addr.in4_addr);
+ printmask(ipe.ipe_family, (u_32_t *)&ipe.ipe_mask.in4_addr);
+ if (ipe.ipe_value != 0) {
+ switch (iph->iph_type & ~IPHASH_ANON)
+ {
+ case IPHASH_GROUPMAP :
+ if (strncmp(ipe.ipe_group, iph->iph_name,
+ FR_GROUPLEN))
+ PRINTF(", group=%s", ipe.ipe_group);
+ break;
+ }
+ }
+ putchar(';');
+ }
+
+ ipep = ipe.ipe_next;
+ return ipep;
+}
diff --git a/contrib/ipfilter/lib/printhost.c b/contrib/ipfilter/lib/printhost.c
new file mode 100644
index 0000000..009a9bb
--- /dev/null
+++ b/contrib/ipfilter/lib/printhost.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: printhost.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+
+void
+printhost(family, addr)
+ int family;
+ u_32_t *addr;
+{
+#ifdef USE_INET6
+ char ipbuf[64];
+#else
+ struct in_addr ipa;
+#endif
+
+ if ((family == -1) || !*addr)
+ PRINTF("any");
+ else {
+#ifdef USE_INET6
+ void *ptr = addr;
+
+ PRINTF("%s", inet_ntop(family, ptr, ipbuf, sizeof(ipbuf)));
+#else
+ ipa.s_addr = *addr;
+ PRINTF("%s", inet_ntoa(ipa));
+#endif
+ }
+}
diff --git a/contrib/ipfilter/lib/printhostmap.c b/contrib/ipfilter/lib/printhostmap.c
new file mode 100644
index 0000000..714bc41
--- /dev/null
+++ b/contrib/ipfilter/lib/printhostmap.c
@@ -0,0 +1,31 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+void
+printhostmap(hmp, hv)
+ hostmap_t *hmp;
+ u_int hv;
+{
+
+ printactiveaddress(hmp->hm_v, "%s", &hmp->hm_osrcip6, NULL);
+ putchar(',');
+ printactiveaddress(hmp->hm_v, "%s", &hmp->hm_odstip6, NULL);
+ PRINTF(" -> ");
+ printactiveaddress(hmp->hm_v, "%s", &hmp->hm_nsrcip6, NULL);
+ putchar(',');
+ printactiveaddress(hmp->hm_v, "%s", &hmp->hm_ndstip6, NULL);
+ putchar(' ');
+ PRINTF("(use = %d", hmp->hm_ref);
+ if (opts & OPT_VERBOSE)
+ PRINTF(" hv = %u", hv);
+ printf(")\n");
+}
diff --git a/contrib/ipfilter/lib/printhostmask.c b/contrib/ipfilter/lib/printhostmask.c
new file mode 100644
index 0000000..b1e41f9
--- /dev/null
+++ b/contrib/ipfilter/lib/printhostmask.c
@@ -0,0 +1,39 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void
+printhostmask(family, addr, mask)
+ int family;
+ u_32_t *addr, *mask;
+{
+#ifdef USE_INET6
+ char ipbuf[64];
+#else
+ struct in_addr ipa;
+#endif
+
+ if ((family == -1) || ((!addr || !*addr) && (!mask || !*mask)))
+ PRINTF("any");
+ else {
+#ifdef USE_INET6
+ void *ptr = addr;
+
+ PRINTF("%s", inet_ntop(family, ptr, ipbuf, sizeof(ipbuf)));
+#else
+ ipa.s_addr = *addr;
+ PRINTF("%s", inet_ntoa(ipa));
+#endif
+ if (mask != NULL)
+ printmask(family, mask);
+ }
+}
diff --git a/contrib/ipfilter/lib/printifname.c b/contrib/ipfilter/lib/printifname.c
new file mode 100644
index 0000000..2e554d9
--- /dev/null
+++ b/contrib/ipfilter/lib/printifname.c
@@ -0,0 +1,22 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void
+printifname(format, name, ifp)
+ char *format, *name;
+ void *ifp;
+{
+ PRINTF("%s%s", format, name);
+ if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*"))
+ PRINTF("(!)");
+}
diff --git a/contrib/ipfilter/lib/printip.c b/contrib/ipfilter/lib/printip.c
new file mode 100644
index 0000000..6d414fe
--- /dev/null
+++ b/contrib/ipfilter/lib/printip.c
@@ -0,0 +1,43 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void
+printip(family, addr)
+ int family;
+ u_32_t *addr;
+{
+ struct in_addr ipa;
+
+ if (family == AF_INET) {
+ ipa.s_addr = *addr;
+ if (ntohl(ipa.s_addr) < 256)
+ PRINTF("%lu", (u_long)ntohl(ipa.s_addr));
+ else
+ PRINTF("%s", inet_ntoa(ipa));
+ }
+#ifdef AF_INET6
+ else if (family == AF_INET6) {
+ char buf[INET6_ADDRSTRLEN + 1];
+ const char *str;
+
+ buf[0] = '\0';
+ str = inet_ntop(AF_INET6, addr, buf, sizeof(buf) - 1);
+ if (str != NULL)
+ PRINTF("%s", str);
+ else
+ PRINTF("???");
+ }
+#endif
+ else
+ PRINTF("?(%d)?", family);
+}
diff --git a/contrib/ipfilter/lib/printipfexpr.c b/contrib/ipfilter/lib/printipfexpr.c
new file mode 100644
index 0000000..06b987e
--- /dev/null
+++ b/contrib/ipfilter/lib/printipfexpr.c
@@ -0,0 +1,199 @@
+#include "ipf.h"
+
+static void printport __P((int *));
+static void printhosts __P((int *));
+static void printsingle __P((int *));
+#ifdef USE_INET6
+static void printhostsv6 __P((int *));
+#endif
+
+void
+printipfexpr(array)
+ int *array;
+{
+ int i, nelems, j, not;
+ ipfexp_t *ipfe;
+
+ nelems = array[0];
+
+ for (i = 1; i < nelems; ) {
+ ipfe = (ipfexp_t *)(array + i);
+ if (ipfe->ipfe_cmd == IPF_EXP_END)
+ break;
+
+ not = ipfe->ipfe_not;
+
+ switch (ipfe->ipfe_cmd)
+ {
+ case IPF_EXP_IP_ADDR :
+ PRINTF("ip.addr %s= ", not ? "!" : "");
+ printhosts(array + i);
+ break;
+
+ case IPF_EXP_IP_PR :
+ PRINTF("ip.p %s= ", not ? "!" : "");
+ printsingle(array + i);
+ break;
+
+ case IPF_EXP_IP_SRCADDR :
+ PRINTF("ip.src %s= ", not ? "!" : "");
+ printhosts(array + i);
+ break;
+
+ case IPF_EXP_IP_DSTADDR :
+ PRINTF("ip.dst %s= ", not ? "!" : "");
+ printhosts(array + i);
+ break;
+
+ case IPF_EXP_TCP_PORT :
+ PRINTF("tcp.port %s= ", not ? "!" : "");
+ printport(array + i);
+ break;
+
+ case IPF_EXP_TCP_DPORT :
+ PRINTF("tcp.dport %s= ", not ? "!" : "");
+ printport(array + i);
+ break;
+
+ case IPF_EXP_TCP_SPORT :
+ PRINTF("tcp.sport %s= ", not ? "!" : "");
+ printport(array + i);
+ break;
+
+ case IPF_EXP_TCP_FLAGS :
+ PRINTF("tcp.flags %s= ", not ? "!" : "");
+
+ for (j = 0; j < ipfe->ipfe_narg; ) {
+ printtcpflags(array[i + 4], array[i + 5]);
+ j += 2;
+ if (j < array[4])
+ putchar(',');
+ }
+ break;
+
+ case IPF_EXP_UDP_PORT :
+ PRINTF("udp.port %s= ", not ? "!" : "");
+ printport(array + i);
+ break;
+
+ case IPF_EXP_UDP_DPORT :
+ PRINTF("udp.dport %s= ", not ? "!" : "");
+ printport(array + i);
+ break;
+
+ case IPF_EXP_UDP_SPORT :
+ PRINTF("udp.sport %s= ", not ? "!" : "");
+ printport(array + i);
+ break;
+
+ case IPF_EXP_IDLE_GT :
+ PRINTF("idle-gt %s= ", not ? "!" : "");
+ printsingle(array + i);
+ break;
+
+ case IPF_EXP_TCP_STATE :
+ PRINTF("tcp-state %s= ", not ? "!" : "");
+ printsingle(array + i);
+ break;
+
+#ifdef USE_INET6
+ case IPF_EXP_IP6_ADDR :
+ PRINTF("ip6.addr %s= ", not ? "!" : "");
+ printhostsv6(array + i);
+ break;
+
+ case IPF_EXP_IP6_SRCADDR :
+ PRINTF("ip6.src %s= ", not ? "!" : "");
+ printhostsv6(array + i);
+ break;
+
+ case IPF_EXP_IP6_DSTADDR :
+ PRINTF("ip6.dst %s= ", not ? "!" : "");
+ printhostsv6(array + i);
+ break;
+#endif
+
+ case IPF_EXP_END :
+ break;
+
+ default :
+ PRINTF("#%#x,len=%d;",
+ ipfe->ipfe_cmd, ipfe->ipfe_narg);
+ }
+
+ if (array[i] != IPF_EXP_END)
+ putchar(';');
+
+ i += ipfe->ipfe_size;
+ if (array[i] != IPF_EXP_END)
+ putchar(' ');
+ }
+}
+
+
+static void
+printsingle(array)
+ int *array;
+{
+ ipfexp_t *ipfe = (ipfexp_t *)array;
+ int i;
+
+ for (i = 0; i < ipfe->ipfe_narg; ) {
+ PRINTF("%d", array[i + 4]);
+ i++;
+ if (i < ipfe->ipfe_narg)
+ putchar(',');
+ }
+}
+
+
+static void
+printport(array)
+ int *array;
+{
+ ipfexp_t *ipfe = (ipfexp_t *)array;
+ int i;
+
+ for (i = 0; i < ipfe->ipfe_narg; ) {
+ PRINTF("%d", ntohs(array[i + 4]));
+ i++;
+ if (i < ipfe->ipfe_narg)
+ putchar(',');
+ }
+}
+
+
+static void
+printhosts(array)
+ int *array;
+{
+ ipfexp_t *ipfe = (ipfexp_t *)array;
+ int i, j;
+
+ for (i = 0, j = 0; i < ipfe->ipfe_narg; j++) {
+ printhostmask(AF_INET, (u_32_t *)ipfe->ipfe_arg0 + j * 2,
+ (u_32_t *)ipfe->ipfe_arg0 + j * 2 + 1);
+ i += 2;
+ if (i < ipfe->ipfe_narg)
+ putchar(',');
+ }
+}
+
+
+#ifdef USE_INET6
+static void
+printhostsv6(array)
+ int *array;
+{
+ ipfexp_t *ipfe = (ipfexp_t *)array;
+ int i, j;
+
+ for (i = 4, j= 0; i < ipfe->ipfe_size; j++) {
+ printhostmask(AF_INET6, (u_32_t *)ipfe->ipfe_arg0 + j * 8,
+ (u_32_t *)ipfe->ipfe_arg0 + j * 8 + 4);
+ i += 8;
+ if (i < ipfe->ipfe_size)
+ putchar(',');
+ }
+}
+#endif
diff --git a/contrib/ipfilter/lib/printiphdr.c b/contrib/ipfilter/lib/printiphdr.c
new file mode 100644
index 0000000..fdf0f75
--- /dev/null
+++ b/contrib/ipfilter/lib/printiphdr.c
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: printiphdr.c,v 1.1 2009/03/01 12:48:32 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+
+void
+printiphdr(ip)
+ ip_t *ip;
+{
+ PRINTF("ip(v=%d,hl=%d,len=%d,tos=%#x,off=%#x,sum=%#x,src=%#x,dst=%#x",
+ ip->ip_v, ip->ip_hl, ntohs(ip->ip_len), ip->ip_tos,
+ ntohs(ip->ip_off), ntohs(ip->ip_sum), ntohl(ip->ip_src.s_addr),
+ ntohl(ip->ip_dst.s_addr));
+}
diff --git a/contrib/ipfilter/lib/printlog.c b/contrib/ipfilter/lib/printlog.c
new file mode 100644
index 0000000..c5278cd
--- /dev/null
+++ b/contrib/ipfilter/lib/printlog.c
@@ -0,0 +1,39 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+#include <syslog.h>
+
+
+void
+printlog(fp)
+ frentry_t *fp;
+{
+ char *s, *u;
+
+ PRINTF("log");
+ if (fp->fr_flags & FR_LOGBODY)
+ PRINTF(" body");
+ if (fp->fr_flags & FR_LOGFIRST)
+ PRINTF(" first");
+ if (fp->fr_flags & FR_LOGORBLOCK)
+ PRINTF(" or-block");
+ if (fp->fr_loglevel != 0xffff) {
+ PRINTF(" level ");
+ s = fac_toname(fp->fr_loglevel);
+ if (s == NULL || *s == '\0')
+ s = "!!!";
+ u = pri_toname(fp->fr_loglevel);
+ if (u == NULL || *u == '\0')
+ u = "!!!";
+ PRINTF("%s.%s", s, u);
+ }
+}
diff --git a/contrib/ipfilter/lib/printlookup.c b/contrib/ipfilter/lib/printlookup.c
new file mode 100644
index 0000000..51f8d6e
--- /dev/null
+++ b/contrib/ipfilter/lib/printlookup.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void
+printlookup(base, addr, mask)
+ char *base;
+ i6addr_t *addr, *mask;
+{
+ char name[32];
+
+ switch (addr->iplookuptype)
+ {
+ case IPLT_POOL :
+ PRINTF("pool/");
+ break;
+ case IPLT_HASH :
+ PRINTF("hash/");
+ break;
+ case IPLT_DSTLIST :
+ PRINTF("dstlist/");
+ break;
+ default :
+ PRINTF("lookup(%x)=", addr->iplookuptype);
+ break;
+ }
+
+ if (addr->iplookupsubtype == 0)
+ PRINTF("%u", addr->iplookupnum);
+ else if (addr->iplookupsubtype == 1) {
+ strncpy(name, base + addr->iplookupname, sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+ PRINTF("%s", name);
+ }
+}
diff --git a/contrib/ipfilter/lib/printmask.c b/contrib/ipfilter/lib/printmask.c
new file mode 100644
index 0000000..365d7ff
--- /dev/null
+++ b/contrib/ipfilter/lib/printmask.c
@@ -0,0 +1,30 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void
+printmask(family, mask)
+ int family;
+ u_32_t *mask;
+{
+ struct in_addr ipa;
+ int ones;
+
+ if (family == AF_INET6) {
+ PRINTF("/%d", count6bits(mask));
+ } else if ((ones = count4bits(*mask)) == -1) {
+ ipa.s_addr = *mask;
+ PRINTF("/%s", inet_ntoa(ipa));
+ } else {
+ PRINTF("/%d", ones);
+ }
+}
diff --git a/contrib/ipfilter/lib/printnat.c b/contrib/ipfilter/lib/printnat.c
new file mode 100644
index 0000000..a94d4ee
--- /dev/null
+++ b/contrib/ipfilter/lib/printnat.c
@@ -0,0 +1,353 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+
+#include "ipf.h"
+#include "kmem.h"
+
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+/*
+ * Print out a NAT rule
+ */
+void
+printnat(np, opts)
+ ipnat_t *np;
+ int opts;
+{
+ struct protoent *pr;
+ char *base;
+ int family;
+ int proto;
+
+ if (np->in_v[0] == 4)
+ family = AF_INET;
+#ifdef USE_INET6
+ else if (np->in_v[0] == 6)
+ family = AF_INET6;
+#endif
+ else
+ family = AF_UNSPEC;
+
+ if (np->in_flags & IPN_NO)
+ PRINTF("no ");
+
+ switch (np->in_redir)
+ {
+ case NAT_REDIRECT|NAT_ENCAP :
+ PRINTF("encap in on");
+ proto = np->in_pr[0];
+ break;
+ case NAT_MAP|NAT_ENCAP :
+ PRINTF("encap out on");
+ proto = np->in_pr[1];
+ break;
+ case NAT_REDIRECT|NAT_DIVERTUDP :
+ PRINTF("divert in on");
+ proto = np->in_pr[0];
+ break;
+ case NAT_MAP|NAT_DIVERTUDP :
+ PRINTF("divert out on");
+ proto = np->in_pr[1];
+ break;
+ case NAT_REDIRECT|NAT_REWRITE :
+ PRINTF("rewrite in on");
+ proto = np->in_pr[0];
+ break;
+ case NAT_MAP|NAT_REWRITE :
+ PRINTF("rewrite out on");
+ proto = np->in_pr[1];
+ break;
+ case NAT_REDIRECT :
+ PRINTF("rdr");
+ proto = np->in_pr[0];
+ break;
+ case NAT_MAP :
+ PRINTF("map");
+ proto = np->in_pr[1];
+ break;
+ case NAT_MAPBLK :
+ PRINTF("map-block");
+ proto = np->in_pr[1];
+ break;
+ case NAT_BIMAP :
+ PRINTF("bimap");
+ proto = np->in_pr[0];
+ break;
+ default :
+ FPRINTF(stderr, "unknown value for in_redir: %#x\n",
+ np->in_redir);
+ proto = np->in_pr[0];
+ break;
+ }
+
+ pr = getprotobynumber(proto);
+
+ base = np->in_names;
+ if (!strcmp(base + np->in_ifnames[0], "-"))
+ PRINTF(" \"%s\"", base + np->in_ifnames[0]);
+ else
+ PRINTF(" %s", base + np->in_ifnames[0]);
+ if ((np->in_ifnames[1] != -1) &&
+ (strcmp(base + np->in_ifnames[0], base + np->in_ifnames[1]) != 0)) {
+ if (!strcmp(base + np->in_ifnames[1], "-"))
+ PRINTF(",\"%s\"", base + np->in_ifnames[1]);
+ else
+ PRINTF(",%s", base + np->in_ifnames[1]);
+ }
+ putchar(' ');
+
+ if (family == AF_INET6)
+ PRINTF("inet6 ");
+
+ if (np->in_redir & (NAT_REWRITE|NAT_ENCAP|NAT_DIVERTUDP)) {
+ if ((proto != 0) || (np->in_flags & IPN_TCPUDP)) {
+ PRINTF("proto ");
+ printproto(pr, proto, np);
+ putchar(' ');
+ }
+ }
+
+ if (np->in_flags & IPN_FILTER) {
+ if (np->in_flags & IPN_NOTSRC)
+ PRINTF("! ");
+ PRINTF("from ");
+ printnataddr(np->in_v[0], np->in_names, &np->in_osrc,
+ np->in_ifnames[0]);
+ if (np->in_scmp)
+ printportcmp(proto, &np->in_tuc.ftu_src);
+
+ if (np->in_flags & IPN_NOTDST)
+ PRINTF(" !");
+ PRINTF(" to ");
+ printnataddr(np->in_v[0], np->in_names, &np->in_odst,
+ np->in_ifnames[0]);
+ if (np->in_dcmp)
+ printportcmp(proto, &np->in_tuc.ftu_dst);
+ }
+
+ if (np->in_redir & (NAT_ENCAP|NAT_DIVERTUDP)) {
+ PRINTF(" -> src ");
+ printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
+ np->in_ifnames[0]);
+ if ((np->in_redir & NAT_DIVERTUDP) != 0)
+ PRINTF(",%u", np->in_spmin);
+ PRINTF(" dst ");
+ printnataddr(np->in_v[1], np->in_names, &np->in_ndst,
+ np->in_ifnames[0]);
+ if ((np->in_redir & NAT_DIVERTUDP) != 0)
+ PRINTF(",%u udp", np->in_dpmin);
+ if ((np->in_flags & IPN_PURGE) != 0)
+ PRINTF(" purge");
+ PRINTF(";\n");
+
+ } else if (np->in_redir & NAT_REWRITE) {
+ PRINTF(" -> src ");
+ if (np->in_nsrc.na_atype == FRI_LOOKUP &&
+ np->in_nsrc.na_type == IPLT_DSTLIST) {
+ PRINTF("dstlist/");
+ if (np->in_nsrc.na_subtype == 0)
+ PRINTF("%d", np->in_nsrc.na_num);
+ else
+ PRINTF("%s", base + np->in_nsrc.na_num);
+ } else {
+ printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
+ np->in_ifnames[0]);
+ }
+ if ((((np->in_flags & IPN_TCPUDP) != 0)) &&
+ (np->in_spmin != 0)) {
+ if ((np->in_flags & IPN_FIXEDSPORT) != 0) {
+ PRINTF(",port = %u", np->in_spmin);
+ } else {
+ PRINTF(",%u", np->in_spmin);
+ if (np->in_spmax != np->in_spmin)
+ PRINTF("-%u", np->in_spmax);
+ }
+ }
+ PRINTF(" dst ");
+ if (np->in_ndst.na_atype == FRI_LOOKUP &&
+ np->in_ndst.na_type == IPLT_DSTLIST) {
+ PRINTF("dstlist/");
+ if (np->in_ndst.na_subtype == 0)
+ PRINTF("%d", np->in_nsrc.na_num);
+ else
+ PRINTF("%s", base + np->in_ndst.na_num);
+ } else {
+ printnataddr(np->in_v[1], np->in_names, &np->in_ndst,
+ np->in_ifnames[0]);
+ }
+ if ((((np->in_flags & IPN_TCPUDP) != 0)) &&
+ (np->in_dpmin != 0)) {
+ if ((np->in_flags & IPN_FIXEDDPORT) != 0) {
+ PRINTF(",port = %u", np->in_dpmin);
+ } else {
+ PRINTF(",%u", np->in_dpmin);
+ if (np->in_dpmax != np->in_dpmin)
+ PRINTF("-%u", np->in_dpmax);
+ }
+ }
+ if ((np->in_flags & IPN_PURGE) != 0)
+ PRINTF(" purge");
+ PRINTF(";\n");
+
+ } else if (np->in_redir == NAT_REDIRECT) {
+ if (!(np->in_flags & IPN_FILTER)) {
+ printnataddr(np->in_v[0], np->in_names, &np->in_odst,
+ np->in_ifnames[0]);
+ if (np->in_flags & IPN_TCPUDP) {
+ PRINTF(" port %d", np->in_odport);
+ if (np->in_odport != np->in_dtop)
+ PRINTF("-%d", np->in_dtop);
+ }
+ }
+ if (np->in_flags & IPN_NO) {
+ putchar(' ');
+ printproto(pr, proto, np);
+ PRINTF(";\n");
+ return;
+ }
+ PRINTF(" -> ");
+ printnataddr(np->in_v[1], np->in_names, &np->in_ndst,
+ np->in_ifnames[0]);
+ if (np->in_flags & IPN_TCPUDP) {
+ if ((np->in_flags & IPN_FIXEDDPORT) != 0)
+ PRINTF(" port = %d", np->in_dpmin);
+ else {
+ PRINTF(" port %d", np->in_dpmin);
+ if (np->in_dpmin != np->in_dpmax)
+ PRINTF("-%d", np->in_dpmax);
+ }
+ }
+ putchar(' ');
+ printproto(pr, proto, np);
+ if (np->in_flags & IPN_ROUNDR)
+ PRINTF(" round-robin");
+ if (np->in_flags & IPN_FRAG)
+ PRINTF(" frag");
+ if (np->in_age[0] != 0 || np->in_age[1] != 0) {
+ PRINTF(" age %d/%d", np->in_age[0], np->in_age[1]);
+ }
+ if (np->in_flags & IPN_STICKY)
+ PRINTF(" sticky");
+ if (np->in_mssclamp != 0)
+ PRINTF(" mssclamp %d", np->in_mssclamp);
+ if (np->in_plabel != -1)
+ PRINTF(" proxy %s", np->in_names + np->in_plabel);
+ if (np->in_tag.ipt_tag[0] != '\0')
+ PRINTF(" tag %-.*s", IPFTAG_LEN, np->in_tag.ipt_tag);
+ if ((np->in_flags & IPN_PURGE) != 0)
+ PRINTF(" purge");
+ PRINTF("\n");
+ if (opts & OPT_DEBUG)
+ PRINTF("\tpmax %u\n", np->in_dpmax);
+
+ } else {
+ int protoprinted = 0;
+
+ if (!(np->in_flags & IPN_FILTER)) {
+ printnataddr(np->in_v[0], np->in_names, &np->in_osrc,
+ np->in_ifnames[0]);
+ }
+ if (np->in_flags & IPN_NO) {
+ putchar(' ');
+ printproto(pr, proto, np);
+ PRINTF(";\n");
+ return;
+ }
+ PRINTF(" -> ");
+ if (np->in_flags & IPN_SIPRANGE) {
+ PRINTF("range ");
+ printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
+ np->in_ifnames[0]);
+ } else {
+ printnataddr(np->in_v[1], np->in_names, &np->in_nsrc,
+ np->in_ifnames[0]);
+ }
+ if (np->in_plabel != -1) {
+ PRINTF(" proxy port ");
+ if (np->in_odport != 0) {
+ char *s;
+
+ s = portname(proto, np->in_odport);
+ if (s != NULL)
+ fputs(s, stdout);
+ else
+ fputs("???", stdout);
+ }
+ PRINTF(" %s/", np->in_names + np->in_plabel);
+ printproto(pr, proto, NULL);
+ protoprinted = 1;
+ } else if (np->in_redir == NAT_MAPBLK) {
+ if ((np->in_spmin == 0) &&
+ (np->in_flags & IPN_AUTOPORTMAP))
+ PRINTF(" ports auto");
+ else
+ PRINTF(" ports %d", np->in_spmin);
+ if (opts & OPT_DEBUG)
+ PRINTF("\n\tip modulous %d", np->in_spmax);
+
+ } else if (np->in_spmin || np->in_spmax) {
+ if (np->in_flags & IPN_ICMPQUERY) {
+ PRINTF(" icmpidmap ");
+ } else {
+ PRINTF(" portmap ");
+ }
+ printproto(pr, proto, np);
+ protoprinted = 1;
+ if (np->in_flags & IPN_AUTOPORTMAP) {
+ PRINTF(" auto");
+ if (opts & OPT_DEBUG)
+ PRINTF(" [%d:%d %d %d]",
+ np->in_spmin, np->in_spmax,
+ np->in_ippip, np->in_ppip);
+ } else {
+ PRINTF(" %d:%d", np->in_spmin, np->in_spmax);
+ }
+ if (np->in_flags & IPN_SEQUENTIAL)
+ PRINTF(" sequential");
+ }
+
+ if (np->in_flags & IPN_FRAG)
+ PRINTF(" frag");
+ if (np->in_age[0] != 0 || np->in_age[1] != 0) {
+ PRINTF(" age %d/%d", np->in_age[0], np->in_age[1]);
+ }
+ if (np->in_mssclamp != 0)
+ PRINTF(" mssclamp %d", np->in_mssclamp);
+ if (np->in_tag.ipt_tag[0] != '\0')
+ PRINTF(" tag %s", np->in_tag.ipt_tag);
+ if (!protoprinted && (np->in_flags & IPN_TCPUDP || proto)) {
+ putchar(' ');
+ printproto(pr, proto, np);
+ }
+ if ((np->in_flags & IPN_PURGE) != 0)
+ PRINTF(" purge");
+ PRINTF("\n");
+ if (opts & OPT_DEBUG) {
+ PRINTF("\tnextip ");
+ printip(family, &np->in_snip);
+ PRINTF(" pnext %d\n", np->in_spnext);
+ }
+ }
+
+ if (opts & OPT_DEBUG) {
+ PRINTF("\tspace %lu use %u hits %lu flags %#x proto %d/%d",
+ np->in_space, np->in_use, np->in_hits,
+ np->in_flags, np->in_pr[0], np->in_pr[1]);
+ PRINTF(" hv %u/%u\n", np->in_hv[0], np->in_hv[1]);
+ PRINTF("\tifp[0] %p ifp[1] %p apr %p\n",
+ np->in_ifps[0], np->in_ifps[1], np->in_apr);
+ PRINTF("\ttqehead %p/%p comment %p\n",
+ np->in_tqehead[0], np->in_tqehead[1], np->in_comment);
+ }
+}
diff --git a/contrib/ipfilter/lib/printnataddr.c b/contrib/ipfilter/lib/printnataddr.c
new file mode 100644
index 0000000..89faa62
--- /dev/null
+++ b/contrib/ipfilter/lib/printnataddr.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+
+#include "ipf.h"
+#include "kmem.h"
+
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: printnataddr.c,v 1.4.2.2 2012/07/22 08:04:24 darren_r Exp $";
+#endif
+
+
+void
+printnataddr(v, base, addr, ifidx)
+ int v;
+ char *base;
+ nat_addr_t *addr;
+ int ifidx;
+{
+ switch (v)
+ {
+ case 4 :
+ if (addr->na_atype == FRI_NORMAL &&
+ addr->na_addr[0].in4.s_addr == 0) {
+ PRINTF("0/%d", count4bits(addr->na_addr[1].in4.s_addr));
+ } else {
+ printaddr(AF_INET, addr->na_atype, base, ifidx,
+ (u_32_t *)&addr->na_addr[0].in4.s_addr,
+ (u_32_t *)&addr->na_addr[1].in4.s_addr);
+ }
+ break;
+#ifdef USE_INET6
+ case 6 :
+ printaddr(AF_INET6, addr->na_atype, base, ifidx,
+ (u_32_t *)&addr->na_addr[0].in6,
+ (u_32_t *)&addr->na_addr[1].in6);
+ break;
+#endif
+ default :
+ printf("{v=%d}", v);
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printnatfield.c b/contrib/ipfilter/lib/printnatfield.c
new file mode 100644
index 0000000..49596f6
--- /dev/null
+++ b/contrib/ipfilter/lib/printnatfield.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: printnatfield.c,v 1.6.2.2 2012/01/26 05:44:26 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+wordtab_t natfields[] = {
+ { "all", -2 },
+ { "ifp0", 1 },
+ { "ifp1", 2 },
+ { "mtu0", 3 },
+ { "mtu1", 4 },
+ { "ifname0", 5 },
+ { "ifname1", 6 },
+ { "sumd0", 7 },
+ { "sumd1", 8 },
+ { "pkts0", 9 },
+ { "pkts1", 10 },
+ { "bytes0", 11 },
+ { "bytes1", 12 },
+ { "proto0", 13 },
+ { "proto1", 14 },
+ { "hash0", 15 },
+ { "hash1", 16 },
+ { "ref", 17 },
+ { "rev", 18 },
+ { "v0", 19 },
+ { "redir", 20 },
+ { "use", 21 },
+ { "ipsumd", 22 },
+ { "dir", 23 },
+ { "olddstip", 24 },
+ { "oldsrcip", 25 },
+ { "newdstip", 26 },
+ { "newsrcip", 27 },
+ { "olddport", 28 },
+ { "oldsport", 29 },
+ { "newdport", 30 },
+ { "newsport", 31 },
+ { "age", 32 },
+ { "v1", 33 },
+ { NULL, 0 }
+};
+
+
+void
+printnatfield(n, fieldnum)
+ nat_t *n;
+ int fieldnum;
+{
+ int i;
+
+ switch (fieldnum)
+ {
+ case -2 :
+ for (i = 1; natfields[i].w_word != NULL; i++) {
+ if (natfields[i].w_value > 0) {
+ printnatfield(n, i);
+ if (natfields[i + 1].w_value > 0)
+ putchar('\t');
+ }
+ }
+ break;
+
+ case 1:
+ PRINTF("%#lx", (u_long)n->nat_ifps[0]);
+ break;
+
+ case 2:
+ PRINTF("%#lx", (u_long)n->nat_ifps[1]);
+ break;
+
+ case 3:
+ PRINTF("%d", n->nat_mtu[0]);
+ break;
+
+ case 4:
+ PRINTF("%d", n->nat_mtu[1]);
+ break;
+
+ case 5:
+ PRINTF("%s", n->nat_ifnames[0]);
+ break;
+
+ case 6:
+ PRINTF("%s", n->nat_ifnames[1]);
+ break;
+
+ case 7:
+ PRINTF("%d", n->nat_sumd[0]);
+ break;
+
+ case 8:
+ PRINTF("%d", n->nat_sumd[1]);
+ break;
+
+ case 9:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", n->nat_pkts[0]);
+#else
+ PRINTF("%lu", n->nat_pkts[0]);
+#endif
+ break;
+
+ case 10:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", n->nat_pkts[1]);
+#else
+ PRINTF("%lu", n->nat_pkts[1]);
+#endif
+ break;
+
+ case 11:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", n->nat_bytes[0]);
+#else
+ PRINTF("%lu", n->nat_bytes[0]);
+#endif
+ break;
+
+ case 12:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", n->nat_bytes[1]);
+#else
+ PRINTF("%lu", n->nat_bytes[1]);
+#endif
+ break;
+
+ case 13:
+ PRINTF("%d", n->nat_pr[0]);
+ break;
+
+ case 14:
+ PRINTF("%d", n->nat_pr[1]);
+ break;
+
+ case 15:
+ PRINTF("%u", n->nat_hv[0]);
+ break;
+
+ case 16:
+ PRINTF("%u", n->nat_hv[1]);
+ break;
+
+ case 17:
+ PRINTF("%d", n->nat_ref);
+ break;
+
+ case 18:
+ PRINTF("%d", n->nat_rev);
+ break;
+
+ case 19:
+ PRINTF("%d", n->nat_v[0]);
+ break;
+
+ case 33:
+ PRINTF("%d", n->nat_v[0]);
+ break;
+
+ case 20:
+ PRINTF("%d", n->nat_redir);
+ break;
+
+ case 21:
+ PRINTF("%d", n->nat_use);
+ break;
+
+ case 22:
+ PRINTF("%u", n->nat_ipsumd);
+ break;
+
+ case 23:
+ PRINTF("%d", n->nat_dir);
+ break;
+
+ case 24:
+ PRINTF("%s", hostname(n->nat_v[0], &n->nat_odstip));
+ break;
+
+ case 25:
+ PRINTF("%s", hostname(n->nat_v[0], &n->nat_osrcip));
+ break;
+
+ case 26:
+ PRINTF("%s", hostname(n->nat_v[1], &n->nat_ndstip));
+ break;
+
+ case 27:
+ PRINTF("%s", hostname(n->nat_v[1], &n->nat_nsrcip));
+ break;
+
+ case 28:
+ PRINTF("%hu", ntohs(n->nat_odport));
+ break;
+
+ case 29:
+ PRINTF("%hu", ntohs(n->nat_osport));
+ break;
+
+ case 30:
+ PRINTF("%hu", ntohs(n->nat_ndport));
+ break;
+
+ case 31:
+ PRINTF("%hu", ntohs(n->nat_nsport));
+ break;
+
+ case 32:
+ PRINTF("%u", n->nat_age);
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printnatside.c b/contrib/ipfilter/lib/printnatside.c
new file mode 100644
index 0000000..37e1cb8
--- /dev/null
+++ b/contrib/ipfilter/lib/printnatside.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: printnatside.c,v 1.2.2.6 2012/07/22 08:04:24 darren_r Exp $
+ */
+#include "ipf.h"
+
+void
+printnatside(side, ns)
+ char *side;
+ nat_stat_side_t *ns;
+{
+ PRINTF("%lu\tproxy create fail %s\n", ns->ns_appr_fail, side);
+ PRINTF("%lu\tproxy fail %s\n", ns->ns_ipf_proxy_fail, side);
+ PRINTF("%lu\tbad nat %s\n", ns->ns_badnat, side);
+ PRINTF("%lu\tbad nat new %s\n", ns->ns_badnatnew, side);
+ PRINTF("%lu\tbad next addr %s\n", ns->ns_badnextaddr, side);
+ PRINTF("%lu\tbucket max %s\n", ns->ns_bucket_max, side);
+ PRINTF("%lu\tclone nomem %s\n", ns->ns_clone_nomem, side);
+ PRINTF("%lu\tdecap bad %s\n", ns->ns_decap_bad, side);
+ PRINTF("%lu\tdecap fail %s\n", ns->ns_decap_fail, side);
+ PRINTF("%lu\tdecap pullup %s\n", ns->ns_decap_pullup, side);
+ PRINTF("%lu\tdivert dup %s\n", ns->ns_divert_dup, side);
+ PRINTF("%lu\tdivert exist %s\n", ns->ns_divert_exist, side);
+ PRINTF("%lu\tdrop %s\n", ns->ns_drop, side);
+ PRINTF("%lu\texhausted %s\n", ns->ns_exhausted, side);
+ PRINTF("%lu\ticmp address %s\n", ns->ns_icmp_address, side);
+ PRINTF("%lu\ticmp basic %s\n", ns->ns_icmp_basic, side);
+ PRINTF("%lu\tinuse %s\n", ns->ns_inuse, side);
+ PRINTF("%lu\ticmp mbuf wrong size %s\n", ns->ns_icmp_mbuf, side);
+ PRINTF("%lu\ticmp header unmatched %s\n", ns->ns_icmp_notfound, side);
+ PRINTF("%lu\ticmp rebuild failures %s\n", ns->ns_icmp_rebuild, side);
+ PRINTF("%lu\ticmp short %s\n", ns->ns_icmp_short, side);
+ PRINTF("%lu\ticmp packet size wrong %s\n", ns->ns_icmp_size, side);
+ PRINTF("%lu\tIFP address fetch failures %s\n",
+ ns->ns_ifpaddrfail, side);
+ PRINTF("%lu\tpackets untranslated %s\n", ns->ns_ignored, side);
+ PRINTF("%lu\tNAT insert failures %s\n", ns->ns_insert_fail, side);
+ PRINTF("%lu\tNAT lookup misses %s\n", ns->ns_lookup_miss, side);
+ PRINTF("%lu\tNAT lookup nowild %s\n", ns->ns_lookup_nowild, side);
+ PRINTF("%lu\tnew ifpaddr failed %s\n", ns->ns_new_ifpaddr, side);
+ PRINTF("%lu\tmemory requests failed %s\n", ns->ns_memfail, side);
+ PRINTF("%lu\ttable max reached %s\n", ns->ns_table_max, side);
+ PRINTF("%lu\tpackets translated %s\n", ns->ns_translated, side);
+ PRINTF("%lu\tfinalised failed %s\n", ns->ns_unfinalised, side);
+ PRINTF("%lu\tsearch wraps %s\n", ns->ns_wrap, side);
+ PRINTF("%lu\tnull translations %s\n", ns->ns_xlate_null, side);
+ PRINTF("%lu\ttranslation exists %s\n", ns->ns_xlate_exists, side);
+ PRINTF("%lu\tno memory %s\n", ns->ns_memfail, side);
+
+ if (opts & OPT_VERBOSE)
+ PRINTF("%p table %s\n", ns->ns_table, side);
+}
diff --git a/contrib/ipfilter/lib/printpacket.c b/contrib/ipfilter/lib/printpacket.c
new file mode 100644
index 0000000..5c4a749
--- /dev/null
+++ b/contrib/ipfilter/lib/printpacket.c
@@ -0,0 +1,110 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+#ifndef IP_OFFMASK
+# define IP_OFFMASK 0x3fff
+#endif
+
+
+void
+printpacket(dir, m)
+ int dir;
+ mb_t *m;
+{
+ u_short len, off;
+ tcphdr_t *tcp;
+ ip_t *ip;
+
+ ip = MTOD(m, ip_t *);
+
+ if (IP_V(ip) == 6) {
+#ifdef USE_INET6
+ len = ntohs(((ip6_t *)ip)->ip6_plen);
+#else
+ len = ntohs(((u_short *)ip)[2]);
+#endif
+ len += 40;
+ } else {
+ len = ntohs(ip->ip_len);
+ }
+ ASSERT(len == msgdsize(m));
+
+ if ((opts & OPT_HEX) == OPT_HEX) {
+ u_char *s;
+ int i;
+
+ for (; m != NULL; m = m->mb_next) {
+ len = m->mb_len;
+ for (s = (u_char *)m->mb_data, i = 0; i < len; i++) {
+ PRINTF("%02x", *s++ & 0xff);
+ if (len - i > 1) {
+ i++;
+ PRINTF("%02x", *s++ & 0xff);
+ }
+ putchar(' ');
+ }
+ }
+ putchar('\n');
+ putchar('\n');
+ return;
+ }
+
+ if (IP_V(ip) == 6) {
+ printpacket6(dir, m);
+ return;
+ }
+
+ if (dir)
+ PRINTF("> ");
+ else
+ PRINTF("< ");
+
+ PRINTF("%s ", IFNAME(m->mb_ifp));
+
+ off = ntohs(ip->ip_off);
+ tcp = (struct tcphdr *)((char *)ip + (IP_HL(ip) << 2));
+ PRINTF("ip #%d %d(%d) %d", ntohs(ip->ip_id), ntohs(ip->ip_len),
+ IP_HL(ip) << 2, ip->ip_p);
+ if (off & IP_OFFMASK)
+ PRINTF(" @%d", off << 3);
+ PRINTF(" %s", inet_ntoa(ip->ip_src));
+ if (!(off & IP_OFFMASK))
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ PRINTF(",%d", ntohs(tcp->th_sport));
+ PRINTF(" > ");
+ PRINTF("%s", inet_ntoa(ip->ip_dst));
+ if (!(off & IP_OFFMASK)) {
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ PRINTF(",%d", ntohs(tcp->th_dport));
+ if ((ip->ip_p == IPPROTO_TCP) && (tcp->th_flags != 0)) {
+ putchar(' ');
+ if (tcp->th_flags & TH_FIN)
+ putchar('F');
+ if (tcp->th_flags & TH_SYN)
+ putchar('S');
+ if (tcp->th_flags & TH_RST)
+ putchar('R');
+ if (tcp->th_flags & TH_PUSH)
+ putchar('P');
+ if (tcp->th_flags & TH_ACK)
+ putchar('A');
+ if (tcp->th_flags & TH_URG)
+ putchar('U');
+ if (tcp->th_flags & TH_ECN)
+ putchar('E');
+ if (tcp->th_flags & TH_CWR)
+ putchar('C');
+ }
+ }
+
+ putchar('\n');
+}
diff --git a/contrib/ipfilter/lib/printpacket6.c b/contrib/ipfilter/lib/printpacket6.c
new file mode 100644
index 0000000..6363e55
--- /dev/null
+++ b/contrib/ipfilter/lib/printpacket6.c
@@ -0,0 +1,60 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+/*
+ * This is meant to work without the IPv6 header files being present or
+ * the inet_ntop() library.
+ */
+void
+printpacket6(dir, m)
+ int dir;
+ mb_t *m;
+{
+ u_char *buf, p;
+ u_short plen, *addrs;
+ tcphdr_t *tcp;
+ u_32_t flow;
+
+ buf = (u_char *)m->mb_data;
+ tcp = (tcphdr_t *)(buf + 40);
+ p = buf[6];
+ flow = ntohl(*(u_32_t *)buf);
+ flow &= 0xfffff;
+ plen = ntohs(*((u_short *)buf +2));
+ addrs = (u_short *)buf + 4;
+
+ if (dir)
+ PRINTF("> ");
+ else
+ PRINTF("< ");
+
+ PRINTF("%s ", IFNAME(m->mb_ifp));
+
+ PRINTF("ip6/%d %d %#x %d", buf[0] & 0xf, plen, flow, p);
+ PRINTF(" %x:%x:%x:%x:%x:%x:%x:%x",
+ ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]),
+ ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]),
+ ntohs(addrs[6]), ntohs(addrs[7]));
+ if (plen >= 4)
+ if (p == IPPROTO_TCP || p == IPPROTO_UDP)
+ (void)PRINTF(",%d", ntohs(tcp->th_sport));
+ PRINTF(" >");
+ addrs += 8;
+ PRINTF(" %x:%x:%x:%x:%x:%x:%x:%x",
+ ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]),
+ ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]),
+ ntohs(addrs[6]), ntohs(addrs[7]));
+ if (plen >= 4)
+ if (p == IPPROTO_TCP || p == IPPROTO_UDP)
+ PRINTF(",%d", ntohs(tcp->th_dport));
+ putchar('\n');
+}
diff --git a/contrib/ipfilter/lib/printpool.c b/contrib/ipfilter/lib/printpool.c
new file mode 100644
index 0000000..8d8cdcc
--- /dev/null
+++ b/contrib/ipfilter/lib/printpool.c
@@ -0,0 +1,65 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+ip_pool_t *
+printpool(pp, copyfunc, name, opts, fields)
+ ip_pool_t *pp;
+ copyfunc_t copyfunc;
+ char *name;
+ int opts;
+ wordtab_t *fields;
+{
+ ip_pool_node_t *ipnp, *ipnpn, ipn, **pnext;
+ ip_pool_t ipp;
+
+ if ((*copyfunc)(pp, &ipp, sizeof(ipp)))
+ return NULL;
+
+ if ((name != NULL) && strncmp(name, ipp.ipo_name, FR_GROUPLEN))
+ return ipp.ipo_next;
+
+ printpooldata(&ipp, opts);
+
+ if ((ipp.ipo_flags & IPOOL_DELETE) != 0)
+ PRINTF("# ");
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF("\t{");
+
+ ipnpn = ipp.ipo_list;
+ ipp.ipo_list = NULL;
+ pnext = &ipp.ipo_list;
+ while (ipnpn != NULL) {
+ ipnp = (ip_pool_node_t *)malloc(sizeof(*ipnp));
+ (*copyfunc)(ipnpn, ipnp, sizeof(ipn));
+ ipnpn = ipnp->ipn_next;
+ *pnext = ipnp;
+ pnext = &ipnp->ipn_next;
+ ipnp->ipn_next = NULL;
+ }
+
+ if (ipp.ipo_list == NULL) {
+ putchar(';');
+ } else {
+ for (ipnp = ipp.ipo_list; ipnp != NULL; ipnp = ipnpn) {
+ ipnpn = printpoolnode(ipnp, opts, fields);
+ free(ipnp);
+
+ if ((opts & OPT_DEBUG) == 0) {
+ putchar(';');
+ }
+ }
+ }
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF(" };\n");
+
+ return ipp.ipo_next;
+}
diff --git a/contrib/ipfilter/lib/printpool_live.c b/contrib/ipfilter/lib/printpool_live.c
new file mode 100644
index 0000000..2aabf32
--- /dev/null
+++ b/contrib/ipfilter/lib/printpool_live.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+
+
+ip_pool_t *
+printpool_live(pool, fd, name, opts, fields)
+ ip_pool_t *pool;
+ int fd;
+ char *name;
+ int opts;
+ wordtab_t *fields;
+{
+ ip_pool_node_t entry;
+ ipflookupiter_t iter;
+ int printed, last;
+ ipfobj_t obj;
+
+ if ((name != NULL) && strncmp(name, pool->ipo_name, FR_GROUPLEN))
+ return pool->ipo_next;
+
+ if (fields == NULL)
+ printpooldata(pool, opts);
+
+ if ((pool->ipo_flags & IPOOL_DELETE) != 0)
+ PRINTF("# ");
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF("\t{");
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_ptr = &iter;
+ obj.ipfo_size = sizeof(iter);
+
+ iter.ili_data = &entry;
+ iter.ili_type = IPLT_POOL;
+ iter.ili_otype = IPFLOOKUPITER_NODE;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_unit = pool->ipo_unit;
+ strncpy(iter.ili_name, pool->ipo_name, FR_GROUPLEN);
+
+ last = 0;
+ printed = 0;
+
+ if (pool->ipo_list != NULL) {
+ while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) {
+ if (entry.ipn_next == NULL)
+ last = 1;
+ (void) printpoolnode(&entry, opts, fields);
+ if ((opts & OPT_DEBUG) == 0)
+ putchar(';');
+ printed++;
+ }
+ }
+
+ if (printed == 0)
+ putchar(';');
+
+ if ((opts & OPT_DEBUG) == 0)
+ PRINTF(" };\n");
+
+ (void) ioctl(fd,SIOCIPFDELTOK, &iter.ili_key);
+
+ return pool->ipo_next;
+}
diff --git a/contrib/ipfilter/lib/printpooldata.c b/contrib/ipfilter/lib/printpooldata.c
new file mode 100644
index 0000000..a159177
--- /dev/null
+++ b/contrib/ipfilter/lib/printpooldata.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+#include <ctype.h>
+
+
+void
+printpooldata(pool, opts)
+ ip_pool_t *pool;
+ int opts;
+{
+
+ if ((opts & OPT_DEBUG) == 0) {
+ if ((pool->ipo_flags & IPOOL_ANON) != 0)
+ PRINTF("# 'anonymous' tree %s\n", pool->ipo_name);
+ if ((pool->ipo_flags & IPOOL_DELETE) != 0)
+ PRINTF("# ");
+ PRINTF("table role=");
+ } else {
+ if ((pool->ipo_flags & IPOOL_DELETE) != 0)
+ PRINTF("# ");
+ PRINTF("%s: %s",
+ ISDIGIT(*pool->ipo_name) ? "Number" : "Name",
+ pool->ipo_name);
+ if ((pool->ipo_flags & IPOOL_ANON) == IPOOL_ANON)
+ PRINTF("(anon)");
+ putchar(' ');
+ PRINTF("Role: ");
+ }
+
+ printunit(pool->ipo_unit);
+
+ if ((opts & OPT_DEBUG) == 0) {
+ PRINTF(" type=tree %s=%s\n",
+ (!*pool->ipo_name || ISDIGIT(*pool->ipo_name)) ? \
+ "number" : "name", pool->ipo_name);
+ } else {
+ putchar(' ');
+
+ PRINTF("\tReferences: %d\tHits: %lu\n", pool->ipo_ref,
+ pool->ipo_hits);
+ if ((pool->ipo_flags & IPOOL_DELETE) != 0)
+ PRINTF("# ");
+ PRINTF("\tNodes Starting at %p\n", pool->ipo_list);
+ }
+}
diff --git a/contrib/ipfilter/lib/printpoolfield.c b/contrib/ipfilter/lib/printpoolfield.c
new file mode 100644
index 0000000..9254ab8
--- /dev/null
+++ b/contrib/ipfilter/lib/printpoolfield.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: printpoolfield.c,v 1.1.2.4 2012/01/26 05:44:26 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+wordtab_t poolfields[] = {
+ { "all", -2 },
+ { "address", 1 },
+ { "mask", 2 },
+ { "ifname", 3 },
+ { "pkts", 4 },
+ { "bytes", 5 },
+ { "family", 6 },
+ { NULL, 0 }
+};
+
+
+void
+printpoolfield(p, ptype, fieldnum)
+ void *p;
+ int ptype;
+ int fieldnum;
+{
+ addrfamily_t *a;
+ char abuf[80];
+ int i;
+
+ switch (fieldnum)
+ {
+ case -2 :
+ for (i = 1; poolfields[i].w_word != NULL; i++) {
+ if (poolfields[i].w_value > 0) {
+ printpoolfield(p, ptype, i);
+ if (poolfields[i + 1].w_value > 0)
+ putchar('\t');
+ }
+ }
+ break;
+
+ case 1:
+ if (ptype == IPLT_POOL) {
+ ip_pool_node_t *node = (ip_pool_node_t *)p;
+
+ if (node->ipn_info)
+ PRINTF("!");
+ a = &node->ipn_addr;
+ PRINTF("%s", inet_ntop(a->adf_family, &a->adf_addr,
+ abuf, sizeof(abuf)));
+ } else if (ptype == IPLT_HASH) {
+ iphtent_t *node = (iphtent_t *)p;
+
+ PRINTF("%s", inet_ntop(node->ipe_family,
+ &node->ipe_addr,
+ abuf, sizeof(abuf)));
+ } else if (ptype == IPLT_DSTLIST) {
+ ipf_dstnode_t *node = (ipf_dstnode_t *)p;
+
+ a = &node->ipfd_dest.fd_addr;
+ PRINTF("%s", inet_ntop(a->adf_family, &a->adf_addr,
+ abuf, sizeof(abuf)));
+ }
+ break;
+
+ case 2:
+ if (ptype == IPLT_POOL) {
+ ip_pool_node_t *node = (ip_pool_node_t *)p;
+
+ a = &node->ipn_mask;
+ PRINTF("%s", inet_ntop(a->adf_family, &a->adf_addr,
+ abuf, sizeof(abuf)));
+ } else if (ptype == IPLT_HASH) {
+ iphtent_t *node = (iphtent_t *)p;
+
+ PRINTF("%s", inet_ntop(node->ipe_family,
+ &node->ipe_mask,
+ abuf, sizeof(abuf)));
+ } else if (ptype == IPLT_DSTLIST) {
+ PRINTF("%s", "");
+ }
+ break;
+
+ case 3:
+ if (ptype == IPLT_POOL) {
+ PRINTF("%s", "");
+ } else if (ptype == IPLT_HASH) {
+ PRINTF("%s", "");
+ } else if (ptype == IPLT_DSTLIST) {
+ ipf_dstnode_t *node = (ipf_dstnode_t *)p;
+
+ if (node->ipfd_dest.fd_name == -1) {
+ PRINTF("%s", "");
+ } else {
+ PRINTF("%s", node->ipfd_names +
+ node->ipfd_dest.fd_name);
+ }
+ }
+ break;
+
+ case 4:
+ if (ptype == IPLT_POOL) {
+ ip_pool_node_t *node = (ip_pool_node_t *)p;
+
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", node->ipn_hits);
+#else
+ PRINTF("%lu", node->ipn_hits);
+#endif
+ } else if (ptype == IPLT_HASH) {
+ iphtent_t *node = (iphtent_t *)p;
+
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", node->ipe_hits);
+#else
+ PRINTF("%lu", node->ipe_hits);
+#endif
+ } else if (ptype == IPLT_DSTLIST) {
+ printf("0");
+ }
+ break;
+
+ case 5:
+ if (ptype == IPLT_POOL) {
+ ip_pool_node_t *node = (ip_pool_node_t *)p;
+
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", node->ipn_bytes);
+#else
+ PRINTF("%lu", node->ipn_bytes);
+#endif
+ } else if (ptype == IPLT_HASH) {
+ iphtent_t *node = (iphtent_t *)p;
+
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", node->ipe_bytes);
+#else
+ PRINTF("%lu", node->ipe_bytes);
+#endif
+ } else if (ptype == IPLT_DSTLIST) {
+ printf("0");
+ }
+ break;
+
+ case 6:
+ if (ptype == IPLT_POOL) {
+ ip_pool_node_t *node = (ip_pool_node_t *)p;
+
+ PRINTF("%s", familyname(node->ipn_addr.adf_family));
+ } else if (ptype == IPLT_HASH) {
+ iphtent_t *node = (iphtent_t *)p;
+
+ PRINTF("%s", familyname(node->ipe_family));
+ } else if (ptype == IPLT_DSTLIST) {
+ ipf_dstnode_t *node = (ipf_dstnode_t *)p;
+
+ a = &node->ipfd_dest.fd_addr;
+ PRINTF("%s", familyname(a->adf_family));
+ }
+ break;
+
+ default :
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printpoolnode.c b/contrib/ipfilter/lib/printpoolnode.c
new file mode 100644
index 0000000..aa2aed9
--- /dev/null
+++ b/contrib/ipfilter/lib/printpoolnode.c
@@ -0,0 +1,51 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+ip_pool_node_t *
+printpoolnode(np, opts, fields)
+ ip_pool_node_t *np;
+ int opts;
+ wordtab_t *fields;
+{
+ int i;
+
+ if (fields != NULL) {
+ for (i = 0; fields[i].w_value != 0; i++) {
+ printpoolfield(np, IPLT_POOL, i);
+ if (fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ } else if ((opts & OPT_DEBUG) == 0) {
+ putchar(' ');
+ if (np->ipn_info == 1)
+ PRINTF("! ");
+ printip(np->ipn_addr.adf_family,
+ (u_32_t *)&np->ipn_addr.adf_addr.in4);
+ printmask(np->ipn_addr.adf_family,
+ (u_32_t *)&np->ipn_mask.adf_addr);
+ } else {
+ PRINTF("\tAddress: %s%s", np->ipn_info ? "! " : "",
+ inet_ntoa(np->ipn_addr.adf_addr.in4));
+ printmask(np->ipn_addr.adf_family,
+ (u_32_t *)&np->ipn_mask.adf_addr);
+#ifdef USE_QUAD_T
+ PRINTF("\n\t\tHits %"PRIu64"\tBytes %"PRIu64"\tName %s\tRef %d\n",
+ np->ipn_hits, np->ipn_bytes,
+ np->ipn_name, np->ipn_ref);
+#else
+ PRINTF("\n\t\tHits %lu\tBytes %lu\tName %s\tRef %d\n",
+ np->ipn_hits, np->ipn_bytes,
+ np->ipn_name, np->ipn_ref);
+#endif
+ }
+ return np->ipn_next;
+}
diff --git a/contrib/ipfilter/lib/printportcmp.c b/contrib/ipfilter/lib/printportcmp.c
new file mode 100644
index 0000000..2a5bd02
--- /dev/null
+++ b/contrib/ipfilter/lib/printportcmp.c
@@ -0,0 +1,30 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+void
+printportcmp(pr, frp)
+ int pr;
+ frpcmp_t *frp;
+{
+ static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=",
+ "<>", "><", ":" };
+
+ if (frp->frp_cmp == FR_INRANGE || frp->frp_cmp == FR_OUTRANGE)
+ PRINTF(" port %d %s %d", frp->frp_port,
+ pcmp1[frp->frp_cmp], frp->frp_top);
+ else if (frp->frp_cmp == FR_INCRANGE)
+ PRINTF(" port %d:%d", frp->frp_port, frp->frp_top);
+ else
+ PRINTF(" port %s %s", pcmp1[frp->frp_cmp],
+ portname(pr, frp->frp_port));
+}
diff --git a/contrib/ipfilter/lib/printproto.c b/contrib/ipfilter/lib/printproto.c
new file mode 100644
index 0000000..d411bfa
--- /dev/null
+++ b/contrib/ipfilter/lib/printproto.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+void
+printproto(pr, p, np)
+ struct protoent *pr;
+ int p;
+ ipnat_t *np;
+{
+ if (np != NULL) {
+ if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP)
+ PRINTF("tcp/udp");
+ else if (np->in_flags & IPN_TCP)
+ PRINTF("tcp");
+ else if (np->in_flags & IPN_UDP)
+ PRINTF("udp");
+ else if (np->in_flags & IPN_ICMPQUERY)
+ PRINTF("icmp");
+#ifdef _AIX51
+ /*
+ * To make up for "ip = 252" and "hopopt = 0" in /etc/protocols
+ * The IANA has doubled up on the definition of 0 - it is now
+ * also used for IPv6 hop-opts, so we can no longer rely on
+ * /etc/protocols providing the correct name->number mapping.
+ */
+#endif
+ else if (np->in_pr[0] == 0)
+ PRINTF("ip");
+ else if (pr != NULL)
+ PRINTF("%s", pr->p_name);
+ else
+ PRINTF("%d", np->in_pr[0]);
+ } else {
+#ifdef _AIX51
+ if (p == 0)
+ PRINTF("ip");
+ else
+#endif
+ if (pr != NULL)
+ PRINTF("%s", pr->p_name);
+ else
+ PRINTF("%d", p);
+ }
+}
diff --git a/contrib/ipfilter/lib/printsbuf.c b/contrib/ipfilter/lib/printsbuf.c
new file mode 100644
index 0000000..efda99e
--- /dev/null
+++ b/contrib/ipfilter/lib/printsbuf.c
@@ -0,0 +1,42 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#ifdef IPFILTER_SCAN
+
+#include <ctype.h>
+#include <stdio.h>
+#include "ipf.h"
+#include "netinet/ip_scan.h"
+
+void
+printsbuf(buf)
+ char *buf;
+{
+ u_char *s;
+ int i;
+
+ for (s = (u_char *)buf, i = ISC_TLEN; i; i--, s++) {
+ if (ISPRINT(*s))
+ putchar(*s);
+ else
+ PRINTF("\\%o", *s);
+ }
+}
+#else
+void printsbuf(char *buf);
+
+void printsbuf(buf)
+ char *buf;
+{
+#if 0
+ buf = buf; /* gcc -Wextra */
+#endif
+}
+#endif
diff --git a/contrib/ipfilter/lib/printstate.c b/contrib/ipfilter/lib/printstate.c
new file mode 100644
index 0000000..fc85a70
--- /dev/null
+++ b/contrib/ipfilter/lib/printstate.c
@@ -0,0 +1,224 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+#include "kmem.h"
+
+
+ipstate_t *
+printstate(sp, opts, now)
+ ipstate_t *sp;
+ int opts;
+ u_long now;
+{
+ struct protoent *pr;
+ synclist_t ipsync;
+
+ if ((opts & OPT_NORESOLVE) == 0)
+ pr = getprotobynumber(sp->is_p);
+ else
+ pr = NULL;
+
+ PRINTF("%d:", sp->is_v);
+ if (pr != NULL)
+ PRINTF("%s", pr->p_name);
+ else
+ PRINTF("%d", sp->is_p);
+
+ PRINTF(" src:%s", hostname(sp->is_family, &sp->is_src.in4));
+ if (sp->is_p == IPPROTO_UDP || sp->is_p == IPPROTO_TCP) {
+ if (sp->is_flags & IS_WSPORT)
+ PRINTF(",*");
+ else
+ PRINTF(",%d", ntohs(sp->is_sport));
+ }
+
+ PRINTF(" dst:%s", hostname(sp->is_family, &sp->is_dst.in4));
+ if (sp->is_p == IPPROTO_UDP || sp->is_p == IPPROTO_TCP) {
+ if (sp->is_flags & IS_WDPORT)
+ PRINTF(",*");
+ else
+ PRINTF(",%d", ntohs(sp->is_dport));
+ }
+
+ if (sp->is_p == IPPROTO_TCP) {
+ PRINTF(" state:%d/%d", sp->is_state[0], sp->is_state[1]);
+ }
+
+ PRINTF(" %ld", sp->is_die - now);
+ if (sp->is_phnext == NULL)
+ PRINTF(" ORPHAN");
+ if (sp->is_flags & IS_CLONE)
+ PRINTF(" CLONE");
+ putchar('\n');
+
+ if (sp->is_p == IPPROTO_TCP) {
+ PRINTF("\t%x:%x %hu<<%d:%hu<<%d\n",
+ sp->is_send, sp->is_dend,
+ sp->is_maxswin, sp->is_swinscale,
+ sp->is_maxdwin, sp->is_dwinscale);
+ if ((opts & OPT_VERBOSE) != 0) {
+ PRINTF("\tcmsk %04x smsk %04x isc %p s0 %08x/%08x\n",
+ sp->is_smsk[0], sp->is_smsk[1], sp->is_isc,
+ sp->is_s0[0], sp->is_s0[1]);
+ PRINTF("\tFWD: ISN inc %x sumd %x\n",
+ sp->is_isninc[0], sp->is_sumd[0]);
+ PRINTF("\tREV: ISN inc %x sumd %x\n",
+ sp->is_isninc[1], sp->is_sumd[1]);
+#ifdef IPFILTER_SCAN
+ PRINTF("\tsbuf[0] [");
+ printsbuf(sp->is_sbuf[0]);
+ PRINTF("] sbuf[1] [");
+ printsbuf(sp->is_sbuf[1]);
+ PRINTF("]\n");
+#endif
+ }
+ } else if (sp->is_p == IPPROTO_GRE) {
+ PRINTF("\tcall %hx/%hx\n", ntohs(sp->is_gre.gs_call[0]),
+ ntohs(sp->is_gre.gs_call[1]));
+ } else if (sp->is_p == IPPROTO_ICMP
+#ifdef USE_INET6
+ || sp->is_p == IPPROTO_ICMPV6
+#endif
+ ) {
+ PRINTF("\tid %hu seq %hu type %d\n", sp->is_icmp.ici_id,
+ sp->is_icmp.ici_seq, sp->is_icmp.ici_type);
+ }
+
+#ifdef USE_QUAD_T
+ PRINTF("\tFWD: IN pkts %"PRIu64" bytes %"PRIu64" OUT pkts %"PRIu64" bytes %"PRIu64"\n\tREV: IN pkts %"PRIu64" bytes %"PRIu64" OUT pkts %"PRIu64" bytes %"PRIu64"\n",
+ sp->is_pkts[0], sp->is_bytes[0],
+ sp->is_pkts[1], sp->is_bytes[1],
+ sp->is_pkts[2], sp->is_bytes[2],
+ sp->is_pkts[3], sp->is_bytes[3]);
+#else
+ PRINTF("\tFWD: IN pkts %lu bytes %lu OUT pkts %lu bytes %lu\n\tREV: IN pkts %lu bytes %lu OUT pkts %lu bytes %lu\n",
+ sp->is_pkts[0], sp->is_bytes[0],
+ sp->is_pkts[1], sp->is_bytes[1],
+ sp->is_pkts[2], sp->is_bytes[2],
+ sp->is_pkts[3], sp->is_bytes[3]);
+#endif
+
+ PRINTF("\ttag %u pass %#x = ", sp->is_tag, sp->is_pass);
+
+ /*
+ * Print out bits set in the result code for the state being
+ * kept as they would for a rule.
+ */
+ if (FR_ISPASS(sp->is_pass)) {
+ PRINTF("pass");
+ } else if (FR_ISBLOCK(sp->is_pass)) {
+ PRINTF("block");
+ switch (sp->is_pass & FR_RETMASK)
+ {
+ case FR_RETICMP :
+ PRINTF(" return-icmp");
+ break;
+ case FR_FAKEICMP :
+ PRINTF(" return-icmp-as-dest");
+ break;
+ case FR_RETRST :
+ PRINTF(" return-rst");
+ break;
+ default :
+ break;
+ }
+ } else if ((sp->is_pass & FR_LOGMASK) == FR_LOG) {
+ PRINTF("log");
+ if (sp->is_pass & FR_LOGBODY)
+ PRINTF(" body");
+ if (sp->is_pass & FR_LOGFIRST)
+ PRINTF(" first");
+ } else if (FR_ISACCOUNT(sp->is_pass)) {
+ PRINTF("count");
+ } else if (FR_ISPREAUTH(sp->is_pass)) {
+ PRINTF("preauth");
+ } else if (FR_ISAUTH(sp->is_pass))
+ PRINTF("auth");
+
+ if (sp->is_pass & FR_OUTQUE)
+ PRINTF(" out");
+ else
+ PRINTF(" in");
+
+ if ((sp->is_pass & FR_LOG) != 0) {
+ PRINTF(" log");
+ if (sp->is_pass & FR_LOGBODY)
+ PRINTF(" body");
+ if (sp->is_pass & FR_LOGFIRST)
+ PRINTF(" first");
+ if (sp->is_pass & FR_LOGORBLOCK)
+ PRINTF(" or-block");
+ }
+ if (sp->is_pass & FR_QUICK)
+ PRINTF(" quick");
+ if (sp->is_pass & FR_KEEPFRAG)
+ PRINTF(" keep frags");
+ /* a given; no? */
+ if (sp->is_pass & FR_KEEPSTATE) {
+ PRINTF(" keep state");
+ if (sp->is_pass & (FR_STATESYNC|FR_STSTRICT|FR_STLOOSE)) {
+ PRINTF(" (");
+ if (sp->is_pass & FR_STATESYNC)
+ PRINTF(" sync");
+ if (sp->is_pass & FR_STSTRICT)
+ PRINTF(" strict");
+ if (sp->is_pass & FR_STLOOSE)
+ PRINTF(" loose");
+ PRINTF(" )");
+ }
+ }
+ PRINTF("\n");
+
+ if ((opts & OPT_VERBOSE) != 0) {
+ PRINTF("\tref %d", sp->is_ref);
+ PRINTF(" pkt_flags & %x(%x) = %x\n",
+ sp->is_flags & 0xf, sp->is_flags, sp->is_flags >> 4);
+ PRINTF("\tpkt_options & %x = %x, %x = %x \n", sp->is_optmsk[0],
+ sp->is_opt[0], sp->is_optmsk[1], sp->is_opt[1]);
+ PRINTF("\tpkt_security & %x = %x, pkt_auth & %x = %x\n",
+ sp->is_secmsk, sp->is_sec, sp->is_authmsk,
+ sp->is_auth);
+ PRINTF("\tis_flx %#x %#x %#x %#x\n", sp->is_flx[0][0],
+ sp->is_flx[0][1], sp->is_flx[1][0], sp->is_flx[1][1]);
+ }
+ PRINTF("\tinterfaces: in %s[%s", getifname(sp->is_ifp[0]),
+ sp->is_ifname[0]);
+ if (opts & OPT_DEBUG)
+ PRINTF("/%p", sp->is_ifp[0]);
+ putchar(']');
+ PRINTF(",%s[%s", getifname(sp->is_ifp[1]), sp->is_ifname[1]);
+ if (opts & OPT_DEBUG)
+ PRINTF("/%p", sp->is_ifp[1]);
+ putchar(']');
+ PRINTF(" out %s[%s", getifname(sp->is_ifp[2]), sp->is_ifname[2]);
+ if (opts & OPT_DEBUG)
+ PRINTF("/%p", sp->is_ifp[2]);
+ putchar(']');
+ PRINTF(",%s[%s", getifname(sp->is_ifp[3]), sp->is_ifname[3]);
+ if (opts & OPT_DEBUG)
+ PRINTF("/%p", sp->is_ifp[3]);
+ PRINTF("]\n");
+
+ PRINTF("\tSync status: ");
+ if (sp->is_sync != NULL) {
+ if (kmemcpy((char *)&ipsync, (u_long)sp->is_sync,
+ sizeof(ipsync))) {
+ PRINTF("status could not be retrieved\n");
+ return NULL;
+ }
+
+ PRINTF("idx %d num %d v %d pr %d rev %d\n",
+ ipsync.sl_idx, ipsync.sl_num, ipsync.sl_v,
+ ipsync.sl_p, ipsync.sl_rev);
+ } else {
+ PRINTF("not synchronized\n");
+ }
+
+ return sp->is_next;
+}
diff --git a/contrib/ipfilter/lib/printstatefields.c b/contrib/ipfilter/lib/printstatefields.c
new file mode 100644
index 0000000..5632d84
--- /dev/null
+++ b/contrib/ipfilter/lib/printstatefields.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: printstatefields.c,v 1.4.2.2 2012/01/26 05:44:26 darren_r Exp $
+ */
+
+#include "ipf.h"
+
+wordtab_t statefields[] = {
+ { "all", -2 },
+ { "ifp0", 1 },
+ { "ifp1", 2 },
+ { "ifp2", 3 },
+ { "ifp3", 4 },
+ { "ifname0", 5 },
+ { "ifname1", 6 },
+ { "ifname2", 7 },
+ { "ifname3", 8 },
+ { "pkts0", 9 },
+ { "pkts1", 10 },
+ { "pkts2", 11 },
+ { "pkts3", 12 },
+ { "bytes0", 13 },
+ { "bytes1", 14 },
+ { "bytes2", 15 },
+ { "bytes3", 16 },
+ { "state0", 17 },
+ { "state1", 18 },
+ { "age0", 19 },
+ { "age1", 20 },
+ { "ref", 21 },
+ { "isn0", 22 },
+ { "isn1", 23 },
+ { "sumd0", 24 },
+ { "sumd1", 25 },
+ { "src", 26 },
+ { "dst", 27 },
+ { "sport", 28 },
+ { "dport", 29 },
+ { "icmptype", 30 },
+ { "-", 31 },
+ { "pass", 32 },
+ { "proto", 33 },
+ { "version", 34 },
+ { "hash", 35 },
+ { "tag", 36 },
+ { "flags", 37 },
+ { "rulen", 38 },
+ { "group", 39 },
+ { "flx0", 40 },
+ { "flx1", 41 },
+ { "flx2", 42 },
+ { "flx3", 43 },
+ { "opt0", 44 },
+ { "opt1", 45 },
+ { "optmsk0", 46 },
+ { "optmsk1", 47 },
+ { "sec", 48 },
+ { "secmsk", 49 },
+ { "auth", 50 },
+ { "authmsk", 51 },
+ { "icmppkts0", 52 },
+ { "icmppkts1", 53 },
+ { "icmppkts2", 54 },
+ { "icmppkts3", 55 },
+ { NULL, 0 }
+};
+
+
+void
+printstatefield(sp, fieldnum)
+ ipstate_t *sp;
+ int fieldnum;
+{
+ int i;
+
+ switch (fieldnum)
+ {
+ case -2 :
+ for (i = 1; statefields[i].w_word != NULL; i++) {
+ if (statefields[i].w_value > 0) {
+ printstatefield(sp, i);
+ if (statefields[i + 1].w_value > 0)
+ putchar('\t');
+ }
+ }
+ break;
+
+ case 1:
+ PRINTF("%#lx", (u_long)sp->is_ifp[0]);
+ break;
+
+ case 2:
+ PRINTF("%#lx", (u_long)sp->is_ifp[1]);
+ break;
+
+ case 3:
+ PRINTF("%#lx", (u_long)sp->is_ifp[2]);
+ break;
+
+ case 4:
+ PRINTF("%#lx", (u_long)sp->is_ifp[3]);
+ break;
+
+ case 5:
+ PRINTF("%s", sp->is_ifname[0]);
+ break;
+
+ case 6:
+ PRINTF("%s", sp->is_ifname[1]);
+ break;
+
+ case 7:
+ PRINTF("%s", sp->is_ifname[2]);
+ break;
+
+ case 8:
+ PRINTF("%s", sp->is_ifname[3]);
+ break;
+
+ case 9:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_pkts[0]);
+#else
+ PRINTF("%lu", sp->is_pkts[0]);
+#endif
+ break;
+
+ case 10:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_pkts[1]);
+#else
+ PRINTF("%lu", sp->is_pkts[1]);
+#endif
+ break;
+
+ case 11:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_pkts[2]);
+#else
+ PRINTF("%lu", sp->is_pkts[2]);
+#endif
+ break;
+
+ case 12:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_pkts[3]);
+#else
+ PRINTF("%lu", sp->is_pkts[3]);
+#endif
+ break;
+
+ case 13:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_bytes[0]);
+#else
+ PRINTF("%lu", sp->is_bytes[0]);
+#endif
+ break;
+
+ case 14:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_bytes[1]);
+#else
+ PRINTF("%lu", sp->is_bytes[1]);
+#endif
+ break;
+
+ case 15:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_bytes[2]);
+#else
+ PRINTF("%lu", sp->is_bytes[2]);
+#endif
+ break;
+
+ case 16:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_bytes[3]);
+#else
+ PRINTF("%lu", sp->is_bytes[3]);
+#endif
+ break;
+
+ case 17:
+ PRINTF("%d", sp->is_state[0]);
+ break;
+
+ case 18:
+ PRINTF("%d", sp->is_state[1]);
+ break;
+
+ case 19:
+ PRINTF("%d", sp->is_frage[0]);
+ break;
+
+ case 20:
+ PRINTF("%d", sp->is_frage[1]);
+ break;
+
+ case 21:
+ PRINTF("%d", sp->is_ref);
+ break;
+
+ case 22:
+ PRINTF("%d", sp->is_isninc[0]);
+ break;
+
+ case 23:
+ PRINTF("%d", sp->is_isninc[1]);
+ break;
+
+ case 24:
+ PRINTF("%hd", sp->is_sumd[0]);
+ break;
+
+ case 25:
+ PRINTF("%hd", sp->is_sumd[1]);
+ break;
+
+ case 26:
+ PRINTF("%s", hostname(sp->is_v, &sp->is_src.in4));
+ break;
+
+ case 27:
+ PRINTF("%s", hostname(sp->is_v, &sp->is_dst.in4));
+ break;
+
+ case 28:
+ PRINTF("%hu", ntohs(sp->is_sport));
+ break;
+
+ case 29:
+ PRINTF("%hu", ntohs(sp->is_dport));
+ break;
+
+ case 30:
+ PRINTF("%d", sp->is_type);
+ break;
+
+ case 32:
+ PRINTF("%#x", sp->is_pass);
+ break;
+
+ case 33:
+ PRINTF("%d", sp->is_p);
+ break;
+
+ case 34:
+ PRINTF("%d", sp->is_v);
+ break;
+
+ case 35:
+ PRINTF("%d", sp->is_hv);
+ break;
+
+ case 36:
+ PRINTF("%d", sp->is_tag);
+ break;
+
+ case 37:
+ PRINTF("%#x", sp->is_flags);
+ break;
+
+ case 38:
+ PRINTF("%d", sp->is_rulen);
+ break;
+
+ case 39:
+ PRINTF("%s", sp->is_group);
+ break;
+
+ case 40:
+ PRINTF("%#x", sp->is_flx[0][0]);
+ break;
+
+ case 41:
+ PRINTF("%#x", sp->is_flx[0][1]);
+ break;
+
+ case 42:
+ PRINTF("%#x", sp->is_flx[1][0]);
+ break;
+
+ case 43:
+ PRINTF("%#x", sp->is_flx[1][1]);
+ break;
+
+ case 44:
+ PRINTF("%#x", sp->is_opt[0]);
+ break;
+
+ case 45:
+ PRINTF("%#x", sp->is_opt[1]);
+ break;
+
+ case 46:
+ PRINTF("%#x", sp->is_optmsk[0]);
+ break;
+
+ case 47:
+ PRINTF("%#x", sp->is_optmsk[1]);
+ break;
+
+ case 48:
+ PRINTF("%#x", sp->is_sec);
+ break;
+
+ case 49:
+ PRINTF("%#x", sp->is_secmsk);
+ break;
+
+ case 50:
+ PRINTF("%#x", sp->is_auth);
+ break;
+
+ case 51:
+ PRINTF("%#x", sp->is_authmsk);
+ break;
+
+ case 52:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_icmppkts[0]);
+#else
+ PRINTF("%lu", sp->is_icmppkts[0]);
+#endif
+ break;
+
+ case 53:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_icmppkts[1]);
+#else
+ PRINTF("%lu", sp->is_icmppkts[1]);
+#endif
+ break;
+
+ case 54:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_icmppkts[2]);
+#else
+ PRINTF("%lu", sp->is_icmppkts[2]);
+#endif
+ break;
+
+ case 55:
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64"", sp->is_icmppkts[3]);
+#else
+ PRINTF("%lu", sp->is_icmppkts[3]);
+#endif
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/contrib/ipfilter/lib/printtcpflags.c b/contrib/ipfilter/lib/printtcpflags.c
new file mode 100644
index 0000000..9860780
--- /dev/null
+++ b/contrib/ipfilter/lib/printtcpflags.c
@@ -0,0 +1,30 @@
+#include "ipf.h"
+
+
+void
+printtcpflags(tcpf, tcpfm)
+ u_32_t tcpf, tcpfm;
+{
+ u_char *t;
+ char *s;
+
+ if (tcpf & ~TCPF_ALL) {
+ PRINTF("0x%x", tcpf);
+ } else {
+ for (s = flagset, t = flags; *s; s++, t++) {
+ if (tcpf & *t)
+ (void)putchar(*s);
+ }
+ }
+
+ if (tcpfm) {
+ (void)putchar('/');
+ if (tcpfm & ~TCPF_ALL) {
+ PRINTF("0x%x", tcpfm);
+ } else {
+ for (s = flagset, t = flags; *s; s++, t++)
+ if (tcpfm & *t)
+ (void)putchar(*s);
+ }
+ }
+}
diff --git a/contrib/ipfilter/lib/printtqtable.c b/contrib/ipfilter/lib/printtqtable.c
new file mode 100644
index 0000000..ffb512d
--- /dev/null
+++ b/contrib/ipfilter/lib/printtqtable.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+
+
+void
+printtqtable(table)
+ ipftq_t *table;
+{
+ int i;
+
+ PRINTF("TCP Entries per state\n");
+ for (i = 0; i < IPF_TCP_NSTATES; i++)
+ PRINTF(" %5d", i);
+ PRINTF("\n");
+
+ for (i = 0; i < IPF_TCP_NSTATES; i++)
+ PRINTF(" %5d", table[i].ifq_ref - 1);
+ PRINTF("\n");
+}
diff --git a/contrib/ipfilter/lib/printtunable.c b/contrib/ipfilter/lib/printtunable.c
new file mode 100644
index 0000000..aa82841
--- /dev/null
+++ b/contrib/ipfilter/lib/printtunable.c
@@ -0,0 +1,30 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+void
+printtunable(tup)
+ ipftune_t *tup;
+{
+ PRINTF("%s\tmin %lu\tmax %lu\tcurrent ",
+ tup->ipft_name, tup->ipft_min, tup->ipft_max);
+ if (tup->ipft_sz == sizeof(u_long))
+ PRINTF("%lu\n", tup->ipft_vlong);
+ else if (tup->ipft_sz == sizeof(u_int))
+ PRINTF("%u\n", tup->ipft_vint);
+ else if (tup->ipft_sz == sizeof(u_short))
+ PRINTF("%hu\n", tup->ipft_vshort);
+ else if (tup->ipft_sz == sizeof(u_char))
+ PRINTF("%u\n", (u_int)tup->ipft_vchar);
+ else {
+ PRINTF("sz = %d\n", tup->ipft_sz);
+ }
+}
diff --git a/contrib/ipfilter/lib/printunit.c b/contrib/ipfilter/lib/printunit.c
new file mode 100644
index 0000000..bac3d45
--- /dev/null
+++ b/contrib/ipfilter/lib/printunit.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#include "ipf.h"
+
+
+void
+printunit(unit)
+ int unit;
+{
+
+ switch (unit)
+ {
+ case IPL_LOGIPF :
+ PRINTF("ipf");
+ break;
+ case IPL_LOGNAT :
+ PRINTF("nat");
+ break;
+ case IPL_LOGSTATE :
+ PRINTF("state");
+ break;
+ case IPL_LOGAUTH :
+ PRINTF("auth");
+ break;
+ case IPL_LOGSYNC :
+ PRINTF("sync");
+ break;
+ case IPL_LOGSCAN :
+ PRINTF("scan");
+ break;
+ case IPL_LOGLOOKUP :
+ PRINTF("lookup");
+ break;
+ case IPL_LOGCOUNT :
+ PRINTF("count");
+ break;
+ case IPL_LOGALL :
+ PRINTF("all");
+ break;
+ default :
+ PRINTF("unknown(%d)", unit);
+ }
+}
diff --git a/contrib/ipfilter/lib/remove_hash.c b/contrib/ipfilter/lib/remove_hash.c
new file mode 100644
index 0000000..a60c1fd
--- /dev/null
+++ b/contrib/ipfilter/lib/remove_hash.c
@@ -0,0 +1,50 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_htable.h"
+
+
+int
+remove_hash(iphp, iocfunc)
+ iphtable_t *iphp;
+ ioctlfunc_t iocfunc;
+{
+ iplookupop_t op;
+ iphtable_t iph;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_type = IPLT_HASH;
+ op.iplo_unit = iphp->iph_unit;
+ strncpy(op.iplo_name, iphp->iph_name, sizeof(op.iplo_name));
+ if (*op.iplo_name == '\0')
+ op.iplo_arg = IPHASH_ANON;
+ op.iplo_size = sizeof(iph);
+ op.iplo_struct = &iph;
+
+ bzero((char *)&iph, sizeof(iph));
+ iph.iph_unit = iphp->iph_unit;
+ iph.iph_type = iphp->iph_type;
+ strncpy(iph.iph_name, iphp->iph_name, sizeof(iph.iph_name));
+ iph.iph_flags = iphp->iph_flags;
+
+ if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op)) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "remove lookup hash table");
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/remove_hashnode.c b/contrib/ipfilter/lib/remove_hashnode.c
new file mode 100644
index 0000000..58e9125
--- /dev/null
+++ b/contrib/ipfilter/lib/remove_hashnode.c
@@ -0,0 +1,56 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_htable.h"
+
+
+int
+remove_hashnode(unit, name, node, iocfunc)
+ int unit;
+ char *name;
+ iphtent_t *node;
+ ioctlfunc_t iocfunc;
+{
+ iplookupop_t op;
+ iphtent_t ipe;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_type = IPLT_HASH;
+ op.iplo_unit = unit;
+ op.iplo_size = sizeof(ipe);
+ op.iplo_struct = &ipe;
+ op.iplo_arg = 0;
+ strncpy(op.iplo_name, name, sizeof(op.iplo_name));
+
+ bzero((char *)&ipe, sizeof(ipe));
+ bcopy((char *)&node->ipe_addr, (char *)&ipe.ipe_addr,
+ sizeof(ipe.ipe_addr));
+ bcopy((char *)&node->ipe_mask, (char *)&ipe.ipe_mask,
+ sizeof(ipe.ipe_mask));
+
+ if (opts & OPT_DEBUG) {
+ printf("\t%s - ", inet_ntoa(ipe.ipe_addr.in4));
+ printf("%s\n", inet_ntoa(ipe.ipe_mask.in4));
+ }
+
+ if (pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op)) {
+ if (!(opts & OPT_DONOTHING)) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "remove lookup hash node");
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/remove_pool.c b/contrib/ipfilter/lib/remove_pool.c
new file mode 100644
index 0000000..8e75549
--- /dev/null
+++ b/contrib/ipfilter/lib/remove_pool.c
@@ -0,0 +1,47 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_htable.h"
+
+
+int
+remove_pool(poolp, iocfunc)
+ ip_pool_t *poolp;
+ ioctlfunc_t iocfunc;
+{
+ iplookupop_t op;
+ ip_pool_t pool;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_type = IPLT_POOL;
+ op.iplo_unit = poolp->ipo_unit;
+ strncpy(op.iplo_name, poolp->ipo_name, sizeof(op.iplo_name));
+ op.iplo_size = sizeof(pool);
+ op.iplo_struct = &pool;
+
+ bzero((char *)&pool, sizeof(pool));
+ pool.ipo_unit = poolp->ipo_unit;
+ strncpy(pool.ipo_name, poolp->ipo_name, sizeof(pool.ipo_name));
+ pool.ipo_flags = poolp->ipo_flags;
+
+ if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op)) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "delete lookup pool");
+ }
+ }
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/remove_poolnode.c b/contrib/ipfilter/lib/remove_poolnode.c
new file mode 100644
index 0000000..0b78118
--- /dev/null
+++ b/contrib/ipfilter/lib/remove_poolnode.c
@@ -0,0 +1,54 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+
+
+int
+remove_poolnode(unit, name, node, iocfunc)
+ int unit;
+ char *name;
+ ip_pool_node_t *node;
+ ioctlfunc_t iocfunc;
+{
+ ip_pool_node_t pn;
+ iplookupop_t op;
+
+ if (pool_open() == -1)
+ return -1;
+
+ op.iplo_unit = unit;
+ op.iplo_type = IPLT_POOL;
+ op.iplo_arg = 0;
+ strncpy(op.iplo_name, name, sizeof(op.iplo_name));
+ op.iplo_struct = &pn;
+ op.iplo_size = sizeof(pn);
+
+ bzero((char *)&pn, sizeof(pn));
+ bcopy((char *)&node->ipn_addr, (char *)&pn.ipn_addr,
+ sizeof(pn.ipn_addr));
+ bcopy((char *)&node->ipn_mask, (char *)&pn.ipn_mask,
+ sizeof(pn.ipn_mask));
+ pn.ipn_info = node->ipn_info;
+ strncpy(pn.ipn_name, node->ipn_name, sizeof(pn.ipn_name));
+
+ if (pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op)) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ return ipf_perror_fd(pool_fd(), iocfunc,
+ "remove lookup pool node");
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/resetlexer.c b/contrib/ipfilter/lib/resetlexer.c
new file mode 100644
index 0000000..558db98
--- /dev/null
+++ b/contrib/ipfilter/lib/resetlexer.c
@@ -0,0 +1,25 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+long string_start = -1;
+long string_end = -1;
+char *string_val = NULL;
+long pos = 0;
+
+
+void resetlexer()
+{
+ string_start = -1;
+ string_end = -1;
+ string_val = NULL;
+ pos = 0;
+}
diff --git a/contrib/ipfilter/lib/rwlock_emul.c b/contrib/ipfilter/lib/rwlock_emul.c
new file mode 100644
index 0000000..24d00a5
--- /dev/null
+++ b/contrib/ipfilter/lib/rwlock_emul.c
@@ -0,0 +1,145 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+#define EMM_MAGIC 0x97dd8b3a
+
+void eMrwlock_read_enter(rw, file, line)
+ eMrwlock_t *rw;
+ char *file;
+ int line;
+{
+ if (rw->eMrw_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMrwlock_read_enter(%p): bad magic: %#x\n",
+ rw->eMrw_owner, rw, rw->eMrw_magic);
+ abort();
+ }
+ if (rw->eMrw_read != 0 || rw->eMrw_write != 0) {
+ fprintf(stderr,
+ "%s:eMrwlock_read_enter(%p): already locked: %d/%d\n",
+ rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write);
+ abort();
+ }
+ rw->eMrw_read++;
+ rw->eMrw_heldin = file;
+ rw->eMrw_heldat = line;
+}
+
+
+void eMrwlock_write_enter(rw, file, line)
+ eMrwlock_t *rw;
+ char *file;
+ int line;
+{
+ if (rw->eMrw_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMrwlock_write_enter(%p): bad magic: %#x\n",
+ rw->eMrw_owner, rw, rw->eMrw_magic);
+ abort();
+ }
+ if (rw->eMrw_read != 0 || rw->eMrw_write != 0) {
+ fprintf(stderr,
+ "%s:eMrwlock_write_enter(%p): already locked: %d/%d\n",
+ rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write);
+ abort();
+ }
+ rw->eMrw_write++;
+ rw->eMrw_heldin = file;
+ rw->eMrw_heldat = line;
+}
+
+
+void eMrwlock_downgrade(rw, file, line)
+ eMrwlock_t *rw;
+ char *file;
+ int line;
+{
+ if (rw->eMrw_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMrwlock_write_enter(%p): bad magic: %#x\n",
+ rw->eMrw_owner, rw, rw->eMrw_magic);
+ abort();
+ }
+ if (rw->eMrw_read != 0 || rw->eMrw_write != 1) {
+ fprintf(stderr,
+ "%s:eMrwlock_write_enter(%p): already locked: %d/%d\n",
+ rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write);
+ abort();
+ }
+ rw->eMrw_write--;
+ rw->eMrw_read++;
+ rw->eMrw_heldin = file;
+ rw->eMrw_heldat = line;
+}
+
+
+void eMrwlock_exit(rw)
+ eMrwlock_t *rw;
+{
+ if (rw->eMrw_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMrwlock_exit(%p): bad magic: %#x\n",
+ rw->eMrw_owner, rw, rw->eMrw_magic);
+ abort();
+ }
+ if (rw->eMrw_read != 1 && rw->eMrw_write != 1) {
+ fprintf(stderr, "%s:eMrwlock_exit(%p): not locked: %d/%d\n",
+ rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write);
+ abort();
+ }
+ if (rw->eMrw_read == 1)
+ rw->eMrw_read--;
+ else if (rw->eMrw_write == 1)
+ rw->eMrw_write--;
+ rw->eMrw_heldin = NULL;
+ rw->eMrw_heldat = 0;
+}
+
+
+static int initcount = 0;
+
+void eMrwlock_init(rw, who)
+ eMrwlock_t *rw;
+ char *who;
+{
+ if (rw->eMrw_magic == EMM_MAGIC) { /* safe bet ? */
+ fprintf(stderr,
+ "%s:eMrwlock_init(%p): already initialised?: %#x\n",
+ rw->eMrw_owner, rw, rw->eMrw_magic);
+ abort();
+ }
+ rw->eMrw_magic = EMM_MAGIC;
+ rw->eMrw_read = 0;
+ rw->eMrw_write = 0;
+ if (who != NULL)
+ rw->eMrw_owner = strdup(who);
+ else
+ rw->eMrw_owner = NULL;
+ initcount++;
+}
+
+
+void eMrwlock_destroy(rw)
+ eMrwlock_t *rw;
+{
+ if (rw->eMrw_magic != EMM_MAGIC) {
+ fprintf(stderr, "%s:eMrwlock_destroy(%p): bad magic: %#x\n",
+ rw->eMrw_owner, rw, rw->eMrw_magic);
+ abort();
+ }
+ if (rw->eMrw_owner != NULL)
+ free(rw->eMrw_owner);
+ memset(rw, 0xa5, sizeof(*rw));
+ initcount--;
+}
+
+void ipf_rwlock_clean()
+{
+ if (initcount != 0)
+ abort();
+}
diff --git a/contrib/ipfilter/lib/save_execute.c b/contrib/ipfilter/lib/save_execute.c
new file mode 100644
index 0000000..65caca4
--- /dev/null
+++ b/contrib/ipfilter/lib/save_execute.c
@@ -0,0 +1,80 @@
+#include "ipf.h"
+#include "ipmon.h"
+
+static void *execute_parse __P((char **));
+static void execute_destroy __P((void *));
+static int execute_send __P((void *, ipmon_msg_t *));
+static void execute_print __P((void *));
+
+typedef struct execute_opts_s {
+ char *path;
+} execute_opts_t;
+
+ipmon_saver_t executesaver = {
+ "execute",
+ execute_destroy,
+ NULL, /* dup */
+ NULL, /* match */
+ execute_parse,
+ execute_print,
+ execute_send
+};
+
+
+static void *
+execute_parse(char **strings)
+{
+ execute_opts_t *ctx;
+
+ ctx = calloc(1, sizeof(*ctx));
+
+ if (ctx != NULL && strings[0] != NULL && strings[0][0] != '\0') {
+ ctx->path = strdup(strings[0]);
+
+ } else {
+ free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+static void
+execute_print(ctx)
+ void *ctx;
+{
+ execute_opts_t *exe = ctx;
+
+ printf("%s", exe->path);
+}
+
+
+static void
+execute_destroy(ctx)
+ void *ctx;
+{
+ execute_opts_t *exe = ctx;
+
+ if (exe != NULL)
+ free(exe->path);
+ free(exe);
+}
+
+
+static int
+execute_send(ctx, msg)
+ void *ctx;
+ ipmon_msg_t *msg;
+{
+ execute_opts_t *exe = ctx;
+ FILE *fp;
+
+ fp = popen(exe->path, "w");
+ if (fp != NULL) {
+ fwrite(msg->imm_msg, msg->imm_msglen, 1, fp);
+ pclose(fp);
+ }
+ return 0;
+}
+
diff --git a/contrib/ipfilter/lib/save_file.c b/contrib/ipfilter/lib/save_file.c
new file mode 100644
index 0000000..b852bd6
--- /dev/null
+++ b/contrib/ipfilter/lib/save_file.c
@@ -0,0 +1,130 @@
+#include "ipf.h"
+#include "ipmon.h"
+
+static void *file_parse __P((char **));
+static void file_destroy __P((void *));
+static int file_send __P((void *, ipmon_msg_t *));
+static void file_print __P((void *));
+static int file_match __P((void *, void *));
+static void *file_dup __P((void *));
+
+typedef struct file_opts_s {
+ FILE *fp;
+ int raw;
+ char *path;
+ int ref;
+} file_opts_t;
+
+ipmon_saver_t filesaver = {
+ "file",
+ file_destroy,
+ file_dup,
+ file_match,
+ file_parse,
+ file_print,
+ file_send
+};
+
+
+static void *
+file_parse(strings)
+ char **strings;
+{
+ file_opts_t *ctx;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ if (strings[0] != NULL && strings[0][0] != '\0') {
+ ctx->ref = 1;
+ if (!strncmp(strings[0], "raw://", 6)) {
+ ctx->raw = 1;
+ ctx->path = strdup(strings[0] + 6);
+ ctx->fp = fopen(ctx->path, "ab");
+ } else if (!strncmp(strings[0], "file://", 7)) {
+ ctx->path = strdup(strings[0] + 7);
+ ctx->fp = fopen(ctx->path, "a");
+ } else {
+ free(ctx);
+ ctx = NULL;
+ }
+ } else {
+ free(ctx);
+ ctx = NULL;
+ }
+
+ return ctx;
+}
+
+
+static int
+file_match(ctx1, ctx2)
+ void *ctx1, *ctx2;
+{
+ file_opts_t *f1 = ctx1, *f2 = ctx2;
+
+ if (f1->raw != f2->raw)
+ return 1;
+ if (strcmp(f1->path, f2->path))
+ return 1;
+ return 0;
+}
+
+
+static void *
+file_dup(ctx)
+ void *ctx;
+{
+ file_opts_t *f = ctx;
+
+ f->ref++;
+ return f;
+}
+
+
+static void
+file_print(ctx)
+ void *ctx;
+{
+ file_opts_t *file = ctx;
+
+ if (file->raw)
+ printf("raw://");
+ else
+ printf("file://");
+ printf("%s", file->path);
+}
+
+
+static void
+file_destroy(ctx)
+ void *ctx;
+{
+ file_opts_t *file = ctx;
+
+ file->ref--;
+ if (file->ref > 0)
+ return;
+
+ if (file->path != NULL)
+ free(file->path);
+ free(file);
+}
+
+
+static int
+file_send(ctx, msg)
+ void *ctx;
+ ipmon_msg_t *msg;
+{
+ file_opts_t *file = ctx;
+
+ if (file->raw) {
+ fwrite(msg->imm_data, msg->imm_dsize, 1, file->fp);
+ } else {
+ fprintf(file->fp, "%s", msg->imm_msg);
+ }
+ return 0;
+}
+
diff --git a/contrib/ipfilter/lib/save_nothing.c b/contrib/ipfilter/lib/save_nothing.c
new file mode 100644
index 0000000..d25ab51
--- /dev/null
+++ b/contrib/ipfilter/lib/save_nothing.c
@@ -0,0 +1,62 @@
+#include "ipf.h"
+#include "ipmon.h"
+
+static void *nothing_parse __P((char **));
+static void nothing_destroy __P((void *));
+static int nothing_send __P((void *, ipmon_msg_t *));
+
+typedef struct nothing_opts_s {
+ FILE *fp;
+ int raw;
+ char *path;
+} nothing_opts_t;
+
+ipmon_saver_t nothingsaver = {
+ "nothing",
+ nothing_destroy,
+ NULL, /* dup */
+ NULL, /* match */
+ nothing_parse,
+ NULL, /* print */
+ nothing_send
+};
+
+
+static void *
+nothing_parse(char **strings)
+{
+ void *ctx;
+
+#if 0
+ strings = strings; /* gcc -Wextra */
+#endif
+
+ ctx = calloc(1, sizeof(void *));
+
+ return ctx;
+}
+
+
+static void
+nothing_destroy(ctx)
+ void *ctx;
+{
+ free(ctx);
+}
+
+
+static int
+nothing_send(ctx, msg)
+ void *ctx;
+ ipmon_msg_t *msg;
+{
+#if 0
+ ctx = ctx; /* gcc -Wextra */
+ msg = msg; /* gcc -Wextra */
+#endif
+ /*
+ * Do nothing
+ */
+ return 0;
+}
+
diff --git a/contrib/ipfilter/lib/save_syslog.c b/contrib/ipfilter/lib/save_syslog.c
new file mode 100644
index 0000000..c1efdf4
--- /dev/null
+++ b/contrib/ipfilter/lib/save_syslog.c
@@ -0,0 +1,137 @@
+#include "ipf.h"
+#include "ipmon.h"
+#include <syslog.h>
+
+static void *syslog_parse __P((char **));
+static void syslog_destroy __P((void *));
+static int syslog_send __P((void *, ipmon_msg_t *));
+static void syslog_print __P((void *));
+
+typedef struct syslog_opts_s {
+ int facpri;
+ int fac;
+ int pri;
+} syslog_opts_t;
+
+ipmon_saver_t syslogsaver = {
+ "syslog",
+ syslog_destroy,
+ NULL, /* dup */
+ NULL, /* match */
+ syslog_parse,
+ syslog_print,
+ syslog_send
+};
+
+
+static void *
+syslog_parse(char **strings)
+{
+ syslog_opts_t *ctx;
+ char *str;
+ char *s;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->facpri = -1;
+
+ if (strings[0] != NULL && strings[0][0] != '\0') {
+ str = strdup(*strings);
+ if (str != NULL && *str != '\0') {
+ int fac = -1, pri = -1;
+
+ s = strchr(str, '.');
+ if (s != NULL)
+ *s++ = '\0';
+
+ if (*str != '\0') {
+ fac = fac_findname(str);
+ if (fac == -1) {
+ free(str);
+ free(ctx);
+ return NULL;
+ }
+ }
+
+ if (s != NULL && *s != '\0') {
+ pri = pri_findname(s);
+ if (pri == -1) {
+ free(str);
+ free(ctx);
+ return NULL;
+ }
+ }
+ free(str);
+
+ ctx->fac = fac;
+ ctx->pri = pri;
+ if (pri == -1)
+ ctx->facpri = fac;
+ else if (fac == -1)
+ ctx->facpri = pri;
+ else
+ ctx->facpri = fac | pri;
+ } else {
+ if (str != NULL)
+ free(str);
+ free(ctx);
+ ctx = NULL;
+ }
+ }
+
+ return ctx;
+}
+
+
+static void
+syslog_print(ctx)
+ void *ctx;
+{
+ syslog_opts_t *sys = ctx;
+
+ if (sys->facpri == -1)
+ return;
+
+ if (sys->fac == -1) {
+ printf(".%s", pri_toname(sys->pri));
+ } else if (sys->pri == -1) {
+ printf("%s.", fac_toname(sys->fac));
+ } else {
+ printf("%s.%s", fac_toname(sys->facpri & LOG_FACMASK),
+ pri_toname(sys->facpri & LOG_PRIMASK));
+ }
+}
+
+
+static void
+syslog_destroy(ctx)
+ void *ctx;
+{
+ free(ctx);
+}
+
+
+static int
+syslog_send(ctx, msg)
+ void *ctx;
+ ipmon_msg_t *msg;
+{
+ syslog_opts_t *sys = ctx;
+ int facpri;
+
+ if (sys->facpri == -1) {
+ facpri = msg->imm_loglevel;
+ } else {
+ if (sys->pri == -1) {
+ facpri = sys->fac | (msg->imm_loglevel & LOG_PRIMASK);
+ } else if (sys->fac == -1) {
+ facpri = sys->pri | (msg->imm_loglevel & LOG_FACMASK);
+ } else {
+ facpri = sys->facpri;
+ }
+ }
+ syslog(facpri, "%s", msg->imm_msg);
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/save_v1trap.c b/contrib/ipfilter/lib/save_v1trap.c
new file mode 100644
index 0000000..78671c7
--- /dev/null
+++ b/contrib/ipfilter/lib/save_v1trap.c
@@ -0,0 +1,463 @@
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include "ipmon.h"
+#include <ctype.h>
+
+#define IPF_ENTERPRISE 9932
+/*
+ * Enterprise number OID:
+ * 1.3.6.1.4.1.9932
+ */
+static u_char ipf_enterprise[] = { 6, 7, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c };
+static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
+static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
+
+static int writeint __P((u_char *, int));
+static int writelength __P((u_char *, u_int));
+static int maketrap_v1 __P((char *, u_char *, int, u_char *, int, u_32_t,
+ time_t));
+static void snmpv1_destroy __P((void *));
+static void *snmpv1_dup __P((void *));
+static int snmpv1_match __P((void *, void *));
+static void *snmpv1_parse __P((char **));
+static void snmpv1_print __P((void *));
+static int snmpv1_send __P((void *, ipmon_msg_t *));
+
+typedef struct snmpv1_opts_s {
+ char *community;
+ int fd;
+ int v6;
+ int ref;
+#ifdef USE_INET6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr_in sin;
+} snmpv1_opts_t;
+
+ipmon_saver_t snmpv1saver = {
+ "snmpv1",
+ snmpv1_destroy,
+ snmpv1_dup, /* dup */
+ snmpv1_match, /* match */
+ snmpv1_parse,
+ snmpv1_print,
+ snmpv1_send
+};
+
+
+static int
+snmpv1_match(ctx1, ctx2)
+ void *ctx1, *ctx2;
+{
+ snmpv1_opts_t *s1 = ctx1, *s2 = ctx2;
+
+ if (s1->v6 != s2->v6)
+ return 1;
+
+ if (strcmp(s1->community, s2->community))
+ return 1;
+
+#ifdef USE_INET6
+ if (s1->v6 == 1) {
+ if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
+ return 1;
+ } else
+#endif
+ {
+ if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void *
+snmpv1_dup(ctx)
+ void *ctx;
+{
+ snmpv1_opts_t *s = ctx;
+
+ s->ref++;
+ return s;
+}
+
+
+static void
+snmpv1_print(ctx)
+ void *ctx;
+{
+ snmpv1_opts_t *snmpv1 = ctx;
+
+ printf("%s ", snmpv1->community);
+#ifdef USE_INET6
+ if (snmpv1->v6 == 1) {
+ char buf[80];
+
+ printf("%s", inet_ntop(AF_INET6, &snmpv1->sin6.sin6_addr, buf,
+ sizeof(snmpv1->sin6.sin6_addr)));
+ } else
+#endif
+ {
+ printf("%s", inet_ntoa(snmpv1->sin.sin_addr));
+ }
+}
+
+
+static void *
+snmpv1_parse(char **strings)
+{
+ snmpv1_opts_t *ctx;
+ int result;
+ char *str;
+ char *s;
+
+ if (strings[0] == NULL || strings[0][0] == '\0')
+ return NULL;
+
+ if (strchr(*strings, ' ') == NULL)
+ return NULL;
+
+ str = strdup(*strings);
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->fd = -1;
+
+ s = strchr(str, ' ');
+ *s++ = '\0';
+ ctx->community = str;
+
+ while (ISSPACE(*s))
+ s++;
+ if (!*s) {
+ free(str);
+ free(ctx);
+ return NULL;
+ }
+
+#ifdef USE_INET6
+ if (strchr(s, ':') == NULL) {
+ result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
+ if (result == 1) {
+ ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctx->fd >= 0) {
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_port = htons(162);
+ if (connect(ctx->fd,
+ (struct sockaddr *)&ctx->sin,
+ sizeof(ctx->sin)) != 0) {
+ snmpv1_destroy(ctx);
+ return NULL;
+ }
+ }
+ }
+ } else {
+ result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
+ if (result == 1) {
+ ctx->v6 = 1;
+ ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (ctx->fd >= 0) {
+ ctx->sin6.sin6_family = AF_INET6;
+ ctx->sin6.sin6_port = htons(162);
+ if (connect(ctx->fd,
+ (struct sockaddr *)&ctx->sin6,
+ sizeof(ctx->sin6)) != 0) {
+ snmpv1_destroy(ctx);
+ return NULL;
+ }
+ }
+ }
+ }
+#else
+ result = inet_aton(s, &ctx->sin.sin_addr);
+ if (result == 1) {
+ ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctx->fd >= 0) {
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_port = htons(162);
+ if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
+ sizeof(ctx->sin)) != 0) {
+ snmpv1_destroy(ctx);
+ return NULL;
+ }
+ }
+ }
+#endif
+
+ if (result != 1) {
+ free(str);
+ free(ctx);
+ return NULL;
+ }
+
+ ctx->ref = 1;
+
+ return ctx;
+}
+
+
+static void
+snmpv1_destroy(ctx)
+ void *ctx;
+{
+ snmpv1_opts_t *v1 = ctx;
+
+ v1->ref--;
+ if (v1->ref > 0)
+ return;
+
+ if (v1->community)
+ free(v1->community);
+ if (v1->fd >= 0)
+ close(v1->fd);
+ free(v1);
+}
+
+
+static int
+snmpv1_send(ctx, msg)
+ void *ctx;
+ ipmon_msg_t *msg;
+{
+ snmpv1_opts_t *v1 = ctx;
+
+ return sendtrap_v1_0(v1->fd, v1->community,
+ msg->imm_msg, msg->imm_msglen, msg->imm_when);
+}
+
+static char def_community[] = "public"; /* ublic */
+
+static int
+writelength(buffer, value)
+ u_char *buffer;
+ u_int value;
+{
+ u_int n = htonl(value);
+ int len;
+
+ if (value < 128) {
+ *buffer = value;
+ return 1;
+ }
+ if (value > 0xffffff)
+ len = 4;
+ else if (value > 0xffff)
+ len = 3;
+ else if (value > 0xff)
+ len = 2;
+ else
+ len = 1;
+
+ *buffer = 0x80 | len;
+
+ bcopy((u_char *)&n + 4 - len, buffer + 1, len);
+
+ return len + 1;
+}
+
+
+static int
+writeint(buffer, value)
+ u_char *buffer;
+ int value;
+{
+ u_char *s = buffer;
+ u_int n = value;
+
+ if (value == 0) {
+ *buffer = 0;
+ return 1;
+ }
+
+ if (n > 4194304) {
+ *s++ = 0x80 | (n / 4194304);
+ n -= 4194304 * (n / 4194304);
+ }
+ if (n > 32768) {
+ *s++ = 0x80 | (n / 32768);
+ n -= 32768 * (n / 327678);
+ }
+ if (n > 128) {
+ *s++ = 0x80 | (n / 128);
+ n -= (n / 128) * 128;
+ }
+ *s++ = (u_char)n;
+
+ return s - buffer;
+}
+
+
+
+/*
+ * First style of traps is:
+ * 1.3.6.1.4.1.9932.1.1
+ */
+static int
+maketrap_v1(community, buffer, bufsize, msg, msglen, ipaddr, when)
+ char *community;
+ u_char *buffer;
+ int bufsize;
+ u_char *msg;
+ int msglen;
+ u_32_t ipaddr;
+ time_t when;
+{
+ u_char *s = buffer, *t, *pdulen, *varlen;
+ int basesize = 73;
+ u_short len;
+ int trapmsglen;
+ int pdulensz;
+ int varlensz;
+ int baselensz;
+ int n;
+
+ if (community == NULL || *community == '\0')
+ community = def_community;
+ basesize += strlen(community) + msglen;
+
+ if (basesize + 8 > bufsize)
+ return 0;
+
+ memset(buffer, 0xff, bufsize);
+ *s++ = 0x30; /* Sequence */
+ if (basesize - 1 >= 128) {
+ baselensz = 2;
+ basesize++;
+ } else {
+ baselensz = 1;
+ }
+ s += baselensz;
+ *s++ = 0x02; /* Integer32 */
+ *s++ = 0x01; /* length 1 */
+ *s++ = 0x00; /* version 1 */
+ *s++ = 0x04; /* octet string */
+ *s++ = strlen(community); /* length of "public" */
+ bcopy(community, s, s[-1]);
+ s += s[-1];
+ *s++ = 0xA4; /* PDU(4) */
+ pdulen = s++;
+ if (basesize - (s - buffer) >= 128) {
+ pdulensz = 2;
+ basesize++;
+ s++;
+ } else {
+ pdulensz = 1;
+ }
+
+ /* enterprise */
+ bcopy(ipf_enterprise, s, sizeof(ipf_enterprise));
+ s += sizeof(ipf_enterprise);
+
+ /* Agent address */
+ *s++ = 0x40;
+ *s++ = 0x4;
+ bcopy(&ipaddr, s, 4);
+ s += 4;
+
+ /* Generic Trap code */
+ *s++ = 0x2;
+ n = writeint(s + 1, 6);
+ if (n == 0)
+ return 0;
+ *s = n;
+ s += n + 1;
+
+ /* Specific Trap code */
+ *s++ = 0x2;
+ n = writeint(s + 1, 0);
+ if (n == 0)
+ return 0;
+ *s = n;
+ s += n + 1;
+
+ /* Time stamp */
+ *s++ = 0x43; /* TimeTicks */
+ *s++ = 0x04; /* TimeTicks */
+ s[0] = when >> 24;
+ s[1] = when >> 16;
+ s[2] = when >> 8;
+ s[3] = when & 0xff;
+ s += 4;
+
+ /*
+ * The trap0 message is "ipfilter_version" followed by the message
+ */
+ *s++ = 0x30;
+ varlen = s;
+ if (basesize - (s - buffer) >= 128) {
+ varlensz = 2;
+ basesize++;
+ } else {
+ varlensz = 1;
+ }
+ s += varlensz;
+
+ *s++ = 0x30;
+ t = s + 1;
+ bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
+ t += sizeof(ipf_trap0_1);
+
+ *t++ = 0x2; /* Integer */
+ n = writeint(t + 1, IPFILTER_VERSION);
+ *t = n;
+ t += n + 1;
+
+ len = t - s - 1;
+ writelength(s, len);
+
+ s = t;
+ *s++ = 0x30;
+ if (basesize - (s - buffer) >= 128) {
+ trapmsglen = 2;
+ basesize++;
+ } else {
+ trapmsglen = 1;
+ }
+ t = s + trapmsglen;
+ bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
+ t += sizeof(ipf_trap0_2);
+
+ *t++ = 0x4; /* Octet string */
+ n = writelength(t, msglen);
+ t += n;
+ bcopy(msg, t, msglen);
+ t += msglen;
+
+ len = t - s - trapmsglen;
+ writelength(s, len);
+
+ len = t - varlen - varlensz;
+ writelength(varlen, len); /* pdu length */
+
+ len = t - pdulen - pdulensz;
+ writelength(pdulen, len); /* pdu length */
+
+ len = t - buffer - baselensz - 1;
+ writelength(buffer + 1, len); /* length of trap */
+
+ return t - buffer;
+}
+
+
+int
+sendtrap_v1_0(fd, community, msg, msglen, when)
+ int fd;
+ char *community, *msg;
+ int msglen;
+ time_t when;
+{
+
+ u_char buffer[1500];
+ int n;
+
+ n = maketrap_v1(community, buffer, sizeof(buffer),
+ (u_char *)msg, msglen, 0, when);
+ if (n > 0) {
+ return send(fd, buffer, n, 0);
+ }
+
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/save_v2trap.c b/contrib/ipfilter/lib/save_v2trap.c
new file mode 100644
index 0000000..78e76f6
--- /dev/null
+++ b/contrib/ipfilter/lib/save_v2trap.c
@@ -0,0 +1,459 @@
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include "ipmon.h"
+#include <ctype.h>
+
+static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 };
+/*
+ * Enterprise number OID:
+ * 1.3.6.1.4.1.9932
+ */
+static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 };
+static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 };
+
+static int writeint __P((u_char *, int));
+static int writelength __P((u_char *, u_int));
+static int maketrap_v2 __P((char *, u_char *, int, u_char *, int));
+static void snmpv2_destroy __P((void *));
+static void *snmpv2_dup __P((void *));
+static int snmpv2_match __P((void *, void *));
+static void *snmpv2_parse __P((char **));
+static void snmpv2_print __P((void *));
+static int snmpv2_send __P((void *, ipmon_msg_t *));
+
+
+int sendtrap_v2_0 __P((int, char *, char *, int));
+
+static char def_community[] = "public"; /* ublic */
+
+typedef struct snmpv2_opts_s {
+ char *community;
+ char *server;
+ int fd;
+ int v6;
+ int ref;
+#ifdef USE_INET6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr_in sin;
+} snmpv2_opts_t;
+
+ipmon_saver_t snmpv2saver = {
+ "snmpv2",
+ snmpv2_destroy,
+ snmpv2_dup, /* dup */
+ snmpv2_match, /* match */
+ snmpv2_parse,
+ snmpv2_print,
+ snmpv2_send
+};
+
+
+static int
+snmpv2_match(ctx1, ctx2)
+ void *ctx1, *ctx2;
+{
+ snmpv2_opts_t *s1 = ctx1, *s2 = ctx2;
+
+ if (s1->v6 != s2->v6)
+ return 1;
+
+ if (strcmp(s1->community, s2->community))
+ return 1;
+
+#ifdef USE_INET6
+ if (s1->v6 == 1) {
+ if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6)))
+ return 1;
+ } else
+#endif
+ {
+ if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin)))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void *
+snmpv2_dup(ctx)
+ void *ctx;
+{
+ snmpv2_opts_t *s = ctx;
+
+ s->ref++;
+ return s;
+}
+
+
+static void
+snmpv2_print(ctx)
+ void *ctx;
+{
+ snmpv2_opts_t *snmpv2 = ctx;
+
+ printf("%s ", snmpv2->community);
+#ifdef USE_INET6
+ if (snmpv2->v6 == 1) {
+ char buf[80];
+
+ printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf,
+ sizeof(snmpv2->sin6.sin6_addr)));
+ } else
+#endif
+ {
+ printf("%s", inet_ntoa(snmpv2->sin.sin_addr));
+ }
+}
+
+
+static void *
+snmpv2_parse(char **strings)
+{
+ snmpv2_opts_t *ctx;
+ int result;
+ char *str;
+ char *s;
+
+ if (strings[0] == NULL || strings[0][0] == '\0')
+ return NULL;
+ if (strchr(*strings, ' ') == NULL)
+ return NULL;
+
+ str = strdup(*strings);
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->fd = -1;
+
+ s = strchr(str, ' ');
+ *s++ = '\0';
+ ctx->community = str;
+
+ while (ISSPACE(*s))
+ s++;
+ if (!*s) {
+ free(str);
+ free(ctx);
+ return NULL;
+ }
+
+#ifdef USE_INET6
+ if (strchr(s, ':') == NULL) {
+ result = inet_pton(AF_INET, s, &ctx->sin.sin_addr);
+ if (result == 1) {
+ ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctx->fd >= 0) {
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_port = htons(162);
+ if (connect(ctx->fd,
+ (struct sockaddr *)&ctx->sin,
+ sizeof(ctx->sin)) != 0) {
+ snmpv2_destroy(ctx);
+ return NULL;
+ }
+ }
+ }
+ } else {
+ result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr);
+ if (result == 1) {
+ ctx->v6 = 1;
+ ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (ctx->fd >= 0) {
+ ctx->sin6.sin6_family = AF_INET6;
+ ctx->sin6.sin6_port = htons(162);
+ if (connect(ctx->fd,
+ (struct sockaddr *)&ctx->sin6,
+ sizeof(ctx->sin6)) != 0) {
+ snmpv2_destroy(ctx);
+ return NULL;
+ }
+ }
+ }
+ }
+#else
+ result = inet_aton(s, &ctx->sin.sin_addr);
+ if (result == 1) {
+ ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctx->fd >= 0) {
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_port = htons(162);
+ if (connect(ctx->fd, (struct sockaddr *)&ctx->sin,
+ sizeof(ctx->sin)) != 0) {
+ snmpv2_destroy(ctx);
+ return NULL;
+ }
+ }
+ }
+#endif
+
+ if (result != 1) {
+ free(str);
+ free(ctx);
+ return NULL;
+ }
+
+ ctx->ref = 1;
+
+ return ctx;
+}
+
+
+static void
+snmpv2_destroy(ctx)
+ void *ctx;
+{
+ snmpv2_opts_t *v2 = ctx;
+
+ v2->ref--;
+ if (v2->ref > 0)
+ return;
+
+ if (v2->community)
+ free(v2->community);
+ if (v2->fd >= 0)
+ close(v2->fd);
+ free(v2);
+}
+
+
+static int
+snmpv2_send(ctx, msg)
+ void *ctx;
+ ipmon_msg_t *msg;
+{
+ snmpv2_opts_t *v2 = ctx;
+
+ return sendtrap_v2_0(v2->fd, v2->community,
+ msg->imm_msg, msg->imm_msglen);
+}
+static int
+writelength(buffer, value)
+ u_char *buffer;
+ u_int value;
+{
+ u_int n = htonl(value);
+ int len;
+
+ if (value < 128) {
+ *buffer = value;
+ return 1;
+ }
+ if (value > 0xffffff)
+ len = 4;
+ else if (value > 0xffff)
+ len = 3;
+ else if (value > 0xff)
+ len = 2;
+ else
+ len = 1;
+
+ *buffer = 0x80 | len;
+
+ bcopy((u_char *)&n + 4 - len, buffer + 1, len);
+
+ return len + 1;
+}
+
+
+static int
+writeint(buffer, value)
+ u_char *buffer;
+ int value;
+{
+ u_char *s = buffer;
+ u_int n = value;
+
+ if (value == 0) {
+ *buffer = 0;
+ return 1;
+ }
+
+ if (n > 4194304) {
+ *s++ = 0x80 | (n / 4194304);
+ n -= 4194304 * (n / 4194304);
+ }
+ if (n > 32768) {
+ *s++ = 0x80 | (n / 32768);
+ n -= 32768 * (n / 327678);
+ }
+ if (n > 128) {
+ *s++ = 0x80 | (n / 128);
+ n -= (n / 128) * 128;
+ }
+ *s++ = (u_char)n;
+
+ return s - buffer;
+}
+
+
+
+/*
+ * First style of traps is:
+ * 1.3.6.1.4.1.9932.1.1
+ */
+static int
+maketrap_v2(community, buffer, bufsize, msg, msglen)
+ char *community;
+ u_char *buffer;
+ int bufsize;
+ u_char *msg;
+ int msglen;
+{
+ u_char *s = buffer, *t, *pdulen;
+ u_char *varlen;
+ int basesize = 77;
+ u_short len;
+ int trapmsglen;
+ int pdulensz;
+ int varlensz;
+ int baselensz;
+ int n;
+
+ if (community == NULL || *community == '\0')
+ community = def_community;
+ basesize += strlen(community) + msglen;
+
+ if (basesize + 8 > bufsize)
+ return 0;
+
+ memset(buffer, 0xff, bufsize);
+ *s++ = 0x30; /* Sequence */
+
+ if (basesize - 1 >= 128) {
+ baselensz = 2;
+ basesize++;
+ } else {
+ baselensz = 1;
+ }
+ s += baselensz;
+ *s++ = 0x02; /* Integer32 */
+ *s++ = 0x01; /* length 1 */
+ *s++ = 0x01; /* version 2 */
+ *s++ = 0x04; /* octet string */
+ *s++ = strlen(community); /* length of "public" */
+ bcopy(community, s, s[-1]);
+ s += s[-1];
+ *s++ = 0xA7; /* PDU(7) */
+ pdulen = s++;
+ if (basesize - (s - buffer) >= 128) {
+ pdulensz = 2;
+ basesize++;
+ s++;
+ } else {
+ pdulensz = 1;
+ }
+ /* request id */
+ *s++ = 0x2; /* integer */
+ *s++ = 0x4; /* len 4 */
+ *s++ = 0x0; /* noError */
+ *s++ = 0x0; /* noError */
+ *s++ = 0x0; /* noError */
+ *s++ = 0x0; /* noError */
+
+ /* error status */
+ *s++ = 0x2; /* integer */
+ *s++ = 0x1; /* len 1 */
+ *s++ = 0x0; /* noError */
+
+ /* error-index */
+ *s++ = 0x2; /* integer */
+ *s++ = 0x1; /* len 1 */
+ *s++ = 0x0; /* noError */
+
+ *s++ = 0x30; /* sequence */
+ varlen = s++;
+ if (basesize - (s - buffer) >= 128) {
+ varlensz = 2;
+ basesize++;
+ s++;
+ } else {
+ varlensz = 1;
+ }
+
+ *s++ = 0x30; /* sequence */
+ *s++ = sizeof(sysuptime) + 6;
+
+ bcopy(sysuptime, s, sizeof(sysuptime));
+ s += sizeof(sysuptime);
+
+ *s++ = 0x43; /* Timestamp */
+ *s++ = 0x04; /* TimeTicks */
+ *s++ = 0x0;
+ *s++ = 0x0;
+ *s++ = 0x0;
+ *s++ = 0x0;
+
+ *s++ = 0x30;
+ t = s + 1;
+ bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1));
+ t += sizeof(ipf_trap0_1);
+
+ *t++ = 0x2; /* Integer */
+ n = writeint(t + 1, IPFILTER_VERSION);
+ *t = n;
+ t += n + 1;
+
+ len = t - s - 1;
+ writelength(s, len);
+
+ s = t;
+ *s++ = 0x30;
+ if (msglen < 128) {
+ if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128)
+ trapmsglen = 2;
+ else
+ trapmsglen = 1;
+ } else {
+ if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128)
+ trapmsglen = 2;
+ else
+ trapmsglen = 1;
+ }
+ t = s + trapmsglen;
+ bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2));
+ t += sizeof(ipf_trap0_2);
+
+ *t++ = 0x4; /* Octet string */
+ n = writelength(t, msglen);
+ t += n;
+ bcopy(msg, t, msglen);
+ t += msglen;
+
+ len = t - s - trapmsglen;
+ writelength(s, len);
+
+ len = t - varlen - varlensz;
+ writelength(varlen, len); /* pdu length */
+
+ len = t - pdulen - pdulensz;
+ writelength(pdulen, len); /* pdu length */
+
+ len = t - buffer - baselensz - 1;
+ writelength(buffer + 1, len); /* length of trap */
+
+ return t - buffer;
+}
+
+
+int
+sendtrap_v2_0(fd, community, msg, msglen)
+ int fd;
+ char *community, *msg;
+ int msglen;
+{
+
+ u_char buffer[1500];
+ int n;
+
+ n = maketrap_v2(community, buffer, sizeof(buffer),
+ (u_char *)msg, msglen);
+ if (n > 0) {
+ return send(fd, buffer, n, 0);
+ }
+
+ return 0;
+}
diff --git a/contrib/ipfilter/lib/tcp_flags.c b/contrib/ipfilter/lib/tcp_flags.c
new file mode 100644
index 0000000..0b602e6
--- /dev/null
+++ b/contrib/ipfilter/lib/tcp_flags.c
@@ -0,0 +1,50 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2000-2004 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: tcp_flags.c,v 1.8.2.1 2006/06/16 17:21:17 darrenr Exp $
+ */
+
+#include "ipf.h"
+
+extern char flagset[];
+extern u_char flags[];
+
+
+u_char tcp_flags(flgs, mask, linenum)
+char *flgs;
+u_char *mask;
+int linenum;
+{
+ u_char tcpf = 0, tcpfm = 0;
+ char *s;
+
+ s = strchr(flgs, '/');
+ if (s)
+ *s++ = '\0';
+
+ if (*flgs == '0') {
+ tcpf = strtol(flgs, NULL, 0);
+ } else {
+ tcpf = tcpflags(flgs);
+ }
+
+ if (s != NULL) {
+ if (*s == '0')
+ tcpfm = strtol(s, NULL, 0);
+ else
+ tcpfm = tcpflags(s);
+ }
+
+ if (!tcpfm) {
+ if (tcpf == TH_SYN)
+ tcpfm = 0xff & ~(TH_ECN|TH_CWR);
+ else
+ tcpfm = 0xff & ~(TH_ECN);
+ }
+ *mask = tcpfm;
+ return tcpf;
+}
diff --git a/contrib/ipfilter/lib/tcpflags.c b/contrib/ipfilter/lib/tcpflags.c
new file mode 100644
index 0000000..feb3e8a
--- /dev/null
+++ b/contrib/ipfilter/lib/tcpflags.c
@@ -0,0 +1,45 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+/*
+ * ECN is a new addition to TCP - RFC 2481
+ */
+#ifndef TH_ECN
+# define TH_ECN 0x40
+#endif
+#ifndef TH_CWR
+# define TH_CWR 0x80
+#endif
+
+extern char flagset[];
+extern u_char flags[];
+
+
+u_char tcpflags(flgs)
+ char *flgs;
+{
+ u_char tcpf = 0;
+ char *s, *t;
+
+ for (s = flgs; *s; s++) {
+ if (*s == 'W')
+ tcpf |= TH_CWR;
+ else {
+ if (!(t = strchr(flagset, *s))) {
+ return 0;
+ }
+ tcpf |= flags[t - flagset];
+ }
+ }
+ return tcpf;
+}
diff --git a/contrib/ipfilter/lib/tcpoptnames.c b/contrib/ipfilter/lib/tcpoptnames.c
new file mode 100644
index 0000000..24e41bb
--- /dev/null
+++ b/contrib/ipfilter/lib/tcpoptnames.c
@@ -0,0 +1,22 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include "ipf.h"
+
+
+struct ipopt_names tcpoptnames[] ={
+ { TCPOPT_NOP, 0x000001, 1, "nop" },
+ { TCPOPT_MAXSEG, 0x000002, 4, "maxseg" },
+ { TCPOPT_WINDOW, 0x000004, 3, "wscale" },
+ { TCPOPT_SACK_PERMITTED, 0x000008, 2, "sackok" },
+ { TCPOPT_SACK, 0x000010, 3, "sack" },
+ { TCPOPT_TIMESTAMP, 0x000020, 10, "tstamp" },
+ { 0, 0, 0, (char *)NULL } /* must be last */
+};
diff --git a/contrib/ipfilter/lib/v6ionames.c b/contrib/ipfilter/lib/v6ionames.c
new file mode 100644
index 0000000..9f1207f
--- /dev/null
+++ b/contrib/ipfilter/lib/v6ionames.c
@@ -0,0 +1,28 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+#ifdef USE_INET6
+
+struct ipopt_names v6ionames[] ={
+ { IPPROTO_HOPOPTS, 0x000001, 0, "hopopts" },
+ { IPPROTO_IPV6, 0x000002, 0, "ipv6" },
+ { IPPROTO_ROUTING, 0x000004, 0, "routing" },
+ { IPPROTO_FRAGMENT, 0x000008, 0, "frag" },
+ { IPPROTO_ESP, 0x000010, 0, "esp" },
+ { IPPROTO_AH, 0x000020, 0, "ah" },
+ { IPPROTO_NONE, 0x000040, 0, "none" },
+ { IPPROTO_DSTOPTS, 0x000080, 0, "dstopts" },
+ { IPPROTO_MOBILITY, 0x000100, 0, "mobility" },
+ { 0, 0, 0, (char *)NULL }
+};
+
+#endif
diff --git a/contrib/ipfilter/lib/v6optvalue.c b/contrib/ipfilter/lib/v6optvalue.c
new file mode 100644
index 0000000..a6eff92
--- /dev/null
+++ b/contrib/ipfilter/lib/v6optvalue.c
@@ -0,0 +1,39 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+#include "ipf.h"
+
+
+
+u_32_t getv6optbyname(optname)
+ char *optname;
+{
+#ifdef USE_INET6
+ struct ipopt_names *io;
+
+ for (io = v6ionames; io->on_name; io++)
+ if (!strcasecmp(optname, io->on_name))
+ return io->on_bit;
+#endif
+ return -1;
+}
+
+
+u_32_t getv6optbyvalue(optval)
+ int optval;
+{
+#ifdef USE_INET6
+ struct ipopt_names *io;
+
+ for (io = v6ionames; io->on_name; io++)
+ if (io->on_value == optval)
+ return io->on_bit;
+#endif
+ return -1;
+}
diff --git a/contrib/ipfilter/lib/var.c b/contrib/ipfilter/lib/var.c
new file mode 100644
index 0000000..e61c8d1
--- /dev/null
+++ b/contrib/ipfilter/lib/var.c
@@ -0,0 +1,179 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#include <ctype.h>
+
+#include "ipf.h"
+
+typedef struct variable {
+ struct variable *v_next;
+ char *v_name;
+ char *v_value;
+} variable_t;
+
+static variable_t *vtop = NULL;
+
+static variable_t *find_var __P((char *));
+static char *expand_string __P((char *, int));
+
+
+static variable_t *find_var(name)
+ char *name;
+{
+ variable_t *v;
+
+ for (v = vtop; v != NULL; v = v->v_next)
+ if (!strcmp(name, v->v_name))
+ return v;
+ return NULL;
+}
+
+
+char *get_variable(string, after, line)
+ char *string, **after;
+ int line;
+{
+ char c, *s, *t, *value;
+ variable_t *v;
+
+ s = string;
+
+ if (*s == '{') {
+ s++;
+ for (t = s; *t != '\0'; t++)
+ if (*t == '}')
+ break;
+ if (*t == '\0') {
+ fprintf(stderr, "%d: { without }\n", line);
+ return NULL;
+ }
+ } else if (ISALPHA(*s)) {
+ for (t = s + 1; *t != '\0'; t++)
+ if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_'))
+ break;
+ } else {
+ fprintf(stderr, "%d: variables cannot start with '%c'\n",
+ line, *s);
+ return NULL;
+ }
+
+ if (after != NULL)
+ *after = t;
+ c = *t;
+ *t = '\0';
+ v = find_var(s);
+ *t = c;
+ if (v == NULL) {
+ fprintf(stderr, "%d: unknown variable '%s'\n", line, s);
+ return NULL;
+ }
+
+ s = strdup(v->v_value);
+ value = expand_string(s, line);
+ if (value != s)
+ free(s);
+ return value;
+}
+
+
+static char *expand_string(oldstring, line)
+ char *oldstring;
+ int line;
+{
+ char c, *s, *p1, *p2, *p3, *newstring, *value;
+ int len;
+
+ p3 = NULL;
+ newstring = oldstring;
+
+ for (s = oldstring; *s != '\0'; s++)
+ if (*s == '$') {
+ *s = '\0';
+ s++;
+
+ switch (*s)
+ {
+ case '$' :
+ bcopy(s, s - 1, strlen(s));
+ break;
+ default :
+ c = *s;
+ if (c == '\0')
+ return newstring;
+
+ value = get_variable(s, &p3, line);
+ if (value == NULL)
+ return NULL;
+
+ p2 = expand_string(value, line);
+ if (p2 == NULL)
+ return NULL;
+
+ len = strlen(newstring) + strlen(p2);
+ if (p3 != NULL) {
+ if (c == '{' && *p3 == '}')
+ p3++;
+ len += strlen(p3);
+ }
+ p1 = malloc(len + 1);
+ if (p1 == NULL)
+ return NULL;
+
+ *(s - 1) = '\0';
+ strcpy(p1, newstring);
+ strcat(p1, p2);
+ if (p3 != NULL)
+ strcat(p1, p3);
+
+ s = p1 + len - strlen(p3) - 1;
+ if (newstring != oldstring)
+ free(newstring);
+ newstring = p1;
+ break;
+ }
+ }
+ return newstring;
+}
+
+
+void set_variable(name, value)
+ char *name;
+ char *value;
+{
+ variable_t *v;
+ int len;
+
+ if (name == NULL || value == NULL || *name == '\0')
+ return;
+
+ v = find_var(name);
+ if (v != NULL) {
+ free(v->v_value);
+ v->v_value = strdup(value);
+ return;
+ }
+
+ len = strlen(value);
+
+ if ((*value == '"' && value[len - 1] == '"') ||
+ (*value == '\'' && value[len - 1] == '\'')) {
+ value[len - 1] = '\0';
+ value++;
+ len -=2;
+ }
+
+ v = (variable_t *)malloc(sizeof(*v));
+ if (v == NULL)
+ return;
+ v->v_name = strdup(name);
+ v->v_value = strdup(value);
+ v->v_next = vtop;
+ vtop = v;
+}
diff --git a/contrib/ipfilter/lib/verbose.c b/contrib/ipfilter/lib/verbose.c
new file mode 100644
index 0000000..710daab
--- /dev/null
+++ b/contrib/ipfilter/lib/verbose.c
@@ -0,0 +1,55 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#if defined(__STDC__)
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+#include <stdio.h>
+
+#include "ipf.h"
+#include "opts.h"
+
+
+#if defined(__STDC__)
+void verbose(int level, char *fmt, ...)
+#else
+void verbose(level, fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list pvar;
+
+ va_start(pvar, fmt);
+
+ if (opts & OPT_VERBOSE)
+ vprintf(fmt, pvar);
+ va_end(pvar);
+}
+
+
+#if defined(__STDC__)
+void ipfkverbose(char *fmt, ...)
+#else
+void ipfkverbose(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list pvar;
+
+ va_start(pvar, fmt);
+
+ if (opts & OPT_VERBOSE)
+ verbose(0x1fffffff, fmt, pvar);
+ va_end(pvar);
+}
diff --git a/contrib/ipfilter/lib/vtof.c b/contrib/ipfilter/lib/vtof.c
new file mode 100644
index 0000000..fd1a984
--- /dev/null
+++ b/contrib/ipfilter/lib/vtof.c
@@ -0,0 +1,16 @@
+#include "ipf.h"
+
+int
+vtof(version)
+ int version;
+{
+#ifdef USE_INET6
+ if (version == 6)
+ return AF_INET6;
+#endif
+ if (version == 4)
+ return AF_INET;
+ if (version == 0)
+ return AF_UNSPEC;
+ return -1;
+}
diff --git a/contrib/ipfilter/man/Makefile b/contrib/ipfilter/man/Makefile
new file mode 100644
index 0000000..04e97fb
--- /dev/null
+++ b/contrib/ipfilter/man/Makefile
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2012 by Darren Reed.
+#
+# See the IPFILTER.LICENCE file for details on licencing.
+#
+# $FreeBSD$
+#
+
+all:
+
+install:
+ $(INSTALL) -m 0644 -c -o root -g bin mkfilters.1 $(MANDIR)/man1
+ $(INSTALL) -m 0644 -c -o root -g bin ipftest.1 $(MANDIR)/man1
+ $(INSTALL) -m 0644 -c -o root -g bin ipnat.8 $(MANDIR)/man8
+ $(INSTALL) -m 0644 -c -o root -g bin ipf.4 $(MANDIR)/man4
+ $(INSTALL) -m 0644 -c -o root -g bin ipfilter.4 $(MANDIR)/man4
+ $(INSTALL) -m 0644 -c -o root -g bin ipl.4 $(MANDIR)/man4
+ $(INSTALL) -m 0644 -c -o root -g bin ipnat.4 $(MANDIR)/man4
+ $(INSTALL) -m 0644 -c -o root -g bin ipf.5 $(MANDIR)/man5
+ $(INSTALL) -m 0644 -c -o root -g bin ipfilter.5 $(MANDIR)/man5
+ $(INSTALL) -m 0644 -c -o root -g bin ipnat.5 $(MANDIR)/man5
+ $(INSTALL) -m 0644 -c -o root -g bin ipf.8 $(MANDIR)/man8
+ $(INSTALL) -m 0644 -c -o root -g bin ipfs.8 $(MANDIR)/man8
+ $(INSTALL) -m 0644 -c -o root -g bin ipmon.8 $(MANDIR)/man8
+ $(INSTALL) -m 0644 -c -o root -g bin ipmon.5 $(MANDIR)/man5
+ $(INSTALL) -m 0644 -c -o root -g bin ippool.8 $(MANDIR)/man8
+ $(INSTALL) -m 0644 -c -o root -g bin ippool.5 $(MANDIR)/man5
+ $(INSTALL) -m 0644 -c -o root -g bin ipscan.8 $(MANDIR)/man8
+ $(INSTALL) -m 0644 -c -o root -g bin ipscan.5 $(MANDIR)/man5
+ $(INSTALL) -m 0644 -c -o root -g bin ipfstat.8 $(MANDIR)/man8
+ @echo "Remember to rebuild the whatis database."
diff --git a/contrib/ipfilter/man/ipf.4 b/contrib/ipfilter/man/ipf.4
new file mode 100644
index 0000000..aaa050d
--- /dev/null
+++ b/contrib/ipfilter/man/ipf.4
@@ -0,0 +1,254 @@
+.\" $FreeBSD$
+.TH IPF 4
+.SH NAME
+ipf \- packet filtering kernel interface
+.SH SYNOPSIS
+#include <netinet/ip_compat.h>
+.br
+#include <netinet/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 SIOCADDFR)
+ ioctl(fd, SIOCRMAFR, struct frentry **) (same as SIOCDELFR)
+ ioctl(fd, SIOCADIFR, struct frentry **)
+ ioctl(fd, SIOCRMIFR, struct frentry **)
+ ioctl(fd, SIOCINAFR, struct frentry **)
+ ioctl(fd, SIOCINIFR, struct frentry **)
+ ioctl(fd, SIOCSETFF, u_int *)
+ ioctl(fd, SIOGGETFF, u_int *)
+ ioctl(fd, SIOCGETFS, struct friostat **)
+ ioctl(fd, SIOCIPFFL, int *)
+ ioctl(fd, SIOCIPFFB, int *)
+ ioctl(fd, SIOCSWAPA, u_int *)
+ ioctl(fd, SIOCFRENB, u_int *)
+ ioctl(fd, SIOCFRSYN, u_int *)
+ ioctl(fd, SIOCFRZST, struct friostat **)
+ ioctl(fd, SIOCZRLST, struct frentry **)
+ ioctl(fd, SIOCAUTHW, struct fr_info **)
+ ioctl(fd, SIOCAUTHR, struct fr_info **)
+ ioctl(fd, SIOCATHST, struct fr_authstat **)
+.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).
+.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;
+ u_short fr_group; /* group to which this rule belongs */
+ u_short fr_grhead; /* group # which this rule starts */
+ struct frentry *fr_grp;
+ int fr_ref; /* reference count - for grouping */
+ void *fr_ifa;
+#if BSD >= 199306
+ void *fr_oifa;
+#endif
+ /*
+ * These are only incremented when a packet matches this rule and
+ * it is the last match
+ */
+ U_QUAD_T fr_hits;
+ U_QUAD_T fr_bytes;
+ /*
+ * Fields after this may not change whilst in the kernel.
+ */
+ 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_32_t fr_flags; /* per-rule flags && options (see below) */
+ u_short fr_skip; /* # of rules to skip */
+ u_short fr_loglevel; /* syslog log facility + priority */
+ int (*fr_func) __P((int, ip_t *, fr_info_t *));
+ char fr_icode; /* return ICMP code */
+ char fr_ifname[IFNAMSIZ];
+#if BSD > 199306
+ char fr_oifname[IFNAMSIZ];
+#endif
+ struct frdest fr_tif; /* "to" interface */
+ struct frdest fr_dif; /* duplicate packet interfaces */
+} 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).
+.PP
+Flags which are recognised in fr_flags:
+.nf
+
+ FR_BLOCK 0x000001 /* do not allow packet to pass */
+ FR_PASS 0x000002 /* allow packet to pass */
+ FR_OUTQUE 0x000004 /* outgoing packets */
+ FR_INQUE 0x000008 /* ingoing packets */
+ FR_LOG 0x000010 /* Log */
+ FR_LOGB 0x000011 /* Log-fail */
+ FR_LOGP 0x000012 /* Log-pass */
+ FR_LOGBODY 0x000020 /* log the body of packets too */
+ FR_LOGFIRST 0x000040 /* log only the first packet to match */
+ FR_RETRST 0x000080 /* return a TCP RST packet if blocked */
+ FR_RETICMP 0x000100 /* return an ICMP packet if blocked */
+ FR_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */
+ FR_NOMATCH 0x000200 /* no match occured */
+ FR_ACCOUNT 0x000400 /* count packet bytes */
+ FR_KEEPFRAG 0x000800 /* keep fragment information */
+ FR_KEEPSTATE 0x001000 /* keep `connection' state information */
+ FR_INACTIVE 0x002000
+ FR_QUICK 0x004000 /* match & stop processing list */
+ FR_FASTROUTE 0x008000 /* bypass normal routing */
+ FR_CALLNOW 0x010000 /* call another function (fr_func) if matches */
+ FR_DUP 0x020000 /* duplicate the packet */
+ FR_LOGORBLOCK 0x040000 /* block the packet if it can't be logged */
+ FR_NOTSRCIP 0x080000 /* not the src IP# */
+ FR_NOTDSTIP 0x100000 /* not the dst IP# */
+ FR_AUTH 0x200000 /* use authentication */
+ FR_PREAUTH 0x400000 /* require preauthentication */
+
+.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). This ioctl is also implemented for
+\fB/dev/ipstate\fP and will flush all state tables entries if passed 0
+or just all those which are not established if passed 1.
+
+.IP "\fBGeneral Logging Flags\fP" 0
+There are two flags which can be set to log packets independently 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 0x10000000
+ FF_LOGBLOCK 0x20000000
+ FF_LOGNOMATCH 0x40000000
+ FF_BLOCKNONIP 0x80000000 /* Solaris 2.x only */
+.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.
+.IP "\fBFilter statistics\fP" 0
+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[2];
+ struct frentry *f_fout[2];
+ struct frentry *f_acctin[2];
+ struct frentry *f_acctout[2];
+ struct frentry *f_auth;
+ u_long f_froute[2];
+ int f_active; /* 1 or 0 - active rule set */
+ int f_defpass; /* default pass - from fr_pass */
+ int f_running; /* 1 if running, else 0 */
+ int f_logging; /* 1 if enabled, else 0 */
+ char f_version[32]; /* version string */
+};
+
+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_notdata; /* PROTO/PCPROTO that have no data */
+ u_long fr_nodata; /* mblks that have no data */
+ u_long fr_bad; /* bad IP packets to the filter */
+ u_long fr_notip; /* packets passed through no on ip queue */
+ u_long fr_drop; /* packets dropped - no info for them! */
+#endif
+};
+.fi
+If we wanted to retrieve all the statistics and reset the counters back to
+0, then the ioctl() call would be made to SIOCFRZST rather than SIOCGETFS.
+In addition to the statistics above, each rule keeps a hit count, counting
+both number of packets and bytes. To reset these counters for a rule,
+load the various rule information into a frentry structure and call
+SIOCZRLST.
+.IP "Swapping Active lists" 0
+IP Filter supports two lists of rules for filtering and accounting: an
+active list and an inactive list. This allows for large scale rule base
+changes to be put in place atomically with otherwise minimal interruption.
+Which of the two is active can be changed using the SIOCSWAPA ioctl. It
+is important to note that no passed argument is recognised and that the
+value returned is that of the list which is now inactive.
+.br
+.SH FILES
+/dev/ipauth
+.br
+/dev/ipl
+.br
+/dev/ipnat
+.br
+/dev/ipstate
+.SH SEE ALSO
+ipl(4), ipnat(4), ipf(5), ipf(8), ipfstat(8)
diff --git a/contrib/ipfilter/man/ipf.5 b/contrib/ipfilter/man/ipf.5
new file mode 100644
index 0000000..3e5e9b2
--- /dev/null
+++ b/contrib/ipfilter/man/ipf.5
@@ -0,0 +1,1698 @@
+.\" $FreeBSD$
+.TH IPF 5
+.SH NAME
+ipf, ipf.conf \- IPFilter firewall rules file format
+.SH DESCRIPTION
+.PP
+The ipf.conf file is used to specify rules for the firewall, packet
+authentication and packet accounting components of IPFilter. To load rules
+specified in the ipf.conf file, the ipf(8) program is used.
+.PP
+For use as a firewall, there are two important rule types: those that block
+and drop packets (block rules) and those that allow packets through (pass
+rules.) Accompanying the decision to apply is a collection of statements
+that specify under what conditions the result is to be applied and how.
+.PP
+The simplest rules that can be used in ipf.conf are expressed like this:
+.PP
+.nf
+block in all
+pass out all
+.fi
+.PP
+Each rule must contain at least the following three components
+.RS
+.IP *
+a decision keyword (pass, block, etc.)
+.IP *
+the direction of the packet (in or out)
+.IP *
+address patterns or "all" to match any address information
+.RE
+.SS Long lines
+.PP
+For rules lines that are particularly long, it is possible to split
+them over multiple lines implicity like this:
+.PP
+.nf
+pass in on bgeo proto tcp from 1.1.1.1 port > 1000
+ to 2.2.2.2 port < 5000 flags S keep state
+.fi
+.PP
+or explicitly using the backslash ('\\') character:
+.PP
+.nf
+pass in on bgeo proto tcp from 1.1.1.1 port > 1000 \\
+ to 2.2.2.2 port < 5000 flags S keep state
+.fi
+.SS Comments
+.PP
+Comments in the ipf.conf file are indicated by the use of the '#' character.
+This can either be at the start of the line, like this:
+.PP
+.nf
+# Allow all ICMP packets in
+pass in proto icmp from any to any
+.fi
+.PP
+Or at the end of a like, like this:
+.PP
+.nf
+pass in proto icmp from any to any # Allow all ICMP packets in
+.fi
+.SH Firewall rules
+.PP
+This section goes into detail on how to construct firewall rules that
+are placed in the ipf.conf file.
+.PP
+It is beyond the scope of this document to describe what makes a good
+firewall rule set or which packets should be blocked or allowed in.
+Some suggestions will be provided but further reading is expected to
+fully understand what is safe and unsafe to allow in/out.
+.SS Filter rule keywords
+.PP
+The first word found in any filter rule describes what the eventual outcome
+of a packet that matches it will be. Descriptions of the many and various
+sections that can be used to match on the contents of packet headers will
+follow on below.
+.PP
+The complete list of keywords, along with what they do is as follows:
+.RS
+.HP
+pass
+rules that match a packet indicate to ipfilter that it should be
+allowed to continue on in the direction it is flowing.
+.HP
+block
+rules are used when it is desirable to prevent a packet from going
+any further. Packets that are blocked on the "in" side are never seen by
+TCP/IP and those that are blocked going "out" are never seen on the wire.
+.HP
+log
+when IPFilter successfully matches a packet against a log rule a log
+record is generated and made available for ipmon(8) to read. These rules
+have no impact on whether or not a packet is allowed through or not.
+So if a packet first matched a block rule and then matched a log rule,
+the status of the packet after the log rule is that it will still be
+blocked.
+.HP
+count
+rules provide the administrator with the ability to count packets and
+bytes that match the criteria laid out in the configuration file.
+The count rules are applied after NAT and filter rules on the inbound
+path. For outbound packets, count rules are applied before NAT and
+before the packet is dropped. Thus the count rule cannot be used as
+a true indicator of link layer
+.HP
+auth
+rules cause the matching packet to be queued up for processing by a
+user space program. The user space program is responsible for making
+an ioctl system call to collect the information about the queued
+packet and another ioctl system call to return the verdict (block,
+pass, etc) on what to do with the packet. In the event that the queue
+becomes full, the packets will end up being dropped.
+.HP
+call
+provides access to functions built into IPFilter that allow for more
+complex actions to be taken as part of the decision making that goes
+with the rule.
+.HP
+decapsulate
+rules instruct ipfilter to remove any
+other headers (IP, UDP, AH) and then process what is inside as a new packet.
+For non-UDP packets, there are builtin checks that are applied in addition
+to whatever is specified in the rule, to only allow decapsulation of
+recognised protocols. After decapsulating the inner packet, any filtering
+result that is applied to the inner packet is also applied to the other
+packet.
+.PP
+The default way in which filter rules are applied is for the last
+matching rule to be used as the decision maker. So even if the first
+rule to match a packet is a pass, if there is a later matching rule
+that is a block and no further rules match the packet, then it will
+be blocked.
+.SS Matching Network Interfaces
+.PP
+On systems with more than one network interface, it is necessary
+to be able to specify different filter rules for each of them.
+In the first instance, this is because different networks will send us
+packets via each network interface but it is also because of the hosts,
+the role and the resulting security policy that we need to be able to
+distinguish which network interface a packet is on.
+.PP
+To accomodate systems where the presence of a network interface is
+dynamic, it is not necessary for the network interface named in a
+filter rule to be present in the system when the rule is loaded.
+This can lead to silent errors being introduced and unexpected
+behaviour with the simplest of keyboard mistakes - for example,
+typing in hem0 instead of hme0 or hme2 instead of hme3.
+.PP
+On Solaris systems prior to Solaris 10 Update 4, it is not possible
+to filter packets on the loopback interface (lo0) so filter rules
+that specify it will have no impact on the corresponding flow of
+packets. See below for Solaris specific tips on how to enable this.
+.PP
+Some examples of including the network interface in filter rules are:
+.PP
+.nf
+block in on bge0 all
+pass out on bge0 all
+.fi
+.SS Address matching (basic)
+.PP
+The first and most basic part of matching for filtering rules is to
+specify IP addresses and TCP/UDP port numbers. The source address
+information is matched by the "from" information in a filter rule
+and the destination address information is matched with the "to"
+information in a filter rule.
+.PP
+The typical format used for IP addresses is CIDR notation, where an
+IP address (or network) is followed by a '/' and a number representing
+the size of the netmask in bits. This notation is used for specifying
+address matching in both IPv4 and IPv6. If the '/' and bitmask size
+are excluded from the matching string, it is assumed that the address
+specified is a host address and that the netmask applied should be
+all 1's.
+.PP
+Some examples of this are:
+.PP
+.nf
+pass in from 10.1.0.0/24 to any
+block out from any to 10.1.1.1
+.fi
+.PP
+It is not possible to specify a range of addresses that does not
+have a boundary that can be defined by a standard subnet mask.
+.IP
+.B Names instead of addresses
+.RS
+.PP
+Hostnames, resolved either via DNS or /etc/hosts, or network names,
+resolved via /etc/networks, may be used in place of actual addresses
+in the filter rules. WARNING: if a hostname expands to more than one
+address, only the *first* is used in building the filter rule.
+.PP
+Caution should be exercised when relying on DNS for filter rules in
+case the sending and receiving of DNS packets is blocked when ipf(8)
+is processing that part of the configuration file, leading to long
+delays, if not errors, in loading the filter rules.
+.RE
+.SS Protocol Matching
+.PP
+To match packets based on TCP/UDP port information, it is first necessary
+to indicate which protocol the packet must be. This is done using the
+"proto" keyword, followed by either the protocol number or a name which
+is mapped to the protocol number, usually through the /etc/protocols file.
+.PP
+.nf
+pass in proto tcp from 10.1.0.0/24 to any
+block out proto udp from any to 10.1.1.1
+pass in proto icmp from any to 192.168.0.0/16
+.fi
+.SS Sending back error packets
+.PP
+When a packet is just discarded using a block rule, there is no feedback given
+to the host that sent the packet. This is both good and bad. If this is the
+desired behaviour and it is not desirable to send any feedback about packets
+that are to be denied. The catch is that often a host trying to connect to a
+TCP port or with a UDP based application will send more than one packet
+because it assumes that just one packet may be discarded so a retry is
+required. The end result being logs can become cluttered with duplicate
+entries due to the retries.
+.PP
+To address this problem, a block rule can be qualified in two ways.
+The first of these is specific to TCP and instructs IPFilter to send back
+a reset (RST) packet. This packet indicates to the remote system that the
+packet it sent has been rejected and that it shouldn't make any further
+attempts to send packets to that port. Telling IPFilter to return a TCP
+RST packet in response to something that has been received is achieved
+with the return-rst keyword like this:
+.PP
+.nf
+block return-rst in proto tcp from 10.0.0.0/8 to any
+.fi
+.PP
+When sending back a TCP RST packet, IPFilter must construct a new packet
+that has the source address of the intended target, not the source address
+of the system it is running on (if they are different.)
+.PP
+For all of the other protocols handled by the IP protocol suite, to send
+back an error indicating that the received packet was dropped requires
+sending back an ICMP error packet. Whilst these can also be used for TCP,
+the sending host may not treat the received ICMP error as a hard error
+in the same way as it does the TCP RST packet. To return an ICMP error
+it is necessary to place return-icmp after the block keyword like this:
+.PP
+.nf
+block return-icmp in proto udp from any to 192.168.0.1/24
+.fi
+.PP
+When electing to return an ICMP error packet, it is also possible to
+select what type of ICMP error is returned. Whilst the full compliment
+of ICMP unreachable codes can be used by specifying a number instead of
+the string below, only the following should be used in conjunction with
+return-icmp. Which return code to use is a choice to be made when
+weighing up the pro's and con's. Using some of the codes may make it
+more obvious that a firewall is being used rather than just the host
+not responding.
+.RS
+.HP
+filter-prohib
+(prohibited by filter)
+sending packets to the destination given in the received packet is
+prohibited due to the application of a packet filter
+.HP
+net-prohib
+(prohibited network)
+sending packets to the destination given in the received packet is
+administratively prohibited.
+.HP
+host-unk
+(host unknown)
+the destination host address is not known by the system receiving
+the packet and therefore cannot be reached.
+.HP
+host-unr
+(host unreachable)
+it is not possible to reach the host as given by the destination address
+in the packet header.
+.HP
+net-unk
+(network unknown)
+the destination network address is not known by the system receiving
+the packet and therefore cannot be reached.
+.HP
+net-unr
+(network unreachable)
+it is not possible to forward the packet on to its final destination
+as given by the destination address
+.HP
+port-unr
+(port unreachable)
+there is no application using the given destination port and therefore
+it is not possible to reach that port.
+.HP
+proto-unr
+(protocol unreachable)
+the IP protocol specified in the packet is not available to receive
+packets.
+.DE
+.PP
+An example that shows how to send back a port unreachable packet for
+UDP packets to 192.168.1.0/24 is as follows:
+.PP
+.nf
+block return-icmp(port-unr) in proto udp from any to 192.168.1.0/24
+.fi
+.PP
+In the above examples, when sending the ICMP packet, IPFilter will construct
+a new ICMP packet with a source address of the network interface used to
+send the packet back to the original source. This can give away that there
+is an intermediate system blocking packets. To have IPFilter send back
+ICMP packets where the source address is the original destination, regardless
+of whether or not it is on the local host, return-icmp-as-dest is used like
+this:
+.PP
+.nf
+block return-icmp-as-dest(port-unr) in proto udp \\
+ from any to 192.168.1.0/24
+.fi
+.SS TCP/UDP Port Matching
+.PP
+Having specified which protocol is being matched, it is then possible to
+indicate which port numbers a packet must have in order to match the rule.
+Due to port numbers being used differently to addresses, it is therefore
+possible to match on them in different ways. IPFilter allows you to use
+the following logical operations:
+.IP "< x"
+is true if the port number is greater than or equal to x and less than or
+equal to y
+is true if the port number in the packet is less than x
+.IP "<= x"
+is true if the port number in the packet is less than or equal to x
+.IP "> x"
+is true if the port number in the packet is greater than x
+.IP ">= x"
+is true if the port number in the packet is greater or equal to x
+.IP "= x"
+is true if the port number in the packet is equal to x
+.IP "!= x"
+is true if the port number in the packet is not equal to x
+.PP
+Additionally, there are a number of ways to specify a range of ports:
+.IP "x <> y"
+is true if the port number is less than a and greater than y
+.IP "x >< y"
+is true if the port number is greater than x and less than y
+.IP "x:y"
+is true if the port number is greater than or equal to x and less than or
+equal to y
+.PP
+Some examples of this are:
+.PP
+.nf
+block in proto tcp from any port >= 1024 to any port < 1024
+pass in proto tcp from 10.1.0.0/24 to any port = 22
+block out proto udp from any to 10.1.1.1 port = 135
+pass in proto udp from 1.1.1.1 port = 123 to 10.1.1.1 port = 123
+pass in proto tcp from 127.0.0.0/8 to any port = 6000:6009
+.fi
+.PP
+If there is no desire to mention any specific source or destintion
+information in a filter rule then the word "all" can be used to
+indicate that all addresses are considered to match the rule.
+.SS IPv4 or IPv6
+.PP
+If a filter rule is constructed without any addresses then IPFilter
+will attempt to match both IPv4 and IPv6 packets with it. In the
+next list of rules, each one can be applied to either network protocol
+because there is no address specified from which IPFilter can derive
+with network protocol to expect.
+.PP
+.nf
+pass in proto udp from any to any port = 53
+block in proto tcp from any port < 1024 to any
+.fi
+.PP
+To explicitly match a particular network address family with a specific
+rule, the family must be added to the rule. For IPv4 it is necessary to
+add family inet and for IPv6, family inet6. Thus the next rule will
+block all packets (both IPv4 and IPv6:
+.PP
+.nf
+block in all
+.fi
+.PP
+but in the following example, we block all IPv4 packets and only allow
+in IPv6 packets:
+.PP
+.nf
+block in family inet all
+pass in family inet6 all
+.fi
+.PP
+To continue on from the example where we allowed either IPv4 or IPv6
+packets to port 53 in, to change that such that only IPv6 packets to
+port 53 need to allowed blocked then it is possible to add in a
+protocol family qualifier:
+.PP
+.nf
+pass in family inet6 proto udp from any to any port = 53
+.fi
+.SS First match vs last match
+.PP
+To change the default behaviour from being the last matched rule decides
+the outcome to being the first matched rule, the word "quick" is inserted
+to the rule.
+.SH Extended Packet Matching
+.SS Beyond using plain addresses
+.PP
+On firewalls that are working with large numbers of hosts and networks
+or simply trying to filter discretely against various hosts, it can
+be an easier administration task to define a pool of addresses and have
+a filter rule reference that address pool rather than have a rule for
+each address.
+.PP
+In addition to being able to use address pools, it is possible to use
+the interface name(s) in the from/to address fields of a rule. If the
+name being used in the address section can be matched to any of the
+interface names mentioned in the rule's "on" or "via" fields then it
+can be used with one of the following keywords for extended effect:
+.HP
+broadcast
+use the primary broadcast address of the network interface for matching
+packets with this filter rule;
+.IP
+.nf
+pass in on fxp0 proto udp from any to fxp0/broadcast port = 123
+.fi
+.HP
+peer
+use the peer address on point to point network interfaces for matching
+packets with this filter rule. This option typically only has meaningful
+use with link protocols such as SLIP and PPP.
+For example, this rule allows ICMP packets from the remote peer of ppp0
+to be received if they're destined for the address assigned to the link
+at the firewall end.
+.IP
+.nf
+pass in on ppp0 proto icmp from ppp0/peer to ppp0/32
+.fi
+.HP
+netmasked
+use the primary network address, with its netmask, of the network interface
+for matching packets with this filter rule. If a network interface had an
+IP address of 192.168.1.1 and its netmask was 255.255.255.0 (/24), then
+using the word "netmasked" after the interface name would match any
+addresses that would match 192.168.1.0/24. If we assume that bge0 has
+this IP address and netmask then the following two rules both serve
+to produce the same effect:
+.IP
+.nf
+pass in on bge0 proto icmp from any to 192.168.1.0/24
+pass in on bge0 proto icmp from any to bge0/netmasked
+.fi
+.HP
+network
+using the primary network address, and its netmask, of the network interface,
+construct an address for exact matching. If a network interface has an
+address of 192.168.1.1 and its netmask is 255.255.255.0, using this
+option would only match packets to 192.168.1.0.
+.IP
+.nf
+pass in on bge0 proto icmp from any to bge0/network
+.fi
+.PP
+Another way to use the name of a network interface to get the address
+is to wrap the name in ()'s. In the above method, IPFilter
+looks at the interface names in use and to decide whether or not
+the name given is a hostname or network interface name. With the
+use of ()'s, it is possible to tell IPFilter that the name should
+be treated as a network interface name even though it doesn't
+appear in the list of network interface that the rule ias associated
+with.
+.IP
+.nf
+pass in proto icmp from any to (bge0)/32
+.fi
+.SS Using address pools
+.PP
+Rather than list out multiple rules that either allow or deny specific
+addresses, it is possible to create a single object, call an address
+pool, that contains all of those addresses and reference that in the
+filter rule. For documentation on how to write the configuration file
+for those pools and load them, see ippool.conf(5) and ippool(8).
+There are two types of address pools that can be defined in ippool.conf(5):
+trees and hash tables. To refer to a tree defined in ippool.conf(5),
+use this syntax:
+.PP
+.nf
+pass in from pool/trusted to any
+.fi
+.PP
+Either a name or number can be used after the '/', just so long as it
+matches up with something that has already been defined in ipool.conf(5)
+and loaded in with ippool(8). Loading a filter rule that references a
+pool that does not exist will result in an error.
+.PP
+If hash tables have been used in ippool.conf(5) to store the addresses
+in instead of a tree, then replace the word pool with hash:
+.IP
+.nf
+pass in from any to hash/webservers
+.fi
+.PP
+There are different operational characteristics with each, so there
+may be some situations where a pool works better than hash and vice
+versa.
+.SS Matching TCP flags
+.PP
+The TCP header contains a field of flags that is used to decide if the
+packet is a connection request, connection termination, data, etc.
+By matching on the flags in conjunction with port numbers, it is
+possible to restrict the way in which IPFilter allows connections to
+be created. A quick overview of the TCP
+flags is below. Each is listed with the letter used in IPFilter
+rules, followed by its three or four letter pneumonic.
+.HP
+S
+SYN - this bit is set when a host is setting up a connection.
+The initiator typically sends a packet with the SYN bit and the
+responder sends back SYN plus ACK.
+.HP
+A
+ACK - this bit is set when the sender wishes to acknowledge the receipt
+of a packet from another host
+.HP
+P
+PUSH - this bit is set when a sending host has send some data that
+is yet to be acknowledged and a reply is sought
+.HP
+F
+FIN - this bit is set when one end of a connection starts to close
+the connection down
+.HP
+U
+URG - this bit is set to indicate that the packet contains urgent data
+.HP
+R
+RST - this bit is set only in packets that are a reply to another
+that has been received but is not targetted at any open port
+.HP
+C
+CWN
+.HP
+E
+ECN
+.PP
+When matching TCP flags, it is normal to just list the flag that you
+wish to be set. By default the set of flags it is compared against
+is "FSRPAU". Rules that say "flags S" will be displayed by ipfstat(8)
+as having "flags S/FSRPAU". This is normal.
+The last two flags, "C" and "E", are optional - they
+may or may not be used by an end host and have no bearing on either
+the acceptance of data nor control of the connection. Masking them
+out with "flags S/FSRPAUCE" may cause problems for remote hosts
+making a successful connection.
+.PP
+.nf
+pass in quick proto tcp from any to any port = 22 flags S/SAFR
+pass out quick proto tcp from any port = 22 to any flags SA
+.fi
+.PP
+By itself, filtering based on the TCP flags becomes more work but when
+combined with stateful filtering (see below), the situation changes.
+.SS Matching on ICMP header information
+.PP
+The TCP and UDP are not the only protocols for which filtering beyond
+just the IP header is possible, extended matching on ICMP packets is
+also available. The list of valid ICMP types is different for IPv4
+vs IPv6.
+.PP
+As a practical example, to allow the ping command to work
+against a specific target requires allowing two different types of
+ICMP packets, like this:
+.PP
+.nf
+pass in proto icmp from any to webserver icmp-type echo
+pass out proto icmp from webserver to any icmp-type echorep
+.fi
+.PP
+The ICMP header has two fields that are of interest for filtering:
+the ICMP type and code. Filter rules can accept either a name or
+number for both the type and code. The list of names supported for
+ICMP types is listed below, however only ICMP unreachable errors
+have named codes (see above.)
+.PP
+The list of ICMP types that are available for matching an IPv4 packet
+are as follows:
+.PP
+echo (echo request),
+echorep (echo reply),
+inforeq (information request),
+inforep (information reply),
+maskreq (mask request),
+maskrep (mask reply),
+paramprob (parameter problem),
+redir (redirect),
+routerad (router advertisement),
+routersol (router solicit),
+squence (source quence),
+timest (timestamp),
+timestreq (timestamp reply),
+timex (time exceeded),
+unreach (unreachable).
+.PP
+The list of ICMP types that are available for matching an IPv6 packet
+are as follows:
+.PP
+echo (echo request),
+echorep (echo reply),
+fqdnquery (FQDN query),
+fqdnreply (FQDN reply),
+inforeq (information request),
+inforep (information reply),
+listendone (MLD listener done),
+listendqry (MLD listener query),
+listendrep (MLD listener reply),
+neighadvert (neighbour advert),
+neighborsol (neighbour solicit),
+paramprob (parameter problem),
+redir (redirect),
+renumber (router renumbering),
+routerad (router advertisement),
+routersol (router solicit),
+timex (time exceeded),
+toobig (packet too big),
+unreach (unreachable,
+whoreq (WRU request),
+whorep (WRU reply).
+.SH Stateful Packet Filtering
+.PP
+Stateful packet filtering is where IPFilter remembers some information from
+one or more packets that it has seen and is able to apply it to future
+packets that it receives from the network.
+.PP
+What this means for each transport layer protocol is different.
+For TCP it means that if IPFilter
+sees the very first packet of an attempt to make a connection, it has enough
+information to allow all other subsequent packets without there needing to
+be any explicit rules to match them. IPFilter uses the TCP port numbers,
+TCP flags, window size and sequence numbers to determine which packets
+should be matched. For UDP, only the UDP port numbers are available.
+For ICMP, the ICMP types can be combined with the ICMP id field to
+determine which reply packets match a request/query that has already
+been seen. For all other protocols, only matching on IP address and
+protocol number is available for determining if a packet received is a mate
+to one that has already been let through.
+.PP
+The difference this makes is a reduction in the number of rules from
+2 or 4 to 1. For example, these 4 rules:
+.PP
+.nf
+pass in on bge0 proto tcp from any to any port = 22
+pass out on bge1 proto tcp from any to any port = 22
+pass in on bge1 proto tcp from any port = 22 to any
+pass out on bge0 proto tcp from any port = 22 to any
+.fi
+.PP
+can be replaced with this single rule:
+.PP
+.nf
+pass in on bge0 proto tcp from any to any port = 22 flags S keep state
+.fi
+.PP
+Similar rules for UDP and ICMP might be:
+.PP
+.nf
+pass in on bge0 proto udp from any to any port = 53 keep state
+pass in on bge0 proto icmp all icmp-type echo keep state
+.fi
+.PP
+When using stateful filtering with TCP it is best to add "flags S" to the
+rule to ensure that state is only created when a packet is seen that is
+an indication of a new connection. Although IPFilter can gather some
+information from packets in the middle of a TCP connection to do stateful
+filtering, there are some options that are only sent at the start of the
+connection which alter the valid window of what TCP accepts. The end result
+of trying to pickup TCP state in mid connection is that some later packets
+that are part of the connection may not match the known state information
+and be dropped or blocked, causing problems. If a TCP packet matches IP
+addresses and port numbers but does not fit into the recognised window,
+it will not be automatically allowed and will be flagged inside of
+IPFitler as "out of window" (oow). See below, "Extra packet attributes",
+for how to match on this attribute.
+.PP
+Once a TCP connection has reached the established state, the default
+timeout allows for it to be idle for 5 days before it is removed from
+the state table. The timeouts for the other TCP connection states
+vary from 240 seconds to 30 seconds.
+Both UDP and ICMP state entries have asymetric timeouts where the timeout
+set upon seeing packets in the forward direction is much larger than
+for the reverse direction. For UDP the default timeouts are 120 and
+12 seconds, for ICMP 60 and 6 seconds. This is a reflection of the
+use of these protocols being more for query-response than for ongoing
+connections. For all other protocols the
+timeout is 60 seconds in both directions.
+.SS Stateful filtering options
+.PP
+The following options can be used with stateful filtering:
+.HP
+limit
+limit the number of state table entries that this rule can create to
+the number given after limit. A rule that has a limit specified is
+always permitted that many state table entries, even if creating an
+additional entry would cause the table to have more entries than the
+otherwise global limit.
+.IP
+.nf
+pass ... keep state(limit 100)
+.fi
+.HP
+age
+sets the timeout for the state entry when it sees packets going through
+it. Additionally it is possible to set the tieout for the reply packets
+that come back through the firewall to a different value than for the
+forward path. allowing a short timeout to be set after the reply has
+been seen and the state no longer required.
+.RS
+.PP
+.nf
+pass in quick proto icmp all icmp-type echo \\
+ keep state (age 3)
+pass in quick proto udp from any \\
+ to any port = 53 keep state (age 30/1)
+.fi
+.RE
+.HP
+strict
+only has an impact when used with TCP. It forces all packets that are
+allowed through the firewall to be sequential: no out of order delivery
+of packets is allowed. This can cause significant slowdown for some
+connections and may stall others. Use with caution.
+.IP
+.nf
+pass in proto tcp ... keep state(strict)
+.fi
+.HP
+noicmperr
+prevents ICMP error packets from being able to match state table entries
+created with this flag using the contents of the original packet included.
+.IP
+.nf
+pass ... keep state(noicmperr)
+.fi
+.HP
+sync
+indicates to IPFilter that it needs to provide information to the user
+land daemons responsible for syncing other machines state tables up
+with this one.
+.IP
+.nf
+pass ... keep state(sync)
+.fi
+.HP
+nolog
+do not generate any log records for the creation or deletion of state
+table entries.
+.IP
+.nf
+pass ... keep state(nolog)
+.fi
+.HP
+icmp-head
+rather than just precent ICMP error packets from being able to match
+state table entries, allow an ACL to be processed that can filter in or
+out ICMP error packets based as you would with normal firewall rules.
+The icmp-head option requires a filter rule group number or name to
+be present, just as you would use with head.
+.RS
+.PP
+.nf
+pass in quick proto tcp ... keep state(icmp-head 101)
+block in proto icmp from 10.0.0.0/8 to any group 101
+.fi
+.RE
+.HP
+max-srcs
+allows the number of distinct hosts that can create a state entry to
+be defined.
+.IP
+.nf
+pass ... keep state(max-srcs 100)
+pass ... keep state(limit 1000, max-srcs 100)
+.fi
+.HP
+max-per-src
+whilst max-srcs limits the number of individual hosts that may cause
+the creation of a state table entry, each one of those hosts is still
+table to fill up the state table with new entries until the global
+maximum is reached. This option allows the number of state table entries
+per address to be limited.
+.IP
+.nf
+pass ... keep state(max-srcs 100, max-per-src 1)
+pass ... keep state(limit 100, max-srcs 100, max-per-src 1)
+.fi
+.IP
+Whilst these two rules might seem identical, in that they both
+ultimately limit the number of hosts and state table entries created
+from the rule to 100, there is a subtle difference: the second will
+always allow up to 100 state table entries to be created whereas the
+first may not if the state table fills up from other rules.
+.IP
+Further, it is possible to specify a netmask size after the per-host
+limit that enables the per-host limit to become a per-subnet or
+per-network limit.
+.IP
+.nf
+pass ... keep state(max-srcs 100, max-per-src 1/24)
+.fi
+.IP
+If there is no IP protocol implied by addresses or other features of
+the rule, IPFilter will assume that no netmask is an all ones netmask
+for both IPv4 and IPv6.
+.SS Tieing down a connection
+.PP
+For any connection that transits a firewall, each packet will be seen
+twice: once going in and once going out. Thus a connection has 4 flows
+of packets:
+.HP
+forward
+inbound packets
+.HP
+forward
+outbound packets
+.HP
+reverse
+inbound packets
+.HP
+reverse
+outbound packets
+.PP
+IPFilter allows you to define the network interface to be used at all
+four points in the flow of packets. For rules that match inbound packets,
+out-via is used to specify which interfaces the packets go out, For rules
+that match outbound packets, in-via is used to match the inbound packets.
+In each case, the syntax generalises to this:
+.PP
+.nf
+pass ... in on forward-in,reverse-in \\
+ out-via forward-out,reverse-out ...
+
+pass ... out on forward-out,reverse-out \\
+ in-via forward-in,reverse-in ...
+.fi
+.PP
+An example that pins down all 4 network interfaces used by an ssh
+connection might look something like this:
+.PP
+.nf
+pass in on bge0,bge1 out-via bge1,bge0 proto tcp \\
+ from any to any port = 22 flags S keep state
+.fi
+.SS Working with packet fragments
+.PP
+Fragmented packets result in 1 packet containing all of the layer 3 and 4
+header information whilst the data is split across a number of other packets.
+.PP
+To enforce access control on fragmented packets, one of two approaches
+can be taken. The first is to allow through all of the data fragments
+(those that made up the body of the original packet) and rely on matching
+the header information in the "first" fragment, when it is seen. The
+reception of body fragments without the first will result in the receiving
+host being unable to completely reassemble the packet and discarding all
+of the fragments. The following three rules deny all fragmented packets
+from being received except those that are UDP and even then only allows
+those destined for port 2049 to be completed.
+.PP
+.nf
+block in all with frags
+pass in proto udp from any to any with frag-body
+pass in proto udp from any to any port = 2049 with frags
+.fi
+.PP
+Another mechanism that is available is to track "fragment state".
+This relies on the first fragment of a packet that arrives to be
+the fragment that contains all of the layer 3 and layer 4 header
+information. With the receipt of that fragment before any other,
+it is possible to determine which other fragments are to be allowed
+through without needing to explicitly allow all fragment body packets.
+An example of how this is done is as follows:
+.PP
+.nf
+pass in proto udp from any prot = 2049 to any with frags keep fags
+.fi
+.SH Building a tree of rules
+.PP
+Writing your filter rules as one long list of rules can be both inefficient
+in terms of processing the rules and difficult to understand. To make the
+construction of filter rules easier, it is possible to place them in groups.
+A rule can be both a member of a group and the head of a new group.
+.PP
+Using filter groups requires at least two rules: one to be in the group
+one one to send matchign packets to the group. If a packet matches a
+filtre rule that is a group head but does not match any of the rules
+in that group, then the packet is considered to have matched the head
+rule.
+.PP
+Rules that are a member of a group contain the word group followed by
+either a name or number that defines which group they're in. Rules that
+form the branch point or starting point for the group must use the
+word head, followed by either a group name or number. If rules are
+loaded in that define a group but there is no matching head then they
+will effectively be orphaned rules. It is possible to have more than
+one head rule point to the same group, allowing groups to be used
+like subroutines to implement specific common policies.
+.PP
+A common use of filter groups is to define head rules that exist in the
+filter "main line" for each direction with the interfaces in use. For
+example:
+.PP
+.nf
+block in quick on bge0 all head 100
+block out quick on bge0 all head 101
+block in quick on fxp0 all head internal-in
+block out quick on fxp0 all head internal-out
+pass in quick proto icmp all icmp-type echo group 100
+.fi
+.PP
+In the above set of rules, there are four groups defined but only one
+of them has a member rule. The only packets that would be allowed
+through the above ruleset would be ICMP echo packets that are
+received on bge0.
+.PP
+Rules can be both a member of a group and the head of a new group,
+allowing groups to specialise.
+.PP
+.nf
+block in quick on bge0 all head 100
+block in quick proto tcp all head 1006 group 100
+.fi
+.PP
+Another use of filter rule groups is to provide a place for rules to
+be dynamically added without needing to worry about their specific
+ordering amongst the entire ruleset. For example, if I was using this
+simple ruleset:
+.PP
+.nf
+block in quick all with bad
+block in proto tcp from any to any port = smtp head spammers
+pass in quick proto tcp from any to any port = smtp flags S keep state
+.fi
+.PP
+and I was getting lots of connections to my email server from 10.1.1.1
+to deliver spam, I could load the following rule to complement the above:
+.IP
+.nf
+block in quick from 10.1.1.1 to any group spammers
+.fi
+.SS Decapsulation
+.PP
+Rule groups also form a different but vital role for decapsulation rules.
+With the following simple rule, if IPFilter receives an IP packet that has
+an AH header as its layer 4 payload, IPFilter would adjust its view of the
+packet internally and then jump to group 1001 using the data beyond the
+AH header as the new transport header.
+.PP
+.nf
+decapsulate in proto ah all head 1001
+.fi
+.PP
+For protocols that
+are recognised as being used with tunnelling or otherwise encapsulating
+IP protocols, IPFilter is able to decide what it has on the inside
+without any assistance. Some tunnelling protocols use UDP as the
+transport mechanism. In this case, it is necessary to instruct IPFilter
+as to what protocol is inside UDP.
+.PP
+.nf
+decapsulate l5-as(ip) in proto udp from any \\
+ to any port = 1520 head 1001
+.fi
+.PP
+Currently IPFilter only supports finding IPv4 and IPv6 headers
+directly after the UDP header.
+.PP
+If a packet matches a decapsulate rule but fails to match any of the rules
+that are within the specified group, processing of the packet continues
+to the next rule after the decapsulate and IPFilter's internal view of the
+packet is returned to what it was prior to the decapsulate rule.
+.PP
+It is possible to construct a decapsulate rule without the group
+head at the end that ipf(8) will accept but such rules will not
+result in anything happening.
+.SS Policy Based Routing
+.PP
+With firewalls being in the position they often are, at the boundary
+of different networks connecting together and multiple connections that
+have different properties, it is often desirable to have packets flow
+in a direction different to what the routing table instructs the kernel.
+These decisions can often be extended to changing the route based on
+both source and destination address or even port numbers.
+.PP
+To support this kind of configuration, IPFilter allows the next hop
+destination to be specified with a filter rule. The next hop is given
+with the interface name to use for output. The syntax for this is
+interface:ip.address. It is expected that the address given as the next
+hop is directly connected to the network to which the interface is.
+.PP
+.nf
+pass in on bge0 to bge1:1.1.1.1 proto tcp \\
+ from 1.1.2.3 to any port = 80 flags S keep state
+.fi
+.PP
+When this feature is combined with stateful filtering, it becomes
+possible to influence the network interface used to transmit packets
+in both directions because we now have a sense for what its reverse
+flow of packets is.
+.PP
+.nf
+pass in on bge0 to bge1:1.1.1.1 reply-to hme1:2.1.1.2 \\
+ proto tcp from 1.1.2.3 to any port = 80 flags S keep state
+.fi
+.PP
+If the actions of the routing table are perfectly acceptable, but
+you would like to mask the presence of the firewall by not changing
+the TTL in IP packets as they transit it, IPFilter can be instructed
+to do a "fastroute" action like this:
+.PP
+.nf
+pass in on bge0 fastroute proto icmp all
+.fi
+.PP
+This should be used with caution as it can lead to endless packet
+loops. Additionally, policy based routing does not change the IP
+header's TTL value.
+.PP
+A variation on this type of rule supports a duplicate of the original
+packet being created and sent out a different network. This can be
+useful for monitoring traffic and other purposes.
+.PP
+.nf
+pass in on bge0 to bge1:1.1.1.1 reply-to hme1:2.1.1.2 \\
+ dup-to fxp0:10.0.0.1 proto tcp from 1.1.2.3 \\
+ to any port = 80 flags S keep state
+.fi
+.SS Matching IPv4 options
+.PP
+The design for IPv4 allows for the header to be upto 64 bytes long,
+however most traffic only uses the basic header which is 20 bytes long.
+The other 44 bytes can be uesd to store IP options. These options are
+generally not necessary for proper interaction and function on the
+Internet today. For most people it is sufficient to block and drop
+all packets that have any options set. This can be achieved with this
+rule:
+.PP
+.nf
+block in quick all with ipopts
+.fi
+.PP
+This rule is usually placed towards the top of the configuration
+so that all incoming packets are blocked.
+.PP
+If you wanted to allow in a specific IP option type, the syntax
+changes slightly:
+.PP
+.nf
+pass in quick proto igmp all with opt rtralrt
+.fi
+.PP
+The following is a list of IP options that most people encounter and
+what their use/threat is.
+.HP
+lsrr
+(loose source route) the sender of the packet includes a list of addresses
+that they wish the packet to be routed through to on the way to the
+destination. Because replies to such packets are expected to use the
+list of addresses in reverse, hackers are able to very effectively use
+this header option in address spoofing attacks.
+.HP
+rr
+(record route) the sender allocates some buffer space for recording the
+IP address of each router that the packet goes through. This is most often
+used with ping, where the ping response contains a copy of all addresses
+from the original packet, telling the sender what route the packet took
+to get there. Due to performance and security issues with IP header
+options, this is almost no longer used.
+.HP
+rtralrt
+(router alert) this option is often used in IGMP messages as a flag to
+routers that the packet needs to be handled differently. It is unlikely
+to ever be received from an unknown sender. It may be found on LANs or
+otherwise controlled networks where the RSVP protocol and multicast
+traffic is in heavy use.
+.HP
+ssrr
+(strict source route) the sender of the packet includes a list of addresses
+that they wish the packet to be routed through to on the way to the
+destination. Where the lsrr option allows the sender to specify only
+some of the nodes the packet must go through, with the ssrr option,
+every next hop router must be specified.
+.PP
+The complete list of IPv4 options that can be matched on is:
+addext (Address Extention),
+cipso (Classical IP Security Option),
+dps (Dynamic Packet State),
+e-sec (Extended Security),
+eip (Extended Internet Protocol),
+encode (ENCODE),
+finn (Experimental Flow Control),
+imitd (IMI Traffic Descriptor),
+lsrr (Loose Source Route),
+mtup (MTU Probe - obsolete),
+mtur (MTU response - obsolete),
+nop (No Operation),
+nsapa (NSAP Address),
+rr (Record Route),
+rtralrt (Router Alert),
+satid (Stream Identifier),
+sdb (Selective Directed Broadcast),
+sec (Security),
+ssrr (Strict Source Route),
+tr (Tracerote),
+ts (Timestamp),
+ump (Upstream Multicast Packet),
+visa (Experimental Access Control)
+and zsu (Experimental Measurement).
+.SS Security with CIPSO and IPSO
+.PP
+IPFilter supports filtering on IPv4 packets using security attributes embedded
+in the IP options part of the packet. These options are usually only used on
+networks and systems that are using lablled security. Unless you know that
+you are using labelled security and your networking is also labelled, it
+is highly unlikely that this section will be relevant to you.
+.PP
+With the traditional IP Security Options (IPSO), packets can be tagged with
+a security level. The following keywords are recognised and match with the
+relevant RFC with respect to the bit patterns matched:
+confid (confidential),
+rserve-1 (1st reserved value),
+rserve-2 (2nd reserved value),
+rserve-3 (3rd reserved value),
+rserve-4 (4th reserved value),
+secret (secret),
+topsecret (top secret),
+unclass (unclassified).
+.PP
+.nf
+block in quick all with opt sec-class unclass
+pass in all with opt sec-class secret
+.fi
+.SS Matching IPv6 extension headers
+.PP
+Just as it is possible to filter on the various IPv4 header options,
+so too it is possible to filter on the IPv6 extension headers that are
+placed between the IPv6 header and the transport protocol header.
+.PP
+dstopts (destination options),
+esp (encrypted, secure, payload),
+frag (fragment),
+hopopts (hop-by-hop options),
+ipv6 (IPv6 header),
+mobility (IP mobility),
+none,
+routing.
+.SS Logging
+.PP
+There are two ways in which packets can be logged with IPFilter. The
+first is with a rule that specifically says log these types of packets
+and the second is a qualifier to one of the other keywords. Thus it is
+possible to both log and allow or deny a packet with a single rule.
+.PP
+.nf
+pass in log quick proto tcp from any to any port = 22
+.fi
+.PP
+When using stateful filtering, the log action becomes part of the result
+that is remembered about a packet. Thus if the above rule was qualified
+with keep state, every packet in the connection would be logged. To only
+log the first packet from every packet flow tracked with keep state, it
+is necessary to indicate to IPFilter that you only wish to log the first
+packet.
+.PP
+.nf
+pass in log first quick proto tcp from any to any port = 22 \\
+ flags S keep state
+.fi
+.PP
+If it is a requirement that the logging provide an accurate representation
+of which connections are allowed, the log action can be qualified with the
+option or-block. This allows the administrator to instruct IPFilter to
+block the packet if the attempt to record the packet in IPFilter's kernel
+log records (which have an upper bound on size) failed. Unless the system
+shuts down or reboots, once a log record is written into the kernel buffer,
+it is there until ipmon(8) reads it.
+.PP
+.nf
+block in log proto tcp from any to any port = smtp
+pass in log or-block first quick proto tcp from any \\
+ to any port = 22 flags S keep state
+.fi
+.PP
+By default, IPFilter will only log the header portion of a packet received
+on the network. A portion of the body of a packet, upto 128 bytes, can also
+be logged with the body keyword. ipmon(8) will display the contents of the
+portion of the body logged in hex.
+.PP
+.nf
+block in log body proto icmp all
+.fi
+.PP
+When logging packets from ipmon(8) to syslog, by default ipmon(8) will
+control what syslog facility and priority a packet will be logged with.
+This can be tuned on a per rule basis like this:
+.PP
+.nf
+block in quick log level err all with bad
+pass in log level local1.info proto tcp \\
+ from any to any port = 22 flags S keep state
+.fi
+.PP
+ipfstat(8) reports how many packets have been successfully logged and how
+many failed attempts to log a packet there were.
+.SS Filter rule comments
+.PP
+If there is a desire to associate a text string, be it an administrative
+comment or otherwise, with an IPFilter rule, this can be achieved by giving
+the filter rule a comment. The comment is loaded with the rule into the
+kernel and can be seen when the rules are listed with ipfstat.
+.PP
+.nf
+pass in quick proto tcp from any \\
+ to port = 80 comment "all web server traffic is ok"
+pass out quick proto tcp from any port = 80 \\
+ to any comment "all web server traffic is ok"
+.fi
+.SS Tags
+.PP
+To enable filtering and NAT to correctly match up packets with rules,
+tags can be added at with NAT (for inbound packets) and filtering (for
+outbound packets.) This allows a filter to be correctly mated with its
+NAT rule in the event that the NAT rule changed the packet in a way
+that would mean it is not obvious what it was.
+.PP
+For inbound packets, IPFilter can match the tag used in the filter
+rules with that set by NAT. For outbound rules, it is the reverse,
+the filter sets the tag and the NAT rule matches up with it.
+.PP
+.nf
+pass in ... match-tag(nat=proxy)
+pass out ... set-tag(nat=proxy)
+.fi
+.PP
+Another use of tags is to supply a number that is only used with logging.
+When packets match these rules, the log tag is carried over into the
+log file records generated by ipmon(8). With the correct use of tools
+such as grep, extracting log records of interest is simplified.
+.PP
+.nf
+block in quick log ... set-tag(log=33)
+.fi
+.SH Filter Rule Expiration
+.PP
+IPFilter allows rules to be added into the kernel that it will remove after
+a specific period of time by specifying rule-ttl at the end of a rule.
+When listing rules in the kernel using ipfstat(8), rules that are going
+to expire will NOT display "rule-ttl" with the timeout, rather what will
+be seen is a comment with how many ipfilter ticks left the rule has to
+live.
+.PP
+The time to live is specified in seconds.
+.PP
+.nf
+pass in on fxp0 proto tcp from any \\
+ to port = 22 flags S keep state rule-ttl 30
+.fi
+.SH Internal packet attributes
+.PP
+In addition to being able to filter on very specific network and transport
+header fields, it is possible to filter on other attributes that IPFilter
+attaches to a packet. These attributes are placed in a rule after the
+keyword "with", as can be seen with frags and frag-body above. The
+following is a list of the other attributes available:
+.HP
+oow
+the packet's IP addresses and TCP ports match an existing entry in the
+state table but the sequence numbers indicate that it is outside of the
+accepted window.
+.IP
+.nf
+block return-rst in quick proto tcp from any to any with not oow
+.fi
+.HP
+bcast
+this is set by IPFilter when it receives notification that the link
+layer packet was a broadcast packet. No checking of the IP addresses
+is performned to determine if it is a broadcast destination or not.
+.IP
+.nf
+block in quick proto udp all with bcast
+.fi
+.HP
+mcast
+this is set by IPFilter when it receives notification that the link
+layer packet was a multicast packet. No checking of the IP addresses
+is performned to determine if it is a multicast destination or not.
+.IP
+.nf
+pass in quick proto udp from any to any port = dns with mcast
+.fi
+.HP
+mbcast
+can be used to match a packet that is either a multicast or broadcast
+packet at the link layer, as indicated by the operating system.
+.IP
+.nf
+pass in quick proto udp from any to any port = ntp with mbcast
+.fi
+.HP
+nat
+the packet positively matched a NAT table entry.
+.HP
+bad
+sanity checking of the packet failed. This could indicate that the
+layer 3/4 headers are not properly formed.
+.HP
+bad-src
+when reverse path verification is enabled, this flag will be set when
+the interface the packet is received on does not match that which would
+be used to send a packet out of to the source address in the received
+packet.
+.HP
+bad-nat
+an attempt to perform NAT on the packet failed.
+.HP
+not
+each one of the attributes matched using the "with" keyword can also be
+looked for to not be present. For example, to only allow in good packets,
+I can do this:
+.PP
+.nf
+block in all
+pass in all with not bad
+.fi
+.SH Tuning IPFilter
+.PP
+The ipf.conf file can also be used to tune the behaviour of IPFilter,
+allowing, for example, timeouts for the NAT/state table(s) to be set
+along with their sizes. The presence and names of tunables may change
+from one release of IPFilter to the next. The tunables that can be
+changed via ipf.conf is the same as those that can be seen and modified
+using the -T command line option to ipf(8).
+.PP
+NOTE: When parsing ipf.conf, ipf(8) will apply the settings before
+loading any rules. Thus if your settings are at the top, these may
+be applied whilst the rules not applied if there is an error further
+down in the configuration file.
+.PP
+To set one of the values below, the syntax is simple: "set", followed
+by the name of the tuneable to set and then the value to set it to.
+.PP
+.nf
+set state_max 9999;
+set state_size 10101;
+.fi
+.PP
+A list of the currently available variables inside IPFilter that may
+be tuned from ipf.conf are as follows:
+.HP
+active
+set through -s command line switch of ipf(8). See ipf(8) for detals.
+.HP
+chksrc
+when set, enables reverse path verification on source addresses and
+for filters to match packets with bad-src attribute.
+.HP
+control_forwarding
+when set turns off kernel forwarding when IPFilter is disabled or unloaded.
+.HP
+default_pass
+the default policy - whether packets are blocked or passed, etc - is
+represented by the value of this variable. It is a bit field and the
+bits that can be set are found in <netinet/ip_fil.h>. It is not
+recommended to tune this value directly.
+.HP
+ftp_debug
+set the debugging level of the in-kernel FTP proxy.
+Debug messages will be printed to the system console.
+.HP
+ftp_forcepasv
+when set the FTP proxy must see a PASV/EPSV command before creating
+the state/NAT entries for the 227 response.
+.HP
+ftp_insecure
+when set the FTP proxy will not wait for a user to login before allowing
+data connections to be created.
+.HP
+ftp_pasvonly
+when set the proxy will not create state/NAT entries for when it
+sees either the PORT or EPRT command.
+.HP
+ftp_pasvrdr
+when enabled causes the FTP proxy to create very insecure NAT/state
+entries that will allow any connection between the client and server
+hosts when a 227 reply is seen. Use with extreme caution.
+.HP
+ftp_single_xfer
+when set the FTP proxy will only allow one data connection at a time.
+.HP
+hostmap_size
+sets the size of the hostmap table used by NAT to store address mappings
+for use with sticky rules.
+.HP
+icmp_ack_timeout
+default timeout used for ICMP NAT/state when a reply packet is seen for
+an ICMP state that already exists
+.HP
+icmp_minfragmtu
+sets the minimum MTU that is considered acceptable in an ICMP error
+before deciding it is a bad packet.
+.HP
+icmp_timeout
+default timeout used for ICMP NAT/state when the packet matches the rule
+.HP
+ip_timeout
+default timeout used for NAT/state entries that are not TCP/UDP/ICMP.
+.HP
+ipf_flags
+.HP
+ips_proxy_debug
+this sets the debugging level for the proxy support code.
+When enabled, debugging messages will be printed to the system console.
+.HP
+log_all
+when set it changes the behaviour of "log body" to log the entire packet
+rather than just the first 128 bytes.
+.HP
+log_size
+sets the size of the in-kernel log buffer in bytes.
+.HP
+log_suppress
+when set, IPFilter will check to see if the packet it is logging is
+similar to the one it previously logged and if so, increases
+the occurance count for that packet. The previously logged packet
+must not have yet been read by ipmon(8).
+.HP
+min_ttl
+is used to set the TTL value that packets below will be marked with
+the low-ttl attribute.
+.HP
+nat_doflush
+if set it will cause the NAT code to do a more aggressive flush of the
+NAT table at the next opportunity. Once the flush has been done, the
+value is reset to 0.
+.HP
+nat_lock
+this should only be changed using ipfs(8)
+.HP
+nat_logging
+when set, NAT will create log records that can be read from /dev/ipnat.
+.HP
+nat_maxbucket
+maximum number of entries allowed to exist in each NAT hash bucket.
+This prevents an attacker trying to load up the hash table with
+entries in a single bucket, reducing performance.
+.HP
+nat_rules_size
+size of the hash table to store map rules.
+.HP
+nat_table_max
+maximum number of entries allowed into the NAT table
+.HP
+nat_table_size
+size of the hash table used for NAT
+.HP
+nat_table_wm_high
+when the fill percentage of the NAT table exceeds this mark, more
+aggressive flushing is enabled.
+.HP
+nat_table_wm_low
+this sets the percentage at which the NAT table's agressive flushing
+will turn itself off at.
+.HP
+rdr_rules_size
+size of the hash table to store rdr rules.
+.HP
+state_lock
+this should only be changed using ipfs(8)
+.HP
+state_logging
+when set, the stateful filtering will create log records
+that can be read from /dev/ipstate.
+.HP
+state_max
+maximum number of entries allowed into the state table
+.HP
+state_maxbucket
+maximum number of entries allowed to exist in each state hash bucket.
+This prevents an attacker trying to load up the hash table with
+entries in a single bucket, reducing performance.
+.HP
+state_size
+size of the hash table used for stateful filtering
+.HP
+state_wm_freq
+this controls how often the agressive flushing should be run once the
+state table exceeds state_wm_high in percentage full.
+.HP
+state_wm_high
+when the fill percentage of the state table exceeds this mark, more
+aggressive flushing is enabled.
+.HP
+state_wm_low
+this sets the percentage at which the state table's agressive flushing
+will turn itself off at.
+.HP
+tcp_close_wait
+timeout used when a TCP state entry reaches the FIN_WAIT_2 state.
+.HP
+tcp_closed
+timeout used when a TCP state entry is ready to be removed after either
+a RST packet is seen.
+.HP
+tcp_half_closed
+timeout used when a TCP state entry reaches the CLOSE_WAIT state.
+.HP
+tcp_idle_timeout
+timeout used when a TCP state entry reaches the ESTABLISHED state.
+.HP
+tcp_last_ack
+timeout used when a TCP NAT/state entry reaches the LAST_ACK state.
+.HP
+tcp_syn_received
+timeout applied to a TCP NAT/state entry after SYN-ACK packet has been seen.
+.HP
+tcp_syn_sent
+timeout applied to a TCP NAT/state entry after SYN packet has been seen.
+.HP
+tcp_time_wait
+timeout used when a TCP NAT/state entry reaches the TIME_WAIT state.
+.HP
+tcp_timeout
+timeout used when a TCP NAT/state entry reaches either the half established
+state (one ack is seen after a SYN-ACK) or one side is in FIN_WAIT_1.
+.HP
+udp_ack_timeout
+default timeout used for UDP NAT/state when a reply packet is seen for
+a UDP state that already exists
+.HP
+udp_timeout
+default timeout used for UDP NAT/state when the packet matches the rule
+.HP
+update_ipid
+when set, turns on changing the IP id field in NAT'd packets to a random
+number.
+.SS Table of visible variables
+.PP
+A list of all of the tunables, their minimum, maximum and current
+values is as follows.
+.PP
+.nf
+Name Min Max Current
+active 0 0 0
+chksrc 0 1 0
+control_forwarding 0 1 0
+default_pass 0 MAXUINT 134217730
+ftp_debug 0 10 0
+ftp_forcepasv 0 1 1
+ftp_insecure 0 1 0
+ftp_pasvonly 0 1 0
+ftp_pasvrdr 0 1 0
+ftp_single_xfer 0 1 0
+hostmap_size 1 MAXINT 2047
+icmp_ack_timeout 1 MAXINT 12
+icmp_minfragmtu 0 1 68
+icmp_timeout 1 MAXINT 120
+ip_timeout 1 MAXINT 120
+ipf_flags 0 MAXUINT 0
+ips_proxy_debug 0 10 0
+log_all 0 1 0
+log_size 0 524288 32768
+log_suppress 0 1 1
+min_ttl 0 1 4
+nat_doflush 0 1 0
+nat_lock 0 1 0
+nat_logging 0 1 1
+nat_maxbucket 1 MAXINT 22
+nat_rules_size 1 MAXINT 127
+nat_table_max 1 MAXINT 30000
+nat_table_size 1 MAXINT 2047
+nat_table_wm_high 2 100 99
+nat_table_wm_low 1 99 90
+rdr_rules_size 1 MAXINT 127
+state_lock 0 1 0
+state_logging 0 1 1
+state_max 1 MAXINT 4013
+state_maxbucket 1 MAXINT 26
+state_size 1 MAXINT 5737
+state_wm_freq 2 999999 20
+state_wm_high 2 100 99
+state_wm_low 1 99 90
+tcp_close_wait 1 MAXINT 480
+tcp_closed 1 MAXINT 60
+tcp_half_closed 1 MAXINT 14400
+tcp_idle_timeout 1 MAXINT 864000
+tcp_last_ack 1 MAXINT 60
+tcp_syn_received 1 MAXINT 480
+tcp_syn_sent 1 MAXINT 480
+tcp_time_wait 1 MAXINT 480
+tcp_timeout 1 MAXINT 480
+udp_ack_timeout 1 MAXINT 24
+udp_timeout 1 MAXINT 240
+update_ipid 0 1 0
+.fi
+.SH Calling out to internal functions
+.PP
+IPFilter provides a pair of functions that can be called from a rule
+that allow for a single rule to jump out to a group rather than walk
+through a list of rules to find the group. If you've got multiple
+networks, each with its own group of rules, this feature may help
+provide better filtering performance.
+.PP
+The lookup to find which rule group to jump to is done on either the
+source address or the destination address but not both.
+.PP
+In this example below, we are blocking all packets by default but then
+doing a lookup on the source address from group 1010. The two rules in
+the ipf.conf section are lone members of their group. For an incoming
+packet that is from 1.1.1.1, it will go through three rules: (1) the
+block rule, (2) the call rule and (3) the pass rule for group 1020.
+For a packet that is from 3.3.2.2, it will also go through three rules:
+(1) the block rule, (2) the call rule and (3) the pass rule for group
+1030. Should a packet from 3.1.1.1 arrive, it will be blocked as it
+does not match any of the entries in group 1010, leaving it to only
+match the first rule.
+.PP
+.nf
+from ipf.conf
+-------------
+block in all
+call now srcgrpmap/1010 in all
+pass in proto tcp from any to any port = 80 group 1020
+pass in proto icmp all icmp-type echo group 1030
+
+from ippool.conf
+----------------
+group-map in role=ipf number=1010
+ { 1.1.1.1 group = 1020, 3.3.0.0/16 group = 1030; };
+.fi
+.SS IPFilter matching expressions
+.PP
+An experimental feature that has been added to filter rules is to use
+the same expression matching that is available with various commands
+to flush and list state/NAT table entries. The use of such an expression
+precludes the filter rule from using the normal IP header matching.
+.PP
+.nf
+pass in exp { "tcp.sport 23 or tcp.sport 50" } keep state
+.fi
+.SS Filter rules with BPF
+.PP
+On platforms that have the BPF built into the kernel, IPFilter can be
+built to allow BPF expressions in filter rules. This allows for packet
+matching to be on arbitrary data in the packt. The use of a BPF expression
+replaces all of the other protocol header matching done by IPFilter.
+.PP
+.nf
+pass in bpf-v4 { "tcp and (src port 23 or src port 50)" } \\
+ keep state
+.fi
+.PP
+These rules tend to be
+write-only because the act of compiling the filter expression into the
+BPF instructions loaded into the kernel can make it difficut to
+accurately reconstruct the original text filter. The end result is that
+while ipf.conf() can be easy to read, understanding the output from
+ipfstat might not be.
+.SH VARIABLES
+.PP
+This configuration file, like all others used with IPFilter, supports the
+use of variable substitution throughout the text.
+.PP
+.nf
+nif="ppp0";
+pass in on $nif from any to any
+.fi
+.PP
+would become
+.PP
+.nf
+pass in on ppp0 from any to any
+.fi
+.PP
+Variables can be used recursively, such as 'foo="$bar baz";', so long as
+$bar exists when the parser reaches the assignment for foo.
+.PP
+See
+.B ipf(8)
+for instructions on how to define variables to be used from a shell
+environment.
+.DT
+.SH FILES
+/dev/ipf
+/etc/ipf.conf
+.br
+/usr/share/examples/ipf Directory with examples.
+.SH SEE ALSO
+ipf(8), ipfstat(8), ippool.conf(5), ippool(8)
diff --git a/contrib/ipfilter/man/ipf.8 b/contrib/ipfilter/man/ipf.8
new file mode 100644
index 0000000..6e88a9d
--- /dev/null
+++ b/contrib/ipfilter/man/ipf.8
@@ -0,0 +1,172 @@
+.\" $FreeBSD$
+.TH IPF 8
+.SH NAME
+ipf \- alters packet filtering lists for IP packet input and output
+.SH SYNOPSIS
+.B ipf
+[
+.B \-6AcdDEInoPrsvVyzZ
+] [
+.B \-l
+<block|pass|nomatch>
+] [
+.B \-T
+<optionlist>
+] [
+.B \-F
+<i|o|a|s|S>
+]
+.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 \-6
+This option is required to parse IPv6 rules and to have them loaded.
+.TP
+.B \-A
+Set the list to make changes to the active list (default).
+.TP
+.B \-c <language>
+This option causes \fBipf\fP to generate output files for a compiler that
+supports \fBlanguage\fI. At present, the only target language supported is
+\fBC\fB (-cc) for which two files - \fBip_rules.c\fP
+and \fBip_rules.h\fP are generated in the \fBCURRENT DIRECTORY\fP when
+\fBipf\fP is being run. These files can be used with the
+\fBIPFILTER_COMPILED\fP kernel option to build filter rules staticlly into
+the kernel.
+.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<i|o|a>
+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<s|S>
+To flush entries from the state table, the \fB-F\fP option is used in
+conjunction with either "s" (removes state information about any non-fully
+established connections) or "S" (deletes the entire state table). Only
+one of the two options may be given. A fully established connection
+will show up in \fBipfstat -s\fP output as 5/5, with deviations either
+way indicating it is not fully established any more.
+.TP
+.BR \-F <5|6|7|8|9|10|11>
+For the TCP states that represent the closing of a connection has begun,
+be it only one side or the complete connection, it is possible to flush
+those states directly using the number corresponding to that state.
+The numbers relate to the states as follows: 5 = close-wait, 6 = fin-wait-1,
+7 = closing, 8 = last-ack, 9 = fin-wait-2, 10 = time-wait, 11 = closed.
+.TP
+.BR \-F <number>
+If the argument supplied to \fB-F\fP is greater than 30, then state table
+entries that have been idle for more than this many seconds will be flushed.
+.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<pass|block|nomatch>
+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 \-P
+Add rules as temporary entries in the authentication rule table.
+.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 \-T <optionlist>
+This option allows run-time changing of IPFilter kernel variables. Some
+variables require IPFilter to be in a disabled state (\fB-D\fP) for changing,
+others do not. The optionlist parameter is a comma separated list of tuning
+commands. A tuning command is either "list" (retrieve a list of all variables
+in the kernel, their maximum, minimum and current value), a single variable
+name (retrieve its current value) and a variable name with a following
+assignment to set a new value. Some examples follow.
+.nf
+# Print out all IPFilter kernel tunable parameters
+ipf -T list
+# Display the current TCP idle timeout and then set it to 3600
+ipf -D -T fr_tcpidletimeout,fr_tcpidletimeout=3600 -E
+# Display current values for fr_pass and fr_chksrc, then set fr_chksrc to 1.
+ipf -T fr_pass,fr_chksrc,fr_chksrc=1
+.fi
+.TP
+.B \-v
+Turn verbose mode on. Displays information relating to rule processing.
+.TP
+.B \-V
+Show version information. This will display the version information compiled
+into the ipf binary and retrieve it from the kernel code (if running/present).
+If it is present in the kernel, information about its current state will be
+displayed (whether logging is active, default filtering, etc).
+.TP
+.B \-y
+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 zeroed.
+.TP
+.B \-Z
+Zero global statistics held in the kernel for filtering only (this doesn't
+affect fragment or state statistics).
+.DT
+.SH FILES
+/dev/ipauth
+.br
+/dev/ipl
+.br
+/dev/ipstate
+.SH SEE ALSO
+ipftest(1), mkfilters(1), ipf(4), ipl(4), ipf(5), ipfstat(8), ipmon(8), ipnat(8)
+.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@pobox.com
diff --git a/contrib/ipfilter/man/ipfilter.4 b/contrib/ipfilter/man/ipfilter.4
new file mode 100644
index 0000000..10fd18e
--- /dev/null
+++ b/contrib/ipfilter/man/ipfilter.4
@@ -0,0 +1,241 @@
+.\" $FreeBSD$
+.\"
+.TH IP\ FILTER 4
+.SH NAME
+ipfilter \- Introduction to IP packet filtering
+.SH DESCRIPTION
+IP Filter is a TCP/IP packet filter, suitable for use in a firewall
+environment. To use, it can either be used as a loadable kernel module or
+incorporated into your UNIX kernel; use as a loadable kernel module where
+possible is highly recommended. Scripts are provided to install and patch
+system files, as required.
+.SH FEATURES
+The IP packet filter can:
+.IP
+explicitly deny/permit any packet from passing through
+.IP
+distinguish between various interfaces
+.IP
+filter by IP networks or hosts
+.IP
+selectively filter any IP protocol
+.IP
+selectively filter fragmented IP packets
+.IP
+selectively filter packets with IP options
+.IP
+send back an ICMP error/TCP reset for blocked packets
+.IP
+keep packet state information for TCP, UDP and ICMP packet flows
+.IP
+keep fragment state information for any IP packet, applying the same rule
+to all fragments.
+.IP
+act as a Network Address Translator (NAT)
+.IP
+use redirection to setup true transparent proxy connections
+.IP
+provide packet header details to a user program for authentication
+.IP
+in addition, supports temporary storage of pre-authenticated rules for passing packets through
+.PP
+Special provision is made for the three most common Internet protocols, TCP,
+UDP and ICMP. The IP Packet filter allows filtering of:
+.IP
+Inverted host/net matchingTCP/UDP packets by port number or a port number
+range
+.IP
+ICMP packets by type/code
+.IP
+"established" TCP packets
+.IP
+On any arbitrary combination of TCP flags
+.IP
+"short" (fragmented) IP packets with incomplete headers can be filtered
+.IP
+any of the 19 IP options or 8 registered IP security classes TOS (Type of
+Service) field in packets
+.PP
+To keep track of the performance of the IP packet filter, a logging device
+is used which supports logging of:
+.IP
+the TCP/UDP/ICMP and IP packet headers
+.IP
+the first 128 bytes of the packet (including headers)
+.PP
+A packet can be logged when:
+.IP
+it is successfully passed through
+.IP
+it is blocked from passing through
+.IP
+it matches a rule setup to look for suspicious packets
+.PP
+IP Filter keeps its own set of statistics on:
+.IP
+packets blocked
+.IP
+packets (and bytes!) used for accounting
+.IP
+packets passed
+.IP
+packets logged
+.IP
+attempts to log which failed (buffer full)
+.IP
+and much more, for packets going both in and out.
+
+.SH Tools
+The current implementation provides a small set of tools, which can easily
+be used and integrated with regular unix shells and tools. A brief description
+of the tools provided:
+.PP
+ipf(8)
+reads in a set of rules, from either stdin or a file, and adds them to
+the kernels current list (appending them). It can also be used to flush the
+current filter set or delete individual filter rules. The file format is
+described in ipf(5).
+.PP
+ipfs(8)
+is a utility to temporarily lock the IP Filter kernel tables (state tables
+and NAT mappings) and write them to disk. After that the system can be
+rebooted, and ipfs can be used to read these tables from disk and restore
+them into the kernel. This way the system can be rebooted without the
+connections being terminated.
+.PP
+ipfstat(8)
+interrogates the kernel for statistics on packet filtering, so
+far, and retrieves the list of filters in operation for inbound and outbound
+packets.
+.PP
+ipftest(1)
+reads in a filter rule file and then applies sample IP packets to
+the rule file. This allows for testing of filter list and examination of how
+a packet is passed along through it.
+.PP
+ipmon(8)
+reads buffered data from the logging device (default is /dev/ipl)
+for output to either:
+.IP
+screen (standard output)
+.IP
+file
+.IP
+syslog
+.PP
+ipsend(1)
+generates arbitary IP packets for ethernet connected machines.
+.PP
+ipresend(1)
+reads in a data file of saved IP packets (ie
+snoop/tcpdump/etherfind output) and sends it back across the network.
+.PP
+iptest(1)
+contains a set of test "programs" which send out a series of IP
+packets, aimed at testing the strength of the TCP/IP stack at which it is
+aimed at. WARNING: this may crash machine(s) targeted!
+.PP
+ipnat(8)
+reads in a set of rules, from either stdin or a file and adds them
+to the kernels current list of active NAT rules. NAT rules can also be
+deleted using ipnat. The format of the configuration file to be used
+with ipnat is described in ipnat(5).
+.PP
+For use in your own programs (e.g. for writing of transparent application
+proxies), the programming interface and the associated ioctl's are
+documented in ipf(4).
+
+Documentation on ioctl's and the format of data saved
+to the logging character device is provided in ipl(4)
+so that you may develop your own applications to work with or in place of any
+of the above.
+
+Similar, the interface to the NAT code is documented in ipnat(4).
+
+.SH PACKET PROCESSING FLOW
+The following diagram illustrates the flow of TCP/IP packets through the
+various stages introduced by IP Filter.
+.PP
+.nf
+ IN
+ |
+ V
+ +-------------------------+--------------------------+
+ | | |
+ | V |
+ | Network Address Translation |
+ | | |
+ | authenticated | |
+ | +-------<---------+ |
+ | | | |
+ | | V |
+ | V IP Accounting |
+ | | | |
+ | | V |
+ | | Fragment Cache Check--+ |
+ | | | | |
+ | V V V |
+ | | Packet State Check-->+ |
+ | | | | |
+ | | +->--+ | | |
+ | | | | V | |
+ | V groups IP Filtering V |
+ | | | | | | |
+ | | +--<-+ | | |
+ | | | | |
+ | +---------------->|<-----------+ |
+ | | |
+ | V |
+ | +---<----+ |
+ | | | |
+ | function | |
+ | | V |
+ | +--->----+ |
+ | | |
+ | V |
+ +--|---<--- fast-route ---<--+ |
+ | | | |
+ | | V |
+ | +-------------------------+--------------------------+
+ | |
+ | pass only
+ | |
+ | V
+ V [KERNEL TCP/IP Processing]
+ | |
+ | +-------------------------+--------------------------+
+ | | | |
+ | | V |
+ | | Fragment Cache Check--+ |
+ | | | | |
+ | | V V |
+ | | Packet State Check-->+ |
+ | | | | |
+ | | V | |
+ V | IP Filtering | |
+ | | | V |
+ | | |<-----------+ |
+ | | V |
+ | | IP Accounting |
+ | | | |
+ | | V |
+ | | Network Address Translation |
+ | | | |
+ | | V |
+ | +-------------------------+--------------------------+
+ | |
+ | pass only
+ V |
+ +--------------------------->|
+ V
+ OUT
+.fi
+
+.SH MORE INFORMATION
+More information (including pointers to the FAQ and the mailing list) can be
+obtained from the sofware's official homepage: www.ipfilter.org
+
+.SH SEE ALSO
+ipf(4), ipf(5), ipf(8), ipfilter(5), ipfs(8), ipfstat(8), ipftest(1),
+ipl(4), ipmon(8), ipnat(8), ipnat(4),
+
diff --git a/contrib/ipfilter/man/ipfilter.4.mandoc b/contrib/ipfilter/man/ipfilter.4.mandoc
new file mode 100644
index 0000000..22e1f36
--- /dev/null
+++ b/contrib/ipfilter/man/ipfilter.4.mandoc
@@ -0,0 +1,267 @@
+.Dd December 8, 2000
+.Dt IP\ FILTER 4
+.Os
+.Sh NAME
+.Nm IP Filter
+.Nd Introduction to IP packet filtering
+.Sh DESCRIPTION
+IP Filter is a TCP/IP packet filter, suitable for use in a firewall
+environment. To use, it can either be used as a loadable kernel module or
+incorporated into your UNIX kernel; use as a loadable kernel module where
+possible is highly recommended. Scripts are provided to install and patch
+system files, as required.
+.Sh FEATURES
+The IP packet filter can:
+.Bl -bullet -offset indent -compact
+.It
+explicitly deny/permit any packet from passing through
+.It
+distinguish between various interfaces
+.It
+filter by IP networks or hosts
+.It
+selectively filter any IP protocol
+.It
+selectively filter fragmented IP packets
+.It
+selectively filter packets with IP options
+.It
+send back an ICMP error/TCP reset for blocked packets
+.It
+keep packet state information for TCP, UDP and ICMP packet flows
+.It
+keep fragment state information for any IP packet, applying the same rule
+to all fragments.
+.It
+act as a Network Address Translator (NAT)
+.It
+use redirection to setup true transparent proxy connections
+.It
+provide packet header details to a user program for authentication
+.It
+in addition, supports temporary storage of pre-authenticated rules for passing packets through
+.El
+.Pp
+Special provision is made for the three most common Internet protocols, TCP,
+UDP and ICMP. The IP Packet filter allows filtering of:
+.Bl -bullet -offset indent -compact
+.It
+Inverted host/net matchingTCP/UDP packets by port number or a port number
+range
+.It
+ICMP packets by type/code
+.It
+"established" TCP packets
+.It
+On any arbitrary combination of TCP flags
+.It
+"short" (fragmented) IP packets with incomplete headers can be filtered
+.It
+any of the 19 IP options or 8 registered IP security classes TOS (Type of
+Service) field in packets
+.El
+.Pp
+To keep track of the performance of the IP packet filter, a logging device
+is used which supports logging of:
+.Bl -bullet -offset indent -compact
+.It
+the TCP/UDP/ICMP and IP packet headers
+.It
+the first 128 bytes of the packet (including headers)
+.El
+.Pp
+A packet can be logged when:
+.Bl -bullet -offset indent -compact
+.It
+it is successfully passed through
+.It
+it is blocked from passing through
+.It
+it matches a rule setup to look for suspicious packets
+.El
+.Pp
+IP Filter keeps its own set of statistics on:
+.Bl -bullet -offset indent -compact
+.It
+packets blocked
+.It
+packets (and bytes!) used for accounting
+.It
+packets passed
+.li
+packets logged
+.It
+attempts to log which failed (buffer full)
+.El
+and much more, for packets going both in and out.
+
+.Sh Tools
+The current implementation provides a small set of tools, which can easily
+be used and integrated with regular unix shells and tools. A brief description
+of the tools provided:
+.Pp
+.Xr ipf 8
+reads in a set of rules, from either stdin or a file, and adds them to
+the kernels current list (appending them). It can also be used to flush the
+current filter set or delete individual filter rules. The file format is
+described in
+.Xr ipf 5 .
+.Pp
+.Xr ipfs 8
+is a utility to temporarily lock the IP Filter kernel tables (state tables
+and NAT mappings) and write them to disk. After that the system can be
+rebooted, and ipfs can be used to read these tables from disk and restore
+them into the kernel. This way the system can be rebooted without the
+connections being terminated.
+.Pp
+.Xr ipfstat 8
+interrogates the kernel for statistics on packet filtering, so
+far, and retrieves the list of filters in operation for inbound and outbound
+packets.
+.Pp
+.Xr ipftest 1
+reads in a filter rule file and then applies sample IP packets to
+the rule file. This allows for testing of filter list and examination of how
+a packet is passed along through it.
+.Pp
+.Xr ipmon 8
+reads buffered data from the logging device (default is /dev/ipl)
+for output to either:
+.Bl -bullet -offset indent -compact
+.It
+screen (standard output)
+.It
+file
+.It
+syslog
+.El
+.Pp
+.Xr ipsend 1
+generates arbitary IP packets for ethernet connected machines.
+.Pp
+.Xr ipresend 1
+reads in a data file of saved IP packets (ie
+snoop/tcpdump/etherfind output) and sends it back across the network.
+.Pp
+.Xr iptest 1
+contains a set of test "programs" which send out a series of IP
+packets, aimed at testing the strength of the TCP/IP stack at which it is
+aimed at. WARNING: this may crash machine(s) targeted!
+.Pp
+.Xr ipnat 8
+reads in a set of rules, from either stdin or a file and adds them
+to the kernels current list of active NAT rules. NAT rules can also be
+deleted using ipnat. The format of the configuration file to be used
+with ipnat is described in
+.Xr ipnat 5 .
+.Pp
+For use in your own programs (e.g. for writing of transparent application
+proxies), the programming interface and the associated ioctl's are
+documented in
+.Xr ipf 4 .
+
+Documentation on ioctl's and the format of data saved
+to the logging character device is provided in
+.Xr ipl 4
+so that you may develop your own applications to work with or in place of any
+of the above.
+
+Similar, the interface to the NAT code is documented in
+.Xr ipnat 4 .
+
+.Sh PACKET PROCESSING FLOW
+The following diagram illustrates the flow of TCP/IP packets through the
+various stages introduced by IP Filter.
+.Pp
+.nf
+ IN
+ |
+ V
+ +-------------------------+--------------------------+
+ | | |
+ | V |
+ | Network Address Translation |
+ | | |
+ | authenticated | |
+ | +-------<---------+ |
+ | | | |
+ | | V |
+ | V IP Accounting |
+ | | | |
+ | | V |
+ | | Fragment Cache Check--+ |
+ | | | | |
+ | V V V |
+ | | Packet State Check-->+ |
+ | | | | |
+ | | +->--+ | | |
+ | | | | V | |
+ | V groups IP Filtering V |
+ | | | | | | |
+ | | +--<-+ | | |
+ | | | | |
+ | +---------------->|<-----------+ |
+ | | |
+ | V |
+ | +---<----+ |
+ | | | |
+ | function | |
+ | | V |
+ | +--->----+ |
+ | | |
+ | V |
+ +--|---<--- fast-route ---<--+ |
+ | | | |
+ | | V |
+ | +-------------------------+--------------------------+
+ | |
+ | pass only
+ | |
+ | V
+ V [KERNEL TCP/IP Processing]
+ | |
+ | +-------------------------+--------------------------+
+ | | | |
+ | | V |
+ | | Fragment Cache Check--+ |
+ | | | | |
+ | | V V |
+ | | Packet State Check-->+ |
+ | | | | |
+ | | V | |
+ V | IP Filtering | |
+ | | | V |
+ | | |<-----------+ |
+ | | V |
+ | | IP Accounting |
+ | | | |
+ | | V |
+ | | Network Address Translation |
+ | | | |
+ | | V |
+ | +-------------------------+--------------------------+
+ | |
+ | pass only
+ V |
+ +--------------------------->|
+ V
+ OUT
+.fi
+
+.Sh MORE INFORMATION
+More information (including pointers to the FAQ and the mailing list) can be
+obtained from the sofware's official homepage: www.ipfilter.org
+
+.Sh SEE ALSO
+.Xr ipf 4 ,
+.Xr ipf 5 ,
+.Xr ipf 8 ,
+.Xr ipfilter 5 ,
+.Xr ipfs 8 ,
+.Xr ipfstat 8 ,
+.Xr ipftest 1 ,
+.Xr ipl 4 ,
+.Xr ipmon 8 ,
+.Xr ipnat 4 ,
+.Xr ipnat 8 ,
+
diff --git a/contrib/ipfilter/man/ipfilter.5 b/contrib/ipfilter/man/ipfilter.5
new file mode 100644
index 0000000..97e504d
--- /dev/null
+++ b/contrib/ipfilter/man/ipfilter.5
@@ -0,0 +1,11 @@
+.\" $FreeBSD$
+.TH IPFILTER 1
+.SH NAME
+IP Filter
+.SH DESCRIPTION
+.PP
+IP Filter is a package providing packet filtering capabilities for a variety
+of operating systems. On a properly setup system, it can be used to build a
+firewall.
+.SH SEE ALSO
+ipf(8), ipf(1), ipf(5), ipnat(8), ipnat(5), mkfilters(1)
diff --git a/contrib/ipfilter/man/ipfs.8 b/contrib/ipfilter/man/ipfs.8
new file mode 100644
index 0000000..01d0c70
--- /dev/null
+++ b/contrib/ipfilter/man/ipfs.8
@@ -0,0 +1,127 @@
+.\" $FreeBSD$
+.\"
+.TH IPFS 8
+.SH NAME
+ipfs \- saves and restores information for NAT and state tables.
+.SH SYNOPSIS
+.B ipfs
+[-nv] -l
+.PP
+.B ipfs
+[-nv] -u
+.PP
+.B ipfs
+[-nv] [
+.B \-d
+<\fIdirname\fP>
+] -R
+.PP
+.B ipfs
+[-nv] [
+.B \-d
+<\fIdirname\fP>
+] -W
+.PP
+.B ipfs
+[-nNSv] [
+.B \-f
+<\fIfilename\fP>
+] -r
+.PP
+.B ipfs
+[-nNSv] [
+.B \-f
+<\fIfilename\fP>
+] -w
+.PP
+.B ipfs
+[-nNSv]
+.B \-f
+<\fIfilename\fP>
+.B \-i
+<if1>,<if2>
+.SH DESCRIPTION
+.PP
+\fBipfs\fP allows state information created for NAT entries and rules using
+\fIkeep state\fP to be locked (modification prevented) and then saved to disk,
+allowing for the system to experience a reboot, followed by the restoration
+of that information, resulting in connections not being interrupted.
+.SH OPTIONS
+.TP
+.B \-d
+Change the default directory used with
+.B \-R
+and
+.B \-W
+options for saving state information.
+.TP
+.B \-n
+Don't actually take any action that would affect information stored in
+the kernel or on disk.
+.TP
+.B \-v
+Provides a verbose description of what's being done.
+.TP
+.B \-i <ifname1>,<ifname2>
+Change all instances of interface name ifname1 in the state save file to
+ifname2. Useful if you're restoring state information after a hardware
+reconfiguration or change.
+.TP
+.B \-N
+Operate on NAT information.
+.TP
+.B \-S
+Operate on filtering state information.
+.TP
+.B \-u
+Unlock state tables in the kernel.
+.TP
+.B \-l
+Lock state tables in the kernel.
+.TP
+.B \-r
+Read information in from the specified file and load it into the
+kernel. This requires the state tables to have already been locked
+and does not change the lock once complete.
+.TP
+.B \-w
+Write information out to the specified file and from the kernel.
+This requires the state tables to have already been locked
+and does not change the lock once complete.
+.TP
+.B \-R
+Restores all saved state information, if any, from two files,
+\fIipstate.ipf\fP and \fIipnat.ipf\fP, stored in the \fI/var/db/ipf\fP
+directory unless otherwise specified by the
+.B \-d
+option. The state tables are locked at the beginning of this
+operation and unlocked once complete.
+.TP
+.B \-W
+Saves in-kernel state information, if any, out to two files,
+\fIipstate.ipf\fP and \fIipnat.ipf\fP, stored in the \fI/var/db/ipf\fP
+directory unless otherwise specified by the
+.B \-d
+option. The state tables are locked at the beginning of this
+operation and unlocked once complete.
+.DT
+.SH FILES
+/var/db/ipf/ipstate.ipf
+.br
+/var/db/ipf/ipnat.ipf
+.br
+/dev/ipl
+.br
+/dev/ipstate
+.br
+/dev/ipnat
+.SH SEE ALSO
+ipf(8), ipl(4), ipmon(8), ipnat(8)
+.SH DIAGNOSTICS
+.PP
+Perhaps the -W and -R operations should set the locking but rather than
+undo it, restore it to what it was previously. Fragment table information
+is currently not saved.
+.SH BUGS
+.PP
+If you find any, please send email to me at darrenr@pobox.com
diff --git a/contrib/ipfilter/man/ipfstat.8 b/contrib/ipfilter/man/ipfstat.8
new file mode 100644
index 0000000..cea8d5f
--- /dev/null
+++ b/contrib/ipfilter/man/ipfstat.8
@@ -0,0 +1,194 @@
+.\" $FreeBSD$
+.TH ipfstat 8
+.SH NAME
+ipfstat \- reports on packet filter statistics and filter list
+.SH SYNOPSIS
+.B ipfstat
+[
+.B \-6aAdfghIilnoRsv
+]
+.br
+.B ipfstat -t
+[
+.B \-6C
+] [
+.B \-D
+<addrport>
+] [
+.B \-P
+<protocol>
+] [
+.B \-S
+<addrport>
+] [
+.B \-T
+<refresh time>
+]
+.SH DESCRIPTION
+\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/boot/kernel/kernel\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 \-6
+Display filter lists and states for IPv6, if available.
+.TP
+.B \-a
+Display the accounting filter list and show bytes counted against each rule.
+.TP
+.B \-A
+Display packet authentication statistics.
+.TP
+.B \-C
+This option is only valid in combination with \fB\-t\fP.
+Display "closed" states as well in the top. Normally, a TCP connection is
+not displayed when it reaches the CLOSE_WAIT protocol state. With this
+option enabled, all state entries are displayed.
+.TP
+.BR \-d
+Produce debugging output when displaying data.
+.TP
+.BR \-D \0<addrport>
+This option is only valid in combination with \fB\-t\fP. Limit the state top
+display to show only state entries whose destination IP address and port
+match the addrport argument. The addrport specification is of the form
+ipaddress[,port]. The ipaddress and port should be either numerical or the
+string "any" (specifying any IP address resp. any port). If the \fB\-D\fP
+option is not specified, it defaults to "\fB\-D\fP any,any".
+.TP
+.B \-f
+Show fragment state information (statistics) and held state information (in
+the kernel) if any is present.
+.TP
+.B \-g
+Show groups currently configured (both active and inactive).
+.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
+.BR \-P \0<protocol>
+This option is only valid in combination with \fB\-t\fP. Limit the state top
+display to show only state entries that match a specific protocol. The
+argument can be a protocol name (as defined in \fB/etc/protocols\fP) or a
+protocol number. If this option is not specified, state entries for any
+protocol are specified.
+.TP
+.BR \-R
+Don't try to resolve addresses to hostnames and ports to services while
+printing statistics.
+.TP
+.B \-s
+Show packet/flow state information (statistics only).
+.TP
+.B \-sl
+Show held state information (in the kernel) if any is present (no statistics).
+.TP
+.BR \-S \0<addrport>
+This option is only valid in combination with \fB\-t\fP. Limit the state top
+display to show only state entries whose source IP address and port match
+the addrport argument. The addrport specification is of the form
+ipaddress[,port]. The ipaddress and port should be either numerical or the
+string "any" (specifying any IP address resp. any port). If the \fB\-S\fP
+option is not specified, it defaults to "\fB\-S\fP any,any".
+.TP
+.B \-t
+Show the state table in a way similar to the way \fBtop(1)\fP shows the process
+table. States can be sorted using a number of different ways. This option
+requires \fBcurses(3)\fP and needs to be compiled in. It may not be available on
+all operating systems. See below, for more information on the keys that can
+be used while ipfstat is in top mode.
+.TP
+.BR \-T \0<refreshtime>
+This option is only valid in combination with \fB\-t\fP. Specifies how often
+the state top display should be updated. The refresh time is the number of
+seconds between an update. Any positive integer can be used. The default (and
+minimal update time) is 1.
+.TP
+.B \-v
+Turn verbose mode on. Displays more debugging information. When used with
+either \fB-i\fP or \fB-o\fP, counters associated with the rule, such as the
+number of times it has been matched and the number of bytes from such packets
+is displayed. For "keep state" rules, a count of the number of state sessions
+active against the rule is also displayed.
+.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.
+.PP
+One of the statistics that \fBipfstat\fP shows is \fBticks\fP.
+This number indicates how long the filter has been enabled.
+The number is incremented every half\-second.
+.SH STATE TOP
+Using the \fB\-t\fP option \fBipfstat\fP will enter the state top mode. In
+this mode the state table is displayed similar to the way \fBtop\fP displays
+the process table. The \fB\-C\fP, \fB\-D\fP, \fB\-P\fP, \fB\-S\fP and \fB\-T\fP
+command line options can be used to restrict the state entries that will be
+shown and to specify the frequency of display updates.
+.PP
+In state top mode, the following keys can be used to influence the displayed
+information:
+.TP
+\fBb\fP show packets/bytes from backward direction.
+.TP
+\fBf\fP show packets/bytes from forward direction. (default)
+.TP
+\fBl\fP redraw the screen.
+.TP
+\fBq\fP quit the program.
+.TP
+\fBs\fP switch between different sorting criterion.
+.TP
+\fBr\fP reverse the sorting criterion.
+.PP
+States can be sorted by protocol number, by number of IP packets, by number
+of bytes and by time-to-live of the state entry. The default is to sort by
+the number of bytes. States are sorted in descending order, but you can use
+the \fBr\fP key to sort them in ascending order.
+.SH STATE TOP LIMITATIONS
+It is currently not possible to interactively change the source, destination
+and protocol filters or the refresh frequency. This must be done from the
+command line.
+.PP
+The screen must have at least 80 columns. This is however not checked.
+When running state top in IPv6 mode, the screen must be much wider to display
+the very long IPv6 addresses.
+.PP
+Only the first X-5 entries that match the sort and filter criteria are
+displayed (where X is the number of rows on the display. The only way to see
+more entries is to resize the screen.
+.SH FILES
+/dev/kmem
+.br
+/dev/ipl
+.br
+/dev/ipstate
+.br
+/kernel
+.SH SEE ALSO
+ipf(8)
+.SH BUGS
+none known.
diff --git a/contrib/ipfilter/man/ipftest.1 b/contrib/ipfilter/man/ipftest.1
new file mode 100644
index 0000000..10232d3
--- /dev/null
+++ b/contrib/ipfilter/man/ipftest.1
@@ -0,0 +1,205 @@
+.\" $FreeBSD$
+.TH ipftest 1
+.SH NAME
+ipftest \- test packet filter rules with arbitrary input.
+.SH SYNOPSIS
+.B ipftest
+[
+.B \-6bCdDoRvx
+] [
+.B \-F
+input-format
+] [
+.B \-i
+<filename>
+] [
+.B \-I
+interface
+] [
+.B \-l
+<filename>
+] [
+.B \-N
+<filename>
+] [
+.B \-P
+<filename>
+] [
+.B \-r
+<filename>
+] [
+.B \-S
+<ip_address>
+] [
+.B \-T
+<optionlist>
+]
+.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,
+\fBipnat\fP and/or \fBippool\fP
+and apply input, returning output as to the result. However, \fBipftest\fP
+will return one of three values for packets passed through the filter:
+pass, block or nomatch. This is intended to give the operator a better
+idea of what is happening with packets passing through their filter
+ruleset.
+.PP
+At least one of \fB\-N\fP, \fB-P\fP or \fB\-r\fP must be specified.
+.SH OPTIONS
+.TP
+.B \-6
+Use IPv6.
+.TP
+.B \-b
+Cause the output to be a brief summary (one-word) of the result of passing
+the packet through the filter; either "pass", "block" or "nomatch".
+This is used in the regression testing.
+.TP
+.B \-C
+Force the checksums to be (re)calculated for all packets being input into
+\fBipftest\fP. This may be necessary if pcap files from tcpdump are being
+fed in where there are partial checksums present due to hardware offloading.
+.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 \-D
+Dump internal tables before exiting.
+This excludes log messages.
+.TP
+.B \-F
+This option is used to select which input format the input file is in.
+The following formats are available: etherfind, hex, pcap, snoop, tcpdump,text.
+.RS
+.TP
+.B etherfind
+The input file is to be text output from etherfind. The text formats which
+are currently supported are those which result from the following etherfind
+option combinations:
+.PP
+.nf
+ etherfind -n
+ etherfind -n -t
+.fi
+.TP
+.B hex
+The input file is to be hex digits, representing the binary makeup of the
+packet. No length correction is made, if an incorrect length is put in
+the IP header. A packet may be broken up over several lines of hex digits,
+a blank line indicating the end of the packet. It is possible to specify
+both the interface name and direction of the packet (for filtering purposes)
+at the start of the line using this format: [direction,interface] To define
+a packet going in on le0, we would use \fB[in,le0]\fP - the []'s are required
+and part of the input syntax.
+.HP
+.B pcap
+The input file specified by \fB\-i\fP is a binary file produced using libpcap
+(i.e., tcpdump version 3). Packets are read from this file as being input
+(for rule purposes). An interface maybe specified using \fB\-I\fP.
+.TP
+.B snoop
+The input file is to be in "snoop" format (see RFC 1761). Packets are read
+from this file and used as input from any interface. This is perhaps the
+most useful input type, currently.
+.TP
+.B tcpdump
+The input file is to be text output from tcpdump. The text formats which
+are currently supported are those which result from the following tcpdump
+option combinations:
+.PP
+.nf
+ tcpdump -n
+ tcpdump -nq
+ tcpdump -nqt
+ tcpdump -nqtt
+ tcpdump -nqte
+.fi
+.TP
+.B text
+The input file is in \fBipftest\fP text input format.
+This is the default if no \fB\-F\fP argument is specified.
+The format used is as follows:
+.nf
+ "in"|"out" "on" if ["tcp"|"udp"|"icmp"]
+ srchost[,srcport] dsthost[,destport] [FSRPAU]
+.fi
+.PP
+This allows for a packet going "in" or "out" of an interface (if) to be
+generated, being one of the three main protocols (optionally), and if
+either TCP or UDP, a port parameter is also expected. If TCP is selected,
+it is possible to (optionally) supply TCP flags at the end. Some examples
+are:
+.nf
+ # 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
+.RE
+.DT
+.TP
+.BR \-i \0<filename>
+Specify the filename from which to take input. Default is stdin.
+.TP
+.BR \-I \0<interface>
+Set the interface name (used in rule matching) to be the name supplied.
+This is useful where it is
+not otherwise possible to associate a packet with an interface. Normal
+"text packets" can override this setting.
+.TP
+.BR \-l \0<filename>
+Dump log messages generated during testing to the specified file.
+.TP
+.BR \-N \0<filename>
+Specify the filename from which to read NAT rules in \fBipnat\fP(5) format.
+.TP
+.B \-o
+Save output packets that would have been written to each interface in
+a file /tmp/\fIinterface_name\fP in raw format.
+.TP
+.BR \-P \0<filename>
+Read IP pool configuration information in \fBippool\fP(5) format from the
+specified file.
+.TP
+.BR \-r \0<filename>
+Specify the filename from which to read filter rules in \fBipf\fP(5) format.
+.TP
+.B \-R
+Don't attempt to convert IP addresses to hostnames.
+.TP
+.BR \-S \0<ip_address>
+The IP address specifived with this option is used by ipftest to determine
+whether a packet should be treated as "input" or "output". If the source
+address in an IP packet matches then it is considered to be inbound. If it
+does not match then it is considered to be outbound. This is primarily
+for use with tcpdump (pcap) files where there is no in/out information
+saved with each packet.
+.TP
+.BR \-T \0<optionlist>
+This option simulates the run-time changing of IPFilter kernel variables
+available with the \fB\-T\fP option of \fBipf\fP.
+The optionlist parameter is a comma separated list of tuning
+commands. A tuning command is either "list" (retrieve a list of all variables
+in the kernel, their maximum, minimum and current value), a single variable
+name (retrieve its current value) and a variable name with a following
+assignment to set a new value. See \fBipf\fP(8) for examples.
+.TP
+.B \-v
+Verbose mode. This provides more information about which parts of rule
+matching the input packet passes and fails.
+.TP
+.B \-x
+Print a hex dump of each packet before printing the decoded contents.
+.SH SEE ALSO
+ipf(5), ipf(8), snoop(1m), tcpdump(8), etherfind(8c)
+.SH BUGS
+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..da1d9e6
--- /dev/null
+++ b/contrib/ipfilter/man/ipl.4
@@ -0,0 +1,81 @@
+.\" $FreeBSD$
+.\"
+.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. If the log reader
+is busy or otherwise unable to read log records, up to IPLLOGSIZE (8192 is the
+default) bytes of data are stored.
+.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
+/*
+ * Log structure. Each packet header logged is prepended by one of these.
+ * Following this in the log records read from the device will be an ipflog
+ * structure which is then followed by any packet data.
+ */
+typedef struct iplog {
+ u_long ipl_sec;
+ u_long ipl_usec;
+ u_int ipl_len;
+ u_int ipl_count;
+ size_t ipl_dsize;
+ struct iplog *ipl_next;
+} iplog_t;
+
+
+typedef struct ipflog {
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603))
+ u_char fl_ifname[IFNAMSIZ];
+#else
+ u_int fl_unit;
+ u_char fl_ifname[4];
+#endif
+ u_char fl_plen; /* extra data after hlen */
+ u_char fl_hlen; /* length of IP headers saved */
+ u_short fl_rule; /* assume never more than 64k rules, total */
+ u_32_t fl_flags;
+} ipflog_t;
+
+.fi
+.PP
+When reading from the \fBipl\fP device, it is necessary to call read(2) with
+a buffer big enough to hold at least 1 complete log record - reading of partial
+log records is not supported.
+.PP
+If the packet contents are more than 128 bytes when \fBlog body\fP is used,
+then only 128 bytes of the packet contents are logged.
+.PP
+Although it is only possible to read from the \fBipl\fP device, opening it
+for writing is required when using an ioctl which changes any kernel data.
+.PP
+The ioctls which are loaded with this device can be found under \fBipf(4)\fP.
+The ioctls which are for use with logging and don't affect the filter are:
+.LP
+.nf
+ ioctl(fd, SIOCIPFFB, int *)
+ ioctl(fd, FIONREAD, int *)
+.fi
+.PP
+The SIOCIPFFB ioctl flushes the log buffer and returns the number of bytes
+flushed. FIONREAD returns the number of bytes currently used for storing
+log data. If IPFILTER_LOG is not defined when compiling, SIOCIPFFB is not
+available and FIONREAD will return but not do anything.
+.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.5 b/contrib/ipfilter/man/ipmon.5
new file mode 100644
index 0000000..95126f0
--- /dev/null
+++ b/contrib/ipfilter/man/ipmon.5
@@ -0,0 +1,226 @@
+.\" $FreeBSD$
+.\"
+.TH IPMON 5
+.SH NAME
+ipmon, ipmon.conf \- ipmon configuration file format
+.SH DESCRIPTION
+The
+.B ipmon.conf
+file is optionally loaded by
+.B ipmon
+when it starts. Its primary purpose is to direct
+.B ipmon
+to do extra actions when it sees a specific log entry from the kernel.
+.PP
+A line in the
+.B ipmon.conf
+file is either a comment or a
+.B match
+line. Each line must have a matching segment and an action segment.
+These are to the left and right of the word "do", respectively.
+A comment line is any line that starts with a #.
+.PP
+.B NOTE:
+This file differs from all other IPFilter configuration files because it
+attempts to match every line with every log record received. It does
+.B not
+stop at the
+.B first
+match or only use the
+.B last
+match.
+.PP
+For the action segment, a
+.B match
+line can delivery output to one of three destinations:
+\fBfile\fR, \fBemail\fR or \fBcommand\fR. For example:
+.nf
+
+match { type = ipf; } do { save("file:///var/log/ipf-log"); };
+match { type = nat; } do { syslog; };
+match { type = state; } do { execute("/bin/mail root"); };
+.fi
+.PP
+and is roughly described like this:
+.PP
+match { \fImatch-it ,match-it, ...\fP } do { \fIaction, action, ...\fP};
+.PP
+where there can be a list of matching expressions and a list of actions
+to perform if all of the matching expressions are matched up with by
+the current log entry.
+.PP
+The lines above would save all ipf log entries to /var/log/ipf-log, send
+all of the entries for NAT (ipnat related) to syslog and generate an email
+to root for each log entry from the state tables.
+.SH SYNTAX - MATCHING
+.PP
+In the above example, the matching segment was confined to matching on
+the type of log entry generated. The full list of fields that can be
+used here is:
+.TP
+direction <in|out>
+This option is used to match on log records generated for packets going
+in or out.
+.TP
+dstip <address/mask>
+This option is used to match against the destination address associated
+with the packet being logged. A "/mask" must be given and given in CIDR
+notation (/0-/32) so to specify host 192.2.2.1, 192.2.2.1/32 must be given.
+.TP
+dstport <portnumber>
+This option is used to match against the destination port in log entries.
+A number must be given, symbolic names (such as those from /etc/services)
+are not recognised by the parser.
+.TP
+every <second|# seconds|packet|# packets>
+This option is used to regulate how often an \fBipmon.conf\fR entry is
+actioned in response to an otherwise matching log record from the kernel.
+.TP
+group <name|number>
+.TP
+interface <interface-name>
+This option is used to match against the network interface name associated
+with the action causing the logging to happen. In general this will be the
+network interface where the packet is seen by IPFilter.
+.TP
+logtag <number>
+This option is used to match against tags set by ipf rules in \fBipf.conf\fR.
+These tags are set with "set-tag(log=100)" appended to filter rules.
+.TP
+nattag <string>
+This option is used to match against tags set by NAT rules in \fBipnat.conf\fR.
+.TP
+protocol <name|number>
+This option is used to match against the IP protocol field in the packet
+being logged.
+.TP
+result <pass|block|nomatch|log>
+This option is used to match against the result of packet matching in the
+kernel. If a packet is logged, using a \fBlog\fR rule in \fBipf.conf\fR
+then it will match "log" here. The "nomatch" option is for use with
+matching log records generated for all packets as the default.
+.TP
+rule <number>
+This option is used to match against the \fInumber\fR of the rule
+causing the record to be generated. The \fInumber\fR of a rule can be
+observed using "ipfstat -ion".
+.TP
+srcip <address/mask>
+This option is used to match against the source address associated
+with the packet being logged. A "/mask" must be given and given in CIDR
+notation (/0-/32) so to specify host 192.2.2.1, 192.2.2.1/32 must be given.
+.TP
+srcport <portnumber>
+This option is used to match against the source port in log entries.
+A number must be given, symbolic names (such as those from /etc/services)
+are not recognised by the parser.
+.TP
+type <ipf|nat|state>
+The format for files accepted by ipmon is described by the following grammar:
+.B NOTE:
+At present, only IPv4 matching is available for source/destination address
+matching.
+.SH SYNTAX - ACTIONS
+The list of actions supported is as follows:
+.TP
+save("file://<filename>")
+save("raw://<filename>")
+Write out the log record to the filename given. This file will be closed
+and reopened on receipt of a SIGHUP. If the \fIraw\fP target is used,
+binary log data, as read from the kernel, is written out rather than a
+text log record. The filename should be an absolute target, including
+the root directory. Thus, saving to /var/log/ipmon.log would be, as an
+example, save("file:///var/log/ipmon.log").
+.TP
+syslog("<facility>.<priority>")
+syslog("<facility>.")
+syslog(".<priority>")
+To log a text record via syslog, the \fBsyslog\fP action word is used.
+The facility used by default is determined at first by the default
+compiled into \fBipmon\fP (usually LOG_LOCAL0), which can be changed
+via the command line (-L <facility>) or in an \fBipf.conf\fP rule
+using the \fIlevel\fP option with logging. If the facility is
+specified here, it takes precedence over all other settings.
+The same applies to the syslog priority. By default, ipmon will
+determine a priority for the packet, depending on whether or not it
+has been blocked, passed, etc. It is possible to force the complete
+facility/priority value for each log entry or to choose to replace
+only one of them.
+.TP
+execute("<command string>")
+The
+.B execute
+action runs the specified command each time the log entry matches
+and feeds the log entry, as text, to the command being executed.
+The command string given is executed using /bin/sh.
+.TP
+nothing
+Literally, do nothing. Use this if you want to be verbose in your config
+file about doing nothing for a particular log record.
+.SH PLUGIN ACTIONS
+It is possible to configure
+.B ipmon
+to use externally supplied modules to save log entries with.
+These are added to
+.B ipmon
+using the
+.I load_action
+configuration line. The syntax of this line is:
+.nf
+
+load_action <name> <path>;
+.fi
+.TP
+name
+is a short name for the action. It does not need to correspond to the
+name of the library file, but inside the library file, the functions
+.B <name>destroy
+,
+.B <name>parse
+and
+.B <name>store
+must be present.
+.TP
+path
+specifies the path in the filesystem to the shared object
+that contains the implementation of the new action. After the new
+action has been declared using
+.I load_action
+it can then be used in any
+.I do
+statement.
+.SH EXAMPLES
+.PP
+Some further examples are:
+.nf
+
+#
+# log everything to syslog local4, regardless
+#
+match { ; } do { syslog("local4."); };
+#
+# keep a local copy of things packets to/from port 80
+#
+match { srcport = 80; } do { save("file:///var/log/web"); };
+match { dstport = 80; } do { save("file:///var/log/web"); };
+#
+load_action local "/usr/lib/libmyaction.so";
+match { dstip 127.0.0.1; } do { local("local options"); };
+#
+.fi
+.SH MATCHING
+.PP
+All entries of the rules present in the file are
+compared for matches - there is no first or last rule match.
+.SH FILES
+/dev/ipl
+.br
+/dev/ipf
+.br
+/dev/ipnat
+.br
+/dev/ipstate
+.br
+/etc/ipmon.conf
+.SH SEE ALSO
+ipmon(8), ipl(4)
diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8
new file mode 100644
index 0000000..126f4a7
--- /dev/null
+++ b/contrib/ipfilter/man/ipmon.8
@@ -0,0 +1,186 @@
+.\" $FreeBSD$
+.TH ipmon 8
+.SH NAME
+ipmon \- monitors /dev/ipl for logged packets
+.SH SYNOPSIS
+.B ipmon
+[
+.B \-abBDFhnpstvxX
+] [
+.B "\-N <device>"
+] [
+.B "\-L <facility>"
+] [
+.B "\-o [NSI]"
+] [
+.B "\-O [NSI]"
+] [
+.B "\-P <pidfile>"
+] [
+.B "\-S <device>"
+] [
+.B "\-f <device>"
+] [
+.B <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.
+.LP
+Messages generated by ipmon consist of whitespace separated fields.
+Fields common to all messages are:
+.LP
+1. The date of packet receipt. This is suppressed when the message is
+sent to syslog.
+.LP
+2. The time of packet receipt. This is in the form HH:MM:SS.F, for hours,
+minutes seconds, and fractions of a second (which can be several digits
+long).
+.LP
+3. The name of the interface the packet was processed on, e.g., \fBwe1\fP.
+.LP
+4. The group and rule number of the rule, e.g., \fB@0:17\fP. These can be
+viewed with \fBipfstat -n\fP.
+.LP
+5. The action: \fBp\fP for passed, \fBb\fP for blocked, \fB\fP for a short
+packet, \fBn\fP did not match any rules or \fBL\fP for a log rule.
+.LP
+6. The addresses.
+This is actually three fields: the source address and port
+(separated by a comma), the \fB->\fP symbol, and the destination address
+and port. E.g.: \fB209.53.17.22,80 -> 198.73.220.17,1722\fP.
+.LP
+7. \fBPR\fP followed by the protocol name or number, e.g., \fBPR tcp\fP.
+.LP
+8. \fBlen\fP followed by the header length and total length of the packet,
+e.g., \fBlen 20 40\fP.
+.LP
+If the packet is a TCP packet, there will be an additional field starting
+with a hyphen followed by letters corresponding to any flags that were set.
+See the ipf.conf manual page for a list of letters and their flags.
+.LP
+If the packet is an ICMP packet, there will be two fields at the end,
+the first always being `icmp', and the next being the ICMP message and
+submessage type, separated by a slash, e.g., \fBicmp 3/3\fP for a port
+unreachable message.
+.LP
+In order for \fBipmon\fP to properly work, the kernel option
+\fBIPFILTER_LOG\fP must be turned on in your kernel. Please see
+\fBoptions(4)\fP for more details.
+.LP
+\fBipmon\fP reopens its log file(s) and rereads its configuration file
+when it receives a SIGHUP signal.
+.SH OPTIONS
+.TP
+.B \-a
+Open all of the device logfiles for reading log entries from. All entries
+are displayed to the same output 'device' (stderr or syslog).
+.TP
+.B \-b
+For rules which log the body of a packet, generate hex output representing
+the packet contents after the headers.
+.TP
+.B \-B <binarylogfilename>
+Enable logging of the raw, unformatted binary data to the specified
+\fI<binarylogfilename>\fP file. This can be read, later, using \fBipmon\fP
+with the \fB-f\fP option.
+.TP
+.B \-D
+Cause ipmon to turn itself into a daemon. Using subshells or backgrounding
+of ipmon is not required to turn it into an orphan so it can run indefinitely.
+.TP
+.B "\-f <device>"
+specify an alternative device/file from which to read the log information
+for normal IP Filter log records.
+.TP
+.B \-F
+Flush the current packet log buffer. The number of bytes flushed is displayed,
+even should the result be zero.
+.TP
+.B \-L <facility>
+Using this option allows you to change the default syslog facility that
+ipmon uses for syslog messages. The default is local0.
+.TP
+.B \-n
+IP addresses and port numbers will be mapped, where possible, back into
+hostnames and service names.
+.TP
+.B "\-N <device>"
+Set the logfile to be opened for reading NAT log records from to <device>.
+.TP
+.B \-o
+Specify which log files to actually read data from. N - NAT logfile,
+S - State logfile, I - normal IP Filter logfile. The \fB-a\fP option is
+equivalent to using \fB-o NSI\fP.
+.TP
+.B \-O
+Specify which log files you do not wish to read from. This is most sensibly
+used with the \fB-a\fP. Letters available as parameters to this are the same
+as for \fB-o\fP.
+.TP
+.B \-p
+Cause the port number in log messages to always be printed as a number and
+never attempt to look it up as from \fI/etc/services\fP, etc.
+.TP
+.B \-P <pidfile>
+Write the pid of the ipmon process to a file. By default this is
+\fI//etc/opt/ipf/ipmon.pid\fP (Solaris), \fI/var/run/ipmon.pid\fP (44BSD
+or later) or \fI/etc/ipmon.pid\fP for all others.
+.TP
+.B \-s
+Packet information read in will be sent through syslogd rather than
+saved to a file. The default facility when compiled and installed is
+\fBsecurity\fP. 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 "\-S <device>"
+Set the logfile to be opened for reading state log records from to <device>.
+.TP
+.B \-t
+read the input file/device in a manner akin to tail(1).
+.TP
+.B \-v
+show tcp window, ack and sequence fields.
+.TP
+.B \-x
+show the packet data in hex.
+.TP
+.B \-X
+show the log header record data in hex.
+.SH DIAGNOSTICS
+\fBipmon\fP expects data that it reads to be consistent with how it should be
+saved and will abort if it fails an assertion which detects an anomaly in the
+recorded data.
+.SH FILES
+/dev/ipl
+.br
+/dev/ipnat
+.br
+/dev/ipstate
+.br
+/etc/services
+.SH SEE ALSO
+ipl(4), ipf(8), ipfstat(8), ipnat(8)
+.SH BUGS
+.PP
+If you find any, please send email to me at darrenr@pobox.com
diff --git a/contrib/ipfilter/man/ipnat.1 b/contrib/ipfilter/man/ipnat.1
new file mode 100644
index 0000000..f241415
--- /dev/null
+++ b/contrib/ipfilter/man/ipnat.1
@@ -0,0 +1,48 @@
+.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 rule listing (NAT rules)
+.TP
+.B \-F
+delete all active entries in the current NAT translation 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
+and active rules/table entries.
+.DT
+.SH FILES
+/dev/ipnat
+.SH SEE ALSO
+ipnat(5), ipf(8), ipfstat(8)
diff --git a/contrib/ipfilter/man/ipnat.4 b/contrib/ipfilter/man/ipnat.4
new file mode 100644
index 0000000..80c5ba4
--- /dev/null
+++ b/contrib/ipfilter/man/ipnat.4
@@ -0,0 +1,97 @@
+.\" $FreeBSD$
+.TH IPNAT 4
+.SH NAME
+ipnat \- Network Address Translation kernel interface
+.SH SYNOPSIS
+#include <netinet/ip_compat.h>
+.br
+#include <netinet/ip_fil.h>
+.br
+#include <netinet/ip_proxy.h>
+.br
+#include <netinet/ip_nat.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 **)
+ ioctl(fd, SIOCGNATS, struct natstat **)
+ ioctl(fd, SIOCGNATL, struct natlookup **)
+.fi
+.PP
+Unlike \fBipf(4)\fP, there is only a single list supported by the kernel NAT
+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).
+.PP
+The structure 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
+.LP
+\fBNAT statistics\fP
+Statistics on 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 FILES
+/dev/ipnat
+.SH SEE ALSO
+ipf(4), ipnat(5), ipf(8), ipnat(8), ipfstat(8)
diff --git a/contrib/ipfilter/man/ipnat.5 b/contrib/ipfilter/man/ipnat.5
new file mode 100644
index 0000000..69163fc
--- /dev/null
+++ b/contrib/ipfilter/man/ipnat.5
@@ -0,0 +1,728 @@
+.\" $FreeBSD$
+.\"
+.TH IPNAT 5
+.SH NAME
+ipnat, ipnat.conf \- IPFilter NAT file format
+.SH DESCRIPTION
+.PP
+The
+.B ipnat.conf
+file is used to specify rules for the Network Address Translation (NAT)
+component of IPFilter. To load rules specified in the
+.B ipnat.conf
+file, the
+.B ipnat(8)
+program is used.
+.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. Following this it is expected that the old source
+address, and optionally port number, will be specified.
+.PP
+In general, all NAT rules conform to the following layout:
+the first word indicates what type of NAT rule is present, this is followed
+by some stanzas to match a packet, followed by a "->" and this is then
+followed by several more stanzas describing the new data to be put in the
+packet.
+.PP
+In this text and in others,
+use of the term "left hand side" (LHS) when talking about a NAT rule refers
+to text that appears before the "->" and the "right hand side" (RHS) for text
+that appears after it. In essence, the LHS is the packet matching and the
+RHS is the new data to be used.
+.SH VARIABLES
+.PP
+This configuration file, like all others used with IPFilter, supports the
+use of variable substitution throughout the text.
+.nf
+
+nif="ppp0";
+map $nif 0/0 -> 0/32
+.fi
+.PP
+would become
+.nf
+
+map ppp0 0/0 -> 0/32
+.fi
+.PP
+Variables can be used recursively, such as 'foo="$bar baz";', so long as
+$bar exists when the parser reaches the assignment for foo.
+.PP
+See
+.B ipnat(8)
+for instructions on how to define variables to be used from a shell
+environment.
+.SH OUTBOUND SOURCE TRANSLATION (map'ing)
+Changing the source address of a packet is traditionally performed using
+.B map
+rules. Both the source address and optionally port number can be changed
+according to various controls.
+.PP
+To start out with, a common rule used is of the form:
+.nf
+
+map le0 0/0 -> 0/32
+.fi
+.PP
+Here we're saying change the source address of all packets going out of
+le0 (the address/mask pair of 0/0 matching all packets) to that of the
+interface le0 (0/32 is a synonym for the interface's own address at
+the current point in time.) If we wanted to pass the packet through
+with no change in address, we would write it as:
+.nf
+
+map le0 0/0 -> 0/0
+.fi
+.PP
+If we only want to change a portion of our internal network and to a
+different address that is routed back through this host, we might do:
+.nf
+
+map le0 10.1.1.0/24 -> 192.168.55.3/32
+.fi
+.PP
+In some instances, we may have an entire subnet to map internal addresses
+out onto, in which case we can express the translation as this:
+.nf
+
+map le0 10.0.0.0/8 -> 192.168.55.0/24
+.fi
+.PP
+IPFilter will cycle through each of the 256 addresses in the 192.168.55.0/24
+address space to ensure that they all get used.
+.PP
+Of course this poses a problem for TCP and UDP, with many connections made,
+each with its own port number pair. If we're unlucky, translations can be
+dropped because the new address/port pair mapping already exists. To
+mitigate this problem, we add in port translation or port mapping:
+.nf
+
+map le0 10.0.0.0/8 -> 192.168.55.0/24 portmap tcp/udp auto
+.fi
+.PP
+In this instance, the word "auto" tells IPFilter to calculate a private
+range of port numbers for each address on the LHS to use without fear
+of them being trampled by others. This can lead to problems if there are
+connections being generated mire quickly than IPFilter can expire them.
+In this instance, and if we want to get away from a private range of
+port numbers, we can say:
+.nf
+
+map le0 10.0.0.0/8 -> 192.168.55.0/24 portmap tcp/udp 5000:65000
+.fi
+.PP
+And now each connection through le0 will add to the enumeration of
+the port number space 5000-65000 as well as the IP address subnet
+of 192.168.55.0/24.
+.PP
+If the new addresses to be used are in a consecutive range, rather
+than a complete subnet, we can express this as:
+.nf
+
+map le0 10.0.0.0/8 -> range 192.168.55.10-192.168.55.249
+ portmap tcp/udp 5000:65000
+.fi
+.PP
+This tells IPFilter that it has a range of 240 IP address to use, from
+192.168.55.10 to 192.168.55.249, inclusive.
+.PP
+If there were several ranges of addresses for use, we can use each one
+in a round-robin fashion as followed:
+.nf
+
+map le0 10.0.0.0/8 -> range 192.168.55.10-192.168.55.29
+ portmap tcp/udp 5000:65000 round-robin
+map le0 10.0.0.0/8 -> range 192.168.55.40-192.168.55.49
+ portmap tcp/udp 5000:65000 round-robin
+.fi
+.PP
+To specify translation rules that impact a specific IP protocol,
+the protocol name or number is appended to the rule like this:
+.nf
+
+map le0 10.0.0.0/8 -> 192.168.55.0/24 tcp/udp
+map le0 10.0.0.0/8 -> 192.168.55.1/32 icmp
+map le0 10.0.0.0/8 -> 192.168.55.2/32 gre
+.fi
+.PP
+For TCP connections exiting a connection such as PPPoE where the MTU is
+slightly smaller than normal ethernet, it can be useful to reduce the
+Maximum Segment Size (MSS) offered by the internal machines to match,
+reducing the liklihood that the either end will attempt to send packets
+that are too big and result in fragmentation. This is acheived using the
+.B mssclamp
+option with TCP
+.B map
+rules like this:
+.nf
+
+map pppoe0 0/0 -> 0/32 mssclamp 1400 tcp
+.fi
+.PP
+For ICMP packets, we can map the ICMP id space in query packets:
+.nf
+
+map le0 10.0.0.0/8 -> 192.168.55.1/32 icmpidmap icmp 1000:20000
+.fi
+.PP
+If we wish to be more specific about our initial matching criteria on the
+LHS, we can expand to using a syntax more similar to that in
+.B ipf.conf(5)
+:
+.nf
+
+map le0 from 10.0.0.0/8 to 26.0.0.0/8 ->
+ 192.168.55.1
+map le0 from 10.0.0.0/8 port > 1024 to 26.0.0.0/8 ->
+ 192.168.55.2 portmap 5000:9999 tcp/udp
+map le0 from 10.0.0.0/8 ! to 26.0.0.0/8 ->
+ 192.168.55.3 portmap 5000:9999 tcp/udp
+.fi
+.TP
+.B NOTE:
+negation matching with source addresses is
+.B NOT
+possible with
+.B map
+/
+.B map-block
+rules.
+.PP
+The NAT code has builtin default timeouts for TCP, UDP, ICMP and another
+for all other protocols. In general, the timeout for an entry to be
+deleted shrinks once a reply packet has been seen (excluding TCP.)
+If you wish to specify your own timeouts, this can be achieved either
+by setting one timeout for both directions:
+.nf
+
+map le0 0/0 -> 0/32 gre age 30
+.fi
+.PP
+or setting a different timeout for the reply:
+.nf
+
+map le0 from any to any port = 53 -> 0/32 age 60/10 udp
+.fi
+.PP
+A pressing problem that many people encounter when using NAT is that the
+address protocol can be embedded inside an application's communication.
+To address this problem, IPFilter provides a number of built-in proxies
+for the more common trouble makers, such as FTP. These proxies can be
+used as follows:
+.nf
+
+map le0 0/0 -> 0/32 proxy port 21 ftp/tcp
+.fi
+.PP
+In this rule, the word "proxy" tells us that we want to connect up this
+translation with an internal proxy. The "port 21" is an extra restriction
+that requires the destination port number to be 21 if this rule is to be
+activated. The word "ftp" is the proxy identifier that the kernel will
+try and resolve internally, "tcp" the protocol that packets must match.
+.PP
+See below for a list of proxies and their relative staus.
+.PP
+To associate NAT rules with filtering rules, it is possible to set and
+match tags during either inbound or outbound processing. At present the
+tags for forwarded packets are not preserved by forwarding, so once the
+packet leaves IPFilter, the tag is forgotten. For
+.B map
+rules, we can match tags set by filter rules like this:
+.nf
+
+map le0 0/0 -> 0/32 proxy portmap 5000:5999 tag lan1 tcp
+.fi
+.PP
+This would be used with "pass out" rules that includes a stanza such
+as "set-tag (nat = lan1)".
+.PP
+If the interface in which packets are received is different from the
+interface on which packets are sent out, then the translation rule needs
+to be written to take this into account:
+.nf
+
+map hme0,le0 0/0 -> 0/32
+.fi
+.PP
+Although this might seem counterintuitive, the interfaces when listed
+in rules for
+.B ipnat.conf
+are always in the
+.I inbound
+,
+.I outbound
+order. In this case, hme0 would be the return interface and le0 would be
+the outgoing interface. If you wish to allow return packets on any
+interface, the correct syntax to use would be:
+.nf
+
+map *,le0 0/0 -> 0/32
+.fi
+.LP
+A special variant of
+.B map
+rules exists, called
+.B map-block.
+This command is intended for use when there is a large network to be mapped
+onto a smaller network, where the difference in netmasks is upto 14 bits
+difference in size. This is achieved by dividing the address space and
+port space up to ensure that each source address has its own private range
+of ports to use. For example, this rule:
+.nf
+
+map-block ppp0 172.192.0.0/16 -> 209.1.2.0/24 ports auto
+.fi
+.PP
+would result in 172.192.0.0/24 being mapped to 209.1.2.0/32
+with each address, from 172.192.0.0 to 172.192.0.255 having 252 ports of its
+own. As opposed to the above use of \fBmap\fP, if for some reason the user
+of (say) 172.192.0.2 wanted 260 simultaneous connections going out, they would
+be limited to 252 with \fBmap-block\fP but would just \fImove on\fP to the next
+IP address with the \fBmap\fP command.
+.SS Extended matching
+.PP
+If it is desirable to match on both the source and destination of a packet
+before applying an address translation to it, this can be achieved by using
+the same from-to syntax as is used in \fBipf.conf\fP(5). What follows
+applies equally to the
+.B map
+rules discussed above and
+.B rdr
+rules discussed below. A simple example is as follows:
+.nf
+
+map bge0 from 10.1.0.0/16 to 192.168.1.0/24 -> 172.12.1.4
+.fi
+.PP
+This would only match packets that are coming from hosts that have a source
+address matching 10.1.0.0/16 and a destination matching 192.168.1.0/24.
+This can be expanded upon with ports for TCP like this:
+.nf
+
+rdr bge0 from 10.1.0.0/16 to any port = 25 -> 127.0.0.1 port 2501 tcp
+.fi
+.PP
+Where only TCP packets from 10.1.0.0/16 to port 25 will be redirected to
+port 2501.
+.PP
+As with \fBipf.conf\fR(5), if we have a large set of networks or addresses
+that we would like to match up with then we can define a pool using
+\fBippool\fR(8) in \fBippool.conf\fR(5) and then refer to it in an
+\fBipnat\fR rule like this:
+.nf
+
+map bge0 from pool/100 to any port = 25 -> 127.0.0.1 port 2501 tcp
+.fi
+.TP
+.B NOTE:
+In this situation, the rule is considered to have a netmask of "0" and
+thus is looked at last, after any rules with /16's or /24's in them,
+.I even if
+the defined pool only has /24's or /32's. Pools may also be used
+.I wherever
+the from-to syntax in \fBipnat.conf\fR(5) is allowed.
+.SH INBOUND DESTINATION TRANSLATION (redirection)
+.PP
+Redirection of packets is used to change the destination fields in a packet
+and is supported for packets that are moving \fIin\fP on a network interface.
+While the same general syntax for
+.B map
+rules is supported, there are differences and limitations.
+.PP
+Firstly, by default all redirection rules target a single IP address, not
+a network or range of network addresses, so a rule written like this:
+.nf
+
+rdr le0 0/0 -> 192.168.1.0
+.fi
+.PP
+Will not spread packets across all 256 IP addresses in that class C network.
+If you were to try a rule like this:
+.nf
+
+rdr le0 0/0 -> 192.168.1.0/24
+.fi
+.PP
+then you will receive a parsing error.
+.PP
+The from-to source-destination matching used with
+.B map
+rules can be used with rdr rules, along with negation, however the
+restriction moves - only a source address match can be negated:
+.nf
+
+rdr le0 from 1.1.0.0/16 to any -> 192.168.1.3
+rdr le0 ! from 1.1.0.0/16 to any -> 192.168.1.4
+.fi
+.PP
+If there is a consective set of addresses you wish to spread the packets
+over, then this can be done in one of two ways, the word "range" optional
+to preserve:
+.nf
+
+rdr le0 0/0 -> 192.168.1.1 - 192.168.1.5
+rdr le0 0/0 -> range 192.168.1.1 - 192.168.1.5
+.fi
+.PP
+If there are only two addresses to split the packets across, the
+recommended method is to use a comma (",") like this:
+.nf
+
+rdr le0 0/0 -> 192.168.1.1,192.168.1.2
+.fi
+.PP
+If there is a large group of destination addresses that are somewhat
+disjoint in nature, we can cycle through them using a
+.B round-robin
+technique like this:
+.nf
+
+rdr le0 0/0 -> 192.168.1.1,192.168.1.2 round-robin
+rdr le0 0/0 -> 192.168.1.5,192.168.1.7 round-robin
+rdr le0 0/0 -> 192.168.1.9 round-robin
+.fi
+.PP
+If there are a large number of redirect rules and hosts being targetted
+then it may be desirable to have all those from a single source address
+be targetted at the same destination address. To achieve this, the
+word
+.B sticky
+is appended to the rule like this:
+.nf
+
+rdr le0 0/0 -> 192.168.1.1,192.168.1.2 sticky
+rdr le0 0/0 -> 192.168.1.5,192.168.1.7 round-robin sticky
+rdr le0 0/0 -> 192.168.1.9 round-robin sticky
+.fi
+.PP
+The
+.B sticky
+feature can only be combined with
+.B round-robin
+and the use of comma.
+.PP
+For TCP and UDP packets, it is possible to both match on the destiantion
+port number and to modify it. For example, to change the destination port
+from 80 to 3128, we would use a rule like this:
+.nf
+
+rdr de0 0/0 port 80 -> 127.0.0.1 port 3128 tcp
+.fi
+.PP
+If a range of ports is given on the LHS and a single port is given on the
+RHS, the entire range of ports is moved. For example, if we had this:
+.nf
+
+rdr le0 0/0 port 80-88 -> 127.0.0.1 port 3128 tcp
+.fi
+.PP
+then port 80 would become 3128, port 81 would become 3129, etc. If we
+want to redirect a number of different pots to just a single port, an
+equals sign ("=") is placed before the port number on the RHS like this:
+.nf
+
+rdr le0 0/0 port 80-88 -> 127.0.0.1 port = 3128 tcp
+.fi
+.PP
+In this case, port 80 goes to 3128, port 81 to 3128, etc.
+.PP
+As with
+.B map
+rules, it is possible to manually set a timeout using the
+.B age
+option, like this:
+.nf
+
+rdr le0 0/0 port 53 -> 127.0.0.1 port 10053 udp age 5/5
+.fi
+.PP
+The use of proxies is not restricted to
+.B map
+rules and outbound sessions. Proxies can also be used with redirect
+rules, although the syntax is slightly different:
+.nf
+
+rdr ge0 0/0 port 21 -> 127.0.0.1 port 21 tcp proxy ftp
+.fi
+.PP
+For
+.B rdr
+rules, the interfaces supplied are in the same order as
+.B map
+rules - input first, then output. In situations where the outgoing interface
+is not certain, it is also possible to use a wildcard ("*") to effect a match
+on any interface.
+.nf
+
+rdr le0,* 0/0 -> 192.168.1.0
+.fi
+.PP
+A single rule, with as many options set as possible would look something like
+this:
+.nf
+
+rdr le0,ppp0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp
+ round-robin frag age 40/40 sticky mssclamp 1000 tag tagged
+.fi
+.SH REWRITING SOURCE AND DESTINATION
+.PP
+Whilst the above two commands provide a lot of flexibility in changing
+addressing fields in packets, often it can be of benefit to translate
+\fIboth\fP source \fBand\fR destination at the same time or to change
+the source address on input or the destination address on output.
+Doing all of these things can be accomplished using
+.B rewrite
+NAT rules.
+.PP
+A
+.B rewrite
+rule requires the same level of packet matching as before, protocol and
+source/destination information but in addition allows either
+.B in
+or
+.B out
+to be specified like this:
+.nf
+
+rewrite in on ppp0 proto tcp from any to any port = 80 ->
+ src 0/0 dst 127.0.0.1,3128;
+rewrite out on ppp0 from any to any ->
+ src 0/32 dst 10.1.1.0/24;
+.fi
+.PP
+On the RHS we can specify both new source and destination information to place
+into the packet being sent out. As with other rules used in
+\fBipnat.conf\fR, there are shortcuts syntaxes available to use the original
+address information (\fB0/0\fR) and the address associated with the network
+interface (\fB0/32\fR.) For TCP and UDP, both address and port information
+can be changed. At present it is only possible to specify either a range of
+port numbers to be used (\fBX-Y\fR) or a single port number (\fB= X\fR) as
+follows:
+.nf
+
+rewrite in on le0 proto tcp from any to any port = 80 ->
+ src 0/0,2000-20000 dst 127.0.0.1,port = 3128;
+.fi
+.PP
+There are four fields that are stepped through in enumerating the number
+space available for creating a new destination:
+.LP
+source address
+.LP
+source port
+.LP
+destination address
+.LP
+destination port
+.PP
+If one of these happens to be a static then it will be skipped and the next
+one incremented. As an example:
+.nf
+
+rewrite out on le0 proto tcp from any to any port = 80 ->
+ src 1.0.0.0/8,5000-5999 dst 2.0.0.0/24,6000-6999;
+.fi
+.PP
+The translated packets would be:
+.LP
+1st src=1.0.0.1,5000 dst=2.0.0.1,6000
+.LP
+2nd src=1.0.0.2,5000 dst=2.0.0.1,6000
+.LP
+3rd src=1.0.0.2,5001 dst=2.0.0.1,6000
+.LP
+4th src=1.0.0.2,5001 dst=2.0.0.2,6000
+.LP
+5th src=1.0.0.2,5001 dst=2.0.0.2,6001
+.LP
+6th src=1.0.0.3,5001 dst=2.0.0.2,6001
+.PP
+and so on.
+.PP
+As with
+.B map
+rules, it is possible to specify a range of addresses by including the word
+\fIrange\fR before the addresses:
+.nf
+
+rewrite from any to any port = 80 ->
+ src 1.1.2.3 - 1.1.2.6 dst 2.2.3.4 - 2.2.3.6;
+.fi
+.SH DIVERTING PACKETS
+.PP
+If you'd like to send packets to a UDP socket rather than just another
+computer to be decapsulated, this can be achieved using a
+.B divert
+rule.
+.PP
+Divert rules can be be used with both inbound and outbound packet
+matching however the rule
+.B must
+specify host addresses for the outer packet, not ranges of addresses
+or netmasks, just single addresses.
+Additionally the syntax must supply required information for UDP.
+An example of what a divert rule looks ike is as follows:
+.nf
+
+divert in on le0 proto udp from any to any port = 53 ->
+ src 192.1.1.1,54 dst 192.168.1.22.1,5300;
+.fi
+.PP
+On the LHS is a normal set of matching capabilities but on the RHS it is
+a requirement to specify both the source and destination addresses and
+ports.
+.PP
+As this feature is intended to be used with targetting packets at sockets
+and not IPFilter running on other systems, there is no rule provided to
+\fIundivert\fR packets.
+.TP
+.B NOTE:
+Diverted packets \fImay\fP be fragmented if the addition of the
+encapsulating IP header plus UDP header causes the packet to exceed
+the size allowed by the outbound network interface. At present it is
+not possible to cause Path MTU discovery to happen as this feature
+is intended to be transparent to both endpoints.
+.B Path MTU Discovery
+If Path MTU discovery is being used and the "do not fragment" flag
+is set in packets to be encapsulated, an ICMP error message will
+be sent back to the sender if the new packet would need to be
+fragmented.
+.SH COMMON OPTIONS
+This section deals with options that are available with all rules.
+.TP
+.B purge
+When the purge keyword is added to the end of a NAT rule, it will
+cause all of the active NAT sessions to be removed when the rule
+is removed as an individual operation. If all of the NAT rules
+are flushed out, it is expected that the operator will similarly
+flush the NAT table and thus NAT sessions are not removed when the
+NAT rules are flushed out.
+.SH RULE ORDERING
+.PP
+.B NOTE:
+Rules in
+.B ipnat.conf
+are read in sequentially as listed and loaded into the kernel in this
+fashion
+.B BUT
+packet matching is done on \fBnetmask\fR, going from 32 down to 0.
+If a rule uses
+.B pool
+or
+.B hash
+to reference a set of addresses or networks, the netmask value for
+these fields is considered to be "0".
+So if your
+.B ipnat.conf
+has the following rules:
+.nf
+
+rdr le0 192.0.0.0/8 port 80 -> 127.0.0.1 3132 tcp
+rdr le0 192.2.0.0/16 port 80 -> 127.0.0.1 3131 tcp
+rdr le0 from any to pool/100 port 80 -> 127.0.0.1 port 3130 tcp
+rdr le0 192.2.2.0/24 port 80 -> 127.0.0.1 3129 tcp
+rdr le0 192.2.2.1 port 80 -> 127.0.0.1 3128 tcp
+.fi
+.PP
+then the rule with 192.2.2.1 will match \fBfirst\fR, regardless of where
+it appears in the ordering of the above rules. In fact, the order in
+which they would be used to match a packet is:
+.nf
+
+rdr le0 192.2.2.1 port 80 -> 127.0.0.1 3128 tcp
+rdr le0 192.2.2.0/24 port 80 -> 127.0.0.1 3129 tcp
+rdr le0 192.2.0.0/16 port 80 -> 127.0.0.1 3131 tcp
+rdr le0 192.0.0.0/8 port 80 -> 127.0.0.1 3132 tcp
+rdr le0 from any to pool/100 port 80 -> 127.0.0.1 port 3130 tcp
+.fi
+.PP
+where the first line is actually a /32.
+.PP
+If your
+.B ipnat.conf
+file has entries with matching target fields (source address for
+.B map
+rules and destination address for
+.B rdr
+rules), then the ordering in the
+.B ipnat.conf
+file does matter. So if you had the following:
+.nf
+
+rdr le0 from 1.1.0.0/16 to 192.2.2.1 port 80 -> 127.0.0.1 3129 tcp
+rdr le0 from 1.1.1.0/24 to 192.2.2.1 port 80 -> 127.0.0.1 3128 tcp
+.fi
+.PP
+Then no packets will match the 2nd rule, they'll all match the first.
+.SH IPv6
+.PP
+In all of the examples above, where an IPv4 address is present, an IPv6
+address can also be used. All rules must use either IPv4 addresses with
+both halves of the NAT rule or IPv6 addresses for both halves. Mixing
+IPv6 addresses with IPv4 addresses, in a single rule, will result in an
+error.
+.PP
+For shorthand notations such as "0/32", the equivalent for IPv6 is
+"0/128". IPFilter will treat any netmask greater than 32 as an
+implicit direction that the address should be IPv6, not IPv4.
+To be unambiguous with 0/0, for IPv6 use ::0/0.
+.SH KERNEL PROXIES
+.PP
+IP Filter comes with a few, simple, proxies built into the code that is loaded
+into the kernel to allow secondary channels to be opened without forcing the
+packets through a user program. The current state of the proxies is listed
+below, as one of three states:
+.HP
+Aging - protocol is roughly understood from
+the time at which the proxy was written but it is not well tested or
+maintained;
+.HP
+Developmental - basic functionality exists, works most of the time but
+may be problematic in extended real use;
+.HP
+Experimental - rough support for the protocol at best, may or may not
+work as testing has been at best sporadic, possible large scale changes
+to the code in order to properly support the protocol.
+.HP
+Mature - well tested, protocol is properly
+understood by the proxy;
+.PP
+The currently compiled in proxy list is as follows:
+.TP
+FTP - Mature
+(map ... proxy port ftp ftp/tcp)
+.TP
+IRC - Experimental
+(proxy port 6667 irc/tcp)
+.TP
+rpcbind - Experimental
+.TP
+PPTP - Experimental
+.TP
+H.323 - Experimental
+(map ... proxy port 1720 h323/tcp)
+.TP
+Real Audio (PNA) - Aging
+.TP
+DNS - Developmental
+(map ... proxy port 53 dns/udp { block .cnn.com; })
+.TP
+IPsec - Developmental
+(map ... proxy port 500 ipsec/tcp)
+.TP
+netbios - Experimental
+.TP
+R-command - Mature
+(map ... proxy port shell rcmd/tcp)
+.SH KERNEL PROXIES
+.SH FILES
+/dev/ipnat
+.br
+/etc/protocols
+.br
+/etc/services
+.br
+/etc/hosts
+.SH SEE ALSO
+ipnat(4), hosts(5), ipf(5), services(5), ipf(8), ipnat(8)
diff --git a/contrib/ipfilter/man/ipnat.8 b/contrib/ipfilter/man/ipnat.8
new file mode 100644
index 0000000..a49f337
--- /dev/null
+++ b/contrib/ipfilter/man/ipnat.8
@@ -0,0 +1,76 @@
+.\" $FreeBSD$
+.\"
+.TH IPNAT 8
+.SH NAME
+ipnat \- user interface to the NAT subsystem
+.SH SYNOPSIS
+.B ipnat
+[
+.B \-dhlnrsvCF
+]
+[
+.B \-M core
+]
+[
+.B \-N system
+]
+.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.
+.PP
+Note that if
+\fBipf(8)\fP
+is not enabled when NAT is configured, it will be enabled
+automatically, as the same kernel facilities are used for
+NAT functionality. In addition, packet forwarding must be
+enabled.
+.SH OPTIONS
+.TP
+.B \-C
+delete all entries in the current NAT rule listing (NAT rules)
+.TP
+.B \-d
+Enable printing of some extra debugging information.
+.TP
+.B \-F
+delete all active entries in the current NAT translation table (currently
+active NAT mappings)
+.TP
+.B \-h
+Print number of hits for each MAP/Redirect filter.
+.TP
+.B \-l
+Show the list of current NAT table entry mappings.
+.TP
+.B \-n
+This flag (no-change) prevents \fBipf\fP from actually making any ioctl
+calls or doing anything which would alter the currently running kernel.
+.TP
+.B \-p
+This flag is used with the \fB-r\fP flag to cause any active NAT
+sessions that were created by the rules being removed and that are
+currently active to also be removed.
+.TP
+.B \-r
+Remove matching NAT rules rather than add them to the internal lists.
+.TP
+.B \-s
+Retrieve and display NAT statistics.
+.TP
+.B \-v
+Turn verbose mode on. Displays information relating to rule processing
+and active rules/table entries.
+.DT
+.SH FILES
+/dev/ipnat
+.br
+/usr/share/examples/ipfilter Directory with examples.
+.SH SEE ALSO
+ipnat(5), ipf(8), ipfstat(8)
diff --git a/contrib/ipfilter/man/ippool.5 b/contrib/ipfilter/man/ippool.5
new file mode 100644
index 0000000..4de19a4
--- /dev/null
+++ b/contrib/ipfilter/man/ippool.5
@@ -0,0 +1,320 @@
+.\" $FreeBSD$
+.\"
+.TH IPPOOL 5
+.SH NAME
+ippool, ippool.conf \- IP Pool file format
+.SH DESCRIPTION
+The file ippool.conf is used with ippool(8) to configure address pools for
+use with ipnat(8) and ipf(8).
+.PP
+There are four different types of address pools that can be configured
+through ippool.conf. The various types are presented below with a brief
+description of how they are used:
+.HP
+dstlist
+.IP
+destination list - is a collection of IP addresses with an optional
+network interface name that can be used with either redirect (rdr) rules
+in ipnat.conf(5) or as the destination in ipf.conf(5) for policy based
+routing.
+.HP
+group-map
+.IP
+group maps - support the srcgrpmap and dstgrpmap call functions in
+ipf.conf(5) by providing a list of addresses or networks rule group
+numbers to start processing them with.
+.HP
+hash
+.IP
+hash tables - provide the means for performing a very efficient
+lookup address or network when there is expected to be only one
+exact match. These are best used with more static sets of addresses
+so they can be sized optimally.
+.HP
+pool
+.IP
+address pools - are an alternative to hash tables that can perform just
+as well in most circumstances. In addition, the address pools allow for
+heirarchical matching, so it is possible to define a subnet as matching
+but then exclude specific addresses from it.
+.SS
+Evolving Configuration
+.PP
+Over time the configuration syntax used by ippool.conf(5) has evolved.
+Originally the syntax used was more verbose about what a particular
+value was being used for, for example:
+.PP
+.nf
+table role = ipf type = tree number = 100
+ { 1.1.1.1/32; !2.2.0.0/16; 2.2.2.0/24; ef00::5/128; };
+.fi
+.PP
+This is rather long winded. The evolution of the configuration syntax
+has also replaced the use of numbers with names, although numbers can
+still be used as can be seen here:
+.PP
+.nf
+pool ipf/tree (name "100";)
+ { 1.1.1.1/32; !2.2.0.0/16; 2.2.2.0/24; ef00::5/128; };
+.fi
+.PP
+Both of the above examples produce the same configuration in the kernel
+for use with ipf.conf(5).
+.PP
+Newer options for use in ippool.conf(5) will only be offered in the new
+configuration syntax and all output using "ippool -l" will also be in the
+new configuration syntax.
+.SS
+IPFilter devices and pools
+.PP
+To cater to different administration styles, ipool.conf(5) allows you to
+tie a pool to a specific role in IPFilter. The recognised role names are:
+.HP
+ipf
+.IP
+pools defined for role "ipf" are available for use with all rules that are
+found in ipf.conf(5) except for auth rules.
+.HP
+nat
+.IP
+pools defined for role "nat" are available for use with all rules that are
+found in ipnat.conf(5).
+.HP
+auth
+.IP
+pools defined for role "auth" are available only for use with "auth" rules
+that are found in ipf.conf(5)
+.HP
+all
+.IP
+pools that are defined for the "all" role are available to all types of
+rules, be they NAT rules in ipnat.conf(5) or firewall rules in ipf.conf(5).
+.SH Address Pools
+.PP
+An address pool can be used in ipf.conf(5) and ipnat.conf(5) for matching
+the source or destination address of packets. They can be referred to either
+by name or number and can hold an arbitrary number of address patterns to
+match.
+.PP
+An address pool is considered to be a "tree type". In the older configuration
+style, it was necessary to have "type=tree" in ippool.conf(5). In the new
+style configuration, it follows the IPFilter device with which the pool
+is being configured.
+Now it is the default if left out.
+.PP
+For convenience, both IPv4 and IPv6 addresses can be stored in the same
+address pool. It should go without saying that either type of packet can
+only ever match an entry in a pool that is of the same address family.
+.PP
+The address pool searches the list of addresses configured for the best
+match. The "best match" is considered to be the match that has the highest
+number of bits set in the mask. Thus if both 2.2.0.0/16 and 2.2.2.0/24 are
+present in an address pool, the addres 2.2.2.1 will match 2.2.2.0/24 and
+2.2.1.1 will match 2.2.0.0/16. The reason for this is to allow exceptions
+to be added through the use of negative matching. In the following example,
+the pool contains "2.2.0.0/16" and "!2.2.2.0/24", meaning that all packets
+that match 2.2.0.0/16, except those that match 2.2.2.0/24, will be considered
+as a match for this pool.
+.PP
+table role = ipf type = tree number = 100
+ { 1.1.1.1/32; 2.2.0.0/16; !2.2.2.0/24; ef00::5/128; };
+.PP
+For the sake of clarity and to aid in managing large numbers of addresses
+inside address pools, it is possible to specify a location to load the
+addresses from. To do this simply use a "file://" URL where you would
+specify an actual IP address.
+.PP
+.nf
+pool ipf/tree (name rfc1918;) { file:///etc/ipf/rfc1918; };
+.fi
+.PP
+The contents of the file might look something like this:
+.PP
+.nf
+# RFC 1918 networks
+10.0.0.0/8
+!127.0.0.0/8
+172.16.0.0/12
+192.168.0.0/24
+.fi
+.PP
+In this example, the inclusion of the line "!127.0.0.0/8" is, strictly
+speaking not correct and serves only as an example to show that negative
+matching is also supported in this file.
+.PP
+Another format that ippool(8) recognises for input from a file is that
+from whois servers. In the following example, output from a query to a
+WHOIS server for information about which networks are associated with
+the name "microsoft" has been saved in a file named "ms-networks".
+There is no need to modify the output from the whois server, so using
+either the whois command or dumping data directly from it over a TCP
+connection works perfectly file as input.
+.PP
+.nf
+pool ipf/tree (name microsoft;) { whois file "/etc/ipf/ms-networks"; };
+.fi
+.PP
+And to then block all packets to/from networks defined in that file,
+a rule like this might be used:
+.PP
+.nf
+block in from pool/microsoft to any
+.fi
+.PP
+Note that there are limitations on the output returned by whois servers
+so be aware that their output may not be 100% perfect for your goal.
+.SH Destination Lists
+.PP
+Destination lists are provided for use primarily with NAT redirect rules
+(rdr). Their purpose is to allow more sophisticated methods of selecting
+which host to send traffic to next than the simple round-robin technique
+that is present with with "round-robin" rules in ipnat.conf(5).
+.PP
+When building a list of hosts to use as a redirection list, it is
+necessary to list each host to be used explicitly. Expressing a
+collection of hosts as a range or a subnet is not supported. With each
+address it is also possible to specify a network interface name. The
+network interface name is ignored by NAT when using destination lists.
+The network itnerface name is currently only used with policy based
+routing (use of "to"/"dup-to" in ipf.conf(5)).
+.PP
+Unlike the other directives that can be expressed in this file, destination
+lists must be written using the new configuration syntax. Each destination
+list must have a name associated with it and a next hop selection policy.
+Some policies have further options. The currently available selection
+policies are:
+.HP
+round-robin
+.IP
+steps through the list of hosts configured with the destination list
+one by one
+.HP
+random
+.IP
+the next hop is chosen by random selection from the list available
+.HP
+src-hash
+.IP
+a hash is made of the source address components of the packet
+(address and port number) and this is used to select which
+next hop address is used
+.HP
+dst-hash
+.IP
+a hash is made of the destination address components of the packet
+(address and port number) and this is used to select which
+next hop address is used
+.HP
+hash
+.IP
+a hash is made of all the address components in the packet
+(addresses and port numbers) and this is used to select which
+next hop address is used
+.HP
+weighted
+.IP
+selecting a weighted policy for destination selection needs further
+clarification as to what type of weighted selection will be used.
+The sub-options to a weighted policy are:
+.RS
+.HP
+connection
+.IP
+the host that has received the least number of connections is selected
+to be the next hop. When all hosts have the same connection count,
+the last one used will be the next address selected.
+.RE
+.PP
+The first example here shows 4 destinations that are used with a
+round-robin selection policy.
+.PP
+.nf
+pool nat/dstlist (name servers; policy round-robin;)
+ { 1.1.1.2; 1.1.1.4; 1.1.1.5; 1.1.1.9; };
+.fi
+.PP
+In the following example, the destination is chosen by whichever has
+had the least number of connections. By placing the interface name
+with each address and saying "all/dstlist", the destination list can
+be used with both ipnat.conf(5) and ipf.conf(5).
+.PP
+.nf
+pool all/dstlist (name servers; policy weighted connection;)
+ { bge0:1.1.1.2; bge0:1.1.1.4; bge1:1.1.1.5; bge1:1.1.1.9; };
+.fi
+.SH Group maps
+.PP
+Group maps are provided to allow more efficient processing of packets
+where there are a larger number of subnets and groups of rules for those
+subnets. Group maps are used with "call" rules in ipf.conf(5) that
+use the "srcgrpmap" and "dstgrpmap" functions.
+.PP
+A group map declaration must mention which group is the default group
+for all matching addresses to be applied to. Then inside the list of
+addresses and networks for the group, each one may optionally have
+a group number associated with it. A simple example like this, where
+the first two entries would map to group 2020 but 5.0.0.0/8 sends
+rule processing to group 2040.
+.PP
+.nf
+group-map out role = ipf number = 2010 group = 2020
+ { 2.2.2.2/32; 4.4.0.0/16; 5.0.0.0/8, group = 2040; };
+.fi
+.PP
+An example that outlines the real purpose of group maps is below,
+where each one of the 12 subnets is mapped to a different group
+number. This might be because each subnet has its own policy and
+rather than write a list of twelve rules in ipf.conf(5) that match
+the subnet and branch off with a head statement, a single rule can
+be used with this group map to achieve the same result.
+.PP
+.nf
+group-map ( name "2010"; in; )
+ { 192.168.1.0/24, group = 10010; 192.168.2.0/24, group = 10020;
+ 192.168.3.0/24, group = 10030; 192.168.4.0/24, group = 10040;
+ 192.168.5.0/24, group = 10050; 192.168.6.0/24, group = 10060;
+ 192.168.7.0/24, group = 10070; 192.168.8.0/24, group = 10080;
+ 192.168.9.0/24, group = 10090; 192.168.10.0/24, group = 10100;
+ 192.168.11.0/24, group = 10110; 192.168.12.0/24, group = 10120;
+ };
+.fi
+.PP
+The limitation with group maps is that only the source address or the
+destination address can be used to map the packet to the starting group,
+not both, in your ipf.conf(5) file.
+.SH Hash Tables
+.PP
+The hash table is operationally similar to the address pool. It is
+used as a store for a collection of address to match on, saving the
+need to write a lengthy list of rules. As with address pools, searching
+will attempt to find the best match - an address specification with the
+largest contiguous netmask.
+.PP
+Hash tables are best used where the list of addresses, subnets and
+networks is relatively static, which is something of a contrast to
+the address pool that can work with either static or changing
+address list sizes.
+.PP
+Further work is still needed to have IPFilter correctly size and tune
+the hash table to optimise searching. The goal is to allow for small to
+medium sized tables to achieve close to O(1) for either a positive or
+negative match, in contrast to the address pool, which is O(logn).
+.PP
+The following two examples build the same table in the kernel, using
+the old configuration format (first) and the new one (second).
+.PP
+.nf
+table role=all type=hash name=servers size=5
+ { 1.1.1.2/32; 1.1.1.3/32; 11.23.44.66/32; };
+
+pool all/hash (name servers; size 5;)
+ { 1.1.1.2; 1.1.1.3; 11.23.44.66; };
+.fi
+.SH FILES
+/dev/iplookup
+.br
+/etc/ippool.conf
+.br
+/etc/hosts
+.SH SEE ALSO
+ippool(8), hosts(5), ipf(5), ipf(8), ipnat(8)
diff --git a/contrib/ipfilter/man/ippool.8 b/contrib/ipfilter/man/ippool.8
new file mode 100644
index 0000000..26cec20
--- /dev/null
+++ b/contrib/ipfilter/man/ippool.8
@@ -0,0 +1,133 @@
+.\" $FreeBSD$
+.\"
+.TH IPPOOL 8
+.SH NAME
+ippool \- user interface to the IPFilter pools
+.SH SYNOPSIS
+.br
+.B ippool
+-a [-dnv] [-m <name>] [-o <role>] [-t <type>] [-T ttl] -i <ipaddr>[/<netmask>]
+.br
+.B ippool
+-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]
+.br
+.B ippool
+-f <file> [-dnuv]
+.br
+.B ippool
+-F [-dv] [-o <role>] [-t <type>]
+.br
+.B ippool
+-l [-dv] [-m <name>] [-t <type>]
+.br
+.B ippool
+-r [-dnv] [-m <name>] [-o <role>] [-t <type>] -i <ipaddr>[/<netmask>]
+.br
+.B ippool
+-R [-dnv] [-m <name>] [-o <role>] [-t <type>]
+.br
+.B ippool
+-s [-dtv] [-M <core>] [-N <namelist>]
+.SH DESCRIPTION
+.PP
+.B Ippool
+is used to manage information stored in the IP pools subsystem of IPFilter.
+Configuration file information may be parsed and loaded into the kernel,
+currently configured pools removed or changed as well as inspected.
+.PP
+The command line options used are broken into two sections: the global
+options and the instance specific options.
+.SH GLOBAL OPTIONS
+.TP
+.B \-d
+Toggle debugging of processing the configuration file.
+.TP
+.B \-n
+This flag (no-change) prevents
+.B ippool
+from actually making any ioctl
+calls or doing anything which would alter the currently running kernel.
+.TP
+.B \-v
+Turn verbose mode on.
+.SH COMMAND OPTIONS
+.TP
+.B -a
+Add a new data node to an existing pool in the kernel.
+.TP
+.B -A
+Add a new (empty) pool to the kernel.
+.TP
+.B -f <file>
+Read in IP pool configuration information from the file and load it into
+the kernel.
+.TP
+.B -F
+Flush loaded pools from the kernel.
+.TP
+.B -l
+Display a list of pools currently loaded into the kernel.
+.TP
+.B -r
+Remove an existing data node from a pool in the kernel.
+.TP
+.B -R
+Remove an existing pool from within the kernel.
+.TP
+.B -s
+Display IP pool statistical information.
+.SH OPTIONS
+.TP
+.B -i <ipaddr>[/<netmask>]
+Sets the IP address for the operation being undertaken with an
+all-one's mask or, optionally, a specific netmask given in either
+the dotted-quad notation or a single integer.
+.TP
+.B -m <name>
+Sets the pool name for the current operation.
+.TP
+.B -M <core>
+Specify an alternative path to /dev/kmem to retrieve statistical information
+from.
+.TP
+.B -N <namelist>
+Specify an alternative path to lookup symbol name information from when
+retrieving statistical information.
+.TP
+.B -o <role>
+Sets the role with which this pool is to be used. Currently only
+.B ipf,
+.B auth
+and
+.B count
+are accepted as arguments to this option.
+.TP
+.B -S <seed>
+Sets the hashing seed to the number specified. Only for use with
+.B hash
+type pools.
+.TP
+.B -t <type>
+Sets the type of pool being defined. Myst be one of
+.B tree,
+.B hash,
+.B group-map.
+.TP
+.B -T <ttl>
+Sets the expiration of the node being added. The timeout is expressed
+as a number of seconds.
+.B tree,
+.B hash,
+.B group-map.
+.TP
+.B -u
+When parsing a configuration file, rather than load new pool data into the
+kernel, unload it.
+.DT
+.SH FILES
+.br
+/dev/iplookup
+.br
+/etc/ippool.conf
+.SH SEE ALSO
+ippool(5), ipf(8), ipfstat(8)
diff --git a/contrib/ipfilter/man/ipscan.5 b/contrib/ipfilter/man/ipscan.5
new file mode 100644
index 0000000..91bf9b0
--- /dev/null
+++ b/contrib/ipfilter/man/ipscan.5
@@ -0,0 +1,52 @@
+.\" $FreeBSD$
+.\"
+.TH IPSCAN 5
+.SH NAME
+ipscan, ipscan.conf \- ipscan file format
+.SH DESCRIPTION
+.PP
+WARNING: This feature is to be considered experimental and may change
+significantly until a final implementation is drawn up.
+.PP
+The format for files accept by ipscan currently follow this rough grammar:
+.LP
+.nf
+line ::= name ":" matchup [ "," matchup ] "=" action .
+matchup ::= "(" ")" | "(" literal ")" | "(" literal "," match ")" .
+action ::= result | result "else" result .
+result ::= "close" | "track" | redirect .
+redirect ::= "redirect" ip-address [ "(" "," port-number ")" ] .
+match ::= { match-char }
+match-char ::= "*" | "?" | "."
+.fi
+.PP
+In this example an ip-address is a dotted-quad IPv4 address and a port-number
+is a number betwee 1 and 65535, inclusive. The match string is must be of
+same length as the literal string that it is matching (literal). The length
+of either string is limited to 16 bytes.
+.PP
+Currently, the redirect option is not yet been implemented.
+.LP
+.nf
+#
+# * = match any character, . = exact match, ? = case insensitive
+#
+# Scan for anything that looks like HTTP and redirect it to the local
+# proxy. One catch - this feature (redirect) is not yet implemented.
+#
+http : ("GET ", "???." ) = redirect(127.0.0.1)
+#
+# Track ssh connections (i.e do nothing)
+#
+ssh : (), ("SSH-") = track
+#
+# Things which look like smtp to be tracked else closed.
+# Client can start with EHLO (ESMTP) or HELO (SMTP).
+#
+smtp : ("HELO ", "**??."), ("220 ", "....") = track else close
+#
+.fi
+.SH FILES
+/etc/ipscan.conf
+.SH SEE ALSO
+ipscan(8)
diff --git a/contrib/ipfilter/man/ipscan.8 b/contrib/ipfilter/man/ipscan.8
new file mode 100644
index 0000000..513dc94
--- /dev/null
+++ b/contrib/ipfilter/man/ipscan.8
@@ -0,0 +1,44 @@
+.\" $FreeBSD$
+.\"
+.TH IPSCAN 8
+.SH NAME
+ipscan \- user interface to the IPFilter content scanning
+.SH SYNOPSIS
+.B ipscan
+[
+.B \-dlnrsv
+] [
+]
+.B \-f <\fIfilename\fP>
+.SH DESCRIPTION
+.PP
+\fBipscan\fP opens the filename given (treating "\-" as stdin) and parses the
+file to build up a content scanning configuration to load into the kernel.
+Currently only the first 16 bytes of a connection can be compared.
+.SH OPTIONS
+.TP
+.B \-d
+Toggle debugging of processing the configuration file.
+.TP
+.B \-l
+Show the list of currently configured content scanning entries.
+.TP
+.B \-n
+This flag (no-change) prevents \fBipscan\fP from actually making any ioctl
+calls or doing anything which would alter the currently running kernel.
+.TP
+.B \-r
+Remove commands from kernel configuration as they are read from the
+configuration file rather than adding new ones.
+.TP
+.B \-s
+Retrieve and display content scanning statistics
+.TP
+.B \-v
+Turn verbose mode on.
+.DT
+.SH FILES
+/dev/ipscan
+/etc/ipscan.conf
+.SH SEE ALSO
+ipscan(5), ipf(8)
diff --git a/contrib/ipfilter/man/mkfilters.1 b/contrib/ipfilter/man/mkfilters.1
new file mode 100644
index 0000000..262e365
--- /dev/null
+++ b/contrib/ipfilter/man/mkfilters.1
@@ -0,0 +1,16 @@
+.\" $FreeBSD$
+.\"
+.TH MKFILTERS 1
+.SH NAME
+mkfilters \- generate a minimal firewall ruleset for ipfilter
+.SH SYNOPSIS
+.B mkfilters
+.SH FILES
+/usr/share/examples/ipfilter/mkfilters
+.SH DESCRIPTION
+.PP
+\fBmkfilters\fP is a perl script that generates a minimal filter rule set for
+use with \fBipfilter\fP by parsing the output of \fBifconfig\fP.
+.DT
+.SH SEE ALSO
+ipf(8), ipf(5), ipfilter(5), ifconfig(8)
diff --git a/contrib/ipfilter/md5.c b/contrib/ipfilter/md5.c
new file mode 100644
index 0000000..35756cd
--- /dev/null
+++ b/contrib/ipfilter/md5.c
@@ -0,0 +1,319 @@
+/* $FreeBSD$ */
+
+
+
+/*
+ ***********************************************************************
+ ** md5.c -- the source code for MD5 routines **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#if defined(linux) && defined(_KERNEL)
+extern void *memcpy(void *, const void *, unsigned long);
+# define bcopy(a,b,c) memcpy(b,a,c)
+#else
+# if defined(_KERNEL) && !defined(__sgi)
+# include <sys/systm.h>
+# else
+# include <string.h>
+# endif
+#endif
+
+#include "md5.h"
+
+/*
+ ***********************************************************************
+ ** Message-digest routines: **
+ ** To form the message digest for a message M **
+ ** (1) Initialize a context buffer mdContext using MD5Init **
+ ** (2) Call MD5Update on mdContext and M **
+ ** (3) Call MD5Final on mdContext **
+ ** The message digest is now in mdContext->digest[0...15] **
+ ***********************************************************************
+ */
+
+/* forward declaration */
+static void Transform __P((UINT4 *, UINT4 *));
+
+static unsigned char PADDING[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* F, G, H and I are basic MD5 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s, ac) \
+ {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) \
+ {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) \
+ {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) \
+ {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+#ifdef __STDC__
+#define UL(x) x##U
+#else
+#define UL(x) x
+#endif
+
+/* The routine MD5Init initializes the message-digest context
+ mdContext. All fields are set to zero.
+ */
+void MD5Init (mdContext)
+MD5_CTX *mdContext;
+{
+ mdContext->i[0] = mdContext->i[1] = (UINT4)0;
+
+ /* Load magic initialization constants.
+ */
+ mdContext->buf[0] = (UINT4)0x67452301;
+ mdContext->buf[1] = (UINT4)0xefcdab89;
+ mdContext->buf[2] = (UINT4)0x98badcfe;
+ mdContext->buf[3] = (UINT4)0x10325476;
+}
+
+/* The routine MD5Update updates the message-digest context to
+ account for the presence of each of the characters inBuf[0..inLen-1]
+ in the message whose digest is being computed.
+ */
+void MD5Update (mdContext, inBuf, inLen)
+MD5_CTX *mdContext;
+unsigned char *inBuf;
+unsigned int inLen;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* update number of bits */
+ if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
+ mdContext->i[1]++;
+ mdContext->i[0] += ((UINT4)inLen << 3);
+ mdContext->i[1] += ((UINT4)inLen >> 29);
+
+ while (inLen--) {
+ /* add new character to buffer, increment mdi */
+ mdContext->in[mdi++] = *inBuf++;
+
+ /* transform if necessary */
+ if (mdi == 0x40) {
+ for (i = 0, ii = 0; i < 16; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+ mdi = 0;
+ }
+ }
+}
+
+/* The routine MD5Final terminates the message-digest computation and
+ ends with the desired message digest in mdContext->digest[0...15].
+ */
+void MD5Final (hash, mdContext)
+unsigned char hash[];
+MD5_CTX *mdContext;
+{
+ UINT4 in[16];
+ int mdi;
+ unsigned int i, ii;
+ unsigned int padLen;
+
+ /* save number of bits */
+ in[14] = mdContext->i[0];
+ in[15] = mdContext->i[1];
+
+ /* compute number of bytes mod 64 */
+ mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
+
+ /* pad out to 56 mod 64 */
+ padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
+ MD5Update (mdContext, PADDING, padLen);
+
+ /* append length in bits and transform */
+ for (i = 0, ii = 0; i < 14; i++, ii += 4)
+ in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
+ (((UINT4)mdContext->in[ii+2]) << 16) |
+ (((UINT4)mdContext->in[ii+1]) << 8) |
+ ((UINT4)mdContext->in[ii]);
+ Transform (mdContext->buf, in);
+
+ /* store buffer in digest */
+ for (i = 0, ii = 0; i < 4; i++, ii += 4) {
+ mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
+ mdContext->digest[ii+1] =
+ (unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
+ mdContext->digest[ii+2] =
+ (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
+ mdContext->digest[ii+3] =
+ (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
+ }
+ bcopy((char *)mdContext->digest, (char *)hash, 16);
+}
+
+/* Basic MD5 step. Transforms buf based on in.
+ */
+static void Transform (buf, in)
+UINT4 *buf;
+UINT4 *in;
+{
+ UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ ***********************************************************************
+ ** End of md5.c **
+ ******************************** (cut) ********************************
+ */
diff --git a/contrib/ipfilter/md5.h b/contrib/ipfilter/md5.h
new file mode 100644
index 0000000..914df74
--- /dev/null
+++ b/contrib/ipfilter/md5.h
@@ -0,0 +1,72 @@
+/* $FreeBSD$ */
+
+/*
+ ***********************************************************************
+ ** md5.h -- header file for implementation of MD5 **
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
+ ** Created: 2/17/90 RLR **
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
+ ** Revised (for MD5): RLR 4/27/91 **
+ ** -- G modified to have y&~z instead of y&z **
+ ** -- FF, GG, HH modified to add in last register done **
+ ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
+ ** -- distinct additive constant for each step **
+ ** -- round 4 added, working mod 7 **
+ ***********************************************************************
+ */
+
+/*
+ ***********************************************************************
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
+ ** **
+ ** License to copy and use this software is granted provided that **
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message- **
+ ** Digest Algorithm" in all material mentioning or referencing this **
+ ** software or this function. **
+ ** **
+ ** License is also granted to make and use derivative works **
+ ** provided that such works are identified as "derived from the RSA **
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
+ ** material mentioning or referencing the derived work. **
+ ** **
+ ** RSA Data Security, Inc. makes no representations concerning **
+ ** either the merchantability of this software or the suitability **
+ ** of this software for any particular purpose. It is provided "as **
+ ** is" without express or implied warranty of any kind. **
+ ** **
+ ** These notices must be retained in any copies of any part of this **
+ ** documentation and/or software. **
+ ***********************************************************************
+ */
+
+#if !defined(__MD5_INCLUDE__) && !defined(_SYS_MD5_H)
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+#ifndef __STDC__
+# undef const
+# define const
+#endif
+
+/* typedef a 32-bit type */
+typedef unsigned int UINT4;
+
+/* Data structure for MD5 (Message-Digest) computation */
+typedef struct {
+ UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
+ UINT4 buf[4]; /* scratch buffer */
+ unsigned char in[64]; /* input buffer */
+ unsigned char digest[16]; /* actual digest after MD5Final call */
+} MD5_CTX;
+
+extern void MD5Init __P((MD5_CTX *));
+extern void MD5Update __P((MD5_CTX *, unsigned char *, unsigned int));
+extern void MD5Final __P((unsigned char *, MD5_CTX *));
+
+#define __MD5_INCLUDE__
+#endif /* __MD5_INCLUDE__ */
diff --git a/contrib/ipfilter/mkfilters b/contrib/ipfilter/mkfilters
new file mode 100644
index 0000000..fe15c55
--- /dev/null
+++ b/contrib/ipfilter/mkfilters
@@ -0,0 +1,116 @@
+#!/usr/local/bin/perl
+# for best results, bring up all your interfaces before running this
+
+if ($^O =~ m/^irix/i)
+{
+ &irix_mkfilters || regular_mkfilters || die $!;
+}
+else
+{
+ &regular_mkfilters || irix_mkfilters || die $!;
+}
+
+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";
+
+$grpi = 0;
+
+foreach $i (keys %ifaces) {
+ if (!defined($inet{$i})) {
+ next;
+ }
+
+ $grpi += 100;
+ $grpo = $grpi + 50;
+
+ if ($i !~ /lo/) {
+ print "pass out on $i all head $grpo\n";
+ print "block out from 127.0.0.0/8 to any group $grpo\n";
+ print "block out from any to 127.0.0.0/8 group $grpo\n";
+ print "block out from any to $inet{$i}/32 group $grpo\n";
+ print "pass in on $i all head $grpi\n";
+ print "block in from 127.0.0.0/8 to any group $grpi\n";
+ print "block in from $inet{$i}/32 to any group $grpi\n";
+ foreach $j (keys %ifaces) {
+ if ($i ne $j && $j !~ /^lo/ && defined($net{$j})) {
+ print "block in from $net{$j} to any group $grpi\n";
+ }
+ }
+ }
+}
+
+sub irix_mkfilters
+{
+ open(NETSTAT, "/usr/etc/netstat -i|") || return 0;
+
+ while (defined($line = <NETSTAT>))
+ {
+ if ($line =~ m/^Name/)
+ {
+ next;
+ }
+ elsif ($line =~ m/^(\S+)/)
+ {
+ open(I, "/usr/etc/ifconfig $1|") || return 0;
+ &scan_ifconfig;
+ close I; # being neat... - Allen
+ }
+ }
+ close NETSTAT; # again, being neat... - Allen
+ return 1;
+}
+
+sub regular_mkfilters
+{
+ open(I, "ifconfig -a|") || return 0;
+ &scan_ifconfig;
+ close I; # being neat... - Allen
+ return 1;
+}
+
+sub scan_ifconfig
+{
+ 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/;
+ }
+ }
+}
+
diff --git a/contrib/ipfilter/ml_ipl.c b/contrib/ipfilter/ml_ipl.c
new file mode 100644
index 0000000..aaf61a4
--- /dev/null
+++ b/contrib/ipfilter/ml_ipl.c
@@ -0,0 +1,164 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+/*
+ * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+ * its own major char number! Way cool patch!
+ */
+#include <sys/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/ipf"
+#endif
+
+extern int ipfattach(), ipfopen(), ipfclose(), ipfioctl(), ipfread();
+extern int nulldev(), ipfidentify(), errno;
+
+struct cdevsw ipfdevsw =
+{
+ ipfopen, ipfclose, ipfread, nulldev,
+ ipfioctl, nulldev, nulldev, nulldev,
+ 0, nulldev,
+};
+
+
+struct dev_ops ipf_ops =
+{
+ 1,
+ ipfidentify,
+ ipfattach,
+ ipfopen,
+ ipfclose,
+ ipfread,
+ NULL, /* write */
+ NULL, /* strategy */
+ NULL, /* dump */
+ 0, /* psize */
+ ipfioctl,
+ NULL, /* reset */
+ NULL /* mmap */
+};
+
+int ipf_major = 0;
+
+#ifdef sun4m
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO,
+ "ipf",
+ &ipf_ops,
+ NULL,
+ &ipfdevsw,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 1,
+};
+#else /* sun4m */
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO, /* magic */
+ "ipf", /* name */
+#ifdef sun4c
+ &ipf_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 */
+ &ipfdevsw, /* 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 (ipf_major < nchrdev &&
+ cdevsw[ipf_major].d_open != vd_unuseddev)
+ ipf_major++;
+ if (ipf_major == nchrdev)
+ return ENODEV;
+ vd.Drv_charmajor = ipf_major;
+ vdp->vdd_vdtab = (struct vdlinkage *)&vd;
+ return ipf_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 ipfdetach();
+}
+
+
+static int ipf_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 = ipf_major<<8;
+
+ error = vn_create(IPL_NAME, UIO_SYSSPACE, &vattr, EXCL, 0, &vp);
+ if (error == 0)
+ VN_RELE(vp);
+ return ipfattach(0);
+}
diff --git a/contrib/ipfilter/mlf_ipl.c b/contrib/ipfilter/mlf_ipl.c
new file mode 100644
index 0000000..93995af
--- /dev/null
+++ b/contrib/ipfilter/mlf_ipl.c
@@ -0,0 +1,596 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+/*
+ * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+ * its own major char number! Way cool patch!
+ */
+
+
+#include <sys/param.h>
+
+#ifdef IPFILTER_LKM
+# ifndef __FreeBSD_cc_version
+# include <osreldate.h>
+# else
+# if __FreeBSD_cc_version < 430000
+# include <osreldate.h>
+# endif
+# endif
+# define ACTUALLY_LKM_NOT_KERNEL
+#else
+# ifndef __FreeBSD_cc_version
+# include <sys/osreldate.h>
+# else
+# if __FreeBSD_cc_version < 430000
+# include <sys/osreldate.h>
+# endif
+# endif
+#endif
+#include <sys/systm.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
+# ifndef ACTUALLY_LKM_NOT_KERNEL
+# include "opt_devfs.h"
+# endif
+# include <sys/conf.h>
+# include <sys/kernel.h>
+# ifdef DEVFS
+# include <sys/devfsext.h>
+# endif /*DEVFS*/
+#endif
+#include <sys/conf.h>
+#include <sys/file.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
+# include <sys/lock.h>
+#endif
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/exec.h>
+#include <sys/mbuf.h>
+#if BSD >= 199506
+# include <sys/sysctl.h>
+#endif
+#if (__FreeBSD_version >= 300000)
+# include <sys/socket.h>
+#endif
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+#include "netinet/ipl.h"
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_auth.h"
+#include "netinet/ip_frag.h"
+
+
+#if !defined(VOP_LEASE) && defined(LEASE_CHECK)
+#define VOP_LEASE LEASE_CHECK
+#endif
+
+int xxxinit __P((struct lkm_table *, int, int));
+
+#ifdef SYSCTL_OID
+int sysctl_ipf_int SYSCTL_HANDLER_ARGS;
+# define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
+ SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
+ ptr, val, sysctl_ipf_int, "I", descr);
+# define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */
+# define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF)
+SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipf_flags, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipf_pass, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipf_active, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipf_chksrc, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipf_minttl, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
+ &ipf_tcpidletimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
+ &ipf_tcphalfclosed, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
+ &ipf_tcpclosewait, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
+ &ipf_tcplastack, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
+ &ipf_tcptimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
+ &ipf_tcpclosed, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
+ &ipf_udptimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
+ &ipf_icmptimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
+ &ipf_defnatage, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
+ &ipf_ipfrttl, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_running, CTLFLAG_RD,
+ &ipf_running, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
+ &ipf_statesize, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
+ &ipf_statemax, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
+ &ipf_authsize, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
+ &ipf_authused, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
+ &ipf_defaultauthage, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW,
+ &ippr_ftp_pasvonly, 0, "");
+#endif
+
+#ifdef DEVFS
+static void *ipf_devfs[IPL_LOGSIZE];
+#endif
+
+#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
+int ipf_major = 0;
+
+static struct cdevsw ipfdevsw =
+{
+ ipfopen, /* open */
+ ipfclose, /* close */
+ ipfread, /* read */
+ (void *)nullop, /* write */
+ ipfioctl, /* ioctl */
+ (void *)nullop, /* stop */
+ (void *)nullop, /* reset */
+ (void *)NULL, /* tty */
+ (void *)nullop, /* select */
+ (void *)nullop, /* mmap */
+ NULL /* strategy */
+};
+
+MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipfdevsw);
+
+extern struct cdevsw cdevsw[];
+extern int vd_unuseddev __P((void));
+extern int nchrdev;
+#else
+
+static struct cdevsw ipf_cdevsw = {
+ ipfopen, ipfclose, ipfread, nowrite, /* 79 */
+ ipfioctl, nostop, noreset, nodevtotty,
+#if (__FreeBSD_version >= 300000)
+ seltrue, nommap, nostrategy, "ipf",
+#else
+ noselect, nommap, nostrategy, "ipf",
+#endif
+ NULL, -1
+};
+#endif
+
+static void ipf_drvinit __P((void *));
+
+#ifdef ACTUALLY_LKM_NOT_KERNEL
+static int if_ipf_unload __P((struct lkm_table *, int));
+static int if_ipf_load __P((struct lkm_table *, int));
+static int if_ipf_remove __P((void));
+static int ipf_major = CDEV_MAJOR;
+
+static int ipfaction __P((struct lkm_table *, int));
+static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH,
+ IPL_SCAN, IPL_SYNC, IPL_POOL, NULL };
+
+extern int lkmenodev __P((void));
+
+static int ipfaction(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
+ int i = ipf_major;
+ struct lkm_dev *args = lkmtp->private.lkm_dev;
+#endif
+ int err = 0;
+
+ switch (cmd)
+ {
+ case LKM_E_LOAD :
+ if (lkmexists(lkmtp))
+ return EEXIST;
+
+#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
+ for (i = 0; i < nchrdev; i++)
+ if (cdevsw[i].d_open == lkmenodev ||
+ cdevsw[i].d_open == ipfopen)
+ break;
+ if (i == nchrdev) {
+ printf("IP Filter: No free cdevsw slots\n");
+ return ENODEV;
+ }
+
+ ipf_major = i;
+ args->lkm_offset = i; /* slot in cdevsw[] */
+#endif
+ printf("IP Filter: loaded into slot %d\n", ipf_major);
+ err = if_ipf_load(lkmtp, cmd);
+ if (!err)
+ ipf_drvinit((void *)NULL);
+ return err;
+ break;
+ case LKM_E_UNLOAD :
+ err = if_ipf_unload(lkmtp, cmd);
+ if (!err) {
+ printf("IP Filter: unloaded from slot %d\n",
+ ipf_major);
+#ifdef DEVFS
+ if (ipf_devfs[IPL_LOGIPF])
+ devfs_remove_dev(ipf_devfs[IPL_LOGIPF]);
+ if (ipf_devfs[IPL_LOGNAT])
+ devfs_remove_dev(ipf_devfs[IPL_LOGNAT]);
+ if (ipf_devfs[IPL_LOGSTATE])
+ devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]);
+ if (ipf_devfs[IPL_LOGAUTH])
+ devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]);
+ if (ipf_devfs[IPL_LOGSCAN])
+ devfs_remove_dev(ipf_devfs[IPL_LOGSCAN]);
+ if (ipf_devfs[IPL_LOGSYNC])
+ devfs_remove_dev(ipf_devfs[IPL_LOGSYNC]);
+ if (ipf_devfs[IPL_LOGLOOKUP])
+ devfs_remove_dev(ipf_devfs[IPL_LOGLOOKUP]);
+#endif
+ }
+ return err;
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return 0;
+}
+
+
+static int if_ipf_remove __P((void))
+{
+ char *name;
+ struct nameidata nd;
+ int error, i;
+
+ for (i = 0; (name = ipf_devfiles[i]); i++) {
+ NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
+ if ((error = namei(&nd)))
+ return (error);
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+#if (__FreeBSD_version >= 300000)
+ VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc);
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ if (nd.ni_vp != NULLVP)
+ vput(nd.ni_vp);
+#else
+ VOP_LOCK(nd.ni_vp);
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+#endif
+ }
+
+ return 0;
+}
+
+
+static int if_ipf_unload(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ int error = 0;
+
+ error = ipfdetach();
+ if (!error)
+ error = if_ipf_remove();
+ return error;
+}
+
+
+static int if_ipf_load(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ struct nameidata nd;
+ struct vattr vattr;
+ int error = 0, fmode = S_IFCHR|0600, i;
+ char *name;
+
+ error = ipfattach();
+ if (error)
+ return error;
+ (void) if_ipf_remove();
+
+ for (i = 0; (name = ipf_devfiles[i]); i++) {
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, 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 = (ipf_major << 8) | i;
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+#if (__FreeBSD_version >= 300000)
+ vput(nd.ni_dvp);
+#endif
+ if (error)
+ return error;
+ }
+ return 0;
+}
+
+#endif /* actually LKM */
+
+#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000)
+/*
+ * strlen isn't present in 2.1.* kernels.
+ */
+size_t strlen(string)
+ char *string;
+{
+ register char *s;
+
+ for (s = string; *s; s++)
+ ;
+ return (size_t)(s - string);
+}
+
+
+int xxxinit(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
+}
+#else /* __FREEBSD_version >= 220000 */
+# ifdef IPFILTER_LKM
+# include <sys/exec.h>
+
+# if (__FreeBSD_version >= 300000)
+MOD_DEV(if_ipf, LM_DT_CHAR, CDEV_MAJOR, &ipf_cdevsw);
+# else
+MOD_DECL(if_ipf);
+
+
+static struct lkm_dev _module = {
+ LM_DEV,
+ LKM_VERSION,
+ IPL_VERSION,
+ CDEV_MAJOR,
+ LM_DT_CHAR,
+ { (void *)&ipf_cdevsw }
+};
+# endif
+
+
+int if_ipf __P((struct lkm_table *, int, int));
+
+
+int if_ipf(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+# if (__FreeBSD_version >= 300000)
+ MOD_DISPATCH(if_ipf, lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
+# else
+ DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
+# endif
+}
+# endif /* IPFILTER_LKM */
+static ipf_devsw_installed = 0;
+
+static void ipf_drvinit __P((void *unused))
+{
+ dev_t dev;
+# ifdef DEVFS
+ void **tp = ipf_devfs;
+# endif
+
+ if (!ipf_devsw_installed ) {
+ dev = makedev(CDEV_MAJOR, 0);
+ cdevsw_add(&dev, &ipf_cdevsw, NULL);
+ ipf_devsw_installed = 1;
+
+# ifdef DEVFS
+ tp[IPL_LOGIPF] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGIPF,
+ DV_CHR, 0, 0, 0600, "ipf");
+ tp[IPL_LOGNAT] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGNAT,
+ DV_CHR, 0, 0, 0600, "ipnat");
+ tp[IPL_LOGSTATE] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGSTATE,
+ DV_CHR, 0, 0, 0600,
+ "ipstate");
+ tp[IPL_LOGAUTH] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGAUTH,
+ DV_CHR, 0, 0, 0600,
+ "ipauth");
+# endif
+ }
+}
+
+
+#ifdef SYSCTL_IPF
+int
+sysctl_ipf_int SYSCTL_HANDLER_ARGS
+{
+ int error = 0;
+
+ if (arg1)
+ error = SYSCTL_OUT(req, arg1, sizeof(int));
+ else
+ error = SYSCTL_OUT(req, &arg2, sizeof(int));
+
+ if (error || !req->newptr)
+ return (error);
+
+ if (!arg1)
+ error = EPERM;
+ else {
+ if ((oidp->oid_kind & CTLFLAG_OFF) && (ipf_running > 0))
+ error = EBUSY;
+ else
+ error = SYSCTL_IN(req, arg1, sizeof(int));
+ }
+ return (error);
+}
+#endif
+
+
+# if defined(IPFILTER_LKM) || \
+ defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
+SYSINIT(ipfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipf_drvinit,NULL)
+# endif /* IPFILTER_LKM */
+#endif /* _FreeBSD_version */
+
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+int ipfopen(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+ int devtype;
+# if (__FreeBSD_version >= 500024)
+ struct thread *p;
+# else
+ struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ int flags;
+{
+ u_int unit = GET_MINOR(dev);
+
+ if (IPL_LOGMAX < unit)
+ unit = ENXIO;
+ else
+ unit = 0;
+ return unit;
+}
+
+
+int ipfclose(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+ int devtype;
+# if (__FreeBSD_version >= 500024)
+ struct thread *p;
+# else
+ struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ int flags;
+{
+ u_int unit = GET_MINOR(dev);
+
+ if (IPL_LOGMAX < unit)
+ unit = ENXIO;
+ else
+ unit = 0;
+ return unit;
+}
+
+/*
+ * ipfread/ipflog
+ * 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 ipfread(dev, uio, ioflag)
+ int ioflag;
+#else
+int ipfread(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ register struct uio *uio;
+{
+ u_int unit = GET_MINOR(dev);
+
+ if (unit < 0)
+ return ENXIO;
+
+ if (ipf_running < 1)
+ return EIO;
+
+ if (unit == IPL_LOGSYNC)
+ return ipfsync_read(uio);
+
+#ifdef IPFILTER_LOG
+ return ipflog_read(unit, uio);
+#else
+ return ENXIO;
+#endif
+}
+
+
+/*
+ * ipfwrite
+ * 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 ipfwrite(dev, uio, ioflag)
+ int ioflag;
+#else
+int ipfwrite(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ register struct uio *uio;
+{
+
+ if (ipf_running < 1)
+ return EIO;
+
+ if (GET_MINOR(dev) == IPL_LOGSYNC)
+ return ipfsync_write(uio);
+ return ENXIO;
+}
diff --git a/contrib/ipfilter/mlf_rule.c b/contrib/ipfilter/mlf_rule.c
new file mode 100644
index 0000000..babd2c6
--- /dev/null
+++ b/contrib/ipfilter/mlf_rule.c
@@ -0,0 +1,168 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+/*
+ * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+ * its own major char number! Way cool patch!
+ */
+
+
+#include <sys/param.h>
+
+#if defined(__FreeBSD__) && (__FreeBSD__ > 1)
+# ifdef IPFILTER_LKM
+# include <osreldate.h>
+# define ACTUALLY_LKM_NOT_KERNEL
+# else
+# include <sys/osreldate.h>
+# endif
+#endif
+#include <sys/systm.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
+# include <sys/conf.h>
+# include <sys/kernel.h>
+# ifdef DEVFS
+# include <sys/devfsext.h>
+# endif /*DEVFS*/
+#endif
+#include <sys/conf.h>
+#include <sys/file.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
+# include <sys/lock.h>
+#endif
+#include <sys/stat.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/exec.h>
+#include <sys/mbuf.h>
+#if BSD >= 199506
+# include <sys/sysctl.h>
+#endif
+#if (__FreeBSD_version >= 300000)
+# include <sys/socket.h>
+#endif
+#if (__FreeBSD_version >= 199511)
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#endif
+#if (__FreeBSD__ > 1)
+# include <sys/sysent.h>
+#endif
+#include <sys/lkm.h>
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_rules.h"
+
+
+int xxxinit __P((struct lkm_table *, int, int));
+
+#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000)
+MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
+#endif
+
+static int ipfrule_ioctl __P((struct lkm_table *, int));
+
+#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000)
+
+int xxxinit(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, ipfrule_ioctl);
+}
+#else /* __FREEBSD_version >= 220000 */
+# ifdef IPFILTER_LKM
+# include <sys/exec.h>
+
+# if (__FreeBSD_version >= 300000)
+MOD_MISC(ipfrule);
+# else
+MOD_DECL(ipfrule);
+
+
+static struct lkm_misc _module = {
+ LM_MISC,
+ LKM_VERSION,
+ "IP Filter rules",
+ 0,
+};
+# endif
+
+
+int ipfrule __P((struct lkm_table *, int, int));
+
+
+int ipfrule(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+# if (__FreeBSD_version >= 300000)
+ MOD_DISPATCH(ipfrule, lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl,
+ ipfrule_ioctl);
+# else
+ DISPATCH(lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, ipfrule_ioctl);
+# endif
+}
+# endif /* IPFILTER_LKM */
+
+
+int ipfrule_load(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return ipfrule_add();
+}
+
+
+int ipfrule_unload(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return ipfrule_remove();
+}
+
+
+static int ipfrule_ioctl(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ int err = 0;
+
+ switch (cmd)
+ {
+ case LKM_E_LOAD :
+ if (lkmexists(lkmtp))
+ return EEXIST;
+
+ err = ipfrule_load(lkmtp, cmd);
+ if (!err)
+ ipf_refcnt++;
+ break;
+ case LKM_E_UNLOAD :
+ err = ipfrule_unload(lkmtp, cmd);
+ if (!err)
+ ipf_refcnt--;
+ break;
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return err;
+}
+#endif /* _FreeBSD_version */
diff --git a/contrib/ipfilter/mlfk_ipl.c b/contrib/ipfilter/mlfk_ipl.c
new file mode 100644
index 0000000..ba1f44f
--- /dev/null
+++ b/contrib/ipfilter/mlfk_ipl.c
@@ -0,0 +1,529 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/select.h>
+#if __FreeBSD_version >= 500000
+# include <sys/selinfo.h>
+#endif
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+
+
+#include "netinet/ipl.h"
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_auth.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_sync.h"
+
+extern ipf_main_softc_t ipfmain;
+
+#if __FreeBSD_version >= 502116
+static struct cdev *ipf_devs[IPL_LOGSIZE];
+#else
+static dev_t ipf_devs[IPL_LOGSIZE];
+#endif
+
+#if 0
+static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
+#endif
+static int ipf_modload(void);
+static int ipf_modunload(void);
+
+#if (__FreeBSD_version >= 500024)
+# if (__FreeBSD_version >= 502116)
+static int ipfopen __P((struct cdev*, int, int, struct thread *));
+static int ipfclose __P((struct cdev*, int, int, struct thread *));
+# else
+static int ipfopen __P((dev_t, int, int, struct thread *));
+static int ipfclose __P((dev_t, int, int, struct thread *));
+# endif /* __FreeBSD_version >= 502116 */
+#else
+static int ipfopen __P((dev_t, int, int, struct proc *));
+static int ipfclose __P((dev_t, int, int, struct proc *));
+#endif
+#if (__FreeBSD_version >= 502116)
+static int ipfread __P((struct cdev*, struct uio *, int));
+static int ipfwrite __P((struct cdev*, struct uio *, int));
+#else
+static int ipfread __P((dev_t, struct uio *, int));
+static int ipfwrite __P((dev_t, struct uio *, int));
+#endif /* __FreeBSD_version >= 502116 */
+
+
+
+SYSCTL_DECL(_net_inet);
+#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
+ SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
+ ptr, val, sysctl_ipf_int, "I", descr);
+#define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */
+#define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF)
+SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
+#if 0
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipf_flags, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipf_pass, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipf_active, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
+ &ipf_tcpidletimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
+ &ipf_tcphalfclosed, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
+ &ipf_tcpclosewait, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
+ &ipf_tcplastack, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
+ &ipf_tcptimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
+ &ipf_tcpclosed, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
+ &ipf_udptimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
+ &ipf_udpacktimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
+ &ipf_icmptimeout, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
+ &ipf_nat_defage, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
+ &ipf_ipfrttl, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_running, CTLFLAG_RD,
+ &ipf_running, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
+ &ipf_state_size, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
+ &ipf_state_max, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO,
+ &ipf_nat_table_sz, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO,
+ &ipf_nat_maprules_sz, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO,
+ &ipf_nat_rdrrules_sz, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO,
+ &ipf_nat_hostmap_sz, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
+ &ipf_auth_size, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
+ &ipf_auth_used, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
+ &ipf_auth_defaultage, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipf_chksrc, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipf_minttl, 0, "");
+#endif
+
+#define CDEV_MAJOR 79
+#include <sys/poll.h>
+#if __FreeBSD_version >= 500043
+# include <sys/select.h>
+static int ipfpoll(struct cdev *dev, int events, struct thread *td);
+
+static struct cdevsw ipf_cdevsw = {
+#if __FreeBSD_version >= 502103
+ .d_version = D_VERSION,
+ .d_flags = 0, /* D_NEEDGIANT - Should be SMP safe */
+#endif
+ .d_open = ipfopen,
+ .d_close = ipfclose,
+ .d_read = ipfread,
+ .d_write = ipfwrite,
+ .d_ioctl = ipfioctl,
+ .d_poll = ipfpoll,
+ .d_name = "ipf",
+#if __FreeBSD_version < 600000
+ .d_maj = CDEV_MAJOR,
+#endif
+};
+#else
+static int ipfpoll(dev_t dev, int events, struct proc *td);
+
+static struct cdevsw ipf_cdevsw = {
+ /* open */ ipfopen,
+ /* close */ ipfclose,
+ /* read */ ipfread,
+ /* write */ ipfwrite,
+ /* ioctl */ ipfioctl,
+ /* poll */ ipfpoll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "ipf",
+ /* maj */ CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+# if (__FreeBSD_version < 500043)
+ /* bmaj */ -1,
+# endif
+# if (__FreeBSD_version >= 430000)
+ /* kqfilter */ NULL
+# endif
+};
+#endif
+
+static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME,
+ IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL };
+
+
+static int
+ipfilter_modevent(module_t mod, int type, void *unused)
+{
+ int error = 0;
+
+ switch (type)
+ {
+ case MOD_LOAD :
+ error = ipf_modload();
+ break;
+
+ case MOD_UNLOAD :
+ error = ipf_modunload();
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+
+static int
+ipf_modload()
+{
+ char *defpass, *c, *str;
+ int i, j, error;
+
+ if (ipf_load_all() != 0)
+ return EIO;
+
+ if (ipf_create_all(&ipfmain) == NULL)
+ return EIO;
+
+ error = ipfattach(&ipfmain);
+ if (error)
+ return error;
+
+ for (i = 0; i < IPL_LOGSIZE; i++)
+ ipf_devs[i] = NULL;
+
+ for (i = 0; (str = ipf_devfiles[i]); i++) {
+ c = NULL;
+ for(j = strlen(str); j > 0; j--)
+ if (str[j] == '/') {
+ c = str + j + 1;
+ break;
+ }
+ if (!c)
+ c = str;
+ ipf_devs[i] = make_dev(&ipf_cdevsw, i, 0, 0, 0600, c);
+ }
+
+ error = ipf_pfil_hook();
+ if (error != 0)
+ return error;
+ ipf_event_reg();
+
+ if (FR_ISPASS(ipfmain.ipf_pass))
+ defpass = "pass";
+ else if (FR_ISBLOCK(ipfmain.ipf_pass))
+ defpass = "block";
+ else
+ defpass = "no-match -> block";
+
+ printf("%s initialized. Default = %s all, Logging = %s%s\n",
+ ipfilter_version, defpass,
+#ifdef IPFILTER_LOG
+ "enabled",
+#else
+ "disabled",
+#endif
+#ifdef IPFILTER_COMPILED
+ " (COMPILED)"
+#else
+ ""
+#endif
+ );
+ return 0;
+}
+
+
+static int
+ipf_modunload()
+{
+ int error, i;
+
+ if (ipfmain.ipf_refcnt)
+ return EBUSY;
+
+ error = ipf_pfil_unhook();
+ if (error != 0)
+ return error;
+
+ if (ipfmain.ipf_running >= 0) {
+ error = ipfdetach(&ipfmain);
+ if (error != 0)
+ return error;
+
+ ipf_destroy_all(&ipfmain);
+ ipf_unload_all();
+ } else
+ error = 0;
+
+ ipfmain.ipf_running = -2;
+
+ for (i = 0; ipf_devfiles[i]; i++) {
+ if (ipf_devs[i] != NULL)
+ destroy_dev(ipf_devs[i]);
+ }
+
+ printf("%s unloaded\n", ipfilter_version);
+
+ return error;
+}
+
+
+static moduledata_t ipfiltermod = {
+ "ipfilter",
+ ipfilter_modevent,
+ 0
+};
+
+
+DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
+#ifdef MODULE_VERSION
+MODULE_VERSION(ipfilter, 1);
+#endif
+
+
+#if 0
+#ifdef SYSCTL_IPF
+int
+sysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
+{
+ int error = 0;
+
+ if (arg1)
+ error = SYSCTL_OUT(req, arg1, sizeof(int));
+ else
+ error = SYSCTL_OUT(req, &arg2, sizeof(int));
+
+ if (error || !req->newptr)
+ return (error);
+
+ if (!arg1)
+ error = EPERM;
+ else {
+ if ((oidp->oid_kind & CTLFLAG_OFF) && (ipfmain.ipf_running > 0))
+ error = EBUSY;
+ else
+ error = SYSCTL_IN(req, arg1, sizeof(int));
+ }
+ return (error);
+}
+#endif
+#endif
+
+
+static int
+#if __FreeBSD_version >= 500043
+ipfpoll(struct cdev *dev, int events, struct thread *td)
+#else
+ipfpoll(dev_t dev, int events, struct proc *td)
+#endif
+{
+ u_int unit = GET_MINOR(dev);
+ int revents;
+
+ if (unit < 0 || unit > IPL_LOGMAX)
+ return 0;
+
+ revents = 0;
+
+ switch (unit)
+ {
+ case IPL_LOGIPF :
+ case IPL_LOGNAT :
+ case IPL_LOGSTATE :
+#ifdef IPFILTER_LOG
+ if ((events & (POLLIN | POLLRDNORM)) && ipf_log_canread(&ipfmain, unit))
+ revents |= events & (POLLIN | POLLRDNORM);
+#endif
+ break;
+ case IPL_LOGAUTH :
+ if ((events & (POLLIN | POLLRDNORM)) && ipf_auth_waiting(&ipfmain))
+ revents |= events & (POLLIN | POLLRDNORM);
+ break;
+ case IPL_LOGSYNC :
+ if ((events & (POLLIN | POLLRDNORM)) && ipf_sync_canread(&ipfmain))
+ revents |= events & (POLLIN | POLLRDNORM);
+ if ((events & (POLLOUT | POLLWRNORM)) && ipf_sync_canwrite(&ipfmain))
+ revents |= events & (POLLOUT | POLLWRNORM);
+ break;
+ case IPL_LOGSCAN :
+ case IPL_LOGLOOKUP :
+ default :
+ break;
+ }
+
+ if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
+ selrecord(td, &ipfmain.ipf_selwait[unit]);
+
+ return revents;
+}
+
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+static int ipfopen(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+ int devtype;
+# if (__FreeBSD_version >= 500024)
+ struct thread *p;
+# else
+ struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ int flags;
+{
+ u_int unit = GET_MINOR(dev);
+ int error;
+
+ if (IPL_LOGMAX < unit)
+ error = ENXIO;
+ else {
+ switch (unit)
+ {
+ case IPL_LOGIPF :
+ case IPL_LOGNAT :
+ case IPL_LOGSTATE :
+ case IPL_LOGAUTH :
+ case IPL_LOGLOOKUP :
+ case IPL_LOGSYNC :
+#ifdef IPFILTER_SCAN
+ case IPL_LOGSCAN :
+#endif
+ error = 0;
+ break;
+ default :
+ error = ENXIO;
+ break;
+ }
+ }
+ return error;
+}
+
+
+static int ipfclose(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+ int devtype;
+# if (__FreeBSD_version >= 500024)
+ struct thread *p;
+# else
+ struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ int flags;
+{
+ u_int unit = GET_MINOR(dev);
+
+ if (IPL_LOGMAX < unit)
+ unit = ENXIO;
+ else
+ unit = 0;
+ return unit;
+}
+
+/*
+ * ipfread/ipflog
+ * 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)
+static int ipfread(dev, uio, ioflag)
+ int ioflag;
+#else
+static int ipfread(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ struct uio *uio;
+{
+ u_int unit = GET_MINOR(dev);
+
+ if (unit < 0)
+ return ENXIO;
+
+ if (ipfmain.ipf_running < 1)
+ return EIO;
+
+ if (unit == IPL_LOGSYNC)
+ return ipf_sync_read(&ipfmain, uio);
+
+#ifdef IPFILTER_LOG
+ return ipf_log_read(&ipfmain, unit, uio);
+#else
+ return ENXIO;
+#endif
+}
+
+
+/*
+ * ipfwrite
+ * 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)
+static int ipfwrite(dev, uio, ioflag)
+ int ioflag;
+#else
+static int ipfwrite(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ struct uio *uio;
+{
+
+ if (ipfmain.ipf_running < 1)
+ return EIO;
+
+ if (GET_MINOR(dev) == IPL_LOGSYNC)
+ return ipf_sync_write(&ipfmain, uio);
+ return ENXIO;
+}
diff --git a/contrib/ipfilter/mlfk_rule.c b/contrib/ipfilter/mlfk_rule.c
new file mode 100644
index 0000000..9f951cf
--- /dev/null
+++ b/contrib/ipfilter/mlfk_rule.c
@@ -0,0 +1,70 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+
+#include <netinet/ipl.h>
+#include <netinet/ip_compat.h>
+#include <netinet/ip_fil.h>
+#include <netinet/ip_state.h>
+#include <netinet/ip_nat.h>
+#include <netinet/ip_auth.h>
+#include <netinet/ip_frag.h>
+
+#include "ip_rules.h"
+
+extern ipf_main_softc_t ipfmain;
+
+static int
+ipfrule_modevent(module_t mod, int type, void *unused)
+{
+ int error = 0;
+
+ switch (type)
+ {
+ case MOD_LOAD :
+ error = ipfrule_add();
+ if (!error)
+ ipfmain.ipf_refcnt++;
+ break;
+ case MOD_UNLOAD :
+ error = ipfrule_remove();
+ if (!error)
+ ipfmain.ipf_refcnt--;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+static moduledata_t ipfrulemod = {
+ "ipfrule",
+ ipfrule_modevent,
+ 0
+};
+DECLARE_MODULE(ipfrule, ipfrulemod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
+#ifdef MODULE_DEPEND
+MODULE_DEPEND(ipfrule, ipfilter, 1, 1, 1);
+#endif
+#ifdef MODULE_VERSION
+MODULE_VERSION(ipfrule, 1);
+#endif
diff --git a/contrib/ipfilter/mlh_rule.c b/contrib/ipfilter/mlh_rule.c
new file mode 100644
index 0000000..cc2a74c
--- /dev/null
+++ b/contrib/ipfilter/mlh_rule.c
@@ -0,0 +1,114 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+/* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/
+
+/*typedef unsigned int spustate_t;*/
+struct uio;
+
+#include <sys/types.h>
+#include <sys/cmn_err.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/callout.h>
+#include <sys/moddefs.h>
+#include <sys/io.h>
+#include <sys/wsio.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/stropts.h>
+#include <net/if.h>
+#include <net/af.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_rules.h"
+
+
+/*
+ * Driver Header
+ */
+static drv_info_t ipf_drv_info = {
+ "IP Filter Rules", /* type */
+ "pseudo", /* class */
+ DRV_PSEUDO|DRV_SAVE_CONF|DRV_MP_SAFE, /* flags */
+ -1, /* b_major */
+ -1, /* c_major */
+ NULL, /* cdio */
+ NULL, /* gio_private */
+ NULL, /* cdio_private */
+};
+
+
+extern struct mod_operations gio_mod_ops;
+static drv_info_t ipf_drv_info;
+extern struct mod_conf_data ipf_conf_data;
+
+static struct mod_type_data ipf_drv_link = {
+ IPL_VERSION, (void *)NULL
+};
+
+static struct modlink ipf_mod_link[] = {
+ { &gio_mod_ops, (void *)&ipf_drv_link },
+ { NULL, (void *)NULL }
+};
+
+struct modwrapper ipf_wrapper = {
+ MODREV,
+ ipf_load,
+ ipf_unload,
+ (void (*)())NULL,
+ (void *)&ipf_conf_data,
+ ipf_mod_link
+};
+
+
+static int ipf_load(void *arg)
+{
+ int i;
+
+ i = ipfrule_add();
+ if (!i)
+ ipf_refcnt--;
+#ifdef IPFDEBUG
+ printf("IP Filter Rules: ipfrule_add() = %d\n", i);
+#endif
+ if (!i)
+ cmn_err(CE_CONT, "IP Filter Rules: Loaded\n");
+ return i;
+}
+
+
+static int ipf_unload(void *arg)
+{
+ int i;
+
+ i = ipfrule_remove();
+ if (!i)
+ ipf_refcnt--;
+#ifdef IPFDEBUG
+ printf("IP Filter Rules: ipfrule_remove() = %d\n", i);
+#endif
+ if (!i)
+ cmn_err(CE_CONT, "IP Filter Rules: Unloaded\n");
+ return i;
+}
diff --git a/contrib/ipfilter/mli_ipl.c b/contrib/ipfilter/mli_ipl.c
new file mode 100644
index 0000000..2a0024c
--- /dev/null
+++ b/contrib/ipfilter/mli_ipl.c
@@ -0,0 +1,683 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ * (C)opyright 1997 by Marc Boucher.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+/* TODO: (MARCXXX)
+ - ipl_init failure -> open ENODEV or whatever
+ - prevent multiple LKM loads
+ - surround access to ifnet structures by IFNET_LOCK()/IFNET_UNLOCK() ?
+ - m != m1 problem
+*/
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#ifdef IPFILTER_LKM
+#include <sys/mload.h>
+#endif
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#ifdef IFF_DRVRLOCK /* IRIX6 */
+#include <sys/hashing.h>
+#include <netinet/in_var.h>
+#endif
+#include <sys/mbuf.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 <netinet/ipfilter.h>
+#include "ipl.h"
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_nat.h"
+
+#ifndef MBUF_IS_CLUSTER
+# define MBUF_IS_CLUSTER(m) ((m)->m_flags & MCL_CLUSTER)
+#endif
+#undef IPFDEBUG /* #define IPFDEBUG 9 */
+
+#ifdef IPFILTER_LKM
+u_int ipldevflag = D_MP;
+char *iplmversion = M_VERSION;
+#else
+u_int ipfilterdevflag = D_MP;
+char *ipfiltermversion = M_VERSION;
+#endif
+
+ipfmutex_t ipl_mutex, ipfi_mutex, ipf_rw, ipf_stinsert, ipf_auth_mx;
+ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock;
+ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
+ipfrwlock_t ipf_global, ipf_mutex, ipf_ipidfrag, ipf_frcache, ipf_tokens;
+
+int (*ipf_checkp) __P((struct ip *, int, void *, int, mb_t **));
+
+#ifdef IPFILTER_LKM
+static int *ipff_addr = 0;
+static int ipff_value;
+static __psunsigned_t *ipfk_addr = 0;
+static __psunsigned_t ipfk_code[4];
+#endif
+static void nifattach();
+static void nifdetach();
+
+typedef struct nif {
+ struct nif *nf_next;
+ struct ifnet *nf_ifp;
+#if (IRIX < 60500)
+ int (*nf_output)(struct ifnet *, struct mbuf *, struct sockaddr *);
+#else
+ int (*nf_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *);
+#endif
+ char nf_name[LIFNAMSIZ];
+ int nf_unit;
+} nif_t;
+
+static nif_t *nif_head = 0;
+static int nif_interfaces = 0;
+extern int in_interfaces;
+#if IRIX >= 60500
+toid_t ipf_timer_id;
+#endif
+
+extern ipnat_t *nat_list;
+
+#ifdef IPFDEBUG
+static void ipf_dumppacket(m)
+ struct mbuf *m;
+{
+ u_char *s;
+ char *t, line[80];
+ int len, off, i;
+
+ off = 0;
+
+ while (m != NULL) {
+ len = M_LEN(m);
+ s = mtod(m, u_char *);
+ printf("mbuf 0x%lx len %d flags %x type %d\n",
+ m, len, m->m_flags, m->m_type);
+ printf("dat 0x%lx off 0x%lx/%d s 0x%lx next 0x%lx\n",
+ m->m_dat, m->m_off, m->m_off, s, m->m_next);
+ while (len > 0) {
+ t = line;
+ for (i = 0; (i < 16) && (len > 0); len--, i++)
+ sprintf(t, " %02x", *s++), t += strlen(t);
+ *s = '\0';
+ printf("mbuf:%x:%s\n", off, line);
+ off += 16;
+ }
+ m = m->m_next;
+ }
+}
+#endif
+
+
+static int
+#if IRIX < 60500
+ipl_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst)
+#else
+ipl_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+ struct rtentry *rt)
+#endif
+{
+#if (IPFDEBUG >= 0)
+ static unsigned int cnt = 0;
+#endif
+ nif_t *nif;
+
+ MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
+ for (nif = nif_head; nif; nif = nif->nf_next)
+ if (nif->nf_ifp == ifp)
+ break;
+ MUTEX_EXIT(&ipfi_mutex);
+
+ if (nif == NULL) {
+ printf("IP Filter: ipl_if_output intf %x NOT FOUND\n", ifp);
+ return ENETDOWN;
+ }
+
+#if (IPFDEBUG >= 7)
+ if ((++cnt % 200) == 0)
+ printf("IP Filter: ipl_if_output(ifp=0x%lx, m=0x%lx, dst=0x%lx), m_type=%d m_flags=0x%lx m_off=0x%lx\n", ifp, m, dst, m->m_type, (u_long)m->m_flags, m->m_off);
+#endif
+
+ if (ipf_checkp) {
+ struct mbuf *m1 = m;
+ struct ip *ip;
+ int hlen;
+
+ switch(m->m_type)
+ {
+ case MT_HEADER:
+ if (m->m_len == 0) {
+ if (m->m_next == NULL)
+ break;
+ m = m->m_next;
+ }
+ /* FALLTHROUGH */
+ case MT_DATA:
+ if (!MBUF_IS_CLUSTER(m) &&
+ ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) {
+#if (IPFDEBUG >= 4)
+ printf("IP Filter: ipl_if_output: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
+#endif
+ break;
+ }
+ if (m->m_len < sizeof(char)) {
+#if (IPFDEBUG >= 3)
+ printf("IP Filter: ipl_if_output: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (u_long)m->m_flags);
+#endif
+ break;
+ }
+ ip = mtod(m, struct ip *);
+ if (ip->ip_v != IPVERSION) {
+#if (IPFDEBUG >= 2)
+ ipf_dumppacket(m);
+ printf("IP Filter: ipl_if_output: bad ip_v m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
+#endif
+ break;
+ }
+
+ hlen = ip->ip_hl << 2;
+ if ((*ipf_checkp)(ip, hlen, ifp, 1, &m1) || (m1 == NULL))
+ return EHOSTUNREACH;
+
+ m = m1;
+ break;
+
+ default:
+#if (IPFDEBUG >= 2)
+ printf("IP Filter: ipl_if_output: bad m_type=%d m_flags=0x%lxm_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
+#endif
+ break;
+ }
+ }
+#if (IRIX < 60500)
+ return (*nif->nf_output)(ifp, m, dst);
+#else
+ return (*nif->nf_output)(ifp, m, dst, rt);
+#endif
+}
+
+int
+
+
+#if !defined(IPFILTER_LKM) && (IRIX >= 60500)
+ipfilter_kernel(struct ifnet *rcvif, struct mbuf *m)
+#else
+ipl_kernel(struct ifnet *rcvif, struct mbuf *m)
+#endif
+{
+#if (IPFDEBUG >= 7)
+ static unsigned int cnt = 0;
+
+ if ((++cnt % 200) == 0)
+ printf("IP Filter: ipl_kernel(rcvif=0x%lx, m=0x%lx\n",
+ rcvif, m);
+#endif
+
+ if (ipf_running <= 0)
+ return IPF_ACCEPTIT;
+
+ /*
+ * Check if we want to allow this packet to be processed.
+ * Consider it to be bad if not.
+ */
+ if (ipf_checkp) {
+ struct mbuf *m1 = m;
+ struct ip *ip;
+ int hlen;
+
+ if ((m->m_type != MT_DATA) && (m->m_type != MT_HEADER)) {
+#if (IPFDEBUG >= 4)
+ printf("IP Filter: ipl_kernel: bad m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
+#endif
+ return IPF_ACCEPTIT;
+ }
+
+ if (!MBUF_IS_CLUSTER(m) &&
+ ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) {
+#if (IPFDEBUG >= 4)
+ printf("IP Filter: ipl_kernel: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
+#endif
+ return IPF_ACCEPTIT;
+ }
+
+ if (m->m_len < sizeof(char)) {
+#if (IPFDEBUG >= 1)
+ printf("IP Filter: ipl_kernel: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (u_long)m->m_flags);
+#endif
+ return IPF_ACCEPTIT;
+ }
+
+ ip = mtod(m, struct ip *);
+ if (ip->ip_v != IPVERSION) {
+#if (IPFDEBUG >= 4)
+ printf("IP Filter: ipl_kernel: bad ip_v\n");
+#endif
+ m_freem(m);
+ return IPF_DROPIT;
+ }
+
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+ hlen = ip->ip_hl << 2;
+ if ((*ipf_checkp)(ip, hlen, rcvif, 0, &m1) || !m1)
+ return IPF_DROPIT;
+ ip = mtod(m1, struct ip *);
+ ip->ip_len = ntohs(ip->ip_len);
+ ip->ip_off = ntohs(ip->ip_off);
+
+#if (IPFDEBUG >= 2)
+ if (m != m1)
+ printf("IP Filter: ipl_kernel: m != m1\n");
+#endif
+ }
+
+ return IPF_ACCEPTIT;
+}
+
+int
+ipl_ipfilter_attach(void)
+{
+#if defined(IPFILTER_LKM)
+ __psunsigned_t *addr_ff, *addr_fk;
+
+ st_findaddr("ipfilterflag", &addr_ff);
+# if (IPFDEBUG >= 1)
+ printf("IP Filter: st_findaddr ipfilterflag=0x%lx\n", addr_ff);
+# endif
+ if (!addr_ff)
+ return ESRCH;
+
+ st_findaddr("ipfilter_kernel", &addr_fk);
+# if (IPFDEBUG >= 1)
+ printf("IP Filter: st_findaddr ipfilter_kernel=0x%lx\n", addr_fk);
+# endif
+ if (!addr_fk)
+ return ESRCH;
+
+ MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
+
+ ipff_addr = (int *)addr_ff;
+
+ ipff_value = *ipff_addr;
+ *ipff_addr = 0;
+
+
+ ipfk_addr = addr_fk;
+
+ bcopy(ipfk_addr, ipfk_code, sizeof(ipfk_code));
+
+ /* write a "li t4, ipl_kernel" instruction */
+ ipfk_addr[0] = 0x3c0c0000 |
+ (((__psunsigned_t)ipl_kernel >> 16) & 0xffff);
+ ipfk_addr[1] = 0x358c0000 |
+ ((__psunsigned_t)ipl_kernel & 0xffff);
+ /* write a "jr t4" instruction" */
+ ipfk_addr[2] = 0x01800008;
+
+ /* write a "nop" instruction */
+ ipfk_addr[3] = 0;
+
+ icache_inval(ipfk_addr, sizeof(ipfk_code));
+
+ *ipff_addr = 1; /* enable ipfilter_kernel */
+
+ MUTEX_EXIT(&ipfi_mutex);
+#else
+ extern int ipfilterflag;
+
+ ipfilterflag = 1;
+#endif
+ nif_interfaces = 0;
+ nifattach();
+
+ return 0;
+}
+
+
+/*
+ * attach the packet filter to each non-loopback interface that is running
+ */
+static void
+nifattach()
+{
+ nif_t *nif, *qf2;
+ struct ifnet *ifp;
+ struct frentry *f;
+ ipnat_t *np;
+
+ MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
+
+ for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+ if ((!(ifp->if_flags & IFF_RUNNING)) ||
+ (ifp->if_flags & IFF_LOOPBACK))
+ continue;
+
+ /*
+ * Look for entry already setup for this device
+ */
+ for (nif = nif_head; nif; nif = nif->nf_next)
+ if (nif->nf_ifp == ifp)
+ break;
+ if (nif)
+ continue;
+
+ if (ifp->if_output == ipl_if_output) {
+ printf("IP Filter: ERROR INTF 0x%lx STILL ATTACHED\n",
+ ifp);
+ continue;
+ }
+#if (IPFDEBUG >= 2)
+ printf("IP Filter: nifattach nif %x opt %x\n",
+ ifp, ifp->if_output);
+#endif
+ KMALLOC(nif, nif_t *);
+ if (!nif) {
+ printf("IP Filter: malloc(%d) for nif_t failed\n",
+ sizeof(nif_t));
+ continue;
+ }
+
+ nif->nf_ifp = ifp;
+ (void) strncpy(nif->nf_name, ifp->if_name,
+ sizeof(nif->nf_name));
+ nif->nf_name[sizeof(nif->nf_name) - 1] = '\0';
+ nif->nf_unit = ifp->if_unit;
+
+ nif->nf_next = nif_head;
+ nif_head = nif;
+
+ /*
+ * Activate any rules directly associated with this interface
+ */
+ WRITE_ENTER(&ipf_mutex);
+ for (f = ipf_rules[0][0]; f; f = f->fr_next) {
+ if ((f->fr_ifa == (struct ifnet *)-1)) {
+ if (f->fr_ifname[0] &&
+ (GETIFP(f->fr_ifname, 4) == ifp))
+ f->fr_ifa = ifp;
+ }
+ }
+ for (f = ipf_rules[1][0]; f; f = f->fr_next) {
+ if ((f->fr_ifa == (struct ifnet *)-1)) {
+ if (f->fr_ifname[0] &&
+ (GETIFP(f->fr_ifname, 4) == ifp))
+ f->fr_ifa = ifp;
+ }
+ }
+ RWLOCK_EXIT(&ipf_mutex);
+ WRITE_ENTER(&ipf_nat);
+ for (np = nat_list; np; np = np->in_next) {
+ if ((np->in_ifps[0] == (void *)-1)) {
+ if (np->in_ifnames[0][0] &&
+ (GETIFP(np->in_ifnames[0], 4) == ifp))
+ np->in_ifps[0] = (void *)ifp;
+ }
+ if ((np->in_ifps[1] == (void *)-1)) {
+ if (np->in_ifnames[1][0] &&
+ (GETIFP(np->in_ifnames[1], 4) == ifp))
+ np->in_ifps[1] = (void *)ifp;
+ }
+ }
+ RWLOCK_EXIT(&ipf_nat);
+
+ nif->nf_output = ifp->if_output;
+ ifp->if_output = ipl_if_output;
+
+#if (IPFDEBUG >= 2)
+ printf("IP Filter: nifattach: ifp(%lx)->if_output FROM %lx TO %lx\n",
+ ifp, nif->nf_output, ifp->if_output);
+#endif
+
+ printf("IP Filter: attach to [%s,%d]\n",
+ nif->nf_name, ifp->if_unit);
+ }
+ if (!nif_head)
+ printf("IP Filter: not attached to any interfaces\n");
+
+ nif_interfaces = in_interfaces;
+
+ MUTEX_EXIT(&ipfi_mutex);
+
+ return;
+}
+
+
+/*
+ * unhook the IP filter from all defined interfaces with IP addresses
+ */
+static void
+nifdetach()
+{
+ nif_t *nif, *qf2, **qp;
+ struct ifnet *ifp;
+
+ MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
+ /*
+ * Make two passes, first get rid of all the unknown devices, next
+ * unlink known devices.
+ */
+ for (qp = &nif_head; (nif = *qp); ) {
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if (nif->nf_ifp == ifp)
+ break;
+ if (ifp) {
+ qp = &nif->nf_next;
+ continue;
+ }
+ printf("IP Filter: removing [%s]\n", nif->nf_name);
+ *qp = nif->nf_next;
+ KFREE(nif);
+ }
+
+ while ((nif = nif_head)) {
+ nif_head = nif->nf_next;
+ for (ifp = ifnet; ifp; ifp = ifp->if_next)
+ if (nif->nf_ifp == ifp)
+ break;
+ if (ifp) {
+ printf("IP Filter: detaching [%s,%d]\n",
+ nif->nf_name, ifp->if_unit);
+
+#if (IPFDEBUG >= 4)
+ printf("IP Filter: nifdetach: ifp(%lx)->if_output FROM %lx TO %lx\n",
+ ifp, ifp->if_output, nif->nf_output);
+#endif
+ ifp->if_output = nif->nf_output;
+ }
+ KFREE(nif);
+ }
+ MUTEX_EXIT(&ipfi_mutex);
+
+ return;
+}
+
+
+void
+ipl_ipfilter_detach(void)
+{
+#ifdef IPFILTER_LKM
+ nifdetach();
+ MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
+
+ if (ipff_addr) {
+ *ipff_addr = 0;
+
+ if (ipfk_addr) {
+ bcopy(ipfk_code, ipfk_addr, sizeof(ipfk_code));
+ icache_inval(ipfk_addr - 16, sizeof(ipfk_code)+32);
+ }
+
+ *ipff_addr = ipff_value;
+ }
+
+ MUTEX_EXIT(&ipfi_mutex);
+#else
+ extern int ipfilterflag;
+
+ nifdetach();
+
+ ipfilterflag = 0;
+#endif
+}
+
+
+/* this function is called from ipf_slowtimer at 500ms intervals to
+ keep our interface list in sync */
+void
+ipl_ipfilter_intfsync(void)
+{
+ MUTEX_ENTER(&ipfi_mutex);
+ if (nif_interfaces != in_interfaces) {
+ /* if the number of interfaces has changed, resync */
+ MUTEX_EXIT(&ipfi_mutex);
+ ipf_sync(&ipfmain, NULL);
+ } else
+ MUTEX_EXIT(&ipfi_mutex);
+}
+
+#ifdef IPFILTER_LKM
+/* this routine should be treated as an interrupt routine and should
+ not call any routines that would cause it to sleep, such as: biowait(),
+ sleep(), psema() or delay().
+*/
+int
+iplunload(void)
+{
+ int error = 0;
+
+ if (ipf_refcnt)
+ return EBUSY;
+
+ WRITE_ENTER(&ipf_global);
+ error = ipl_detach();
+ if (error != 0) {
+ RWLOCK_EXIT(&ipf_global);
+ return error;
+ }
+ ipf_running = -2;
+
+#if (IRIX < 60500)
+ LOCK_DEALLOC(ipl_mutex.l);
+ LOCK_DEALLOC(ipf_rw.l);
+ LOCK_DEALLOC(ipf_auth.l);
+ LOCK_DEALLOC(ipf_natfrag.l);
+ LOCK_DEALLOC(ipf_ipidfrag.l);
+ LOCK_DEALLOC(ipf_tokens.l);
+ LOCK_DEALLOC(ipf_stinsert.l);
+ LOCK_DEALLOC(ipf_nat_new.l);
+ LOCK_DEALLOC(ipf_natio.l);
+ LOCK_DEALLOC(ipf_nat.l);
+ LOCK_DEALLOC(ipf_state.l);
+ LOCK_DEALLOC(ipf_frag.l);
+ LOCK_DEALLOC(ipf_auth_mx.l);
+ LOCK_DEALLOC(ipf_mutex.l);
+ LOCK_DEALLOC(ipf_frcache.l);
+ LOCK_DEALLOC(ipfi_mutex.l);
+ RWLOCK_EXIT(&ipf_global);
+ LOCK_DEALLOC(ipf_global.l);
+#else
+ MUTEX_DESTROY(&ipf_rw);
+ MUTEX_DESTROY(&ipfi_mutex);
+ MUTEX_DESTROY(&ipf_timeoutlock);
+ RW_DESTROY(&ipf_mutex);
+ RW_DESTROY(&ipf_frcache);
+ RW_DESTROY(&ipf_tokens);
+ RWLOCK_EXIT(&ipf_global);
+ delay(hz);
+ RW_DESTROY(&ipf_global);
+#endif
+
+ printf("%s unloaded\n", ipfilter_version);
+
+ delay(hz);
+
+ return 0;
+}
+#endif
+
+void
+ipfilterinit(void)
+{
+#ifdef IPFILTER_LKM
+ int error;
+#endif
+
+#if (IRIX < 60500)
+ ipfi_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ipf_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ipf_frcache.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ipf_timeoutlock.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_global.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_frag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_state.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_nat.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_stinsert.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_natfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_ipidfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_tokens.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_auth.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipf_rw.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+ ipl_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
+
+ if (!ipfi_mutex.l || !ipf_mutex.l || !ipf_timeoutlock.l ||
+ !ipf_frag.l || !ipf_state.l || !ipf_nat.l || !ipf_natfrag.l ||
+ !ipf_auth.l || !ipf_rw.l || !ipf_ipidfrag.l || !ipl_mutex.l ||
+ !ipf_stinsert.l || !ipf_auth_mx.l || !ipf_frcache.l ||
+ !ipf_tokens.l)
+ panic("IP Filter: LOCK_ALLOC failed");
+#else
+ MUTEX_INIT(&ipf_rw, "ipf rw mutex");
+ MUTEX_INIT(&ipf_timeoutlock, "ipf timeout mutex");
+ RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
+ RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
+ RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
+#endif
+
+#ifdef IPFILTER_LKM
+ error = ipl_attach();
+ if (error) {
+ iplunload();
+ } else {
+ char *defpass;
+
+ if (FR_ISPASS(ipf_pass))
+ defpass = "pass";
+ else if (FR_ISBLOCK(ipf_pass))
+ defpass = "block";
+ else
+ defpass = "no-match -> block";
+
+ printf("%s initialized. Default = %s all, Logging = %s%s\n",
+ ipfilter_version, defpass,
+# ifdef IPFILTER_LOG
+ "enabled",
+# else
+ "disabled",
+# endif
+# ifdef IPFILTER_COMPILED
+ " (COMPILED)"
+# else
+ ""
+# endif
+ );
+ }
+#endif
+
+ return;
+}
diff --git a/contrib/ipfilter/mln_ipl.c b/contrib/ipfilter/mln_ipl.c
new file mode 100644
index 0000000..28b5407
--- /dev/null
+++ b/contrib/ipfilter/mln_ipl.c
@@ -0,0 +1,355 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+/*
+ * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+ * its own major char number! Way cool patch!
+ */
+
+
+#include <sys/param.h>
+
+/*
+ * 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
+
+#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>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <sys/lkm.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include "ipl.h"
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_auth.h"
+#include "ip_state.h"
+#include "ip_nat.h"
+#include "ip_sync.h"
+
+#if !defined(__NetBSD_Version__) || __NetBSD_Version__ < 103050000
+#define vn_lock(v,f) VOP_LOCK(v)
+#endif
+
+#if !defined(VOP_LEASE) && defined(LEASE_CHECK)
+#define VOP_LEASE LEASE_CHECK
+#endif
+
+
+extern int lkmenodev __P((void));
+
+#if NetBSD >= 199706
+int ipflkm_lkmentry __P((struct lkm_table *, int, int));
+#else
+int xxxinit __P((struct lkm_table *, int, int));
+#endif
+static int ipf_unload __P((void));
+static int ipf_load __P((void));
+static int ipf_remove __P((void));
+static int ipfaction __P((struct lkm_table *, int));
+static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
+ IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
+ IPLOOKUP_NAME, NULL };
+
+int ipf_major = 0;
+extern ipf_main_softc_t ipfmain;
+extern const struct cdevsw ipl_cdevsw;
+
+#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
+MOD_DEV(IPL_VERSION, "ipf", NULL, -1, &ipl_cdevsw, -1);
+#else
+MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw);
+#endif
+
+extern int vd_unuseddev __P((void));
+extern struct cdevsw cdevsw[];
+extern int nchrdev;
+
+
+int
+#if NetBSD >= 199706
+ipflkm_lkmentry(lkmtp, cmd, ver)
+#else
+xxxinit(lkmtp, cmd, ver)
+#endif
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
+}
+
+
+static int
+ipfaction(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+#if !defined(__NetBSD__) || (__NetBSD_Version__ < 106080000)
+ int i;
+#endif
+ struct lkm_dev *args = lkmtp->private.lkm_dev;
+ int err = 0;
+
+ switch (cmd)
+ {
+ case LKM_E_LOAD :
+ if (lkmexists(lkmtp))
+ return EEXIST;
+
+#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
+# if (__NetBSD_Version__ < 200000000)
+ err = devsw_attach(args->lkm_devname,
+ args->lkm_bdev, &args->lkm_bdevmaj,
+ args->lkm_cdev, &args->lkm_cdevmaj);
+ if (err != 0)
+ return (err);
+# endif
+ ipf_major = args->lkm_cdevmaj;
+#else
+ for (i = 0; i < nchrdev; i++)
+ if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev ||
+ cdevsw[i].d_open == ipfopen)
+ break;
+ if (i == nchrdev) {
+ printf("IP Filter: No free cdevsw slots\n");
+ return ENODEV;
+ }
+
+ ipf_major = i;
+ args->lkm_offset = i; /* slot in cdevsw[] */
+#endif
+ printf("IP Filter: loaded into slot %d\n", ipf_major);
+ return ipf_load();
+ case LKM_E_UNLOAD :
+#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000)
+ devsw_detach(args->lkm_bdev, args->lkm_cdev);
+ args->lkm_bdevmaj = -1;
+ args->lkm_cdevmaj = -1;
+#endif
+ err = ipf_unload();
+ if (!err)
+ printf("IP Filter: unloaded from slot %d\n",
+ ipf_major);
+ break;
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return err;
+}
+
+
+static int
+ipf_remove()
+{
+ char *name;
+ struct nameidata nd;
+ int error, i;
+
+ for (i = 0; (name = ipf_devfiles[i]); i++) {
+#if (__NetBSD_Version__ > 106009999)
+# if (__NetBSD_Version__ > 399001400)
+# if (__NetBSD_Version__ > 499001400)
+ NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE,
+ name);
+# else
+ NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE,
+ name, curlwp);
+# endif
+# else
+ NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE,
+ name, curproc);
+# endif
+#else
+ NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
+#endif
+ if ((error = namei(&nd)))
+ return (error);
+#if (__NetBSD_Version__ > 399001400)
+# if (__NetBSD_Version__ > 399002000)
+# if (__NetBSD_Version__ < 499001400)
+ VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE);
+# endif
+# else
+ VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE);
+# endif
+#else
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+#endif
+#if !defined(__NetBSD_Version__) || (__NetBSD_Version__ < 106000000)
+ vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY);
+#endif
+#if (__NetBSD_Version__ >= 399002000)
+# if (__NetBSD_Version__ < 499001400)
+ VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_cred, LEASE_WRITE);
+# endif
+#else
+# if (__NetBSD_Version__ > 399001400)
+ VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE);
+# else
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+# endif
+#endif
+ (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+ }
+ return 0;
+}
+
+
+static int
+ipf_unload()
+{
+ int error = 0;
+
+ /*
+ * Unloading - remove the filter rule check from the IP
+ * input/output stream.
+ */
+ if (ipfmain.ipf_refcnt)
+ error = EBUSY;
+ else if (ipfmain.ipf_running >= 0) {
+ error = ipfdetach(&ipfmain);
+ if (error == 0) {
+ ipf_destroy_all(&ipfmain);
+ ipf_unload_all();
+ }
+ }
+
+ if (error == 0) {
+ ipfmain.ipf_running = -2;
+ error = ipf_remove();
+ printf("%s unloaded\n", ipfilter_version);
+ }
+ return error;
+}
+
+
+static int
+ipf_load()
+{
+ struct nameidata nd;
+ struct vattr vattr;
+ int error = 0, fmode = S_IFCHR|0600, i;
+ char *name;
+
+ /*
+ * XXX Remove existing device nodes prior to creating new ones
+ * XXX using the assigned LKM device slot's major number. In a
+ * XXX perfect world we could use the ones specified by cdevsw[].
+ */
+ (void)ipf_remove();
+
+ bzero((char *)&ipfmain, sizeof(ipfmain));
+ error = ipf_load_all();
+ if (error != 0)
+ return error;
+ if (ipf_create_all(&ipfmain) == NULL) {
+ ipf_unload_all();
+ return EIO;
+ }
+
+ error = ipfattach(&ipfmain);
+ if (error != 0) {
+ (void) ipf_unload();
+ return error;
+ }
+
+ for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) {
+#if (__NetBSD_Version__ > 399001400)
+# if (__NetBSD_Version__ > 499001400)
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name);
+# else
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curlwp);
+# endif
+#else
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
+#endif
+ if ((error = namei(&nd)))
+ break;
+ 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);
+ error = EEXIST;
+ break;
+ }
+ VATTR_NULL(&vattr);
+ vattr.va_type = VCHR;
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = (ipf_major << 8) | i;
+#if (__NetBSD_Version__ > 399001400)
+# if (__NetBSD_Version__ >= 399002000)
+# if (__NetBSD_Version__ < 499001400)
+ VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE);
+# endif
+# else
+ VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE);
+# endif
+#else
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+#endif
+ error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+ if (error == 0)
+ vput(nd.ni_vp);
+ }
+
+ if (error == 0) {
+ char *defpass;
+
+ if (FR_ISPASS(ipfmain.ipf_pass))
+ defpass = "pass";
+ else if (FR_ISBLOCK(ipfmain.ipf_pass))
+ defpass = "block";
+ else
+ defpass = "no-match -> block";
+
+ printf("%s initialized. Default = %s all, Logging = %s%s\n",
+ ipfilter_version, defpass,
+#ifdef IPFILTER_LOG
+ "enabled",
+#else
+ "disabled",
+#endif
+#ifdef IPFILTER_COMPILED
+ " (COMPILED)"
+#else
+ ""
+#endif
+ );
+ ipfmain.ipf_running = 1;
+ }
+ return error;
+}
diff --git a/contrib/ipfilter/mln_rule.c b/contrib/ipfilter/mln_rule.c
new file mode 100644
index 0000000..2df3376
--- /dev/null
+++ b/contrib/ipfilter/mln_rule.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/exec.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <sys/lkm.h>
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_rules.h"
+
+
+static int ipfruleaction __P((struct lkm_table *, int));
+
+#ifdef IPFILTER_LKM
+# if NetBSD >= 199706
+int ipfrule_lkmentry __P((struct lkm_table *, int, int));
+# else
+int xxxinit __P((struct lkm_table *, int, int));
+# endif
+
+
+MOD_MISC("IPFilter Rules");
+
+# if NetBSD >= 199706
+int ipfrule_lkmentry(lkmtp, cmd, ver)
+# else
+int xxxinit(lkmtp, cmd, ver)
+# endif
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, ipfruleaction, ipfruleaction, ipfruleaction);
+}
+
+static int ipfruleaction(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ int err = 0;
+
+ switch (cmd)
+ {
+ case LKM_E_LOAD :
+ if (lkmexists(lkmtp))
+ return EEXIST;
+
+ err = ipfrule_add();
+ if (!err)
+ ipf_refcnt++;
+ break;
+ case LKM_E_UNLOAD :
+ err = ipfrule_remove();
+ if (!err)
+ ipf_refcnt--;
+ break;
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return err;
+}
+#endif /* IPFILTER_LKM */
diff --git a/contrib/ipfilter/mlo_ipl.c b/contrib/ipfilter/mlo_ipl.c
new file mode 100644
index 0000000..35556fa
--- /dev/null
+++ b/contrib/ipfilter/mlo_ipl.c
@@ -0,0 +1,364 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#include <sys/param.h>
+#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>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <sys/lkm.h>
+#include "ipl.h"
+#include "ip_compat.h"
+#include "ip_fil.h"
+
+#define vn_lock(v,f) VOP_LOCK(v)
+
+#if !defined(VOP_LEASE) && defined(LEASE_CHECK)
+#define VOP_LEASE LEASE_CHECK
+#endif
+
+
+extern int lkmenodev __P((void));
+
+#if OpenBSD >= 200311
+int if_ipf_lkmentry __P((struct lkm_table *, int, int));
+#else
+int if_ipf __P((struct lkm_table *, int, int));
+#endif
+static int ipf_unload __P((void));
+static int ipf_load __P((void));
+static int ipf_remove __P((void));
+static int ipfaction __P((struct lkm_table *, int));
+static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
+ IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
+ IPLOOKUP_NAME, NULL };
+
+
+struct cdevsw ipfdevsw =
+{
+ ipfopen, /* open */
+ ipfclose, /* close */
+ ipfread, /* read */
+ (void *)nullop, /* write */
+ ipfioctl, /* ioctl */
+ (void *)nullop, /* stop */
+ (void *)NULL, /* tty */
+ (void *)nullop, /* select */
+ (void *)nullop, /* mmap */
+ NULL /* strategy */
+};
+
+int ipf_major = 0;
+
+MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipfdevsw);
+
+extern int vd_unuseddev __P((void));
+extern struct cdevsw cdevsw[];
+extern int nchrdev;
+
+
+#if OpenBSD >= 200311
+int if_ipf_lkmentry (lkmtp, cmd, ver)
+#else
+int if_ipf(lkmtp, cmd, ver)
+#endif
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction);
+}
+
+int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */
+
+static int ipfaction(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 == (dev_type_open((*)))lkmenodev ||
+ cdevsw[i].d_open == ipfopen)
+ break;
+ if (i == nchrdev) {
+ printf("IP Filter: No free cdevsw slots\n");
+ return ENODEV;
+ }
+
+ ipf_major = i;
+ args->lkm_offset = i; /* slot in cdevsw[] */
+ printf("IP Filter: loaded into slot %d\n", ipf_major);
+ return ipf_load();
+ case LKM_E_UNLOAD :
+ err = ipf_unload();
+ if (!err)
+ printf("IP Filter: unloaded from slot %d\n",
+ ipf_major);
+ break;
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return err;
+}
+
+
+static int ipf_remove()
+{
+ struct nameidata nd;
+ int error, i;
+ char *name;
+
+ for (i = 0; (name = ipf_devfiles[i]); i++) {
+#if OpenBSD >= 200311
+ NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE,
+ name, curproc);
+#else
+ NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
+#endif
+ if ((error = namei(&nd)))
+ return (error);
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+#if OpenBSD < 200311
+ VOP_LOCK(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY, curproc);
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+#else
+ (void)uvm_vnp_uncache(nd.ni_vp);
+
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE);
+#endif
+ (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
+ }
+ return 0;
+}
+
+
+static int ipf_unload()
+{
+ int error = 0;
+
+ /*
+ * Unloading - remove the filter rule check from the IP
+ * input/output stream.
+ */
+ if (ipf_refcnt)
+ error = EBUSY;
+ else if (ipf_running >= 0)
+ error = ipfdetach();
+
+ if (error == 0) {
+ ipf_running = -2;
+ error = ipf_remove();
+ printf("%s unloaded\n", ipfilter_version);
+ }
+ return error;
+}
+
+
+static int ipf_load()
+{
+ struct nameidata nd;
+ struct vattr vattr;
+ int error = 0, fmode = S_IFCHR|0600, i;
+ char *name;
+
+ /*
+ * XXX Remove existing device nodes prior to creating new ones
+ * XXX using the assigned LKM device slot's major number. In a
+ * XXX perfect world we could use the ones specified by cdevsw[].
+ */
+ (void)ipf_remove();
+
+ error = ipfattach();
+
+ for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) {
+ NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc);
+ if ((error = namei(&nd)))
+ break;
+ 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);
+ error = EEXIST;
+ break;
+ }
+ VATTR_NULL(&vattr);
+ vattr.va_type = VCHR;
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = (ipf_major << 8) | i;
+ VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE);
+ error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
+ }
+
+ if (error == 0) {
+ char *defpass;
+
+ if (FR_ISPASS(ipf_pass))
+ defpass = "pass";
+ else if (FR_ISBLOCK(ipf_pass))
+ defpass = "block";
+ else
+ defpass = "no-match -> block";
+
+ printf("%s initialized. Default = %s all, Logging = %s%s\n",
+ ipfilter_version, defpass,
+#ifdef IPFILTER_LOG
+ "enabled",
+#else
+ "disabled",
+#endif
+#ifdef IPFILTER_COMPILED
+ " (COMPILED)"
+#else
+ ""
+#endif
+ );
+ ipf_running = 1;
+ }
+ return error;
+}
+
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+int
+ipfopen(dev, flags, devtype, p)
+ dev_t dev;
+ int flags;
+ int devtype;
+ struct proc *p;
+{
+ u_int min = GET_MINOR(dev);
+ int error;
+
+ if (IPL_LOGMAX < min) {
+ error = ENXIO;
+ } else {
+ switch (unit)
+ {
+ case IPL_LOGIPF :
+ case IPL_LOGNAT :
+ case IPL_LOGSTATE :
+ case IPL_LOGAUTH :
+ case IPL_LOGLOOKUP :
+ case IPL_LOGSYNC :
+#ifdef IPFILTER_SCAN
+ case IPL_LOGSCAN :
+#endif
+ error = 0;
+ break;
+ default :
+ error = ENXIO;
+ break;
+ }
+ }
+ return error;
+}
+
+
+int
+ipfclose(dev, flags, devtype, p)
+ dev_t dev;
+ int flags;
+ int devtype;
+ struct proc *p;
+{
+ u_int min = GET_MINOR(dev);
+
+ if (IPL_LOGMAX < min)
+ min = ENXIO;
+ else
+ min = 0;
+ return min;
+}
+
+
+/*
+ * ipfread/ipflog
+ * 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
+ipfread(dev, uio, ioflag)
+ dev_t dev;
+ register struct uio *uio;
+ int ioflag;
+{
+
+ if (ipf_running < 1)
+ return EIO;
+
+ if (GET_MINOR(dev) == IPL_LOGSYNC)
+ return ipfsync_read(uio);
+
+#ifdef IPFILTER_LOG
+ return ipflog_read(GET_MINOR(dev), uio);
+#else
+ return ENXIO;
+#endif
+}
+
+
+/*
+ * ipfwrite
+ * 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
+#if (BSD >= 199306)
+ipfwrite(dev, uio, ioflag)
+ int ioflag;
+#else
+ipfwrite(dev, uio)
+#endif
+ dev_t dev;
+ register struct uio *uio;
+{
+
+ if (ipf_running < 1)
+ return EIO;
+
+ if (GET_MINOR(dev) == IPL_LOGSYNC)
+ return ipfsync_write(uio);
+ return ENXIO;
+}
diff --git a/contrib/ipfilter/mlo_rule.c b/contrib/ipfilter/mlo_rule.c
new file mode 100644
index 0000000..dbd4305
--- /dev/null
+++ b/contrib/ipfilter/mlo_rule.c
@@ -0,0 +1,80 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/exec.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <net/route.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <sys/lkm.h>
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_rules.h"
+
+
+#ifdef IPFILTER_LKM
+
+static int ipfruleaction __P((struct lkm_table *, int));
+
+int ipfrule __P((struct lkm_table *, int, int));
+
+
+MOD_MISC("IPFilter Rules");
+
+int ipfrule(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd, ver;
+{
+ DISPATCH(lkmtp, cmd, ver, ipfruleaction, ipfruleaction, ipfruleaction);
+}
+
+int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */
+
+static int ipfruleaction(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ int err = 0;
+
+ switch (cmd)
+ {
+ case LKM_E_LOAD :
+ if (lkmexists(lkmtp))
+ return EEXIST;
+
+ err = ipfrule_add();
+ if (!err)
+ ipf_refcnt++;
+ break;
+ case LKM_E_UNLOAD :
+ err = ipfrule_remove();
+ if (!err)
+ ipf_refcnt--;
+ break;
+ case LKM_E_STAT :
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+ return err;
+}
+#endif /* IPFILTER_LKM */
diff --git a/contrib/ipfilter/mls_ipl.c b/contrib/ipfilter/mls_ipl.c
new file mode 100644
index 0000000..4388b61
--- /dev/null
+++ b/contrib/ipfilter/mls_ipl.c
@@ -0,0 +1,351 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+/*
+ * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+ * its own major char number! Way cool patch!
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/conf.h>
+#include <sys/syslog.h>
+#include <sys/buf.h>
+#include <sys/mbuf.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 <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 "ipl.h"
+#include "ip_compat.h"
+#include "ip_fil.h"
+
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)mls_ipl.c 2.6 10/15/95 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+extern int ipfdetach __P((void));
+#ifndef IPFILTER_LOG
+#define ipfread nulldev
+#endif
+extern int nulldev __P((void));
+extern int errno;
+
+extern int nodev __P((void));
+
+static int unload __P((void));
+static int ipf_attach __P((void));
+int xxxinit __P((u_int, struct vddrv *, caddr_t, struct vdstat *));
+static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
+ IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
+ IPLOOKUP_NAME, NULL };
+static int ipfopen __P((dev_t, int));
+static int ipfclose __P((dev_t, int));
+static int ipfread __P((dev_t, struct uio *));
+static int ipfwrite __P((dev_t, struct uio *));
+
+
+struct cdevsw ipfdevsw =
+{
+ ipfopen, ipfclose, ipfread, nulldev,
+ ipfioctl, nulldev, nulldev, nulldev,
+ 0, nulldev,
+};
+
+
+struct dev_ops ipf_ops =
+{
+ 1,
+ ipfidentify,
+ ipfattach,
+ ipfopen,
+ ipfclose,
+ ipfread,
+ ipfwrite,
+ NULL, /* strategy */
+ NULL, /* dump */
+ 0, /* psize */
+ ipfioctl,
+ NULL, /* reset */
+ NULL /* mmap */
+};
+
+int ipf_major = 0;
+
+#ifdef sun4m
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO,
+ IPL_VERSION,
+ &ipf_ops,
+ NULL,
+ &ipfdevsw,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 1,
+};
+#else /* sun4m */
+struct vdldrv vd =
+{
+ VDMAGIC_PSEUDO, /* magic */
+ IPL_VERSION,
+#ifdef sun4c
+ &ipf_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 */
+ &ipfdevsw, /* cdevsw */
+ 0, /* block major */
+ 0, /* char major */
+};
+#endif /* sun4m */
+
+extern int vd_unuseddev __P((void));
+extern struct cdevsw cdevsw[];
+extern int nchrdev;
+
+xxxinit(fc, vdp, data, vds)
+ u_int fc;
+ struct vddrv *vdp;
+ caddr_t data;
+ struct vdstat *vds;
+{
+ struct vdioctl_load *vdi = (struct vdioctl_load *)data;
+
+ switch (fc)
+ {
+ case VDLOAD:
+ {
+ struct vdconf *vdc;
+ if (vdi && vdi->vdi_userconf)
+ for (vdc = vdi->vdi_userconf; vdc->vdc_type; vdc++)
+ if (vdc->vdc_type == VDCCHARMAJOR) {
+ ipf_major = vdc->vdc_data;
+ break;
+ }
+
+ if (!ipf_major) {
+ while (ipf_major < nchrdev &&
+ cdevsw[ipf_major].d_open != vd_unuseddev)
+ ipf_major++;
+ if (ipf_major == nchrdev)
+ return ENODEV;
+ }
+ vdp->vdd_vdtab = (struct vdlinkage *)&vd;
+ vd.Drv_charmajor = ipf_major;
+ return ipf_attach();
+ }
+ case VDUNLOAD:
+ return unload();
+ case VDSTAT:
+ return 0;
+ default:
+ return EIO;
+ }
+}
+
+
+static int
+unload()
+{
+ int err = 0, i;
+ char *name;
+
+ if (ipf_refcnt != 0)
+ err = EBUSY;
+ else if (ipf_running >= 0)
+ err = ipfdetach();
+ if (err)
+ return err;
+
+ ipf_running = -2;
+ for (i = 0; (name = ipf_devfiles[i]); i++)
+ (void) vn_remove(name, UIO_SYSSPACE, FILE);
+ printf("%s unloaded\n", ipfilter_version);
+ return 0;
+}
+
+
+static int
+ipf_attach()
+{
+ struct vnode *vp;
+ struct vattr vattr;
+ int error = 0, fmode = S_IFCHR|0600, i;
+ char *name;
+
+ error = ipfattach();
+ if (error)
+ return error;
+
+ for (i = 0; (name = ipf_devfiles[i]); i++) {
+ (void) vn_remove(name, UIO_SYSSPACE, FILE);
+ vattr_null(&vattr);
+ vattr.va_type = MFTOVT(fmode);
+ vattr.va_mode = (fmode & 07777);
+ vattr.va_rdev = (ipf_major << 8) | i;
+
+ error = vn_create(name, UIO_SYSSPACE, &vattr, EXCL, 0, &vp);
+ if (error) {
+ printf("IP Filter: vn_create(%s) = %d\n", name, error);
+ break;
+ } else {
+ VN_RELE(vp);
+ }
+ }
+
+ if (error == 0) {
+ char *defpass;
+
+ if (FR_ISPASS(ipf_pass))
+ defpass = "pass";
+ else if (FR_ISBLOCK(ipf_pass))
+ defpass = "block";
+ else
+ defpass = "no-match -> block";
+
+ printf("%s initialized. Default = %s all, Logging = %s%s\n",
+ ipfilter_version, defpass,
+#ifdef IPFILTER_LOG
+ "enabled",
+#else
+ "disabled",
+#endif
+#ifdef IPFILTER_COMPILED
+ " (COMPILED)"
+#else
+ ""
+#endif
+ );
+ ipf_running = 1;
+ }
+ return error;
+}
+
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+static int
+ipfopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ u_int unit = GET_MINOR(dev);
+ int error;
+
+ if (IPL_LOGMAX < unit) {
+ error = ENXIO;
+ } else {
+ switch (unit)
+ {
+ case IPL_LOGIPF :
+ case IPL_LOGNAT :
+ case IPL_LOGSTATE :
+ case IPL_LOGAUTH :
+ case IPL_LOGLOOKUP :
+ case IPL_LOGSYNC :
+#ifdef IPFILTER_SCAN
+ case IPL_LOGSCAN :
+#endif
+ error = 0;
+ break;
+ default :
+ error = ENXIO;
+ break;
+ }
+ }
+ return error;
+}
+
+
+static int
+ipfclose(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ u_int unit = GET_MINOR(dev);
+
+ if (IPL_LOGMAX < unit)
+ unit = ENXIO;
+ else
+ unit = 0;
+ return unit;
+}
+
+
+/*
+ * ipfread/ipflog
+ * 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.
+ */
+static int
+ipfread(dev, uio)
+ dev_t dev;
+ register struct uio *uio;
+{
+
+ if (ipf_running < 1) {
+ ipfmain.ipf_interror = 130006;
+ return EIO;
+ }
+
+#ifdef IPFILTER_LOG
+ return ipflog_read(GET_MINOR(dev), uio);
+#else
+ ipfmain.ipf_interror = 130007;
+ return ENXIO;
+#endif
+}
+
+
+/*
+ * ipfwrite
+ */
+static int
+ipfwrite(dev, uio)
+ dev_t dev;
+ register struct uio *uio;
+{
+
+ if (ipf_running < 1) {
+ ipfmain.ipf_interror = 130008;
+ return EIO;
+ }
+
+ if (getminor(dev) == IPL_LOGSYNC)
+ return ipfsync_write(uio);
+ ipfmain.ipf_interror = 130009;
+ return ENXIO;
+}
diff --git a/contrib/ipfilter/mls_rule.c b/contrib/ipfilter/mls_rule.c
new file mode 100644
index 0000000..e37df0c
--- /dev/null
+++ b/contrib/ipfilter/mls_rule.c
@@ -0,0 +1,116 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+/*
+ * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate
+ * its own major char number! Way cool patch!
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/conf.h>
+#include <sys/syslog.h>
+#include <sys/buf.h>
+#include <sys/mbuf.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 <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 "ip_fil.h"
+#include "ip_rules.h"
+
+
+extern int errno;
+
+
+int xxxinit __P((u_int, struct vddrv *, caddr_t, struct vdstat *));
+
+int ipl_major = 0;
+
+#ifdef sun4m
+struct vdldrv vd =
+{
+ VDMAGIC_USER,
+ "IP Filter rules",
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 1,
+};
+#else /* sun4m */
+struct vdldrv vd =
+{
+ VDMAGIC_USER, /* magic */
+ "IP Filter rules",
+#ifdef sun4c
+ NULL, /* 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 */
+ NULL, /* cdevsw */
+ 0, /* block major */
+ 0, /* char major */
+};
+#endif /* sun4m */
+
+
+xxxinit(fc, vdp, data, vds)
+ u_int fc;
+ struct vddrv *vdp;
+ caddr_t data;
+ struct vdstat *vds;
+{
+ struct vdioctl_load *vdi = (struct vdioctl_load *)data;
+ int err;
+
+ switch (fc)
+ {
+ case VDLOAD:
+ err = ipfrule_add();
+ if (!err)
+ ipf_refcnt++;
+ break;
+ case VDUNLOAD:
+ err = ipfrule_remove();
+ if (!err)
+ ipf_refcnt--;
+ break;
+ case VDSTAT:
+ err = 0;
+ break;
+ default:
+ err = EIO;
+ break;
+ }
+}
diff --git a/contrib/ipfilter/mlso_rule.c b/contrib/ipfilter/mlso_rule.c
new file mode 100644
index 0000000..a9395f2
--- /dev/null
+++ b/contrib/ipfilter/mlso_rule.c
@@ -0,0 +1,130 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#pragma ident "@(#)$Id$"
+
+#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 <sys/dlpi.h>
+#include <sys/stropts.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#if SOLARIS2 >= 6
+# include <net/if_types.h>
+#endif
+#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 <sys/ddi.h>
+#include <sys/sunddi.h>
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_rules.h"
+
+char _depends_on[] = "drv/ipf";
+
+
+extern ipf_main_softc_t ipfmain;
+extern struct mod_ops mod_miscops;
+static struct modlmisc ipfrulemod = {
+ &mod_miscops,
+ "IP Filter rules"
+};
+
+static struct modlinkage modlink1 = {
+ MODREV_1,
+ &ipfrulemod,
+ NULL
+};
+
+
+int _init()
+{
+ int ipfruleinst;
+
+ ipfruleinst = mod_install(&modlink1);
+#ifdef IPFRULEDEBUG
+ cmn_err(CE_NOTE, "IP Filter Rules: _init() = %d", ipfruleinst);
+#endif
+
+ if (ipfruleinst == 0) {
+ if (ipfmain.ipf_running >= 0) {
+ ipfruleinst = ipfrule_add();
+ if (!ipfruleinst)
+ ipfmain.ipf_refcnt++;
+ else {
+ cmn_err(CE_NOTE,
+ "IP Filter Rules: ipfrule_add failed");
+ ipfruleinst = -1;
+ }
+ } else
+ ipfruleinst = -1;
+ }
+ if (ipfruleinst == 0)
+ cmn_err(CE_CONT, "IP Filter Rules: loaded\n");
+ return ipfruleinst;
+}
+
+
+int _fini(void)
+{
+ int ipfruleinst;
+
+ ipfruleinst = mod_remove(&modlink1);
+#ifdef IPFRULEDEBUG
+ cmn_err(CE_NOTE, "IP Filter Rules: _fini() = %d", ipfruleinst);
+#endif
+ if (ipfruleinst == 0) {
+ ipfruleinst = ipfrule_remove();
+ if (!ipfruleinst)
+ ipfmain.ipf_refcnt--;
+ else
+ ipfruleinst = -1;
+ }
+ if (ipfruleinst == 0)
+ cmn_err(CE_CONT, "IP Filter Rules: unloaded\n");
+ return ipfruleinst;
+}
+
+
+int _info(modinfop)
+ struct modinfo *modinfop;
+{
+ int ipfruleinst;
+
+ ipfruleinst = mod_info(&modlink1, modinfop);
+#ifdef IPFRULEDEBUG
+ cmn_err(CE_NOTE, "IP Filter Rules: _info(%x) = %x",
+ modinfop, ipfruleinst);
+#endif
+ return ipfruleinst;
+}
diff --git a/contrib/ipfilter/opt_inet6.h b/contrib/ipfilter/opt_inet6.h
new file mode 100644
index 0000000..43e7657
--- /dev/null
+++ b/contrib/ipfilter/opt_inet6.h
@@ -0,0 +1 @@
+#define INET6
diff --git a/contrib/ipfilter/opts.h b/contrib/ipfilter/opts.h
new file mode 100644
index 0000000..3c8b88b
--- /dev/null
+++ b/contrib/ipfilter/opts.h
@@ -0,0 +1,69 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+#ifndef __OPTS_H__
+#define __OPTS_H__
+
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+#define OPT_REMOVE 0x000001
+#define OPT_DEBUG 0x000002
+#define OPT_AUTHSTATS 0x000004
+#define OPT_RAW 0x000008
+#define OPT_LOG 0x000010
+#define OPT_SHOWLIST 0x000020
+#define OPT_VERBOSE 0x000040
+#define OPT_DONOTHING 0x000080
+#define OPT_HITS 0x000100
+#define OPT_BRIEF 0x000200
+#define OPT_ACCNT 0x000400
+#define OPT_FRSTATES 0x000800
+#define OPT_SHOWLINENO 0x001000
+#define OPT_PRINTFR 0x002000
+#define OPT_OUTQUE FR_OUTQUE /* 0x4000 */
+#define OPT_INQUE FR_INQUE /* 0x8000 */
+#define OPT_ZERORULEST 0x010000
+#define OPT_SAVEOUT 0x020000
+#define OPT_IPSTATES 0x040000
+#define OPT_INACTIVE 0x080000
+#define OPT_NAT 0x100000
+#define OPT_GROUPS 0x200000
+#define OPT_STATETOP 0x400000
+#define OPT_FLUSH 0x800000
+#define OPT_CLEAR 0x1000000
+#define OPT_HEX 0x2000000
+#define OPT_ASCII 0x4000000
+#define OPT_NORESOLVE 0x8000000
+#define OPT_DONTOPEN 0x10000000
+#define OPT_PURGE 0x20000000
+
+#define OPT_STAT OPT_FRSTATES
+#define OPT_LIST OPT_SHOWLIST
+
+
+#ifndef __P
+# ifdef __STDC__
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+#if defined(sun) && !SOLARIS
+# define STRERROR(x) sys_errlist[x]
+extern char *sys_errlist[];
+#else
+# define STRERROR(x) strerror(x)
+#endif
+
+extern int opts;
+
+#endif /* __OPTS_H__ */
diff --git a/contrib/ipfilter/pcap-bpf.h b/contrib/ipfilter/pcap-bpf.h
new file mode 100644
index 0000000..51002a3
--- /dev/null
+++ b/contrib/ipfilter/pcap-bpf.h
@@ -0,0 +1,687 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.h 7.1 (Berkeley) 5/7/91
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.37 2005/05/01 19:46:27 guy Exp $ (LBL)
+ */
+
+/*
+ * This is libpcap's cut-down version of bpf.h; it includes only
+ * the stuff needed for the code generator and the userland BPF
+ * interpreter, and the libpcap APIs for setting filters, etc..
+ *
+ * "pcap-bpf.c" will include the native OS version, as it deals with
+ * the OS's BPF implementation.
+ *
+ * XXX - should this all just be moved to "pcap.h"?
+ */
+
+#ifndef BPF_MAJOR_VERSION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BSD style release date */
+#define BPF_RELEASE 199606
+
+#ifdef MSDOS /* must be 32-bit */
+typedef long bpf_int32;
+typedef unsigned long bpf_u_int32;
+#else
+typedef int bpf_int32;
+typedef u_int bpf_u_int32;
+#endif
+
+/*
+ * Alignment macros. BPF_WORDALIGN rounds up to the next
+ * even multiple of BPF_ALIGNMENT.
+ */
+#ifndef __NetBSD__
+#define BPF_ALIGNMENT sizeof(bpf_int32)
+#else
+#define BPF_ALIGNMENT sizeof(long)
+#endif
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_MAXINSNS 512
+#define BPF_MAXBUFSIZE 0x8000
+#define BPF_MINBUFSIZE 32
+
+/*
+ * Structure for "pcap_compile()", "pcap_setfilter()", etc..
+ */
+struct bpf_program {
+ u_int bf_len;
+ struct bpf_insn *bf_insns;
+};
+
+/*
+ * Struct return by BIOCVERSION. This represents the version number of
+ * the filter language described by the instruction encodings below.
+ * bpf understands a program iff kernel_major == filter_major &&
+ * kernel_minor >= filter_minor, that is, if the value returned by the
+ * running kernel has the same major number and a minor number equal
+ * equal to or less than the filter being downloaded. Otherwise, the
+ * results are undefined, meaning an error may be returned or packets
+ * may be accepted haphazardly.
+ * It has nothing to do with the source code version.
+ */
+struct bpf_version {
+ u_short bv_major;
+ u_short bv_minor;
+};
+/* Current version number of filter architecture. */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+/*
+ * Data-link level type codes.
+ *
+ * Do *NOT* add new values to this list without asking
+ * "tcpdump-workers@tcpdump.org" for a value. Otherwise, you run the
+ * risk of using a value that's already being used for some other purpose,
+ * and of having tools that read libpcap-format captures not being able
+ * to handle captures with your new DLT_ value, with no hope that they
+ * will ever be changed to do so (as that would destroy their ability
+ * to read captures using that value for that other purpose).
+ */
+
+/*
+ * These are the types that are the same on all platforms, and that
+ * have been defined by <net/bpf.h> for ages.
+ */
+#define DLT_NULL 0 /* BSD loopback encapsulation */
+#define DLT_EN10MB 1 /* Ethernet (10Mb) */
+#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
+#define DLT_AX25 3 /* Amateur Radio AX.25 */
+#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
+#define DLT_CHAOS 5 /* Chaos */
+#define DLT_IEEE802 6 /* IEEE 802 Networks */
+#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */
+#define DLT_SLIP 8 /* Serial Line IP */
+#define DLT_PPP 9 /* Point-to-point Protocol */
+#define DLT_FDDI 10 /* FDDI */
+
+/*
+ * These are types that are different on some platforms, and that
+ * have been defined by <net/bpf.h> for ages. We use #ifdefs to
+ * detect the BSDs that define them differently from the traditional
+ * libpcap <net/bpf.h>
+ *
+ * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS,
+ * but I don't know what the right #define is for BSD/OS.
+ */
+#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */
+
+#ifdef __OpenBSD__
+#define DLT_RAW 14 /* raw IP */
+#else
+#define DLT_RAW 12 /* raw IP */
+#endif
+
+/*
+ * Given that the only OS that currently generates BSD/OS SLIP or PPP
+ * is, well, BSD/OS, arguably everybody should have chosen its values
+ * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they
+ * didn't. So it goes.
+ */
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#ifndef DLT_SLIP_BSDOS
+#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */
+#endif
+#else
+#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */
+#endif
+
+/*
+ * 17 is used for DLT_OLD_PFLOG in OpenBSD;
+ * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below.
+ * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else.
+ */
+
+#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */
+
+/*
+ * Apparently Redback uses this for its SmartEdge 400/800. I hope
+ * nobody else decided to use it, too.
+ */
+#define DLT_REDBACK_SMARTEDGE 32
+
+/*
+ * These values are defined by NetBSD; other platforms should refrain from
+ * using them for other purposes, so that NetBSD savefiles with link
+ * types of 50 or 51 can be read as this type on all platforms.
+ */
+#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */
+#define DLT_PPP_ETHER 51 /* PPP over Ethernet */
+
+/*
+ * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses
+ * a link-layer type of 99 for the tcpdump it supplies. The link-layer
+ * header has 6 bytes of unknown data, something that appears to be an
+ * Ethernet type, and 36 bytes that appear to be 0 in at least one capture
+ * I've seen.
+ */
+#define DLT_SYMANTEC_FIREWALL 99
+
+/*
+ * Values between 100 and 103 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that differ
+ * between platforms; don't use those values for new DLT_ new types.
+ */
+
+/*
+ * This value was defined by libpcap 0.5; platforms that have defined
+ * it with a different value should define it here with that value -
+ * a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ * whatever value that happens to be, so programs will correctly
+ * handle files with that link type regardless of the value of
+ * DLT_C_HDLC.
+ *
+ * The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ * compatibility with programs written for BSD/OS.
+ *
+ * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ * for source compatibility with programs written for libpcap 0.5.
+ */
+#define DLT_C_HDLC 104 /* Cisco HDLC */
+#define DLT_CHDLC DLT_C_HDLC
+
+#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */
+
+/*
+ * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW,
+ * except when it isn't. (I.e., sometimes it's just raw IP, and
+ * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL,
+ * so that we don't have to worry about the link-layer header.)
+ */
+
+/*
+ * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides
+ * with other values.
+ * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header
+ * (DLCI, etc.).
+ */
+#define DLT_FRELAY 107
+
+/*
+ * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ * that the AF_ type in the link-layer header is in network byte order.
+ *
+ * OpenBSD defines it as 12, but that collides with DLT_RAW, so we
+ * define it as 108 here. If OpenBSD picks up this file, it should
+ * define DLT_LOOP as 12 in its version, as per the comment above -
+ * and should not use 108 as a DLT_ value.
+ */
+#define DLT_LOOP 108
+
+/*
+ * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's
+ * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other
+ * than OpenBSD.
+ */
+#ifdef __OpenBSD__
+#define DLT_ENC 13
+#else
+#define DLT_ENC 109
+#endif
+
+/*
+ * Values between 110 and 112 are reserved for use in capture file headers
+ * as link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ types
+ * other than the corresponding DLT_ types.
+ */
+
+/*
+ * This is for Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL 113
+
+/*
+ * Apple LocalTalk hardware.
+ */
+#define DLT_LTALK 114
+
+/*
+ * Acorn Econet.
+ */
+#define DLT_ECONET 115
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define DLT_IPFILTER 116
+
+/*
+ * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023
+ * in SuSE 6.3, so we can't use 17 for it in capture-file headers.
+ *
+ * XXX: is there a conflict with DLT_PFSYNC 18 as well?
+ */
+#ifdef __OpenBSD__
+#define DLT_OLD_PFLOG 17
+#define DLT_PFSYNC 18
+#endif
+#define DLT_PFLOG 117
+
+/*
+ * Registered for Cisco-internal use.
+ */
+#define DLT_CISCO_IOS 118
+
+/*
+ * For 802.11 cards using the Prism II chips, with a link-layer
+ * header including Prism monitor mode information plus an 802.11
+ * header.
+ */
+#define DLT_PRISM_HEADER 119
+
+/*
+ * Reserved for Aironet 802.11 cards, with an Aironet link-layer header
+ * (see Doug Ambrisko's FreeBSD patches).
+ */
+#define DLT_AIRONET_HEADER 120
+
+/*
+ * Reserved for Siemens HiPath HDLC.
+ */
+#define DLT_HHDLC 121
+
+/*
+ * This is for RFC 2625 IP-over-Fibre Channel.
+ *
+ * This is not for use with raw Fibre Channel, where the link-layer
+ * header starts with a Fibre Channel frame header; it's for IP-over-FC,
+ * where the link-layer header starts with an RFC 2625 Network_Header
+ * field.
+ */
+#define DLT_IP_OVER_FC 122
+
+/*
+ * This is for Full Frontal ATM on Solaris with SunATM, with a
+ * pseudo-header followed by an AALn PDU.
+ *
+ * There may be other forms of Full Frontal ATM on other OSes,
+ * with different pseudo-headers.
+ *
+ * If ATM software returns a pseudo-header with VPI/VCI information
+ * (and, ideally, packet type information, e.g. signalling, ILMI,
+ * LANE, LLC-multiplexed traffic, etc.), it should not use
+ * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump
+ * and the like don't have to infer the presence or absence of a
+ * pseudo-header and the form of the pseudo-header.
+ */
+#define DLT_SUNATM 123 /* Solaris+SunATM */
+
+/*
+ * Reserved as per request from Kent Dahlgren <kent@praesum.com>
+ * for private use.
+ */
+#define DLT_RIO 124 /* RapidIO */
+#define DLT_PCI_EXP 125 /* PCI Express */
+#define DLT_AURORA 126 /* Xilinx Aurora link layer */
+
+/*
+ * Header for 802.11 plus a number of bits of link-layer information
+ * including radio information, used by some recent BSD drivers as
+ * well as the madwifi Atheros driver for Linux.
+ */
+#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */
+
+/*
+ * Reserved for the TZSP encapsulation, as per request from
+ * Chris Waters <chris.waters@networkchemistry.com>
+ * TZSP is a generic encapsulation for any other link type,
+ * which includes a means to include meta-information
+ * with the packet, e.g. signal strength and channel
+ * for 802.11 packets.
+ */
+#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */
+
+/*
+ * BSD's ARCNET headers have the source host, destination host,
+ * and type at the beginning of the packet; that's what's handed
+ * up to userland via BPF.
+ *
+ * Linux's ARCNET headers, however, have a 2-byte offset field
+ * between the host IDs and the type; that's what's handed up
+ * to userland via PF_PACKET sockets.
+ *
+ * We therefore have to have separate DLT_ values for them.
+ */
+#define DLT_ARCNET_LINUX 129 /* ARCNET */
+
+/*
+ * Juniper-private data link types, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MLPPP 130
+#define DLT_JUNIPER_MLFR 131
+#define DLT_JUNIPER_ES 132
+#define DLT_JUNIPER_GGSN 133
+#define DLT_JUNIPER_MFR 134
+#define DLT_JUNIPER_ATM2 135
+#define DLT_JUNIPER_SERVICES 136
+#define DLT_JUNIPER_ATM1 137
+
+/*
+ * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund
+ * <dieter@apple.com>. The header that's presented is an Ethernet-like
+ * header:
+ *
+ * #define FIREWIRE_EUI64_LEN 8
+ * struct firewire_header {
+ * u_char firewire_dhost[FIREWIRE_EUI64_LEN];
+ * u_char firewire_shost[FIREWIRE_EUI64_LEN];
+ * u_short firewire_type;
+ * };
+ *
+ * with "firewire_type" being an Ethernet type value, rather than,
+ * for example, raw GASP frames being handed up.
+ */
+#define DLT_APPLE_IP_OVER_IEEE1394 138
+
+/*
+ * Various SS7 encapsulations, as per a request from Jeff Morriss
+ * <jeff.morriss[AT]ulticom.com> and subsequent discussions.
+ */
+#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */
+#define DLT_MTP2 140 /* MTP2, without pseudo-header */
+#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */
+#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */
+
+/*
+ * DOCSIS MAC frames.
+ */
+#define DLT_DOCSIS 143
+
+/*
+ * Linux-IrDA packets. Protocol defined at http://www.irda.org.
+ * Those packets include IrLAP headers and above (IrLMP...), but
+ * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy
+ * framing can be handled by the hardware and depend on the bitrate.
+ * This is exactly the format you would get capturing on a Linux-IrDA
+ * interface (irdaX), but not on a raw serial port.
+ * Note the capture is done in "Linux-cooked" mode, so each packet include
+ * a fake packet header (struct sll_header). This is because IrDA packet
+ * decoding is dependant on the direction of the packet (incomming or
+ * outgoing).
+ * When/if other platform implement IrDA capture, we may revisit the
+ * issue and define a real DLT_IRDA...
+ * Jean II
+ */
+#define DLT_LINUX_IRDA 144
+
+/*
+ * Reserved for IBM SP switch and IBM Next Federation switch.
+ */
+#define DLT_IBM_SP 145
+#define DLT_IBM_SN 146
+
+/*
+ * Reserved for private use. If you have some link-layer header type
+ * that you want to use within your organization, with the capture files
+ * using that link-layer header type not ever be sent outside your
+ * organization, you can use these values.
+ *
+ * No libpcap release will use these for any purpose, nor will any
+ * tcpdump release use them, either.
+ *
+ * Do *NOT* use these in capture files that you expect anybody not using
+ * your private versions of capture-file-reading tools to read; in
+ * particular, do *NOT* use them in products, otherwise you may find that
+ * people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ * read capture files from your firewall/intrusion detection/traffic
+ * monitoring/etc. appliance, or whatever product uses that DLT_ value,
+ * and you may also find that the developers of those applications will
+ * not accept patches to let them read those files.
+ *
+ * Also, do not use them if somebody might send you a capture using them
+ * for *their* private type and tools using them for *your* private type
+ * would have to read them.
+ *
+ * Instead, ask "tcpdump-workers@tcpdump.org" for a new DLT_ value,
+ * as per the comment above, and use the type you're given.
+ */
+#define DLT_USER0 147
+#define DLT_USER1 148
+#define DLT_USER2 149
+#define DLT_USER3 150
+#define DLT_USER4 151
+#define DLT_USER5 152
+#define DLT_USER6 153
+#define DLT_USER7 154
+#define DLT_USER8 155
+#define DLT_USER9 156
+#define DLT_USER10 157
+#define DLT_USER11 158
+#define DLT_USER12 159
+#define DLT_USER13 160
+#define DLT_USER14 161
+#define DLT_USER15 162
+
+/*
+ * For future use with 802.11 captures - defined by AbsoluteValue
+ * Systems to store a number of bits of link-layer information
+ * including radio information:
+ *
+ * http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ *
+ * but it might be used by some non-AVS drivers now or in the
+ * future.
+ */
+#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MONITOR 164
+
+/*
+ * Reserved for BACnet MS/TP.
+ */
+#define DLT_BACNET_MS_TP 165
+
+/*
+ * Another PPP variant as per request from Karsten Keil <kkeil@suse.de>.
+ *
+ * This is used in some OSes to allow a kernel socket filter to distinguish
+ * between incoming and outgoing packets, on a socket intended to
+ * supply pppd with outgoing packets so it can do dial-on-demand and
+ * hangup-on-lack-of-demand; incoming packets are filtered out so they
+ * don't cause pppd to hold the connection up (you don't want random
+ * input packets such as port scans, packets from old lost connections,
+ * etc. to force the connection to stay up).
+ *
+ * The first byte of the PPP header (0xff03) is modified to accomodate
+ * the direction - 0x00 = IN, 0x01 = OUT.
+ */
+#define DLT_PPP_PPPD 166
+
+/*
+ * Names for backwards compatibility with older versions of some PPP
+ * software; new software should use DLT_PPP_PPPD.
+ */
+#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD
+#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, cookies, etc..
+ */
+#define DLT_JUNIPER_PPPOE 167
+#define DLT_JUNIPER_PPPOE_ATM 168
+
+#define DLT_GPRS_LLC 169 /* GPRS LLC */
+#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */
+#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */
+
+/*
+ * Requested by Oolan Zimmer <oz@gcom.com> for use in Gcom's T1/E1 line
+ * monitoring equipment.
+ */
+#define DLT_GCOM_T1E1 172
+#define DLT_GCOM_SERIAL 173
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_ is used
+ * for internal communication to Physical Interface Cards (PIC)
+ */
+#define DLT_JUNIPER_PIC_PEER 174
+
+/*
+ * Link types requested by Gregor Maier <gregor@endace.com> of Endace
+ * Measurement Systems. They add an ERF header (see
+ * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * the link-layer header.
+ */
+#define DLT_ERF_ETH 175 /* Ethernet */
+#define DLT_ERF_POS 176 /* Packet-over-SONET */
+
+/*
+ * Requested by Daniele Orlandi <daniele@orlandi.com> for raw LAPD
+ * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header
+ * includes additional information before the LAPD header, so it's
+ * not necessarily a generic LAPD header.
+ */
+#define DLT_LINUX_LAPD 177
+
+/*
+ * The instruction encodings.
+ */
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define BPF_A 0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define BPF_TAX 0x00
+#define BPF_TXA 0x80
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+ u_short code;
+ u_char jt;
+ u_char jf;
+ bpf_int32 k;
+};
+
+/*
+ * Macros for insn array initializers.
+ */
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+#if __STDC__ || defined(__cplusplus)
+extern int bpf_validate(struct bpf_insn *, int);
+extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
+#else
+extern int bpf_validate();
+extern u_int bpf_filter();
+#endif
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/ipfilter/pcap-ipf.h b/contrib/ipfilter/pcap-ipf.h
new file mode 100644
index 0000000..b856760
--- /dev/null
+++ b/contrib/ipfilter/pcap-ipf.h
@@ -0,0 +1,35 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+/*
+ * This header file is constructed to match the version described by
+ * PCAP_VERSION_MAJ.
+ *
+ * The structure largely derives from libpcap which wouldn't include
+ * nicely without bpf.
+ */
+typedef struct pcap_filehdr {
+ u_int pc_id;
+ u_short pc_v_maj;
+ u_short pc_v_min;
+ u_int pc_zone;
+ u_int pc_sigfigs;
+ u_int pc_slen;
+ u_int pc_type;
+} pcaphdr_t;
+
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+
+#define PCAP_VERSION_MAJ 2
+
+typedef struct pcap_pkthdr {
+ struct timeval ph_ts;
+ u_int ph_clen;
+ u_int ph_len;
+} pcappkt_t;
+
diff --git a/contrib/ipfilter/radix_ipf.c b/contrib/ipfilter/radix_ipf.c
new file mode 100644
index 0000000..f145c38
--- /dev/null
+++ b/contrib/ipfilter/radix_ipf.c
@@ -0,0 +1,1528 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#if !defined(_KERNEL)
+# include <stddef.h>
+# include <stdlib.h>
+# include <strings.h>
+# include <string.h>
+#endif
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#ifdef RDX_DEBUG
+# include <arpa/inet.h>
+# include <stdlib.h>
+# include <stdio.h>
+#endif
+#include "netinet/radix_ipf.h"
+
+#define ADF_OFF offsetof(addrfamily_t, adf_addr)
+#define ADF_OFF_BITS (ADF_OFF << 3)
+
+static ipf_rdx_node_t *ipf_rx_insert __P((ipf_rdx_head_t *,
+ ipf_rdx_node_t nodes[2], int *));
+static void ipf_rx_attach_mask __P((ipf_rdx_node_t *, ipf_rdx_mask_t *));
+static int count_mask_bits __P((addrfamily_t *, u_32_t **));
+static void buildnodes __P((addrfamily_t *, addrfamily_t *,
+ ipf_rdx_node_t n[2]));
+static ipf_rdx_node_t *ipf_rx_find_addr __P((ipf_rdx_node_t *, u_32_t *));
+static ipf_rdx_node_t *ipf_rx_lookup __P((ipf_rdx_head_t *, addrfamily_t *,
+ addrfamily_t *));
+static ipf_rdx_node_t *ipf_rx_match __P((ipf_rdx_head_t *, addrfamily_t *));
+
+/*
+ * Foreword.
+ * ---------
+ * The code in this file has been written to target using the addrfamily_t
+ * data structure to house the address information and no other. Thus there
+ * are certain aspects of thise code (such as offsets to the address itself)
+ * that are hard coded here whilst they might be more variable elsewhere.
+ * Similarly, this code enforces no maximum key length as that's implied by
+ * all keys needing to be stored in addrfamily_t.
+ */
+
+/* ------------------------------------------------------------------------ */
+/* Function: count_mask_bits */
+/* Returns: number of consecutive bits starting at "mask". */
+/* */
+/* Count the number of bits set in the address section of addrfamily_t and */
+/* return both that number and a pointer to the last word with a bit set if */
+/* lastp is not NULL. The bit count is performed using network byte order */
+/* as the guide for which bit is the most significant bit. */
+/* ------------------------------------------------------------------------ */
+static int
+count_mask_bits(mask, lastp)
+ addrfamily_t *mask;
+ u_32_t **lastp;
+{
+ u_32_t *mp = (u_32_t *)&mask->adf_addr;
+ u_32_t m;
+ int count = 0;
+ int mlen;
+
+ mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
+ for (; mlen > 0; mlen -= 4, mp++) {
+ if ((m = ntohl(*mp)) == 0)
+ break;
+ if (lastp != NULL)
+ *lastp = mp;
+ for (; m & 0x80000000; m <<= 1)
+ count++;
+ }
+
+ return count;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: buildnodes */
+/* Returns: Nil */
+/* Parameters: addr(I) - network address for this radix node */
+/* mask(I) - netmask associated with the above address */
+/* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
+/* associated with addr and mask. */
+/* */
+/* Initialise the fields in a pair of radix tree nodes according to the */
+/* data supplied in the paramters "addr" and "mask". It is expected that */
+/* "mask" will contain a consecutive string of bits set. Masks with gaps in */
+/* the middle are not handled by this implementation. */
+/* ------------------------------------------------------------------------ */
+static void
+buildnodes(addr, mask, nodes)
+ addrfamily_t *addr, *mask;
+ ipf_rdx_node_t nodes[2];
+{
+ u_32_t maskbits;
+ u_32_t lastbits;
+ u_32_t lastmask;
+ u_32_t *last;
+ int masklen;
+
+ last = NULL;
+ maskbits = count_mask_bits(mask, &last);
+ if (last == NULL) {
+ masklen = 0;
+ lastmask = 0;
+ } else {
+ masklen = last - (u_32_t *)mask;
+ lastmask = *last;
+ }
+ lastbits = maskbits & 0x1f;
+
+ bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
+ nodes[0].maskbitcount = maskbits;
+ nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
+ nodes[0].addrkey = (u_32_t *)addr;
+ nodes[0].maskkey = (u_32_t *)mask;
+ nodes[0].addroff = nodes[0].addrkey + masklen;
+ nodes[0].maskoff = nodes[0].maskkey + masklen;
+ nodes[0].parent = &nodes[1];
+ nodes[0].offset = masklen;
+ nodes[0].lastmask = lastmask;
+ nodes[1].offset = masklen;
+ nodes[1].left = &nodes[0];
+ nodes[1].maskbitcount = maskbits;
+#ifdef RDX_DEBUG
+ (void) strcpy(nodes[0].name, "_BUILD.0");
+ (void) strcpy(nodes[1].name, "_BUILD.1");
+#endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_find_addr */
+/* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */
+/* Parameters: tree(I) - pointer to first right node in tree to search */
+/* addr(I) - pointer to address to match */
+/* */
+/* Walk the radix tree given by "tree", looking for a leaf node that is a */
+/* match for the address given by "addr". */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_find_addr(tree, addr)
+ ipf_rdx_node_t *tree;
+ u_32_t *addr;
+{
+ ipf_rdx_node_t *cur;
+
+ for (cur = tree; cur->index >= 0;) {
+ if (cur->bitmask & addr[cur->offset]) {
+ cur = cur->right;
+ } else {
+ cur = cur->left;
+ }
+ }
+
+ return (cur);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_match */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - pointer to address to find */
+/* */
+/* Search the radix tree for the best match to the address pointed to by */
+/* "addr" and return a pointer to that node. This search will not match the */
+/* address information stored in either of the root leaves as neither of */
+/* them are considered to be part of the tree of data being stored. */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_match(head, addr)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr;
+{
+ ipf_rdx_mask_t *masknode;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *cur;
+ u_32_t *data;
+ u_32_t *mask;
+ u_32_t *key;
+ u_32_t *end;
+ int len;
+ int i;
+
+ len = addr->adf_len;
+ end = (u_32_t *)((u_char *)addr + len);
+ node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+
+ /*
+ * Search the dupkey list for a potential match.
+ */
+ for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
+ i = cur[0].addroff - cur[0].addrkey;
+ data = cur[0].addrkey + i;
+ mask = cur[0].maskkey + i;
+ key = (u_32_t *)addr + i;
+ for (; key < end; data++, key++, mask++)
+ if ((*key & *mask) != *data)
+ break;
+ if ((end == key) && (cur->root == 0))
+ return (cur); /* Equal keys */
+ }
+ prev = node->parent;
+ key = (u_32_t *)addr;
+
+ for (node = prev; node->root == 0; node = node->parent) {
+ /*
+ * We know that the node hasn't matched so therefore only
+ * the entries in the mask list are searched, not the top
+ * node nor the dupkey list.
+ */
+ masknode = node->masks;
+ for (; masknode != NULL; masknode = masknode->next) {
+ if (masknode->maskbitcount > node->maskbitcount)
+ continue;
+ cur = masknode->node;
+ for (i = ADF_OFF >> 2; i <= node->offset; i++) {
+ if ((key[i] & masknode->mask[i]) ==
+ cur->addrkey[i])
+ return (cur);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_lookup */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - address part of the key to match */
+/* mask(I) - netmask part of the key to match */
+/* */
+/* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */
+/* is to see if a given key is in the tree, not to see if a route exists. */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_lookup(head, addr, mask)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr, *mask;
+{
+ ipf_rdx_node_t *found;
+ ipf_rdx_node_t *node;
+ u_32_t *akey;
+ int count;
+
+ found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+ if (found->root == 1)
+ return NULL;
+
+ /*
+ * It is possible to find a matching address in the tree but for the
+ * netmask to not match. If the netmask does not match and there is
+ * no list of alternatives present at dupkey, return a failure.
+ */
+ count = count_mask_bits(mask, NULL);
+ if (count != found->maskbitcount && found->dupkey == NULL)
+ return (NULL);
+
+ akey = (u_32_t *)addr;
+ if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
+ akey[found->offset])
+ return NULL;
+
+ if (found->dupkey != NULL) {
+ node = found;
+ while (node != NULL && node->maskbitcount != count)
+ node = node->dupkey;
+ if (node == NULL)
+ return (NULL);
+ found = node;
+ }
+ return found;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_attach_mask */
+/* Returns: Nil */
+/* Parameters: node(I) - pointer to a radix tree node */
+/* mask(I) - pointer to mask structure to add */
+/* */
+/* Add the netmask to the given node in an ordering where the most specific */
+/* netmask is at the top of the list. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rx_attach_mask(node, mask)
+ ipf_rdx_node_t *node;
+ ipf_rdx_mask_t *mask;
+{
+ ipf_rdx_mask_t **pm;
+ ipf_rdx_mask_t *m;
+
+ for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
+ if (m->maskbitcount < mask->maskbitcount)
+ break;
+ mask->next = *pm;
+ *pm = mask;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_insert */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to add nodes to */
+/* nodes(I) - pointer to radix nodes to be added */
+/* dup(O) - set to 1 if node is a duplicate, else 0. */
+/* */
+/* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
+/* If there is already a matching key in the table, "dup" will be set to 1 */
+/* and the existing node pointer returned if there is a complete key match. */
+/* A complete key match is a matching of all key data that is presented by */
+/* by the netmask. */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_insert(head, nodes, dup)
+ ipf_rdx_head_t *head;
+ ipf_rdx_node_t nodes[2];
+ int *dup;
+{
+ ipf_rdx_mask_t **pmask;
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_mask_t *mask;
+ ipf_rdx_node_t *cur;
+ u_32_t nodemask;
+ u_32_t *addr;
+ u_32_t *data;
+ int nodebits;
+ u_32_t *key;
+ u_32_t *end;
+ u_32_t bits;
+ int nodekey;
+ int nodeoff;
+ int nlen;
+ int len;
+
+ addr = nodes[0].addrkey;
+
+ node = ipf_rx_find_addr(head->root, addr);
+ len = ((addrfamily_t *)addr)->adf_len;
+ key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
+ data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
+ end = (u_32_t *)((u_char *)addr + len);
+ for (nlen = 0; key < end; data++, key++, nlen += 32)
+ if (*key != *data)
+ break;
+ if (end == data) {
+ *dup = 1;
+ return (node); /* Equal keys */
+ }
+ *dup = 0;
+
+ bits = (ntohl(*data) ^ ntohl(*key));
+ for (; bits != 0; nlen++) {
+ if ((bits & 0x80000000) != 0)
+ break;
+ bits <<= 1;
+ }
+ nlen += ADF_OFF_BITS;
+ nodes[1].index = nlen;
+ nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
+ nodes[0].offset = nlen / 32;
+ nodes[1].offset = nlen / 32;
+
+ /*
+ * Walk through the tree and look for the correct place to attach
+ * this node. ipf_rx_fin_addr is not used here because the place
+ * to attach this node may be an internal node (same key, different
+ * netmask.) Additionally, the depth of the search is forcibly limited
+ * here to not exceed the netmask, so that a short netmask will be
+ * added higher up the tree even if there are lower branches.
+ */
+ cur = head->root;
+ key = nodes[0].addrkey;
+ do {
+ prev = cur;
+ if (key[cur->offset] & cur->bitmask) {
+ cur = cur->right;
+ } else {
+ cur = cur->left;
+ }
+ } while (nlen > (unsigned)cur->index);
+
+ if ((key[prev->offset] & prev->bitmask) == 0) {
+ prev->left = &nodes[1];
+ } else {
+ prev->right = &nodes[1];
+ }
+ cur->parent = &nodes[1];
+ nodes[1].parent = prev;
+ if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) {
+ nodes[1].right = cur;
+ } else {
+ nodes[1].right = &nodes[0];
+ nodes[1].left = cur;
+ }
+
+ nodeoff = nodes[0].offset;
+ nodekey = nodes[0].addrkey[nodeoff];
+ nodemask = nodes[0].lastmask;
+ nodebits = nodes[0].maskbitcount;
+ prev = NULL;
+ /*
+ * Find the node up the tree with the largest pattern that still
+ * matches the node being inserted to see if this mask can be
+ * moved there.
+ */
+ for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
+ if (cur->maskbitcount <= nodebits)
+ break;
+ if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
+ break;
+ prev = cur;
+ }
+
+ KMALLOC(mask, ipf_rdx_mask_t *);
+ if (mask == NULL)
+ return NULL;
+ bzero(mask, sizeof(*mask));
+ mask->next = NULL;
+ mask->node = &nodes[0];
+ mask->maskbitcount = nodebits;
+ mask->mask = nodes[0].maskkey;
+ nodes[0].mymask = mask;
+
+ if (prev != NULL) {
+ ipf_rdx_mask_t *m;
+
+ for (pmask = &prev->masks; (m = *pmask) != NULL;
+ pmask = &m->next) {
+ if (m->maskbitcount < nodebits)
+ break;
+ }
+ } else {
+ /*
+ * No higher up nodes qualify, so attach mask locally.
+ */
+ pmask = &nodes[0].masks;
+ }
+ mask->next = *pmask;
+ *pmask = mask;
+
+ /*
+ * Search the mask list on each child to see if there are any masks
+ * there that can be moved up to this newly inserted node.
+ */
+ cur = nodes[1].right;
+ if (cur->root == 0) {
+ for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
+ if (mask->maskbitcount < nodebits) {
+ *pmask = mask->next;
+ ipf_rx_attach_mask(&nodes[0], mask);
+ } else {
+ pmask = &mask->next;
+ }
+ }
+ }
+ cur = nodes[1].left;
+ if (cur->root == 0 && cur != &nodes[0]) {
+ for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
+ if (mask->maskbitcount < nodebits) {
+ *pmask = mask->next;
+ ipf_rx_attach_mask(&nodes[0], mask);
+ } else {
+ pmask = &mask->next;
+ }
+ }
+ }
+ return (&nodes[0]);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_addroute */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - address portion of "route" to add */
+/* mask(I) - netmask portion of "route" to add */
+/* nodes(I) - radix tree data nodes inside allocate structure */
+/* */
+/* Attempt to add a node to the radix tree. The key for the node is the */
+/* (addr,mask). No memory allocation for the radix nodes themselves is */
+/* performed here, the data structure that this radix node is being used to */
+/* find is expected to house the node data itself however the call to */
+/* ipf_rx_insert() will attempt to allocate memory in order for netmask to */
+/* be promoted further up the tree. */
+/* In this case, the ip_pool_node_t structure from ip_pool.h contains both */
+/* the key material (addr,mask) and the radix tree nodes[]. */
+/* */
+/* The mechanics of inserting the node into the tree is handled by the */
+/* function ipf_rx_insert() above. Here, the code deals with the case */
+/* where the data to be inserted is a duplicate. */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_addroute(head, addr, mask, nodes)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr, *mask;
+ ipf_rdx_node_t *nodes;
+{
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_node_t *x;
+ int dup;
+
+ buildnodes(addr, mask, nodes);
+ x = ipf_rx_insert(head, nodes, &dup);
+ if (x == NULL)
+ return NULL;
+
+ if (dup == 1) {
+ node = &nodes[0];
+ prev = NULL;
+ /*
+ * The duplicate list is kept sorted with the longest
+ * mask at the top, meaning that the most specific entry
+ * in the listis found first. This list thus allows for
+ * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
+ */
+ while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
+ prev = x;
+ x = x->dupkey;
+ }
+
+ /*
+ * Is it a complete duplicate? If so, return NULL and
+ * fail the insert. Otherwise, insert it into the list
+ * of netmasks active for this key.
+ */
+ if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
+ return (NULL);
+
+ if (prev != NULL) {
+ nodes[0].dupkey = x;
+ prev->dupkey = &nodes[0];
+ nodes[0].parent = prev;
+ if (x != NULL)
+ x->parent = &nodes[0];
+ } else {
+ nodes[0].dupkey = x->dupkey;
+ prev = x->parent;
+ nodes[0].parent = prev;
+ x->parent = &nodes[0];
+ if (prev->left == x)
+ prev->left = &nodes[0];
+ else
+ prev->right = &nodes[0];
+ }
+ }
+
+ return &nodes[0];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_delete */
+/* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */
+/* the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - pointer to the address part of the key */
+/* mask(I) - pointer to the netmask part of the key */
+/* */
+/* Search for an entry in the radix tree that is an exact match for (addr, */
+/* mask) and remove it if it exists. In the case where (addr,mask) is a not */
+/* a unique key, the tree structure itself is not changed - only the list */
+/* of duplicate keys. */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_delete(head, addr, mask)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr, *mask;
+{
+ ipf_rdx_mask_t **pmask;
+ ipf_rdx_node_t *parent;
+ ipf_rdx_node_t *found;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *cur;
+ ipf_rdx_mask_t *m;
+ int count;
+
+ found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+ if (found == NULL)
+ return NULL;
+ if (found->root == 1)
+ return NULL;
+ count = count_mask_bits(mask, NULL);
+ parent = found->parent;
+ if (found->dupkey != NULL) {
+ node = found;
+ while (node != NULL && node->maskbitcount != count)
+ node = node->dupkey;
+ if (node == NULL)
+ return (NULL);
+ if (node != found) {
+ /*
+ * Remove from the dupkey list. Here, "parent" is
+ * the previous node on the list (rather than tree)
+ * and "dupkey" is the next node on the list.
+ */
+ parent = node->parent;
+ parent->dupkey = node->dupkey;
+ node->dupkey->parent = parent;
+ } else {
+ /*
+ *
+ * When removing the top node of the dupkey list,
+ * the pointers at the top of the list that point
+ * to other tree nodes need to be preserved and
+ * any children must have their parent updated.
+ */
+ node = node->dupkey;
+ node->parent = found->parent;
+ node->right = found->right;
+ node->left = found->left;
+ found->right->parent = node;
+ found->left->parent = node;
+ if (parent->left == found)
+ parent->left = node;
+ else
+ parent->right= node;
+ }
+ } else {
+ if (count != found->maskbitcount)
+ return (NULL);
+ /*
+ * Remove the node from the tree and reconnect the subtree
+ * below.
+ */
+ /*
+ * If there is a tree to the left, look for something to
+ * attach in place of "found".
+ */
+ prev = found + 1;
+ cur = parent->parent;
+ if (parent != found + 1) {
+ if ((found + 1)->parent->right == found + 1)
+ (found + 1)->parent->right = parent;
+ else
+ (found + 1)->parent->left = parent;
+ if (cur->right == parent) {
+ if (parent->left == found) {
+ cur->right = parent->right;
+ } else if (parent->left != parent - 1) {
+ cur->right = parent->left;
+ } else {
+ cur->right = parent - 1;
+ }
+ cur->right->parent = cur;
+ } else {
+ if (parent->right == found) {
+ cur->left = parent->left;
+ } else if (parent->right != parent - 1) {
+ cur->left = parent->right;
+ } else {
+ cur->left = parent - 1;
+ }
+ cur->left->parent = cur;
+ }
+ parent->left = (found + 1)->left;
+ if ((found + 1)->right != parent)
+ parent->right = (found + 1)->right;
+ parent->left->parent = parent;
+ parent->right->parent = parent;
+ parent->parent = (found + 1)->parent;
+
+ parent->bitmask = prev->bitmask;
+ parent->offset = prev->offset;
+ parent->index = prev->index;
+ } else {
+ /*
+ * We found an edge node.
+ */
+ cur = parent->parent;
+ if (cur->left == parent) {
+ if (parent->left == found) {
+ cur->left = parent->right;
+ parent->right->parent = cur;
+ } else {
+ cur->left = parent->left;
+ parent->left->parent = cur;
+ }
+ } else {
+ if (parent->right != found) {
+ cur->right = parent->right;
+ parent->right->parent = cur;
+ } else {
+ cur->right = parent->left;
+ prev->left->parent = cur;
+ }
+ }
+ }
+ }
+
+ /*
+ * Remove mask associated with this node.
+ */
+ for (cur = parent; cur->root == 0; cur = cur->parent) {
+ ipf_rdx_mask_t **pm;
+
+ if (cur->maskbitcount <= found->maskbitcount)
+ break;
+ if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
+ found->addrkey[found->offset])
+ break;
+ for (pm = &cur->masks; (m = *pm) != NULL; )
+ if (m->node == cur) {
+ *pm = m->next;
+ break;
+ } else {
+ pm = &m->next;
+ }
+ }
+ KFREE(found->mymask);
+
+ /*
+ * Masks that have been brought up to this node from below need to
+ * be sent back down.
+ */
+ for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
+ *pmask = m->next;
+ cur = m->node;
+ if (cur == found)
+ continue;
+ if (found->addrkey[cur->offset] & cur->lastmask) {
+ ipf_rx_attach_mask(parent->right, m);
+ } else if (parent->left != found) {
+ ipf_rx_attach_mask(parent->left, m);
+ }
+ }
+
+ return (found);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_walktree */
+/* Returns: Nil */
+/* Paramters: head(I) - pointer to tree head to search */
+/* walker(I) - function to call for each node in the tree */
+/* arg(I) - parameter to pass to walker, in addition to the */
+/* node pointer */
+/* */
+/* A standard tree walking function except that it is iterative, rather */
+/* than recursive and tracks the next node in case the "walker" function */
+/* should happen to delete and free the current node. It thus goes without */
+/* saying that the "walker" function is not permitted to cause any change */
+/* in the validity of the data found at either the left or right child. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_walktree(head, walker, arg)
+ ipf_rdx_head_t *head;
+ radix_walk_func_t walker;
+ void *arg;
+{
+ ipf_rdx_node_t *next;
+ ipf_rdx_node_t *node = head->root;
+ ipf_rdx_node_t *base;
+
+ while (node->index >= 0)
+ node = node->left;
+
+ for (;;) {
+ base = node;
+ while ((node->parent->right == node) && (node->root == 0))
+ node = node->parent;
+
+ for (node = node->parent->right; node->index >= 0; )
+ node = node->left;
+ next = node;
+
+ for (node = base; node != NULL; node = base) {
+ base = node->dupkey;
+ if (node->root == 0)
+ walker(node, arg);
+ }
+ node = next;
+ if (node->root)
+ return;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_inithead */
+/* Returns: int - 0 = success, else failure */
+/* Paramters: softr(I) - pointer to radix context */
+/* headp(O) - location for where to store allocated tree head */
+/* */
+/* This function allocates and initialises a radix tree head structure. */
+/* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
+/* "2" is used as the all ones sentinel, leaving node "1" as the root from */
+/* which the tree is hung with node "0" on its left and node "2" to the */
+/* right. The context, "softr", is used here to provide a common source of */
+/* the zeroes and ones data rather than have one per head. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_rx_inithead(softr, headp)
+ radix_softc_t *softr;
+ ipf_rdx_head_t **headp;
+{
+ ipf_rdx_head_t *ptr;
+ ipf_rdx_node_t *node;
+
+ KMALLOC(ptr, ipf_rdx_head_t *);
+ *headp = ptr;
+ if (ptr == NULL)
+ return -1;
+ bzero(ptr, sizeof(*ptr));
+ node = ptr->nodes;
+ ptr->root = node + 1;
+ node[0].index = ADF_OFF_BITS;
+ node[0].index = -1 - node[0].index;
+ node[1].index = ADF_OFF_BITS;
+ node[2].index = node[0].index;
+ node[0].parent = node + 1;
+ node[1].parent = node + 1;
+ node[2].parent = node + 1;
+ node[1].bitmask = htonl(0x80000000);
+ node[0].root = 1;
+ node[1].root = 1;
+ node[2].root = 1;
+ node[0].offset = ADF_OFF_BITS >> 5;
+ node[1].offset = ADF_OFF_BITS >> 5;
+ node[2].offset = ADF_OFF_BITS >> 5;
+ node[1].left = &node[0];
+ node[1].right = &node[2];
+ node[0].addrkey = (u_32_t *)softr->zeros;
+ node[2].addrkey = (u_32_t *)softr->ones;
+#ifdef RDX_DEBUG
+ (void) strcpy(node[0].name, "0_ROOT");
+ (void) strcpy(node[1].name, "1_ROOT");
+ (void) strcpy(node[2].name, "2_ROOT");
+#endif
+
+ ptr->addaddr = ipf_rx_addroute;
+ ptr->deladdr = ipf_rx_delete;
+ ptr->lookup = ipf_rx_lookup;
+ ptr->matchaddr = ipf_rx_match;
+ ptr->walktree = ipf_rx_walktree;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_freehead */
+/* Returns: Nil */
+/* Paramters: head(I) - pointer to tree head to free */
+/* */
+/* This function simply free's up the radix tree head. Prior to calling */
+/* this function, it is expected that the tree will have been emptied. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_freehead(head)
+ ipf_rdx_head_t *head;
+{
+ KFREE(head);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_create */
+/* Parameters: Nil */
+/* */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_rx_create()
+{
+ radix_softc_t *softr;
+
+ KMALLOC(softr, radix_softc_t *);
+ if (softr == NULL)
+ return NULL;
+ bzero((char *)softr, sizeof(*softr));
+
+ KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
+ if (softr->zeros == NULL) {
+ KFREE(softr);
+ return (NULL);
+ }
+ softr->ones = softr->zeros + sizeof(addrfamily_t);
+
+ return softr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_init */
+/* Returns: int - 0 = success (always) */
+/* */
+/* ------------------------------------------------------------------------ */
+int
+ipf_rx_init(ctx)
+ void *ctx;
+{
+ radix_softc_t *softr = ctx;
+
+ memset(softr->zeros, 0, 3 * sizeof(addrfamily_t));
+ memset(softr->ones, 0xff, sizeof(addrfamily_t));
+
+ return (0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_destroy */
+/* Returns: Nil */
+/* */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_destroy(ctx)
+ void *ctx;
+{
+ radix_softc_t *softr = ctx;
+
+ if (softr->zeros != NULL)
+ KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
+ KFREE(softr);
+}
+
+/* ====================================================================== */
+
+#ifdef RDX_DEBUG
+/*
+ * To compile this file as a standalone test unit, use -DRDX_DEBUG=1
+ */
+#define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name)
+#define GNAME(y) ((y) == NULL ? "NULL" : NAME(y))
+
+typedef struct myst {
+ struct ipf_rdx_node nodes[2];
+ addrfamily_t dst;
+ addrfamily_t mask;
+ struct myst *next;
+ int printed;
+} myst_t;
+
+typedef struct tabe_s {
+ char *host;
+ char *mask;
+ char *what;
+} tabe_t;
+
+tabe_t builtin[] = {
+#if 1
+ { "192:168:100::0", "48", "d" },
+ { "192:168:100::2", "128", "d" },
+#else
+ { "127.192.0.0", "255.255.255.0", "d" },
+ { "127.128.0.0", "255.255.255.0", "d" },
+ { "127.96.0.0", "255.255.255.0", "d" },
+ { "127.80.0.0", "255.255.255.0", "d" },
+ { "127.72.0.0", "255.255.255.0", "d" },
+ { "127.64.0.0", "255.255.255.0", "d" },
+ { "127.56.0.0", "255.255.255.0", "d" },
+ { "127.48.0.0", "255.255.255.0", "d" },
+ { "127.40.0.0", "255.255.255.0", "d" },
+ { "127.32.0.0", "255.255.255.0", "d" },
+ { "127.24.0.0", "255.255.255.0", "d" },
+ { "127.16.0.0", "255.255.255.0", "d" },
+ { "127.8.0.0", "255.255.255.0", "d" },
+ { "124.0.0.0", "255.0.0.0", "d" },
+ { "125.0.0.0", "255.0.0.0", "d" },
+ { "126.0.0.0", "255.0.0.0", "d" },
+ { "127.0.0.0", "255.0.0.0", "d" },
+ { "10.0.0.0", "255.0.0.0", "d" },
+ { "128.250.0.0", "255.255.0.0", "d" },
+ { "192.168.0.0", "255.255.0.0", "d" },
+ { "192.168.1.0", "255.255.255.0", "d" },
+#endif
+ { NULL, NULL, NULL }
+};
+
+char *mtable[][1] = {
+#if 1
+ { "192:168:100::2" },
+ { "192:168:101::2" },
+#else
+ { "9.0.0.0" },
+ { "9.0.0.1" },
+ { "11.0.0.0" },
+ { "11.0.0.1" },
+ { "127.0.0.1" },
+ { "127.0.1.0" },
+ { "255.255.255.0" },
+ { "126.0.0.1" },
+ { "128.251.0.0" },
+ { "128.251.0.1" },
+ { "128.251.255.255" },
+ { "129.250.0.0" },
+ { "129.250.0.1" },
+ { "192.168.255.255" },
+#endif
+ { NULL }
+};
+
+
+int forder[22] = {
+ 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8,
+ 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21
+};
+
+static int nodecount = 0;
+myst_t *myst_top = NULL;
+tabe_t *ttable = NULL;
+
+void add_addr(ipf_rdx_head_t *, int , int);
+void checktree(ipf_rdx_head_t *);
+void delete_addr(ipf_rdx_head_t *rnh, int item);
+void dumptree(ipf_rdx_head_t *rnh);
+void nodeprinter(ipf_rdx_node_t *, void *);
+void printroots(ipf_rdx_head_t *);
+void random_add(ipf_rdx_head_t *);
+void random_delete(ipf_rdx_head_t *);
+void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int);
+
+
+static void
+ipf_rx_freenode(node, arg)
+ ipf_rdx_node_t *node;
+ void *arg;
+{
+ ipf_rdx_head_t *head = arg;
+ ipf_rdx_node_t *rv;
+ myst_t *stp;
+
+ stp = (myst_t *)node;
+ rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
+ if (rv != NULL) {
+ free(rv);
+ }
+}
+
+
+const char *
+addrname(ap)
+ addrfamily_t *ap;
+{
+ static char name[80];
+ const char *txt;
+
+ bzero((char *)name, sizeof(name));
+ txt = inet_ntop(ap->adf_family, &ap->adf_addr, name,
+ sizeof(name));
+ return txt;
+}
+
+
+void
+fill6bits(bits, msk)
+ int bits;
+ u_int *msk;
+{
+ if (bits == 0) {
+ msk[0] = 0;
+ msk[1] = 0;
+ msk[2] = 0;
+ msk[3] = 0;
+ return;
+ }
+
+ msk[0] = 0xffffffff;
+ msk[1] = 0xffffffff;
+ msk[2] = 0xffffffff;
+ msk[3] = 0xffffffff;
+
+ if (bits == 128)
+ return;
+ if (bits > 96) {
+ msk[3] = htonl(msk[3] << (128 - bits));
+ } else if (bits > 64) {
+ msk[3] = 0;
+ msk[2] = htonl(msk[2] << (96 - bits));
+ } else if (bits > 32) {
+ msk[3] = 0;
+ msk[2] = 0;
+ msk[1] = htonl(msk[1] << (64 - bits));
+ } else {
+ msk[3] = 0;
+ msk[2] = 0;
+ msk[1] = 0;
+ msk[0] = htonl(msk[0] << (32 - bits));
+ }
+}
+
+
+void
+setaddr(afp, str)
+ addrfamily_t *afp;
+ char *str;
+{
+
+ bzero((char *)afp, sizeof(*afp));
+
+ if (strchr(str, ':') == NULL) {
+ afp->adf_family = AF_INET;
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+ } else {
+ afp->adf_family = AF_INET6;
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
+ }
+ inet_pton(afp->adf_family, str, &afp->adf_addr);
+}
+
+
+void
+setmask(afp, str)
+ addrfamily_t *afp;
+ char *str;
+{
+ if (strchr(str, '.') != NULL) {
+ afp->adf_addr.in4.s_addr = inet_addr(str);
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+ } else if (afp->adf_family == AF_INET) {
+ afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str)));
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+ } else if (afp->adf_family == AF_INET6) {
+ fill6bits(atoi(str), afp->adf_addr.i6);
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
+ }
+}
+
+
+void
+nodeprinter(node, arg)
+ ipf_rdx_node_t *node;
+ void *arg;
+{
+ myst_t *stp = (myst_t *)node;
+
+ printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
+ node[0].name,
+ GNAME(node[1].left), GNAME(node[1].right),
+ GNAME(node[0].parent), GNAME(node[1].parent),
+ addrname(&stp->dst), node[0].maskbitcount);
+ if (stp->printed == -1)
+ printf("!!! %d\n", stp->printed);
+ else
+ stp->printed = 1;
+}
+
+
+void
+printnode(stp)
+ myst_t *stp;
+{
+ ipf_rdx_node_t *node = &stp->nodes[0];
+
+ if (stp->nodes[0].index > 0)
+ stp = (myst_t *)&stp->nodes[-1];
+
+ printf("Node %-9.9s ", node[0].name);
+ printf("L %-9.9s ", GNAME(node[1].left));
+ printf("R %-9.9s ", GNAME(node[1].right));
+ printf("P %9.9s", GNAME(node[0].parent));
+ printf("/%-9.9s ", GNAME(node[1].parent));
+ printf("%s P%d\n", addrname(&stp->dst), stp->printed);
+}
+
+
+void
+buildtab(void)
+{
+ char line[80], *s;
+ tabe_t *tab;
+ int lines;
+ FILE *fp;
+
+ lines = 0;
+ fp = fopen("hosts", "r");
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ s = strchr(line, '\n');
+ if (s != NULL)
+ *s = '\0';
+ lines++;
+ if (lines == 1)
+ tab = malloc(sizeof(*tab) * 2);
+ else
+ tab = realloc(tab, (lines + 1) * sizeof(*tab));
+ tab[lines - 1].host = strdup(line);
+ s = strchr(tab[lines - 1].host, '/');
+ *s++ = '\0';
+ tab[lines - 1].mask = s;
+ tab[lines - 1].what = "d";
+ }
+ fclose(fp);
+
+ tab[lines].host = NULL;
+ tab[lines].mask = NULL;
+ tab[lines].what = NULL;
+ ttable = tab;
+}
+
+
+void
+printroots(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+ GNAME(&rnh->nodes[0]),
+ rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
+ GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
+ printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+ GNAME(&rnh->nodes[1]),
+ rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
+ GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
+ printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+ GNAME(&rnh->nodes[2]),
+ rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
+ GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ addrfamily_t af;
+ ipf_rdx_head_t *rnh;
+ radix_softc_t *ctx;
+ int j;
+ int i;
+
+ rnh = NULL;
+
+ buildtab();
+ ctx = ipf_rx_create();
+ ipf_rx_init(ctx);
+ ipf_rx_inithead(ctx, &rnh);
+
+ printf("=== ADD-0 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ add_addr(rnh, i, i);
+ checktree(rnh);
+ }
+ printroots(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ printf("=== DELETE-0 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ delete_addr(rnh, i);
+ printroots(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ }
+ printf("=== ADD-1 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ setaddr(&af, ttable[i].host);
+ add_addr(rnh, i, i); /*forder[i]); */
+ checktree(rnh);
+ }
+ dumptree(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ printf("=== TEST-1 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ setaddr(&af, ttable[i].host);
+ test_addr(rnh, i, &af, -1);
+ }
+
+ printf("=== TEST-2 ===\n");
+ for (i = 0; mtable[i][0] != NULL; i++) {
+ setaddr(&af, mtable[i][0]);
+ test_addr(rnh, i, &af, -1);
+ }
+ printf("=== DELETE-1 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ if (ttable[i].what[0] != 'd')
+ continue;
+ delete_addr(rnh, i);
+ for (j = 0; ttable[j].host != NULL; j++) {
+ setaddr(&af, ttable[j].host);
+ test_addr(rnh, i, &af, 3);
+ }
+ printroots(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ }
+
+ dumptree(rnh);
+
+ printf("=== ADD-2 ===\n");
+ random_add(rnh);
+ checktree(rnh);
+ dumptree(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ printf("=== DELETE-2 ===\n");
+ random_delete(rnh);
+ checktree(rnh);
+ dumptree(rnh);
+
+ ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
+
+ return 0;
+}
+
+
+void
+dumptree(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ myst_t *stp;
+
+ printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
+ printroots(rnh);
+ for (stp = myst_top; stp; stp = stp->next)
+ printnode(stp);
+ printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
+}
+
+
+void
+test_addr(rnh, pref, addr, limit)
+ ipf_rdx_head_t *rnh;
+ int pref;
+ addrfamily_t *addr;
+{
+ static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
+ 15, 16, 19, 255, 256, 65535, 65536
+ };
+ ipf_rdx_node_t *rn;
+ addrfamily_t af;
+ char name[80];
+ myst_t *stp;
+ int i;
+
+ memset(&af, 0, sizeof(af));
+#if 0
+ if (limit < 0 || limit > 14)
+ limit = 14;
+
+ for (i = 0; i < limit; i++) {
+ if (ttable[i].host == NULL)
+ break;
+ setaddr(&af, ttable[i].host);
+ printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af));
+ rn = ipf_rx_match(rnh, &af);
+ stp = (myst_t *)rn;
+ printf(" = %s (%s/%d)\n", GNAME(rn),
+ rn ? addrname(&stp->dst) : "NULL",
+ rn ? rn->maskbitcount : 0);
+ }
+#else
+ printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr));
+ rn = ipf_rx_match(rnh, addr);
+ stp = (myst_t *)rn;
+ printf(" = %s (%s/%d)\n", GNAME(rn),
+ rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0);
+#endif
+}
+
+
+void
+delete_addr(rnh, item)
+ ipf_rdx_head_t *rnh;
+ int item;
+{
+ ipf_rdx_node_t *rn;
+ addrfamily_t mask;
+ addrfamily_t af;
+ myst_t **pstp;
+ myst_t *stp;
+
+ memset(&af, 0, sizeof(af));
+ memset(&mask, 0, sizeof(mask));
+ setaddr(&af, ttable[item].host);
+ mask.adf_family = af.adf_family;
+ setmask(&mask, ttable[item].mask);
+
+ printf("DELETE(%s)\n", addrname(&af));
+ rn = ipf_rx_delete(rnh, &af, &mask);
+ if (rn == NULL) {
+ printf("FAIL LOOKUP DELETE\n");
+ checktree(rnh);
+ for (stp = myst_top; stp != NULL; stp = stp->next)
+ if (stp->printed != -1)
+ stp->printed = -2;
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ dumptree(rnh);
+ abort();
+ }
+ printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn));
+
+ for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
+ if (stp == (myst_t *)rn)
+ break;
+ stp->printed = -1;
+ stp->nodes[0].parent = &stp->nodes[0];
+ stp->nodes[1].parent = &stp->nodes[1];
+ *pstp = stp->next;
+ free(stp);
+ nodecount--;
+ checktree(rnh);
+}
+
+
+void
+add_addr(rnh, n, item)
+ ipf_rdx_head_t *rnh;
+ int n, item;
+{
+ ipf_rdx_node_t *rn;
+ myst_t *stp;
+
+ stp = calloc(1, sizeof(*stp));
+ rn = (ipf_rdx_node_t *)stp;
+ setaddr(&stp->dst, ttable[item].host);
+ stp->mask.adf_family = stp->dst.adf_family;
+ setmask(&stp->mask, ttable[item].mask);
+ stp->next = myst_top;
+ myst_top = stp;
+ (void) sprintf(rn[0].name, "_BORN.0");
+ (void) sprintf(rn[1].name, "_BORN.1");
+ rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
+ (void) sprintf(rn[0].name, "%d_NODE.0", item);
+ (void) sprintf(rn[1].name, "%d_NODE.1", item);
+ printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
+ nodecount++;
+ checktree(rnh);
+}
+
+
+void
+checktree(ipf_rdx_head_t *head)
+{
+ myst_t *s1;
+ ipf_rdx_node_t *rn;
+
+ if (nodecount <= 1)
+ return;
+
+ for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
+ int fault = 0;
+ if (s1->printed == -1)
+ continue;
+ rn = &s1->nodes[1];
+ if (rn->right->parent != rn)
+ fault |= 1;
+ if (rn->left->parent != rn)
+ fault |= 2;
+ if (rn->parent->left != rn && rn->parent->right != rn)
+ fault |= 4;
+ if (fault != 0) {
+ printf("FAULT %#x %s\n", fault, rn->name);
+ dumptree(head);
+ ipf_rx_walktree(head, nodeprinter, NULL);
+ fflush(stdout);
+ fflush(stderr);
+ printf("--\n");
+ abort();
+ }
+ }
+}
+
+
+int *
+randomize(int *pnitems)
+{
+ int *order;
+ int nitems;
+ int choice;
+ int j;
+ int i;
+
+ nitems = sizeof(ttable) / sizeof(ttable[0]);
+ *pnitems = nitems;
+ order = calloc(nitems, sizeof(*order));
+ srandom(getpid() * time(NULL));
+ memset(order, 0xff, nitems * sizeof(*order));
+ order[21] = 21;
+ for (i = 0; i < nitems - 1; i++) {
+ do {
+ choice = rand() % (nitems - 1);
+ for (j = 0; j < nitems; j++)
+ if (order[j] == choice)
+ break;
+ } while (j != nitems);
+ order[i] = choice;
+ }
+
+ return order;
+}
+
+
+void
+random_add(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ int *order;
+ int nitems;
+ int i;
+
+ order = randomize(&nitems);
+
+ for (i = 0; i < nitems - 1; i++) {
+ add_addr(rnh, i, order[i]);
+ checktree(rnh);
+ }
+}
+
+
+void
+random_delete(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ int *order;
+ int nitems;
+ int i;
+
+ order = randomize(&nitems);
+
+ for (i = 0; i < nitems - 1; i++) {
+ delete_addr(rnh, i);
+ checktree(rnh);
+ }
+}
+#endif /* RDX_DEBUG */
diff --git a/contrib/ipfilter/radix_ipf.h b/contrib/ipfilter/radix_ipf.h
new file mode 100644
index 0000000..bbbf559
--- /dev/null
+++ b/contrib/ipfilter/radix_ipf.h
@@ -0,0 +1,97 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#ifndef __RADIX_IPF_H__
+#define __RADIX_IPF_H__
+
+#ifndef U_32_T
+typedef unsigned int u_32_t;
+# define U_32_T 1
+#endif
+
+typedef struct ipf_rdx_mask {
+ struct ipf_rdx_mask *next;
+ struct ipf_rdx_node *node;
+ u_32_t *mask;
+ int maskbitcount;
+} ipf_rdx_mask_t;
+
+typedef struct ipf_rdx_node {
+ struct ipf_rdx_node *left;
+ struct ipf_rdx_node *right;
+ struct ipf_rdx_node *parent;
+ struct ipf_rdx_node *dupkey;
+ struct ipf_rdx_mask *masks;
+ struct ipf_rdx_mask *mymask;
+ u_32_t *addrkey;
+ u_32_t *maskkey;
+ u_32_t *addroff;
+ u_32_t *maskoff;
+ u_32_t lastmask;
+ u_32_t bitmask;
+ int offset;
+ int index;
+ int maskbitcount;
+ int root;
+#ifdef RDX_DEBUG
+ char name[40];
+#endif
+} ipf_rdx_node_t;
+
+struct ipf_rdx_head;
+
+typedef void (* radix_walk_func_t)(ipf_rdx_node_t *, void *);
+typedef ipf_rdx_node_t *(* idx_hamn_func_t)(struct ipf_rdx_head *,
+ addrfamily_t *, addrfamily_t *,
+ ipf_rdx_node_t *);
+typedef ipf_rdx_node_t *(* idx_ham_func_t)(struct ipf_rdx_head *,
+ addrfamily_t *, addrfamily_t *);
+typedef ipf_rdx_node_t *(* idx_ha_func_t)(struct ipf_rdx_head *,
+ addrfamily_t *);
+typedef void (* idx_walk_func_t)(struct ipf_rdx_head *,
+ radix_walk_func_t, void *);
+
+typedef struct ipf_rdx_head {
+ ipf_rdx_node_t *root;
+ ipf_rdx_node_t nodes[3];
+ ipfmutex_t lock;
+ idx_hamn_func_t addaddr; /* add addr/mask to tree */
+ idx_ham_func_t deladdr; /* delete addr/mask from tree */
+ idx_ham_func_t lookup; /* look for specific addr/mask */
+ idx_ha_func_t matchaddr; /* search tree for address match */
+ idx_walk_func_t walktree; /* walk entire tree */
+} ipf_rdx_head_t;
+
+typedef struct radix_softc {
+ u_char *zeros;
+ u_char *ones;
+} radix_softc_t;
+
+#undef RADIX_NODE_HEAD_LOCK
+#undef RADIX_NODE_HEAD_UNLOCK
+#ifdef _KERNEL
+# define RADIX_NODE_HEAD_LOCK(x) MUTEX_ENTER(&(x)->lock)
+# define RADIX_NODE_HEAD_UNLOCK(x) MUTEX_UNLOCK(&(x)->lock)
+#else
+# define RADIX_NODE_HEAD_LOCK(x)
+# define RADIX_NODE_HEAD_UNLOCK(x)
+#endif
+
+extern void *ipf_rx_create __P((void));
+extern int ipf_rx_init __P((void *));
+extern void ipf_rx_destroy __P((void *));
+extern int ipf_rx_inithead __P((radix_softc_t *, ipf_rdx_head_t **));
+extern void ipf_rx_freehead __P((ipf_rdx_head_t *));
+extern ipf_rdx_node_t *ipf_rx_addroute __P((ipf_rdx_head_t *,
+ addrfamily_t *, addrfamily_t *,
+ ipf_rdx_node_t *));
+extern ipf_rdx_node_t *ipf_rx_delete __P((ipf_rdx_head_t *, addrfamily_t *,
+ addrfamily_t *));
+extern void ipf_rx_walktree __P((ipf_rdx_head_t *, radix_walk_func_t,
+ void *));
+
+#endif /* __RADIX_IPF_H__ */
diff --git a/contrib/ipfilter/rules/BASIC.NAT b/contrib/ipfilter/rules/BASIC.NAT
new file mode 100644
index 0000000..213e338
--- /dev/null
+++ b/contrib/ipfilter/rules/BASIC.NAT
@@ -0,0 +1,46 @@
+#!/sbin/ipnat -f -
+#
+# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3
+#
+# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32
+#
+# ed0 - (internal) network interface, address w.x.y.z/32
+#
+# If we have only 1 valid IP address from our ISP, then we do this:
+#
+# To make ftp work, using the internal ftp proxy, use:
+#
+map ppp0 w.x.y.z/24 -> a.b.c.d/32 proxy port ftp ftp/tcp
+#
+# For normal TCP/UDP and other IP protocols
+#
+map ppp0 w.x.y.z/24 -> a.b.c.d/32 portmap tcp/udp 40000:60000
+map ppp0 w.x.y.z/24 -> a.b.c.d/32
+#
+# if we get a different dialup IP address each time, then we would use:
+#
+#map ppp0 w.x.y.z/24 -> 0/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.z/24 -> 0/32
+#
+# If we have a class C address space of valid IP#'s from our ISP, then we can
+# do this:
+#
+#map ppp0 w.x.y.z/24 -> a.b.c.d/24 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.z/24 -> a.b.c.d/24
+#
+# or, if we only have a small number of PC's, this:
+#
+#map ppp0 w.x.y.v/32 -> a.b.c.E/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.v/32 -> a.b.c.E/32
+#map ppp0 w.x.y.u/32 -> a.b.c.F/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.u/32 -> a.b.c.F/32
+#map ppp0 w.x.y.t/32 -> a.b.c.G/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.t/32 -> a.b.c.G/32
+#map ppp0 w.x.y.s/32 -> a.b.c.H/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.s/32 -> a.b.c.H/32
+#map ppp0 w.x.y.r/32 -> a.b.c.I/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.r/32 -> a.b.c.I/32
+#map ppp0 w.x.y.q/32 -> a.b.c.J/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.q/32 -> a.b.c.J/32
+#map ppp0 w.x.y.p/32 -> a.b.c.K/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.p/32 -> a.b.c.K/32
diff --git a/contrib/ipfilter/rules/BASIC_1.FW b/contrib/ipfilter/rules/BASIC_1.FW
new file mode 100644
index 0000000..642dde0
--- /dev/null
+++ b/contrib/ipfilter/rules/BASIC_1.FW
@@ -0,0 +1,99 @@
+#!/sbin/ipf -f -
+#
+# SAMPLE: RESTRICTIVE FILTER RULES
+#
+# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3
+#
+# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32
+#
+# ed0 - (internal) network interface, address w.x.y.z/32
+#
+# This file contains the basic rules needed to construct a firewall for the
+# above situation.
+#
+#-------------------------------------------------------
+# *Nasty* packets we don't want to allow near us at all!
+# short packets which are packets fragmented too short to be real.
+block in log quick all with short
+#-------------------------------------------------------
+# Group setup.
+# ============
+# By default, block and log everything. This maybe too much logging
+# (especially for ed0) and needs to be further refined.
+#
+block in log on ppp0 all head 100
+block in log proto tcp all flags S/SA head 101 group 100
+block out log on ppp0 all head 150
+block in log on ed0 from w.x.y.z/24 to any head 200
+block in log proto tcp all flags S/SA head 201 group 200
+block in log proto udp all head 202 group 200
+block out log on ed0 all head 250
+#-------------------------------------------------------
+# Localhost packets.
+# ==================
+# packets going in/out of network interfaces that aren't on the loopback
+# interface should *NOT* exist.
+block in log quick from 127.0.0.0/8 to any group 100
+block in log quick from any to 127.0.0.0/8 group 100
+block in log quick from 127.0.0.0/8 to any group 200
+block in log quick from any to 127.0.0.0/8 group 200
+# And of course, make sure the loopback allows packets to traverse it.
+pass in quick on lo0 all
+pass out quick on lo0 all
+#-------------------------------------------------------
+# Invalid Internet packets.
+# =========================
+#
+# Deny reserved addresses.
+#
+block in log quick from 10.0.0.0/8 to any group 100
+block in log quick from 192.168.0.0/16 to any group 100
+block in log quick from 172.16.0.0/12 to any group 100
+#
+# Prevent IP spoofing.
+#
+block in log quick from a.b.c.d/24 to any group 100
+#
+#-------------------------------------------------------
+# Allow outgoing DNS requests (no named on firewall)
+#
+pass in quick proto udp from any to any port = 53 keep state group 202
+#
+# If we were running named on the firewall and all internal hosts talked to
+# it, we'd use the following:
+#
+#pass in quick proto udp from any to w.x.y.z/32 port = 53 keep state group 202
+#pass out quick on ppp0 proto udp from a.b.c.d/32 to any port = 53 keep state
+#
+# Allow outgoing FTP from any internal host to any external FTP server.
+#
+pass in quick proto tcp from any to any port = ftp keep state group 201
+pass in quick proto tcp from any to any port = ftp-data keep state group 201
+pass in quick proto tcp from any port = ftp-data to any port > 1023 keep state group 101
+#
+# Allow NTP from any internal host to any external NTP server.
+#
+pass in quick proto udp from any to any port = ntp keep state group 202
+#
+# Allow outgoing connections: SSH, TELNET, WWW
+#
+pass in quick proto tcp from any to any port = 22 keep state group 201
+pass in quick proto tcp from any to any port = telnet keep state group 201
+pass in quick proto tcp from any to any port = www keep state group 201
+#
+#-------------------------------------------------------
+block in log proto tcp from any to a.b.c.d/32 flags S/SA head 110 group 100
+#
+# Allow incoming to the external firewall interface: mail, WWW, DNS
+#
+pass in log quick proto tcp from any to any port = smtp keep state group 110
+pass in log quick proto tcp from any to any port = www keep state group 110
+pass in log quick proto tcp from any to any port = 53 keep state group 110
+pass in log quick proto udp from any to any port = 53 keep state group 100
+#-------------------------------------------------------
+# Log these:
+# ==========
+# * return RST packets for invalid SYN packets to help the other end close
+block return-rst in log proto tcp from any to any flags S/SA group 100
+# * return ICMP error packets for invalid UDP packets
+block return-icmp(net-unr) in proto udp all group 100
diff --git a/contrib/ipfilter/rules/BASIC_2.FW b/contrib/ipfilter/rules/BASIC_2.FW
new file mode 100644
index 0000000..1d4fd73
--- /dev/null
+++ b/contrib/ipfilter/rules/BASIC_2.FW
@@ -0,0 +1,72 @@
+#!/sbin/ipf -f -
+#
+# SAMPLE: PERMISSIVE FILTER RULES
+#
+# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3
+#
+# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32
+#
+# ed0 - (internal) network interface, address w.x.y.z/32
+#
+# This file contains the basic rules needed to construct a firewall for the
+# above situation.
+#
+#-------------------------------------------------------
+# *Nasty* packets we don't want to allow near us at all!
+# short packets which are packets fragmented too short to be real.
+block in log quick all with short
+#-------------------------------------------------------
+# Group setup.
+# ============
+# By default, block and log everything. This maybe too much logging
+# (especially for ed0) and needs to be further refined.
+#
+block in log on ppp0 all head 100
+block out log on ppp0 all head 150
+block in log on ed0 from w.x.y.z/24 to any head 200
+block out log on ed0 all head 250
+#-------------------------------------------------------
+# Invalid Internet packets.
+# =========================
+#
+# Deny reserved addresses.
+#
+block in log quick from 10.0.0.0/8 to any group 100
+block in log quick from 192.168.0.0/16 to any group 100
+block in log quick from 172.16.0.0/12 to any group 100
+#
+# Prevent IP spoofing.
+#
+block in log quick from a.b.c.d/24 to any group 100
+#
+#-------------------------------------------------------
+# Localhost packets.
+# ==================
+# packets going in/out of network interfaces that aren't on the loopback
+# interface should *NOT* exist.
+block in log quick from 127.0.0.0/8 to any group 100
+block in log quick from any to 127.0.0.0/8 group 100
+block in log quick from 127.0.0.0/8 to any group 200
+block in log quick from any to 127.0.0.0/8 group 200
+# And of course, make sure the loopback allows packets to traverse it.
+pass in quick on lo0 all
+pass out quick on lo0 all
+#-------------------------------------------------------
+# Allow any communication between the inside network and the outside only.
+#
+# Allow all outgoing connections (SSH, TELNET, FTP, WWW, gopher, etc)
+#
+pass in log quick proto tcp all flags S/SA keep state group 200
+#
+# Support all UDP `connections' initiated from inside.
+#
+# Allow ping out
+#
+pass in log quick proto icmp all keep state group 200
+#-------------------------------------------------------
+# Log these:
+# ==========
+# * return RST packets for invalid SYN packets to help the other end close
+block return-rst in log proto tcp from any to any flags S/SA group 100
+# * return ICMP error packets for invalid UDP packets
+block return-icmp(net-unr) in proto udp all group 100
diff --git a/contrib/ipfilter/rules/example.1 b/contrib/ipfilter/rules/example.1
new file mode 100644
index 0000000..ff93f49
--- /dev/null
+++ b/contrib/ipfilter/rules/example.1
@@ -0,0 +1,4 @@
+#
+# block all incoming TCP packets on le0 from host 10.1.1.1 to any destination.
+#
+block in on le0 proto tcp from 10.1.1.1/32 to any
diff --git a/contrib/ipfilter/rules/example.10 b/contrib/ipfilter/rules/example.10
new file mode 100644
index 0000000..560d1e6
--- /dev/null
+++ b/contrib/ipfilter/rules/example.10
@@ -0,0 +1,12 @@
+#
+# pass ack packets (ie established connection)
+#
+pass in proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A
+pass out proto tcp from 10.1.0.0/16 port = 23 to 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..c6b4e7f
--- /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 10.2.2.2/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 10.2.2.2 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..854f07f
--- /dev/null
+++ b/contrib/ipfilter/rules/example.13
@@ -0,0 +1,17 @@
+#
+# Log all short TCP packets to qe3, with 10.3.3.3 as the intended
+# destination for the packet.
+#
+block in on qe0 to qe3:10.3.3.3 proto tcp all with short
+#
+# Log all connection attempts for TCP
+#
+pass in on le0 dup-to le1:10.3.3.3 proto tcp all flags S/SA
+#
+# Route all UDP packets through transparently.
+#
+pass in on ppp0 fastroute proto udp all
+#
+# Route all ICMP packets to network 10 out through le1, to 10.3.3.1
+#
+pass in on le0 to le1:10.3.3.1 proto icmp all
diff --git a/contrib/ipfilter/rules/example.2 b/contrib/ipfilter/rules/example.2
new file mode 100644
index 0000000..4f81725
--- /dev/null
+++ b/contrib/ipfilter/rules/example.2
@@ -0,0 +1,5 @@
+#
+# block all outgoing TCP packets on le0 from any host to port 23 of
+# host 10.1.1.2
+#
+block out on le0 proto tcp from any to 10.1.1.3/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..6d688b5
--- /dev/null
+++ b/contrib/ipfilter/rules/example.5
@@ -0,0 +1,25 @@
+#
+# test ruleset
+#
+# allow packets coming from foo to bar through.
+#
+pass in from 10.1.1.2 to 10.2.1.1
+#
+# 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 10.2.2.2/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 10.2.2.2 port != 53 to localhost
+#
+# block all ICMP unreachables.
+#
+block in proto icmp from any to any icmp-type unreach
+#
+# allow packets through which have a non-standard IP header length (ie there
+# are IP options such as source-routing present).
+#
+pass in 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..daff203
--- /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 le1 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/firewall b/contrib/ipfilter/rules/firewall
new file mode 100644
index 0000000..f26b715
--- /dev/null
+++ b/contrib/ipfilter/rules/firewall
@@ -0,0 +1,39 @@
+Configuring IP Filter for firewall usage.
+=========================================
+
+Step 1 - Block out "bad" IP packets.
+------------------------------------
+
+Run the perl script "mkfilters". This will generate a list of blocking
+rules which:
+ a) blocks all packets which might belong to an IP Spoofing attack;
+ b) blocks all packets with IP options;
+ c) blocks all packets which have a length which is too short for
+ any legal packet;
+
+Step 2 - Convert Network Security Policy to filter rules.
+---------------------------------------------------------
+
+Draw up a list of which services you want to allow users to use on the
+Internet (e.g. WWW, ftp, etc). Draw up a separate list for what you
+want each host that is part of your firewall to be allowed to do, including
+communication with internal hosts.
+
+Step 3 - Create TCP "keep state" rules.
+---------------------------------------
+
+For each service that uses TCP, create a rule as follows:
+
+pass in on <int-a> proto tcp from <int-net> to any port <ext-service> flags S/SA keep state
+
+where
+* "int-a" is the internal interface of the firewall. That is, it is the
+ closest to your internal network in terms of network hops.
+
+* "int-net" is the internal network IP# subnet address range. This might
+ be something like 10.1.0.0/16, or 128.33.1.0/24
+
+* "ext-service" is the service to which you wish to connect or if it doesn't
+ have a proper name, a number can be used. The translation of "ext-service"
+ as a name to a number is controlled with the /etc/services file.
+
diff --git a/contrib/ipfilter/rules/ftp-proxy b/contrib/ipfilter/rules/ftp-proxy
new file mode 100644
index 0000000..ad2f717
--- /dev/null
+++ b/contrib/ipfilter/rules/ftp-proxy
@@ -0,0 +1,45 @@
+How to setup FTP proxying using the built in proxy code.
+========================================================
+
+NOTE: Currently, the built-in FTP proxy is only available for use with NAT
+ (i.e. only if you're already using "map" rules with ipnat). It does
+ support null-NAT mappings, that is, using the proxy without changing
+ the addresses.
+
+Lets assume your network diagram looks something like this:
+
+
+[host A]
+ |a
+---+-------------+----------
+ |b
+ [host B]
+ |c
+---+-------------+----------
+ |d
+[host C]
+
+and IP Filter is running on host B. If you want to proxy FTP from A to C
+then you would do:
+
+map int-c ipaddr-a/32 -> ip-addr-c-net/32 proxy port ftp ftp/tcp
+
+int-c = name of "interface c"
+ipaddr-a = ip# of interface a
+ipaddr-c-net = another ip# on the C-network (usually not the same as the
+interface).
+
+e.g., if host A was 10.1.1.1, host B had two network interfaces ed0 and vx0
+which had IP#'s 10.1.1.2 and 203.45.67.89 respectively, and host C was
+203.45.67.90, you would do:
+
+map vx0 10.1.1.1/32 -> 203.45.67.91/32 proxy port ftp ftp/tcp
+
+where:
+ipaddr-a = 10.1.1.1
+int-c = vx0
+ipaddr-c-net = 203.45.67.91
+
+The "map" rule for this proxy should precede any other NAT rules you are
+using.
+
diff --git a/contrib/ipfilter/rules/ftppxy b/contrib/ipfilter/rules/ftppxy
new file mode 100755
index 0000000..2c42c52
--- /dev/null
+++ b/contrib/ipfilter/rules/ftppxy
@@ -0,0 +1,6 @@
+#!/bin/sh
+# The proxy bit is as follows:
+# proxy [port <portname>] <tag>/<protocol>
+# the <tag> should match a tagname in the proxy table, as does the protocol.
+# this format isn't finalised yet
+echo "map ed0 0/0 -> 192.1.1.1/32 proxy port ftp ftp/tcp" | /sbin/ipnat -f -
diff --git a/contrib/ipfilter/rules/ip_rules b/contrib/ipfilter/rules/ip_rules
new file mode 100644
index 0000000..9850f16
--- /dev/null
+++ b/contrib/ipfilter/rules/ip_rules
@@ -0,0 +1,3 @@
+# Used to generate ../ip_rules.c and ../ip_rules.h
+pass in all
+pass out all
diff --git a/contrib/ipfilter/rules/ipmon.conf b/contrib/ipfilter/rules/ipmon.conf
new file mode 100644
index 0000000..652afce
--- /dev/null
+++ b/contrib/ipfilter/rules/ipmon.conf
@@ -0,0 +1,25 @@
+#
+#
+#
+#
+match { logtag = 10000; }
+do { execute("/usr/bin/mail -s 'logtag 10000' root"); };
+#
+match { logtag = 2000, every 10 seconds; }
+do { execute("echo 'XXXXXXXX tag 2000 packet XXXXXXXX'"); };
+#
+match { protocol = udp, result = block; }
+do { file("file:///var/log/udp-block"); };
+#
+match { protocol = tcp, result = block, dstport = 25; }
+do { syslog("local0.info"), syslog("local1."), syslog(".warn"); };
+#
+match { srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; }
+do { execute("/usr/bin/mail -s 'from 10.1 to 192.168.1' root"); };
+
+#
+match {
+ rule = 12, logtag = 101, direction = in, result = block,
+ protocol = udp, srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; }
+do { nothing; };
+#
diff --git a/contrib/ipfilter/rules/nat-setup b/contrib/ipfilter/rules/nat-setup
new file mode 100644
index 0000000..b10e8f1
--- /dev/null
+++ b/contrib/ipfilter/rules/nat-setup
@@ -0,0 +1,77 @@
+Configuring NAT on your network.
+================================
+
+To start setting up NAT, we need to define which is your "internal" interface
+and which is your "external" interface. The "internal" interface is the
+network adapter connected to the network with private IP addresses which
+you need to change for communicating on the Internet. The "external"
+interface is configured with a valid internet address.
+
+For example, your internal interface might have an IP# of 10.1.1.1 and be
+connected to your ethernet, whilst your external interface might be a PPP
+connection with an IP number of 204.51.62.176.
+
+Thus your network might look like this:
+
+<Internal Network>
+ [pc] [pc]
+ | |
++-+---------+------+
+ |
+ [firewall]
+ |
+ |
+ Internet
+<External Network>
+
+
+Writing the map-rule.
+---------------------
+When you're connected to the Internet, you will either have a block of IP
+addresses assigned to you, maybe several different blocks, or you use a
+single IP address, i.e. with dialup PPP. If you have a block of addresses
+assigned, these can be used to create either a 1:1 mapping (if you have
+only a few internal IP addresses) or N:1 mappings, where groups of internal
+addresses map to a single IP address and unless you have enough Internet
+addresses for a 1:1 mapping, you will want to do "portmapping" for TCP and
+UDP port numbers.
+
+For an N:1 situation, you might have:
+
+map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap
+
+where if you had 16 addresses available, you could do:
+
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap
+
+Or if you wanted to allocate subnets to each IP#, you might do:
+
+map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap
+map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap
+map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap
+
+*** NOTE: NAT rules are used on a first-match basis only!
+
+
+Filtering with NAT.
+-------------------
+IP Filter will always translate addresses in a packet _BEFORE_ it checks its
+access list for inbound packets and translates addresses _AFTER_ it has
+checked the access control lists for outbound packets.
+
+For example (using the above NAT rules), if you wanted to prevent all hosts
+in the 10.1.2.0/24 subnet from using NAT, you might use the following rule
+with ipf:
+
+block out on ppp0 from 10.1.2.0/24 to any
+block in on ppp0 from any to 10.1.2.0/24
+
+and use these with ipnat:
+
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap
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/pool.conf b/contrib/ipfilter/rules/pool.conf
new file mode 100644
index 0000000..285398d
--- /dev/null
+++ b/contrib/ipfilter/rules/pool.conf
@@ -0,0 +1,4 @@
+#
+pool 0 = { !10.0.0.0 - 10.255.255.255, 10.1.0.0 - 10.1.255.255,
+ 10.1.1.0 - 10.1.1.255, !10.1.2.0 - 10.2.2.255,
+ 10.1.2.3 - 10.1.2.3, 10.1.2.15 - 10.1.2.15 };
diff --git a/contrib/ipfilter/rules/server b/contrib/ipfilter/rules/server
new file mode 100644
index 0000000..de0e9bb
--- /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 log quick on le0 from any to any
+block in log quick 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/samples/Makefile b/contrib/ipfilter/samples/Makefile
new file mode 100644
index 0000000..47ab4a2
--- /dev/null
+++ b/contrib/ipfilter/samples/Makefile
@@ -0,0 +1,24 @@
+CC=gcc
+all:
+ @echo "Please do one of the following:"
+ @echo "make bsd"
+ @echo "make bsdi"
+ @echo "make freebsd"
+ @echo "make freebsd22"
+ @echo "make netbsd"
+ @echo "make openbsd"
+ @echo "make sunos4"
+ @echo "make sunos5"
+
+sunos5:
+ $(CC) -I.. userauth.c -o userauth -lsocket -lnsl
+ $(CC) -I.. proxy.c -o proxy -lsocket -lnsl
+ $(CC) -I.. relay.c -o relay -lsocket -lnsl
+
+freebsd freebsd22 netbsd bsd bsdi sunos4 openbsd:
+ $(CC) -I.. userauth.c -o userauth
+ $(CC) -I.. proxy.c -o proxy
+ $(CC) -I.. relay.c -o relay
+
+clean:
+ /bin/rm -f userauth proxy relay
diff --git a/contrib/ipfilter/samples/ipfilter-pb.gif b/contrib/ipfilter/samples/ipfilter-pb.gif
new file mode 100644
index 0000000..afaefa8
--- /dev/null
+++ b/contrib/ipfilter/samples/ipfilter-pb.gif
Binary files differ
diff --git a/contrib/ipfilter/samples/proxy.c b/contrib/ipfilter/samples/proxy.c
new file mode 100644
index 0000000..483c4b5
--- /dev/null
+++ b/contrib/ipfilter/samples/proxy.c
@@ -0,0 +1,317 @@
+/* $FreeBSD$ */
+
+/*
+ * Sample transparent proxy program.
+ *
+ * Sample implementation of a program which intercepts a TCP connectiona and
+ * just echos all data back to the origin. Written to work via inetd as a
+ * "nonwait" program running as root; ie.
+ * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy
+ * with a NAT rue like this:
+ * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1
+ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <syslog.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.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 <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <ctype.h>
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ipl.h"
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin, sloc, sout;
+ ipfobj_t obj;
+ natlookup_t natlook;
+ char buffer[512];
+ int namelen, fd, n;
+
+ /*
+ * get IP# and port # of the remote end of the connection (at the
+ * origin).
+ */
+ namelen = sizeof(sin);
+ if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) {
+ perror("getpeername");
+ exit(-1);
+ }
+
+ /*
+ * get IP# and port # of the local end of the connection (at the
+ * man-in-the-middle).
+ */
+ namelen = sizeof(sin);
+ if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) {
+ perror("getsockname");
+ exit(-1);
+ }
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(natlook);
+ obj.ipfo_ptr = &natlook;
+ obj.ipfo_type = IPFOBJ_NATLOOKUP;
+
+ /*
+ * Build up the NAT natlookup structure.
+ */
+ bzero((char *)&natlook, sizeof(natlook));
+ natlook.nl_outip = sin.sin_addr;
+ natlook.nl_inip = sloc.sin_addr;
+ natlook.nl_flags = IPN_TCP;
+ natlook.nl_outport = sin.sin_port;
+ natlook.nl_inport = sloc.sin_port;
+
+ /*
+ * Open the NAT device and lookup the mapping pair.
+ */
+ fd = open(IPNAT_NAME, O_RDONLY);
+ if (ioctl(fd, SIOCGNATL, &obj) == -1) {
+ perror("ioctl(SIOCGNATL)");
+ exit(-1);
+ }
+
+#define DO_NAT_OUT
+#ifdef DO_NAT_OUT
+ if (argc > 1)
+ do_nat_out(0, 1, fd, &natlook, argv[1]);
+#else
+
+ /*
+ * Log it
+ */
+ syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d",
+ inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport));
+ printf("connect to %s,%d\n",
+ inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport));
+
+ /*
+ * Just echo data read in from stdin to stdout
+ */
+ while ((n = read(0, buffer, sizeof(buffer))) > 0)
+ if (write(1, buffer, n) != n)
+ break;
+ close(0);
+#endif
+}
+
+
+#ifdef DO_NAT_OUT
+do_nat_out(in, out, fd, nlp, extif)
+ int fd;
+ natlookup_t *nlp;
+ char *extif;
+{
+ nat_save_t ns, *nsp = &ns;
+ struct sockaddr_in usin;
+ u_32_t sum1, sum2, sumd;
+ int onoff, ofd, slen;
+ ipfobj_t obj;
+ ipnat_t *ipn;
+ nat_t *nat;
+
+ bzero((char *)&ns, sizeof(ns));
+
+ nat = &ns.ipn_nat;
+ nat->nat_p = IPPROTO_TCP;
+ nat->nat_dir = NAT_OUTBOUND;
+ if ((extif != NULL) && (*extif != '\0')) {
+ strncpy(nat->nat_ifnames[0], extif,
+ sizeof(nat->nat_ifnames[0]));
+ strncpy(nat->nat_ifnames[1], extif,
+ sizeof(nat->nat_ifnames[1]));
+ nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0';
+ nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0';
+ }
+
+ ofd = socket(AF_INET, SOCK_DGRAM, 0);
+ bzero((char *)&usin, sizeof(usin));
+ usin.sin_family = AF_INET;
+ usin.sin_addr = nlp->nl_realip;
+ usin.sin_port = nlp->nl_realport;
+ (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin));
+ slen = sizeof(usin);
+ (void) getsockname(ofd, (struct sockaddr *)&usin, &slen);
+ close(ofd);
+printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr));
+
+ if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ perror("socket");
+ usin.sin_port = 0;
+ if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin)))
+ perror("bind");
+ slen = sizeof(usin);
+ if (getsockname(ofd, (struct sockaddr *)&usin, &slen))
+ perror("getsockname");
+printf("local port# to use: %d\n", ntohs(usin.sin_port));
+
+ nat->nat_inip = usin.sin_addr;
+ nat->nat_outip = nlp->nl_outip;
+ nat->nat_oip = nlp->nl_realip;
+
+ sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port);
+ sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+ nat->nat_sumd[1] = nat->nat_sumd[0];
+
+ sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr));
+ sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
+
+ nat->nat_inport = usin.sin_port;
+ nat->nat_outport = nlp->nl_outport;
+ nat->nat_oport = nlp->nl_realport;
+
+ nat->nat_flags = IPN_TCPUDP;
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(*nsp);
+ obj.ipfo_ptr = nsp;
+ obj.ipfo_type = IPFOBJ_NATSAVE;
+
+ onoff = 1;
+ if (ioctl(fd, SIOCSTLCK, &onoff) == 0) {
+ if (ioctl(fd, SIOCSTPUT, &obj) != 0)
+ perror("SIOCSTPUT");
+ onoff = 0;
+ if (ioctl(fd, SIOCSTLCK, &onoff) != 0)
+ perror("SIOCSTLCK");
+ }
+
+ usin.sin_addr = nlp->nl_realip;
+ usin.sin_port = nlp->nl_realport;
+printf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr),
+ntohs(usin.sin_port));
+fflush(stdout);
+ if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin)))
+ perror("connect");
+
+ relay(in, out, ofd);
+}
+
+
+relay(in, out, net)
+ int in, out, net;
+{
+ char netbuf[1024], outbuf[1024];
+ char *nwptr, *nrptr, *owptr, *orptr;
+ size_t nsz, osz;
+ fd_set rd, wr;
+ int i, n, maxfd;
+
+ n = 0;
+ maxfd = in;
+ if (out > maxfd)
+ maxfd = out;
+ if (net > maxfd)
+ maxfd = net;
+
+ nrptr = netbuf;
+ nwptr = netbuf;
+ nsz = sizeof(netbuf);
+ orptr = outbuf;
+ owptr = outbuf;
+ osz = sizeof(outbuf);
+
+ while (n >= 0) {
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+
+ if (nrptr - netbuf < sizeof(netbuf))
+ FD_SET(in, &rd);
+ if (orptr - outbuf < sizeof(outbuf))
+ FD_SET(net, &rd);
+
+ if (nsz < sizeof(netbuf))
+ FD_SET(net, &wr);
+ if (osz < sizeof(outbuf))
+ FD_SET(out, &wr);
+
+ n = select(maxfd + 1, &rd, &wr, NULL, NULL);
+
+ if ((n > 0) && FD_ISSET(in, &rd)) {
+ i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf));
+ if (i <= 0)
+ break;
+ nsz -= i;
+ nrptr += i;
+ n--;
+ }
+
+ if ((n > 0) && FD_ISSET(net, &rd)) {
+ i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf));
+ if (i <= 0)
+ break;
+ osz -= i;
+ orptr += i;
+ n--;
+ }
+
+ if ((n > 0) && FD_ISSET(out, &wr)) {
+ i = write(out, owptr, orptr - owptr);
+ if (i <= 0)
+ break;
+ osz += i;
+ if (osz == sizeof(outbuf) || owptr == orptr) {
+ orptr = outbuf;
+ owptr = outbuf;
+ } else
+ owptr += i;
+ n--;
+ }
+
+ if ((n > 0) && FD_ISSET(net, &wr)) {
+ i = write(net, nwptr, nrptr - nwptr);
+ if (i <= 0)
+ break;
+ nsz += i;
+ if (nsz == sizeof(netbuf) || nwptr == nrptr) {
+ nrptr = netbuf;
+ nwptr = netbuf;
+ } else
+ nwptr += i;
+ }
+ }
+
+ close(net);
+ close(out);
+ close(in);
+}
+#endif
diff --git a/contrib/ipfilter/samples/relay.c b/contrib/ipfilter/samples/relay.c
new file mode 100644
index 0000000..11b76b0
--- /dev/null
+++ b/contrib/ipfilter/samples/relay.c
@@ -0,0 +1,196 @@
+/* $FreeBSD$ */
+
+/*
+ * Sample program to be used as a transparent proxy.
+ *
+ * Must be executed with permission enough to do an ioctl on /dev/ipl
+ * or equivalent. This is just a sample and is only alpha quality.
+ * - Darren Reed (8 April 1996)
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ipl.h"
+
+#define RELAY_BUFSZ 8192
+
+char ibuff[RELAY_BUFSZ];
+char obuff[RELAY_BUFSZ];
+
+int relay(ifd, ofd, rfd)
+ int ifd, ofd, rfd;
+{
+ fd_set rfds, wfds;
+ char *irh, *irt, *rrh, *rrt;
+ char *iwh, *iwt, *rwh, *rwt;
+ int nfd, n, rw;
+
+ irh = irt = ibuff;
+ iwh = iwt = obuff;
+ nfd = ifd;
+ if (nfd < ofd)
+ nfd = ofd;
+ if (nfd < rfd)
+ nfd = rfd;
+
+ while (1) {
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ if (irh > irt)
+ FD_SET(rfd, &wfds);
+ if (irh < (ibuff + RELAY_BUFSZ))
+ FD_SET(ifd, &rfds);
+ if (iwh > iwt)
+ FD_SET(ofd, &wfds);
+ if (iwh < (obuff + RELAY_BUFSZ))
+ FD_SET(rfd, &rfds);
+
+ switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL)))
+ {
+ case -1 :
+ case 0 :
+ return -1;
+ default :
+ if (FD_ISSET(ifd, &rfds)) {
+ rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh);
+ if (rw == -1)
+ return -1;
+ if (rw == 0)
+ return 0;
+ irh += rw;
+ n--;
+ }
+ if (n && FD_ISSET(ofd, &wfds)) {
+ rw = write(ofd, iwt, iwh - iwt);
+ if (rw == -1)
+ return -1;
+ iwt += rw;
+ n--;
+ }
+ if (n && FD_ISSET(rfd, &rfds)) {
+ rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh);
+ if (rw == -1)
+ return -1;
+ if (rw == 0)
+ return 0;
+ iwh += rw;
+ n--;
+ }
+ if (n && FD_ISSET(rfd, &wfds)) {
+ rw = write(rfd, irt, irh - irt);
+ if (rw == -1)
+ return -1;
+ irt += rw;
+ n--;
+ }
+ if (irh == irt)
+ irh = irt = ibuff;
+ if (iwh == iwt)
+ iwh = iwt = obuff;
+ }
+ }
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin;
+ ipfobj_t obj;
+ natlookup_t nl;
+ natlookup_t *nlp = &nl;
+ int fd, sl = sizeof(sl), se;
+
+ openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON);
+ if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
+ se = errno;
+ perror("open");
+ errno = se;
+ syslog(LOG_ERR, "open: %m\n");
+ exit(-1);
+ }
+
+ bzero(&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(nl);
+ obj.ipfo_ptr = &nl;
+ obj.ipfo_type = IPFOBJ_NATLOOKUP;
+
+ bzero(&nl, sizeof(nl));
+ nl.nl_flags = IPN_TCP;
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sl = sizeof(sin);
+ if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) {
+ se = errno;
+ perror("getsockname");
+ errno = se;
+ syslog(LOG_ERR, "getsockname: %m\n");
+ exit(-1);
+ } else {
+ nl.nl_inip.s_addr = sin.sin_addr.s_addr;
+ nl.nl_inport = sin.sin_port;
+ }
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sl = sizeof(sin);
+ if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) {
+ se = errno;
+ perror("getpeername");
+ errno = se;
+ syslog(LOG_ERR, "getpeername: %m\n");
+ exit(-1);
+ } else {
+ nl.nl_outip.s_addr = sin.sin_addr.s_addr;
+ nl.nl_outport = sin.sin_port;
+ }
+
+ if (ioctl(fd, SIOCGNATL, &obj) == -1) {
+ se = errno;
+ perror("ioctl");
+ errno = se;
+ syslog(LOG_ERR, "ioctl: %m\n");
+ exit(-1);
+ }
+
+ sin.sin_port = nl.nl_realport;
+ sin.sin_addr = nl.nl_realip;
+ sl = sizeof(sin);
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(fd, (struct sockaddr *)&sin, sl) == -1) {
+ se = errno;
+ perror("connect");
+ errno = se;
+ syslog(LOG_ERR, "connect: %m\n");
+ exit(-1);
+ }
+
+ (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
+ (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
+ (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
+
+ syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr),
+ ntohs(sin.sin_port));
+ if (relay(0, 1, fd) == -1) {
+ se = errno;
+ perror("relay");
+ errno = se;
+ syslog(LOG_ERR, "relay: %m\n");
+ exit(-1);
+ }
+ exit(0);
+}
diff --git a/contrib/ipfilter/samples/userauth.c b/contrib/ipfilter/samples/userauth.c
new file mode 100644
index 0000000..620bd72
--- /dev/null
+++ b/contrib/ipfilter/samples/userauth.c
@@ -0,0 +1,62 @@
+/* $FreeBSD$ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_auth.h"
+
+extern int errno;
+
+main()
+{
+ struct frauth fra;
+ struct frauth *frap = &fra;
+ fr_info_t *fin = &fra.fra_info;
+ fr_ip_t *fi = &fin->fin_fi;
+ char yn[16];
+ int fd;
+
+ fd = open(IPL_NAME, O_RDWR);
+ fra.fra_len = 0;
+ fra.fra_buf = NULL;
+ while (ioctl(fd, SIOCAUTHW, &frap) == 0) {
+ if (fra.fra_info.fin_out)
+ fra.fra_pass = FR_OUTQUE;
+ else
+ fra.fra_pass = FR_INQUE;
+
+ printf("%s ", inet_ntoa(fi->fi_src));
+ if (fi->fi_flx & FI_TCPUDP)
+ printf("port %d ", fin->fin_data[0]);
+ printf("-> %s ", inet_ntoa(fi->fi_dst));
+ if (fi->fi_flx & FI_TCPUDP)
+ printf("port %d ", fin->fin_data[1]);
+ printf("\n");
+ printf("Allow packet through ? [y/n]");
+ fflush(stdout);
+ if (!fgets(yn, sizeof(yn), stdin))
+ break;
+ fflush(stdin);
+ if (yn[0] == 'n' || yn[0] == 'N')
+ fra.fra_pass |= FR_BLOCK;
+ else if (yn[0] == 'y' || yn[0] == 'Y') {
+ fra.fra_pass |= FR_PASS;
+ if (fra.fra_info.fin_fi.fi_flx & FI_TCPUDP)
+ fra.fra_pass |= FR_KEEPSTATE;
+ } else
+ fra.fra_pass |= FR_NOMATCH;
+ printf("answer = %c (%x), id %d idx %d\n", yn[0],
+ fra.fra_pass, fra.fra_info.fin_id, fra.fra_index);
+ if (ioctl(fd, SIOCAUTHR, &frap) != 0)
+ perror("SIOCAUTHR");
+ }
+ fprintf(stderr, "errno=%d \n", errno);
+ perror("frauth-SIOCAUTHW");
+}
diff --git a/contrib/ipfilter/snoop.h b/contrib/ipfilter/snoop.h
new file mode 100644
index 0000000..74bc247
--- /dev/null
+++ b/contrib/ipfilter/snoop.h
@@ -0,0 +1,47 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#ifndef __SNOOP_H__
+#define __SNOOP_H__
+
+/*
+ * written to comply with the RFC (1761) from Sun.
+ * $Id$
+ */
+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;
+};
+
+#endif /* __SNOOP_H__ */
diff --git a/contrib/ipfilter/sys/tree.h b/contrib/ipfilter/sys/tree.h
new file mode 100644
index 0000000..5855885
--- /dev/null
+++ b/contrib/ipfilter/sys/tree.h
@@ -0,0 +1,750 @@
+/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
+/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
+/* $FreeBSD: src/sys/sys/tree.h,v 1.7 2007/12/28 07:03:26 jasone Exp $ */
+
+/*-
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#ifndef _SYS_TREE_H_
+#define _SYS_TREE_H_
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+\
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+ __left = __right = &__node; \
+\
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+/*
+ * Undef for Linux
+ */
+#undef RB_BLACK
+#undef RB_RED
+#undef RB_ROOT
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_RB_NEXT(struct type *); \
+attr struct type *name##_RB_PREV(struct type *); \
+attr struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) != NULL && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field);\
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oleft, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_LEFT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oright, field) = RB_BLACK;\
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field);\
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+ RB_ROTATE_RIGHT(head, parent, tmp, field);\
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field)) != NULL) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+ RB_LEFT(RB_PARENT(old, field), field) = elm;\
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field)) != NULL); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#endif /* _SYS_TREE_H_ */
diff --git a/contrib/ipfilter/tools/BNF.ipf b/contrib/ipfilter/tools/BNF.ipf
new file mode 100644
index 0000000..0740c58
--- /dev/null
+++ b/contrib/ipfilter/tools/BNF.ipf
@@ -0,0 +1,80 @@
+filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ]
+ [ proto ] [ ip ] [ group ] [ tag ] [ pps ] .
+
+insert = "@" decnumber .
+action = block | "pass" | log | "count" | auth | call .
+in-out = "in" | "out" .
+options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] .
+tos = "tos" decnumber | "tos" hexnumber .
+ttl = "ttl" decnumber .
+proto = "proto" protocol .
+ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
+group = [ "head" decnumber ] [ "group" decnumber ] .
+pps = "pps" decnumber .
+
+onif = "on" interface-name [ "out-via" interface-name ] .
+block = "block" [ return-icmp[return-code] | "return-rst" ] .
+auth = "auth" | "preauth" .
+log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] .
+tag = "tag" tagid .
+call = "call" [ "now" ] function-name .
+dup = "dup-to" interface-name[":"ipaddr] .
+froute = "fastroute" | "to" interface-name .
+protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber .
+srcdst = "all" | fromto .
+fromto = "from" object "to" object .
+
+return-icmp = "return-icmp" | "return-icmp-as-dest" .
+loglevel = facility"."priority | priority .
+object = addr [ port-comp | port-range ] .
+addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] .
+port-comp = "port" compare port-num .
+port-range = "port" port-num range port-num .
+flags = "flags" flag { flag } [ "/" flag { flag } ] .
+with = "with" | "and" .
+icmp = "icmp-type" icmp-type [ "code" decnumber ] .
+return-code = "("icmp-code")" .
+keep = "keep" "state" [ "limit" number ] | "keep" "frags" .
+
+nummask = host-name [ "/" decnumber ] .
+host-name = ipaddr | hostname | "any" .
+ipaddr = host-num "." host-num "." host-num "." host-num .
+host-num = digit [ digit [ digit ] ] .
+port-num = service-name | decnumber .
+
+withopt = [ "not" | "no" ] opttype [ withopt ] .
+opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" |
+ "mbcast" | "opt" ipopts .
+optname = ipopts [ "," optname ] .
+ipopts = optlist | "sec-class" [ secname ] .
+secname = seclvl [ "," secname ] .
+seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" |
+ "reserv-4" | "secret" | "topsecret" .
+icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" |
+ "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" |
+ "inforep" | "maskreq" | "maskrep" | "routerad" |
+ "routersol" | decnumber .
+icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" |
+ "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
+ "net-prohib" | "host-prohib" | "net-tos" | "host-tos" |
+ "filter-prohib" | "host-preced" | "cutoff-preced" .
+optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" |
+ "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" |
+ "visa" | "imitd" | "eip" | "finn" .
+facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" |
+ "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" |
+ "audit" | "logalert" | "local0" | "local1" | "local2" |
+ "local3" | "local4" | "local5" | "local6" | "local7" .
+priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" |
+ "info" | "debug" .
+
+hexnumber = "0" "x" hexstring .
+hexstring = hexdigit [ hexstring ] .
+decnumber = digit [ decnumber ] .
+
+compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" |
+ "le" | "ge" .
+range = "<>" | "><" .
+hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" .
+digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
+flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" .
diff --git a/contrib/ipfilter/tools/BNF.ipnat b/contrib/ipfilter/tools/BNF.ipnat
new file mode 100644
index 0000000..69ed8a2
--- /dev/null
+++ b/contrib/ipfilter/tools/BNF.ipnat
@@ -0,0 +1,28 @@
+ipmap :: = mapblock | redir | map .
+
+map ::= mapit ifname ipmask "->" ipmask [ mapport | mapicmpid ] .
+map ::= mapit ifname fromto "->" ipmask [ mapport | mapicmpid ] .
+mapblock ::= "map-block" ifname ipmask "->" ipmask [ ports ] .
+redir ::= "rdr" ifname ipmask dport "->" ip [ "," ip ] [ ports ] options .
+
+dport ::= "port" portnum [ "-" portnum ] .
+ports ::= "ports" numports | "auto" .
+mapit ::= "map" | "bimap" .
+fromto ::= "from" object "to" object .
+ipmask ::= ip "/" bits | ip "/" mask | ip "netmask" mask .
+mapport ::= "portmap" tcpudp portnumber ":" portnumber .
+mapicmpid ::= "icmpidmap" icmp idnumber ":" idnumber .
+options ::= [ tcpudp ] [ rr ] .
+
+object = addr [ port-comp | port-range ] .
+addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] .
+port-comp = "port" compare port-num .
+port-range = "port" port-num range port-num .
+
+rr ::= "round-robin" .
+tcpudp ::= "tcp" | "udp" | "tcp/udp" .
+portnumber ::= number { numbers } | "auto" .
+idnumber ::= number { numbers } .
+ifname ::= 'A' - 'Z' { 'A' - 'Z' } numbers .
+
+numbers ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' .
diff --git a/contrib/ipfilter/tools/Makefile b/contrib/ipfilter/tools/Makefile
new file mode 100644
index 0000000..ce1ab0e
--- /dev/null
+++ b/contrib/ipfilter/tools/Makefile
@@ -0,0 +1,104 @@
+YACC=yacc -v
+
+DEST=.
+
+all: $(DEST)/ipf_y.c $(DEST)/ipf_y.h $(DEST)/ipf_l.c \
+ $(DEST)/ipmon_y.c $(DEST)/ipmon_y.h $(DEST)/ipmon_l.c \
+ $(DEST)/ipnat_y.c $(DEST)/ipnat_y.h $(DEST)/ipnat_l.c \
+ $(DEST)/ipscan_y.c $(DEST)/ipscan_y.h $(DEST)/ipscan_l.c \
+ $(DEST)/ippool_y.c $(DEST)/ippool_y.h $(DEST)/ippool_l.c \
+ $(DEST)/ipf_l.h $(DEST)/ipnat_l.h $(DEST)/ipscan_l.h \
+ $(DEST)/ippool_l.h $(DEST)/ipmon_l.h
+
+$(DEST)/ipf_y.h: $(DEST)/ipf_y.c
+
+$(DEST)/ipf_y.c: ipf_y.y
+ $(YACC) -d ipf_y.y
+ sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.c/' \
+ -e 's/"ipf_y.y"/"..\/tools\/ipf_y.y"/' \
+ y.tab.c > $(DEST)/ipf_y.c
+ sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' y.tab.h > $(DEST)/ipf_y.h
+ /bin/rm -f y.tab.c y.tab.h
+
+$(DEST)/ipf_l.c: lexer.c
+ sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' \
+ -e 's/lexer.h/ipf_l.h/' lexer.c > $@
+
+$(DEST)/ipmon_y.n: $(DEST)/ipmon_y.c
+
+$(DEST)/ipmon_y.c $(DEST)/ipmon_y.h: ipmon_y.y
+ $(YACC) -d ipmon_y.y
+ sed -e 's/yy/ipmon_yy/g' -e 's/"ipmon_y.y"/"..\/tools\/ipmon_y.y"/' \
+ y.tab.c > $(DEST)/ipmon_y.c
+ sed -e 's/yy/ipmon_yy/g' y.tab.h > $(DEST)/ipmon_y.h
+ /bin/rm -f y.tab.c y.tab.h
+
+$(DEST)/ipmon_l.c: lexer.c
+ sed -e 's/yy/ipmon_yy/g' -e 's/y.tab.h/ipmon_y.h/' \
+ -e 's/lexer.h/ipmon_l.h/' lexer.c > $@
+
+$(DEST)/ipscan_y.h: $(DEST)/ipscan_y.c
+
+$(DEST)/ipscan_y.c $(DEST)/ipscan_y.h: ipscan_y.y
+ $(YACC) -d ipscan_y.y
+ sed -e 's/yy/ipscan_yy/g' \
+ -e 's/"ipscan_y.y"/"..\/tools\/ipscan_y.y"/' \
+ y.tab.c > $(DEST)/ipscan_y.c
+ sed -e 's/yy/ipscan_yy/g' y.tab.h > $(DEST)/ipscan_y.h
+ /bin/rm -f y.tab.c y.tab.h
+
+$(DEST)/ipscan_l.c: lexer.c
+ sed -e 's/yy/ipscan_yy/g' -e 's/y.tab.h/ipscan_y.h/' \
+ -e 's/lexer.h/ipscan_l.h/' lexer.c > $@
+
+$(DEST)/ippool_y.h: $(DEST)/ippool_y.c
+
+$(DEST)/ippool_y.c $(DEST)/ippool_y.h: ippool_y.y
+ $(YACC) -d ippool_y.y
+ sed -e 's/yy/ippool_yy/g' -e 's/"ippool_y.y"/"..\/tools\/ippool_y.y"/' \
+ y.tab.c > $(DEST)/ippool_y.c
+ sed -e 's/yy/ippool_yy/g' y.tab.h > $(DEST)/ippool_y.h
+ /bin/rm -f y.tab.c y.tab.h
+
+$(DEST)/ippool_l.c: lexer.c
+ sed -e 's/yy/ippool_yy/g' -e 's/y.tab.h/ippool_y.h/' \
+ -e 's/lexer.h/ippool_l.h/' lexer.c > $@
+
+$(DEST)/ipnat_y.h: $(DEST)/ipnat_y.c
+
+$(DEST)/ipnat_y.c $(DEST)/ipnat_y.h: ipnat_y.y
+ $(YACC) -d ipnat_y.y
+ sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.c/ipnat_y.c/' \
+ -e s/\"ipnat_y.y\"/\"..\\/tools\\/ipnat_y.y\"/ \
+ y.tab.c > $(DEST)/ipnat_y.c
+ sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \
+ y.tab.h > $(DEST)/ipnat_y.h
+ /bin/rm -f y.tab.c y.tab.h
+
+$(DEST)/ipnat_l.c: lexer.c
+ sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \
+ -e 's/lexer.h/ipnat_l.h/' lexer.c > $@
+
+$(DEST)/ipf_l.h: lexer.h
+ sed -e 's/yy/ipf_yy/g' lexer.h > $@
+
+$(DEST)/ipmon_l.h: lexer.h
+ sed -e 's/yy/ipmon_yy/g' lexer.h > $@
+
+$(DEST)/ipscan_l.h: lexer.h
+ sed -e 's/yy/ipscan_yy/g' lexer.h > $@
+
+$(DEST)/ippool_l.h: lexer.h
+ sed -e 's/yy/ippool_yy/g' lexer.h > $@
+
+$(DEST)/ipnat_l.h: lexer.h
+ sed -e 's/yy/ipnat_yy/g' lexer.h > $@
+
+clean:
+ /bin/rm -f $(DEST)/ipf_y.c $(DEST)/ipf_y.h $(DEST)/ipf_l.c
+ /bin/rm -f $(DEST)/ipmon_y.c $(DEST)/ipmon_y.h $(DEST)/ipmon_l.c
+ /bin/rm -f $(DEST)/ipscan_y.c $(DEST)/ipscan_y.h $(DEST)/ipscan_l.c
+ /bin/rm -f $(DEST)/ippool_y.c $(DEST)/ippool_y.h $(DEST)/ippool_l.c
+ /bin/rm -f $(DEST)/ipnat_y.c $(DEST)/ipnat_y.h $(DEST)/ipnat_l.c
+ /bin/rm -f $(DEST)/ipf_l.h $(DEST)/ipmon_l.h $(DEST)/ippool_l.h
+ /bin/rm -f $(DEST)/ipscan_l.h $(DEST)/ipnat_l.h
diff --git a/contrib/ipfilter/tools/ipf.c b/contrib/ipfilter/tools/ipf.c
new file mode 100644
index 0000000..08cfb0a
--- /dev/null
+++ b/contrib/ipfilter/tools/ipf.c
@@ -0,0 +1,601 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#ifdef __FreeBSD__
+# ifndef __FreeBSD_cc_version
+# include <osreldate.h>
+# else
+# if __FreeBSD_cc_version < 430000
+# include <osreldate.h>
+# endif
+# endif
+#endif
+#include "ipf.h"
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include "netinet/ipl.h"
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#if !defined(__SVR4) && defined(__GNUC__)
+extern char *index __P((const char *, int));
+#endif
+
+extern char *optarg;
+extern int optind;
+extern frentry_t *frtop;
+
+
+void ipf_frsync __P((void));
+void zerostats __P((void));
+int main __P((int, char *[]));
+
+int opts = 0;
+int outputc = 0;
+int use_inet6 = 0;
+int exitstatus = 0;
+
+static void procfile __P((char *));
+static void flushfilter __P((char *, int *));
+static void set_state __P((u_int));
+static void showstats __P((friostat_t *));
+static void packetlogon __P((char *));
+static void swapactive __P((void));
+static int opendevice __P((char *, int));
+static void closedevice __P((void));
+static char *ipfname = IPL_NAME;
+static void usage __P((void));
+static int showversion __P((void));
+static int get_flags __P((void));
+static int ipf_interceptadd __P((int, ioctlfunc_t, void *));
+
+static int fd = -1;
+static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl,
+ ioctl, ioctl, ioctl,
+ ioctl, ioctl };
+
+/* XXX The following was added to satisfy a rescue/rescue/ build
+ XXX requirement. */
+int nohdrfields;
+
+static void usage()
+{
+ fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n",
+ "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]",
+ "[-f filename] [-T <tuneopts>]");
+ exit(1);
+}
+
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ int c, *filter = NULL;
+
+ if (argc < 2)
+ usage();
+
+ assigndefined(getenv("IPF_PREDEFINED"));
+
+ while ((c = getopt(argc, argv, "46Ac:dDEf:F:Il:m:noPrRsT:vVyzZ")) != -1) {
+ switch (c)
+ {
+ case '?' :
+ usage();
+ break;
+ case '4' :
+ use_inet6 = -1;
+ break;
+ case '6' :
+ use_inet6 = 1;
+ break;
+ case 'A' :
+ opts &= ~OPT_INACTIVE;
+ break;
+ case 'c' :
+ if (strcmp(optarg, "c") == 0)
+ outputc = 1;
+ break;
+ case 'E' :
+ set_state((u_int)1);
+ break;
+ case 'D' :
+ set_state((u_int)0);
+ break;
+ case 'd' :
+ opts ^= OPT_DEBUG;
+ break;
+ case 'f' :
+ procfile(optarg);
+ break;
+ case 'F' :
+ flushfilter(optarg, filter);
+ break;
+ case 'I' :
+ opts ^= OPT_INACTIVE;
+ break;
+ case 'l' :
+ packetlogon(optarg);
+ break;
+ case 'm' :
+ filter = parseipfexpr(optarg, NULL);
+ break;
+ case 'n' :
+ opts ^= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'o' :
+ break;
+ case 'P' :
+ ipfname = IPAUTH_NAME;
+ break;
+ case 'R' :
+ opts ^= OPT_NORESOLVE;
+ break;
+ case 'r' :
+ opts ^= OPT_REMOVE;
+ break;
+ case 's' :
+ swapactive();
+ break;
+ case 'T' :
+ if (opendevice(ipfname, 1) >= 0)
+ ipf_dotuning(fd, optarg, ioctl);
+ break;
+ case 'v' :
+ opts += OPT_VERBOSE;
+ break;
+ case 'V' :
+ if (showversion())
+ exit(1);
+ break;
+ case 'y' :
+ ipf_frsync();
+ break;
+ case 'z' :
+ opts ^= OPT_ZERORULEST;
+ break;
+ case 'Z' :
+ zerostats();
+ break;
+ }
+ }
+
+ if (optind < 2)
+ usage();
+
+ if (fd != -1)
+ (void) close(fd);
+
+ return(exitstatus);
+ /* NOTREACHED */
+}
+
+
+static int opendevice(ipfdev, check)
+ char *ipfdev;
+ int check;
+{
+ if (opts & OPT_DONOTHING)
+ return -2;
+
+ if (check && checkrev(ipfname) == -1) {
+ fprintf(stderr, "User/kernel version check failed\n");
+ return -2;
+ }
+
+ if (!ipfdev)
+ ipfdev = ipfname;
+
+ if (fd == -1)
+ if ((fd = open(ipfdev, O_RDWR)) == -1)
+ if ((fd = open(ipfdev, O_RDONLY)) == -1)
+ ipferror(fd, "open device");
+ return fd;
+}
+
+
+static void closedevice()
+{
+ close(fd);
+ fd = -1;
+}
+
+
+static int get_flags()
+{
+ int i = 0;
+
+ if ((opendevice(ipfname, 1) != -2) &&
+ (ioctl(fd, SIOCGETFF, &i) == -1)) {
+ ipferror(fd, "SIOCGETFF");
+ return 0;
+ }
+ return i;
+}
+
+
+static void set_state(enable)
+ u_int enable;
+{
+ if (opendevice(ipfname, 0) != -2) {
+ if (ioctl(fd, SIOCFRENB, &enable) == -1) {
+ if (errno == EBUSY) {
+ fprintf(stderr,
+ "IP FIlter: already initialized\n");
+ } else {
+ ipferror(fd, "SIOCFRENB");
+ }
+ }
+ }
+ return;
+}
+
+
+static void procfile(file)
+ char *file;
+{
+ (void) opendevice(ipfname, 1);
+
+ initparse();
+
+ ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file);
+
+ if (outputc) {
+ printC(0);
+ printC(1);
+ emit(-1, -1, NULL, NULL);
+ }
+}
+
+
+static int ipf_interceptadd(fd, ioctlfunc, ptr)
+ int fd;
+ ioctlfunc_t ioctlfunc;
+ void *ptr;
+{
+ if (outputc)
+ printc(ptr);
+
+ if (ipf_addrule(fd, ioctlfunc, ptr) != 0)
+ exitstatus = 1;
+ return 0;
+}
+
+
+static void packetlogon(opt)
+ char *opt;
+{
+ int flag, xfd, logopt, change = 0;
+
+ flag = get_flags();
+ if (flag != 0) {
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE)
+ printf("log flag is currently %#x\n", flag);
+ }
+
+ flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK);
+
+ if (strstr(opt, "pass")) {
+ flag |= FF_LOGPASS;
+ if (opts & OPT_VERBOSE)
+ printf("set log flag: pass\n");
+ change = 1;
+ }
+ if (strstr(opt, "nomatch")) {
+ flag |= FF_LOGNOMATCH;
+ if (opts & OPT_VERBOSE)
+ printf("set log flag: nomatch\n");
+ change = 1;
+ }
+ if (strstr(opt, "block") || strchr(opt, 'd')) {
+ flag |= FF_LOGBLOCK;
+ if (opts & OPT_VERBOSE)
+ printf("set log flag: block\n");
+ change = 1;
+ }
+ if (strstr(opt, "none")) {
+ if (opts & OPT_VERBOSE)
+ printf("disable all log flags\n");
+ change = 1;
+ }
+
+ if (change == 1) {
+ if (opendevice(ipfname, 1) != -2 &&
+ (ioctl(fd, SIOCSETFF, &flag) != 0))
+ ipferror(fd, "ioctl(SIOCSETFF)");
+ }
+
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
+ flag = get_flags();
+ printf("log flags are now %#x\n", flag);
+ }
+
+ if (strstr(opt, "state")) {
+ if (opts & OPT_VERBOSE)
+ printf("set state log flag\n");
+ xfd = open(IPSTATE_NAME, O_RDWR);
+ if (xfd >= 0) {
+ logopt = 0;
+ if (ioctl(xfd, SIOCGETLG, &logopt))
+ ipferror(fd, "ioctl(SIOCGETLG)");
+ else {
+ logopt = 1 - logopt;
+ if (ioctl(xfd, SIOCSETLG, &logopt))
+ ipferror(xfd, "ioctl(SIOCSETLG)");
+ }
+ close(xfd);
+ }
+ }
+
+ if (strstr(opt, "nat")) {
+ if (opts & OPT_VERBOSE)
+ printf("set nat log flag\n");
+ xfd = open(IPNAT_NAME, O_RDWR);
+ if (xfd >= 0) {
+ logopt = 0;
+ if (ioctl(xfd, SIOCGETLG, &logopt))
+ ipferror(xfd, "ioctl(SIOCGETLG)");
+ else {
+ logopt = 1 - logopt;
+ if (ioctl(xfd, SIOCSETLG, &logopt))
+ ipferror(xfd, "ioctl(SIOCSETLG)");
+ }
+ close(xfd);
+ }
+ }
+}
+
+
+static void flushfilter(arg, filter)
+ char *arg;
+ int *filter;
+{
+ int fl = 0, rem;
+
+ if (!arg || !*arg)
+ return;
+ if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) {
+ if (*arg == 'S')
+ fl = 0;
+ else if (*arg == 's')
+ fl = 1;
+ else
+ fl = atoi(arg);
+ rem = fl;
+
+ closedevice();
+ if (opendevice(IPSTATE_NAME, 1) == -2)
+ exit(1);
+
+ if (!(opts & OPT_DONOTHING)) {
+ if (use_inet6) {
+ fprintf(stderr,
+ "IPv6 rules are no longer seperate\n");
+ } else if (filter != NULL) {
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = filter[0] * sizeof(int);
+ obj.ipfo_type = IPFOBJ_IPFEXPR;
+ obj.ipfo_ptr = filter;
+ if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
+ ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
+ fl = -1;
+ } else {
+ fl = obj.ipfo_retval;
+ }
+ } else {
+ if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
+ ipferror(fd, "ioctl(SIOCIPFFL)");
+ exit(1);
+ }
+ }
+ }
+ if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
+ printf("remove flags %s (%d)\n", arg, rem);
+ }
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
+ printf("%d state entries removed\n", fl);
+ }
+ closedevice();
+ return;
+ }
+
+#ifdef SIOCIPFFA
+ if (!strcmp(arg, "u")) {
+ closedevice();
+ /*
+ * Flush auth rules and packets
+ */
+ if (opendevice(IPL_AUTH, 1) == -1)
+ perror("open(IPL_AUTH)");
+ else {
+ if (ioctl(fd, SIOCIPFFA, &fl) == -1)
+ ipferror(fd, "ioctl(SIOCIPFFA)");
+ }
+ closedevice();
+ return;
+ }
+#endif
+
+ if (strchr(arg, 'i') || strchr(arg, 'I'))
+ fl = FR_INQUE;
+ if (strchr(arg, 'o') || strchr(arg, 'O'))
+ fl = FR_OUTQUE;
+ if (strchr(arg, 'a') || strchr(arg, 'A'))
+ fl = FR_OUTQUE|FR_INQUE;
+ if (opts & OPT_INACTIVE)
+ fl |= FR_INACTIVE;
+ rem = fl;
+
+ if (opendevice(ipfname, 1) == -2)
+ exit(1);
+
+ if (!(opts & OPT_DONOTHING)) {
+ if (use_inet6) {
+ if (ioctl(fd, SIOCIPFL6, &fl) == -1) {
+ ipferror(fd, "ioctl(SIOCIPFL6)");
+ exit(1);
+ }
+ } else {
+ if (ioctl(fd, SIOCIPFFL, &fl) == -1) {
+ ipferror(fd, "ioctl(SIOCIPFFL)");
+ exit(1);
+ }
+ }
+ }
+
+ if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) {
+ printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "",
+ (rem & FR_OUTQUE) ? "O" : "", rem);
+ }
+ if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) {
+ printf("%d filter rules removed\n", fl);
+ }
+ return;
+}
+
+
+static void swapactive()
+{
+ int in = 2;
+
+ if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1)
+ ipferror(fd, "ioctl(SIOCSWAPA)");
+ else
+ printf("Set %d now inactive\n", in);
+}
+
+
+void ipf_frsync()
+{
+ int frsyn = 0;
+
+ if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1)
+ ipferror(fd, "SIOCFRSYN");
+ else
+ printf("filter sync'd\n");
+}
+
+
+void zerostats()
+{
+ ipfobj_t obj;
+ friostat_t fio;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_IPFSTAT;
+ obj.ipfo_size = sizeof(fio);
+ obj.ipfo_ptr = &fio;
+ obj.ipfo_offset = 0;
+
+ if (opendevice(ipfname, 1) != -2) {
+ if (ioctl(fd, SIOCFRZST, &obj) == -1) {
+ ipferror(fd, "ioctl(SIOCFRZST)");
+ exit(-1);
+ }
+ showstats(&fio);
+ }
+
+}
+
+
+/*
+ * read the kernel stats for packets blocked and passed
+ */
+static void showstats(fp)
+ friostat_t *fp;
+{
+ printf("bad packets:\t\tin %lu\tout %lu\n",
+ fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
+ printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu",
+ fp->f_st[0].fr_block, fp->f_st[0].fr_pass,
+ fp->f_st[0].fr_nom);
+ printf(" counted %lu\n", fp->f_st[0].fr_acct);
+ printf("output packets:\t\tblocked %lu passed %lu nomatch %lu",
+ fp->f_st[1].fr_block, fp->f_st[1].fr_pass,
+ fp->f_st[1].fr_nom);
+ printf(" counted %lu\n", fp->f_st[0].fr_acct);
+ printf(" input packets logged:\tblocked %lu passed %lu\n",
+ fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
+ printf("output packets logged:\tblocked %lu passed %lu\n",
+ fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
+}
+
+
+static int showversion()
+{
+ struct friostat fio;
+ ipfobj_t ipfo;
+ u_32_t flags;
+ char *s;
+ int vfd;
+
+ bzero((caddr_t)&ipfo, sizeof(ipfo));
+ ipfo.ipfo_rev = IPFILTER_VERSION;
+ ipfo.ipfo_size = sizeof(fio);
+ ipfo.ipfo_ptr = (void *)&fio;
+ ipfo.ipfo_type = IPFOBJ_IPFSTAT;
+
+ printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t));
+
+ if ((vfd = open(ipfname, O_RDONLY)) == -1) {
+ perror("open device");
+ return 1;
+ }
+
+ if (ioctl(vfd, SIOCGETFS, &ipfo)) {
+ ipferror(vfd, "ioctl(SIOCGETFS)");
+ close(vfd);
+ return 1;
+ }
+ close(vfd);
+ flags = get_flags();
+
+ printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version),
+ (int)sizeof(fio.f_version), fio.f_version);
+ printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no");
+ printf("Log Flags: %#x = ", flags);
+ s = "";
+ if (flags & FF_LOGPASS) {
+ printf("pass");
+ s = ", ";
+ }
+ if (flags & FF_LOGBLOCK) {
+ printf("%sblock", s);
+ s = ", ";
+ }
+ if (flags & FF_LOGNOMATCH) {
+ printf("%snomatch", s);
+ s = ", ";
+ }
+ if (flags & FF_BLOCKNONIP) {
+ printf("%snonip", s);
+ s = ", ";
+ }
+ if (!*s)
+ printf("none set");
+ putchar('\n');
+
+ printf("Default: ");
+ if (FR_ISPASS(fio.f_defpass))
+ s = "pass";
+ else if (FR_ISBLOCK(fio.f_defpass))
+ s = "block";
+ else
+ s = "nomatch -> block";
+ printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un");
+ printf("Active list: %d\n", fio.f_active);
+ printf("Feature mask: %#x\n", fio.f_features);
+
+ return 0;
+}
diff --git a/contrib/ipfilter/tools/ipf_y.y b/contrib/ipfilter/tools/ipf_y.y
new file mode 100644
index 0000000..e0dc847
--- /dev/null
+++ b/contrib/ipfilter/tools/ipf_y.y
@@ -0,0 +1,2749 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+%{
+#include "ipf.h"
+#include <sys/ioctl.h>
+#include <syslog.h>
+#ifdef IPFILTER_BPF
+# include <pcap.h>
+#endif
+#include "netinet/ip_pool.h"
+#include "netinet/ip_htable.h"
+#include "netinet/ipl.h"
+#include "ipf_l.h"
+
+#define YYDEBUG 1
+#define DOALL(x) for (fr = frc; fr != NULL; fr = fr->fr_next) { x }
+#define DOREM(x) for (; fr != NULL; fr = fr->fr_next) { x }
+
+extern void yyerror __P((char *));
+extern int yyparse __P((void));
+extern int yylex __P((void));
+extern int yydebug;
+extern FILE *yyin;
+extern int yylineNum;
+
+static int addname __P((frentry_t **, char *));
+static frentry_t *addrule __P((void));
+static frentry_t *allocfr __P((void));
+static void build_dstaddr_af __P((frentry_t *, void *));
+static void build_srcaddr_af __P((frentry_t *, void *));
+static void dobpf __P((int, char *));
+static void doipfexpr __P((char *));
+static void do_tuneint __P((char *, int));
+static void do_tunestr __P((char *, char *));
+static void fillgroup __P((frentry_t *));
+static int lookuphost __P((char *, i6addr_t *));
+static u_int makehash __P((struct alist_s *));
+static int makepool __P((struct alist_s *));
+static struct alist_s *newalist __P((struct alist_s *));
+static void newrule __P((void));
+static void resetaddr __P((void));
+static void setgroup __P((frentry_t **, char *));
+static void setgrhead __P((frentry_t **, char *));
+static void seticmphead __P((frentry_t **, char *));
+static void setifname __P((frentry_t **, int, char *));
+static void setipftype __P((void));
+static void setsyslog __P((void));
+static void unsetsyslog __P((void));
+
+frentry_t *fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL;
+
+static int ifpflag = 0;
+static int nowith = 0;
+static int dynamic = -1;
+static int pooled = 0;
+static int hashed = 0;
+static int nrules = 0;
+static int newlist = 0;
+static int added = 0;
+static int ipffd = -1;
+static int *yycont = NULL;
+static ioctlfunc_t ipfioctls[IPL_LOGSIZE];
+static addfunc_t ipfaddfunc = NULL;
+
+%}
+%union {
+ char *str;
+ u_32_t num;
+ frentry_t fr;
+ frtuc_t *frt;
+ struct alist_s *alist;
+ u_short port;
+ struct in_addr ip4;
+ struct {
+ u_short p1;
+ u_short p2;
+ int pc;
+ } pc;
+ struct ipp_s {
+ int type;
+ int ifpos;
+ int f;
+ int v;
+ int lif;
+ union i6addr a;
+ union i6addr m;
+ char *name;
+ } ipp;
+ struct {
+ i6addr_t adr;
+ int f;
+ } adr;
+ i6addr_t ip6;
+ struct {
+ char *if1;
+ char *if2;
+ } ifs;
+ char gname[FR_GROUPLEN];
+};
+
+%type <port> portnum
+%type <num> facility priority icmpcode seclevel secname icmptype
+%type <num> opt compare range opttype flagset optlist ipv6hdrlist ipv6hdr
+%type <num> portc porteq ipmask maskopts
+%type <ip4> ipv4 ipv4_16 ipv4_24
+%type <adr> hostname
+%type <ipp> addr ipaddr
+%type <str> servicename name interfacename groupname
+%type <pc> portrange portcomp
+%type <alist> addrlist poollist
+%type <ifs> onname
+
+%token <num> YY_NUMBER YY_HEX
+%token <str> YY_STR
+%token YY_COMMENT
+%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
+%token YY_RANGE_OUT YY_RANGE_IN
+%token <ip6> YY_IPV6
+
+%token IPFY_SET
+%token IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL IPFY_NOMATCH
+%token IPFY_RETICMP IPFY_RETRST IPFY_RETICMPASDST
+%token IPFY_IN IPFY_OUT
+%token IPFY_QUICK IPFY_ON IPFY_OUTVIA IPFY_INVIA
+%token IPFY_DUPTO IPFY_TO IPFY_FROUTE IPFY_REPLY_TO IPFY_ROUTETO
+%token IPFY_TOS IPFY_TTL IPFY_PROTO IPFY_INET IPFY_INET6
+%token IPFY_HEAD IPFY_GROUP
+%token IPFY_AUTH IPFY_PREAUTH
+%token IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK IPFY_L5AS
+%token IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP IPFY_DECAPS
+%token IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH
+%token IPFY_IPFEXPR IPFY_PPS IPFY_FAMILY IPFY_DSTLIST
+%token IPFY_ESP IPFY_AH
+%token IPFY_WITH IPFY_AND IPFY_NOT IPFY_NO IPFY_OPT
+%token IPFY_TCPUDP IPFY_TCP IPFY_UDP
+%token IPFY_FLAGS IPFY_MULTICAST
+%token IPFY_MASK IPFY_BROADCAST IPFY_NETWORK IPFY_NETMASKED IPFY_PEER
+%token IPFY_RPC IPFY_PORT
+%token IPFY_NOW IPFY_COMMENT IPFY_RULETTL
+%token IPFY_ICMP IPFY_ICMPTYPE IPFY_ICMPCODE
+%token IPFY_IPOPTS IPFY_SHORT IPFY_NAT IPFY_BADSRC IPFY_LOWTTL IPFY_FRAG
+%token IPFY_MBCAST IPFY_BAD IPFY_BADNAT IPFY_OOW IPFY_NEWISN IPFY_NOICMPERR
+%token IPFY_KEEP IPFY_STATE IPFY_FRAGS IPFY_LIMIT IPFY_STRICT IPFY_AGE
+%token IPFY_SYNC IPFY_FRAGBODY IPFY_ICMPHEAD IPFY_NOLOG IPFY_LOOSE
+%token IPFY_MAX_SRCS IPFY_MAX_PER_SRC
+%token IPFY_IPOPT_NOP IPFY_IPOPT_RR IPFY_IPOPT_ZSU IPFY_IPOPT_MTUP
+%token IPFY_IPOPT_MTUR IPFY_IPOPT_ENCODE IPFY_IPOPT_TS IPFY_IPOPT_TR
+%token IPFY_IPOPT_SEC IPFY_IPOPT_LSRR IPFY_IPOPT_ESEC IPFY_IPOPT_CIPSO
+%token IPFY_IPOPT_SATID IPFY_IPOPT_SSRR IPFY_IPOPT_ADDEXT IPFY_IPOPT_VISA
+%token IPFY_IPOPT_IMITD IPFY_IPOPT_EIP IPFY_IPOPT_FINN IPFY_IPOPT_DPS
+%token IPFY_IPOPT_SDB IPFY_IPOPT_NSAPA IPFY_IPOPT_RTRALRT IPFY_IPOPT_UMP
+%token IPFY_SECCLASS IPFY_SEC_UNC IPFY_SEC_CONF IPFY_SEC_RSV1 IPFY_SEC_RSV2
+%token IPFY_SEC_RSV4 IPFY_SEC_SEC IPFY_SEC_TS IPFY_SEC_RSV3 IPFY_DOI
+
+%token IPFY_V6HDRS IPFY_IPV6OPT IPFY_IPV6OPT_DSTOPTS IPFY_IPV6OPT_HOPOPTS
+%token IPFY_IPV6OPT_IPV6 IPFY_IPV6OPT_NONE IPFY_IPV6OPT_ROUTING IPFY_V6HDR
+%token IPFY_IPV6OPT_MOBILITY IPFY_IPV6OPT_ESP IPFY_IPV6OPT_FRAG
+
+%token IPFY_ICMPT_UNR IPFY_ICMPT_ECHO IPFY_ICMPT_ECHOR IPFY_ICMPT_SQUENCH
+%token IPFY_ICMPT_REDIR IPFY_ICMPT_TIMEX IPFY_ICMPT_PARAMP IPFY_ICMPT_TIMEST
+%token IPFY_ICMPT_TIMESTREP IPFY_ICMPT_INFOREQ IPFY_ICMPT_INFOREP
+%token IPFY_ICMPT_MASKREQ IPFY_ICMPT_MASKREP IPFY_ICMPT_ROUTERAD
+%token IPFY_ICMPT_ROUTERSOL
+
+%token IPFY_ICMPC_NETUNR IPFY_ICMPC_HSTUNR IPFY_ICMPC_PROUNR IPFY_ICMPC_PORUNR
+%token IPFY_ICMPC_NEEDF IPFY_ICMPC_SRCFAIL IPFY_ICMPC_NETUNK IPFY_ICMPC_HSTUNK
+%token IPFY_ICMPC_ISOLATE IPFY_ICMPC_NETPRO IPFY_ICMPC_HSTPRO
+%token IPFY_ICMPC_NETTOS IPFY_ICMPC_HSTTOS IPFY_ICMPC_FLTPRO IPFY_ICMPC_HSTPRE
+%token IPFY_ICMPC_CUTPRE
+
+%token IPFY_FAC_KERN IPFY_FAC_USER IPFY_FAC_MAIL IPFY_FAC_DAEMON IPFY_FAC_AUTH
+%token IPFY_FAC_SYSLOG IPFY_FAC_LPR IPFY_FAC_NEWS IPFY_FAC_UUCP IPFY_FAC_CRON
+%token IPFY_FAC_LOCAL0 IPFY_FAC_LOCAL1 IPFY_FAC_LOCAL2 IPFY_FAC_LOCAL3
+%token IPFY_FAC_LOCAL4 IPFY_FAC_LOCAL5 IPFY_FAC_LOCAL6 IPFY_FAC_LOCAL7
+%token IPFY_FAC_SECURITY IPFY_FAC_FTP IPFY_FAC_AUTHPRIV IPFY_FAC_AUDIT
+%token IPFY_FAC_LFMT IPFY_FAC_CONSOLE
+
+%token IPFY_PRI_EMERG IPFY_PRI_ALERT IPFY_PRI_CRIT IPFY_PRI_ERR IPFY_PRI_WARN
+%token IPFY_PRI_NOTICE IPFY_PRI_INFO IPFY_PRI_DEBUG
+%%
+file: settings rules
+ | rules
+ ;
+
+settings:
+ YY_COMMENT
+ | setting
+ | settings setting
+ ;
+
+rules: line
+ | assign
+ | rules line
+ | rules assign
+ ;
+
+setting:
+ IPFY_SET YY_STR YY_NUMBER ';' { do_tuneint($2, $3); }
+ | IPFY_SET YY_STR YY_HEX ';' { do_tuneint($2, $3); }
+ | IPFY_SET YY_STR YY_STR ';' { do_tunestr($2, $3); }
+ ;
+
+line: rule { while ((fr = frtop) != NULL) {
+ frtop = fr->fr_next;
+ fr->fr_next = NULL;
+ if ((fr->fr_type == FR_T_IPF) &&
+ (fr->fr_ip.fi_v == 0))
+ fr->fr_mip.fi_v = 0;
+ /* XXX validate ? */
+ (*ipfaddfunc)(ipffd, ipfioctls[IPL_LOGIPF], fr);
+ fr->fr_next = frold;
+ frold = fr;
+ }
+ resetlexer();
+ }
+ | YY_COMMENT
+ ;
+
+xx: { newrule(); }
+ ;
+
+assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
+ resetlexer();
+ free($1);
+ free($3);
+ yyvarnext = 0;
+ }
+ ;
+
+assigning:
+ '=' { yyvarnext = 1; }
+ ;
+
+rule: inrule eol
+ | outrule eol
+ ;
+
+eol: | ';'
+ ;
+
+inrule:
+ rulehead markin inopts rulemain ruletail intag ruletail2
+ ;
+
+outrule:
+ rulehead markout outopts rulemain ruletail outtag ruletail2
+ ;
+
+rulehead:
+ xx collection action
+ | xx insert collection action
+ ;
+
+markin: IPFY_IN { fr->fr_flags |= FR_INQUE; }
+ ;
+
+markout:
+ IPFY_OUT { fr->fr_flags |= FR_OUTQUE; }
+ ;
+
+rulemain:
+ ipfrule
+ | bpfrule
+ | exprrule
+ ;
+
+ipfrule:
+ family tos ttl proto ip
+ ;
+
+family: | IPFY_FAMILY IPFY_INET { if (use_inet6 == 1) {
+ YYERROR;
+ } else {
+ frc->fr_family = AF_INET;
+ }
+ }
+ | IPFY_INET { if (use_inet6 == 1) {
+ YYERROR;
+ } else {
+ frc->fr_family = AF_INET;
+ }
+ }
+ | IPFY_FAMILY IPFY_INET6 { if (use_inet6 == -1) {
+ YYERROR;
+ } else {
+ frc->fr_family = AF_INET6;
+ }
+ }
+ | IPFY_INET6 { if (use_inet6 == -1) {
+ YYERROR;
+ } else {
+ frc->fr_family = AF_INET6;
+ }
+ }
+ ;
+
+bpfrule:
+ IPFY_BPFV4 '{' YY_STR '}' { dobpf(4, $3); free($3); }
+ | IPFY_BPFV6 '{' YY_STR '}' { dobpf(6, $3); free($3); }
+ ;
+
+exprrule:
+ IPFY_IPFEXPR '{' YY_STR '}' { doipfexpr($3); }
+ ;
+
+ruletail:
+ with keep head group
+ ;
+
+ruletail2:
+ pps age new rulettl comment
+ ;
+
+intag: settagin matchtagin
+ ;
+
+outtag: settagout matchtagout
+ ;
+
+insert:
+ '@' YY_NUMBER { fr->fr_hits = (U_QUAD_T)$2 + 1; }
+ ;
+
+collection:
+ | YY_NUMBER { fr->fr_collect = $1; }
+ ;
+
+action: block
+ | IPFY_PASS { fr->fr_flags |= FR_PASS; }
+ | IPFY_NOMATCH { fr->fr_flags |= FR_NOMATCH; }
+ | log
+ | IPFY_COUNT { fr->fr_flags |= FR_ACCOUNT; }
+ | decaps { fr->fr_flags |= FR_DECAPSULATE; }
+ | auth
+ | IPFY_SKIP YY_NUMBER { fr->fr_flags |= FR_SKIP;
+ fr->fr_arg = $2; }
+ | IPFY_CALL func
+ | IPFY_CALL IPFY_NOW func { fr->fr_flags |= FR_CALLNOW; }
+ ;
+
+block: blocked
+ | blocked blockreturn
+ ;
+
+blocked:
+ IPFY_BLOCK { fr->fr_flags = FR_BLOCK; }
+ ;
+blockreturn:
+ IPFY_RETICMP { fr->fr_flags |= FR_RETICMP; }
+ | IPFY_RETICMP returncode { fr->fr_flags |= FR_RETICMP; }
+ | IPFY_RETICMPASDST { fr->fr_flags |= FR_FAKEICMP; }
+ | IPFY_RETICMPASDST returncode { fr->fr_flags |= FR_FAKEICMP; }
+ | IPFY_RETRST { fr->fr_flags |= FR_RETRST; }
+ ;
+
+decaps: IPFY_DECAPS
+ | IPFY_DECAPS IPFY_L5AS '(' YY_STR ')'
+ { fr->fr_icode = atoi($4); }
+ ;
+
+log: IPFY_LOG { fr->fr_flags |= FR_LOG; }
+ | IPFY_LOG logoptions { fr->fr_flags |= FR_LOG; }
+ ;
+
+auth: IPFY_AUTH { fr->fr_flags |= FR_AUTH; }
+ | IPFY_AUTH blockreturn { fr->fr_flags |= FR_AUTH;}
+ | IPFY_PREAUTH { fr->fr_flags |= FR_PREAUTH; }
+ ;
+
+func: YY_STR '/' YY_NUMBER
+ { fr->fr_func = nametokva($1, ipfioctls[IPL_LOGIPF]);
+ fr->fr_arg = $3;
+ free($1);
+ }
+ ;
+
+inopts:
+ | inopts inopt
+ ;
+
+inopt:
+ logopt
+ | quick
+ | on
+ | dup
+ | froute
+ | proute
+ | replyto
+ ;
+
+outopts:
+ | outopts outopt
+ ;
+
+outopt:
+ logopt
+ | quick
+ | on
+ | dup
+ | proute
+ | froute
+ | replyto
+ ;
+
+tos: | settos YY_NUMBER { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) }
+ | settos YY_HEX { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) }
+ | settos lstart toslist lend
+ ;
+
+settos: IPFY_TOS { setipftype(); }
+ ;
+
+toslist:
+ YY_NUMBER { DOALL(fr->fr_tos = $1; fr->fr_mtos = 0xff;) }
+ | YY_HEX { DOREM(fr->fr_tos = $1; fr->fr_mtos = 0xff;) }
+ | toslist lmore YY_NUMBER
+ { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) }
+ | toslist lmore YY_HEX
+ { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) }
+ ;
+
+ttl: | setttl YY_NUMBER
+ { DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) }
+ | setttl lstart ttllist lend
+ ;
+
+lstart: '{' { newlist = 1; fr = frc; added = 0; }
+ ;
+
+lend: '}' { nrules += added; }
+ ;
+
+lmore: lanother { if (newlist == 1) {
+ newlist = 0;
+ }
+ fr = addrule();
+ if (yycont != NULL)
+ *yycont = 1;
+ }
+ ;
+
+lanother:
+ | ','
+ ;
+
+setttl: IPFY_TTL { setipftype(); }
+ ;
+
+ttllist:
+ YY_NUMBER { DOREM(fr->fr_ttl = $1; fr->fr_mttl = 0xff;) }
+ | ttllist lmore YY_NUMBER
+ { DOREM(fr->fr_ttl = $3; fr->fr_mttl = 0xff;) }
+ ;
+
+proto: | protox protocol { yyresetdict(); }
+ ;
+
+protox: IPFY_PROTO { setipftype();
+ fr = frc;
+ yysetdict(NULL); }
+ ;
+
+ip: srcdst flags icmp
+ ;
+
+group: | IPFY_GROUP groupname { DOALL(setgroup(&fr, $2); \
+ fillgroup(fr););
+ free($2);
+ }
+ ;
+
+head: | IPFY_HEAD groupname { DOALL(setgrhead(&fr, $2););
+ free($2);
+ }
+ ;
+
+groupname:
+ YY_STR { $$ = $1;
+ if (strlen($$) >= FR_GROUPLEN)
+ $$[FR_GROUPLEN - 1] = '\0';
+ }
+ | YY_NUMBER { $$ = malloc(16);
+ sprintf($$, "%d", $1);
+ }
+ ;
+
+settagin:
+ | IPFY_SETTAG '(' taginlist ')'
+ ;
+
+taginlist:
+ taginspec
+ | taginlist ',' taginspec
+ ;
+
+taginspec:
+ logtag
+ ;
+
+nattag: IPFY_NAT '=' YY_STR { DOALL(strncpy(fr->fr_nattag.ipt_tag,\
+ $3, IPFTAG_LEN););
+ free($3); }
+ | IPFY_NAT '=' YY_NUMBER { DOALL(sprintf(fr->fr_nattag.ipt_tag,\
+ "%d", $3 & 0xffffffff);) }
+ ;
+
+logtag: IPFY_LOG '=' YY_NUMBER { DOALL(fr->fr_logtag = $3;) }
+ ;
+
+settagout:
+ | IPFY_SETTAG '(' tagoutlist ')'
+ ;
+
+tagoutlist:
+ tagoutspec
+ | tagoutlist ',' tagoutspec
+ ;
+
+tagoutspec:
+ logtag
+ | nattag
+ ;
+
+matchtagin:
+ | IPFY_MATCHTAG '(' tagoutlist ')'
+ ;
+
+matchtagout:
+ | IPFY_MATCHTAG '(' taginlist ')'
+ ;
+
+pps: | IPFY_PPS YY_NUMBER { DOALL(fr->fr_pps = $2;) }
+ ;
+
+new: | savegroup file restoregroup
+ ;
+
+rulettl:
+ | IPFY_RULETTL YY_NUMBER { DOALL(fr->fr_die = $2;) }
+ ;
+
+comment:
+ | IPFY_COMMENT YY_STR { DOALL(fr->fr_comment = addname(&fr, \
+ $2);) }
+ ;
+
+savegroup:
+ '{'
+ ;
+
+restoregroup:
+ '}'
+ ;
+
+logopt: log
+ ;
+
+quick: IPFY_QUICK { fr->fr_flags |= FR_QUICK; }
+ ;
+
+on: IPFY_ON onname { setifname(&fr, 0, $2.if1);
+ free($2.if1);
+ if ($2.if2 != NULL) {
+ setifname(&fr, 1,
+ $2.if2);
+ free($2.if2);
+ }
+ }
+ | IPFY_ON lstart onlist lend
+ | IPFY_ON onname IPFY_INVIA vianame { setifname(&fr, 0, $2.if1);
+ free($2.if1);
+ if ($2.if2 != NULL) {
+ setifname(&fr, 1,
+ $2.if2);
+ free($2.if2);
+ }
+ }
+ | IPFY_ON onname IPFY_OUTVIA vianame { setifname(&fr, 0, $2.if1);
+ free($2.if1);
+ if ($2.if2 != NULL) {
+ setifname(&fr, 1,
+ $2.if2);
+ free($2.if2);
+ }
+ }
+ ;
+
+onlist: onname { DOREM(setifname(&fr, 0, $1.if1); \
+ if ($1.if2 != NULL) \
+ setifname(&fr, 1, $1.if2); \
+ )
+ free($1.if1);
+ if ($1.if2 != NULL)
+ free($1.if2);
+ }
+ | onlist lmore onname { DOREM(setifname(&fr, 0, $3.if1); \
+ if ($3.if2 != NULL) \
+ setifname(&fr, 1, $3.if2); \
+ )
+ free($3.if1);
+ if ($3.if2 != NULL)
+ free($3.if2);
+ }
+ ;
+
+onname: interfacename { $$.if1 = $1;
+ $$.if2 = NULL;
+ }
+ | interfacename ',' interfacename
+ { $$.if1 = $1;
+ $$.if2 = $3;
+ }
+ ;
+
+vianame:
+ name { setifname(&fr, 2, $1);
+ free($1);
+ }
+ | name ',' name { setifname(&fr, 2, $1);
+ free($1);
+ setifname(&fr, 3, $3);
+ free($3);
+ }
+ ;
+
+dup: IPFY_DUPTO name
+ { int idx = addname(&fr, $2);
+ fr->fr_dif.fd_name = idx;
+ free($2);
+ }
+ | IPFY_DUPTO IPFY_DSTLIST '/' name
+ { int idx = addname(&fr, $4);
+ fr->fr_dif.fd_name = idx;
+ fr->fr_dif.fd_type = FRD_DSTLIST;
+ free($4);
+ }
+ | IPFY_DUPTO name duptoseparator hostname
+ { int idx = addname(&fr, $2);
+ fr->fr_dif.fd_name = idx;
+ fr->fr_dif.fd_ptr = (void *)-1;
+ fr->fr_dif.fd_ip6 = $4.adr;
+ if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC)
+ fr->fr_family = $4.f;
+ yyexpectaddr = 0;
+ free($2);
+ }
+ ;
+
+duptoseparator:
+ ':' { yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); }
+ ;
+
+froute: IPFY_FROUTE { fr->fr_flags |= FR_FASTROUTE; }
+ ;
+
+proute: routeto name
+ { int idx = addname(&fr, $2);
+ fr->fr_tif.fd_name = idx;
+ free($2);
+ }
+ | routeto IPFY_DSTLIST '/' name
+ { int idx = addname(&fr, $4);
+ fr->fr_tif.fd_name = idx;
+ fr->fr_tif.fd_type = FRD_DSTLIST;
+ free($4);
+ }
+ | routeto name duptoseparator hostname
+ { int idx = addname(&fr, $2);
+ fr->fr_tif.fd_name = idx;
+ fr->fr_tif.fd_ptr = (void *)-1;
+ fr->fr_tif.fd_ip6 = $4.adr;
+ if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC)
+ fr->fr_family = $4.f;
+ yyexpectaddr = 0;
+ free($2);
+ }
+ ;
+
+routeto:
+ IPFY_TO
+ | IPFY_ROUTETO
+ ;
+
+replyto:
+ IPFY_REPLY_TO name
+ { int idx = addname(&fr, $2);
+ fr->fr_rif.fd_name = idx;
+ free($2);
+ }
+ | IPFY_REPLY_TO IPFY_DSTLIST '/' name
+ { fr->fr_rif.fd_name = addname(&fr, $4);
+ fr->fr_rif.fd_type = FRD_DSTLIST;
+ free($4);
+ }
+ | IPFY_REPLY_TO name duptoseparator hostname
+ { int idx = addname(&fr, $2);
+ fr->fr_rif.fd_name = idx;
+ fr->fr_rif.fd_ptr = (void *)-1;
+ fr->fr_rif.fd_ip6 = $4.adr;
+ if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC)
+ fr->fr_family = $4.f;
+ free($2);
+ }
+ ;
+
+logoptions:
+ logoption
+ | logoptions logoption
+ ;
+
+logoption:
+ IPFY_BODY { fr->fr_flags |= FR_LOGBODY; }
+ | IPFY_FIRST { fr->fr_flags |= FR_LOGFIRST; }
+ | IPFY_ORBLOCK { fr->fr_flags |= FR_LOGORBLOCK; }
+ | level loglevel { unsetsyslog(); }
+ ;
+
+returncode:
+ starticmpcode icmpcode ')' { fr->fr_icode = $2; yyresetdict(); }
+ ;
+
+starticmpcode:
+ '(' { yysetdict(icmpcodewords); }
+ ;
+
+srcdst: | IPFY_ALL
+ | fromto
+ ;
+
+protocol:
+ YY_NUMBER { DOALL(fr->fr_proto = $1; \
+ fr->fr_mproto = 0xff;)
+ }
+ | YY_STR { if (!strcmp($1, "tcp-udp")) {
+ DOALL(fr->fr_flx |= FI_TCPUDP; \
+ fr->fr_mflx |= FI_TCPUDP;)
+ } else {
+ int p = getproto($1);
+ if (p == -1)
+ yyerror("protocol unknown");
+ DOALL(fr->fr_proto = p; \
+ fr->fr_mproto = 0xff;)
+ }
+ free($1);
+ }
+ | YY_STR nextstring YY_STR
+ { if (!strcmp($1, "tcp") &&
+ !strcmp($3, "udp")) {
+ DOREM(fr->fr_flx |= FI_TCPUDP; \
+ fr->fr_mflx |= FI_TCPUDP;)
+ } else {
+ YYERROR;
+ }
+ free($1);
+ free($3);
+ }
+ ;
+
+nextstring:
+ '/' { yysetdict(NULL); }
+ ;
+
+fromto: from srcobject to dstobject { yyexpectaddr = 0; yycont = NULL; }
+ | to dstobject { yyexpectaddr = 0; yycont = NULL; }
+ | from srcobject { yyexpectaddr = 0; yycont = NULL; }
+ ;
+
+from: IPFY_FROM { setipftype();
+ if (fr == NULL)
+ fr = frc;
+ yyexpectaddr = 1;
+ if (yydebug)
+ printf("set yyexpectaddr\n");
+ yycont = &yyexpectaddr;
+ yysetdict(addrwords);
+ resetaddr(); }
+ ;
+
+to: IPFY_TO { if (fr == NULL)
+ fr = frc;
+ yyexpectaddr = 1;
+ if (yydebug)
+ printf("set yyexpectaddr\n");
+ yycont = &yyexpectaddr;
+ yysetdict(addrwords);
+ resetaddr();
+ }
+ ;
+
+with: | andwith withlist
+ ;
+
+andwith:
+ IPFY_WITH { nowith = 0; setipftype(); }
+ | IPFY_AND { nowith = 0; setipftype(); }
+ ;
+
+flags: | startflags flagset
+ { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) }
+ | startflags flagset '/' flagset
+ { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
+ | startflags '/' flagset
+ { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) }
+ | startflags YY_NUMBER
+ { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) }
+ | startflags '/' YY_NUMBER
+ { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) }
+ | startflags YY_NUMBER '/' YY_NUMBER
+ { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
+ | startflags flagset '/' YY_NUMBER
+ { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
+ | startflags YY_NUMBER '/' flagset
+ { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) }
+ ;
+
+startflags:
+ IPFY_FLAGS { if (frc->fr_type != FR_T_IPF)
+ yyerror("flags with non-ipf type rule");
+ if (frc->fr_proto != IPPROTO_TCP)
+ yyerror("flags with non-TCP rule");
+ }
+ ;
+
+flagset:
+ YY_STR { $$ = tcpflags($1); free($1); }
+ | YY_HEX { $$ = $1; }
+ ;
+
+srcobject:
+ { yyresetdict(); } fromport
+ | srcaddr srcport
+ | '!' srcaddr srcport
+ { DOALL(fr->fr_flags |= FR_NOTSRCIP;) }
+ ;
+
+srcaddr:
+ addr { build_srcaddr_af(fr, &$1); }
+ | lstart srcaddrlist lend
+ ;
+
+srcaddrlist:
+ addr { build_srcaddr_af(fr, &$1); }
+ | srcaddrlist lmore addr
+ { build_srcaddr_af(fr, &$3); }
+ ;
+
+srcport:
+ | portcomp
+ { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) }
+ | portrange
+ { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \
+ fr->fr_stop = $1.p2;) }
+ | porteq lstart srcportlist lend
+ { yyresetdict(); }
+ ;
+
+fromport:
+ portcomp
+ { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) }
+ | portrange
+ { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \
+ fr->fr_stop = $1.p2;) }
+ | porteq lstart srcportlist lend
+ { yyresetdict(); }
+ ;
+
+srcportlist:
+ portnum { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $1;) }
+ | portnum ':' portnum
+ { DOREM(fr->fr_scmp = FR_INCRANGE; fr->fr_sport = $1; \
+ fr->fr_stop = $3;) }
+ | portnum YY_RANGE_IN portnum
+ { DOREM(fr->fr_scmp = FR_INRANGE; fr->fr_sport = $1; \
+ fr->fr_stop = $3;) }
+ | srcportlist lmore portnum
+ { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $3;) }
+ | srcportlist lmore portnum ':' portnum
+ { DOREM(fr->fr_scmp = FR_INCRANGE; fr->fr_sport = $3; \
+ fr->fr_stop = $5;) }
+ | srcportlist lmore portnum YY_RANGE_IN portnum
+ { DOREM(fr->fr_scmp = FR_INRANGE; fr->fr_sport = $3; \
+ fr->fr_stop = $5;) }
+ ;
+
+dstobject:
+ { yyresetdict(); } toport
+ | dstaddr dstport
+ | '!' dstaddr dstport
+ { DOALL(fr->fr_flags |= FR_NOTDSTIP;) }
+ ;
+
+dstaddr:
+ addr { if (($1.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) &&
+ ($1.f != frc->fr_family))
+ yyerror("1.src/dst address family mismatch");
+ build_dstaddr_af(fr, &$1);
+ }
+ | lstart dstaddrlist lend
+ ;
+
+dstaddrlist:
+ addr { if (($1.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) &&
+ ($1.f != frc->fr_family))
+ yyerror("2.src/dst address family mismatch");
+ build_dstaddr_af(fr, &$1);
+ }
+ | dstaddrlist lmore addr
+ { if (($3.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) &&
+ ($3.f != frc->fr_family))
+ yyerror("3.src/dst address family mismatch");
+ build_dstaddr_af(fr, &$3);
+ }
+ ;
+
+
+dstport:
+ | portcomp
+ { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) }
+ | portrange
+ { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \
+ fr->fr_dtop = $1.p2;) }
+ | porteq lstart dstportlist lend
+ { yyresetdict(); }
+ ;
+
+toport:
+ portcomp
+ { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) }
+ | portrange
+ { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \
+ fr->fr_dtop = $1.p2;) }
+ | porteq lstart dstportlist lend
+ { yyresetdict(); }
+ ;
+
+dstportlist:
+ portnum { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $1;) }
+ | portnum ':' portnum
+ { DOREM(fr->fr_dcmp = FR_INCRANGE; fr->fr_dport = $1; \
+ fr->fr_dtop = $3;) }
+ | portnum YY_RANGE_IN portnum
+ { DOREM(fr->fr_dcmp = FR_INRANGE; fr->fr_dport = $1; \
+ fr->fr_dtop = $3;) }
+ | dstportlist lmore portnum
+ { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $3;) }
+ | dstportlist lmore portnum ':' portnum
+ { DOREM(fr->fr_dcmp = FR_INCRANGE; fr->fr_dport = $3; \
+ fr->fr_dtop = $5;) }
+ | dstportlist lmore portnum YY_RANGE_IN portnum
+ { DOREM(fr->fr_dcmp = FR_INRANGE; fr->fr_dport = $3; \
+ fr->fr_dtop = $5;) }
+ ;
+
+addr: pool '/' YY_NUMBER { pooled = 1;
+ yyexpectaddr = 0;
+ $$.type = FRI_LOOKUP;
+ $$.v = 0;
+ $$.ifpos = -1;
+ $$.f = AF_UNSPEC;
+ $$.a.iplookuptype = IPLT_POOL;
+ $$.a.iplookupsubtype = 0;
+ $$.a.iplookupnum = $3; }
+ | pool '/' YY_STR { pooled = 1;
+ $$.ifpos = -1;
+ $$.f = AF_UNSPEC;
+ $$.type = FRI_LOOKUP;
+ $$.a.iplookuptype = IPLT_POOL;
+ $$.a.iplookupsubtype = 1;
+ $$.a.iplookupname = addname(&fr, $3);
+ }
+ | pool '=' '(' { yyexpectaddr = 1;
+ pooled = 1;
+ }
+ poollist ')' { yyexpectaddr = 0;
+ $$.v = 0;
+ $$.ifpos = -1;
+ $$.f = AF_UNSPEC;
+ $$.type = FRI_LOOKUP;
+ $$.a.iplookuptype = IPLT_POOL;
+ $$.a.iplookupsubtype = 0;
+ $$.a.iplookupnum = makepool($5);
+ }
+ | hash '/' YY_NUMBER { hashed = 1;
+ yyexpectaddr = 0;
+ $$.v = 0;
+ $$.ifpos = -1;
+ $$.f = AF_UNSPEC;
+ $$.type = FRI_LOOKUP;
+ $$.a.iplookuptype = IPLT_HASH;
+ $$.a.iplookupsubtype = 0;
+ $$.a.iplookupnum = $3;
+ }
+ | hash '/' YY_STR { hashed = 1;
+ $$.type = FRI_LOOKUP;
+ $$.v = 0;
+ $$.ifpos = -1;
+ $$.f = AF_UNSPEC;
+ $$.a.iplookuptype = IPLT_HASH;
+ $$.a.iplookupsubtype = 1;
+ $$.a.iplookupname = addname(&fr, $3);
+ }
+ | hash '=' '(' { hashed = 1;
+ yyexpectaddr = 1;
+ }
+ addrlist ')' { yyexpectaddr = 0;
+ $$.v = 0;
+ $$.ifpos = -1;
+ $$.f = AF_UNSPEC;
+ $$.type = FRI_LOOKUP;
+ $$.a.iplookuptype = IPLT_HASH;
+ $$.a.iplookupsubtype = 0;
+ $$.a.iplookupnum = makehash($5);
+ }
+ | ipaddr { $$ = $1;
+ yyexpectaddr = 0; }
+ ;
+
+ipaddr: IPFY_ANY { memset(&($$), 0, sizeof($$));
+ $$.type = FRI_NORMAL;
+ $$.ifpos = -1;
+ yyexpectaddr = 0;
+ }
+ | hostname { memset(&($$), 0, sizeof($$));
+ $$.a = $1.adr;
+ $$.f = $1.f;
+ if ($1.f == AF_INET6)
+ fill6bits(128, $$.m.i6);
+ else if ($1.f == AF_INET)
+ fill6bits(32, $$.m.i6);
+ $$.v = ftov($1.f);
+ $$.ifpos = dynamic;
+ $$.type = FRI_NORMAL;
+ }
+ | hostname { yyresetdict(); }
+ maskspace { yysetdict(maskwords);
+ yyexpectaddr = 2; }
+ ipmask { memset(&($$), 0, sizeof($$));
+ ntomask($1.f, $5, $$.m.i6);
+ $$.a = $1.adr;
+ $$.a.i6[0] &= $$.m.i6[0];
+ $$.a.i6[1] &= $$.m.i6[1];
+ $$.a.i6[2] &= $$.m.i6[2];
+ $$.a.i6[3] &= $$.m.i6[3];
+ $$.f = $1.f;
+ $$.v = ftov($1.f);
+ $$.type = ifpflag;
+ $$.ifpos = dynamic;
+ if (ifpflag != 0 && $$.v == 0) {
+ if (frc->fr_family == AF_INET6){
+ $$.v = 6;
+ $$.f = AF_INET6;
+ } else {
+ $$.v = 4;
+ $$.f = AF_INET;
+ }
+ }
+ yyresetdict();
+ yyexpectaddr = 0;
+ }
+ | '(' YY_STR ')' { memset(&($$), 0, sizeof($$));
+ $$.type = FRI_DYNAMIC;
+ ifpflag = FRI_DYNAMIC;
+ $$.ifpos = addname(&fr, $2);
+ $$.lif = 0;
+ }
+ | '(' YY_STR ')' '/'
+ { ifpflag = FRI_DYNAMIC; yysetdict(maskwords); }
+ maskopts
+ { memset(&($$), 0, sizeof($$));
+ $$.type = ifpflag;
+ $$.ifpos = addname(&fr, $2);
+ $$.lif = 0;
+ if (frc->fr_family == AF_UNSPEC)
+ frc->fr_family = AF_INET;
+ if (ifpflag == FRI_DYNAMIC) {
+ ntomask(frc->fr_family,
+ $6, $$.m.i6);
+ }
+ yyresetdict();
+ yyexpectaddr = 0;
+ }
+ | '(' YY_STR ':' YY_NUMBER ')' '/'
+ { ifpflag = FRI_DYNAMIC; yysetdict(maskwords); }
+ maskopts
+ { memset(&($$), 0, sizeof($$));
+ $$.type = ifpflag;
+ $$.ifpos = addname(&fr, $2);
+ $$.lif = $4;
+ if (frc->fr_family == AF_UNSPEC)
+ frc->fr_family = AF_INET;
+ if (ifpflag == FRI_DYNAMIC) {
+ ntomask(frc->fr_family,
+ $8, $$.m.i6);
+ }
+ yyresetdict();
+ yyexpectaddr = 0;
+ }
+ ;
+
+maskspace:
+ '/'
+ | IPFY_MASK
+ ;
+
+ipmask: ipv4 { $$ = count4bits($1.s_addr); }
+ | YY_HEX { $$ = count4bits(htonl($1)); }
+ | YY_NUMBER { $$ = $1; }
+ | YY_IPV6 { $$ = count6bits($1.i6); }
+ | maskopts { $$ = $1; }
+ ;
+
+maskopts:
+ IPFY_BROADCAST { if (ifpflag == FRI_DYNAMIC) {
+ ifpflag = FRI_BROADCAST;
+ } else {
+ YYERROR;
+ }
+ $$ = 0;
+ }
+ | IPFY_NETWORK { if (ifpflag == FRI_DYNAMIC) {
+ ifpflag = FRI_NETWORK;
+ } else {
+ YYERROR;
+ }
+ $$ = 0;
+ }
+ | IPFY_NETMASKED { if (ifpflag == FRI_DYNAMIC) {
+ ifpflag = FRI_NETMASKED;
+ } else {
+ YYERROR;
+ }
+ $$ = 0;
+ }
+ | IPFY_PEER { if (ifpflag == FRI_DYNAMIC) {
+ ifpflag = FRI_PEERADDR;
+ } else {
+ YYERROR;
+ }
+ $$ = 0;
+ }
+ | YY_NUMBER { $$ = $1; }
+ ;
+
+hostname:
+ ipv4 { memset(&($$), 0, sizeof($$));
+ $$.adr.in4 = $1;
+ if (frc->fr_family == AF_INET6)
+ YYERROR;
+ $$.f = AF_INET;
+ yyexpectaddr = 2;
+ }
+ | YY_NUMBER { memset(&($$), 0, sizeof($$));
+ if (frc->fr_family == AF_INET6)
+ YYERROR;
+ $$.adr.in4_addr = $1;
+ $$.f = AF_INET;
+ yyexpectaddr = 2;
+ }
+ | YY_HEX { memset(&($$), 0, sizeof($$));
+ if (frc->fr_family == AF_INET6)
+ YYERROR;
+ $$.adr.in4_addr = $1;
+ $$.f = AF_INET;
+ yyexpectaddr = 2;
+ }
+ | YY_STR { memset(&($$), 0, sizeof($$));
+ if (lookuphost($1, &$$.adr) == 0)
+ $$.f = AF_INET;
+ free($1);
+ yyexpectaddr = 2;
+ }
+ | YY_IPV6 { memset(&($$), 0, sizeof($$));
+ if (frc->fr_family == AF_INET)
+ YYERROR;
+ $$.adr = $1;
+ $$.f = AF_INET6;
+ yyexpectaddr = 2;
+ }
+ ;
+
+addrlist:
+ ipaddr { $$ = newalist(NULL);
+ $$->al_family = $1.f;
+ $$->al_i6addr = $1.a;
+ $$->al_i6mask = $1.m;
+ }
+ | ipaddr ',' { yyexpectaddr = 1; } addrlist
+ { $$ = newalist($4);
+ $$->al_family = $1.f;
+ $$->al_i6addr = $1.a;
+ $$->al_i6mask = $1.m;
+ }
+ ;
+
+pool: IPFY_POOL { yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
+ ;
+
+hash: IPFY_HASH { yyexpectaddr = 0; yycont = NULL; yyresetdict(); }
+ ;
+
+poollist:
+ ipaddr { $$ = newalist(NULL);
+ $$->al_family = $1.f;
+ $$->al_i6addr = $1.a;
+ $$->al_i6mask = $1.m;
+ }
+ | '!' ipaddr { $$ = newalist(NULL);
+ $$->al_not = 1;
+ $$->al_family = $2.f;
+ $$->al_i6addr = $2.a;
+ $$->al_i6mask = $2.m;
+ }
+ | poollist ',' ipaddr
+ { $$ = newalist($1);
+ $$->al_family = $3.f;
+ $$->al_i6addr = $3.a;
+ $$->al_i6mask = $3.m;
+ }
+ | poollist ',' '!' ipaddr
+ { $$ = newalist($1);
+ $$->al_not = 1;
+ $$->al_family = $4.f;
+ $$->al_i6addr = $4.a;
+ $$->al_i6mask = $4.m;
+ }
+ ;
+
+port: IPFY_PORT { yyexpectaddr = 0;
+ yycont = NULL;
+ if (frc->fr_proto != 0 &&
+ frc->fr_proto != IPPROTO_UDP &&
+ frc->fr_proto != IPPROTO_TCP)
+ yyerror("port use incorrect");
+ }
+ ;
+
+portc: port compare { $$ = $2;
+ yysetdict(NULL);
+ }
+ | porteq { $$ = $1; }
+ ;
+
+porteq: port '=' { $$ = FR_EQUAL;
+ yysetdict(NULL);
+ }
+ ;
+
+portr: IPFY_PORT { yyexpectaddr = 0;
+ yycont = NULL;
+ yysetdict(NULL);
+ }
+ ;
+
+portcomp:
+ portc portnum { $$.pc = $1;
+ $$.p1 = $2;
+ yyresetdict();
+ }
+ ;
+
+portrange:
+ portr portnum range portnum { $$.p1 = $2;
+ $$.pc = $3;
+ $$.p2 = $4;
+ yyresetdict();
+ }
+ ;
+
+icmp: | itype icode
+ ;
+
+itype: seticmptype icmptype
+ { DOALL(fr->fr_icmp = htons($2 << 8); fr->fr_icmpm = htons(0xff00););
+ yyresetdict();
+ }
+ | seticmptype lstart typelist lend { yyresetdict(); }
+ ;
+
+seticmptype:
+ IPFY_ICMPTYPE { if (frc->fr_family == AF_UNSPEC)
+ frc->fr_family = AF_INET;
+ if (frc->fr_family == AF_INET &&
+ frc->fr_type == FR_T_IPF &&
+ frc->fr_proto != IPPROTO_ICMP) {
+ yyerror("proto not icmp");
+ }
+ if (frc->fr_family == AF_INET6 &&
+ frc->fr_type == FR_T_IPF &&
+ frc->fr_proto != IPPROTO_ICMPV6) {
+ yyerror("proto not ipv6-icmp");
+ }
+ setipftype();
+ DOALL(if (fr->fr_family == AF_INET) { \
+ fr->fr_ip.fi_v = 4; \
+ fr->fr_mip.fi_v = 0xf; \
+ }
+ if (fr->fr_family == AF_INET6) { \
+ fr->fr_ip.fi_v = 6; \
+ fr->fr_mip.fi_v = 0xf; \
+ }
+ )
+ yysetdict(NULL);
+ }
+ ;
+
+icode: | seticmpcode icmpcode
+ { DOALL(fr->fr_icmp |= htons($2); fr->fr_icmpm |= htons(0xff););
+ yyresetdict();
+ }
+ | seticmpcode lstart codelist lend { yyresetdict(); }
+ ;
+
+seticmpcode:
+ IPFY_ICMPCODE { yysetdict(icmpcodewords); }
+ ;
+
+typelist:
+ icmptype
+ { DOREM(fr->fr_icmp = htons($1 << 8); fr->fr_icmpm = htons(0xff00);) }
+ | typelist lmore icmptype
+ { DOREM(fr->fr_icmp = htons($3 << 8); fr->fr_icmpm = htons(0xff00);) }
+ ;
+
+codelist:
+ icmpcode
+ { DOREM(fr->fr_icmp |= htons($1); fr->fr_icmpm |= htons(0xff);) }
+ | codelist lmore icmpcode
+ { DOREM(fr->fr_icmp &= htons(0xff00); fr->fr_icmp |= htons($3); \
+ fr->fr_icmpm |= htons(0xff);) }
+ ;
+
+age: | IPFY_AGE YY_NUMBER { DOALL(fr->fr_age[0] = $2; \
+ fr->fr_age[1] = $2;) }
+ | IPFY_AGE YY_NUMBER '/' YY_NUMBER
+ { DOALL(fr->fr_age[0] = $2; \
+ fr->fr_age[1] = $4;) }
+ ;
+
+keep: | IPFY_KEEP keepstate keep
+ | IPFY_KEEP keepfrag keep
+ ;
+
+keepstate:
+ IPFY_STATE stateoptlist { DOALL(fr->fr_flags |= FR_KEEPSTATE;)}
+ ;
+
+keepfrag:
+ IPFY_FRAGS fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
+ | IPFY_FRAG fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) }
+ ;
+
+fragoptlist:
+ | '(' fragopts ')'
+ ;
+
+fragopts:
+ fragopt lanother fragopts
+ | fragopt
+ ;
+
+fragopt:
+ IPFY_STRICT { DOALL(fr->fr_flags |= FR_FRSTRICT;) }
+ ;
+
+stateoptlist:
+ | '(' stateopts ')'
+ ;
+
+stateopts:
+ stateopt lanother stateopts
+ | stateopt
+ ;
+
+stateopt:
+ IPFY_LIMIT YY_NUMBER { DOALL(fr->fr_statemax = $2;) }
+ | IPFY_STRICT { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
+ YYERROR; \
+ } else if (fr->fr_flags & FR_STLOOSE) {\
+ YYERROR; \
+ } else \
+ fr->fr_flags |= FR_STSTRICT;)
+ }
+ | IPFY_LOOSE { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
+ YYERROR; \
+ } else if (fr->fr_flags & FR_STSTRICT){\
+ YYERROR; \
+ } else \
+ fr->fr_flags |= FR_STLOOSE;)
+ }
+ | IPFY_NEWISN { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \
+ YYERROR; \
+ } else \
+ fr->fr_flags |= FR_NEWISN;)
+ }
+ | IPFY_NOICMPERR { DOALL(fr->fr_flags |= FR_NOICMPERR;) }
+
+ | IPFY_SYNC { DOALL(fr->fr_flags |= FR_STATESYNC;) }
+ | IPFY_AGE YY_NUMBER { DOALL(fr->fr_age[0] = $2; \
+ fr->fr_age[1] = $2;) }
+ | IPFY_AGE YY_NUMBER '/' YY_NUMBER
+ { DOALL(fr->fr_age[0] = $2; \
+ fr->fr_age[1] = $4;) }
+ | IPFY_ICMPHEAD groupname
+ { DOALL(seticmphead(&fr, $2);)
+ free($2);
+ }
+ | IPFY_NOLOG
+ { DOALL(fr->fr_nostatelog = 1;) }
+ | IPFY_RPC
+ { DOALL(fr->fr_rpc = 1;) }
+ | IPFY_RPC IPFY_IN YY_STR
+ { DOALL(fr->fr_rpc = 1;) }
+ | IPFY_MAX_SRCS YY_NUMBER
+ { DOALL(fr->fr_srctrack.ht_max_nodes = $2;) }
+ | IPFY_MAX_PER_SRC YY_NUMBER
+ { DOALL(fr->fr_srctrack.ht_max_per_node = $2; \
+ fr->fr_srctrack.ht_netmask = \
+ fr->fr_family == AF_INET ? 32: 128;)
+ }
+ | IPFY_MAX_PER_SRC YY_NUMBER '/' YY_NUMBER
+ { DOALL(fr->fr_srctrack.ht_max_per_node = $2; \
+ fr->fr_srctrack.ht_netmask = $4;)
+ }
+ ;
+
+portnum:
+ servicename { if (getport(frc, $1,
+ &($$), NULL) == -1)
+ yyerror("service unknown");
+ $$ = ntohs($$);
+ free($1);
+ }
+ | YY_NUMBER { if ($1 > 65535) /* Unsigned */
+ yyerror("invalid port number");
+ else
+ $$ = $1;
+ }
+ ;
+
+withlist:
+ withopt { nowith = 0; }
+ | withlist withopt { nowith = 0; }
+ | withlist ',' withopt { nowith = 0; }
+ ;
+
+withopt:
+ opttype { DOALL(fr->fr_flx |= $1; fr->fr_mflx |= $1;) }
+ | notwith opttype { DOALL(fr->fr_mflx |= $2;) }
+ | ipopt ipopts { yyresetdict(); }
+ | notwith ipopt ipopts { yyresetdict(); }
+ | startv6hdr ipv6hdrs { yyresetdict(); }
+ ;
+
+ipopt: IPFY_OPT { yysetdict(ipv4optwords); }
+ ;
+
+startv6hdr:
+ IPFY_V6HDR { if (frc->fr_family != AF_INET6)
+ yyerror("only available with IPv6");
+ yysetdict(ipv6optwords);
+ }
+ ;
+
+notwith:
+ IPFY_NOT { nowith = 1; }
+ | IPFY_NO { nowith = 1; }
+ ;
+
+opttype:
+ IPFY_IPOPTS { $$ = FI_OPTIONS; }
+ | IPFY_SHORT { $$ = FI_SHORT; }
+ | IPFY_NAT { $$ = FI_NATED; }
+ | IPFY_BAD { $$ = FI_BAD; }
+ | IPFY_BADNAT { $$ = FI_BADNAT; }
+ | IPFY_BADSRC { $$ = FI_BADSRC; }
+ | IPFY_LOWTTL { $$ = FI_LOWTTL; }
+ | IPFY_FRAG { $$ = FI_FRAG; }
+ | IPFY_FRAGBODY { $$ = FI_FRAGBODY; }
+ | IPFY_FRAGS { $$ = FI_FRAG; }
+ | IPFY_MBCAST { $$ = FI_MBCAST; }
+ | IPFY_MULTICAST { $$ = FI_MULTICAST; }
+ | IPFY_BROADCAST { $$ = FI_BROADCAST; }
+ | IPFY_STATE { $$ = FI_STATE; }
+ | IPFY_OOW { $$ = FI_OOW; }
+ | IPFY_AH { $$ = FI_AH; }
+ | IPFY_V6HDRS { $$ = FI_V6EXTHDR; }
+ ;
+
+ipopts: optlist { DOALL(fr->fr_mip.fi_optmsk |= $1;
+ if (fr->fr_family == AF_UNSPEC) {
+ fr->fr_family = AF_INET;
+ fr->fr_ip.fi_v = 4;
+ fr->fr_mip.fi_v = 0xf;
+ } else if (fr->fr_family != AF_INET) {
+ YYERROR;
+ }
+ if (!nowith)
+ fr->fr_ip.fi_optmsk |= $1;)
+ }
+ ;
+
+optlist:
+ opt { $$ |= $1; }
+ | optlist ',' opt { $$ |= $1 | $3; }
+ ;
+
+ipv6hdrs:
+ ipv6hdrlist { DOALL(fr->fr_mip.fi_optmsk |= $1;
+ if (!nowith)
+ fr->fr_ip.fi_optmsk |= $1;)
+ }
+ ;
+
+ipv6hdrlist:
+ ipv6hdr { $$ |= $1; }
+ | ipv6hdrlist ',' ipv6hdr { $$ |= $1 | $3; }
+ ;
+
+secname:
+ seclevel { $$ |= $1; }
+ | secname ',' seclevel { $$ |= $1 | $3; }
+ ;
+
+seclevel:
+ IPFY_SEC_UNC { $$ = secbit(IPSO_CLASS_UNCL); }
+ | IPFY_SEC_CONF { $$ = secbit(IPSO_CLASS_CONF); }
+ | IPFY_SEC_RSV1 { $$ = secbit(IPSO_CLASS_RES1); }
+ | IPFY_SEC_RSV2 { $$ = secbit(IPSO_CLASS_RES2); }
+ | IPFY_SEC_RSV3 { $$ = secbit(IPSO_CLASS_RES3); }
+ | IPFY_SEC_RSV4 { $$ = secbit(IPSO_CLASS_RES4); }
+ | IPFY_SEC_SEC { $$ = secbit(IPSO_CLASS_SECR); }
+ | IPFY_SEC_TS { $$ = secbit(IPSO_CLASS_TOPS); }
+ ;
+
+icmptype:
+ YY_NUMBER { $$ = $1; }
+ | YY_STR { $$ = geticmptype(frc->fr_family, $1);
+ if ($$ == -1)
+ yyerror("unrecognised icmp type");
+ }
+ ;
+
+icmpcode:
+ YY_NUMBER { $$ = $1; }
+ | IPFY_ICMPC_NETUNR { $$ = ICMP_UNREACH_NET; }
+ | IPFY_ICMPC_HSTUNR { $$ = ICMP_UNREACH_HOST; }
+ | IPFY_ICMPC_PROUNR { $$ = ICMP_UNREACH_PROTOCOL; }
+ | IPFY_ICMPC_PORUNR { $$ = ICMP_UNREACH_PORT; }
+ | IPFY_ICMPC_NEEDF { $$ = ICMP_UNREACH_NEEDFRAG; }
+ | IPFY_ICMPC_SRCFAIL { $$ = ICMP_UNREACH_SRCFAIL; }
+ | IPFY_ICMPC_NETUNK { $$ = ICMP_UNREACH_NET_UNKNOWN; }
+ | IPFY_ICMPC_HSTUNK { $$ = ICMP_UNREACH_HOST_UNKNOWN; }
+ | IPFY_ICMPC_ISOLATE { $$ = ICMP_UNREACH_ISOLATED; }
+ | IPFY_ICMPC_NETPRO { $$ = ICMP_UNREACH_NET_PROHIB; }
+ | IPFY_ICMPC_HSTPRO { $$ = ICMP_UNREACH_HOST_PROHIB; }
+ | IPFY_ICMPC_NETTOS { $$ = ICMP_UNREACH_TOSNET; }
+ | IPFY_ICMPC_HSTTOS { $$ = ICMP_UNREACH_TOSHOST; }
+ | IPFY_ICMPC_FLTPRO { $$ = ICMP_UNREACH_ADMIN_PROHIBIT; }
+ | IPFY_ICMPC_HSTPRE { $$ = 14; }
+ | IPFY_ICMPC_CUTPRE { $$ = 15; }
+ ;
+
+opt:
+ IPFY_IPOPT_NOP { $$ = getoptbyvalue(IPOPT_NOP); }
+ | IPFY_IPOPT_RR { $$ = getoptbyvalue(IPOPT_RR); }
+ | IPFY_IPOPT_ZSU { $$ = getoptbyvalue(IPOPT_ZSU); }
+ | IPFY_IPOPT_MTUP { $$ = getoptbyvalue(IPOPT_MTUP); }
+ | IPFY_IPOPT_MTUR { $$ = getoptbyvalue(IPOPT_MTUR); }
+ | IPFY_IPOPT_ENCODE { $$ = getoptbyvalue(IPOPT_ENCODE); }
+ | IPFY_IPOPT_TS { $$ = getoptbyvalue(IPOPT_TS); }
+ | IPFY_IPOPT_TR { $$ = getoptbyvalue(IPOPT_TR); }
+ | IPFY_IPOPT_SEC { $$ = getoptbyvalue(IPOPT_SECURITY); }
+ | IPFY_IPOPT_LSRR { $$ = getoptbyvalue(IPOPT_LSRR); }
+ | IPFY_IPOPT_ESEC { $$ = getoptbyvalue(IPOPT_E_SEC); }
+ | IPFY_IPOPT_CIPSO { $$ = getoptbyvalue(IPOPT_CIPSO); }
+ | IPFY_IPOPT_CIPSO doi { $$ = getoptbyvalue(IPOPT_CIPSO); }
+ | IPFY_IPOPT_SATID { $$ = getoptbyvalue(IPOPT_SATID); }
+ | IPFY_IPOPT_SSRR { $$ = getoptbyvalue(IPOPT_SSRR); }
+ | IPFY_IPOPT_ADDEXT { $$ = getoptbyvalue(IPOPT_ADDEXT); }
+ | IPFY_IPOPT_VISA { $$ = getoptbyvalue(IPOPT_VISA); }
+ | IPFY_IPOPT_IMITD { $$ = getoptbyvalue(IPOPT_IMITD); }
+ | IPFY_IPOPT_EIP { $$ = getoptbyvalue(IPOPT_EIP); }
+ | IPFY_IPOPT_FINN { $$ = getoptbyvalue(IPOPT_FINN); }
+ | IPFY_IPOPT_DPS { $$ = getoptbyvalue(IPOPT_DPS); }
+ | IPFY_IPOPT_SDB { $$ = getoptbyvalue(IPOPT_SDB); }
+ | IPFY_IPOPT_NSAPA { $$ = getoptbyvalue(IPOPT_NSAPA); }
+ | IPFY_IPOPT_RTRALRT { $$ = getoptbyvalue(IPOPT_RTRALRT); }
+ | IPFY_IPOPT_UMP { $$ = getoptbyvalue(IPOPT_UMP); }
+ | setsecclass secname
+ { DOALL(fr->fr_mip.fi_secmsk |= $2;
+ if (fr->fr_family == AF_UNSPEC) {
+ fr->fr_family = AF_INET;
+ fr->fr_ip.fi_v = 4;
+ fr->fr_mip.fi_v = 0xf;
+ } else if (fr->fr_family != AF_INET) {
+ YYERROR;
+ }
+ if (!nowith)
+ fr->fr_ip.fi_secmsk |= $2;)
+ $$ = 0;
+ yyresetdict();
+ }
+ ;
+
+setsecclass:
+ IPFY_SECCLASS { yysetdict(ipv4secwords); }
+ ;
+
+doi: IPFY_DOI YY_NUMBER { DOALL(fr->fr_doimask = 0xffffffff; \
+ if (!nowith) \
+ fr->fr_doi = $2;) }
+ | IPFY_DOI YY_HEX { DOALL(fr->fr_doimask = 0xffffffff; \
+ if (!nowith) \
+ fr->fr_doi = $2;) }
+ ;
+
+ipv6hdr:
+ IPFY_AH { $$ = getv6optbyvalue(IPPROTO_AH); }
+ | IPFY_IPV6OPT_DSTOPTS { $$ = getv6optbyvalue(IPPROTO_DSTOPTS); }
+ | IPFY_IPV6OPT_ESP { $$ = getv6optbyvalue(IPPROTO_ESP); }
+ | IPFY_IPV6OPT_HOPOPTS { $$ = getv6optbyvalue(IPPROTO_HOPOPTS); }
+ | IPFY_IPV6OPT_IPV6 { $$ = getv6optbyvalue(IPPROTO_IPV6); }
+ | IPFY_IPV6OPT_NONE { $$ = getv6optbyvalue(IPPROTO_NONE); }
+ | IPFY_IPV6OPT_ROUTING { $$ = getv6optbyvalue(IPPROTO_ROUTING); }
+ | IPFY_IPV6OPT_FRAG { $$ = getv6optbyvalue(IPPROTO_FRAGMENT); }
+ | IPFY_IPV6OPT_MOBILITY { $$ = getv6optbyvalue(IPPROTO_MOBILITY); }
+ ;
+
+level: IPFY_LEVEL { setsyslog(); }
+ ;
+
+loglevel:
+ priority { fr->fr_loglevel = LOG_LOCAL0|$1; }
+ | facility '.' priority { fr->fr_loglevel = $1 | $3; }
+ ;
+
+facility:
+ IPFY_FAC_KERN { $$ = LOG_KERN; }
+ | IPFY_FAC_USER { $$ = LOG_USER; }
+ | IPFY_FAC_MAIL { $$ = LOG_MAIL; }
+ | IPFY_FAC_DAEMON { $$ = LOG_DAEMON; }
+ | IPFY_FAC_AUTH { $$ = LOG_AUTH; }
+ | IPFY_FAC_SYSLOG { $$ = LOG_SYSLOG; }
+ | IPFY_FAC_LPR { $$ = LOG_LPR; }
+ | IPFY_FAC_NEWS { $$ = LOG_NEWS; }
+ | IPFY_FAC_UUCP { $$ = LOG_UUCP; }
+ | IPFY_FAC_CRON { $$ = LOG_CRON; }
+ | IPFY_FAC_FTP { $$ = LOG_FTP; }
+ | IPFY_FAC_AUTHPRIV { $$ = LOG_AUTHPRIV; }
+ | IPFY_FAC_AUDIT { $$ = LOG_AUDIT; }
+ | IPFY_FAC_LFMT { $$ = LOG_LFMT; }
+ | IPFY_FAC_LOCAL0 { $$ = LOG_LOCAL0; }
+ | IPFY_FAC_LOCAL1 { $$ = LOG_LOCAL1; }
+ | IPFY_FAC_LOCAL2 { $$ = LOG_LOCAL2; }
+ | IPFY_FAC_LOCAL3 { $$ = LOG_LOCAL3; }
+ | IPFY_FAC_LOCAL4 { $$ = LOG_LOCAL4; }
+ | IPFY_FAC_LOCAL5 { $$ = LOG_LOCAL5; }
+ | IPFY_FAC_LOCAL6 { $$ = LOG_LOCAL6; }
+ | IPFY_FAC_LOCAL7 { $$ = LOG_LOCAL7; }
+ | IPFY_FAC_SECURITY { $$ = LOG_SECURITY; }
+ ;
+
+priority:
+ IPFY_PRI_EMERG { $$ = LOG_EMERG; }
+ | IPFY_PRI_ALERT { $$ = LOG_ALERT; }
+ | IPFY_PRI_CRIT { $$ = LOG_CRIT; }
+ | IPFY_PRI_ERR { $$ = LOG_ERR; }
+ | IPFY_PRI_WARN { $$ = LOG_WARNING; }
+ | IPFY_PRI_NOTICE { $$ = LOG_NOTICE; }
+ | IPFY_PRI_INFO { $$ = LOG_INFO; }
+ | IPFY_PRI_DEBUG { $$ = LOG_DEBUG; }
+ ;
+
+compare:
+ YY_CMP_EQ { $$ = FR_EQUAL; }
+ | YY_CMP_NE { $$ = FR_NEQUAL; }
+ | YY_CMP_LT { $$ = FR_LESST; }
+ | YY_CMP_LE { $$ = FR_LESSTE; }
+ | YY_CMP_GT { $$ = FR_GREATERT; }
+ | YY_CMP_GE { $$ = FR_GREATERTE; }
+ ;
+
+range: YY_RANGE_IN { $$ = FR_INRANGE; }
+ | YY_RANGE_OUT { $$ = FR_OUTRANGE; }
+ | ':' { $$ = FR_INCRANGE; }
+ ;
+
+servicename:
+ YY_STR { $$ = $1; }
+ ;
+
+interfacename: name { $$ = $1; }
+ | name ':' YY_NUMBER
+ { $$ = $1;
+ fprintf(stderr, "%d: Logical interface %s:%d unsupported, "
+ "use the physical interface %s instead.\n",
+ yylineNum, $1, $3, $1);
+ }
+ ;
+
+name: YY_STR { $$ = $1; }
+ | '-' { $$ = strdup("-"); }
+ ;
+
+ipv4_16:
+ YY_NUMBER '.' YY_NUMBER
+ { if ($1 > 255 || $3 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ $$.s_addr = ($1 << 24) | ($3 << 16);
+ $$.s_addr = htonl($$.s_addr);
+ }
+ ;
+
+ipv4_24:
+ ipv4_16 '.' YY_NUMBER
+ { if ($3 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ $$.s_addr |= htonl($3 << 8);
+ }
+ ;
+
+ipv4: ipv4_24 '.' YY_NUMBER
+ { if ($3 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ $$.s_addr |= htonl($3);
+ }
+ | ipv4_24
+ | ipv4_16
+ ;
+
+%%
+
+
+static struct wordtab ipfwords[] = {
+ { "age", IPFY_AGE },
+ { "ah", IPFY_AH },
+ { "all", IPFY_ALL },
+ { "and", IPFY_AND },
+ { "auth", IPFY_AUTH },
+ { "bad", IPFY_BAD },
+ { "bad-nat", IPFY_BADNAT },
+ { "bad-src", IPFY_BADSRC },
+ { "bcast", IPFY_BROADCAST },
+ { "block", IPFY_BLOCK },
+ { "body", IPFY_BODY },
+ { "bpf-v4", IPFY_BPFV4 },
+#ifdef USE_INET6
+ { "bpf-v6", IPFY_BPFV6 },
+#endif
+ { "call", IPFY_CALL },
+ { "code", IPFY_ICMPCODE },
+ { "comment", IPFY_COMMENT },
+ { "count", IPFY_COUNT },
+ { "decapsulate", IPFY_DECAPS },
+ { "dstlist", IPFY_DSTLIST },
+ { "doi", IPFY_DOI },
+ { "dup-to", IPFY_DUPTO },
+ { "eq", YY_CMP_EQ },
+ { "esp", IPFY_ESP },
+ { "exp", IPFY_IPFEXPR },
+ { "family", IPFY_FAMILY },
+ { "fastroute", IPFY_FROUTE },
+ { "first", IPFY_FIRST },
+ { "flags", IPFY_FLAGS },
+ { "frag", IPFY_FRAG },
+ { "frag-body", IPFY_FRAGBODY },
+ { "frags", IPFY_FRAGS },
+ { "from", IPFY_FROM },
+ { "ge", YY_CMP_GE },
+ { "group", IPFY_GROUP },
+ { "gt", YY_CMP_GT },
+ { "head", IPFY_HEAD },
+ { "icmp", IPFY_ICMP },
+ { "icmp-head", IPFY_ICMPHEAD },
+ { "icmp-type", IPFY_ICMPTYPE },
+ { "in", IPFY_IN },
+ { "in-via", IPFY_INVIA },
+ { "inet", IPFY_INET },
+ { "inet6", IPFY_INET6 },
+ { "ipopt", IPFY_IPOPTS },
+ { "ipopts", IPFY_IPOPTS },
+ { "keep", IPFY_KEEP },
+ { "l5-as", IPFY_L5AS },
+ { "le", YY_CMP_LE },
+ { "level", IPFY_LEVEL },
+ { "limit", IPFY_LIMIT },
+ { "log", IPFY_LOG },
+ { "loose", IPFY_LOOSE },
+ { "lowttl", IPFY_LOWTTL },
+ { "lt", YY_CMP_LT },
+ { "mask", IPFY_MASK },
+ { "match-tag", IPFY_MATCHTAG },
+ { "max-per-src", IPFY_MAX_PER_SRC },
+ { "max-srcs", IPFY_MAX_SRCS },
+ { "mbcast", IPFY_MBCAST },
+ { "mcast", IPFY_MULTICAST },
+ { "multicast", IPFY_MULTICAST },
+ { "nat", IPFY_NAT },
+ { "ne", YY_CMP_NE },
+ { "net", IPFY_NETWORK },
+ { "newisn", IPFY_NEWISN },
+ { "no", IPFY_NO },
+ { "no-icmp-err", IPFY_NOICMPERR },
+ { "nolog", IPFY_NOLOG },
+ { "nomatch", IPFY_NOMATCH },
+ { "now", IPFY_NOW },
+ { "not", IPFY_NOT },
+ { "oow", IPFY_OOW },
+ { "on", IPFY_ON },
+ { "opt", IPFY_OPT },
+ { "or-block", IPFY_ORBLOCK },
+ { "out", IPFY_OUT },
+ { "out-via", IPFY_OUTVIA },
+ { "pass", IPFY_PASS },
+ { "port", IPFY_PORT },
+ { "pps", IPFY_PPS },
+ { "preauth", IPFY_PREAUTH },
+ { "proto", IPFY_PROTO },
+ { "quick", IPFY_QUICK },
+ { "reply-to", IPFY_REPLY_TO },
+ { "return-icmp", IPFY_RETICMP },
+ { "return-icmp-as-dest", IPFY_RETICMPASDST },
+ { "return-rst", IPFY_RETRST },
+ { "route-to", IPFY_ROUTETO },
+ { "rule-ttl", IPFY_RULETTL },
+ { "rpc", IPFY_RPC },
+ { "sec-class", IPFY_SECCLASS },
+ { "set", IPFY_SET },
+ { "set-tag", IPFY_SETTAG },
+ { "skip", IPFY_SKIP },
+ { "short", IPFY_SHORT },
+ { "state", IPFY_STATE },
+ { "state-age", IPFY_AGE },
+ { "strict", IPFY_STRICT },
+ { "sync", IPFY_SYNC },
+ { "tcp", IPFY_TCP },
+ { "tcp-udp", IPFY_TCPUDP },
+ { "tos", IPFY_TOS },
+ { "to", IPFY_TO },
+ { "ttl", IPFY_TTL },
+ { "udp", IPFY_UDP },
+ { "v6hdr", IPFY_V6HDR },
+ { "v6hdrs", IPFY_V6HDRS },
+ { "with", IPFY_WITH },
+ { NULL, 0 }
+};
+
+static struct wordtab addrwords[] = {
+ { "any", IPFY_ANY },
+ { "hash", IPFY_HASH },
+ { "pool", IPFY_POOL },
+ { NULL, 0 }
+};
+
+static struct wordtab maskwords[] = {
+ { "broadcast", IPFY_BROADCAST },
+ { "netmasked", IPFY_NETMASKED },
+ { "network", IPFY_NETWORK },
+ { "peer", IPFY_PEER },
+ { NULL, 0 }
+};
+
+static struct wordtab icmpcodewords[] = {
+ { "cutoff-preced", IPFY_ICMPC_CUTPRE },
+ { "filter-prohib", IPFY_ICMPC_FLTPRO },
+ { "isolate", IPFY_ICMPC_ISOLATE },
+ { "needfrag", IPFY_ICMPC_NEEDF },
+ { "net-prohib", IPFY_ICMPC_NETPRO },
+ { "net-tos", IPFY_ICMPC_NETTOS },
+ { "host-preced", IPFY_ICMPC_HSTPRE },
+ { "host-prohib", IPFY_ICMPC_HSTPRO },
+ { "host-tos", IPFY_ICMPC_HSTTOS },
+ { "host-unk", IPFY_ICMPC_HSTUNK },
+ { "host-unr", IPFY_ICMPC_HSTUNR },
+ { "net-unk", IPFY_ICMPC_NETUNK },
+ { "net-unr", IPFY_ICMPC_NETUNR },
+ { "port-unr", IPFY_ICMPC_PORUNR },
+ { "proto-unr", IPFY_ICMPC_PROUNR },
+ { "srcfail", IPFY_ICMPC_SRCFAIL },
+ { NULL, 0 },
+};
+
+static struct wordtab ipv4optwords[] = {
+ { "addext", IPFY_IPOPT_ADDEXT },
+ { "cipso", IPFY_IPOPT_CIPSO },
+ { "dps", IPFY_IPOPT_DPS },
+ { "e-sec", IPFY_IPOPT_ESEC },
+ { "eip", IPFY_IPOPT_EIP },
+ { "encode", IPFY_IPOPT_ENCODE },
+ { "finn", IPFY_IPOPT_FINN },
+ { "imitd", IPFY_IPOPT_IMITD },
+ { "lsrr", IPFY_IPOPT_LSRR },
+ { "mtup", IPFY_IPOPT_MTUP },
+ { "mtur", IPFY_IPOPT_MTUR },
+ { "nop", IPFY_IPOPT_NOP },
+ { "nsapa", IPFY_IPOPT_NSAPA },
+ { "rr", IPFY_IPOPT_RR },
+ { "rtralrt", IPFY_IPOPT_RTRALRT },
+ { "satid", IPFY_IPOPT_SATID },
+ { "sdb", IPFY_IPOPT_SDB },
+ { "sec", IPFY_IPOPT_SEC },
+ { "ssrr", IPFY_IPOPT_SSRR },
+ { "tr", IPFY_IPOPT_TR },
+ { "ts", IPFY_IPOPT_TS },
+ { "ump", IPFY_IPOPT_UMP },
+ { "visa", IPFY_IPOPT_VISA },
+ { "zsu", IPFY_IPOPT_ZSU },
+ { NULL, 0 },
+};
+
+static struct wordtab ipv4secwords[] = {
+ { "confid", IPFY_SEC_CONF },
+ { "reserv-1", IPFY_SEC_RSV1 },
+ { "reserv-2", IPFY_SEC_RSV2 },
+ { "reserv-3", IPFY_SEC_RSV3 },
+ { "reserv-4", IPFY_SEC_RSV4 },
+ { "secret", IPFY_SEC_SEC },
+ { "topsecret", IPFY_SEC_TS },
+ { "unclass", IPFY_SEC_UNC },
+ { NULL, 0 },
+};
+
+static struct wordtab ipv6optwords[] = {
+ { "dstopts", IPFY_IPV6OPT_DSTOPTS },
+ { "esp", IPFY_IPV6OPT_ESP },
+ { "frag", IPFY_IPV6OPT_FRAG },
+ { "hopopts", IPFY_IPV6OPT_HOPOPTS },
+ { "ipv6", IPFY_IPV6OPT_IPV6 },
+ { "mobility", IPFY_IPV6OPT_MOBILITY },
+ { "none", IPFY_IPV6OPT_NONE },
+ { "routing", IPFY_IPV6OPT_ROUTING },
+ { NULL, 0 },
+};
+
+static struct wordtab logwords[] = {
+ { "kern", IPFY_FAC_KERN },
+ { "user", IPFY_FAC_USER },
+ { "mail", IPFY_FAC_MAIL },
+ { "daemon", IPFY_FAC_DAEMON },
+ { "auth", IPFY_FAC_AUTH },
+ { "syslog", IPFY_FAC_SYSLOG },
+ { "lpr", IPFY_FAC_LPR },
+ { "news", IPFY_FAC_NEWS },
+ { "uucp", IPFY_FAC_UUCP },
+ { "cron", IPFY_FAC_CRON },
+ { "ftp", IPFY_FAC_FTP },
+ { "authpriv", IPFY_FAC_AUTHPRIV },
+ { "audit", IPFY_FAC_AUDIT },
+ { "logalert", IPFY_FAC_LFMT },
+ { "console", IPFY_FAC_CONSOLE },
+ { "security", IPFY_FAC_SECURITY },
+ { "local0", IPFY_FAC_LOCAL0 },
+ { "local1", IPFY_FAC_LOCAL1 },
+ { "local2", IPFY_FAC_LOCAL2 },
+ { "local3", IPFY_FAC_LOCAL3 },
+ { "local4", IPFY_FAC_LOCAL4 },
+ { "local5", IPFY_FAC_LOCAL5 },
+ { "local6", IPFY_FAC_LOCAL6 },
+ { "local7", IPFY_FAC_LOCAL7 },
+ { "emerg", IPFY_PRI_EMERG },
+ { "alert", IPFY_PRI_ALERT },
+ { "crit", IPFY_PRI_CRIT },
+ { "err", IPFY_PRI_ERR },
+ { "warn", IPFY_PRI_WARN },
+ { "notice", IPFY_PRI_NOTICE },
+ { "info", IPFY_PRI_INFO },
+ { "debug", IPFY_PRI_DEBUG },
+ { NULL, 0 },
+};
+
+
+
+
+int ipf_parsefile(fd, addfunc, iocfuncs, filename)
+int fd;
+addfunc_t addfunc;
+ioctlfunc_t *iocfuncs;
+char *filename;
+{
+ FILE *fp = NULL;
+ char *s;
+
+ yylineNum = 1;
+ yysettab(ipfwords);
+
+ s = getenv("YYDEBUG");
+ if (s != NULL)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ if (strcmp(filename, "-")) {
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "fopen(%s) failed: %s\n", filename,
+ STRERROR(errno));
+ return -1;
+ }
+ } else
+ fp = stdin;
+
+ while (ipf_parsesome(fd, addfunc, iocfuncs, fp) == 1)
+ ;
+ if (fp != NULL)
+ fclose(fp);
+ return 0;
+}
+
+
+int ipf_parsesome(fd, addfunc, iocfuncs, fp)
+int fd;
+addfunc_t addfunc;
+ioctlfunc_t *iocfuncs;
+FILE *fp;
+{
+ char *s;
+ int i;
+
+ ipffd = fd;
+ for (i = 0; i <= IPL_LOGMAX; i++)
+ ipfioctls[i] = iocfuncs[i];
+ ipfaddfunc = addfunc;
+
+ if (feof(fp))
+ return 0;
+ i = fgetc(fp);
+ if (i == EOF)
+ return 0;
+ if (ungetc(i, fp) == 0)
+ return 0;
+ if (feof(fp))
+ return 0;
+ s = getenv("YYDEBUG");
+ if (s != NULL)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ yyin = fp;
+ yyparse();
+ return 1;
+}
+
+
+static void newrule()
+{
+ frentry_t *frn;
+
+ frn = allocfr();
+ for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next)
+ ;
+ if (fr != NULL) {
+ fr->fr_next = frn;
+ frn->fr_pnext = &fr->fr_next;
+ }
+ if (frtop == NULL) {
+ frtop = frn;
+ frn->fr_pnext = &frtop;
+ }
+ fr = frn;
+ frc = frn;
+ fr->fr_loglevel = 0xffff;
+ fr->fr_isc = (void *)-1;
+ fr->fr_logtag = FR_NOLOGTAG;
+ fr->fr_type = FR_T_NONE;
+ fr->fr_flineno = yylineNum;
+
+ if (use_inet6 == 1)
+ fr->fr_family = AF_INET6;
+ else if (use_inet6 == -1)
+ fr->fr_family = AF_INET;
+
+ nrules = 1;
+}
+
+
+static void setipftype()
+{
+ for (fr = frc; fr != NULL; fr = fr->fr_next) {
+ if (fr->fr_type == FR_T_NONE) {
+ fr->fr_type = FR_T_IPF;
+ fr->fr_data = (void *)calloc(sizeof(fripf_t), 1);
+ fr->fr_dsize = sizeof(fripf_t);
+ fr->fr_family = frc->fr_family;
+ if (fr->fr_family == AF_INET) {
+ fr->fr_ip.fi_v = 4;
+ }
+ else if (fr->fr_family == AF_INET6) {
+ fr->fr_ip.fi_v = 6;
+ }
+ fr->fr_mip.fi_v = 0xf;
+ fr->fr_ipf->fri_sifpidx = -1;
+ fr->fr_ipf->fri_difpidx = -1;
+ }
+ if (fr->fr_type != FR_T_IPF) {
+ fprintf(stderr, "IPF Type not set\n");
+ }
+ }
+}
+
+
+static frentry_t *addrule()
+{
+ frentry_t *f, *f1, *f2;
+ int count;
+
+ for (f2 = frc; f2->fr_next != NULL; f2 = f2->fr_next)
+ ;
+
+ count = nrules;
+ f = f2;
+ for (f1 = frc; count > 0; count--, f1 = f1->fr_next) {
+ f->fr_next = allocfr();
+ if (f->fr_next == NULL)
+ return NULL;
+ f->fr_next->fr_pnext = &f->fr_next;
+ added++;
+ f = f->fr_next;
+ *f = *f1;
+ f->fr_next = NULL;
+ if (f->fr_caddr != NULL) {
+ f->fr_caddr = malloc(f->fr_dsize);
+ bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize);
+ }
+ }
+
+ return f2->fr_next;
+}
+
+
+static int
+lookuphost(name, addrp)
+ char *name;
+ i6addr_t *addrp;
+{
+ int i;
+
+ hashed = 0;
+ pooled = 0;
+ dynamic = -1;
+
+ for (i = 0; i < 4; i++) {
+ if (fr->fr_ifnames[i] == -1)
+ continue;
+ if (strcmp(name, fr->fr_names + fr->fr_ifnames[i]) == 0) {
+ ifpflag = FRI_DYNAMIC;
+ dynamic = addname(&fr, name);
+ return 1;
+ }
+ }
+
+ if (gethost(AF_INET, name, addrp) == -1) {
+ fprintf(stderr, "unknown name \"%s\"\n", name);
+ return -1;
+ }
+ return 0;
+}
+
+
+static void dobpf(v, phrase)
+int v;
+char *phrase;
+{
+#ifdef IPFILTER_BPF
+ struct bpf_program bpf;
+ struct pcap *p;
+#endif
+ fakebpf_t *fb;
+ u_32_t l;
+ char *s;
+ int i;
+
+ for (fr = frc; fr != NULL; fr = fr->fr_next) {
+ if (fr->fr_type != FR_T_NONE) {
+ fprintf(stderr, "cannot mix IPF and BPF matching\n");
+ return;
+ }
+ fr->fr_family = vtof(v);
+ fr->fr_type = FR_T_BPFOPC;
+
+ if (!strncmp(phrase, "0x", 2)) {
+ fb = malloc(sizeof(fakebpf_t));
+
+ for (i = 0, s = strtok(phrase, " \r\n\t"); s != NULL;
+ s = strtok(NULL, " \r\n\t"), i++) {
+ fb = realloc(fb, (i / 4 + 1) * sizeof(*fb));
+ l = (u_32_t)strtol(s, NULL, 0);
+ switch (i & 3)
+ {
+ case 0 :
+ fb[i / 4].fb_c = l & 0xffff;
+ break;
+ case 1 :
+ fb[i / 4].fb_t = l & 0xff;
+ break;
+ case 2 :
+ fb[i / 4].fb_f = l & 0xff;
+ break;
+ case 3 :
+ fb[i / 4].fb_k = l;
+ break;
+ }
+ }
+ if ((i & 3) != 0) {
+ fprintf(stderr,
+ "Odd number of bytes in BPF code\n");
+ exit(1);
+ }
+ i--;
+ fr->fr_dsize = (i / 4 + 1) * sizeof(*fb);
+ fr->fr_data = fb;
+ return;
+ }
+
+#ifdef IPFILTER_BPF
+ bzero((char *)&bpf, sizeof(bpf));
+ p = pcap_open_dead(DLT_RAW, 1);
+ if (!p) {
+ fprintf(stderr, "pcap_open_dead failed\n");
+ return;
+ }
+
+ if (pcap_compile(p, &bpf, phrase, 1, 0xffffffff)) {
+ pcap_perror(p, "ipf");
+ pcap_close(p);
+ fprintf(stderr, "pcap parsing failed (%s)\n", phrase);
+ return;
+ }
+ pcap_close(p);
+
+ fr->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn);
+ fr->fr_data = malloc(fr->fr_dsize);
+ bcopy((char *)bpf.bf_insns, fr->fr_data, fr->fr_dsize);
+ if (!bpf_validate(fr->fr_data, bpf.bf_len)) {
+ fprintf(stderr, "BPF validation failed\n");
+ return;
+ }
+#endif
+ }
+
+#ifdef IPFILTER_BPF
+ if (opts & OPT_DEBUG)
+ bpf_dump(&bpf, 0);
+#else
+ fprintf(stderr, "BPF filter expressions not supported\n");
+ exit(1);
+#endif
+}
+
+
+static void resetaddr()
+{
+ hashed = 0;
+ pooled = 0;
+ dynamic = -1;
+}
+
+
+static alist_t *newalist(ptr)
+alist_t *ptr;
+{
+ alist_t *al;
+
+ al = malloc(sizeof(*al));
+ if (al == NULL)
+ return NULL;
+ al->al_not = 0;
+ al->al_next = ptr;
+ return al;
+}
+
+
+static int
+makepool(list)
+ alist_t *list;
+{
+ ip_pool_node_t *n, *top;
+ ip_pool_t pool;
+ alist_t *a;
+ int num;
+
+ if (list == NULL)
+ return 0;
+ top = calloc(1, sizeof(*top));
+ if (top == NULL)
+ return 0;
+
+ for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
+ if (use_inet6 == 1) {
+#ifdef AF_INET6
+ n->ipn_addr.adf_family = AF_INET6;
+ n->ipn_addr.adf_addr = a->al_i6addr;
+ n->ipn_addr.adf_len = offsetof(addrfamily_t,
+ adf_addr) + 16;
+ n->ipn_mask.adf_family = AF_INET6;
+ n->ipn_mask.adf_addr = a->al_i6mask;
+ n->ipn_mask.adf_len = offsetof(addrfamily_t,
+ adf_addr) + 16;
+
+#endif
+ } else {
+ n->ipn_addr.adf_family = AF_INET;
+ n->ipn_addr.adf_addr.in4.s_addr = a->al_1;
+ n->ipn_addr.adf_len = offsetof(addrfamily_t,
+ adf_addr) + 4;
+ n->ipn_mask.adf_family = AF_INET;
+ n->ipn_mask.adf_addr.in4.s_addr = a->al_2;
+ n->ipn_mask.adf_len = offsetof(addrfamily_t,
+ adf_addr) + 4;
+ }
+ n->ipn_info = a->al_not;
+ if (a->al_next != NULL) {
+ n->ipn_next = calloc(1, sizeof(*n));
+ n = n->ipn_next;
+ }
+ }
+
+ bzero((char *)&pool, sizeof(pool));
+ pool.ipo_unit = IPL_LOGIPF;
+ pool.ipo_list = top;
+ num = load_pool(&pool, ipfioctls[IPL_LOGLOOKUP]);
+
+ while ((n = top) != NULL) {
+ top = n->ipn_next;
+ free(n);
+ }
+ return num;
+}
+
+
+static u_int makehash(list)
+alist_t *list;
+{
+ iphtent_t *n, *top;
+ iphtable_t iph;
+ alist_t *a;
+ int num;
+
+ if (list == NULL)
+ return 0;
+ top = calloc(1, sizeof(*top));
+ if (top == NULL)
+ return 0;
+
+ for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) {
+ if (a->al_family == AF_INET6) {
+ n->ipe_family = AF_INET6;
+ n->ipe_addr = a->al_i6addr;
+ n->ipe_mask = a->al_i6mask;
+ } else {
+ n->ipe_family = AF_INET;
+ n->ipe_addr.in4_addr = a->al_1;
+ n->ipe_mask.in4_addr = a->al_2;
+ }
+ n->ipe_value = 0;
+ if (a->al_next != NULL) {
+ n->ipe_next = calloc(1, sizeof(*n));
+ n = n->ipe_next;
+ }
+ }
+
+ bzero((char *)&iph, sizeof(iph));
+ iph.iph_unit = IPL_LOGIPF;
+ iph.iph_type = IPHASH_LOOKUP;
+ *iph.iph_name = '\0';
+
+ if (load_hash(&iph, top, ipfioctls[IPL_LOGLOOKUP]) == 0)
+ sscanf(iph.iph_name, "%u", &num);
+ else
+ num = 0;
+
+ while ((n = top) != NULL) {
+ top = n->ipe_next;
+ free(n);
+ }
+ return num;
+}
+
+
+int ipf_addrule(fd, ioctlfunc, ptr)
+int fd;
+ioctlfunc_t ioctlfunc;
+void *ptr;
+{
+ ioctlcmd_t add, del;
+ frentry_t *fr;
+ ipfobj_t obj;
+
+ if (ptr == NULL)
+ return 0;
+
+ fr = ptr;
+ add = 0;
+ del = 0;
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = fr->fr_size;
+ obj.ipfo_type = IPFOBJ_FRENTRY;
+ obj.ipfo_ptr = ptr;
+
+ if ((opts & OPT_DONOTHING) != 0)
+ fd = -1;
+
+ if (opts & OPT_ZERORULEST) {
+ add = SIOCZRLST;
+ } else if (opts & OPT_INACTIVE) {
+ add = (u_int)fr->fr_hits ? SIOCINIFR :
+ SIOCADIFR;
+ del = SIOCRMIFR;
+ } else {
+ add = (u_int)fr->fr_hits ? SIOCINAFR :
+ SIOCADAFR;
+ del = SIOCRMAFR;
+ }
+
+ if ((opts & OPT_OUTQUE) != 0)
+ fr->fr_flags |= FR_OUTQUE;
+ if (fr->fr_hits)
+ fr->fr_hits--;
+ if ((opts & OPT_VERBOSE) != 0)
+ printfr(fr, ioctlfunc);
+
+ if ((opts & OPT_DEBUG) != 0) {
+ binprint(fr, sizeof(*fr));
+ if (fr->fr_data != NULL)
+ binprint(fr->fr_data, fr->fr_dsize);
+ }
+
+ if ((opts & OPT_ZERORULEST) != 0) {
+ if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%d:ioctl(zero rule)",
+ fr->fr_flineno);
+ return ipf_perror_fd(fd, ioctlfunc, msg);
+ }
+ } else {
+#ifdef USE_QUAD_T
+ printf("hits %qd bytes %qd ",
+ (long long)fr->fr_hits,
+ (long long)fr->fr_bytes);
+#else
+ printf("hits %ld bytes %ld ",
+ fr->fr_hits, fr->fr_bytes);
+#endif
+ printfr(fr, ioctlfunc);
+ }
+ } else if ((opts & OPT_REMOVE) != 0) {
+ if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%d:ioctl(delete rule)",
+ fr->fr_flineno);
+ return ipf_perror_fd(fd, ioctlfunc, msg);
+ }
+ }
+ } else {
+ if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%d:ioctl(add/insert rule)",
+ fr->fr_flineno);
+ return ipf_perror_fd(fd, ioctlfunc, msg);
+ }
+ }
+ }
+ return 0;
+}
+
+static void setsyslog()
+{
+ yysetdict(logwords);
+ yybreakondot = 1;
+}
+
+
+static void unsetsyslog()
+{
+ yyresetdict();
+ yybreakondot = 0;
+}
+
+
+static void fillgroup(fr)
+frentry_t *fr;
+{
+ frentry_t *f;
+
+ for (f = frold; f != NULL; f = f->fr_next) {
+ if (f->fr_grhead == -1 && fr->fr_group == -1)
+ break;
+ if (f->fr_grhead == -1 || fr->fr_group == -1)
+ continue;
+ if (strcmp(f->fr_names + f->fr_grhead,
+ fr->fr_names + fr->fr_group) == 0)
+ break;
+ }
+
+ if (f == NULL)
+ return;
+
+ /*
+ * Only copy down matching fields if the rules are of the same type
+ * and are of ipf type. The only fields that are copied are those
+ * that impact the rule parsing itself, eg. need for knowing what the
+ * protocol should be for rules with port comparisons in them.
+ */
+ if (f->fr_type != fr->fr_type || f->fr_type != FR_T_IPF)
+ return;
+
+ if (fr->fr_family == 0 && f->fr_family != 0)
+ fr->fr_family = f->fr_family;
+
+ if (fr->fr_mproto == 0 && f->fr_mproto != 0)
+ fr->fr_mproto = f->fr_mproto;
+ if (fr->fr_proto == 0 && f->fr_proto != 0)
+ fr->fr_proto = f->fr_proto;
+
+ if ((fr->fr_mproto == 0) && ((fr->fr_flx & FI_TCPUDP) == 0) &&
+ ((f->fr_flx & FI_TCPUDP) != 0)) {
+ fr->fr_flx |= FI_TCPUDP;
+ fr->fr_mflx |= FI_TCPUDP;
+ }
+}
+
+
+static void doipfexpr(line)
+char *line;
+{
+ int *array;
+ char *error;
+
+ array = parseipfexpr(line, &error);
+ if (array == NULL) {
+ fprintf(stderr, "%s:", error);
+ yyerror("error parsing ipf matching expression");
+ return;
+ }
+
+ fr->fr_type = FR_T_IPFEXPR;
+ fr->fr_data = array;
+ fr->fr_dsize = array[0] * sizeof(*array);
+}
+
+
+static void do_tuneint(varname, value)
+char *varname;
+int value;
+{
+ char buffer[80];
+
+ strncpy(buffer, varname, 60);
+ buffer[59] = '\0';
+ strcat(buffer, "=");
+ sprintf(buffer, "%u", value);
+ ipf_dotuning(ipffd, buffer, ioctl);
+}
+
+
+static void do_tunestr(varname, value)
+char *varname, *value;
+{
+
+ if (!strcasecmp(value, "true")) {
+ do_tuneint(varname, 1);
+ } else if (!strcasecmp(value, "false")) {
+ do_tuneint(varname, 0);
+ } else {
+ yyerror("did not find true/false where expected");
+ }
+}
+
+
+static void setifname(frp, idx, name)
+frentry_t **frp;
+int idx;
+char *name;
+{
+ int pos;
+
+ pos = addname(frp, name);
+ if (pos == -1)
+ return;
+ (*frp)->fr_ifnames[idx] = pos;
+}
+
+
+static int addname(frp, name)
+frentry_t **frp;
+char *name;
+{
+ frentry_t *f;
+ int nlen;
+ int pos;
+
+ nlen = strlen(name) + 1;
+ f = realloc(*frp, (*frp)->fr_size + nlen);
+ if (*frp == frc)
+ frc = f;
+ *frp = f;
+ if (f == NULL)
+ return -1;
+ if (f->fr_pnext != NULL)
+ *f->fr_pnext = f;
+ f->fr_size += nlen;
+ pos = f->fr_namelen;
+ f->fr_namelen += nlen;
+ strcpy(f->fr_names + pos, name);
+ f->fr_names[f->fr_namelen] = '\0';
+ return pos;
+}
+
+
+static frentry_t *allocfr()
+{
+ frentry_t *fr;
+
+ fr = calloc(1, sizeof(*fr));
+ if (fr != NULL) {
+ fr->fr_size = sizeof(*fr);
+ fr->fr_comment = -1;
+ fr->fr_group = -1;
+ fr->fr_grhead = -1;
+ fr->fr_icmphead = -1;
+ fr->fr_ifnames[0] = -1;
+ fr->fr_ifnames[1] = -1;
+ fr->fr_ifnames[2] = -1;
+ fr->fr_ifnames[3] = -1;
+ fr->fr_tif.fd_name = -1;
+ fr->fr_rif.fd_name = -1;
+ fr->fr_dif.fd_name = -1;
+ }
+ return fr;
+}
+
+
+static void setgroup(frp, name)
+frentry_t **frp;
+char *name;
+{
+ int pos;
+
+ pos = addname(frp, name);
+ if (pos == -1)
+ return;
+ (*frp)->fr_group = pos;
+}
+
+
+static void setgrhead(frp, name)
+frentry_t **frp;
+char *name;
+{
+ int pos;
+
+ pos = addname(frp, name);
+ if (pos == -1)
+ return;
+ (*frp)->fr_grhead = pos;
+}
+
+
+static void seticmphead(frp, name)
+frentry_t **frp;
+char *name;
+{
+ int pos;
+
+ pos = addname(frp, name);
+ if (pos == -1)
+ return;
+ (*frp)->fr_icmphead = pos;
+}
+
+
+static void
+build_dstaddr_af(fp, ptr)
+ frentry_t *fp;
+ void *ptr;
+{
+ struct ipp_s *ipp = ptr;
+ frentry_t *f = fp;
+
+ if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) {
+ ipp->f = f->fr_family;
+ ipp->v = f->fr_ip.fi_v;
+ }
+ if (ipp->f == AF_INET)
+ ipp->v = 4;
+ else if (ipp->f == AF_INET6)
+ ipp->v = 6;
+
+ for (; f != NULL; f = f->fr_next) {
+ f->fr_ip.fi_dst = ipp->a;
+ f->fr_mip.fi_dst = ipp->m;
+ f->fr_family = ipp->f;
+ f->fr_ip.fi_v = ipp->v;
+ f->fr_mip.fi_v = 0xf;
+ f->fr_datype = ipp->type;
+ if (ipp->ifpos != -1)
+ f->fr_ipf->fri_difpidx = ipp->ifpos;
+ }
+ fr = NULL;
+}
+
+
+static void
+build_srcaddr_af(fp, ptr)
+ frentry_t *fp;
+ void *ptr;
+{
+ struct ipp_s *ipp = ptr;
+ frentry_t *f = fp;
+
+ if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) {
+ ipp->f = f->fr_family;
+ ipp->v = f->fr_ip.fi_v;
+ }
+ if (ipp->f == AF_INET)
+ ipp->v = 4;
+ else if (ipp->f == AF_INET6)
+ ipp->v = 6;
+
+ for (; f != NULL; f = f->fr_next) {
+ f->fr_ip.fi_src = ipp->a;
+ f->fr_mip.fi_src = ipp->m;
+ f->fr_family = ipp->f;
+ f->fr_ip.fi_v = ipp->v;
+ f->fr_mip.fi_v = 0xf;
+ f->fr_satype = ipp->type;
+ f->fr_ipf->fri_sifpidx = ipp->ifpos;
+ }
+ fr = NULL;
+}
diff --git a/contrib/ipfilter/tools/ipfcomp.c b/contrib/ipfilter/tools/ipfcomp.c
new file mode 100644
index 0000000..eba28ce
--- /dev/null
+++ b/contrib/ipfilter/tools/ipfcomp.c
@@ -0,0 +1,1374 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#include "ipf.h"
+
+
+typedef struct {
+ int c;
+ int e;
+ int n;
+ int p;
+ int s;
+} mc_t;
+
+
+static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" };
+static int count = 0;
+
+int intcmp __P((const void *, const void *));
+static void indent __P((FILE *, int));
+static void printeq __P((FILE *, char *, int, int, int));
+static void printipeq __P((FILE *, char *, int, int, int));
+static void addrule __P((FILE *, frentry_t *));
+static void printhooks __P((FILE *, int, int, frgroup_t *));
+static void emitheader __P((frgroup_t *, u_int, u_int));
+static void emitGroup __P((int, int, void *, frentry_t *, char *,
+ u_int, u_int));
+static void emittail __P((void));
+static void printCgroup __P((int, frentry_t *, mc_t *, char *));
+
+#define FRC_IFN 0
+#define FRC_V 1
+#define FRC_P 2
+#define FRC_FL 3
+#define FRC_TOS 4
+#define FRC_TTL 5
+#define FRC_SRC 6
+#define FRC_DST 7
+#define FRC_TCP 8
+#define FRC_SP 9
+#define FRC_DP 10
+#define FRC_OPT 11
+#define FRC_SEC 12
+#define FRC_ATH 13
+#define FRC_ICT 14
+#define FRC_ICC 15
+#define FRC_MAX 16
+
+
+static FILE *cfile = NULL;
+
+/*
+ * This is called once per filter rule being loaded to emit data structures
+ * required.
+ */
+void printc(fr)
+ frentry_t *fr;
+{
+ fripf_t *ipf;
+ u_long *ulp;
+ char *and;
+ FILE *fp;
+ int i;
+
+ if (fr->fr_family == 6)
+ return;
+ if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE))
+ return;
+ if ((fr->fr_type == FR_T_IPF) &&
+ ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL)))
+ return;
+ ipf = fr->fr_ipf;
+
+ if (cfile == NULL)
+ cfile = fopen("ip_rules.c", "w");
+ if (cfile == NULL)
+ return;
+ fp = cfile;
+ if (count == 0) {
+ fprintf(fp, "/*\n");
+ fprintf(fp, "* Copyright (C) 2012 by Darren Reed.\n");
+ fprintf(fp, "*\n");
+ fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n");
+ fprintf(fp, "* provided that this notice is preserved and due credit is given\n");
+ fprintf(fp, "* to the original author and the contributors.\n");
+ fprintf(fp, "*/\n\n");
+
+ fprintf(fp, "#include <sys/param.h>\n");
+ fprintf(fp, "#include <sys/types.h>\n");
+ fprintf(fp, "#include <sys/time.h>\n");
+ fprintf(fp, "#include <sys/socket.h>\n");
+ fprintf(fp, "#if (__FreeBSD_version >= 40000)\n");
+ fprintf(fp, "# if defined(_KERNEL)\n");
+ fprintf(fp, "# include <sys/libkern.h>\n");
+ fprintf(fp, "# else\n");
+ fprintf(fp, "# include <sys/unistd.h>\n");
+ fprintf(fp, "# endif\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "#if (__NetBSD_Version__ >= 399000000)\n");
+ fprintf(fp, "#else\n");
+ fprintf(fp, "# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n");
+ fprintf(fp, "# include <sys/systm.h>\n");
+ fprintf(fp, "# endif\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "#include <sys/errno.h>\n");
+ fprintf(fp, "#include <sys/param.h>\n");
+ fprintf(fp,
+"#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n");
+ fprintf(fp, "# include <sys/mbuf.h>\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp,
+"#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n");
+ fprintf(fp, "# include <sys/sockio.h>\n");
+ fprintf(fp, "#else\n");
+ fprintf(fp, "# include <sys/ioctl.h>\n");
+ fprintf(fp, "#endif /* FreeBSD */\n");
+ fprintf(fp, "#include <net/if.h>\n");
+ fprintf(fp, "#include <netinet/in.h>\n");
+ fprintf(fp, "#include <netinet/in_systm.h>\n");
+ fprintf(fp, "#include <netinet/ip.h>\n");
+ fprintf(fp, "#include <netinet/tcp.h>\n");
+ fprintf(fp, "#include \"netinet/ip_compat.h\"\n");
+ fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n");
+ fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n");
+ fprintf(fp, "#ifndef _KERNEL\n");
+ fprintf(fp, "# include <string.h>\n");
+ fprintf(fp, "#endif /* _KERNEL */\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#ifdef IPFILTER_COMPILED\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "extern ipf_main_softc_t ipfmain;\n");
+ fprintf(fp, "\n");
+ }
+
+ addrule(fp, fr);
+ fr->fr_type |= FR_T_BUILTIN;
+ and = "";
+ fr->fr_ref = 1;
+ i = sizeof(*fr);
+ if (i & -(1 - sizeof(*ulp)))
+ i += sizeof(u_long);
+ for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) {
+ fprintf(fp, "%s%#lx", and, *ulp++);
+ and = ", ";
+ }
+ fprintf(fp, "\n};\n");
+ fr->fr_type &= ~FR_T_BUILTIN;
+
+ count++;
+
+ fflush(fp);
+}
+
+
+static frgroup_t *groups = NULL;
+
+
+static void addrule(fp, fr)
+ FILE *fp;
+ frentry_t *fr;
+{
+ frentry_t *f, **fpp;
+ frgroup_t *g;
+ u_long *ulp;
+ char *ghead;
+ char *gname;
+ char *and;
+ int i;
+
+ f = (frentry_t *)malloc(sizeof(*f));
+ bcopy((char *)fr, (char *)f, sizeof(*fr));
+ if (fr->fr_ipf) {
+ f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf));
+ bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf,
+ sizeof(*fr->fr_ipf));
+ }
+
+ f->fr_next = NULL;
+ gname = FR_NAME(fr, fr_group);
+
+ for (g = groups; g != NULL; g = g->fg_next)
+ if ((strncmp(g->fg_name, gname, FR_GROUPLEN) == 0) &&
+ (g->fg_flags == (f->fr_flags & FR_INOUT)))
+ break;
+
+ if (g == NULL) {
+ g = (frgroup_t *)calloc(1, sizeof(*g));
+ g->fg_next = groups;
+ groups = g;
+ g->fg_head = f;
+ strncpy(g->fg_name, gname, FR_GROUPLEN);
+ g->fg_ref = 0;
+ g->fg_flags = f->fr_flags & FR_INOUT;
+ }
+
+ for (fpp = &g->fg_start; *fpp != NULL; )
+ fpp = &((*fpp)->fr_next);
+ *fpp = f;
+
+ if (fr->fr_dsize > 0) {
+ fprintf(fp, "\
+static u_long ipf%s_rule_data_%s_%u[] = {\n",
+ f->fr_flags & FR_INQUE ? "in" : "out",
+ g->fg_name, g->fg_ref);
+ and = "";
+ i = fr->fr_dsize;
+ ulp = fr->fr_data;
+ for (i /= sizeof(u_long); i > 0; i--) {
+ fprintf(fp, "%s%#lx", and, *ulp++);
+ and = ", ";
+ }
+ fprintf(fp, "\n};\n");
+ }
+
+ fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n",
+ f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref);
+
+ g->fg_ref++;
+
+ if (f->fr_grhead != -1) {
+ ghead = FR_NAME(f, fr_grhead);
+ for (g = groups; g != NULL; g = g->fg_next)
+ if ((strncmp(g->fg_name, ghead, FR_GROUPLEN) == 0) &&
+ g->fg_flags == (f->fr_flags & FR_INOUT))
+ break;
+ if (g == NULL) {
+ g = (frgroup_t *)calloc(1, sizeof(*g));
+ g->fg_next = groups;
+ groups = g;
+ g->fg_head = f;
+ strncpy(g->fg_name, ghead, FR_GROUPLEN);
+ g->fg_ref = 0;
+ g->fg_flags = f->fr_flags & FR_INOUT;
+ }
+ }
+}
+
+
+int intcmp(c1, c2)
+ const void *c1, *c2;
+{
+ const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2;
+
+ if (i1->n == i2->n) {
+ return i1->c - i2->c;
+ }
+ return i2->n - i1->n;
+}
+
+
+static void indent(fp, in)
+ FILE *fp;
+ int in;
+{
+ for (; in; in--)
+ fputc('\t', fp);
+}
+
+static void printeq(fp, var, m, max, v)
+ FILE *fp;
+ char *var;
+ int m, max, v;
+{
+ if (m == max)
+ fprintf(fp, "%s == %#x) {\n", var, v);
+ else
+ fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v);
+}
+
+/*
+ * Parameters: var - IP# being compared
+ * fl - 0 for positive match, 1 for negative match
+ * m - netmask
+ * v - required address
+ */
+static void printipeq(fp, var, fl, m, v)
+ FILE *fp;
+ char *var;
+ int fl, m, v;
+{
+ if (m == 0xffffffff)
+ fprintf(fp, "%s ", var);
+ else
+ fprintf(fp, "(%s & %#x) ", var, m);
+ fprintf(fp, "%c", fl ? '!' : '=');
+ fprintf(fp, "= %#x) {\n", v);
+}
+
+
+void emit(num, dir, v, fr)
+ int num, dir;
+ void *v;
+ frentry_t *fr;
+{
+ u_int incnt, outcnt;
+ frgroup_t *g;
+ frentry_t *f;
+
+ for (g = groups; g != NULL; g = g->fg_next) {
+ if (dir == 0 || dir == -1) {
+ if ((g->fg_flags & FR_INQUE) == 0)
+ continue;
+ for (incnt = 0, f = g->fg_start; f != NULL;
+ f = f->fr_next)
+ incnt++;
+ emitGroup(num, dir, v, fr, g->fg_name, incnt, 0);
+ }
+ if (dir == 1 || dir == -1) {
+ if ((g->fg_flags & FR_OUTQUE) == 0)
+ continue;
+ for (outcnt = 0, f = g->fg_start; f != NULL;
+ f = f->fr_next)
+ outcnt++;
+ emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt);
+ }
+ }
+
+ if (num == -1 && dir == -1) {
+ for (g = groups; g != NULL; g = g->fg_next) {
+ if ((g->fg_flags & FR_INQUE) != 0) {
+ for (incnt = 0, f = g->fg_start; f != NULL;
+ f = f->fr_next)
+ incnt++;
+ if (incnt > 0)
+ emitheader(g, incnt, 0);
+ }
+ if ((g->fg_flags & FR_OUTQUE) != 0) {
+ for (outcnt = 0, f = g->fg_start; f != NULL;
+ f = f->fr_next)
+ outcnt++;
+ if (outcnt > 0)
+ emitheader(g, 0, outcnt);
+ }
+ }
+ emittail();
+ fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n");
+ }
+
+}
+
+
+static void emitheader(grp, incount, outcount)
+ frgroup_t *grp;
+ u_int incount, outcount;
+{
+ static FILE *fph = NULL;
+ frgroup_t *g;
+
+ if (fph == NULL) {
+ fph = fopen("ip_rules.h", "w");
+ if (fph == NULL)
+ return;
+
+ fprintf(fph, "extern int ipfrule_add __P((void));\n");
+ fprintf(fph, "extern int ipfrule_remove __P((void));\n");
+ }
+
+ printhooks(cfile, incount, outcount, grp);
+
+ if (incount) {
+ fprintf(fph, "\n\
+extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\
+extern frentry_t *ipf_rules_in_%s[%d];\n",
+ grp->fg_name, grp->fg_name, incount);
+
+ for (g = groups; g != grp; g = g->fg_next)
+ if ((strncmp(g->fg_name, grp->fg_name,
+ FR_GROUPLEN) == 0) &&
+ g->fg_flags == grp->fg_flags)
+ break;
+ if (g == grp) {
+ fprintf(fph, "\n\
+extern int ipfrule_add_in_%s __P((void));\n\
+extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name);
+ }
+ }
+ if (outcount) {
+ fprintf(fph, "\n\
+extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\
+extern frentry_t *ipf_rules_out_%s[%d];\n",
+ grp->fg_name, grp->fg_name, outcount);
+
+ for (g = groups; g != grp; g = g->fg_next)
+ if ((strncmp(g->fg_name, grp->fg_name,
+ FR_GROUPLEN) == 0) &&
+ g->fg_flags == grp->fg_flags)
+ break;
+ if (g == grp) {
+ fprintf(fph, "\n\
+extern int ipfrule_add_out_%s __P((void));\n\
+extern int ipfrule_remove_out_%s __P((void));\n",
+ grp->fg_name, grp->fg_name);
+ }
+ }
+}
+
+static void emittail()
+{
+ frgroup_t *g;
+
+ fprintf(cfile, "\n\
+int ipfrule_add()\n\
+{\n\
+ int err;\n\
+\n");
+ for (g = groups; g != NULL; g = g->fg_next)
+ fprintf(cfile, "\
+ err = ipfrule_add_%s_%s();\n\
+ if (err != 0)\n\
+ return err;\n",
+ (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
+ fprintf(cfile, "\
+ return 0;\n");
+ fprintf(cfile, "}\n\
+\n");
+
+ fprintf(cfile, "\n\
+int ipfrule_remove()\n\
+{\n\
+ int err;\n\
+\n");
+ for (g = groups; g != NULL; g = g->fg_next)
+ fprintf(cfile, "\
+ err = ipfrule_remove_%s_%s();\n\
+ if (err != 0)\n\
+ return err;\n",
+ (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name);
+ fprintf(cfile, "\
+ return 0;\n");
+ fprintf(cfile, "}\n");
+}
+
+
+static void emitGroup(num, dir, v, fr, group, incount, outcount)
+ int num, dir;
+ void *v;
+ frentry_t *fr;
+ char *group;
+ u_int incount, outcount;
+{
+ static FILE *fp = NULL;
+ static int header[2] = { 0, 0 };
+ static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ static int openfunc = 0;
+ static mc_t *n = NULL;
+ static int sin = 0;
+ frentry_t *f;
+ frgroup_t *g;
+ fripf_t *ipf;
+ int i, in, j;
+ mc_t *m = v;
+
+ if (fp == NULL)
+ fp = cfile;
+ if (fp == NULL)
+ return;
+ if (strncmp(egroup, group, FR_GROUPLEN)) {
+ for (sin--; sin > 0; sin--) {
+ indent(fp, sin);
+ fprintf(fp, "}\n");
+ }
+ if (openfunc == 1) {
+ fprintf(fp, "\treturn fr;\n}\n");
+ openfunc = 0;
+ if (n != NULL) {
+ free(n);
+ n = NULL;
+ }
+ }
+ sin = 0;
+ header[0] = 0;
+ header[1] = 0;
+ strncpy(egroup, group, FR_GROUPLEN);
+ } else if (openfunc == 1 && num < 0) {
+ if (n != NULL) {
+ free(n);
+ n = NULL;
+ }
+ for (sin--; sin > 0; sin--) {
+ indent(fp, sin);
+ fprintf(fp, "}\n");
+ }
+ if (openfunc == 1) {
+ fprintf(fp, "\treturn fr;\n}\n");
+ openfunc = 0;
+ }
+ }
+
+ if (dir == -1)
+ return;
+
+ for (g = groups; g != NULL; g = g->fg_next) {
+ if (dir == 0 && (g->fg_flags & FR_INQUE) == 0)
+ continue;
+ else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0)
+ continue;
+ if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0)
+ continue;
+ break;
+ }
+
+ /*
+ * Output the array of pointers to rules for this group.
+ */
+ if (g != NULL && num == -2 && dir == 0 && header[0] == 0 &&
+ incount != 0) {
+ fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {",
+ group, incount);
+ for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
+ if ((f->fr_flags & FR_INQUE) == 0)
+ continue;
+ if ((i & 1) == 0) {
+ fprintf(fp, "\n\t");
+ }
+ fprintf(fp, "(frentry_t *)&in_rule_%s_%d",
+ FR_NAME(f, fr_group), i);
+ if (i + 1 < incount)
+ fprintf(fp, ", ");
+ i++;
+ }
+ fprintf(fp, "\n};\n");
+ }
+
+ if (g != NULL && num == -2 && dir == 1 && header[0] == 0 &&
+ outcount != 0) {
+ fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {",
+ group, outcount);
+ for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
+ if ((f->fr_flags & FR_OUTQUE) == 0)
+ continue;
+ if ((i & 1) == 0) {
+ fprintf(fp, "\n\t");
+ }
+ fprintf(fp, "(frentry_t *)&out_rule_%s_%d",
+ FR_NAME(f, fr_group), i);
+ if (i + 1 < outcount)
+ fprintf(fp, ", ");
+ i++;
+ }
+ fprintf(fp, "\n};\n");
+ fp = NULL;
+ }
+
+ if (num < 0)
+ return;
+
+ in = 0;
+ ipf = fr->fr_ipf;
+
+ /*
+ * If the function header has not been printed then print it now.
+ */
+ if (g != NULL && header[dir] == 0) {
+ int pdst = 0, psrc = 0;
+
+ openfunc = 1;
+ fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n",
+ (dir == 0) ? "in" : "out", group);
+ fprintf(fp, "fr_info_t *fin;\n");
+ fprintf(fp, "u_32_t *passp;\n");
+ fprintf(fp, "{\n");
+ fprintf(fp, "\tfrentry_t *fr = NULL;\n");
+
+ /*
+ * Print out any variables that need to be declared.
+ */
+ for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) {
+ if (incount + outcount > m[FRC_SRC].e + 1)
+ psrc = 1;
+ if (incount + outcount > m[FRC_DST].e + 1)
+ pdst = 1;
+ }
+ if (psrc == 1)
+ fprintf(fp, "\tu_32_t src = ntohl(%s);\n",
+ "fin->fin_fi.fi_saddr");
+ if (pdst == 1)
+ fprintf(fp, "\tu_32_t dst = ntohl(%s);\n",
+ "fin->fin_fi.fi_daddr");
+ }
+
+ for (i = 0; i < FRC_MAX; i++) {
+ switch(m[i].c)
+ {
+ case FRC_IFN :
+ if (fr->fr_ifnames[0] != -1)
+ m[i].s = 1;
+ break;
+ case FRC_V :
+ if (ipf != NULL && ipf->fri_mip.fi_v != 0)
+ m[i].s = 1;
+ break;
+ case FRC_FL :
+ if (ipf != NULL && ipf->fri_mip.fi_flx != 0)
+ m[i].s = 1;
+ break;
+ case FRC_P :
+ if (ipf != NULL && ipf->fri_mip.fi_p != 0)
+ m[i].s = 1;
+ break;
+ case FRC_TTL :
+ if (ipf != NULL && ipf->fri_mip.fi_ttl != 0)
+ m[i].s = 1;
+ break;
+ case FRC_TOS :
+ if (ipf != NULL && ipf->fri_mip.fi_tos != 0)
+ m[i].s = 1;
+ break;
+ case FRC_TCP :
+ if (ipf == NULL)
+ break;
+ if ((ipf->fri_ip.fi_p == IPPROTO_TCP) &&
+ fr->fr_tcpfm != 0)
+ m[i].s = 1;
+ break;
+ case FRC_SP :
+ if (ipf == NULL)
+ break;
+ if (fr->fr_scmp == FR_INRANGE)
+ m[i].s = 1;
+ else if (fr->fr_scmp == FR_OUTRANGE)
+ m[i].s = 1;
+ else if (fr->fr_scmp != 0)
+ m[i].s = 1;
+ break;
+ case FRC_DP :
+ if (ipf == NULL)
+ break;
+ if (fr->fr_dcmp == FR_INRANGE)
+ m[i].s = 1;
+ else if (fr->fr_dcmp == FR_OUTRANGE)
+ m[i].s = 1;
+ else if (fr->fr_dcmp != 0)
+ m[i].s = 1;
+ break;
+ case FRC_SRC :
+ if (ipf == NULL)
+ break;
+ if (fr->fr_satype == FRI_LOOKUP) {
+ ;
+ } else if ((fr->fr_smask != 0) ||
+ (fr->fr_flags & FR_NOTSRCIP) != 0)
+ m[i].s = 1;
+ break;
+ case FRC_DST :
+ if (ipf == NULL)
+ break;
+ if (fr->fr_datype == FRI_LOOKUP) {
+ ;
+ } else if ((fr->fr_dmask != 0) ||
+ (fr->fr_flags & FR_NOTDSTIP) != 0)
+ m[i].s = 1;
+ break;
+ case FRC_OPT :
+ if (ipf == NULL)
+ break;
+ if (fr->fr_optmask != 0)
+ m[i].s = 1;
+ break;
+ case FRC_SEC :
+ if (ipf == NULL)
+ break;
+ if (fr->fr_secmask != 0)
+ m[i].s = 1;
+ break;
+ case FRC_ATH :
+ if (ipf == NULL)
+ break;
+ if (fr->fr_authmask != 0)
+ m[i].s = 1;
+ break;
+ case FRC_ICT :
+ if (ipf == NULL)
+ break;
+ if ((fr->fr_icmpm & 0xff00) != 0)
+ m[i].s = 1;
+ break;
+ case FRC_ICC :
+ if (ipf == NULL)
+ break;
+ if ((fr->fr_icmpm & 0xff) != 0)
+ m[i].s = 1;
+ break;
+ }
+ }
+
+ if (!header[dir]) {
+ fprintf(fp, "\n");
+ header[dir] = 1;
+ sin = 0;
+ }
+
+ qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
+
+ if (n) {
+ /*
+ * Calculate the indentation interval upto the last common
+ * common comparison being made.
+ */
+ for (i = 0, in = 1; i < FRC_MAX; i++) {
+ if (n[i].c != m[i].c)
+ break;
+ if (n[i].s != m[i].s)
+ break;
+ if (n[i].s) {
+ if (n[i].n && (n[i].n > n[i].e)) {
+ m[i].p++;
+ in += m[i].p;
+ break;
+ }
+ if (n[i].e > 0) {
+ in++;
+ } else
+ break;
+ }
+ }
+ if (sin != in) {
+ for (j = sin - 1; j >= in; j--) {
+ indent(fp, j);
+ fprintf(fp, "}\n");
+ }
+ }
+ } else {
+ in = 1;
+ i = 0;
+ }
+
+ /*
+ * print out C code that implements a filter rule.
+ */
+ for (; i < FRC_MAX; i++) {
+ switch(m[i].c)
+ {
+ case FRC_IFN :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (fin->fin_ifp == ");
+ fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n",
+ dir ? "out" : "in", group, num);
+ in++;
+ }
+ break;
+ case FRC_V :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (fin->fin_v == %d) {\n",
+ ipf->fri_ip.fi_v);
+ in++;
+ }
+ break;
+ case FRC_FL :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_flx",
+ ipf->fri_mip.fi_flx, 0xf,
+ ipf->fri_ip.fi_flx);
+ in++;
+ }
+ break;
+ case FRC_P :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (fin->fin_p == %d) {\n",
+ ipf->fri_ip.fi_p);
+ in++;
+ }
+ break;
+ case FRC_TTL :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_ttl",
+ ipf->fri_mip.fi_ttl, 0xff,
+ ipf->fri_ip.fi_ttl);
+ in++;
+ }
+ break;
+ case FRC_TOS :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (fin->fin_tos");
+ printeq(fp, "fin->fin_tos",
+ ipf->fri_mip.fi_tos, 0xff,
+ ipf->fri_ip.fi_tos);
+ in++;
+ }
+ break;
+ case FRC_TCP :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm,
+ 0xff, fr->fr_tcpf);
+ in++;
+ }
+ break;
+ case FRC_SP :
+ if (!m[i].s)
+ break;
+ if (fr->fr_scmp == FR_INRANGE) {
+ indent(fp, in);
+ fprintf(fp, "if ((fin->fin_data[0] > %d) && ",
+ fr->fr_sport);
+ fprintf(fp, "(fin->fin_data[0] < %d)",
+ fr->fr_stop);
+ fprintf(fp, ") {\n");
+ in++;
+ } else if (fr->fr_scmp == FR_OUTRANGE) {
+ indent(fp, in);
+ fprintf(fp, "if ((fin->fin_data[0] < %d) || ",
+ fr->fr_sport);
+ fprintf(fp, "(fin->fin_data[0] > %d)",
+ fr->fr_stop);
+ fprintf(fp, ") {\n");
+ in++;
+ } else if (fr->fr_scmp) {
+ indent(fp, in);
+ fprintf(fp, "if (fin->fin_data[0] %s %d)",
+ portcmp[fr->fr_scmp], fr->fr_sport);
+ fprintf(fp, " {\n");
+ in++;
+ }
+ break;
+ case FRC_DP :
+ if (!m[i].s)
+ break;
+ if (fr->fr_dcmp == FR_INRANGE) {
+ indent(fp, in);
+ fprintf(fp, "if ((fin->fin_data[1] > %d) && ",
+ fr->fr_dport);
+ fprintf(fp, "(fin->fin_data[1] < %d)",
+ fr->fr_dtop);
+ fprintf(fp, ") {\n");
+ in++;
+ } else if (fr->fr_dcmp == FR_OUTRANGE) {
+ indent(fp, in);
+ fprintf(fp, "if ((fin->fin_data[1] < %d) || ",
+ fr->fr_dport);
+ fprintf(fp, "(fin->fin_data[1] > %d)",
+ fr->fr_dtop);
+ fprintf(fp, ") {\n");
+ in++;
+ } else if (fr->fr_dcmp) {
+ indent(fp, in);
+ fprintf(fp, "if (fin->fin_data[1] %s %d)",
+ portcmp[fr->fr_dcmp], fr->fr_dport);
+ fprintf(fp, " {\n");
+ in++;
+ }
+ break;
+ case FRC_SRC :
+ if (!m[i].s)
+ break;
+ if (fr->fr_satype == FRI_LOOKUP) {
+ ;
+ } else if ((fr->fr_smask != 0) ||
+ (fr->fr_flags & FR_NOTSRCIP) != 0) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printipeq(fp, "src",
+ fr->fr_flags & FR_NOTSRCIP,
+ fr->fr_smask, fr->fr_saddr);
+ in++;
+ }
+ break;
+ case FRC_DST :
+ if (!m[i].s)
+ break;
+ if (fr->fr_datype == FRI_LOOKUP) {
+ ;
+ } else if ((fr->fr_dmask != 0) ||
+ (fr->fr_flags & FR_NOTDSTIP) != 0) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printipeq(fp, "dst",
+ fr->fr_flags & FR_NOTDSTIP,
+ fr->fr_dmask, fr->fr_daddr);
+ in++;
+ }
+ break;
+ case FRC_OPT :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_fi.fi_optmsk",
+ fr->fr_optmask, 0xffffffff,
+ fr->fr_optbits);
+ in++;
+ }
+ break;
+ case FRC_SEC :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_fi.fi_secmsk",
+ fr->fr_secmask, 0xffff,
+ fr->fr_secbits);
+ in++;
+ }
+ break;
+ case FRC_ATH :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_fi.fi_authmsk",
+ fr->fr_authmask, 0xffff,
+ fr->fr_authbits);
+ in++;
+ }
+ break;
+ case FRC_ICT :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_data[0]",
+ fr->fr_icmpm & 0xff00, 0xffff,
+ fr->fr_icmp & 0xff00);
+ in++;
+ }
+ break;
+ case FRC_ICC :
+ if (m[i].s) {
+ indent(fp, in);
+ fprintf(fp, "if (");
+ printeq(fp, "fin->fin_data[0]",
+ fr->fr_icmpm & 0xff, 0xffff,
+ fr->fr_icmp & 0xff);
+ in++;
+ }
+ break;
+ }
+
+ }
+
+ indent(fp, in);
+ if (fr->fr_flags & FR_QUICK) {
+ fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n",
+ fr->fr_flags & FR_INQUE ? "in" : "out",
+ FR_NAME(fr, fr_group), num);
+ } else {
+ fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n",
+ fr->fr_flags & FR_INQUE ? "in" : "out",
+ FR_NAME(fr, fr_group), num);
+ }
+ if (n == NULL)
+ n = (mc_t *)malloc(sizeof(*n) * FRC_MAX);
+ bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX);
+ sin = in;
+}
+
+
+void printC(dir)
+ int dir;
+{
+ static mc_t *m = NULL;
+ frgroup_t *g;
+
+ if (m == NULL)
+ m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX);
+
+ for (g = groups; g != NULL; g = g->fg_next) {
+ if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0))
+ printCgroup(dir, g->fg_start, m, g->fg_name);
+ if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0))
+ printCgroup(dir, g->fg_start, m, g->fg_name);
+ }
+
+ emit(-1, dir, m, NULL);
+}
+
+
+/*
+ * Now print out code to implement all of the rules.
+ */
+static void printCgroup(dir, top, m, group)
+ int dir;
+ frentry_t *top;
+ mc_t *m;
+ char *group;
+{
+ frentry_t *fr, *fr1;
+ int i, n, rn;
+ u_int count;
+
+ for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) {
+ if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0))
+ count++;
+ else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0))
+ count++;
+ }
+
+ if (dir == 0)
+ emitGroup(-2, dir, m, fr1, group, count, 0);
+ else if (dir == 1)
+ emitGroup(-2, dir, m, fr1, group, 0, count);
+
+ /*
+ * Before printing each rule, check to see how many of its fields are
+ * matched by subsequent rules.
+ */
+ for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) {
+ if (!dir && !(fr1->fr_flags & FR_INQUE))
+ continue;
+ if (dir && !(fr1->fr_flags & FR_OUTQUE))
+ continue;
+ n = 0xfffffff;
+
+ for (i = 0; i < FRC_MAX; i++)
+ m[i].e = 0;
+ qsort(m, FRC_MAX, sizeof(mc_t), intcmp);
+
+ for (i = 0; i < FRC_MAX; i++) {
+ m[i].c = i;
+ m[i].e = 0;
+ m[i].n = 0;
+ m[i].s = 0;
+ }
+
+ for (fr = fr1->fr_next; fr; fr = fr->fr_next) {
+ if (!dir && !(fr->fr_flags & FR_INQUE))
+ continue;
+ if (dir && !(fr->fr_flags & FR_OUTQUE))
+ continue;
+
+ if ((n & 0x0001) &&
+ !strcmp(fr1->fr_names + fr1->fr_ifnames[0],
+ fr->fr_names + fr->fr_ifnames[0])) {
+ m[FRC_IFN].e++;
+ m[FRC_IFN].n++;
+ } else
+ n &= ~0x0001;
+
+ if ((n & 0x0002) && (fr1->fr_family == fr->fr_family)) {
+ m[FRC_V].e++;
+ m[FRC_V].n++;
+ } else
+ n &= ~0x0002;
+
+ if ((n & 0x0004) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) &&
+ (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) {
+ m[FRC_FL].e++;
+ m[FRC_FL].n++;
+ } else
+ n &= ~0x0004;
+
+ if ((n & 0x0008) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (fr1->fr_proto == fr->fr_proto)) {
+ m[FRC_P].e++;
+ m[FRC_P].n++;
+ } else
+ n &= ~0x0008;
+
+ if ((n & 0x0010) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (fr1->fr_ttl == fr->fr_ttl)) {
+ m[FRC_TTL].e++;
+ m[FRC_TTL].n++;
+ } else
+ n &= ~0x0010;
+
+ if ((n & 0x0020) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (fr1->fr_tos == fr->fr_tos)) {
+ m[FRC_TOS].e++;
+ m[FRC_TOS].n++;
+ } else
+ n &= ~0x0020;
+
+ if ((n & 0x0040) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ ((fr1->fr_tcpfm == fr->fr_tcpfm) &&
+ (fr1->fr_tcpf == fr->fr_tcpf))) {
+ m[FRC_TCP].e++;
+ m[FRC_TCP].n++;
+ } else
+ n &= ~0x0040;
+
+ if ((n & 0x0080) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ ((fr1->fr_scmp == fr->fr_scmp) &&
+ (fr1->fr_stop == fr->fr_stop) &&
+ (fr1->fr_sport == fr->fr_sport))) {
+ m[FRC_SP].e++;
+ m[FRC_SP].n++;
+ } else
+ n &= ~0x0080;
+
+ if ((n & 0x0100) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ ((fr1->fr_dcmp == fr->fr_dcmp) &&
+ (fr1->fr_dtop == fr->fr_dtop) &&
+ (fr1->fr_dport == fr->fr_dport))) {
+ m[FRC_DP].e++;
+ m[FRC_DP].n++;
+ } else
+ n &= ~0x0100;
+
+ if ((n & 0x0200) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ ((fr1->fr_satype == FRI_LOOKUP) &&
+ (fr->fr_satype == FRI_LOOKUP) &&
+ (fr1->fr_srcnum == fr->fr_srcnum))) {
+ m[FRC_SRC].e++;
+ m[FRC_SRC].n++;
+ } else if ((n & 0x0200) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (((fr1->fr_flags & FR_NOTSRCIP) ==
+ (fr->fr_flags & FR_NOTSRCIP)))) {
+ if ((fr1->fr_smask == fr->fr_smask) &&
+ (fr1->fr_saddr == fr->fr_saddr))
+ m[FRC_SRC].e++;
+ else
+ n &= ~0x0200;
+ if (fr1->fr_smask &&
+ (fr1->fr_saddr & fr1->fr_smask) ==
+ (fr->fr_saddr & fr1->fr_smask)) {
+ m[FRC_SRC].n++;
+ n |= 0x0200;
+ }
+ } else {
+ n &= ~0x0200;
+ }
+
+ if ((n & 0x0400) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ ((fr1->fr_datype == FRI_LOOKUP) &&
+ (fr->fr_datype == FRI_LOOKUP) &&
+ (fr1->fr_dstnum == fr->fr_dstnum))) {
+ m[FRC_DST].e++;
+ m[FRC_DST].n++;
+ } else if ((n & 0x0400) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (((fr1->fr_flags & FR_NOTDSTIP) ==
+ (fr->fr_flags & FR_NOTDSTIP)))) {
+ if ((fr1->fr_dmask == fr->fr_dmask) &&
+ (fr1->fr_daddr == fr->fr_daddr))
+ m[FRC_DST].e++;
+ else
+ n &= ~0x0400;
+ if (fr1->fr_dmask &&
+ (fr1->fr_daddr & fr1->fr_dmask) ==
+ (fr->fr_daddr & fr1->fr_dmask)) {
+ m[FRC_DST].n++;
+ n |= 0x0400;
+ }
+ } else {
+ n &= ~0x0400;
+ }
+
+ if ((n & 0x0800) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (fr1->fr_optmask == fr->fr_optmask) &&
+ (fr1->fr_optbits == fr->fr_optbits)) {
+ m[FRC_OPT].e++;
+ m[FRC_OPT].n++;
+ } else
+ n &= ~0x0800;
+
+ if ((n & 0x1000) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (fr1->fr_secmask == fr->fr_secmask) &&
+ (fr1->fr_secbits == fr->fr_secbits)) {
+ m[FRC_SEC].e++;
+ m[FRC_SEC].n++;
+ } else
+ n &= ~0x1000;
+
+ if ((n & 0x10000) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ (fr1->fr_authmask == fr->fr_authmask) &&
+ (fr1->fr_authbits == fr->fr_authbits)) {
+ m[FRC_ATH].e++;
+ m[FRC_ATH].n++;
+ } else
+ n &= ~0x10000;
+
+ if ((n & 0x20000) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ ((fr1->fr_icmpm & 0xff00) ==
+ (fr->fr_icmpm & 0xff00)) &&
+ ((fr1->fr_icmp & 0xff00) ==
+ (fr->fr_icmp & 0xff00))) {
+ m[FRC_ICT].e++;
+ m[FRC_ICT].n++;
+ } else
+ n &= ~0x20000;
+
+ if ((n & 0x40000) &&
+ (fr->fr_type == fr1->fr_type) &&
+ (fr->fr_type == FR_T_IPF) &&
+ ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) &&
+ ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) {
+ m[FRC_ICC].e++;
+ m[FRC_ICC].n++;
+ } else
+ n &= ~0x40000;
+ }
+ /*msort(m);*/
+
+ if (dir == 0)
+ emitGroup(rn, dir, m, fr1, group, count, 0);
+ else if (dir == 1)
+ emitGroup(rn, dir, m, fr1, group, 0, count);
+ }
+}
+
+static void printhooks(fp, in, out, grp)
+ FILE *fp;
+ int in;
+ int out;
+ frgroup_t *grp;
+{
+ frentry_t *fr;
+ char *group;
+ int dogrp, i;
+ char *instr;
+
+ group = grp->fg_name;
+ dogrp = 0;
+
+ if (in && out) {
+ fprintf(stderr,
+ "printhooks called with both in and out set\n");
+ exit(1);
+ }
+
+ if (in) {
+ instr = "in";
+ } else if (out) {
+ instr = "out";
+ } else {
+ instr = "???";
+ }
+ fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group);
+
+ fprintf(fp, "\
+\n\
+int ipfrule_add_%s_%s()\n", instr, group);
+ fprintf(fp, "\
+{\n\
+ int i, j, err = 0, max;\n\
+ frentry_t *fp;\n");
+
+ if (dogrp)
+ fprintf(fp, "\
+ frgroup_t *fg;\n");
+
+ fprintf(fp, "\n");
+
+ for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next)
+ if (fr->fr_dsize > 0) {
+ fprintf(fp, "\
+ ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n",
+ instr, grp->fg_name, i,
+ instr, grp->fg_name, i);
+ }
+ fprintf(fp, "\
+ max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\
+ for (i = 0; i < max; i++) {\n\
+ fp = ipf_rules_%s_%s[i];\n\
+ fp->fr_next = NULL;\n", instr, group, instr, group);
+
+ fprintf(fp, "\
+ for (j = i + 1; j < max; j++)\n\
+ if (strncmp(fp->fr_names + fp->fr_group,\n\
+ ipf_rules_%s_%s[j]->fr_names +\n\
+ ipf_rules_%s_%s[j]->fr_group,\n\
+ FR_GROUPLEN) == 0) {\n\
+ if (ipf_rules_%s_%s[j] != NULL)\n\
+ ipf_rules_%s_%s[j]->fr_pnext =\n\
+ &fp->fr_next;\n\
+ fp->fr_pnext = &ipf_rules_%s_%s[j];\n\
+ fp->fr_next = ipf_rules_%s_%s[j];\n\
+ break;\n\
+ }\n", instr, group, instr, group, instr, group,
+ instr, group, instr, group, instr, group);
+ if (dogrp)
+ fprintf(fp, "\
+\n\
+ if (fp->fr_grhead != -1) {\n\
+ fg = fr_addgroup(fp->fr_names + fp->fr_grhead,\n\
+ fp, FR_INQUE, IPL_LOGIPF, 0);\n\
+ if (fg != NULL)\n\
+ fp->fr_grp = &fg->fg_start;\n\
+ }\n");
+ fprintf(fp, "\
+ }\n\
+\n\
+ fp = &ipfrule_%s_%s;\n", instr, group);
+ fprintf(fp, "\
+ bzero((char *)fp, sizeof(*fp));\n\
+ fp->fr_type = FR_T_CALLFUNC_BUILTIN;\n\
+ fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\
+ fp->fr_data = (void *)ipf_rules_%s_%s[0];\n",
+ (in != 0) ? "IN" : "OUT", instr, group);
+ fprintf(fp, "\
+ fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n",
+ instr, group);
+
+ fprintf(fp, "\
+ fp->fr_family = AF_INET;\n\
+ fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\
+ err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,\n\
+ ipfmain.ipf_active, 0);\n",
+ instr, group);
+ fprintf(fp, "\treturn err;\n}\n");
+
+ fprintf(fp, "\n\n\
+int ipfrule_remove_%s_%s()\n", instr, group);
+ fprintf(fp, "\
+{\n\
+ int err = 0, i;\n\
+ frentry_t *fp;\n\
+\n\
+ /*\n\
+ * Try to remove the %sbound rule.\n", instr);
+
+ fprintf(fp, "\
+ */\n\
+ if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group);
+
+ fprintf(fp, "\
+ err = EBUSY;\n\
+ } else {\n");
+
+ fprintf(fp, "\
+ i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\
+ for (; i >= 0; i--) {\n\
+ fp = ipf_rules_%s_%s[i];\n\
+ if (fp->fr_ref > 1) {\n\
+ err = EBUSY;\n\
+ break;\n\
+ }\n\
+ }\n\
+ }\n\
+ if (err == 0)\n\
+ err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,\n\
+ (caddr_t)&ipfrule_%s_%s,\n\
+ ipfmain.ipf_active, 0);\n",
+ instr, group, instr, group, instr, group);
+ fprintf(fp, "\
+ if (err)\n\
+ return err;\n\
+\n\n");
+
+ fprintf(fp, "\treturn err;\n}\n");
+}
diff --git a/contrib/ipfilter/tools/ipfs.c b/contrib/ipfilter/tools/ipfs.c
new file mode 100644
index 0000000..43abd74
--- /dev/null
+++ b/contrib/ipfilter/tools/ipfs.c
@@ -0,0 +1,881 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#ifdef __FreeBSD__
+# ifndef __FreeBSD_cc_version
+# include <osreldate.h>
+# else
+# if __FreeBSD_cc_version < 430000
+# include <osreldate.h>
+# endif
+# endif
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <netinet/ip.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#ifndef IPF_SAVEDIR
+# define IPF_SAVEDIR "/var/db/ipf"
+#endif
+#ifndef IPF_NATFILE
+# define IPF_NATFILE "ipnat.ipf"
+#endif
+#ifndef IPF_STATEFILE
+# define IPF_STATEFILE "ipstate.ipf"
+#endif
+
+#if !defined(__SVR4) && defined(__GNUC__)
+extern char *index __P((const char *, int));
+#endif
+
+extern char *optarg;
+extern int optind;
+
+int main __P((int, char *[]));
+void usage __P((void));
+int changestateif __P((char *, char *));
+int changenatif __P((char *, char *));
+int readstate __P((int, char *));
+int readnat __P((int, char *));
+int writestate __P((int, char *));
+int opendevice __P((char *));
+void closedevice __P((int));
+int setlock __P((int, int));
+int writeall __P((char *));
+int readall __P((char *));
+int writenat __P((int, char *));
+
+int opts = 0;
+char *progname;
+
+
+void usage()
+{
+ fprintf(stderr, "usage: %s [-nv] -l\n", progname);
+ fprintf(stderr, "usage: %s [-nv] -u\n", progname);
+ fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname);
+ fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname);
+ fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname);
+ fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname);
+ fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n",
+ progname);
+ exit(1);
+}
+
+
+/*
+ * Change interface names in state information saved out to disk.
+ */
+int changestateif(ifs, fname)
+ char *ifs, *fname;
+{
+ int fd, olen, nlen, rw;
+ ipstate_save_t ips;
+ off_t pos;
+ char *s;
+
+ s = strchr(ifs, ',');
+ if (!s)
+ usage();
+ *s++ = '\0';
+ nlen = strlen(s);
+ olen = strlen(ifs);
+ if (nlen >= sizeof(ips.ips_is.is_ifname) ||
+ olen >= sizeof(ips.ips_is.is_ifname))
+ usage();
+
+ fd = open(fname, O_RDWR);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+
+ for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) {
+ rw = 0;
+ if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) {
+ strcpy(ips.ips_is.is_ifname[0], s);
+ rw = 1;
+ }
+ if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) {
+ strcpy(ips.ips_is.is_ifname[1], s);
+ rw = 1;
+ }
+ if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) {
+ strcpy(ips.ips_is.is_ifname[2], s);
+ rw = 1;
+ }
+ if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) {
+ strcpy(ips.ips_is.is_ifname[3], s);
+ rw = 1;
+ }
+ if (rw == 1) {
+ if (lseek(fd, pos, SEEK_SET) != pos) {
+ perror("lseek");
+ exit(1);
+ }
+ if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) {
+ perror("write");
+ exit(1);
+ }
+ }
+ pos = lseek(fd, 0, SEEK_CUR);
+ }
+ close(fd);
+
+ return 0;
+}
+
+
+/*
+ * Change interface names in NAT information saved out to disk.
+ */
+int changenatif(ifs, fname)
+ char *ifs, *fname;
+{
+ int fd, olen, nlen, rw;
+ nat_save_t ipn;
+ nat_t *nat;
+ off_t pos;
+ char *s;
+
+ s = strchr(ifs, ',');
+ if (!s)
+ usage();
+ *s++ = '\0';
+ nlen = strlen(s);
+ olen = strlen(ifs);
+ nat = &ipn.ipn_nat;
+ if (nlen >= sizeof(nat->nat_ifnames[0]) ||
+ olen >= sizeof(nat->nat_ifnames[0]))
+ usage();
+
+ fd = open(fname, O_RDWR);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+
+ for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) {
+ rw = 0;
+ if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) {
+ strcpy(nat->nat_ifnames[0], s);
+ rw = 1;
+ }
+ if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) {
+ strcpy(nat->nat_ifnames[1], s);
+ rw = 1;
+ }
+ if (rw == 1) {
+ if (lseek(fd, pos, SEEK_SET) != pos) {
+ perror("lseek");
+ exit(1);
+ }
+ if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) {
+ perror("write");
+ exit(1);
+ }
+ }
+ pos = lseek(fd, 0, SEEK_CUR);
+ }
+ close(fd);
+
+ return 0;
+}
+
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0;
+ char *dirname = NULL, *filename = NULL, *ifs = NULL;
+
+ progname = argv[0];
+ while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ if ((set == 0) && !dirname && !filename)
+ dirname = optarg;
+ else
+ usage();
+ break;
+ case 'f' :
+ if ((set != 0) && !dirname && !filename)
+ filename = optarg;
+ else
+ usage();
+ break;
+ case 'i' :
+ ifs = optarg;
+ set = 1;
+ break;
+ case 'l' :
+ if (filename || dirname || set)
+ usage();
+ lock = 1;
+ set = 1;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING;
+ break;
+ case 'N' :
+ if ((ns >= 0) || dirname || (rw != -1) || set)
+ usage();
+ ns = 0;
+ set = 1;
+ break;
+ case 'r' :
+ if (dirname || (rw != -1) || (ns == -1))
+ usage();
+ rw = 0;
+ set = 1;
+ break;
+ case 'R' :
+ rw = 2;
+ set = 1;
+ break;
+ case 'S' :
+ if ((ns >= 0) || dirname || (rw != -1) || set)
+ usage();
+ ns = 1;
+ set = 1;
+ break;
+ case 'u' :
+ if (filename || dirname || set)
+ usage();
+ lock = 0;
+ set = 1;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ case 'w' :
+ if (dirname || (rw != -1) || (ns == -1))
+ usage();
+ rw = 1;
+ set = 1;
+ break;
+ case 'W' :
+ rw = 3;
+ set = 1;
+ break;
+ case '?' :
+ default :
+ usage();
+ }
+
+ if (ifs) {
+ if (!filename || ns < 0)
+ usage();
+ if (ns == 0)
+ return changenatif(ifs, filename);
+ else
+ return changestateif(ifs, filename);
+ }
+
+ if ((ns >= 0) || (lock >= 0)) {
+ if (lock >= 0)
+ devfd = opendevice(NULL);
+ else if (ns >= 0) {
+ if (ns == 1)
+ devfd = opendevice(IPSTATE_NAME);
+ else if (ns == 0)
+ devfd = opendevice(IPNAT_NAME);
+ }
+ if (devfd == -1)
+ exit(1);
+ }
+
+ if (lock >= 0)
+ err = setlock(devfd, lock);
+ else if (rw >= 0) {
+ if (rw & 1) { /* WRITE */
+ if (rw & 2)
+ err = writeall(dirname);
+ else {
+ if (ns == 0)
+ err = writenat(devfd, filename);
+ else if (ns == 1)
+ err = writestate(devfd, filename);
+ }
+ } else {
+ if (rw & 2)
+ err = readall(dirname);
+ else {
+ if (ns == 0)
+ err = readnat(devfd, filename);
+ else if (ns == 1)
+ err = readstate(devfd, filename);
+ }
+ }
+ }
+ return err;
+}
+
+
+int opendevice(ipfdev)
+ char *ipfdev;
+{
+ int fd = -1;
+
+ if (opts & OPT_DONOTHING)
+ return -2;
+
+ if (!ipfdev)
+ ipfdev = IPL_NAME;
+
+ if ((fd = open(ipfdev, O_RDWR)) == -1)
+ if ((fd = open(ipfdev, O_RDONLY)) == -1)
+ perror("open device");
+ return fd;
+}
+
+
+void closedevice(fd)
+ int fd;
+{
+ close(fd);
+}
+
+
+int setlock(fd, lock)
+ int fd, lock;
+{
+ if (opts & OPT_VERBOSE)
+ printf("Turn lock %s\n", lock ? "on" : "off");
+ if (!(opts & OPT_DONOTHING)) {
+ if (ioctl(fd, SIOCSTLCK, &lock) == -1) {
+ perror("SIOCSTLCK");
+ return 1;
+ }
+ if (opts & OPT_VERBOSE)
+ printf("Lock now %s\n", lock ? "on" : "off");
+ }
+ return 0;
+}
+
+
+int writestate(fd, file)
+ int fd;
+ char *file;
+{
+ ipstate_save_t ips, *ipsp;
+ ipfobj_t obj;
+ int wfd = -1;
+
+ if (!file)
+ file = IPF_STATEFILE;
+
+ wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
+ if (wfd == -1) {
+ fprintf(stderr, "%s ", file);
+ perror("state:open");
+ return 1;
+ }
+
+ ipsp = &ips;
+ bzero((char *)&obj, sizeof(obj));
+ bzero((char *)ipsp, sizeof(ips));
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(*ipsp);
+ obj.ipfo_type = IPFOBJ_STATESAVE;
+ obj.ipfo_ptr = ipsp;
+
+ do {
+
+ if (opts & OPT_VERBOSE)
+ printf("Getting state from addr %p\n", ips.ips_next);
+ if (ioctl(fd, SIOCSTGET, &obj)) {
+ if (errno == ENOENT)
+ break;
+ perror("state:SIOCSTGET");
+ close(wfd);
+ return 1;
+ }
+ if (opts & OPT_VERBOSE)
+ printf("Got state next %p\n", ips.ips_next);
+ if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) {
+ perror("state:write");
+ close(wfd);
+ return 1;
+ }
+ } while (ips.ips_next != NULL);
+ close(wfd);
+
+ return 0;
+}
+
+
+int readstate(fd, file)
+ int fd;
+ char *file;
+{
+ ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL;
+ int sfd = -1, i;
+ ipfobj_t obj;
+
+ if (!file)
+ file = IPF_STATEFILE;
+
+ sfd = open(file, O_RDONLY, 0600);
+ if (sfd == -1) {
+ fprintf(stderr, "%s ", file);
+ perror("open");
+ return 1;
+ }
+
+ bzero((char *)&ips, sizeof(ips));
+
+ /*
+ * 1. Read all state information in.
+ */
+ do {
+ i = read(sfd, &ips, sizeof(ips));
+ if (i == -1) {
+ perror("read");
+ goto freeipshead;
+ }
+ if (i == 0)
+ break;
+ if (i != sizeof(ips)) {
+ fprintf(stderr, "state:incomplete read: %d != %d\n",
+ i, (int)sizeof(ips));
+ goto freeipshead;
+ }
+ is = (ipstate_save_t *)malloc(sizeof(*is));
+ if (is == NULL) {
+ fprintf(stderr, "malloc failed\n");
+ goto freeipshead;
+ }
+
+ bcopy((char *)&ips, (char *)is, sizeof(ips));
+
+ /*
+ * Check to see if this is the first state entry that will
+ * reference a particular rule and if so, flag it as such
+ * else just adjust the rule pointer to become a pointer to
+ * the other. We do this so we have a means later for tracking
+ * who is referencing us when we get back the real pointer
+ * in is_rule after doing the ioctl.
+ */
+ for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next)
+ if (is1->ips_rule == is->ips_rule)
+ break;
+ if (is1 == NULL)
+ is->ips_is.is_flags |= SI_NEWFR;
+ else
+ is->ips_rule = (void *)&is1->ips_rule;
+
+ /*
+ * Use a tail-queue type list (add things to the end)..
+ */
+ is->ips_next = NULL;
+ if (!ipshead)
+ ipshead = is;
+ if (ipstail)
+ ipstail->ips_next = is;
+ ipstail = is;
+ } while (1);
+
+ close(sfd);
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(*is);
+ obj.ipfo_type = IPFOBJ_STATESAVE;
+
+ while ((is = ipshead) != NULL) {
+ if (opts & OPT_VERBOSE)
+ printf("Loading new state table entry\n");
+ if (is->ips_is.is_flags & SI_NEWFR) {
+ if (opts & OPT_VERBOSE)
+ printf("Loading new filter rule\n");
+ }
+
+ obj.ipfo_ptr = is;
+ if (!(opts & OPT_DONOTHING))
+ if (ioctl(fd, SIOCSTPUT, &obj)) {
+ perror("SIOCSTPUT");
+ goto freeipshead;
+ }
+
+ if (is->ips_is.is_flags & SI_NEWFR) {
+ if (opts & OPT_VERBOSE)
+ printf("Real rule addr %p\n", is->ips_rule);
+ for (is1 = is->ips_next; is1; is1 = is1->ips_next)
+ if (is1->ips_rule == (frentry_t *)&is->ips_rule)
+ is1->ips_rule = is->ips_rule;
+ }
+
+ ipshead = is->ips_next;
+ free(is);
+ }
+
+ return 0;
+
+freeipshead:
+ while ((is = ipshead) != NULL) {
+ ipshead = is->ips_next;
+ free(is);
+ }
+ if (sfd != -1)
+ close(sfd);
+ return 1;
+}
+
+
+int readnat(fd, file)
+ int fd;
+ char *file;
+{
+ nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL;
+ ipfobj_t obj;
+ int nfd, i;
+ nat_t *nat;
+ char *s;
+ int n;
+
+ nfd = -1;
+ in = NULL;
+ ipnhead = NULL;
+ ipntail = NULL;
+
+ if (!file)
+ file = IPF_NATFILE;
+
+ nfd = open(file, O_RDONLY);
+ if (nfd == -1) {
+ fprintf(stderr, "%s ", file);
+ perror("nat:open");
+ return 1;
+ }
+
+ bzero((char *)&ipn, sizeof(ipn));
+
+ /*
+ * 1. Read all state information in.
+ */
+ do {
+ i = read(nfd, &ipn, sizeof(ipn));
+ if (i == -1) {
+ perror("read");
+ goto freenathead;
+ }
+ if (i == 0)
+ break;
+ if (i != sizeof(ipn)) {
+ fprintf(stderr, "nat:incomplete read: %d != %d\n",
+ i, (int)sizeof(ipn));
+ goto freenathead;
+ }
+
+ in = (nat_save_t *)malloc(ipn.ipn_dsize);
+ if (in == NULL) {
+ fprintf(stderr, "nat:cannot malloc nat save atruct\n");
+ goto freenathead;
+ }
+
+ if (ipn.ipn_dsize > sizeof(ipn)) {
+ n = ipn.ipn_dsize - sizeof(ipn);
+ if (n > 0) {
+ s = in->ipn_data + sizeof(in->ipn_data);
+ i = read(nfd, s, n);
+ if (i == 0)
+ break;
+ if (i != n) {
+ fprintf(stderr,
+ "nat:incomplete read: %d != %d\n",
+ i, n);
+ goto freenathead;
+ }
+ }
+ }
+ bcopy((char *)&ipn, (char *)in, sizeof(ipn));
+
+ /*
+ * Check to see if this is the first NAT entry that will
+ * reference a particular rule and if so, flag it as such
+ * else just adjust the rule pointer to become a pointer to
+ * the other. We do this so we have a means later for tracking
+ * who is referencing us when we get back the real pointer
+ * in is_rule after doing the ioctl.
+ */
+ nat = &in->ipn_nat;
+ if (nat->nat_fr != NULL) {
+ for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next)
+ if (in1->ipn_rule == nat->nat_fr)
+ break;
+ if (in1 == NULL)
+ nat->nat_flags |= SI_NEWFR;
+ else
+ nat->nat_fr = &in1->ipn_fr;
+ }
+
+ /*
+ * Use a tail-queue type list (add things to the end)..
+ */
+ in->ipn_next = NULL;
+ if (!ipnhead)
+ ipnhead = in;
+ if (ipntail)
+ ipntail->ipn_next = in;
+ ipntail = in;
+ } while (1);
+
+ close(nfd);
+ nfd = -1;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_NATSAVE;
+
+ while ((in = ipnhead) != NULL) {
+ if (opts & OPT_VERBOSE)
+ printf("Loading new NAT table entry\n");
+ nat = &in->ipn_nat;
+ if (nat->nat_flags & SI_NEWFR) {
+ if (opts & OPT_VERBOSE)
+ printf("Loading new filter rule\n");
+ }
+
+ obj.ipfo_ptr = in;
+ obj.ipfo_size = in->ipn_dsize;
+ if (!(opts & OPT_DONOTHING))
+ if (ioctl(fd, SIOCSTPUT, &obj)) {
+ fprintf(stderr, "in=%p:", in);
+ perror("SIOCSTPUT");
+ return 1;
+ }
+
+ if (nat->nat_flags & SI_NEWFR) {
+ if (opts & OPT_VERBOSE)
+ printf("Real rule addr %p\n", nat->nat_fr);
+ for (in1 = in->ipn_next; in1; in1 = in1->ipn_next)
+ if (in1->ipn_rule == &in->ipn_fr)
+ in1->ipn_rule = nat->nat_fr;
+ }
+
+ ipnhead = in->ipn_next;
+ free(in);
+ }
+
+ return 0;
+
+freenathead:
+ while ((in = ipnhead) != NULL) {
+ ipnhead = in->ipn_next;
+ free(in);
+ }
+ if (nfd != -1)
+ close(nfd);
+ return 1;
+}
+
+
+int writenat(fd, file)
+ int fd;
+ char *file;
+{
+ nat_save_t *ipnp = NULL, *next = NULL;
+ ipfobj_t obj;
+ int nfd = -1;
+ natget_t ng;
+
+ if (!file)
+ file = IPF_NATFILE;
+
+ nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
+ if (nfd == -1) {
+ fprintf(stderr, "%s ", file);
+ perror("nat:open");
+ return 1;
+ }
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_NATSAVE;
+
+ do {
+ if (opts & OPT_VERBOSE)
+ printf("Getting nat from addr %p\n", ipnp);
+ ng.ng_ptr = next;
+ ng.ng_sz = 0;
+ if (ioctl(fd, SIOCSTGSZ, &ng)) {
+ perror("nat:SIOCSTGSZ");
+ close(nfd);
+ if (ipnp != NULL)
+ free(ipnp);
+ return 1;
+ }
+
+ if (opts & OPT_VERBOSE)
+ printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr);
+
+ if (ng.ng_sz == 0)
+ break;
+
+ if (!ipnp)
+ ipnp = malloc(ng.ng_sz);
+ else
+ ipnp = realloc((char *)ipnp, ng.ng_sz);
+ if (!ipnp) {
+ fprintf(stderr,
+ "malloc for %d bytes failed\n", ng.ng_sz);
+ break;
+ }
+
+ bzero((char *)ipnp, ng.ng_sz);
+ obj.ipfo_size = ng.ng_sz;
+ obj.ipfo_ptr = ipnp;
+ ipnp->ipn_dsize = ng.ng_sz;
+ ipnp->ipn_next = next;
+ if (ioctl(fd, SIOCSTGET, &obj)) {
+ if (errno == ENOENT)
+ break;
+ perror("nat:SIOCSTGET");
+ close(nfd);
+ free(ipnp);
+ return 1;
+ }
+
+ if (opts & OPT_VERBOSE)
+ printf("Got nat next %p ipn_dsize %d ng_sz %d\n",
+ ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz);
+ if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) {
+ perror("nat:write");
+ close(nfd);
+ free(ipnp);
+ return 1;
+ }
+ next = ipnp->ipn_next;
+ } while (ipnp && next);
+ if (ipnp != NULL)
+ free(ipnp);
+ close(nfd);
+
+ return 0;
+}
+
+
+int writeall(dirname)
+ char *dirname;
+{
+ int fd, devfd;
+
+ if (!dirname)
+ dirname = IPF_SAVEDIR;
+
+ if (chdir(dirname)) {
+ fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname);
+ perror("chdir(IPF_SAVEDIR)");
+ return 1;
+ }
+
+ fd = opendevice(NULL);
+ if (fd == -1)
+ return 1;
+ if (setlock(fd, 1)) {
+ close(fd);
+ return 1;
+ }
+
+ devfd = opendevice(IPSTATE_NAME);
+ if (devfd == -1)
+ goto bad;
+ if (writestate(devfd, NULL))
+ goto bad;
+ close(devfd);
+
+ devfd = opendevice(IPNAT_NAME);
+ if (devfd == -1)
+ goto bad;
+ if (writenat(devfd, NULL))
+ goto bad;
+ close(devfd);
+
+ if (setlock(fd, 0)) {
+ close(fd);
+ return 1;
+ }
+
+ close(fd);
+ return 0;
+
+bad:
+ setlock(fd, 0);
+ close(fd);
+ return 1;
+}
+
+
+int readall(dirname)
+ char *dirname;
+{
+ int fd, devfd;
+
+ if (!dirname)
+ dirname = IPF_SAVEDIR;
+
+ if (chdir(dirname)) {
+ perror("chdir(IPF_SAVEDIR)");
+ return 1;
+ }
+
+ fd = opendevice(NULL);
+ if (fd == -1)
+ return 1;
+ if (setlock(fd, 1)) {
+ close(fd);
+ return 1;
+ }
+
+ devfd = opendevice(IPSTATE_NAME);
+ if (devfd == -1)
+ return 1;
+ if (readstate(devfd, NULL))
+ return 1;
+ close(devfd);
+
+ devfd = opendevice(IPNAT_NAME);
+ if (devfd == -1)
+ return 1;
+ if (readnat(devfd, NULL))
+ return 1;
+ close(devfd);
+
+ if (setlock(fd, 0)) {
+ close(fd);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c
new file mode 100644
index 0000000..3261cef
--- /dev/null
+++ b/contrib/ipfilter/tools/ipfstat.c
@@ -0,0 +1,2375 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#ifdef __FreeBSD__
+# ifndef __FreeBSD_cc_version
+# include <osreldate.h>
+# else
+# if __FreeBSD_cc_version < 430000
+# include <osreldate.h>
+# endif
+# endif
+#endif
+#include <sys/ioctl.h>
+#include <ctype.h>
+#include <fcntl.h>
+#ifdef linux
+# include <linux/a.out.h>
+#else
+# include <nlist.h>
+#endif
+#include <ctype.h>
+#if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+# include <stddef.h>
+#endif
+#include "ipf.h"
+#include "netinet/ipl.h"
+#if defined(STATETOP)
+# if defined(_BSDI_VERSION)
+# undef STATETOP
+# endif
+# if defined(__FreeBSD__) && \
+ (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000))
+# undef STATETOP
+# endif
+# if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000)
+# undef STATETOP
+# endif
+# if defined(sun)
+# if defined(__svr4__) || defined(__SVR4)
+# include <sys/select.h>
+# else
+# undef STATETOP /* NOT supported on SunOS4 */
+# endif
+# endif
+#endif
+#if defined(STATETOP) && !defined(linux)
+# include <netinet/ip_var.h>
+# include <netinet/tcp_fsm.h>
+#endif
+#ifdef STATETOP
+# include <ctype.h>
+# include <signal.h>
+# include <time.h>
+# if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \
+ defined(__sgi)
+# ifdef ERR
+# undef ERR
+# endif
+# include <curses.h>
+# else /* SOLARIS */
+# include <ncurses.h>
+# endif /* SOLARIS */
+#endif /* STATETOP */
+#include "kmem.h"
+#if defined(__NetBSD__) || (__OpenBSD__)
+# include <paths.h>
+#endif
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+#ifdef __hpux
+# define nlist nlist64
+#endif
+
+extern char *optarg;
+extern int optind;
+extern int opterr;
+
+#define PRINTF (void)printf
+#define FPRINTF (void)fprintf
+static char *filters[4] = { "ipfilter(in)", "ipfilter(out)",
+ "ipacct(in)", "ipacct(out)" };
+static int state_logging = -1;
+static wordtab_t *state_fields = NULL;
+
+int nohdrfields = 0;
+int opts = 0;
+int use_inet6 = 0;
+int live_kernel = 1;
+int state_fd = -1;
+int ipf_fd = -1;
+int auth_fd = -1;
+int nat_fd = -1;
+frgroup_t *grtop = NULL;
+frgroup_t *grtail = NULL;
+
+char *blockreasons[FRB_MAX_VALUE + 1] = {
+ "packet blocked",
+ "log rule failure",
+ "pps rate exceeded",
+ "jumbogram",
+ "makefrip failed",
+ "cannot add state",
+ "IP ID update failed",
+ "log-or-block failed",
+ "decapsulate failure",
+ "cannot create new auth entry",
+ "packet queued for auth",
+ "buffer coalesce failure",
+ "buffer pullup failure",
+ "auth feedback",
+ "bad fragment",
+ "IPv4 NAT failure",
+ "IPv6 NAT failure"
+};
+
+#ifdef STATETOP
+#define STSTRSIZE 80
+#define STGROWSIZE 16
+#define HOSTNMLEN 40
+
+#define STSORT_PR 0
+#define STSORT_PKTS 1
+#define STSORT_BYTES 2
+#define STSORT_TTL 3
+#define STSORT_SRCIP 4
+#define STSORT_SRCPT 5
+#define STSORT_DSTIP 6
+#define STSORT_DSTPT 7
+#define STSORT_MAX STSORT_DSTPT
+#define STSORT_DEFAULT STSORT_BYTES
+
+
+typedef struct statetop {
+ i6addr_t st_src;
+ i6addr_t st_dst;
+ u_short st_sport;
+ u_short st_dport;
+ u_char st_p;
+ u_char st_v;
+ u_char st_state[2];
+ U_QUAD_T st_pkts;
+ U_QUAD_T st_bytes;
+ u_long st_age;
+} statetop_t;
+#endif
+
+int main __P((int, char *[]));
+
+static int fetchfrag __P((int, int, ipfr_t *));
+static void showstats __P((friostat_t *, u_32_t));
+static void showfrstates __P((ipfrstat_t *, u_long));
+static void showlist __P((friostat_t *));
+static void showstatestats __P((ips_stat_t *));
+static void showipstates __P((ips_stat_t *, int *));
+static void showauthstates __P((ipf_authstat_t *));
+static void showtqtable_live __P((int));
+static void showgroups __P((friostat_t *));
+static void usage __P((char *));
+static int state_matcharray __P((ipstate_t *, int *));
+static int printlivelist __P((friostat_t *, int, int, frentry_t *,
+ char *, char *));
+static void printdeadlist __P((friostat_t *, int, int, frentry_t *,
+ char *, char *));
+static void printside __P((char *, ipf_statistics_t *));
+static void parse_ipportstr __P((const char *, i6addr_t *, int *));
+static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **,
+ ipfrstat_t **, ipf_authstat_t **, u_32_t *));
+static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **,
+ ipfrstat_t **, ipf_authstat_t **, u_32_t *));
+static ipstate_t *fetchstate __P((ipstate_t *, ipstate_t *));
+#ifdef STATETOP
+static void topipstates __P((i6addr_t, i6addr_t, int, int, int,
+ int, int, int, int *));
+static void sig_break __P((int));
+static void sig_resize __P((int));
+static char *getip __P((int, i6addr_t *));
+static char *ttl_to_string __P((long));
+static int sort_p __P((const void *, const void *));
+static int sort_pkts __P((const void *, const void *));
+static int sort_bytes __P((const void *, const void *));
+static int sort_ttl __P((const void *, const void *));
+static int sort_srcip __P((const void *, const void *));
+static int sort_srcpt __P((const void *, const void *));
+static int sort_dstip __P((const void *, const void *));
+static int sort_dstpt __P((const void *, const void *));
+#endif
+
+
+static void usage(name)
+ char *name;
+{
+#ifdef USE_INET6
+ fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name);
+#else
+ fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name);
+#endif
+ fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name);
+#ifdef USE_INET6
+ fprintf(stderr, " %s -t [-6C] ", name);
+#else
+ fprintf(stderr, " %s -t [-C] ", name);
+#endif
+ fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n");
+ exit(1);
+}
+
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ ipf_authstat_t frauthst;
+ ipf_authstat_t *frauthstp = &frauthst;
+ friostat_t fio;
+ friostat_t *fiop = &fio;
+ ips_stat_t ipsst;
+ ips_stat_t *ipsstp = &ipsst;
+ ipfrstat_t ifrst;
+ ipfrstat_t *ifrstp = &ifrst;
+ char *options;
+ char *kern = NULL;
+ char *memf = NULL;
+ int c;
+ int myoptind;
+ int *filter = NULL;
+
+ int protocol = -1; /* -1 = wild card for any protocol */
+ int refreshtime = 1; /* default update time */
+ int sport = -1; /* -1 = wild card for any source port */
+ int dport = -1; /* -1 = wild card for any dest port */
+ int topclosed = 0; /* do not show closed tcp sessions */
+ i6addr_t saddr, daddr;
+ u_32_t frf;
+
+#ifdef USE_INET6
+ options = "6aACdfghIilnostvD:m:M:N:O:P:RS:T:";
+#else
+ options = "aACdfghIilnostvD:m:M:N:O:P:RS:T:";
+#endif
+
+ saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */
+ daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */
+#ifdef USE_INET6
+ saddr.in6 = in6addr_any; /* default any v6 source addr */
+ daddr.in6 = in6addr_any; /* default any v6 dest addr */
+#endif
+
+ /* Don't warn about invalid flags when we run getopt for the 1st time */
+ opterr = 0;
+
+ /*
+ * Parse these two arguments now lest there be any buffer overflows
+ * in the parsing of the rest.
+ */
+ myoptind = optind;
+ while ((c = getopt(argc, argv, options)) != -1) {
+ switch (c)
+ {
+ case 'M' :
+ memf = optarg;
+ live_kernel = 0;
+ break;
+ case 'N' :
+ kern = optarg;
+ live_kernel = 0;
+ break;
+ }
+ }
+ optind = myoptind;
+
+ if (live_kernel == 1) {
+ if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) {
+ perror("open(IPSTATE_NAME)");
+ exit(-1);
+ }
+ if ((auth_fd = open(IPAUTH_NAME, O_RDONLY)) == -1) {
+ perror("open(IPAUTH_NAME)");
+ exit(-1);
+ }
+ if ((nat_fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
+ perror("open(IPAUTH_NAME)");
+ exit(-1);
+ }
+ if ((ipf_fd = open(IPL_NAME, O_RDONLY)) == -1) {
+ fprintf(stderr, "open(%s)", IPL_NAME);
+ perror("");
+ exit(-1);
+ }
+ }
+
+ if (kern != NULL || memf != NULL) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+
+ if (live_kernel == 1) {
+ (void) checkrev(IPL_NAME);
+ } else {
+ if (openkmem(kern, memf) == -1)
+ exit(-1);
+ }
+
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+
+ opterr = 1;
+
+ while ((c = getopt(argc, argv, options)) != -1)
+ {
+ switch (c)
+ {
+#ifdef USE_INET6
+ case '6' :
+ use_inet6 = 1;
+ break;
+#endif
+ case 'a' :
+ opts |= OPT_ACCNT|OPT_SHOWLIST;
+ break;
+ case 'A' :
+ opts |= OPT_AUTHSTATS;
+ break;
+ case 'C' :
+ topclosed = 1;
+ break;
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'D' :
+ parse_ipportstr(optarg, &daddr, &dport);
+ break;
+ case 'f' :
+ opts |= OPT_FRSTATES;
+ break;
+ case 'g' :
+ opts |= OPT_GROUPS;
+ break;
+ case 'h' :
+ opts |= OPT_HITS;
+ break;
+ case 'i' :
+ opts |= OPT_INQUE|OPT_SHOWLIST;
+ break;
+ case 'I' :
+ opts |= OPT_INACTIVE;
+ break;
+ case 'l' :
+ opts |= OPT_SHOWLIST;
+ break;
+ case 'm' :
+ filter = parseipfexpr(optarg, NULL);
+ if (filter == NULL) {
+ fprintf(stderr, "Error parseing '%s'\n",
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'M' :
+ break;
+ case 'N' :
+ break;
+ case 'n' :
+ opts |= OPT_SHOWLINENO;
+ break;
+ case 'o' :
+ opts |= OPT_OUTQUE|OPT_SHOWLIST;
+ break;
+ case 'O' :
+ state_fields = parsefields(statefields, optarg);
+ break;
+ case 'P' :
+ protocol = getproto(optarg);
+ if (protocol == -1) {
+ fprintf(stderr, "%s: Invalid protocol: %s\n",
+ argv[0], optarg);
+ exit(-2);
+ }
+ break;
+ case 'R' :
+ opts |= OPT_NORESOLVE;
+ break;
+ case 's' :
+ opts |= OPT_IPSTATES;
+ break;
+ case 'S' :
+ parse_ipportstr(optarg, &saddr, &sport);
+ break;
+ case 't' :
+#ifdef STATETOP
+ opts |= OPT_STATETOP;
+ break;
+#else
+ fprintf(stderr,
+ "%s: state top facility not compiled in\n",
+ argv[0]);
+ exit(-2);
+#endif
+ case 'T' :
+ if (!sscanf(optarg, "%d", &refreshtime) ||
+ (refreshtime <= 0)) {
+ fprintf(stderr,
+ "%s: Invalid refreshtime < 1 : %s\n",
+ argv[0], optarg);
+ exit(-2);
+ }
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (live_kernel == 1) {
+ bzero((char *)&fio, sizeof(fio));
+ bzero((char *)&ipsst, sizeof(ipsst));
+ bzero((char *)&ifrst, sizeof(ifrst));
+
+ ipfstate_live(IPL_NAME, &fiop, &ipsstp, &ifrstp,
+ &frauthstp, &frf);
+ } else {
+ ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf);
+ }
+
+ if (opts & OPT_IPSTATES) {
+ showipstates(ipsstp, filter);
+ } else if (opts & OPT_SHOWLIST) {
+ showlist(fiop);
+ if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
+ opts &= ~OPT_OUTQUE;
+ showlist(fiop);
+ }
+ } else if (opts & OPT_FRSTATES)
+ showfrstates(ifrstp, fiop->f_ticks);
+#ifdef STATETOP
+ else if (opts & OPT_STATETOP)
+ topipstates(saddr, daddr, sport, dport, protocol,
+ use_inet6 ? 6 : 4, refreshtime, topclosed, filter);
+#endif
+ else if (opts & OPT_AUTHSTATS)
+ showauthstates(frauthstp);
+ else if (opts & OPT_GROUPS)
+ showgroups(fiop);
+ else
+ showstats(fiop, frf);
+
+ return 0;
+}
+
+
+/*
+ * Fill in the stats structures from the live kernel, using a combination
+ * of ioctl's and copying directly from kernel memory.
+ */
+static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
+ char *device;
+ friostat_t **fiopp;
+ ips_stat_t **ipsstpp;
+ ipfrstat_t **ifrstpp;
+ ipf_authstat_t **frauthstpp;
+ u_32_t *frfp;
+{
+ ipfobj_t ipfo;
+
+ if (checkrev(device) == -1) {
+ fprintf(stderr, "User/kernel version check failed\n");
+ exit(1);
+ }
+
+ if ((opts & OPT_AUTHSTATS) == 0) {
+ bzero((caddr_t)&ipfo, sizeof(ipfo));
+ ipfo.ipfo_rev = IPFILTER_VERSION;
+ ipfo.ipfo_type = IPFOBJ_IPFSTAT;
+ ipfo.ipfo_size = sizeof(friostat_t);
+ ipfo.ipfo_ptr = (void *)*fiopp;
+
+ if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) {
+ ipferror(ipf_fd, "ioctl(ipf:SIOCGETFS)");
+ exit(-1);
+ }
+
+ if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1)
+ ipferror(ipf_fd, "ioctl(SIOCGETFF)");
+ }
+
+ if ((opts & OPT_IPSTATES) != 0) {
+
+ bzero((caddr_t)&ipfo, sizeof(ipfo));
+ ipfo.ipfo_rev = IPFILTER_VERSION;
+ ipfo.ipfo_type = IPFOBJ_STATESTAT;
+ ipfo.ipfo_size = sizeof(ips_stat_t);
+ ipfo.ipfo_ptr = (void *)*ipsstpp;
+
+ if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
+ ipferror(state_fd, "ioctl(state:SIOCGETFS)");
+ exit(-1);
+ }
+ if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) {
+ ipferror(state_fd, "ioctl(state:SIOCGETLG)");
+ exit(-1);
+ }
+ }
+
+ if ((opts & OPT_FRSTATES) != 0) {
+ bzero((caddr_t)&ipfo, sizeof(ipfo));
+ ipfo.ipfo_rev = IPFILTER_VERSION;
+ ipfo.ipfo_type = IPFOBJ_FRAGSTAT;
+ ipfo.ipfo_size = sizeof(ipfrstat_t);
+ ipfo.ipfo_ptr = (void *)*ifrstpp;
+
+ if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) {
+ ipferror(ipf_fd, "ioctl(SIOCGFRST)");
+ exit(-1);
+ }
+ }
+
+ if (opts & OPT_DEBUG)
+ PRINTF("opts %#x name %s\n", opts, device);
+
+ if ((opts & OPT_AUTHSTATS) != 0) {
+ bzero((caddr_t)&ipfo, sizeof(ipfo));
+ ipfo.ipfo_rev = IPFILTER_VERSION;
+ ipfo.ipfo_type = IPFOBJ_AUTHSTAT;
+ ipfo.ipfo_size = sizeof(ipf_authstat_t);
+ ipfo.ipfo_ptr = (void *)*frauthstpp;
+
+ if (ioctl(auth_fd, SIOCATHST, &ipfo) == -1) {
+ ipferror(auth_fd, "ioctl(SIOCATHST)");
+ exit(-1);
+ }
+ }
+}
+
+
+/*
+ * Build up the stats structures from data held in the "core" memory.
+ * This is mainly useful when looking at data in crash dumps and ioctl's
+ * just won't work any more.
+ */
+static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp)
+ char *kernel;
+ friostat_t **fiopp;
+ ips_stat_t **ipsstpp;
+ ipfrstat_t **ifrstpp;
+ ipf_authstat_t **frauthstpp;
+ u_32_t *frfp;
+{
+ static ipf_authstat_t frauthst, *frauthstp;
+ static ipftq_t ipstcptab[IPF_TCP_NSTATES];
+ static ips_stat_t ipsst, *ipsstp;
+ static ipfrstat_t ifrst, *ifrstp;
+ static friostat_t fio, *fiop;
+ int temp;
+
+ void *rules[2][2];
+ struct nlist deadlist[44] = {
+ { "ipf_auth_stats", 0, 0, 0, 0 }, /* 0 */
+ { "fae_list", 0, 0, 0, 0 },
+ { "ipauth", 0, 0, 0, 0 },
+ { "ipf_auth_list", 0, 0, 0, 0 },
+ { "ipf_auth_start", 0, 0, 0, 0 },
+ { "ipf_auth_end", 0, 0, 0, 0 }, /* 5 */
+ { "ipf_auth_next", 0, 0, 0, 0 },
+ { "ipf_auth", 0, 0, 0, 0 },
+ { "ipf_auth_used", 0, 0, 0, 0 },
+ { "ipf_auth_size", 0, 0, 0, 0 },
+ { "ipf_auth_defaultage", 0, 0, 0, 0 }, /* 10 */
+ { "ipf_auth_pkts", 0, 0, 0, 0 },
+ { "ipf_auth_lock", 0, 0, 0, 0 },
+ { "frstats", 0, 0, 0, 0 },
+ { "ips_stats", 0, 0, 0, 0 },
+ { "ips_num", 0, 0, 0, 0 }, /* 15 */
+ { "ips_wild", 0, 0, 0, 0 },
+ { "ips_list", 0, 0, 0, 0 },
+ { "ips_table", 0, 0, 0, 0 },
+ { "ipf_state_max", 0, 0, 0, 0 },
+ { "ipf_state_size", 0, 0, 0, 0 }, /* 20 */
+ { "ipf_state_doflush", 0, 0, 0, 0 },
+ { "ipf_state_lock", 0, 0, 0, 0 },
+ { "ipfr_heads", 0, 0, 0, 0 },
+ { "ipfr_nattab", 0, 0, 0, 0 },
+ { "ipfr_stats", 0, 0, 0, 0 }, /* 25 */
+ { "ipfr_inuse", 0, 0, 0, 0 },
+ { "ipf_ipfrttl", 0, 0, 0, 0 },
+ { "ipf_frag_lock", 0, 0, 0, 0 },
+ { "ipfr_timer_id", 0, 0, 0, 0 },
+ { "ipf_nat_lock", 0, 0, 0, 0 }, /* 30 */
+ { "ipf_rules", 0, 0, 0, 0 },
+ { "ipf_acct", 0, 0, 0, 0 },
+ { "ipl_frouteok", 0, 0, 0, 0 },
+ { "ipf_running", 0, 0, 0, 0 },
+ { "ipf_groups", 0, 0, 0, 0 }, /* 35 */
+ { "ipf_active", 0, 0, 0, 0 },
+ { "ipf_pass", 0, 0, 0, 0 },
+ { "ipf_flags", 0, 0, 0, 0 },
+ { "ipf_state_logging", 0, 0, 0, 0 },
+ { "ips_tqtqb", 0, 0, 0, 0 }, /* 40 */
+ { NULL, 0, 0, 0, 0 }
+ };
+
+
+ frauthstp = &frauthst;
+ ipsstp = &ipsst;
+ ifrstp = &ifrst;
+ fiop = &fio;
+
+ *frfp = 0;
+ *fiopp = fiop;
+ *ipsstpp = ipsstp;
+ *ifrstpp = ifrstp;
+ *frauthstpp = frauthstp;
+
+ bzero((char *)fiop, sizeof(*fiop));
+ bzero((char *)ipsstp, sizeof(*ipsstp));
+ bzero((char *)ifrstp, sizeof(*ifrstp));
+ bzero((char *)frauthstp, sizeof(*frauthstp));
+
+ if (nlist(kernel, deadlist) == -1) {
+ fprintf(stderr, "nlist error\n");
+ return;
+ }
+
+ /*
+ * This is for SIOCGETFF.
+ */
+ kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp));
+
+ /*
+ * f_locks is a combination of the lock variable from each part of
+ * ipfilter (state, auth, nat, fragments).
+ */
+ kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop));
+ kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value,
+ sizeof(fiop->f_locks[0]));
+ kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value,
+ sizeof(fiop->f_locks[1]));
+ kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value,
+ sizeof(fiop->f_locks[2]));
+ kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value,
+ sizeof(fiop->f_locks[3]));
+
+ /*
+ * Get pointers to each list of rules (active, inactive, in, out)
+ */
+ kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules));
+ fiop->f_fin[0] = rules[0][0];
+ fiop->f_fin[1] = rules[0][1];
+ fiop->f_fout[0] = rules[1][0];
+ fiop->f_fout[1] = rules[1][1];
+
+ /*
+ * Now get accounting rules pointers.
+ */
+ kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules));
+ fiop->f_acctin[0] = rules[0][0];
+ fiop->f_acctin[1] = rules[0][1];
+ fiop->f_acctout[0] = rules[1][0];
+ fiop->f_acctout[1] = rules[1][1];
+
+ /*
+ * A collection of "global" variables used inside the kernel which
+ * are all collected in friostat_t via ioctl.
+ */
+ kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[33].n_value,
+ sizeof(fiop->f_froute));
+ kmemcpy((char *)&fiop->f_running, (u_long)deadlist[34].n_value,
+ sizeof(fiop->f_running));
+ kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[35].n_value,
+ sizeof(fiop->f_groups));
+ kmemcpy((char *)&fiop->f_active, (u_long)deadlist[36].n_value,
+ sizeof(fiop->f_active));
+ kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[37].n_value,
+ sizeof(fiop->f_defpass));
+
+ /*
+ * Build up the state information stats structure.
+ */
+ kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp));
+ kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp));
+ kmemcpy((char *)ipstcptab, (u_long)deadlist[40].n_value,
+ sizeof(ipstcptab));
+ ipsstp->iss_active = temp;
+ ipsstp->iss_table = (void *)deadlist[18].n_value;
+ ipsstp->iss_list = (void *)deadlist[17].n_value;
+ ipsstp->iss_tcptab = ipstcptab;
+
+ /*
+ * Build up the authentiation information stats structure.
+ */
+ kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value,
+ sizeof(*frauthstp));
+ frauthstp->fas_faelist = (void *)deadlist[1].n_value;
+
+ /*
+ * Build up the fragment information stats structure.
+ */
+ kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value,
+ sizeof(*ifrstp));
+ ifrstp->ifs_table = (void *)deadlist[23].n_value;
+ ifrstp->ifs_nattab = (void *)deadlist[24].n_value;
+ kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value,
+ sizeof(ifrstp->ifs_inuse));
+
+ /*
+ * Get logging on/off switches
+ */
+ kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value,
+ sizeof(state_logging));
+}
+
+
+static void printside(side, frs)
+ char *side;
+ ipf_statistics_t *frs;
+{
+ int i;
+
+ PRINTF("%lu\t%s bad packets\n", frs->fr_bad, side);
+#ifdef USE_INET6
+ PRINTF("%lu\t%s IPv6 packets\n", frs->fr_ipv6, side);
+#endif
+ PRINTF("%lu\t%s packets blocked\n", frs->fr_block, side);
+ PRINTF("%lu\t%s packets passed\n", frs->fr_pass, side);
+ PRINTF("%lu\t%s packets not matched\n", frs->fr_nom, side);
+ PRINTF("%lu\t%s packets counted\n", frs->fr_acct, side);
+ PRINTF("%lu\t%s packets short\n", frs->fr_short, side);
+ PRINTF("%lu\t%s packets logged and blocked\n", frs->fr_bpkl, side);
+ PRINTF("%lu\t%s packets logged and passed\n", frs->fr_ppkl, side);
+ PRINTF("%lu\t%s fragment state kept\n", frs->fr_nfr, side);
+ PRINTF("%lu\t%s fragment state lost\n", frs->fr_bnfr, side);
+ PRINTF("%lu\t%s packet state kept\n", frs->fr_ads, side);
+ PRINTF("%lu\t%s packet state lost\n", frs->fr_bads, side);
+ PRINTF("%lu\t%s invalid source\n", frs->fr_v4_badsrc, side);
+ PRINTF("%lu\t%s cache hits\n", frs->fr_chit, side);
+ PRINTF("%lu\t%s cache misses\n", frs->fr_cmiss, side);
+ PRINTF("%lu\t%s bad coalesces\n", frs->fr_badcoalesces, side);
+ PRINTF("%lu\t%s pullups succeeded\n", frs->fr_pull[0], side);
+ PRINTF("%lu\t%s pullups failed\n", frs->fr_pull[1], side);
+ PRINTF("%lu\t%s TCP checksum failures\n", frs->fr_tcpbad, side);
+ for (i = 0; i <= FRB_MAX_VALUE; i++)
+ PRINTF("%lu\t%s block reason %s\n",
+ frs->fr_blocked[i], side, blockreasons[i]);
+}
+
+
+/*
+ * Display the kernel stats for packets blocked and passed and other
+ * associated running totals which are kept.
+ */
+static void showstats(fp, frf)
+ struct friostat *fp;
+ u_32_t frf;
+{
+ printside("input", &fp->f_st[0]);
+ printside("output", &fp->f_st[1]);
+
+ PRINTF("%lu\tpackets logged\n", fp->f_log_ok);
+ PRINTF("%lu\tlog failures\n", fp->f_log_fail);
+ PRINTF("%lu\tred-black no memory\n", fp->f_rb_no_mem);
+ PRINTF("%lu\tred-black node maximum\n", fp->f_rb_node_max);
+ PRINTF("%lu\tICMP replies sent\n", fp->f_st[0].fr_ret);
+ PRINTF("%lu\tTCP RSTs sent\n", fp->f_st[1].fr_ret);
+ PRINTF("%lu\tfastroute successes\n", fp->f_froute[0]);
+ PRINTF("%lu\tfastroute failures\n", fp->f_froute[1]);
+ PRINTF("%u\tIPF Ticks\n", fp->f_ticks);
+
+ PRINTF("%x\tPacket log flags set:\n", frf);
+ if (frf & FF_LOGPASS)
+ PRINTF("\tpackets passed through filter\n");
+ if (frf & FF_LOGBLOCK)
+ PRINTF("\tpackets blocked by filter\n");
+ if (frf & FF_LOGNOMATCH)
+ PRINTF("\tpackets not matched by filter\n");
+ if (!frf)
+ PRINTF("\tnone\n");
+}
+
+
+/*
+ * Print out a list of rules from the kernel, starting at the one passed.
+ */
+static int
+printlivelist(fiop, out, set, fp, group, comment)
+ struct friostat *fiop;
+ int out, set;
+ frentry_t *fp;
+ char *group, *comment;
+{
+ struct frentry fb;
+ ipfruleiter_t rule;
+ frentry_t zero;
+ frgroup_t *g;
+ ipfobj_t obj;
+ int rules;
+ int num;
+
+ rules = 0;
+
+ rule.iri_inout = out;
+ rule.iri_active = set;
+ rule.iri_rule = &fb;
+ rule.iri_nrules = 1;
+ if (group != NULL)
+ strncpy(rule.iri_group, group, FR_GROUPLEN);
+ else
+ rule.iri_group[0] = '\0';
+
+ bzero((char *)&zero, sizeof(zero));
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_IPFITER;
+ obj.ipfo_size = sizeof(rule);
+ obj.ipfo_ptr = &rule;
+
+ while (rule.iri_rule != NULL) {
+ u_long array[1000];
+
+ memset(array, 0xff, sizeof(array));
+ fp = (frentry_t *)array;
+ rule.iri_rule = fp;
+ if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
+ ipferror(ipf_fd, "ioctl(SIOCIPFITER)");
+ num = IPFGENITER_IPF;
+ (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
+ return rules;
+ }
+ if (bcmp(fp, &zero, sizeof(zero)) == 0)
+ break;
+ if (rule.iri_rule == NULL)
+ break;
+#ifdef USE_INET6
+ if (use_inet6 != 0) {
+ if (fp->fr_family != 0 && fp->fr_family != AF_INET6)
+ continue;
+ } else
+#endif
+ {
+ if (fp->fr_family != 0 && fp->fr_family != AF_INET)
+ continue;
+ }
+ if (fp->fr_data != NULL)
+ fp->fr_data = (char *)fp + fp->fr_size;
+
+ rules++;
+
+ if (opts & (OPT_HITS|OPT_DEBUG))
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_hits);
+#else
+ PRINTF("%lu ", fp->fr_hits);
+#endif
+ if (opts & (OPT_ACCNT|OPT_DEBUG))
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_bytes);
+#else
+ PRINTF("%lu ", fp->fr_bytes);
+#endif
+ if (opts & OPT_SHOWLINENO)
+ PRINTF("@%d ", rules);
+
+ if (fp->fr_die != 0)
+ fp->fr_die -= fiop->f_ticks;
+
+ printfr(fp, ioctl);
+ if (opts & OPT_DEBUG) {
+ binprint(fp, fp->fr_size);
+ if (fp->fr_data != NULL && fp->fr_dsize > 0)
+ binprint(fp->fr_data, fp->fr_dsize);
+ }
+ if (fp->fr_grhead != -1) {
+ for (g = grtop; g != NULL; g = g->fg_next) {
+ if (!strncmp(fp->fr_names + fp->fr_grhead,
+ g->fg_name,
+ FR_GROUPLEN))
+ break;
+ }
+ if (g == NULL) {
+ g = calloc(1, sizeof(*g));
+
+ if (g != NULL) {
+ strncpy(g->fg_name,
+ fp->fr_names + fp->fr_grhead,
+ FR_GROUPLEN);
+ if (grtop == NULL) {
+ grtop = g;
+ grtail = g;
+ } else {
+ grtail->fg_next = g;
+ grtail = g;
+ }
+ }
+ }
+ }
+ if (fp->fr_type == FR_T_CALLFUNC) {
+ rules += printlivelist(fiop, out, set, fp->fr_data,
+ group, "# callfunc: ");
+ }
+ }
+
+ num = IPFGENITER_IPF;
+ (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num);
+
+ return rules;
+}
+
+
+static void printdeadlist(fiop, out, set, fp, group, comment)
+ friostat_t *fiop;
+ int out, set;
+ frentry_t *fp;
+ char *group, *comment;
+{
+ frgroup_t *grtop, *grtail, *g;
+ struct frentry fb;
+ char *data;
+ u_32_t type;
+ int n;
+
+ fb.fr_next = fp;
+ n = 0;
+ grtop = NULL;
+ grtail = NULL;
+
+ for (n = 1; fp; fp = fb.fr_next, n++) {
+ if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
+ fb.fr_size) == -1) {
+ perror("kmemcpy");
+ return;
+ }
+ fp = &fb;
+ if (use_inet6 != 0) {
+ if (fp->fr_family != 0 && fp->fr_family != 6)
+ continue;
+ } else {
+ if (fp->fr_family != 0 && fp->fr_family != 4)
+ continue;
+ }
+
+ data = NULL;
+ type = fb.fr_type & ~FR_T_BUILTIN;
+ if (type == FR_T_IPF || type == FR_T_BPFOPC) {
+ if (fb.fr_dsize) {
+ data = malloc(fb.fr_dsize);
+
+ if (kmemcpy(data, (u_long)fb.fr_data,
+ fb.fr_dsize) == -1) {
+ perror("kmemcpy");
+ return;
+ }
+ fb.fr_data = data;
+ }
+ }
+
+ if (opts & OPT_HITS)
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_hits);
+#else
+ PRINTF("%lu ", fb.fr_hits);
+#endif
+ if (opts & OPT_ACCNT)
+#ifdef USE_QUAD_T
+ PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_bytes);
+#else
+ PRINTF("%lu ", fb.fr_bytes);
+#endif
+ if (opts & OPT_SHOWLINENO)
+ PRINTF("@%d ", n);
+
+ printfr(fp, ioctl);
+ if (opts & OPT_DEBUG) {
+ binprint(fp, fp->fr_size);
+ if (fb.fr_data != NULL && fb.fr_dsize > 0)
+ binprint(fb.fr_data, fb.fr_dsize);
+ }
+ if (data != NULL)
+ free(data);
+ if (fb.fr_grhead != -1) {
+ g = calloc(1, sizeof(*g));
+
+ if (g != NULL) {
+ strncpy(g->fg_name, fb.fr_names + fb.fr_grhead,
+ FR_GROUPLEN);
+ if (grtop == NULL) {
+ grtop = g;
+ grtail = g;
+ } else {
+ grtail->fg_next = g;
+ grtail = g;
+ }
+ }
+ }
+ if (type == FR_T_CALLFUNC) {
+ printdeadlist(fiop, out, set, fb.fr_data, group,
+ "# callfunc: ");
+ }
+ }
+
+ while ((g = grtop) != NULL) {
+ printdeadlist(fiop, out, set, NULL, g->fg_name, comment);
+ grtop = g->fg_next;
+ free(g);
+ }
+}
+
+/*
+ * print out all of the asked for rule sets, using the stats struct as
+ * the base from which to get the pointers.
+ */
+static void showlist(fiop)
+ struct friostat *fiop;
+{
+ struct frentry *fp = NULL;
+ int i, set;
+
+ set = fiop->f_active;
+ if (opts & OPT_INACTIVE)
+ set = 1 - set;
+ if (opts & OPT_ACCNT) {
+ if (opts & OPT_OUTQUE) {
+ i = F_ACOUT;
+ fp = (struct frentry *)fiop->f_acctout[set];
+ } else if (opts & OPT_INQUE) {
+ i = F_ACIN;
+ fp = (struct frentry *)fiop->f_acctin[set];
+ } else {
+ FPRINTF(stderr, "No -i or -o given with -a\n");
+ return;
+ }
+ } else {
+ 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_DEBUG)
+ FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
+
+ if (opts & OPT_DEBUG)
+ PRINTF("fp %p set %d\n", fp, set);
+
+ if (live_kernel == 1) {
+ int printed;
+
+ printed = printlivelist(fiop, i, set, fp, NULL, NULL);
+ if (printed == 0) {
+ FPRINTF(stderr, "# empty list for %s%s\n",
+ (opts & OPT_INACTIVE) ? "inactive " : "",
+ filters[i]);
+ }
+ } else {
+ if (!fp) {
+ FPRINTF(stderr, "# empty list for %s%s\n",
+ (opts & OPT_INACTIVE) ? "inactive " : "",
+ filters[i]);
+ } else {
+ printdeadlist(fiop, i, set, fp, NULL, NULL);
+ }
+ }
+}
+
+
+/*
+ * Display ipfilter stateful filtering information
+ */
+static void showipstates(ipsp, filter)
+ ips_stat_t *ipsp;
+ int *filter;
+{
+ ipstate_t *is;
+ int i;
+
+ /*
+ * If a list of states hasn't been asked for, only print out stats
+ */
+ if (!(opts & OPT_SHOWLIST)) {
+ showstatestats(ipsp);
+ return;
+ }
+
+ if ((state_fields != NULL) && (nohdrfields == 0)) {
+ for (i = 0; state_fields[i].w_value != 0; i++) {
+ printfieldhdr(statefields, state_fields + i);
+ if (state_fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ }
+
+ /*
+ * Print out all the state information currently held in the kernel.
+ */
+ for (is = ipsp->iss_list; is != NULL; ) {
+ ipstate_t ips;
+
+ is = fetchstate(is, &ips);
+
+ if (is == NULL)
+ break;
+
+ is = ips.is_next;
+ if ((filter != NULL) &&
+ (state_matcharray(&ips, filter) == 0)) {
+ continue;
+ }
+ if (state_fields != NULL) {
+ for (i = 0; state_fields[i].w_value != 0; i++) {
+ printstatefield(&ips, state_fields[i].w_value);
+ if (state_fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ } else {
+ printstate(&ips, opts, ipsp->iss_ticks);
+ }
+ }
+}
+
+
+static void showstatestats(ipsp)
+ ips_stat_t *ipsp;
+{
+ int minlen, maxlen, totallen;
+ ipftable_t table;
+ u_int *buckets;
+ ipfobj_t obj;
+ int i, sz;
+
+ /*
+ * If a list of states hasn't been asked for, only print out stats
+ */
+
+ sz = sizeof(*buckets) * ipsp->iss_state_size;
+ buckets = (u_int *)malloc(sz);
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_GTABLE;
+ obj.ipfo_size = sizeof(table);
+ obj.ipfo_ptr = &table;
+
+ table.ita_type = IPFTABLE_BUCKETS;
+ table.ita_table = buckets;
+
+ if (live_kernel == 1) {
+ if (ioctl(state_fd, SIOCGTABL, &obj) != 0) {
+ free(buckets);
+ return;
+ }
+ } else {
+ if (kmemcpy((char *)buckets,
+ (u_long)ipsp->iss_bucketlen, sz)) {
+ free(buckets);
+ return;
+ }
+ }
+
+ PRINTF("%u\tactive state table entries\n",ipsp->iss_active);
+ PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad);
+ PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup);
+ PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked);
+ PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow);
+ PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full);
+ PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad);
+ PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss);
+ PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag);
+ PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem);
+ PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag);
+ PRINTF("%lu\tcheck success\n", ipsp->iss_hits);
+ PRINTF("%lu\tcloned\n", ipsp->iss_cloned);
+ PRINTF("%lu\texpired\n", ipsp->iss_expire);
+ PRINTF("%lu\tflush all\n", ipsp->iss_flush_all);
+ PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing);
+ PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue);
+ PRINTF("%lu\tflush state\n", ipsp->iss_flush_state);
+ PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout);
+ PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse);
+ PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad);
+ PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned);
+ PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr);
+ PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock);
+ PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits);
+ PRINTF("%lu\tICMP not query\n", ipsp->iss_icmp_notquery);
+ PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short);
+ PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany);
+ PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr);
+ PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss);
+ PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo);
+ PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery);
+ PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail);
+ PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok);
+ PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp);
+ PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask);
+ PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport);
+ PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss);
+ PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref);
+ PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track);
+ PRINTF("%lu\tno memory\n", ipsp->iss_nomem);
+ PRINTF("%lu\tout of window\n", ipsp->iss_oow);
+ PRINTF("%lu\torphans\n", ipsp->iss_orphan);
+ PRINTF("%lu\tscan block\n", ipsp->iss_scan_block);
+ PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max);
+ PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing);
+ PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow);
+ PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd);
+ PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall);
+ PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt);
+ PRINTF("%lu\tTCP removed\n", ipsp->iss_fin);
+ PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm);
+ PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict);
+ PRINTF("%lu\tTCP wild\n", ipsp->iss_wild);
+ PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack);
+
+ PRINTF("State logging %sabled\n", state_logging ? "en" : "dis");
+
+ PRINTF("IP states added:\n");
+ for (i = 0; i < 256; i++) {
+ if (ipsp->iss_proto[i] != 0) {
+ struct protoent *proto;
+
+ proto = getprotobynumber(i);
+ PRINTF("%lu", ipsp->iss_proto[i]);
+ if (proto != NULL)
+ PRINTF("\t%s\n", proto->p_name);
+ else
+ PRINTF("\t%d\n", i);
+ }
+ }
+
+ PRINTF("\nState table bucket statistics:\n");
+ PRINTF("%u\tin use\n", ipsp->iss_inuse);
+
+ minlen = ipsp->iss_max;
+ totallen = 0;
+ maxlen = 0;
+
+ for (i = 0; i < ipsp->iss_state_size; i++) {
+ if (buckets[i] > maxlen)
+ maxlen = buckets[i];
+ if (buckets[i] < minlen)
+ minlen = buckets[i];
+ totallen += buckets[i];
+ }
+
+ PRINTF("%d\thash efficiency\n",
+ totallen ? ipsp->iss_inuse * 100 / totallen : 0);
+ PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n",
+ ((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0,
+ minlen);
+ PRINTF("%u\tmaximal length\n%.3f\taverage length\n",
+ maxlen,
+ ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse :
+ 0.0);
+
+#define ENTRIES_PER_LINE 5
+
+ if (opts & OPT_VERBOSE) {
+ PRINTF("\nCurrent bucket sizes :\n");
+ for (i = 0; i < ipsp->iss_state_size; i++) {
+ if ((i % ENTRIES_PER_LINE) == 0)
+ PRINTF("\t");
+ PRINTF("%4d -> %4u", i, buckets[i]);
+ if ((i % ENTRIES_PER_LINE) ==
+ (ENTRIES_PER_LINE - 1))
+ PRINTF("\n");
+ else
+ PRINTF(" ");
+ }
+ PRINTF("\n");
+ }
+ PRINTF("\n");
+
+ free(buckets);
+
+ if (live_kernel == 1) {
+ showtqtable_live(state_fd);
+ } else {
+ printtqtable(ipsp->iss_tcptab);
+ }
+}
+
+
+#ifdef STATETOP
+static int handle_resize = 0, handle_break = 0;
+
+static void topipstates(saddr, daddr, sport, dport, protocol, ver,
+ refreshtime, topclosed, filter)
+ i6addr_t saddr;
+ i6addr_t daddr;
+ int sport;
+ int dport;
+ int protocol;
+ int ver;
+ int refreshtime;
+ int topclosed;
+ int *filter;
+{
+ char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
+ int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
+ int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0;
+ int len, srclen, dstlen, forward = 1, c = 0;
+ ips_stat_t ipsst, *ipsstp = &ipsst;
+ int token_type = IPFGENITER_STATE;
+ statetop_t *tstable = NULL, *tp;
+ const char *errstr = "";
+ ipstate_t ips;
+ ipfobj_t ipfo;
+ struct timeval selecttimeout;
+ char hostnm[HOSTNMLEN];
+ struct protoent *proto;
+ fd_set readfd;
+ time_t t;
+
+ /* install signal handlers */
+ signal(SIGINT, sig_break);
+ signal(SIGQUIT, sig_break);
+ signal(SIGTERM, sig_break);
+ signal(SIGWINCH, sig_resize);
+
+ /* init ncurses stuff */
+ initscr();
+ cbreak();
+ noecho();
+ curs_set(0);
+ timeout(0);
+ getmaxyx(stdscr, maxy, maxx);
+
+ /* init hostname */
+ gethostname(hostnm, sizeof(hostnm) - 1);
+ hostnm[sizeof(hostnm) - 1] = '\0';
+
+ /* init ipfobj_t stuff */
+ bzero((caddr_t)&ipfo, sizeof(ipfo));
+ ipfo.ipfo_rev = IPFILTER_VERSION;
+ ipfo.ipfo_type = IPFOBJ_STATESTAT;
+ ipfo.ipfo_size = sizeof(*ipsstp);
+ ipfo.ipfo_ptr = (void *)ipsstp;
+
+ /* repeat until user aborts */
+ while ( 1 ) {
+
+ /* get state table */
+ bzero((char *)&ipsst, sizeof(ipsst));
+ if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) {
+ errstr = "ioctl(SIOCGETFS)";
+ ret = -1;
+ goto out;
+ }
+
+ /* clear the history */
+ tsentry = -1;
+
+ /* reset max str len */
+ srclen = dstlen = 0;
+
+ /* read the state table and store in tstable */
+ for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
+
+ ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips);
+ if (ipsstp->iss_list == NULL)
+ break;
+
+ if (ips.is_v != ver)
+ continue;
+
+ if ((filter != NULL) &&
+ (state_matcharray(&ips, filter) == 0))
+ continue;
+
+ /* check v4 src/dest addresses */
+ if (ips.is_v == 4) {
+ if ((saddr.in4.s_addr != INADDR_ANY &&
+ saddr.in4.s_addr != ips.is_saddr) ||
+ (daddr.in4.s_addr != INADDR_ANY &&
+ daddr.in4.s_addr != ips.is_daddr))
+ continue;
+ }
+#ifdef USE_INET6
+ /* check v6 src/dest addresses */
+ if (ips.is_v == 6) {
+ if ((IP6_NEQ(&saddr, &in6addr_any) &&
+ IP6_NEQ(&saddr, &ips.is_src)) ||
+ (IP6_NEQ(&daddr, &in6addr_any) &&
+ IP6_NEQ(&daddr, &ips.is_dst)))
+ continue;
+ }
+#endif
+ /* check protocol */
+ if (protocol > 0 && protocol != ips.is_p)
+ continue;
+
+ /* check ports if protocol is TCP or UDP */
+ if (((ips.is_p == IPPROTO_TCP) ||
+ (ips.is_p == IPPROTO_UDP)) &&
+ (((sport > 0) && (htons(sport) != ips.is_sport)) ||
+ ((dport > 0) && (htons(dport) != ips.is_dport))))
+ continue;
+
+ /* show closed TCP sessions ? */
+ if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
+ (ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
+ (ips.is_state[1] >= IPF_TCPS_LAST_ACK))
+ continue;
+
+ /*
+ * if necessary make room for this state
+ * entry
+ */
+ tsentry++;
+ if (!maxtsentries || tsentry == maxtsentries) {
+ maxtsentries += STGROWSIZE;
+ tstable = realloc(tstable,
+ maxtsentries * sizeof(statetop_t));
+ if (tstable == NULL) {
+ perror("realloc");
+ exit(-1);
+ }
+ }
+
+ /* get max src/dest address string length */
+ len = strlen(getip(ips.is_v, &ips.is_src));
+ if (srclen < len)
+ srclen = len;
+ len = strlen(getip(ips.is_v, &ips.is_dst));
+ if (dstlen < len)
+ dstlen = len;
+
+ /* fill structure */
+ tp = tstable + tsentry;
+ tp->st_src = ips.is_src;
+ tp->st_dst = ips.is_dst;
+ tp->st_p = ips.is_p;
+ tp->st_v = ips.is_v;
+ tp->st_state[0] = ips.is_state[0];
+ tp->st_state[1] = ips.is_state[1];
+ if (forward) {
+ tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
+ tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
+ } else {
+ tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3];
+ tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3];
+ }
+ tp->st_age = ips.is_die - ipsstp->iss_ticks;
+ if ((ips.is_p == IPPROTO_TCP) ||
+ (ips.is_p == IPPROTO_UDP)) {
+ tp->st_sport = ips.is_sport;
+ tp->st_dport = ips.is_dport;
+ }
+ }
+
+ (void) ioctl(state_fd, SIOCIPFDELTOK, &token_type);
+
+ /* sort the array */
+ if (tsentry != -1) {
+ switch (sorting)
+ {
+ case STSORT_PR:
+ qsort(tstable, tsentry + 1,
+ sizeof(statetop_t), sort_p);
+ break;
+ case STSORT_PKTS:
+ qsort(tstable, tsentry + 1,
+ sizeof(statetop_t), sort_pkts);
+ break;
+ case STSORT_BYTES:
+ qsort(tstable, tsentry + 1,
+ sizeof(statetop_t), sort_bytes);
+ break;
+ case STSORT_TTL:
+ qsort(tstable, tsentry + 1,
+ sizeof(statetop_t), sort_ttl);
+ break;
+ case STSORT_SRCIP:
+ qsort(tstable, tsentry + 1,
+ sizeof(statetop_t), sort_srcip);
+ break;
+ case STSORT_SRCPT:
+ qsort(tstable, tsentry +1,
+ sizeof(statetop_t), sort_srcpt);
+ break;
+ case STSORT_DSTIP:
+ qsort(tstable, tsentry + 1,
+ sizeof(statetop_t), sort_dstip);
+ break;
+ case STSORT_DSTPT:
+ qsort(tstable, tsentry + 1,
+ sizeof(statetop_t), sort_dstpt);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* handle window resizes */
+ if (handle_resize) {
+ endwin();
+ initscr();
+ cbreak();
+ noecho();
+ curs_set(0);
+ timeout(0);
+ getmaxyx(stdscr, maxy, maxx);
+ redraw = 1;
+ handle_resize = 0;
+ }
+
+ /* stop program? */
+ if (handle_break)
+ break;
+
+ /* print title */
+ erase();
+ attron(A_BOLD);
+ winy = 0;
+ move(winy,0);
+ sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION);
+ for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++)
+ printw(" ");
+ printw("%s", str1);
+ attroff(A_BOLD);
+
+ /* just for fun add a clock */
+ move(winy, maxx - 8);
+ t = time(NULL);
+ strftime(str1, 80, "%T", localtime(&t));
+ printw("%s\n", str1);
+
+ /*
+ * print the display filters, this is placed in the loop,
+ * because someday I might add code for changing these
+ * while the programming is running :-)
+ */
+ if (sport >= 0)
+ sprintf(str1, "%s,%d", getip(ver, &saddr), sport);
+ else
+ sprintf(str1, "%s", getip(ver, &saddr));
+
+ if (dport >= 0)
+ sprintf(str2, "%s,%d", getip(ver, &daddr), dport);
+ else
+ sprintf(str2, "%s", getip(ver, &daddr));
+
+ if (protocol < 0)
+ strcpy(str3, "any");
+ else if ((proto = getprotobynumber(protocol)) != NULL)
+ sprintf(str3, "%s", proto->p_name);
+ else
+ sprintf(str3, "%d", protocol);
+
+ switch (sorting)
+ {
+ case STSORT_PR:
+ sprintf(str4, "proto");
+ break;
+ case STSORT_PKTS:
+ sprintf(str4, "# pkts");
+ break;
+ case STSORT_BYTES:
+ sprintf(str4, "# bytes");
+ break;
+ case STSORT_TTL:
+ sprintf(str4, "ttl");
+ break;
+ case STSORT_SRCIP:
+ sprintf(str4, "src ip");
+ break;
+ case STSORT_SRCPT:
+ sprintf(str4, "src port");
+ break;
+ case STSORT_DSTIP:
+ sprintf(str4, "dest ip");
+ break;
+ case STSORT_DSTPT:
+ sprintf(str4, "dest port");
+ break;
+ default:
+ sprintf(str4, "unknown");
+ break;
+ }
+
+ if (reverse)
+ strcat(str4, " (reverse)");
+
+ winy += 2;
+ move(winy,0);
+ printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
+ str1, str2, str3, str4);
+
+ /*
+ * For an IPv4 IP address we need at most 15 characters,
+ * 4 tuples of 3 digits, separated by 3 dots. Enforce this
+ * length, so the colums do not change positions based
+ * on the size of the IP address. This length makes the
+ * output fit in a 80 column terminal.
+ * We are lacking a good solution for IPv6 addresses (that
+ * can be longer that 15 characters), so we do not enforce
+ * a maximum on the IP field size.
+ */
+ if (srclen < 15)
+ srclen = 15;
+ if (dstlen < 15)
+ dstlen = 15;
+
+ /* print column description */
+ winy += 2;
+ move(winy,0);
+ attron(A_BOLD);
+ printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
+ srclen + 6, "Source IP", dstlen + 6, "Destination IP",
+ "ST", "PR", "#pkts", "#bytes", "ttl");
+ attroff(A_BOLD);
+
+ /* print all the entries */
+ tp = tstable;
+ if (reverse)
+ tp += tsentry;
+
+ if (tsentry > maxy - 6)
+ tsentry = maxy - 6;
+ for (i = 0; i <= tsentry; i++) {
+ /* print src/dest and port */
+ if ((tp->st_p == IPPROTO_TCP) ||
+ (tp->st_p == IPPROTO_UDP)) {
+ sprintf(str1, "%s,%hu",
+ getip(tp->st_v, &tp->st_src),
+ ntohs(tp->st_sport));
+ sprintf(str2, "%s,%hu",
+ getip(tp->st_v, &tp->st_dst),
+ ntohs(tp->st_dport));
+ } else {
+ sprintf(str1, "%s", getip(tp->st_v,
+ &tp->st_src));
+ sprintf(str2, "%s", getip(tp->st_v,
+ &tp->st_dst));
+ }
+ winy++;
+ move(winy, 0);
+ printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
+
+ /* print state */
+ sprintf(str1, "%X/%X", tp->st_state[0],
+ tp->st_state[1]);
+ printw(" %3s", str1);
+
+ /* print protocol */
+ proto = getprotobynumber(tp->st_p);
+ if (proto) {
+ strncpy(str1, proto->p_name, 4);
+ str1[4] = '\0';
+ } else {
+ sprintf(str1, "%d", tp->st_p);
+ }
+ /* just print icmp for IPv6-ICMP */
+ if (tp->st_p == IPPROTO_ICMPV6)
+ strcpy(str1, "icmp");
+ printw(" %4s", str1);
+
+ /* print #pkt/#bytes */
+#ifdef USE_QUAD_T
+ printw(" %7qu %9qu", (unsigned long long) tp->st_pkts,
+ (unsigned long long) tp->st_bytes);
+#else
+ printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes);
+#endif
+ printw(" %9s", ttl_to_string(tp->st_age));
+
+ if (reverse)
+ tp--;
+ else
+ tp++;
+ }
+
+ /* screen data structure is filled, now update the screen */
+ if (redraw)
+ clearok(stdscr,1);
+
+ if (refresh() == ERR)
+ break;
+ if (redraw) {
+ clearok(stdscr,0);
+ redraw = 0;
+ }
+
+ /* wait for key press or a 1 second time out period */
+ selecttimeout.tv_sec = refreshtime;
+ selecttimeout.tv_usec = 0;
+ FD_ZERO(&readfd);
+ FD_SET(0, &readfd);
+ select(1, &readfd, NULL, NULL, &selecttimeout);
+
+ /* if key pressed, read all waiting keys */
+ if (FD_ISSET(0, &readfd)) {
+ c = wgetch(stdscr);
+ if (c == ERR)
+ continue;
+
+ if (ISALPHA(c) && ISUPPER(c))
+ c = TOLOWER(c);
+ if (c == 'l') {
+ redraw = 1;
+ } else if (c == 'q') {
+ break;
+ } else if (c == 'r') {
+ reverse = !reverse;
+ } else if (c == 'b') {
+ forward = 0;
+ } else if (c == 'f') {
+ forward = 1;
+ } else if (c == 's') {
+ if (++sorting > STSORT_MAX)
+ sorting = 0;
+ }
+ }
+ } /* while */
+
+out:
+ printw("\n");
+ curs_set(1);
+ /* nocbreak(); XXX - endwin() should make this redundant */
+ endwin();
+
+ free(tstable);
+ if (ret != 0)
+ perror(errstr);
+}
+#endif
+
+
+/*
+ * Show fragment cache information that's held in the kernel.
+ */
+static void showfrstates(ifsp, ticks)
+ ipfrstat_t *ifsp;
+ u_long ticks;
+{
+ struct ipfr *ipfrtab[IPFT_SIZE], ifr;
+ int i;
+
+ /*
+ * print out the numeric statistics
+ */
+ PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n",
+ ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
+ PRINTF("%lu\tretrans\n%lu\ttoo short\n",
+ ifsp->ifs_retrans0, ifsp->ifs_short);
+ PRINTF("%lu\tno memory\n%lu\talready exist\n",
+ ifsp->ifs_nomem, ifsp->ifs_exists);
+ PRINTF("%lu\tinuse\n", ifsp->ifs_inuse);
+ PRINTF("\n");
+
+ if (live_kernel == 0) {
+ if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table,
+ sizeof(ipfrtab)))
+ return;
+ }
+
+ /*
+ * Print out the contents (if any) of the fragment cache table.
+ */
+ if (live_kernel == 1) {
+ do {
+ if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0)
+ break;
+ if (ifr.ipfr_ifp == NULL)
+ break;
+ ifr.ipfr_ttl -= ticks;
+ printfraginfo("", &ifr);
+ } while (ifr.ipfr_next != NULL);
+ } else {
+ for (i = 0; i < IPFT_SIZE; i++)
+ while (ipfrtab[i] != NULL) {
+ if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
+ sizeof(ifr)) == -1)
+ break;
+ printfraginfo("", &ifr);
+ ipfrtab[i] = ifr.ipfr_next;
+ }
+ }
+ /*
+ * Print out the contents (if any) of the NAT fragment cache table.
+ */
+
+ if (live_kernel == 0) {
+ if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,
+ sizeof(ipfrtab)))
+ return;
+ }
+
+ if (live_kernel == 1) {
+ do {
+ if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0)
+ break;
+ if (ifr.ipfr_ifp == NULL)
+ break;
+ ifr.ipfr_ttl -= ticks;
+ printfraginfo("NAT: ", &ifr);
+ } while (ifr.ipfr_next != NULL);
+ } else {
+ for (i = 0; i < IPFT_SIZE; i++)
+ while (ipfrtab[i] != NULL) {
+ if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i],
+ sizeof(ifr)) == -1)
+ break;
+ printfraginfo("NAT: ", &ifr);
+ ipfrtab[i] = ifr.ipfr_next;
+ }
+ }
+}
+
+
+/*
+ * Show stats on how auth within IPFilter has been used
+ */
+static void showauthstates(asp)
+ ipf_authstat_t *asp;
+{
+ frauthent_t *frap, fra;
+ ipfgeniter_t auth;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_GENITER;
+ obj.ipfo_size = sizeof(auth);
+ obj.ipfo_ptr = &auth;
+
+ auth.igi_type = IPFGENITER_AUTH;
+ auth.igi_nitems = 1;
+ auth.igi_data = &fra;
+
+#ifdef USE_QUAD_T
+ printf("Authorisation hits: %"PRIu64"\tmisses %"PRIu64"\n",
+ (unsigned long long) asp->fas_hits,
+ (unsigned long long) asp->fas_miss);
+#else
+ printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits,
+ asp->fas_miss);
+#endif
+ printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n",
+ asp->fas_nospace, asp->fas_added, asp->fas_sendfail,
+ asp->fas_sendok);
+ printf("queok %ld\nquefail %ld\nexpire %ld\n",
+ asp->fas_queok, asp->fas_quefail, asp->fas_expire);
+
+ frap = asp->fas_faelist;
+ while (frap) {
+ if (live_kernel == 1) {
+ if (ioctl(auth_fd, SIOCGENITER, &obj))
+ break;
+ } else {
+ if (kmemcpy((char *)&fra, (u_long)frap,
+ sizeof(fra)) == -1)
+ break;
+ }
+ printf("age %ld\t", fra.fae_age);
+ printfr(&fra.fae_fr, ioctl);
+ frap = fra.fae_next;
+ }
+}
+
+
+/*
+ * Display groups used for each of filter rules, accounting rules and
+ * authentication, separately.
+ */
+static void showgroups(fiop)
+ struct friostat *fiop;
+{
+ static char *gnames[3] = { "Filter", "Accounting", "Authentication" };
+ static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH };
+ frgroup_t *fp, grp;
+ int on, off, i;
+
+ on = fiop->f_active;
+ off = 1 - on;
+
+ for (i = 0; i < 3; i++) {
+ printf("%s groups (active):\n", gnames[i]);
+ for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL;
+ fp = grp.fg_next)
+ if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
+ break;
+ else
+ printf("%s\n", grp.fg_name);
+ printf("%s groups (inactive):\n", gnames[i]);
+ for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL;
+ fp = grp.fg_next)
+ if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp)))
+ break;
+ else
+ printf("%s\n", grp.fg_name);
+ }
+}
+
+
+static void parse_ipportstr(argument, ip, port)
+ const char *argument;
+ i6addr_t *ip;
+ int *port;
+{
+ char *s, *comma;
+ int ok = 0;
+
+ /* make working copy of argument, Theoretically you must be able
+ * to write to optarg, but that seems very ugly to me....
+ */
+ s = strdup(argument);
+ if (s == NULL)
+ return;
+
+ /* get port */
+ if ((comma = strchr(s, ',')) != NULL) {
+ if (!strcasecmp(comma + 1, "any")) {
+ *port = -1;
+ } else if (!sscanf(comma + 1, "%d", port) ||
+ (*port < 0) || (*port > 65535)) {
+ fprintf(stderr, "Invalid port specification in %s\n",
+ argument);
+ free(s);
+ exit(-2);
+ }
+ *comma = '\0';
+ }
+
+
+ /* get ip address */
+ if (!strcasecmp(s, "any")) {
+ ip->in4.s_addr = INADDR_ANY;
+ ok = 1;
+#ifdef USE_INET6
+ ip->in6 = in6addr_any;
+ } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
+ ok = 1;
+#endif
+ } else if (inet_aton(s, &ip->in4))
+ ok = 1;
+
+ if (ok == 0) {
+ fprintf(stderr, "Invalid IP address: %s\n", s);
+ free(s);
+ exit(-2);
+ }
+
+ /* free allocated memory */
+ free(s);
+}
+
+
+#ifdef STATETOP
+static void sig_resize(s)
+ int s;
+{
+ handle_resize = 1;
+}
+
+static void sig_break(s)
+ int s;
+{
+ handle_break = 1;
+}
+
+static char *getip(v, addr)
+ int v;
+ i6addr_t *addr;
+{
+#ifdef USE_INET6
+ static char hostbuf[MAXHOSTNAMELEN+1];
+#endif
+
+ if (v == 4)
+ return inet_ntoa(addr->in4);
+
+#ifdef USE_INET6
+ (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1);
+ hostbuf[MAXHOSTNAMELEN] = '\0';
+ return hostbuf;
+#else
+ return "IPv6";
+#endif
+}
+
+
+static char *ttl_to_string(ttl)
+ long int ttl;
+{
+ static char ttlbuf[STSTRSIZE];
+ int hours, minutes, seconds;
+
+ /* ttl is in half seconds */
+ ttl /= 2;
+
+ hours = ttl / 3600;
+ ttl = ttl % 3600;
+ minutes = ttl / 60;
+ seconds = ttl % 60;
+
+ if (hours > 0)
+ sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds);
+ else
+ sprintf(ttlbuf, "%2d:%02d", minutes, seconds);
+ return ttlbuf;
+}
+
+
+static int sort_pkts(a, b)
+ const void *a;
+ const void *b;
+{
+
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+ if (ap->st_pkts == bp->st_pkts)
+ return 0;
+ else if (ap->st_pkts < bp->st_pkts)
+ return 1;
+ return -1;
+}
+
+
+static int sort_bytes(a, b)
+ const void *a;
+ const void *b;
+{
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+ if (ap->st_bytes == bp->st_bytes)
+ return 0;
+ else if (ap->st_bytes < bp->st_bytes)
+ return 1;
+ return -1;
+}
+
+
+static int sort_p(a, b)
+ const void *a;
+ const void *b;
+{
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+ if (ap->st_p == bp->st_p)
+ return 0;
+ else if (ap->st_p < bp->st_p)
+ return 1;
+ return -1;
+}
+
+
+static int sort_ttl(a, b)
+ const void *a;
+ const void *b;
+{
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+ if (ap->st_age == bp->st_age)
+ return 0;
+ else if (ap->st_age < bp->st_age)
+ return 1;
+ return -1;
+}
+
+static int sort_srcip(a, b)
+ const void *a;
+ const void *b;
+{
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+#ifdef USE_INET6
+ if (use_inet6) {
+ if (IP6_EQ(&ap->st_src, &bp->st_src))
+ return 0;
+ else if (IP6_GT(&ap->st_src, &bp->st_src))
+ return 1;
+ } else
+#endif
+ {
+ if (ntohl(ap->st_src.in4.s_addr) ==
+ ntohl(bp->st_src.in4.s_addr))
+ return 0;
+ else if (ntohl(ap->st_src.in4.s_addr) >
+ ntohl(bp->st_src.in4.s_addr))
+ return 1;
+ }
+ return -1;
+}
+
+static int sort_srcpt(a, b)
+ const void *a;
+ const void *b;
+{
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+ if (htons(ap->st_sport) == htons(bp->st_sport))
+ return 0;
+ else if (htons(ap->st_sport) > htons(bp->st_sport))
+ return 1;
+ return -1;
+}
+
+static int sort_dstip(a, b)
+ const void *a;
+ const void *b;
+{
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+#ifdef USE_INET6
+ if (use_inet6) {
+ if (IP6_EQ(&ap->st_dst, &bp->st_dst))
+ return 0;
+ else if (IP6_GT(&ap->st_dst, &bp->st_dst))
+ return 1;
+ } else
+#endif
+ {
+ if (ntohl(ap->st_dst.in4.s_addr) ==
+ ntohl(bp->st_dst.in4.s_addr))
+ return 0;
+ else if (ntohl(ap->st_dst.in4.s_addr) >
+ ntohl(bp->st_dst.in4.s_addr))
+ return 1;
+ }
+ return -1;
+}
+
+static int sort_dstpt(a, b)
+ const void *a;
+ const void *b;
+{
+ register const statetop_t *ap = a;
+ register const statetop_t *bp = b;
+
+ if (htons(ap->st_dport) == htons(bp->st_dport))
+ return 0;
+ else if (htons(ap->st_dport) > htons(bp->st_dport))
+ return 1;
+ return -1;
+}
+
+#endif
+
+
+ipstate_t *fetchstate(src, dst)
+ ipstate_t *src, *dst;
+{
+
+ if (live_kernel == 1) {
+ ipfgeniter_t state;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_GENITER;
+ obj.ipfo_size = sizeof(state);
+ obj.ipfo_ptr = &state;
+
+ state.igi_type = IPFGENITER_STATE;
+ state.igi_nitems = 1;
+ state.igi_data = dst;
+
+ if (ioctl(state_fd, SIOCGENITER, &obj) != 0)
+ return NULL;
+ if (dst->is_next == NULL) {
+ int n = IPFGENITER_STATE;
+ (void) ioctl(ipf_fd,SIOCIPFDELTOK, &n);
+ }
+ } else {
+ if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst)))
+ return NULL;
+ }
+ return dst;
+}
+
+
+static int fetchfrag(fd, type, frp)
+ int fd, type;
+ ipfr_t *frp;
+{
+ ipfgeniter_t frag;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_GENITER;
+ obj.ipfo_size = sizeof(frag);
+ obj.ipfo_ptr = &frag;
+
+ frag.igi_type = type;
+ frag.igi_nitems = 1;
+ frag.igi_data = frp;
+
+ if (ioctl(fd, SIOCGENITER, &obj))
+ return EFAULT;
+ return 0;
+}
+
+
+static int state_matcharray(stp, array)
+ ipstate_t *stp;
+ int *array;
+{
+ int i, n, *x, rv, p;
+ ipfexp_t *e;
+
+ rv = 0;
+
+ for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) {
+ e = (ipfexp_t *)x;
+ if (e->ipfe_cmd == IPF_EXP_END)
+ break;
+ n -= e->ipfe_size;
+
+ rv = 0;
+ /*
+ * The upper 16 bits currently store the protocol value.
+ * This is currently used with TCP and UDP port compares and
+ * allows "tcp.port = 80" without requiring an explicit
+ " "ip.pr = tcp" first.
+ */
+ p = e->ipfe_cmd >> 16;
+ if ((p != 0) && (p != stp->is_p))
+ break;
+
+ switch (e->ipfe_cmd)
+ {
+ case IPF_EXP_IP_PR :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (stp->is_p == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_IP_SRCADDR :
+ if (stp->is_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((stp->is_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_DSTADDR :
+ if (stp->is_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((stp->is_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_ADDR :
+ if (stp->is_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((stp->is_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((stp->is_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+#ifdef USE_INET6
+ case IPF_EXP_IP6_SRCADDR :
+ if (stp->is_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&stp->is_src,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_DSTADDR :
+ if (stp->is_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&stp->is_dst,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_ADDR :
+ if (stp->is_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&stp->is_src,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&stp->is_dst,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+#endif
+
+ case IPF_EXP_UDP_PORT :
+ case IPF_EXP_TCP_PORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (stp->is_sport == e->ipfe_arg0[i]) ||
+ (stp->is_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_SPORT :
+ case IPF_EXP_TCP_SPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (stp->is_sport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_DPORT :
+ case IPF_EXP_TCP_DPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (stp->is_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_IDLE_GT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (stp->is_die < e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_TCP_STATE :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (stp->is_state[0] == e->ipfe_arg0[i]) ||
+ (stp->is_state[1] == e->ipfe_arg0[i]);
+ }
+ break;
+ }
+ rv ^= e->ipfe_not;
+
+ if (rv == 0)
+ break;
+ }
+
+ return rv;
+}
+
+
+static void showtqtable_live(fd)
+ int fd;
+{
+ ipftq_t table[IPF_TCP_NSTATES];
+ ipfobj_t obj;
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(table);
+ obj.ipfo_ptr = (void *)table;
+ obj.ipfo_type = IPFOBJ_STATETQTAB;
+
+ if (ioctl(fd, SIOCGTQTAB, &obj) == 0) {
+ printtqtable(table);
+ }
+}
diff --git a/contrib/ipfilter/tools/ipfsyncd.c b/contrib/ipfilter/tools/ipfsyncd.c
new file mode 100644
index 0000000..d4671e4
--- /dev/null
+++ b/contrib/ipfilter/tools/ipfsyncd.c
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id: ipfsyncd.c,v 1.1.2.2 2012/07/22 08:04:24 darren_r Exp $";
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/sockio.h>
+#include <sys/errno.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+
+#include "ipf.h"
+#include "opts.h"
+
+
+#define R_IO_ERROR -1
+#define R_OKAY 0
+#define R_MORE 1
+#define R_SKIP 2
+#if defined(sun) && !defined(SOLARIS2)
+# define STRERROR(x) sys_errlist[x]
+extern char *sys_errlist[];
+#else
+# define STRERROR(x) strerror(x)
+#endif
+
+
+int main __P((int, char *[]));
+void usage __P((char *));
+void printsynchdr __P((synchdr_t *));
+void printtable __P((int));
+void printsmcproto __P((char *));
+void printcommand __P((int));
+int do_kbuff __P((int, char *, int *));
+int do_packet __P((int, char *));
+int buildsocket __P((char *, struct sockaddr_in *));
+void do_io __P((void));
+void handleterm __P((int));
+
+int terminate = 0;
+int igmpfd = -1;
+int nfd = -1;
+int lfd = -1;
+int opts = 0;
+
+void
+usage(progname)
+ char *progname;
+{
+ fprintf(stderr,
+ "Usage: %s [-d] [-p port] [-i address] -I <interface>\n",
+ progname);
+}
+
+void
+handleterm(sig)
+ int sig;
+{
+ terminate = sig;
+}
+
+
+/* should be large enough to hold header + any datatype */
+#define BUFFERLEN 1400
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin;
+ char *interface;
+ char *progname;
+ int opt, tries;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) {
+ progname++;
+ } else {
+ progname = argv[0];
+ }
+
+ opts = 0;
+ tries = 0;
+ interface = NULL;
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(0xaf6c);
+ sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066);
+
+ while ((opt = getopt(argc, argv, "di:I:p:")) != -1)
+ switch (opt)
+ {
+ case 'd' :
+ debuglevel++;
+ break;
+ case 'I' :
+ interface = optarg;
+ break;
+ case 'i' :
+ sin.sin_addr.s_addr = inet_addr(optarg);
+ break;
+ case 'p' :
+ sin.sin_port = htons(atoi(optarg));
+ break;
+ }
+
+ if (interface == NULL) {
+ usage(progname);
+ exit(1);
+ }
+
+ if (!debuglevel) {
+
+#if BSD >= 199306
+ daemon(0, 0);
+#else
+ int fd = open("/dev/null", O_RDWR);
+
+ switch (fork())
+ {
+ case 0 :
+ break;
+
+ case -1 :
+ fprintf(stderr, "%s: fork() failed: %s\n",
+ argv[0], STRERROR(errno));
+ exit(1);
+ /* NOTREACHED */
+
+ default :
+ exit(0);
+ /* NOTREACHED */
+ }
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+
+ setsid();
+#endif
+ }
+
+ signal(SIGHUP, handleterm);
+ signal(SIGINT, handleterm);
+ signal(SIGTERM, handleterm);
+
+ openlog(progname, LOG_PID, LOG_SECURITY);
+
+ while (!terminate) {
+ if (lfd != -1) {
+ close(lfd);
+ lfd = -1;
+ }
+ if (nfd != -1) {
+ close(nfd);
+ nfd = -1;
+ }
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+
+ if (buildsocket(interface, &sin) == -1)
+ goto tryagain;
+
+ lfd = open(IPSYNC_NAME, O_RDWR);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME);
+ debug(1, "open(%s): %s\n", IPSYNC_NAME,
+ STRERROR(errno));
+ goto tryagain;
+ }
+
+ tries = -1;
+ do_io();
+tryagain:
+ tries++;
+ syslog(LOG_INFO, "retry in %d seconds", 1 << tries);
+ debug(1, "wait %d seconds\n", 1 << tries);
+ sleep(1 << tries);
+ }
+
+
+ /* terminate */
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ syslog(LOG_ERR, "signal %d received, exiting...", terminate);
+ debug(1, "signal %d received, exiting...", terminate);
+
+ exit(1);
+}
+
+
+void
+do_io()
+{
+ char nbuff[BUFFERLEN];
+ char buff[BUFFERLEN];
+ fd_set mrd, rd;
+ int maxfd;
+ int inbuf;
+ int n1;
+ int left;
+
+ FD_ZERO(&mrd);
+ FD_SET(lfd, &mrd);
+ FD_SET(nfd, &mrd);
+ maxfd = nfd;
+ if (lfd > maxfd)
+ maxfd = lfd;
+ debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd);
+
+ inbuf = 0;
+ /*
+ * A threaded approach to this loop would have one thread
+ * work on reading lfd (only) all the time and another thread
+ * working on reading nfd all the time.
+ */
+ while (!terminate) {
+ int n;
+
+ rd = mrd;
+
+ n = select(maxfd + 1, &rd, NULL, NULL, NULL);
+ if (n < 0) {
+ switch (errno)
+ {
+ case EINTR :
+ continue;
+ default :
+ syslog(LOG_ERR, "select error: %m");
+ debug(1, "select error: %s\n", STRERROR(errno));
+ return;
+ }
+ }
+
+ if (FD_ISSET(lfd, &rd)) {
+ n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
+
+ debug(3, "read(K):%d\n", n1);
+
+ if (n1 <= 0) {
+ syslog(LOG_ERR, "read error (k-header): %m");
+ debug(1, "read error (k-header): %s\n",
+ STRERROR(errno));
+ return;
+ }
+
+ left = 0;
+
+ switch (do_kbuff(n1, buff, &left))
+ {
+ case R_IO_ERROR :
+ return;
+ case R_MORE :
+ inbuf += left;
+ break;
+ default :
+ inbuf = 0;
+ break;
+ }
+ }
+
+ if (FD_ISSET(nfd, &rd)) {
+ n1 = recv(nfd, nbuff, sizeof(nbuff), 0);
+
+ debug(3, "read(N):%d\n", n1);
+
+ if (n1 <= 0) {
+ syslog(LOG_ERR, "read error (n-header): %m");
+ debug(1, "read error (n-header): %s\n",
+ STRERROR(errno));
+ return;
+ }
+
+ switch (do_packet(n1, nbuff))
+ {
+ case R_IO_ERROR :
+ return;
+ default :
+ break;
+ }
+ }
+ }
+}
+
+
+int
+buildsocket(nicname, sinp)
+ char *nicname;
+ struct sockaddr_in *sinp;
+{
+ struct sockaddr_in *reqip;
+ struct ifreq req;
+ char opt;
+
+ debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr));
+
+ if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) {
+ struct in_addr addr;
+ struct ip_mreq mreq;
+
+ igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
+ if (igmpfd == -1) {
+ syslog(LOG_ERR, "socket:%m");
+ debug(1, "socket:%s\n", STRERROR(errno));
+ return -1;
+ }
+
+ bzero((char *)&req, sizeof(req));
+ strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
+ req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
+ if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
+ debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+ reqip = (struct sockaddr_in *)&req.ifr_addr;
+
+ addr = reqip->sin_addr;
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF,
+ (char *)&addr, sizeof(addr)) == -1) {
+ syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m",
+ inet_ntoa(addr));
+ debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n",
+ inet_ntoa(addr), STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ opt = 0;
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ (char *)&opt, sizeof(opt)) == -1) {
+ syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m");
+ debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n",
+ STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ opt = 63;
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&opt, sizeof(opt)) == -1) {
+ syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m",
+ opt);
+ debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt,
+ STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = reqip->sin_addr.s_addr;
+
+ if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) == -1) {
+ char buffer[80];
+
+ sprintf(buffer, "%s,", inet_ntoa(sinp->sin_addr));
+ strcat(buffer, inet_ntoa(reqip->sin_addr));
+
+ syslog(LOG_ERR,
+ "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer);
+ debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n",
+ buffer, STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+ }
+ nfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (nfd == -1) {
+ syslog(LOG_ERR, "socket:%m");
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+ return -1;
+ }
+ bzero((char *)&req, sizeof(req));
+ strncpy(req.ifr_name, nicname, sizeof(req.ifr_name));
+ req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
+ if (ioctl(nfd, SIOCGIFADDR, &req) == -1) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m");
+ debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno));
+ close(igmpfd);
+ igmpfd = -1;
+ return -1;
+ }
+
+ if (bind(nfd, (struct sockaddr *)&req.ifr_addr,
+ sizeof(req.ifr_addr)) == -1) {
+ syslog(LOG_ERR, "bind:%m");
+ debug(1, "bind:%s\n", STRERROR(errno));
+ close(nfd);
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+ nfd = -1;
+ return -1;
+ }
+
+ if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) {
+ syslog(LOG_ERR, "connect:%m");
+ debug(1, "connect:%s\n", STRERROR(errno));
+ close(nfd);
+ if (igmpfd != -1) {
+ close(igmpfd);
+ igmpfd = -1;
+ }
+ nfd = -1;
+ return -1;
+ }
+ syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr));
+ debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr));
+
+ return nfd;
+}
+
+
+int
+do_packet(pklen, buff)
+ int pklen;
+ char *buff;
+{
+ synchdr_t *sh;
+ u_32_t magic;
+ int len;
+ int n2;
+ int n3;
+
+ while (pklen > 0) {
+ if (pklen < sizeof(*sh)) {
+ syslog(LOG_ERR, "packet length too short:%d", pklen);
+ debug(2, "packet length too short:%d\n", pklen);
+ return R_SKIP;
+ }
+
+ sh = (synchdr_t *)buff;
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR, "invalid header magic %x", magic);
+ debug(2, "invalid header magic %x\n", magic);
+ return R_SKIP;
+ }
+
+ if (pklen < len + sizeof(*sh)) {
+ syslog(LOG_ERR, "packet length too short:%d", pklen);
+ debug(2, "packet length too short:%d\n", pklen);
+ return R_SKIP;
+ }
+
+ if (debuglevel > 3) {
+ printsynchdr(sh);
+ printcommand(sh->sm_cmd);
+ printtable(sh->sm_table);
+ printsmcproto(buff);
+ }
+
+ n2 = sizeof(*sh) + len;
+
+ do {
+ n3 = write(lfd, buff, n2);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "write error: %m");
+ debug(1, "write error: %s\n", STRERROR(errno));
+ return R_IO_ERROR;
+ }
+
+ n2 -= n3;
+ buff += n3;
+ pklen -= n3;
+ } while (n3 != 0);
+ }
+
+ return R_OKAY;
+}
+
+
+
+int
+do_kbuff(inbuf, buf, left)
+ int inbuf, *left;
+ char *buf;
+{
+ synchdr_t *sh;
+ u_32_t magic;
+ int complete;
+ int sendlen;
+ int error;
+ int bytes;
+ int len;
+ int n2;
+ int n3;
+
+ sendlen = 0;
+ bytes = inbuf;
+ error = R_OKAY;
+ sh = (synchdr_t *)buf;
+
+ for (complete = 0; bytes > 0; complete++) {
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR,
+ "read invalid header magic 0x%x, flushing",
+ magic);
+ debug(2, "read invalid header magic 0x%x, flushing\n",
+ magic);
+ n2 = SMC_RLOG;
+ (void) ioctl(lfd, SIOCIPFFL, &n2);
+ break;
+ }
+
+ if (debuglevel > 3) {
+ printsynchdr(sh);
+ printcommand(sh->sm_cmd);
+ printtable(sh->sm_table);
+ putchar('\n');
+ }
+
+ if (bytes < sizeof(*sh) + len) {
+ debug(3, "Not enough bytes %d < %d\n", bytes,
+ sizeof(*sh) + len);
+ error = R_MORE;
+ break;
+ }
+
+ if (debuglevel > 3) {
+ printsmcproto(buf);
+ }
+
+ sendlen += len + sizeof(*sh);
+ sh = (synchdr_t *)(buf + sendlen);
+ bytes -= sendlen;
+ }
+
+ if (complete) {
+ n3 = send(nfd, buf, sendlen, 0);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "write error: %m");
+ debug(1, "write error: %s\n", STRERROR(errno));
+ return R_IO_ERROR;
+ }
+ debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3);
+ error = R_OKAY;
+ }
+
+ /* move buffer to the front,we might need to make
+ * this more efficient, by using a rolling pointer
+ * over the buffer and only copying it, when
+ * we are reaching the end
+ */
+ if (bytes > 0) {
+ bcopy(buf + bytes, buf, bytes);
+ error = R_MORE;
+ }
+ debug(4, "complete %d bytes %d error %d\n", complete, bytes, error);
+
+ *left = bytes;
+
+ return error;
+}
+
+
+void
+printcommand(cmd)
+ int cmd;
+{
+
+ switch (cmd)
+ {
+ case SMC_CREATE :
+ printf(" cmd:CREATE");
+ break;
+ case SMC_UPDATE :
+ printf(" cmd:UPDATE");
+ break;
+ default :
+ printf(" cmd:Unknown(%d)", cmd);
+ break;
+ }
+}
+
+
+void
+printtable(table)
+ int table;
+{
+ switch (table)
+ {
+ case SMC_NAT :
+ printf(" table:NAT");
+ break;
+ case SMC_STATE :
+ printf(" table:STATE");
+ break;
+ default :
+ printf(" table:Unknown(%d)", table);
+ break;
+ }
+}
+
+
+void
+printsmcproto(buff)
+ char *buff;
+{
+ syncupdent_t *su;
+ synchdr_t *sh;
+
+ sh = (synchdr_t *)buff;
+
+ if (sh->sm_cmd == SMC_CREATE) {
+ ;
+
+ } else if (sh->sm_cmd == SMC_UPDATE) {
+ su = (syncupdent_t *)buff;
+ if (sh->sm_p == IPPROTO_TCP) {
+ printf(" TCP Update: age %lu state %d/%d\n",
+ su->sup_tcp.stu_age,
+ su->sup_tcp.stu_state[0],
+ su->sup_tcp.stu_state[1]);
+ }
+ } else {
+ printf("Unknown command\n");
+ }
+}
+
+
+void
+printsynchdr(sh)
+ synchdr_t *sh;
+{
+
+ printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p,
+ ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic));
+}
diff --git a/contrib/ipfilter/tools/ipftest.c b/contrib/ipfilter/tools/ipftest.c
new file mode 100644
index 0000000..378523d
--- /dev/null
+++ b/contrib/ipfilter/tools/ipftest.c
@@ -0,0 +1,874 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include "ipf.h"
+#include "ipt.h"
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+extern char *optarg;
+extern struct ipread pcap, iptext, iphex;
+extern struct ifnet *get_unit __P((char *, int));
+extern void init_ifp __P((void));
+extern ipnat_t *natparse __P((char *, int));
+extern hostmap_t **ipf_hm_maptable;
+extern hostmap_t *ipf_hm_maplist;
+
+ipfmutex_t ipl_mutex, ipf_auth_mx, ipf_rw, ipf_stinsert;
+ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock;
+ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ip_poolrw, ipf_frcache;
+ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_authlk;
+ipfrwlock_t ipf_tokens;
+int opts = OPT_DONTOPEN;
+int use_inet6 = 0;
+int docksum = 0;
+int pfil_delayed_copy = 0;
+int main __P((int, char *[]));
+int loadrules __P((char *, int));
+int kmemcpy __P((char *, long, int));
+int kstrncpy __P((char *, long, int n));
+int blockreason;
+void dumpnat __P((void *));
+void dumpgroups __P((ipf_main_softc_t *));
+void dumprules __P((frentry_t *));
+void drain_log __P((char *));
+void fixv4sums __P((mb_t *, ip_t *));
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \
+ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
+ defined(__osf__) || defined(linux)
+int ipftestioctl __P((int, ioctlcmd_t, ...));
+int ipnattestioctl __P((int, ioctlcmd_t, ...));
+int ipstatetestioctl __P((int, ioctlcmd_t, ...));
+int ipauthtestioctl __P((int, ioctlcmd_t, ...));
+int ipscantestioctl __P((int, ioctlcmd_t, ...));
+int ipsynctestioctl __P((int, ioctlcmd_t, ...));
+int ipooltestioctl __P((int, ioctlcmd_t, ...));
+#else
+int ipftestioctl __P((dev_t, ioctlcmd_t, void *));
+int ipnattestioctl __P((dev_t, ioctlcmd_t, void *));
+int ipstatetestioctl __P((dev_t, ioctlcmd_t, void *));
+int ipauthtestioctl __P((dev_t, ioctlcmd_t, void *));
+int ipsynctestioctl __P((dev_t, ioctlcmd_t, void *));
+int ipscantestioctl __P((dev_t, ioctlcmd_t, void *));
+int ipooltestioctl __P((dev_t, ioctlcmd_t, void *));
+#endif
+
+static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ipftestioctl,
+ ipnattestioctl,
+ ipstatetestioctl,
+ ipauthtestioctl,
+ ipsynctestioctl,
+ ipscantestioctl,
+ ipooltestioctl,
+ NULL };
+static ipf_main_softc_t *softc = NULL;
+
+
+int
+main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ char *datain, *iface, *ifname, *logout;
+ int fd, i, dir, c, loaded, dump, hlen;
+ struct in_addr sip;
+ struct ifnet *ifp;
+ struct ipread *r;
+ mb_t mb, *m, *n;
+ ip_t *ip;
+
+ m = &mb;
+ dir = 0;
+ dump = 0;
+ hlen = 0;
+ loaded = 0;
+ r = &iptext;
+ iface = NULL;
+ logout = NULL;
+ datain = NULL;
+ sip.s_addr = 0;
+ ifname = "anon0";
+
+ initparse();
+
+ ipf_load_all();
+
+ softc = ipf_create_all(NULL);
+ if (softc == NULL)
+ exit(1);
+
+ if (ipf_init_all(softc) == -1)
+ exit(1);
+
+ i = 1;
+ if (ipftestioctl(IPL_LOGIPF, SIOCFRENB, &i) != 0)
+ exit(1);
+
+ while ((c = getopt(argc, argv, "6bCdDF:i:I:l:N:P:or:RS:T:vxX")) != -1)
+ switch (c)
+ {
+ case '6' :
+#ifdef USE_INET6
+ use_inet6 = 1;
+#else
+ fprintf(stderr, "IPv6 not supported\n");
+ exit(1);
+#endif
+ break;
+ case 'b' :
+ opts |= OPT_BRIEF;
+ break;
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'C' :
+ docksum = 1;
+ break;
+ case 'D' :
+ dump = 1;
+ break;
+ case 'F' :
+ if (strcasecmp(optarg, "pcap") == 0)
+ r = &pcap;
+ else if (strcasecmp(optarg, "hex") == 0)
+ r = &iphex;
+ else if (strcasecmp(optarg, "text") == 0)
+ r = &iptext;
+ break;
+ case 'i' :
+ datain = optarg;
+ break;
+ case 'I' :
+ ifname = optarg;
+ break;
+ case 'l' :
+ logout = optarg;
+ break;
+ case 'N' :
+ if (ipnat_parsefile(-1, ipnat_addrule, ipnattestioctl,
+ optarg) == -1)
+ return -1;
+ loaded = 1;
+ opts |= OPT_NAT;
+ break;
+ case 'o' :
+ opts |= OPT_SAVEOUT;
+ break;
+ case 'P' :
+ if (ippool_parsefile(-1, optarg, ipooltestioctl) == -1)
+ return -1;
+ loaded = 1;
+ break;
+ case 'r' :
+ if (ipf_parsefile(-1, ipf_addrule, iocfunctions,
+ optarg) == -1)
+ return -1;
+ loaded = 1;
+ break;
+ case 'S' :
+ sip.s_addr = inet_addr(optarg);
+ break;
+ case 'R' :
+ opts |= OPT_NORESOLVE;
+ break;
+ case 'T' :
+ ipf_dotuning(-1, optarg, ipftestioctl);
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ case 'x' :
+ opts |= OPT_HEX;
+ break;
+ }
+
+ if (loaded == 0) {
+ (void)fprintf(stderr,"no rules loaded\n");
+ exit(-1);
+ }
+
+ if (opts & OPT_SAVEOUT)
+ init_ifp();
+
+ if (datain)
+ fd = (*r->r_open)(datain);
+ else
+ fd = (*r->r_open)("-");
+
+ if (fd < 0) {
+ perror("error opening input");
+ exit(-1);
+ }
+
+ m->m_data = (char *)m->mb_buf;
+ while ((i = (*r->r_readip)(m, &iface, &dir)) > 0) {
+
+ if ((iface == NULL) || (*iface == '\0'))
+ iface = ifname;
+
+ ip = MTOD(m, ip_t *);
+ ifp = get_unit(iface, IP_V(ip));
+
+ if (IP_V(ip) == 4) {
+ if ((r->r_flags & R_DO_CKSUM) || docksum)
+ fixv4sums(m, ip);
+ hlen = IP_HL(ip) << 2;
+ if (sip.s_addr)
+ dir = !(sip.s_addr == ip->ip_src.s_addr);
+ }
+#ifdef USE_INET6
+ else
+ hlen = sizeof(ip6_t);
+#endif
+ /* ipfr_slowtimer(); */
+ blockreason = 0;
+ m = &mb;
+ m->mb_ifp = ifp;
+ m->mb_len = i;
+ i = ipf_check(softc, ip, hlen, ifp, dir, &m);
+ if ((opts & OPT_NAT) == 0)
+ switch (i)
+ {
+ case -4 :
+ (void)printf("preauth");
+ break;
+ case -3 :
+ (void)printf("account");
+ break;
+ case -2 :
+ (void)printf("auth");
+ break;
+ case -1 :
+ (void)printf("block");
+ break;
+ case 0 :
+ (void)printf("pass");
+ break;
+ case 1 :
+ if (m == NULL)
+ (void)printf("bad-packet");
+ else
+ (void)printf("nomatch");
+ break;
+ case 3 :
+ (void)printf("block return-rst");
+ break;
+ case 4 :
+ (void)printf("block return-icmp");
+ break;
+ case 5 :
+ (void)printf("block return-icmp-as-dest");
+ break;
+ default :
+ (void)printf("recognised return %#x\n", i);
+ break;
+ }
+
+ if (!(opts & OPT_BRIEF)) {
+ putchar(' ');
+ if (m != NULL)
+ printpacket(dir, m);
+ else
+ printpacket(dir, &mb);
+ printf("--------------");
+ } else if ((opts & (OPT_BRIEF|OPT_NAT)) ==
+ (OPT_NAT|OPT_BRIEF)) {
+ if (m != NULL)
+ printpacket(dir, m);
+ else
+ PRINTF("%d\n", blockreason);
+ }
+
+ ipf_state_flush(softc, 1, 0);
+
+ if (dir && (ifp != NULL) && IP_V(ip) && (m != NULL))
+#if defined(__sgi) && (IRIX < 60500)
+ (*ifp->if_output)(ifp, (void *)m, NULL);
+#else
+# if TRU64 >= 1885
+ (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0);
+# else
+ (*ifp->if_output)(ifp, (void *)m, NULL, 0);
+# endif
+#endif
+
+ while ((m != NULL) && (m != &mb)) {
+ n = m->mb_next;
+ freembt(m);
+ m = n;
+ }
+
+ if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF))
+ putchar('\n');
+ dir = 0;
+ if (iface != ifname) {
+ free(iface);
+ iface = ifname;
+ }
+ m = &mb;
+ m->mb_data = (char *)m->mb_buf;
+ }
+
+ if (i != 0)
+ fprintf(stderr, "readip failed: %d\n", i);
+ (*r->r_close)();
+
+ if (logout != NULL) {
+ drain_log(logout);
+ }
+
+ if (dump == 1) {
+ dumpnat(softc->ipf_nat_soft);
+ ipf_state_dump(softc, softc->ipf_state_soft);
+ ipf_lookup_dump(softc, softc->ipf_state_soft);
+ dumpgroups(softc);
+ }
+
+ ipf_fini_all(softc);
+
+ ipf_destroy_all(softc);
+
+ ipf_unload_all();
+
+ ipf_mutex_clean();
+ ipf_rwlock_clean();
+
+ if (getenv("FINDLEAKS")) {
+ fflush(stdout);
+ abort();
+ }
+ return 0;
+}
+
+
+#if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \
+ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
+ defined(__osf__) || defined(linux)
+int ipftestioctl(int dev, ioctlcmd_t cmd, ...)
+{
+ caddr_t data;
+ va_list ap;
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ va_start(ap, cmd);
+ data = va_arg(ap, caddr_t);
+ va_end(ap);
+
+ i = ipfioctl(softc, IPL_LOGIPF, cmd, data, FWRITE|FREAD);
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "ipfioctl(IPF,%#x,%p) = %d (%d)\n",
+ (u_int)cmd, data, i, softc->ipf_interror);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipnattestioctl(int dev, ioctlcmd_t cmd, ...)
+{
+ caddr_t data;
+ va_list ap;
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ va_start(ap, cmd);
+ data = va_arg(ap, caddr_t);
+ va_end(ap);
+
+ i = ipfioctl(softc, IPL_LOGNAT, cmd, data, FWRITE|FREAD);
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "ipfioctl(NAT,%#x,%p) = %d\n",
+ (u_int)cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipstatetestioctl(int dev, ioctlcmd_t cmd, ...)
+{
+ caddr_t data;
+ va_list ap;
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ va_start(ap, cmd);
+ data = va_arg(ap, caddr_t);
+ va_end(ap);
+
+ i = ipfioctl(softc, IPL_LOGSTATE, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(STATE,%#x,%p) = %d\n",
+ (u_int)cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipauthtestioctl(int dev, ioctlcmd_t cmd, ...)
+{
+ caddr_t data;
+ va_list ap;
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ va_start(ap, cmd);
+ data = va_arg(ap, caddr_t);
+ va_end(ap);
+
+ i = ipfioctl(softc, IPL_LOGAUTH, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(AUTH,%#x,%p) = %d\n",
+ (u_int)cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipscantestioctl(int dev, ioctlcmd_t cmd, ...)
+{
+ caddr_t data;
+ va_list ap;
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ va_start(ap, cmd);
+ data = va_arg(ap, caddr_t);
+ va_end(ap);
+
+ i = ipfioctl(softc, IPL_LOGSCAN, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(SCAN,%#x,%p) = %d\n",
+ (u_int)cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipsynctestioctl(int dev, ioctlcmd_t cmd, ...)
+{
+ caddr_t data;
+ va_list ap;
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ va_start(ap, cmd);
+ data = va_arg(ap, caddr_t);
+ va_end(ap);
+
+ i = ipfioctl(softc, IPL_LOGSYNC, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(SYNC,%#x,%p) = %d\n",
+ (u_int)cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipooltestioctl(int dev, ioctlcmd_t cmd, ...)
+{
+ caddr_t data;
+ va_list ap;
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ va_start(ap, cmd);
+ data = va_arg(ap, caddr_t);
+ va_end(ap);
+
+ i = ipfioctl(softc, IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(POOL,%#x,%p) = %d (%d)\n",
+ (u_int)cmd, data, i, softc->ipf_interror);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+#else
+int ipftestioctl(dev, cmd, data)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ void *data;
+{
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ i = ipfioctl(softc, IPL_LOGIPF, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(IPF,%#x,%p) = %d (%d)\n",
+ cmd, data, i, softc->ipf_interror);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipnattestioctl(dev, cmd, data)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ void *data;
+{
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ i = ipfioctl(softc, IPL_LOGNAT, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(NAT,%#x,%p) = %d\n", cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipstatetestioctl(dev, cmd, data)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ void *data;
+{
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ i = ipfioctl(softc, IPL_LOGSTATE, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(STATE,%#x,%p) = %d\n", cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipauthtestioctl(dev, cmd, data)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ void *data;
+{
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ i = ipfioctl(softc, IPL_LOGAUTH, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(AUTH,%#x,%p) = %d\n", cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipsynctestioctl(dev, cmd, data)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ void *data;
+{
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ i = ipfioctl(softc, IPL_LOGSYNC, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(SYNC,%#x,%p) = %d\n", cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipscantestioctl(dev, cmd, data)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ void *data;
+{
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ i = ipfioctl(softc, IPL_LOGSCAN, cmd, data, FWRITE|FREAD);
+ if ((opts & OPT_DEBUG) || (i != 0))
+ fprintf(stderr, "ipfioctl(SCAN,%#x,%p) = %d\n", cmd, data, i);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+
+
+int ipooltestioctl(dev, cmd, data)
+ dev_t dev;
+ ioctlcmd_t cmd;
+ void *data;
+{
+ int i;
+
+ dev = dev; /* gcc -Wextra */
+ i = ipfioctl(softc, IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD);
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "ipfioctl(POOL,%#x,%p) = %d (%d)\n",
+ cmd, data, i, softc->ipf_interror);
+ if (i != 0) {
+ errno = i;
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+
+int kmemcpy(addr, offset, size)
+ char *addr;
+ long offset;
+ int size;
+{
+ bcopy((char *)offset, addr, size);
+ return 0;
+}
+
+
+int kstrncpy(buf, pos, n)
+ char *buf;
+ long pos;
+ int n;
+{
+ char *ptr;
+
+ ptr = (char *)pos;
+
+ while ((n > 0) && (*buf++ = *ptr++))
+ ;
+ return 0;
+}
+
+
+/*
+ * Display the built up NAT table rules and mapping entries.
+ */
+void dumpnat(arg)
+ void *arg;
+{
+ ipf_nat_softc_t *softn = arg;
+ hostmap_t *hm;
+ ipnat_t *ipn;
+ nat_t *nat;
+
+ printf("List of active MAP/Redirect filters:\n");
+ for (ipn = softn->ipf_nat_list; ipn != NULL; ipn = ipn->in_next)
+ printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
+ printf("\nList of active sessions:\n");
+ for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
+ printactivenat(nat, opts, 0);
+ if (nat->nat_aps)
+ printf("\tproxy active\n");
+ }
+
+ printf("\nHostmap table:\n");
+ for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next)
+ printhostmap(hm, hm->hm_hv);
+}
+
+
+void dumpgroups(softc)
+ ipf_main_softc_t *softc;
+{
+ frgroup_t *fg;
+ int i;
+
+ printf("List of groups configured (set 0)\n");
+ for (i = 0; i < IPL_LOGSIZE; i++)
+ for (fg = softc->ipf_groups[i][0]; fg != NULL;
+ fg = fg->fg_next) {
+ printf("Dev.%d. Group %s Ref %d Flags %#x\n",
+ i, fg->fg_name, fg->fg_ref, fg->fg_flags);
+ dumprules(fg->fg_start);
+ }
+
+ printf("List of groups configured (set 1)\n");
+ for (i = 0; i < IPL_LOGSIZE; i++)
+ for (fg = softc->ipf_groups[i][1]; fg != NULL;
+ fg = fg->fg_next) {
+ printf("Dev.%d. Group %s Ref %d Flags %#x\n",
+ i, fg->fg_name, fg->fg_ref, fg->fg_flags);
+ dumprules(fg->fg_start);
+ }
+
+ printf("Rules configured (set 0, in)\n");
+ dumprules(softc->ipf_rules[0][0]);
+ printf("Rules configured (set 0, out)\n");
+ dumprules(softc->ipf_rules[1][0]);
+ printf("Rules configured (set 1, in)\n");
+ dumprules(softc->ipf_rules[0][1]);
+ printf("Rules configured (set 1, out)\n");
+ dumprules(softc->ipf_rules[1][1]);
+
+ printf("Accounting rules configured (set 0, in)\n");
+ dumprules(softc->ipf_acct[0][0]);
+ printf("Accounting rules configured (set 0, out)\n");
+ dumprules(softc->ipf_acct[0][1]);
+ printf("Accounting rules configured (set 1, in)\n");
+ dumprules(softc->ipf_acct[1][0]);
+ printf("Accounting rules configured (set 1, out)\n");
+ dumprules(softc->ipf_acct[1][1]);
+}
+
+void dumprules(rulehead)
+ frentry_t *rulehead;
+{
+ frentry_t *fr;
+
+ for (fr = rulehead; fr != NULL; fr = fr->fr_next) {
+#ifdef USE_QUAD_T
+ printf("%"PRIu64" ",(unsigned long long)fr->fr_hits);
+#else
+ printf("%ld ", fr->fr_hits);
+#endif
+ printfr(fr, ipftestioctl);
+ }
+}
+
+
+void drain_log(filename)
+ char *filename;
+{
+ char buffer[DEFAULT_IPFLOGSIZE];
+ struct iovec iov;
+ struct uio uio;
+ size_t resid;
+ int fd, i;
+
+ fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
+ if (fd == -1) {
+ perror("drain_log:open");
+ return;
+ }
+
+ for (i = 0; i <= IPL_LOGMAX; i++)
+ while (1) {
+ bzero((char *)&iov, sizeof(iov));
+ iov.iov_base = buffer;
+ iov.iov_len = sizeof(buffer);
+
+ bzero((char *)&uio, sizeof(uio));
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_resid = iov.iov_len;
+ resid = uio.uio_resid;
+
+ if (ipf_log_read(softc, i, &uio) == 0) {
+ /*
+ * If nothing was read then break out.
+ */
+ if (uio.uio_resid == resid)
+ break;
+ write(fd, buffer, resid - uio.uio_resid);
+ } else
+ break;
+ }
+
+ close(fd);
+}
+
+
+void fixv4sums(m, ip)
+ mb_t *m;
+ ip_t *ip;
+{
+ u_char *csump, *hdr, p;
+ fr_info_t tmp;
+ int len;
+
+ p = 0;
+ len = 0;
+ bzero((char *)&tmp, sizeof(tmp));
+
+ csump = (u_char *)ip;
+ if (IP_V(ip) == 4) {
+ ip->ip_sum = 0;
+ ip->ip_sum = ipf_cksum((u_short *)ip, IP_HL(ip) << 2);
+ tmp.fin_hlen = IP_HL(ip) << 2;
+ csump += IP_HL(ip) << 2;
+ p = ip->ip_p;
+ len = ntohs(ip->ip_len);
+#ifdef USE_INET6
+ } else if (IP_V(ip) == 6) {
+ tmp.fin_hlen = sizeof(ip6_t);
+ csump += sizeof(ip6_t);
+ p = ((ip6_t *)ip)->ip6_nxt;
+ len = ntohs(((ip6_t *)ip)->ip6_plen);
+ len += sizeof(ip6_t);
+#endif
+ }
+ tmp.fin_plen = len;
+ tmp.fin_dlen = len - tmp.fin_hlen;
+
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ hdr = csump;
+ csump += offsetof(tcphdr_t, th_sum);
+ break;
+ case IPPROTO_UDP :
+ hdr = csump;
+ csump += offsetof(udphdr_t, uh_sum);
+ break;
+ case IPPROTO_ICMP :
+ hdr = csump;
+ csump += offsetof(icmphdr_t, icmp_cksum);
+ break;
+ default :
+ csump = NULL;
+ hdr = NULL;
+ break;
+ }
+ if (hdr != NULL) {
+ tmp.fin_m = m;
+ tmp.fin_mp = &m;
+ tmp.fin_dp = hdr;
+ tmp.fin_ip = ip;
+ tmp.fin_plen = len;
+ *csump = 0;
+ *(u_short *)csump = fr_cksum(&tmp, ip, p, hdr);
+ }
+}
+
+void
+ip_fillid(struct ip *ip)
+{
+ static uint16_t ip_id;
+
+ ip->ip_id = ip_id++;
+}
diff --git a/contrib/ipfilter/tools/ipmon.c b/contrib/ipfilter/tools/ipmon.c
new file mode 100644
index 0000000..1c52e7f
--- /dev/null
+++ b/contrib/ipfilter/tools/ipmon.c
@@ -0,0 +1,1910 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include "ipf.h"
+#include "ipmon.h"
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#if !defined(lint)
+static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+#if defined(sun) && !defined(SOLARIS2)
+#define STRERROR(x) sys_errlist[x]
+extern char *sys_errlist[];
+#else
+#define STRERROR(x) strerror(x)
+#endif
+
+extern int optind;
+extern char *optarg;
+
+extern ipmon_saver_t executesaver;
+extern ipmon_saver_t filesaver;
+extern ipmon_saver_t nothingsaver;
+extern ipmon_saver_t snmpv1saver;
+extern ipmon_saver_t snmpv2saver;
+extern ipmon_saver_t syslogsaver;
+
+
+struct flags {
+ int value;
+ char flag;
+};
+
+typedef struct logsource {
+ int fd;
+ int logtype;
+ char *file;
+ int regular;
+ size_t size;
+} logsource_t;
+
+typedef struct config {
+ int opts;
+ int maxfd;
+ logsource_t logsrc[3];
+ fd_set fdmr;
+ FILE *blog;
+ char *bfile;
+ FILE *log;
+ char *file;
+ char *cfile;
+} config_t;
+
+typedef struct icmp_subtype {
+ int ist_val;
+ char *ist_name;
+} icmp_subtype_t;
+
+typedef struct icmp_type {
+ int it_val;
+ struct icmp_subtype *it_subtable;
+ size_t it_stsize;
+ char *it_name;
+} icmp_type_t;
+
+
+#define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t))
+
+
+struct flags tcpfl[] = {
+ { TH_ACK, 'A' },
+ { TH_RST, 'R' },
+ { TH_SYN, 'S' },
+ { TH_FIN, 'F' },
+ { TH_URG, 'U' },
+ { TH_PUSH,'P' },
+ { TH_ECN, 'E' },
+ { TH_CWR, 'C' },
+ { 0, '\0' }
+};
+
+char *reasons[] = {
+ "filter-rule",
+ "log-or-block_1",
+ "pps-rate",
+ "jumbogram",
+ "makefrip-fail",
+ "state_add-fail",
+ "updateipid-fail",
+ "log-or-block_2",
+ "decap-fail",
+ "auth_new-fail",
+ "auth_captured",
+ "coalesce-fail",
+ "pullup-fail",
+ "auth-feedback",
+ "bad-frag",
+ "natv4_out-fail",
+ "natv4_in-fail",
+ "natv6_out-fail",
+ "natv6_in-fail",
+};
+
+#ifdef MENTAT
+static char *pidfile = "/etc/opt/ipf/ipmon.pid";
+#else
+# if BSD >= 199306
+static char *pidfile = "/var/run/ipmon.pid";
+# else
+static char *pidfile = "/etc/ipmon.pid";
+# endif
+#endif
+
+static char line[2048];
+static int donehup = 0;
+static void usage __P((char *));
+static void handlehup __P((int));
+static void flushlogs __P((char *, FILE *));
+static void print_log __P((config_t *, logsource_t *, char *, int));
+static void print_ipflog __P((config_t *, char *, int));
+static void print_natlog __P((config_t *, char *, int));
+static void print_statelog __P((config_t *, char *, int));
+static int read_log __P((int, int *, char *, int));
+static void write_pid __P((char *));
+static char *icmpname __P((u_int, u_int));
+static char *icmpname6 __P((u_int, u_int));
+static icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t));
+static icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t));
+#ifdef __hpux
+static struct tm *get_tm __P((u_32_t));
+#else
+static struct tm *get_tm __P((time_t));
+#endif
+
+char *portlocalname __P((int, char *, u_int));
+int main __P((int, char *[]));
+
+static void logopts __P((int, char *));
+static void init_tabs __P((void));
+static char *getlocalproto __P((u_int));
+static void openlogs __P((config_t *conf));
+static int read_loginfo __P((config_t *conf));
+static void initconfig __P((config_t *conf));
+
+static char **protocols = NULL;
+static char **udp_ports = NULL;
+static char **tcp_ports = NULL;
+
+
+#define HOSTNAMEV4(b) hostname(AF_INET, (u_32_t *)&(b))
+
+#ifndef LOGFAC
+#define LOGFAC LOG_LOCAL0
+#endif
+int logfac = LOGFAC;
+int ipmonopts = 0;
+int opts = OPT_NORESOLVE;
+int use_inet6 = 0;
+
+
+static icmp_subtype_t icmpunreachnames[] = {
+ { ICMP_UNREACH_NET, "net" },
+ { ICMP_UNREACH_HOST, "host" },
+ { ICMP_UNREACH_PROTOCOL, "protocol" },
+ { ICMP_UNREACH_PORT, "port" },
+ { ICMP_UNREACH_NEEDFRAG, "needfrag" },
+ { ICMP_UNREACH_SRCFAIL, "srcfail" },
+ { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" },
+ { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" },
+ { ICMP_UNREACH_NET, "isolated" },
+ { ICMP_UNREACH_NET_PROHIB, "net_prohib" },
+ { ICMP_UNREACH_NET_PROHIB, "host_prohib" },
+ { ICMP_UNREACH_TOSNET, "tosnet" },
+ { ICMP_UNREACH_TOSHOST, "toshost" },
+ { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" },
+ { -2, NULL }
+};
+
+static icmp_subtype_t redirectnames[] = {
+ { ICMP_REDIRECT_NET, "net" },
+ { ICMP_REDIRECT_HOST, "host" },
+ { ICMP_REDIRECT_TOSNET, "tosnet" },
+ { ICMP_REDIRECT_TOSHOST, "toshost" },
+ { -2, NULL }
+};
+
+static icmp_subtype_t timxceednames[] = {
+ { ICMP_TIMXCEED_INTRANS, "transit" },
+ { ICMP_TIMXCEED_REASS, "reassem" },
+ { -2, NULL }
+};
+
+static icmp_subtype_t paramnames[] = {
+ { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" },
+ { ICMP_PARAMPROB_OPTABSENT, "optmissing" },
+ { ICMP_PARAMPROB_LENGTH, "length" },
+ { -2, NULL }
+};
+
+static icmp_type_t icmptypes4[] = {
+ { ICMP_ECHOREPLY, NULL, 0, "echoreply" },
+ { -1, NULL, 0, NULL },
+ { -1, NULL, 0, NULL },
+ { ICMP_UNREACH, icmpunreachnames,
+ IST_SZ(icmpunreachnames),"unreach" },
+ { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" },
+ { ICMP_REDIRECT, redirectnames,
+ IST_SZ(redirectnames), "redirect" },
+ { -1, NULL, 0, NULL },
+ { -1, NULL, 0, NULL },
+ { ICMP_ECHO, NULL, 0, "echo" },
+ { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" },
+ { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" },
+ { ICMP_TIMXCEED, timxceednames,
+ IST_SZ(timxceednames), "timxceed" },
+ { ICMP_PARAMPROB, paramnames,
+ IST_SZ(paramnames), "paramprob" },
+ { ICMP_TSTAMP, NULL, 0, "timestamp" },
+ { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" },
+ { ICMP_IREQ, NULL, 0, "inforeq" },
+ { ICMP_IREQREPLY, NULL, 0, "inforeply" },
+ { ICMP_MASKREQ, NULL, 0, "maskreq" },
+ { ICMP_MASKREPLY, NULL, 0, "maskreply" },
+ { -2, NULL, 0, NULL }
+};
+
+static icmp_subtype_t icmpredirect6[] = {
+ { ICMP6_DST_UNREACH_NOROUTE, "noroute" },
+ { ICMP6_DST_UNREACH_ADMIN, "admin" },
+ { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" },
+ { ICMP6_DST_UNREACH_ADDR, "address" },
+ { ICMP6_DST_UNREACH_NOPORT, "noport" },
+ { -2, NULL }
+};
+
+static icmp_subtype_t icmptimexceed6[] = {
+ { ICMP6_TIME_EXCEED_TRANSIT, "intransit" },
+ { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" },
+ { -2, NULL }
+};
+
+static icmp_subtype_t icmpparamprob6[] = {
+ { ICMP6_PARAMPROB_HEADER, "header" },
+ { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" },
+ { ICMP6_PARAMPROB_OPTION, "option" },
+ { -2, NULL }
+};
+
+static icmp_subtype_t icmpquerysubject6[] = {
+ { ICMP6_NI_SUBJ_IPV6, "ipv6" },
+ { ICMP6_NI_SUBJ_FQDN, "fqdn" },
+ { ICMP6_NI_SUBJ_IPV4, "ipv4" },
+ { -2, NULL },
+};
+
+static icmp_subtype_t icmpnodeinfo6[] = {
+ { ICMP6_NI_SUCCESS, "success" },
+ { ICMP6_NI_REFUSED, "refused" },
+ { ICMP6_NI_UNKNOWN, "unknown" },
+ { -2, NULL }
+};
+
+static icmp_subtype_t icmprenumber6[] = {
+ { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" },
+ { ICMP6_ROUTER_RENUMBERING_RESULT, "result" },
+ { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" },
+ { -2, NULL }
+};
+
+static icmp_type_t icmptypes6[] = {
+ { 0, NULL, 0, NULL },
+ { ICMP6_DST_UNREACH, icmpredirect6,
+ IST_SZ(icmpredirect6), "unreach" },
+ { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" },
+ { ICMP6_TIME_EXCEEDED, icmptimexceed6,
+ IST_SZ(icmptimexceed6), "timxceed" },
+ { ICMP6_PARAM_PROB, icmpparamprob6,
+ IST_SZ(icmpparamprob6), "paramprob" },
+ { ICMP6_ECHO_REQUEST, NULL, 0, "echo" },
+ { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" },
+ { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6,
+ IST_SZ(icmpquerysubject6), "groupmemberquery" },
+ { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" },
+ { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" },
+ { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" },
+ { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" },
+ { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" },
+ { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" },
+ { ND_REDIRECT, NULL, 0, "redirect" },
+ { ICMP6_ROUTER_RENUMBERING, icmprenumber6,
+ IST_SZ(icmprenumber6), "routerrenumber" },
+ { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" },
+ { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" },
+ { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" },
+ { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" },
+ { ICMP6_NI_QUERY, icmpnodeinfo6,
+ IST_SZ(icmpnodeinfo6), "nodeinforequest" },
+ { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" },
+ { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" },
+ { MLD6_MTRACE, NULL, 0, "mtracerequest" },
+ { -2, NULL, 0, NULL }
+};
+
+static icmp_subtype_t *find_icmpsubtype(type, table, tablesz)
+ int type;
+ icmp_subtype_t *table;
+ size_t tablesz;
+{
+ icmp_subtype_t *ist;
+ int i;
+
+ if (tablesz < 2)
+ return NULL;
+
+ if ((type < 0) || (type > table[tablesz - 2].ist_val))
+ return NULL;
+
+ i = type;
+ if (table[type].ist_val == type)
+ return table + type;
+
+ for (i = 0, ist = table; ist->ist_val != -2; i++, ist++)
+ if (ist->ist_val == type)
+ return ist;
+ return NULL;
+}
+
+
+static icmp_type_t *find_icmptype(type, table, tablesz)
+ int type;
+ icmp_type_t *table;
+ size_t tablesz;
+{
+ icmp_type_t *it;
+ int i;
+
+ if (tablesz < 2)
+ return NULL;
+
+ if ((type < 0) || (type > table[tablesz - 2].it_val))
+ return NULL;
+
+ i = type;
+ if (table[type].it_val == type)
+ return table + type;
+
+ for (i = 0, it = table; it->it_val != -2; i++, it++)
+ if (it->it_val == type)
+ return it;
+ return NULL;
+}
+
+
+static void handlehup(sig)
+ int sig;
+{
+ signal(SIGHUP, handlehup);
+ donehup = 1;
+}
+
+
+static void init_tabs()
+{
+ struct protoent *p;
+ struct servent *s;
+ char *name, **tab;
+ int port, i;
+
+ if (protocols != NULL) {
+ for (i = 0; i < 256; i++)
+ if (protocols[i] != NULL) {
+ free(protocols[i]);
+ protocols[i] = NULL;
+ }
+ free(protocols);
+ protocols = NULL;
+ }
+ protocols = (char **)malloc(256 * sizeof(*protocols));
+ if (protocols != NULL) {
+ bzero((char *)protocols, 256 * sizeof(*protocols));
+
+ setprotoent(1);
+ while ((p = getprotoent()) != NULL)
+ if (p->p_proto >= 0 && p->p_proto <= 255 &&
+ p->p_name != NULL && protocols[p->p_proto] == NULL)
+ protocols[p->p_proto] = strdup(p->p_name);
+ endprotoent();
+ if (protocols[0])
+ free(protocols[0]);
+ protocols[0] = strdup("ip");
+#if defined(_AIX51)
+ if (protocols[252])
+ free(protocols[252]);
+ protocols[252] = NULL;
+#endif
+ }
+
+ if (udp_ports != NULL) {
+ for (i = 0; i < 65536; i++)
+ if (udp_ports[i] != NULL) {
+ free(udp_ports[i]);
+ udp_ports[i] = NULL;
+ }
+ free(udp_ports);
+ udp_ports = NULL;
+ }
+ udp_ports = (char **)malloc(65536 * sizeof(*udp_ports));
+ if (udp_ports != NULL)
+ bzero((char *)udp_ports, 65536 * sizeof(*udp_ports));
+
+ if (tcp_ports != NULL) {
+ for (i = 0; i < 65536; i++)
+ if (tcp_ports[i] != NULL) {
+ free(tcp_ports[i]);
+ tcp_ports[i] = NULL;
+ }
+ free(tcp_ports);
+ tcp_ports = NULL;
+ }
+ tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports));
+ if (tcp_ports != NULL)
+ bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports));
+
+ setservent(1);
+ while ((s = getservent()) != NULL) {
+ if (s->s_proto == NULL)
+ continue;
+ else if (!strcmp(s->s_proto, "tcp")) {
+ port = ntohs(s->s_port);
+ name = s->s_name;
+ tab = tcp_ports;
+ } else if (!strcmp(s->s_proto, "udp")) {
+ port = ntohs(s->s_port);
+ name = s->s_name;
+ tab = udp_ports;
+ } else
+ continue;
+ if ((port < 0 || port > 65535) || (name == NULL))
+ continue;
+ if (tab != NULL)
+ tab[port] = strdup(name);
+ }
+ endservent();
+}
+
+
+static char *getlocalproto(p)
+ u_int p;
+{
+ static char pnum[4];
+ char *s;
+
+ p &= 0xff;
+ s = protocols ? protocols[p] : NULL;
+ if (s == NULL) {
+ sprintf(pnum, "%u", p);
+ s = pnum;
+ }
+ return s;
+}
+
+
+static int read_log(fd, lenp, buf, bufsize)
+ int fd, bufsize, *lenp;
+ char *buf;
+{
+ int nr;
+
+ if (bufsize > IPFILTER_LOGSIZE)
+ bufsize = IPFILTER_LOGSIZE;
+
+ nr = read(fd, buf, bufsize);
+ if (!nr)
+ return 2;
+ if ((nr < 0) && (errno != EINTR))
+ return -1;
+ *lenp = nr;
+ return 0;
+}
+
+
+char *portlocalname(res, proto, port)
+ int res;
+ char *proto;
+ u_int port;
+{
+ static char pname[8];
+ char *s;
+
+ port = ntohs(port);
+ port &= 0xffff;
+ sprintf(pname, "%u", port);
+ if (!res || (ipmonopts & IPMON_PORTNUM))
+ return pname;
+ s = NULL;
+ if (!strcmp(proto, "tcp"))
+ s = tcp_ports[port];
+ else if (!strcmp(proto, "udp"))
+ s = udp_ports[port];
+ if (s == NULL)
+ s = pname;
+ return s;
+}
+
+
+static char *icmpname(type, code)
+ u_int type;
+ u_int code;
+{
+ static char name[80];
+ icmp_subtype_t *ist;
+ icmp_type_t *it;
+ char *s;
+
+ s = NULL;
+ it = find_icmptype(type, icmptypes4, sizeof(icmptypes4) / sizeof(*it));
+ if (it != NULL)
+ s = it->it_name;
+
+ if (s == NULL)
+ sprintf(name, "icmptype(%d)/", type);
+ else
+ sprintf(name, "%s/", s);
+
+ ist = NULL;
+ if (it != NULL && it->it_subtable != NULL)
+ ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize);
+
+ if (ist != NULL && ist->ist_name != NULL)
+ strcat(name, ist->ist_name);
+ else
+ sprintf(name + strlen(name), "%d", code);
+
+ return name;
+}
+
+static char *icmpname6(type, code)
+ u_int type;
+ u_int code;
+{
+ static char name[80];
+ icmp_subtype_t *ist;
+ icmp_type_t *it;
+ char *s;
+
+ s = NULL;
+ it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it));
+ if (it != NULL)
+ s = it->it_name;
+
+ if (s == NULL)
+ sprintf(name, "icmpv6type(%d)/", type);
+ else
+ sprintf(name, "%s/", s);
+
+ ist = NULL;
+ if (it != NULL && it->it_subtable != NULL)
+ ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize);
+
+ if (ist != NULL && ist->ist_name != NULL)
+ strcat(name, ist->ist_name);
+ else
+ sprintf(name + strlen(name), "%d", code);
+
+ return name;
+}
+
+
+void dumphex(log, dopts, buf, len)
+ FILE *log;
+ int dopts;
+ char *buf;
+ int len;
+{
+ char hline[80];
+ int i, j, k;
+ u_char *s = (u_char *)buf, *t = (u_char *)hline;
+
+ if (buf == NULL || len == 0)
+ return;
+
+ *hline = '\0';
+
+ for (i = len, j = 0; i; i--, j++, s++) {
+ if (j && !(j & 0xf)) {
+ *t++ = '\n';
+ *t = '\0';
+ if ((dopts & IPMON_SYSLOG))
+ syslog(LOG_INFO, "%s", hline);
+ else if (log != NULL)
+ fputs(hline, log);
+ t = (u_char *)hline;
+ *t = '\0';
+ }
+ sprintf((char *)t, "%02x", *s & 0xff);
+ t += 2;
+ if (!((j + 1) & 0xf)) {
+ s -= 15;
+ sprintf((char *)t, " ");
+ t += 8;
+ for (k = 16; k; k--, s++)
+ *t++ = (isprint(*s) ? *s : '.');
+ s--;
+ }
+
+ if ((j + 1) & 0xf)
+ *t++ = ' ';;
+ }
+
+ if (j & 0xf) {
+ for (k = 16 - (j & 0xf); k; k--) {
+ *t++ = ' ';
+ *t++ = ' ';
+ *t++ = ' ';
+ }
+ sprintf((char *)t, " ");
+ t += 7;
+ s -= j & 0xf;
+ for (k = j & 0xf; k; k--, s++)
+ *t++ = (isprint(*s) ? *s : '.');
+ *t++ = '\n';
+ *t = '\0';
+ }
+ if ((dopts & IPMON_SYSLOG) != 0)
+ syslog(LOG_INFO, "%s", hline);
+ else if (log != NULL) {
+ fputs(hline, log);
+ fflush(log);
+ }
+}
+
+
+static struct tm *get_tm(sec)
+#ifdef __hpux
+ u_32_t sec;
+#else
+ time_t sec;
+#endif
+{
+ struct tm *tm;
+ time_t t;
+
+ t = sec;
+ tm = localtime(&t);
+ return tm;
+}
+
+static void print_natlog(conf, buf, blen)
+ config_t *conf;
+ char *buf;
+ int blen;
+{
+ static u_32_t seqnum = 0;
+ int res, i, len, family;
+ struct natlog *nl;
+ struct tm *tm;
+ iplog_t *ipl;
+ char *proto;
+ int simple;
+ char *t;
+
+ t = line;
+ simple = 0;
+ ipl = (iplog_t *)buf;
+ if (ipl->ipl_seqnum != seqnum) {
+ if ((ipmonopts & IPMON_SYSLOG) != 0) {
+ syslog(LOG_WARNING,
+ "missed %u NAT log entries: %u %u",
+ ipl->ipl_seqnum - seqnum, seqnum,
+ ipl->ipl_seqnum);
+ } else {
+ (void) fprintf(conf->log,
+ "missed %u NAT log entries: %u %u\n",
+ ipl->ipl_seqnum - seqnum, seqnum,
+ ipl->ipl_seqnum);
+ }
+ }
+ seqnum = ipl->ipl_seqnum + ipl->ipl_count;
+
+ nl = (struct natlog *)((char *)ipl + sizeof(*ipl));
+ res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0;
+ tm = get_tm(ipl->ipl_sec);
+ len = sizeof(line);
+
+ if (!(ipmonopts & IPMON_SYSLOG)) {
+ (void) strftime(t, len, "%d/%m/%Y ", tm);
+ i = strlen(t);
+ len -= i;
+ t += i;
+ }
+ (void) strftime(t, len, "%T", tm);
+ t += strlen(t);
+ sprintf(t, ".%-.6ld @%hd ", (long)ipl->ipl_usec, nl->nl_rule + 1);
+ t += strlen(t);
+
+ switch (nl->nl_action)
+ {
+ case NL_NEW :
+ strcpy(t, "NAT:NEW");
+ break;
+
+ case NL_FLUSH :
+ strcpy(t, "NAT:FLUSH");
+ break;
+
+ case NL_CLONE :
+ strcpy(t, "NAT:CLONE");
+ break;
+
+ case NL_EXPIRE :
+ strcpy(t, "NAT:EXPIRE");
+ break;
+
+ case NL_DESTROY :
+ strcpy(t, "NAT:DESTROY");
+ break;
+
+ case NL_PURGE :
+ strcpy(t, "NAT:PURGE");
+ break;
+
+ default :
+ sprintf(t, "NAT:Action(%d)", nl->nl_action);
+ break;
+ }
+ t += strlen(t);
+
+
+ switch (nl->nl_type)
+ {
+ case NAT_MAP :
+ strcpy(t, "-MAP ");
+ simple = 1;
+ break;
+
+ case NAT_REDIRECT :
+ strcpy(t, "-RDR ");
+ simple = 1;
+ break;
+
+ case NAT_BIMAP :
+ strcpy(t, "-BIMAP ");
+ simple = 1;
+ break;
+
+ case NAT_MAPBLK :
+ strcpy(t, "-MAPBLOCK ");
+ simple = 1;
+ break;
+
+ case NAT_REWRITE|NAT_MAP :
+ strcpy(t, "-RWR_MAP ");
+ break;
+
+ case NAT_REWRITE|NAT_REDIRECT :
+ strcpy(t, "-RWR_RDR ");
+ break;
+
+ case NAT_ENCAP|NAT_MAP :
+ strcpy(t, "-ENC_MAP ");
+ break;
+
+ case NAT_ENCAP|NAT_REDIRECT :
+ strcpy(t, "-ENC_RDR ");
+ break;
+
+ case NAT_DIVERTUDP|NAT_MAP :
+ strcpy(t, "-DIV_MAP ");
+ break;
+
+ case NAT_DIVERTUDP|NAT_REDIRECT :
+ strcpy(t, "-DIV_RDR ");
+ break;
+
+ default :
+ sprintf(t, "-Type(%d) ", nl->nl_type);
+ break;
+ }
+ t += strlen(t);
+
+ proto = getlocalproto(nl->nl_p[0]);
+
+ family = vtof(nl->nl_v[0]);
+
+ if (simple == 1) {
+ sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_osrcip.i6),
+ portlocalname(res, proto, (u_int)nl->nl_osrcport));
+ t += strlen(t);
+ sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6),
+ portlocalname(res, proto, (u_int)nl->nl_nsrcport));
+ t += strlen(t);
+ sprintf(t, "[%s,%s] ", hostname(family, nl->nl_odstip.i6),
+ portlocalname(res, proto, (u_int)nl->nl_odstport));
+ } else {
+ sprintf(t, "%s,%s ", hostname(family, nl->nl_osrcip.i6),
+ portlocalname(res, proto, (u_int)nl->nl_osrcport));
+ t += strlen(t);
+ sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_odstip.i6),
+ portlocalname(res, proto, (u_int)nl->nl_odstport));
+ t += strlen(t);
+ sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6),
+ portlocalname(res, proto, (u_int)nl->nl_nsrcport));
+ t += strlen(t);
+ sprintf(t, "%s,%s ", hostname(family, nl->nl_ndstip.i6),
+ portlocalname(res, proto, (u_int)nl->nl_ndstport));
+ }
+ t += strlen(t);
+
+ strcpy(t, getlocalproto(nl->nl_p[0]));
+ t += strlen(t);
+
+ if (nl->nl_action == NL_EXPIRE || nl->nl_action == NL_FLUSH) {
+#ifdef USE_QUAD_T
+# ifdef PRId64
+ sprintf(t, " Pkts %" PRId64 "/%" PRId64 " Bytes %" PRId64 "/%"
+ PRId64,
+# else
+ sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd",
+# endif
+#else
+ sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld",
+#endif
+ nl->nl_pkts[0], nl->nl_pkts[1],
+ nl->nl_bytes[0], nl->nl_bytes[1]);
+ t += strlen(t);
+ }
+
+ *t++ = '\n';
+ *t++ = '\0';
+ if (ipmonopts & IPMON_SYSLOG)
+ syslog(LOG_INFO, "%s", line);
+ else if (conf->log != NULL)
+ (void) fprintf(conf->log, "%s", line);
+}
+
+
+static void print_statelog(conf, buf, blen)
+ config_t *conf;
+ char *buf;
+ int blen;
+{
+ static u_32_t seqnum = 0;
+ int res, i, len, family;
+ struct ipslog *sl;
+ char *t, *proto;
+ struct tm *tm;
+ iplog_t *ipl;
+
+ t = line;
+ ipl = (iplog_t *)buf;
+ if (ipl->ipl_seqnum != seqnum) {
+ if ((ipmonopts & IPMON_SYSLOG) != 0) {
+ syslog(LOG_WARNING,
+ "missed %u state log entries: %u %u",
+ ipl->ipl_seqnum - seqnum, seqnum,
+ ipl->ipl_seqnum);
+ } else {
+ (void) fprintf(conf->log,
+ "missed %u state log entries: %u %u\n",
+ ipl->ipl_seqnum - seqnum, seqnum,
+ ipl->ipl_seqnum);
+ }
+ }
+ seqnum = ipl->ipl_seqnum + ipl->ipl_count;
+
+ sl = (struct ipslog *)((char *)ipl + sizeof(*ipl));
+ res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0;
+ tm = get_tm(ipl->ipl_sec);
+ len = sizeof(line);
+ if (!(ipmonopts & IPMON_SYSLOG)) {
+ (void) strftime(t, len, "%d/%m/%Y ", tm);
+ i = strlen(t);
+ len -= i;
+ t += i;
+ }
+ (void) strftime(t, len, "%T", tm);
+ t += strlen(t);
+ sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec);
+ t += strlen(t);
+
+ family = vtof(sl->isl_v);
+
+ switch (sl->isl_type)
+ {
+ case ISL_NEW :
+ strcpy(t, "STATE:NEW ");
+ break;
+
+ case ISL_CLONE :
+ strcpy(t, "STATE:CLONED ");
+ break;
+
+ case ISL_EXPIRE :
+ if ((sl->isl_p == IPPROTO_TCP) &&
+ (sl->isl_state[0] > IPF_TCPS_ESTABLISHED ||
+ sl->isl_state[1] > IPF_TCPS_ESTABLISHED))
+ strcpy(t, "STATE:CLOSE ");
+ else
+ strcpy(t, "STATE:EXPIRE ");
+ break;
+
+ case ISL_FLUSH :
+ strcpy(t, "STATE:FLUSH ");
+ break;
+
+ case ISL_INTERMEDIATE :
+ strcpy(t, "STATE:INTERMEDIATE ");
+ break;
+
+ case ISL_REMOVE :
+ strcpy(t, "STATE:REMOVE ");
+ break;
+
+ case ISL_KILLED :
+ strcpy(t, "STATE:KILLED ");
+ break;
+
+ case ISL_UNLOAD :
+ strcpy(t, "STATE:UNLOAD ");
+ break;
+
+ default :
+ sprintf(t, "Type: %d ", sl->isl_type);
+ break;
+ }
+ t += strlen(t);
+
+ proto = getlocalproto(sl->isl_p);
+
+ if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) {
+ sprintf(t, "%s,%s -> ",
+ hostname(family, (u_32_t *)&sl->isl_src),
+ portlocalname(res, proto, (u_int)sl->isl_sport));
+ t += strlen(t);
+ sprintf(t, "%s,%s PR %s",
+ hostname(family, (u_32_t *)&sl->isl_dst),
+ portlocalname(res, proto, (u_int)sl->isl_dport), proto);
+ } else if (sl->isl_p == IPPROTO_ICMP) {
+ sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src));
+ t += strlen(t);
+ sprintf(t, "%s PR icmp %d",
+ hostname(family, (u_32_t *)&sl->isl_dst),
+ sl->isl_itype);
+ } else if (sl->isl_p == IPPROTO_ICMPV6) {
+ sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src));
+ t += strlen(t);
+ sprintf(t, "%s PR icmpv6 %d",
+ hostname(family, (u_32_t *)&sl->isl_dst),
+ sl->isl_itype);
+ } else {
+ sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src));
+ t += strlen(t);
+ sprintf(t, "%s PR %s",
+ hostname(family, (u_32_t *)&sl->isl_dst), proto);
+ }
+ t += strlen(t);
+ if (sl->isl_tag != FR_NOLOGTAG) {
+ sprintf(t, " tag %u", sl->isl_tag);
+ t += strlen(t);
+ }
+ if (sl->isl_type != ISL_NEW) {
+ sprintf(t,
+#ifdef USE_QUAD_T
+#ifdef PRId64
+ " Forward: Pkts in %" PRId64 " Bytes in %" PRId64
+ " Pkts out %" PRId64 " Bytes out %" PRId64
+ " Backward: Pkts in %" PRId64 " Bytes in %" PRId64
+ " Pkts out %" PRId64 " Bytes out %" PRId64,
+#else
+ " Forward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd Backward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd",
+#endif /* PRId64 */
+#else
+ " Forward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld Backward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld",
+#endif
+ sl->isl_pkts[0], sl->isl_bytes[0],
+ sl->isl_pkts[1], sl->isl_bytes[1],
+ sl->isl_pkts[2], sl->isl_bytes[2],
+ sl->isl_pkts[3], sl->isl_bytes[3]);
+
+ t += strlen(t);
+ }
+
+ *t++ = '\n';
+ *t++ = '\0';
+ if (ipmonopts & IPMON_SYSLOG)
+ syslog(LOG_INFO, "%s", line);
+ else if (conf->log != NULL)
+ (void) fprintf(conf->log, "%s", line);
+}
+
+
+static void print_log(conf, log, buf, blen)
+ config_t *conf;
+ logsource_t *log;
+ char *buf;
+ int blen;
+{
+ char *bp, *bpo;
+ iplog_t *ipl;
+ int psize;
+
+ bp = NULL;
+ bpo = NULL;
+
+ while (blen > 0) {
+ ipl = (iplog_t *)buf;
+ if ((u_long)ipl & (sizeof(long)-1)) {
+ if (bp)
+ bpo = bp;
+ bp = (char *)malloc(blen);
+ bcopy((char *)ipl, bp, blen);
+ if (bpo) {
+ free(bpo);
+ bpo = NULL;
+ }
+ buf = bp;
+ continue;
+ }
+
+ psize = ipl->ipl_dsize;
+ if (psize > blen)
+ break;
+
+ if (conf->blog != NULL) {
+ fwrite(buf, psize, 1, conf->blog);
+ fflush(conf->blog);
+ }
+
+ if (log->logtype == IPL_LOGIPF) {
+ if (ipl->ipl_magic == IPL_MAGIC)
+ print_ipflog(conf, buf, psize);
+
+ } else if (log->logtype == IPL_LOGNAT) {
+ if (ipl->ipl_magic == IPL_MAGIC_NAT)
+ print_natlog(conf, buf, psize);
+
+ } else if (log->logtype == IPL_LOGSTATE) {
+ if (ipl->ipl_magic == IPL_MAGIC_STATE)
+ print_statelog(conf, buf, psize);
+ }
+
+ blen -= psize;
+ buf += psize;
+ }
+ if (bp)
+ free(bp);
+ return;
+}
+
+
+static void print_ipflog(conf, buf, blen)
+ config_t *conf;
+ char *buf;
+ int blen;
+{
+ static u_32_t seqnum = 0;
+ int i, f, lvl, res, len, off, plen, ipoff, defaction;
+ struct icmp *icmp;
+ struct icmp *ic;
+ char *t, *proto;
+ ip_t *ipc, *ip;
+ struct tm *tm;
+ u_32_t *s, *d;
+ u_short hl, p;
+ ipflog_t *ipf;
+ iplog_t *ipl;
+ tcphdr_t *tp;
+#ifdef USE_INET6
+ struct ip6_ext *ehp;
+ u_short ehl;
+ ip6_t *ip6;
+ int go;
+#endif
+
+ ipl = (iplog_t *)buf;
+ if (ipl->ipl_seqnum != seqnum) {
+ if ((ipmonopts & IPMON_SYSLOG) != 0) {
+ syslog(LOG_WARNING,
+ "missed %u ipf log entries: %u %u",
+ ipl->ipl_seqnum - seqnum, seqnum,
+ ipl->ipl_seqnum);
+ } else {
+ (void) fprintf(conf->log,
+ "missed %u ipf log entries: %u %u\n",
+ ipl->ipl_seqnum - seqnum, seqnum,
+ ipl->ipl_seqnum);
+ }
+ }
+ seqnum = ipl->ipl_seqnum + ipl->ipl_count;
+
+ ipf = (ipflog_t *)((char *)buf + sizeof(*ipl));
+ ip = (ip_t *)((char *)ipf + sizeof(*ipf));
+ f = ipf->fl_family;
+ res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0;
+ t = line;
+ *t = '\0';
+ tm = get_tm(ipl->ipl_sec);
+
+ len = sizeof(line);
+ if (!(ipmonopts & IPMON_SYSLOG)) {
+ (void) strftime(t, len, "%d/%m/%Y ", tm);
+ i = strlen(t);
+ len -= i;
+ t += i;
+ }
+ (void) strftime(t, len, "%T", tm);
+ t += strlen(t);
+ sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec);
+ t += strlen(t);
+ if (ipl->ipl_count > 1) {
+ sprintf(t, "%dx ", ipl->ipl_count);
+ t += strlen(t);
+ }
+#if (defined(MENTAT) || \
+ (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \
+ (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux)
+ {
+ char ifname[sizeof(ipf->fl_ifname) + 1];
+
+ strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname));
+ ifname[sizeof(ipf->fl_ifname)] = '\0';
+ sprintf(t, "%s", ifname);
+ t += strlen(t);
+# if defined(MENTAT) || defined(linux)
+# if defined(linux)
+ /*
+ * On Linux, the loopback interface is just "lo", not "lo0".
+ */
+ if (strcmp(ifname, "lo") != 0)
+# endif
+ if (ISALPHA(*(t - 1))) {
+ sprintf(t, "%d", ipf->fl_unit);
+ t += strlen(t);
+ }
+# endif
+ }
+#else
+ for (len = 0; len < 3; len++)
+ if (ipf->fl_ifname[len] == '\0')
+ break;
+ if (ipf->fl_ifname[len])
+ len++;
+ sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit);
+ t += strlen(t);
+#endif
+ if ((ipf->fl_group[0] == (char)~0) && (ipf->fl_group[1] == '\0'))
+ strcat(t, " @-1:");
+ else if (ipf->fl_group[0] == '\0')
+ (void) strcpy(t, " @0:");
+ else
+ sprintf(t, " @%s:", ipf->fl_group);
+ t += strlen(t);
+ if (ipf->fl_rule == 0xffffffff)
+ strcat(t, "-1 ");
+ else
+ sprintf(t, "%u ", ipf->fl_rule + 1);
+ t += strlen(t);
+
+ lvl = LOG_NOTICE;
+
+ if (ipf->fl_lflags & FI_SHORT) {
+ *t++ = 'S';
+ lvl = LOG_ERR;
+ }
+
+ if (FR_ISPASS(ipf->fl_flags)) {
+ if (ipf->fl_flags & FR_LOGP)
+ *t++ = 'p';
+ else
+ *t++ = 'P';
+ } else if (FR_ISBLOCK(ipf->fl_flags)) {
+ if (ipf->fl_flags & FR_LOGB)
+ *t++ = 'b';
+ else
+ *t++ = 'B';
+ lvl = LOG_WARNING;
+ } else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) {
+ *t++ = 'L';
+ lvl = LOG_INFO;
+ } else if (ipf->fl_flags & FF_LOGNOMATCH) {
+ *t++ = 'n';
+ } else {
+ *t++ = '?';
+ lvl = LOG_EMERG;
+ }
+ if (ipf->fl_loglevel != 0xffff)
+ lvl = ipf->fl_loglevel;
+ *t++ = ' ';
+ *t = '\0';
+
+ if (f == AF_INET) {
+ hl = IP_HL(ip) << 2;
+ ipoff = ntohs(ip->ip_off);
+ off = ipoff & IP_OFFMASK;
+ p = (u_short)ip->ip_p;
+ s = (u_32_t *)&ip->ip_src;
+ d = (u_32_t *)&ip->ip_dst;
+ plen = ntohs(ip->ip_len);
+ } else
+#ifdef USE_INET6
+ if (f == AF_INET6) {
+ off = 0;
+ ipoff = 0;
+ hl = sizeof(ip6_t);
+ ip6 = (ip6_t *)ip;
+ p = (u_short)ip6->ip6_nxt;
+ s = (u_32_t *)&ip6->ip6_src;
+ d = (u_32_t *)&ip6->ip6_dst;
+ plen = hl + ntohs(ip6->ip6_plen);
+ go = 1;
+ ehp = (struct ip6_ext *)((char *)ip6 + hl);
+ while (go == 1) {
+ switch (p)
+ {
+ case IPPROTO_HOPOPTS :
+ case IPPROTO_MOBILITY :
+ case IPPROTO_DSTOPTS :
+ case IPPROTO_ROUTING :
+ case IPPROTO_AH :
+ p = ehp->ip6e_nxt;
+ ehl = 8 + (ehp->ip6e_len << 3);
+ hl += ehl;
+ ehp = (struct ip6_ext *)((char *)ehp + ehl);
+ break;
+ case IPPROTO_FRAGMENT :
+ hl += sizeof(struct ip6_frag);
+ /* FALLTHROUGH */
+ default :
+ go = 0;
+ break;
+ }
+ }
+ } else
+#endif
+ {
+ goto printipflog;
+ }
+ proto = getlocalproto(p);
+
+ if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) {
+ tp = (tcphdr_t *)((char *)ip + hl);
+ if (!(ipf->fl_lflags & FI_SHORT)) {
+ sprintf(t, "%s,%s -> ", hostname(f, s),
+ portlocalname(res, proto, (u_int)tp->th_sport));
+ t += strlen(t);
+ sprintf(t, "%s,%s PR %s len %hu %hu",
+ hostname(f, d),
+ portlocalname(res, proto, (u_int)tp->th_dport),
+ proto, hl, plen);
+ t += strlen(t);
+
+ if (p == IPPROTO_TCP) {
+ *t++ = ' ';
+ *t++ = '-';
+ for (i = 0; tcpfl[i].value; i++)
+ if (tp->th_flags & tcpfl[i].value)
+ *t++ = tcpfl[i].flag;
+ if (ipmonopts & IPMON_VERBOSE) {
+ sprintf(t, " %lu %lu %hu",
+ (u_long)(ntohl(tp->th_seq)),
+ (u_long)(ntohl(tp->th_ack)),
+ ntohs(tp->th_win));
+ t += strlen(t);
+ }
+ }
+ *t = '\0';
+ } else {
+ sprintf(t, "%s -> ", hostname(f, s));
+ t += strlen(t);
+ sprintf(t, "%s PR %s len %hu %hu",
+ hostname(f, d), proto, hl, plen);
+ }
+#if defined(AF_INET6) && defined(IPPROTO_ICMPV6)
+ } else if ((p == IPPROTO_ICMPV6) && !off && (f == AF_INET6)) {
+ ic = (struct icmp *)((char *)ip + hl);
+ sprintf(t, "%s -> ", hostname(f, s));
+ t += strlen(t);
+ sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s",
+ hostname(f, d), hl, plen,
+ icmpname6(ic->icmp_type, ic->icmp_code));
+#endif
+ } else if ((p == IPPROTO_ICMP) && !off && (f == AF_INET)) {
+ ic = (struct icmp *)((char *)ip + hl);
+ sprintf(t, "%s -> ", hostname(f, s));
+ t += strlen(t);
+ sprintf(t, "%s PR icmp len %hu %hu icmp %s",
+ hostname(f, d), hl, plen,
+ icmpname(ic->icmp_type, ic->icmp_code));
+ if (ic->icmp_type == ICMP_UNREACH ||
+ ic->icmp_type == ICMP_SOURCEQUENCH ||
+ ic->icmp_type == ICMP_PARAMPROB ||
+ ic->icmp_type == ICMP_REDIRECT ||
+ ic->icmp_type == ICMP_TIMXCEED) {
+ ipc = &ic->icmp_ip;
+ i = ntohs(ipc->ip_len);
+ /*
+ * XXX - try to guess endian of ip_len in ICMP
+ * returned data.
+ */
+ if (i > 1500)
+ i = ipc->ip_len;
+ ipoff = ntohs(ipc->ip_off);
+ proto = getlocalproto(ipc->ip_p);
+
+ if (!(ipoff & IP_OFFMASK) &&
+ ((ipc->ip_p == IPPROTO_TCP) ||
+ (ipc->ip_p == IPPROTO_UDP))) {
+ tp = (tcphdr_t *)((char *)ipc + hl);
+ t += strlen(t);
+ sprintf(t, " for %s,%s -",
+ HOSTNAMEV4(ipc->ip_src),
+ portlocalname(res, proto,
+ (u_int)tp->th_sport));
+ t += strlen(t);
+ sprintf(t, " %s,%s PR %s len %hu %hu",
+ HOSTNAMEV4(ipc->ip_dst),
+ portlocalname(res, proto,
+ (u_int)tp->th_dport),
+ proto, IP_HL(ipc) << 2, i);
+ } else if (!(ipoff & IP_OFFMASK) &&
+ (ipc->ip_p == IPPROTO_ICMP)) {
+ icmp = (icmphdr_t *)((char *)ipc + hl);
+
+ t += strlen(t);
+ sprintf(t, " for %s -",
+ HOSTNAMEV4(ipc->ip_src));
+ t += strlen(t);
+ sprintf(t,
+ " %s PR icmp len %hu %hu icmp %d/%d",
+ HOSTNAMEV4(ipc->ip_dst),
+ IP_HL(ipc) << 2, i,
+ icmp->icmp_type, icmp->icmp_code);
+ } else {
+ t += strlen(t);
+ sprintf(t, " for %s -",
+ HOSTNAMEV4(ipc->ip_src));
+ t += strlen(t);
+ sprintf(t, " %s PR %s len %hu (%hu)",
+ HOSTNAMEV4(ipc->ip_dst), proto,
+ IP_HL(ipc) << 2, i);
+ t += strlen(t);
+ if (ipoff & IP_OFFMASK) {
+ sprintf(t, "(frag %d:%hu@%hu%s%s)",
+ ntohs(ipc->ip_id),
+ i - (IP_HL(ipc) << 2),
+ (ipoff & IP_OFFMASK) << 3,
+ ipoff & IP_MF ? "+" : "",
+ ipoff & IP_DF ? "-" : "");
+ }
+ }
+
+ }
+ } else {
+ sprintf(t, "%s -> ", hostname(f, s));
+ t += strlen(t);
+ sprintf(t, "%s PR %s len %hu (%hu)",
+ hostname(f, d), proto, hl, plen);
+ t += strlen(t);
+ if (off & IP_OFFMASK)
+ sprintf(t, " (frag %d:%hu@%hu%s%s)",
+ ntohs(ip->ip_id),
+ plen - hl, (off & IP_OFFMASK) << 3,
+ ipoff & IP_MF ? "+" : "",
+ ipoff & IP_DF ? "-" : "");
+ }
+ t += strlen(t);
+
+printipflog:
+ if (ipf->fl_flags & FR_KEEPSTATE) {
+ (void) strcpy(t, " K-S");
+ t += strlen(t);
+ }
+
+ if (ipf->fl_flags & FR_KEEPFRAG) {
+ (void) strcpy(t, " K-F");
+ t += strlen(t);
+ }
+
+ if (ipf->fl_dir == 0)
+ strcpy(t, " IN");
+ else if (ipf->fl_dir == 1)
+ strcpy(t, " OUT");
+ t += strlen(t);
+ if (ipf->fl_logtag != 0) {
+ sprintf(t, " log-tag %d", ipf->fl_logtag);
+ t += strlen(t);
+ }
+ if (ipf->fl_nattag.ipt_num[0] != 0) {
+ strcpy(t, " nat-tag ");
+ t += strlen(t);
+ strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag));
+ t += strlen(t);
+ }
+ if ((ipf->fl_lflags & FI_LOWTTL) != 0) {
+ strcpy(t, " low-ttl");
+ t += 8;
+ }
+ if ((ipf->fl_lflags & FI_OOW) != 0) {
+ strcpy(t, " OOW");
+ t += 4;
+ }
+ if ((ipf->fl_lflags & FI_BAD) != 0) {
+ strcpy(t, " bad");
+ t += 4;
+ }
+ if ((ipf->fl_lflags & FI_NATED) != 0) {
+ strcpy(t, " NAT");
+ t += 4;
+ }
+ if ((ipf->fl_lflags & FI_BADNAT) != 0) {
+ strcpy(t, " bad-NAT");
+ t += 8;
+ }
+ if ((ipf->fl_lflags & FI_BADSRC) != 0) {
+ strcpy(t, " bad-src");
+ t += 8;
+ }
+ if ((ipf->fl_lflags & FI_MULTICAST) != 0) {
+ strcpy(t, " multicast");
+ t += 10;
+ }
+ if ((ipf->fl_lflags & FI_BROADCAST) != 0) {
+ strcpy(t, " broadcast");
+ t += 10;
+ }
+ if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) ==
+ FI_MBCAST) {
+ strcpy(t, " mbcast");
+ t += 7;
+ }
+ if (ipf->fl_breason != 0) {
+ strcpy(t, " reason:");
+ t += 8;
+ strcpy(t, reasons[ipf->fl_breason]);
+ t += strlen(reasons[ipf->fl_breason]);
+ }
+ *t++ = '\n';
+ *t++ = '\0';
+ defaction = 0;
+ if (conf->cfile != NULL)
+ defaction = check_action(buf, line, ipmonopts, lvl);
+
+ if (defaction == 0) {
+ if (ipmonopts & IPMON_SYSLOG) {
+ syslog(lvl, "%s", line);
+ } else if (conf->log != NULL) {
+ (void) fprintf(conf->log, "%s", line);
+ }
+
+ if (ipmonopts & IPMON_HEXHDR) {
+ dumphex(conf->log, ipmonopts, buf,
+ sizeof(iplog_t) + sizeof(*ipf));
+ }
+ if (ipmonopts & IPMON_HEXBODY) {
+ dumphex(conf->log, ipmonopts, (char *)ip,
+ ipf->fl_plen + ipf->fl_hlen);
+ } else if ((ipmonopts & IPMON_LOGBODY) &&
+ (ipf->fl_flags & FR_LOGBODY)) {
+ dumphex(conf->log, ipmonopts, (char *)ip + ipf->fl_hlen,
+ ipf->fl_plen);
+ }
+ }
+}
+
+
+static void usage(prog)
+ char *prog;
+{
+ fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog);
+ exit(1);
+}
+
+
+static void write_pid(file)
+ char *file;
+{
+ FILE *fp = NULL;
+ int fd;
+
+ if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) {
+ fp = fdopen(fd, "w");
+ if (fp == NULL) {
+ close(fd);
+ fprintf(stderr,
+ "unable to open/create pid file: %s\n", file);
+ return;
+ }
+ fprintf(fp, "%d", getpid());
+ fclose(fp);
+ }
+}
+
+
+static void flushlogs(file, log)
+ char *file;
+ FILE *log;
+{
+ int fd, flushed = 0;
+
+ if ((fd = open(file, O_RDWR)) == -1) {
+ (void) fprintf(stderr, "%s: open: %s\n",
+ file, STRERROR(errno));
+ exit(1);
+ }
+
+ if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
+ printf("%d bytes flushed from log buffer\n",
+ flushed);
+ fflush(stdout);
+ } else
+ ipferror(fd, "SIOCIPFFB");
+ (void) close(fd);
+
+ if (flushed) {
+ if (ipmonopts & IPMON_SYSLOG) {
+ syslog(LOG_INFO, "%d bytes flushed from log\n",
+ flushed);
+ } else if ((log != stdout) && (log != NULL)) {
+ fprintf(log, "%d bytes flushed from log\n", flushed);
+ }
+ }
+}
+
+
+static void logopts(turnon, options)
+ int turnon;
+ char *options;
+{
+ int flags = 0;
+ char *s;
+
+ for (s = options; *s; s++)
+ {
+ switch (*s)
+ {
+ case 'N' :
+ flags |= IPMON_NAT;
+ break;
+ case 'S' :
+ flags |= IPMON_STATE;
+ break;
+ case 'I' :
+ flags |= IPMON_FILTER;
+ break;
+ default :
+ fprintf(stderr, "Unknown log option %c\n", *s);
+ exit(1);
+ }
+ }
+
+ if (turnon)
+ ipmonopts |= flags;
+ else
+ ipmonopts &= ~(flags);
+}
+
+static void initconfig(config_t *conf)
+{
+ int i;
+
+ memset(conf, 0, sizeof(*conf));
+
+ conf->log = stdout;
+ conf->maxfd = -1;
+
+ for (i = 0; i < 3; i++) {
+ conf->logsrc[i].fd = -1;
+ conf->logsrc[i].logtype = -1;
+ conf->logsrc[i].regular = -1;
+ }
+
+ conf->logsrc[0].file = IPL_NAME;
+ conf->logsrc[1].file = IPNAT_NAME;
+ conf->logsrc[2].file = IPSTATE_NAME;
+
+ add_doing(&executesaver);
+ add_doing(&snmpv1saver);
+ add_doing(&snmpv2saver);
+ add_doing(&syslogsaver);
+ add_doing(&filesaver);
+ add_doing(&nothingsaver);
+}
+
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int doread, c, make_daemon = 0;
+ char *prog;
+ config_t config;
+
+ prog = strrchr(argv[0], '/');
+ if (prog == NULL)
+ prog = argv[0];
+ else
+ prog++;
+
+ initconfig(&config);
+
+ while ((c = getopt(argc, argv,
+ "?abB:C:Df:FhL:nN:o:O:pP:sS:tvxX")) != -1)
+ switch (c)
+ {
+ case 'a' :
+ ipmonopts |= IPMON_LOGALL;
+ config.logsrc[0].logtype = IPL_LOGIPF;
+ config.logsrc[1].logtype = IPL_LOGNAT;
+ config.logsrc[2].logtype = IPL_LOGSTATE;
+ break;
+ case 'b' :
+ ipmonopts |= IPMON_LOGBODY;
+ break;
+ case 'B' :
+ config.bfile = optarg;
+ config.blog = fopen(optarg, "a");
+ break;
+ case 'C' :
+ config.cfile = optarg;
+ break;
+ case 'D' :
+ make_daemon = 1;
+ break;
+ case 'f' : case 'I' :
+ ipmonopts |= IPMON_FILTER;
+ config.logsrc[0].logtype = IPL_LOGIPF;
+ config.logsrc[0].file = optarg;
+ break;
+ case 'F' :
+ flushlogs(config.logsrc[0].file, config.log);
+ flushlogs(config.logsrc[1].file, config.log);
+ flushlogs(config.logsrc[2].file, config.log);
+ break;
+ case 'L' :
+ logfac = fac_findname(optarg);
+ if (logfac == -1) {
+ fprintf(stderr,
+ "Unknown syslog facility '%s'\n",
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'n' :
+ ipmonopts |= IPMON_RESOLVE;
+ opts &= ~OPT_NORESOLVE;
+ break;
+ case 'N' :
+ ipmonopts |= IPMON_NAT;
+ config.logsrc[1].logtype = IPL_LOGNAT;
+ config.logsrc[1].file = optarg;
+ break;
+ case 'o' : case 'O' :
+ logopts(c == 'o', optarg);
+ if (ipmonopts & IPMON_FILTER)
+ config.logsrc[0].logtype = IPL_LOGIPF;
+ if (ipmonopts & IPMON_NAT)
+ config.logsrc[1].logtype = IPL_LOGNAT;
+ if (ipmonopts & IPMON_STATE)
+ config.logsrc[2].logtype = IPL_LOGSTATE;
+ break;
+ case 'p' :
+ ipmonopts |= IPMON_PORTNUM;
+ break;
+ case 'P' :
+ pidfile = optarg;
+ break;
+ case 's' :
+ ipmonopts |= IPMON_SYSLOG;
+ config.log = NULL;
+ break;
+ case 'S' :
+ ipmonopts |= IPMON_STATE;
+ config.logsrc[2].logtype = IPL_LOGSTATE;
+ config.logsrc[2].file = optarg;
+ break;
+ case 't' :
+ ipmonopts |= IPMON_TAIL;
+ break;
+ case 'v' :
+ ipmonopts |= IPMON_VERBOSE;
+ break;
+ case 'x' :
+ ipmonopts |= IPMON_HEXBODY;
+ break;
+ case 'X' :
+ ipmonopts |= IPMON_HEXHDR;
+ break;
+ default :
+ case 'h' :
+ case '?' :
+ usage(argv[0]);
+ }
+
+ if (ipmonopts & IPMON_SYSLOG)
+ openlog(prog, LOG_NDELAY|LOG_PID, logfac);
+
+ init_tabs();
+ if (config.cfile)
+ if (load_config(config.cfile) == -1) {
+ unload_config();
+ exit(1);
+ }
+
+ /*
+ * Default action is to only open the filter log file.
+ */
+ if ((config.logsrc[0].logtype == -1) &&
+ (config.logsrc[0].logtype == -1) &&
+ (config.logsrc[0].logtype == -1))
+ config.logsrc[0].logtype = IPL_LOGIPF;
+
+ openlogs(&config);
+
+ if (!(ipmonopts & IPMON_SYSLOG)) {
+ config.file = argv[optind];
+ config.log = config.file ? fopen(config.file, "a") : stdout;
+ if (config.log == NULL) {
+ (void) fprintf(stderr, "%s: fopen: %s\n",
+ argv[optind], STRERROR(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+ setvbuf(config.log, NULL, _IONBF, 0);
+ } else {
+ config.log = NULL;
+ }
+
+ if (make_daemon &&
+ ((config.log != stdout) || (ipmonopts & IPMON_SYSLOG))) {
+#if BSD >= 199306
+ daemon(0, !(ipmonopts & IPMON_SYSLOG));
+#else
+ int pid;
+
+ switch (fork())
+ {
+ case -1 :
+ (void) fprintf(stderr, "%s: fork() failed: %s\n",
+ argv[0], STRERROR(errno));
+ exit(1);
+ /* NOTREACHED */
+ case 0 :
+ break;
+ default :
+ exit(0);
+ }
+
+ setsid();
+ if ((ipmonopts & IPMON_SYSLOG))
+ close(2);
+#endif /* !BSD */
+ close(0);
+ close(1);
+ write_pid(pidfile);
+ }
+
+ signal(SIGHUP, handlehup);
+
+ for (doread = 1; doread; )
+ doread = read_loginfo(&config);
+
+ unload_config();
+
+ return(0);
+ /* NOTREACHED */
+}
+
+
+static void openlogs(config_t *conf)
+{
+ logsource_t *l;
+ struct stat sb;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ l = &conf->logsrc[i];
+ if (l->logtype == -1)
+ continue;
+ if (!strcmp(l->file, "-"))
+ l->fd = 0;
+ else {
+ if ((l->fd= open(l->file, O_RDONLY)) == -1) {
+ (void) fprintf(stderr,
+ "%s: open: %s\n", l->file,
+ STRERROR(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ if (fstat(l->fd, &sb) == -1) {
+ (void) fprintf(stderr, "%d: fstat: %s\n",
+ l->fd, STRERROR(errno));
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ l->regular = !S_ISCHR(sb.st_mode);
+ if (l->regular)
+ l->size = sb.st_size;
+
+ FD_SET(l->fd, &conf->fdmr);
+ if (l->fd > conf->maxfd)
+ conf->maxfd = l->fd;
+ }
+ }
+}
+
+
+static int read_loginfo(config_t *conf)
+{
+ iplog_t buf[DEFAULT_IPFLOGSIZE/sizeof(iplog_t)+1];
+ int n, tr, nr, i;
+ logsource_t *l;
+ fd_set fdr;
+
+ fdr = conf->fdmr;
+
+ n = select(conf->maxfd + 1, &fdr, NULL, NULL, NULL);
+ if (n == 0)
+ return 1;
+ if (n == -1) {
+ if (errno == EINTR)
+ return 1;
+ return -1;
+ }
+
+ for (i = 0, nr = 0; i < 3; i++) {
+ l = &conf->logsrc[i];
+
+ if ((l->logtype == -1) || !FD_ISSET(l->fd, &fdr))
+ continue;
+
+ tr = 0;
+ if (l->regular) {
+ tr = (lseek(l->fd, 0, SEEK_CUR) < l->size);
+ if (!tr && !(ipmonopts & IPMON_TAIL))
+ return 0;
+ }
+
+ n = 0;
+ tr = read_log(l->fd, &n, (char *)buf, sizeof(buf));
+ if (donehup) {
+ if (conf->file != NULL) {
+ if (conf->log != NULL) {
+ fclose(conf->log);
+ conf->log = NULL;
+ }
+ conf->log = fopen(conf->file, "a");
+ }
+
+ if (conf->bfile != NULL) {
+ if (conf->blog != NULL) {
+ fclose(conf->blog);
+ conf->blog = NULL;
+ }
+ conf->blog = fopen(conf->bfile, "a");
+ }
+
+ init_tabs();
+ if (conf->cfile != NULL)
+ load_config(conf->cfile);
+ donehup = 0;
+ }
+
+ switch (tr)
+ {
+ case -1 :
+ if (ipmonopts & IPMON_SYSLOG)
+ syslog(LOG_CRIT, "read: %m\n");
+ else {
+ ipferror(l->fd, "read");
+ }
+ return 0;
+ case 1 :
+ if (ipmonopts & IPMON_SYSLOG)
+ syslog(LOG_CRIT, "aborting logging\n");
+ else if (conf->log != NULL)
+ fprintf(conf->log, "aborting logging\n");
+ return 0;
+ case 2 :
+ break;
+ case 0 :
+ nr += tr;
+ if (n > 0) {
+ print_log(conf, l, (char *)buf, n);
+ if (!(ipmonopts & IPMON_SYSLOG))
+ fflush(conf->log);
+ }
+ break;
+ }
+ }
+
+ if (!nr && (ipmonopts & IPMON_TAIL))
+ sleep(1);
+
+ return 1;
+}
diff --git a/contrib/ipfilter/tools/ipmon_y.y b/contrib/ipfilter/tools/ipmon_y.y
new file mode 100644
index 0000000..f14180d
--- /dev/null
+++ b/contrib/ipfilter/tools/ipmon_y.y
@@ -0,0 +1,1052 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+%{
+#include "ipf.h"
+#include <syslog.h>
+#undef OPT_NAT
+#undef OPT_VERBOSE
+#include "ipmon_l.h"
+#include "ipmon.h"
+
+#include <dlfcn.h>
+
+#define YYDEBUG 1
+
+extern void yyerror __P((char *));
+extern int yyparse __P((void));
+extern int yylex __P((void));
+extern int yydebug;
+extern FILE *yyin;
+extern int yylineNum;
+extern int ipmonopts;
+
+typedef struct opt_s {
+ struct opt_s *o_next;
+ int o_line;
+ int o_type;
+ int o_num;
+ char *o_str;
+ struct in_addr o_ip;
+ int o_logfac;
+ int o_logpri;
+} opt_t;
+
+static void build_action __P((opt_t *, ipmon_doing_t *));
+static opt_t *new_opt __P((int));
+static void free_action __P((ipmon_action_t *));
+static void print_action __P((ipmon_action_t *));
+static int find_doing __P((char *));
+static ipmon_doing_t *build_doing __P((char *, char *));
+static void print_match __P((ipmon_action_t *));
+static int install_saver __P((char *, char *));
+
+static ipmon_action_t *alist = NULL;
+
+ipmon_saver_int_t *saverlist = NULL;
+%}
+
+%union {
+ char *str;
+ u_32_t num;
+ struct in_addr addr;
+ struct opt_s *opt;
+ union i6addr ip6;
+ struct ipmon_doing_s *ipmd;
+}
+
+%token <num> YY_NUMBER YY_HEX
+%token <str> YY_STR
+%token <ip6> YY_IPV6
+%token YY_COMMENT
+%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
+%token YY_RANGE_OUT YY_RANGE_IN
+
+%token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT
+%token IPM_EVERY IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT IPM_LOADACTION
+%token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE
+%token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH
+%token IPM_DO IPM_DOING IPM_TYPE IPM_NAT
+%token IPM_STATE IPM_NATTAG IPM_IPF
+%type <addr> ipv4
+%type <opt> direction dstip dstport every group interface
+%type <opt> protocol result rule srcip srcport logtag matching
+%type <opt> matchopt nattag type
+%type <num> typeopt
+%type <ipmd> doopt doing
+
+%%
+file: action
+ | file action
+ ;
+
+action: line ';'
+ | assign ';'
+ | IPM_COMMENT
+ | YY_COMMENT
+ ;
+
+line: IPM_MATCH '{' matching ';' '}' IPM_DO '{' doing ';' '}'
+ { build_action($3, $8);
+ resetlexer();
+ }
+ | IPM_LOADACTION YY_STR YY_STR { if (install_saver($2, $3))
+ yyerror("install saver");
+ }
+ ;
+
+assign: YY_STR assigning YY_STR { set_variable($1, $3);
+ resetlexer();
+ free($1);
+ free($3);
+ yyvarnext = 0;
+ }
+ ;
+
+assigning:
+ '=' { yyvarnext = 1; }
+ ;
+
+matching:
+ matchopt { $$ = $1; }
+ | matchopt ',' matching { $1->o_next = $3; $$ = $1; }
+ ;
+
+matchopt:
+ direction { $$ = $1; }
+ | dstip { $$ = $1; }
+ | dstport { $$ = $1; }
+ | every { $$ = $1; }
+ | group { $$ = $1; }
+ | interface { $$ = $1; }
+ | protocol { $$ = $1; }
+ | result { $$ = $1; }
+ | rule { $$ = $1; }
+ | srcip { $$ = $1; }
+ | srcport { $$ = $1; }
+ | logtag { $$ = $1; }
+ | nattag { $$ = $1; }
+ | type { $$ = $1; }
+ ;
+
+doing:
+ doopt { $$ = $1; }
+ | doopt ',' doing { $1->ipmd_next = $3; $$ = $1; }
+ ;
+
+doopt:
+ YY_STR { if (find_doing($1) != IPM_DOING)
+ yyerror("unknown action");
+ }
+ '(' YY_STR ')' { $$ = build_doing($1, $4);
+ if ($$ == NULL)
+ yyerror("action building");
+ }
+ | YY_STR { if (find_doing($1) == IPM_DOING)
+ $$ = build_doing($1, NULL);
+ }
+ ;
+
+direction:
+ IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION);
+ $$->o_num = IPM_IN; }
+ | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION);
+ $$->o_num = IPM_OUT; }
+ ;
+
+dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP);
+ $$->o_ip = $3;
+ $$->o_num = $5; }
+ ;
+
+dstport:
+ IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT);
+ $$->o_num = $3; }
+ | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT);
+ $$->o_str = $3; }
+ ;
+
+every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND);
+ $$->o_num = 1; }
+ | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND);
+ $$->o_num = $2; }
+ | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET);
+ $$->o_num = 1; }
+ | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET);
+ $$->o_num = $2; }
+ ;
+
+group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP);
+ $$->o_num = $3; }
+ | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP);
+ $$->o_str = $3; }
+ ;
+
+interface:
+ IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE);
+ $$->o_str = $3; }
+ ;
+
+logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG);
+ $$->o_num = $3; }
+ ;
+
+nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG);
+ $$->o_str = $3; }
+ ;
+
+protocol:
+ IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL);
+ $$->o_num = $3; }
+ | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL);
+ $$->o_num = getproto($3);
+ free($3);
+ }
+ ;
+
+result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT);
+ $$->o_str = $3; }
+ ;
+
+rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE);
+ $$->o_num = YY_NUMBER; }
+ ;
+
+srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP);
+ $$->o_ip = $3;
+ $$->o_num = $5; }
+ ;
+
+srcport:
+ IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT);
+ $$->o_num = $3; }
+ | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT);
+ $$->o_str = $3; }
+ ;
+
+type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE);
+ $$->o_num = $3; }
+ ;
+
+typeopt:
+ IPM_IPF { $$ = IPL_MAGIC; }
+ | IPM_NAT { $$ = IPL_MAGIC_NAT; }
+ | IPM_STATE { $$ = IPL_MAGIC_STATE; }
+ ;
+
+
+
+ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
+ { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
+ $$.s_addr = htonl($$.s_addr);
+ }
+%%
+static struct wordtab yywords[] = {
+ { "body", IPM_BODY },
+ { "direction", IPM_DIRECTION },
+ { "do", IPM_DO },
+ { "dstip", IPM_DSTIP },
+ { "dstport", IPM_DSTPORT },
+ { "every", IPM_EVERY },
+ { "group", IPM_GROUP },
+ { "in", IPM_IN },
+ { "interface", IPM_INTERFACE },
+ { "ipf", IPM_IPF },
+ { "load_action",IPM_LOADACTION },
+ { "logtag", IPM_LOGTAG },
+ { "match", IPM_MATCH },
+ { "nat", IPM_NAT },
+ { "nattag", IPM_NATTAG },
+ { "no", IPM_NO },
+ { "out", IPM_OUT },
+ { "packet", IPM_PACKET },
+ { "packets", IPM_PACKETS },
+ { "protocol", IPM_PROTOCOL },
+ { "result", IPM_RESULT },
+ { "rule", IPM_RULE },
+ { "second", IPM_SECOND },
+ { "seconds", IPM_SECONDS },
+ { "srcip", IPM_SRCIP },
+ { "srcport", IPM_SRCPORT },
+ { "state", IPM_STATE },
+ { "with", IPM_WITH },
+ { NULL, 0 }
+};
+
+static int macflags[17][2] = {
+ { IPM_DIRECTION, IPMAC_DIRECTION },
+ { IPM_DSTIP, IPMAC_DSTIP },
+ { IPM_DSTPORT, IPMAC_DSTPORT },
+ { IPM_GROUP, IPMAC_GROUP },
+ { IPM_INTERFACE, IPMAC_INTERFACE },
+ { IPM_LOGTAG, IPMAC_LOGTAG },
+ { IPM_NATTAG, IPMAC_NATTAG },
+ { IPM_PACKET, IPMAC_EVERY },
+ { IPM_PROTOCOL, IPMAC_PROTOCOL },
+ { IPM_RESULT, IPMAC_RESULT },
+ { IPM_RULE, IPMAC_RULE },
+ { IPM_SECOND, IPMAC_EVERY },
+ { IPM_SRCIP, IPMAC_SRCIP },
+ { IPM_SRCPORT, IPMAC_SRCPORT },
+ { IPM_TYPE, IPMAC_TYPE },
+ { IPM_WITH, IPMAC_WITH },
+ { 0, 0 }
+};
+
+static opt_t *
+new_opt(type)
+ int type;
+{
+ opt_t *o;
+
+ o = (opt_t *)calloc(1, sizeof(*o));
+ o->o_type = type;
+ o->o_line = yylineNum;
+ o->o_logfac = -1;
+ o->o_logpri = -1;
+ return o;
+}
+
+static void
+build_action(olist, todo)
+ opt_t *olist;
+ ipmon_doing_t *todo;
+{
+ ipmon_action_t *a;
+ opt_t *o;
+ int i;
+
+ a = (ipmon_action_t *)calloc(1, sizeof(*a));
+ if (a == NULL)
+ return;
+
+ while ((o = olist) != NULL) {
+ /*
+ * Check to see if the same comparator is being used more than
+ * once per matching statement.
+ */
+ for (i = 0; macflags[i][0]; i++)
+ if (macflags[i][0] == o->o_type)
+ break;
+ if (macflags[i][1] & a->ac_mflag) {
+ fprintf(stderr, "%s redfined on line %d\n",
+ yykeytostr(o->o_type), yylineNum);
+ if (o->o_str != NULL)
+ free(o->o_str);
+ olist = o->o_next;
+ free(o);
+ continue;
+ }
+
+ a->ac_mflag |= macflags[i][1];
+
+ switch (o->o_type)
+ {
+ case IPM_DIRECTION :
+ a->ac_direction = o->o_num;
+ break;
+ case IPM_DSTIP :
+ a->ac_dip = o->o_ip.s_addr;
+ a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num));
+ break;
+ case IPM_DSTPORT :
+ a->ac_dport = htons(o->o_num);
+ break;
+ case IPM_INTERFACE :
+ a->ac_iface = o->o_str;
+ o->o_str = NULL;
+ break;
+ case IPM_GROUP :
+ if (o->o_str != NULL)
+ strncpy(a->ac_group, o->o_str, FR_GROUPLEN);
+ else
+ sprintf(a->ac_group, "%d", o->o_num);
+ break;
+ case IPM_LOGTAG :
+ a->ac_logtag = o->o_num;
+ break;
+ case IPM_NATTAG :
+ strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag));
+ break;
+ case IPM_PACKET :
+ a->ac_packet = o->o_num;
+ break;
+ case IPM_PROTOCOL :
+ a->ac_proto = o->o_num;
+ break;
+ case IPM_RULE :
+ a->ac_rule = o->o_num;
+ break;
+ case IPM_RESULT :
+ if (!strcasecmp(o->o_str, "pass"))
+ a->ac_result = IPMR_PASS;
+ else if (!strcasecmp(o->o_str, "block"))
+ a->ac_result = IPMR_BLOCK;
+ else if (!strcasecmp(o->o_str, "nomatch"))
+ a->ac_result = IPMR_NOMATCH;
+ else if (!strcasecmp(o->o_str, "log"))
+ a->ac_result = IPMR_LOG;
+ break;
+ case IPM_SECOND :
+ a->ac_second = o->o_num;
+ break;
+ case IPM_SRCIP :
+ a->ac_sip = o->o_ip.s_addr;
+ a->ac_smsk = htonl(0xffffffff << (32 - o->o_num));
+ break;
+ case IPM_SRCPORT :
+ a->ac_sport = htons(o->o_num);
+ break;
+ case IPM_TYPE :
+ a->ac_type = o->o_num;
+ break;
+ case IPM_WITH :
+ break;
+ default :
+ break;
+ }
+
+ olist = o->o_next;
+ if (o->o_str != NULL)
+ free(o->o_str);
+ free(o);
+ }
+
+ a->ac_doing = todo;
+ a->ac_next = alist;
+ alist = a;
+
+ if (ipmonopts & IPMON_VERBOSE)
+ print_action(a);
+}
+
+
+int
+check_action(buf, log, opts, lvl)
+ char *buf, *log;
+ int opts, lvl;
+{
+ ipmon_action_t *a;
+ struct timeval tv;
+ ipmon_doing_t *d;
+ ipmon_msg_t msg;
+ ipflog_t *ipf;
+ tcphdr_t *tcp;
+ iplog_t *ipl;
+ int matched;
+ u_long t1;
+ ip_t *ip;
+
+ matched = 0;
+ ipl = (iplog_t *)buf;
+ ipf = (ipflog_t *)(ipl +1);
+ ip = (ip_t *)(ipf + 1);
+ tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2));
+
+ msg.imm_data = ipl;
+ msg.imm_dsize = ipl->ipl_dsize;
+ msg.imm_when = ipl->ipl_time.tv_sec;
+ msg.imm_msg = log;
+ msg.imm_msglen = strlen(log);
+ msg.imm_loglevel = lvl;
+
+ for (a = alist; a != NULL; a = a->ac_next) {
+ verbose(0, "== checking config rule\n");
+ if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
+ if (a->ac_direction == IPM_IN) {
+ if ((ipf->fl_flags & FR_INQUE) == 0) {
+ verbose(8, "-- direction not in\n");
+ continue;
+ }
+ } else if (a->ac_direction == IPM_OUT) {
+ if ((ipf->fl_flags & FR_OUTQUE) == 0) {
+ verbose(8, "-- direction not out\n");
+ continue;
+ }
+ }
+ }
+
+ if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) {
+ verbose(8, "-- type mismatch\n");
+ continue;
+ }
+
+ if ((a->ac_mflag & IPMAC_EVERY) != 0) {
+ gettimeofday(&tv, NULL);
+ t1 = tv.tv_sec - a->ac_lastsec;
+ if (tv.tv_usec <= a->ac_lastusec)
+ t1--;
+ if (a->ac_second != 0) {
+ if (t1 < a->ac_second) {
+ verbose(8, "-- too soon\n");
+ continue;
+ }
+ a->ac_lastsec = tv.tv_sec;
+ a->ac_lastusec = tv.tv_usec;
+ }
+
+ if (a->ac_packet != 0) {
+ if (a->ac_pktcnt == 0)
+ a->ac_pktcnt++;
+ else if (a->ac_pktcnt == a->ac_packet) {
+ a->ac_pktcnt = 0;
+ verbose(8, "-- packet count\n");
+ continue;
+ } else {
+ a->ac_pktcnt++;
+ verbose(8, "-- packet count\n");
+ continue;
+ }
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
+ if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) {
+ verbose(8, "-- dstip wrong\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
+ if (ip->ip_p != IPPROTO_UDP &&
+ ip->ip_p != IPPROTO_TCP) {
+ verbose(8, "-- not port protocol\n");
+ continue;
+ }
+ if (tcp->th_dport != a->ac_dport) {
+ verbose(8, "-- dport mismatch\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_GROUP) != 0) {
+ if (strncmp(a->ac_group, ipf->fl_group,
+ FR_GROUPLEN) != 0) {
+ verbose(8, "-- group mismatch\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
+ if (strcmp(a->ac_iface, ipf->fl_ifname)) {
+ verbose(8, "-- ifname mismatch\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
+ if (a->ac_proto != ip->ip_p) {
+ verbose(8, "-- protocol mismatch\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_RESULT) != 0) {
+ if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) {
+ if (a->ac_result != IPMR_NOMATCH) {
+ verbose(8, "-- ff-flags mismatch\n");
+ continue;
+ }
+ } else if (FR_ISPASS(ipf->fl_flags)) {
+ if (a->ac_result != IPMR_PASS) {
+ verbose(8, "-- pass mismatch\n");
+ continue;
+ }
+ } else if (FR_ISBLOCK(ipf->fl_flags)) {
+ if (a->ac_result != IPMR_BLOCK) {
+ verbose(8, "-- block mismatch\n");
+ continue;
+ }
+ } else { /* Log only */
+ if (a->ac_result != IPMR_LOG) {
+ verbose(8, "-- log mismatch\n");
+ continue;
+ }
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_RULE) != 0) {
+ if (a->ac_rule != ipf->fl_rule) {
+ verbose(8, "-- rule mismatch\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
+ if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) {
+ verbose(8, "-- srcip mismatch\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
+ if (ip->ip_p != IPPROTO_UDP &&
+ ip->ip_p != IPPROTO_TCP) {
+ verbose(8, "-- port protocol mismatch\n");
+ continue;
+ }
+ if (tcp->th_sport != a->ac_sport) {
+ verbose(8, "-- sport mismatch\n");
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
+ if (a->ac_logtag != ipf->fl_logtag) {
+ verbose(8, "-- logtag %d != %d\n",
+ a->ac_logtag, ipf->fl_logtag);
+ continue;
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
+ if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag,
+ IPFTAG_LEN) != 0) {
+ verbose(8, "-- nattag mismatch\n");
+ continue;
+ }
+ }
+
+ matched = 1;
+ verbose(8, "++ matched\n");
+
+ /*
+ * It matched so now perform the saves
+ */
+ for (d = a->ac_doing; d != NULL; d = d->ipmd_next)
+ (*d->ipmd_store)(d->ipmd_token, &msg);
+ }
+
+ return matched;
+}
+
+
+static void
+free_action(a)
+ ipmon_action_t *a;
+{
+ ipmon_doing_t *d;
+
+ while ((d = a->ac_doing) != NULL) {
+ a->ac_doing = d->ipmd_next;
+ (*d->ipmd_saver->ims_destroy)(d->ipmd_token);
+ free(d);
+ }
+
+ if (a->ac_iface != NULL) {
+ free(a->ac_iface);
+ a->ac_iface = NULL;
+ }
+ a->ac_next = NULL;
+ free(a);
+}
+
+
+int
+load_config(file)
+ char *file;
+{
+ FILE *fp;
+ char *s;
+
+ unload_config();
+
+ s = getenv("YYDEBUG");
+ if (s != NULL)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ yylineNum = 1;
+
+ (void) yysettab(yywords);
+
+ fp = fopen(file, "r");
+ if (!fp) {
+ perror("load_config:fopen:");
+ return -1;
+ }
+ yyin = fp;
+ while (!feof(fp))
+ yyparse();
+ fclose(fp);
+ return 0;
+}
+
+
+void
+unload_config()
+{
+ ipmon_saver_int_t *sav, **imsip;
+ ipmon_saver_t *is;
+ ipmon_action_t *a;
+
+ while ((a = alist) != NULL) {
+ alist = a->ac_next;
+ free_action(a);
+ }
+
+ /*
+ * Look for savers that have been added in dynamically from the
+ * configuration file.
+ */
+ for (imsip = &saverlist; (sav = *imsip) != NULL; ) {
+ if (sav->imsi_handle == NULL)
+ imsip = &sav->imsi_next;
+ else {
+ dlclose(sav->imsi_handle);
+
+ *imsip = sav->imsi_next;
+ is = sav->imsi_stor;
+ free(sav);
+
+ free(is->ims_name);
+ free(is);
+ }
+ }
+}
+
+
+void
+dump_config()
+{
+ ipmon_action_t *a;
+
+ for (a = alist; a != NULL; a = a->ac_next) {
+ print_action(a);
+
+ printf("#\n");
+ }
+}
+
+
+static void
+print_action(a)
+ ipmon_action_t *a;
+{
+ ipmon_doing_t *d;
+
+ printf("match { ");
+ print_match(a);
+ printf("; }\n");
+ printf("do {");
+ for (d = a->ac_doing; d != NULL; d = d->ipmd_next) {
+ printf("%s", d->ipmd_saver->ims_name);
+ if (d->ipmd_saver->ims_print != NULL) {
+ printf("(\"");
+ (*d->ipmd_saver->ims_print)(d->ipmd_token);
+ printf("\")");
+ }
+ printf(";");
+ }
+ printf("};\n");
+}
+
+
+void *
+add_doing(saver)
+ ipmon_saver_t *saver;
+{
+ ipmon_saver_int_t *it;
+
+ if (find_doing(saver->ims_name) == IPM_DOING)
+ return NULL;
+
+ it = calloc(1, sizeof(*it));
+ if (it == NULL)
+ return NULL;
+ it->imsi_stor = saver;
+ it->imsi_next = saverlist;
+ saverlist = it;
+ return it;
+}
+
+
+static int
+find_doing(string)
+ char *string;
+{
+ ipmon_saver_int_t *it;
+
+ for (it = saverlist; it != NULL; it = it->imsi_next) {
+ if (!strcmp(it->imsi_stor->ims_name, string))
+ return IPM_DOING;
+ }
+ return 0;
+}
+
+
+static ipmon_doing_t *
+build_doing(target, options)
+ char *target;
+ char *options;
+{
+ ipmon_saver_int_t *it;
+ char *strarray[2];
+ ipmon_doing_t *d, *d1;
+ ipmon_action_t *a;
+ ipmon_saver_t *save;
+
+ d = calloc(1, sizeof(*d));
+ if (d == NULL)
+ return NULL;
+
+ for (it = saverlist; it != NULL; it = it->imsi_next) {
+ if (!strcmp(it->imsi_stor->ims_name, target))
+ break;
+ }
+ if (it == NULL) {
+ free(d);
+ return NULL;
+ }
+
+ strarray[0] = options;
+ strarray[1] = NULL;
+
+ d->ipmd_token = (*it->imsi_stor->ims_parse)(strarray);
+ if (d->ipmd_token == NULL) {
+ free(d);
+ return NULL;
+ }
+
+ save = it->imsi_stor;
+ d->ipmd_saver = save;
+ d->ipmd_store = it->imsi_stor->ims_store;
+
+ /*
+ * Look for duplicate do-things that need to be dup'd
+ */
+ for (a = alist; a != NULL; a = a->ac_next) {
+ for (d1 = a->ac_doing; d1 != NULL; d1 = d1->ipmd_next) {
+ if (save != d1->ipmd_saver)
+ continue;
+ if (save->ims_match == NULL || save->ims_dup == NULL)
+ continue;
+ if ((*save->ims_match)(d->ipmd_token, d1->ipmd_token))
+ continue;
+
+ (*d->ipmd_saver->ims_destroy)(d->ipmd_token);
+ d->ipmd_token = (*save->ims_dup)(d1->ipmd_token);
+ break;
+ }
+ }
+
+ return d;
+}
+
+
+static void
+print_match(a)
+ ipmon_action_t *a;
+{
+ char *coma = "";
+
+ if ((a->ac_mflag & IPMAC_DIRECTION) != 0) {
+ printf("direction = ");
+ if (a->ac_direction == IPM_IN)
+ printf("in");
+ else if (a->ac_direction == IPM_OUT)
+ printf("out");
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_DSTIP) != 0) {
+ printf("%sdstip = ", coma);
+ printhostmask(AF_INET, &a->ac_dip, &a->ac_dmsk);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_DSTPORT) != 0) {
+ printf("%sdstport = %hu", coma, ntohs(a->ac_dport));
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_GROUP) != 0) {
+ char group[FR_GROUPLEN+1];
+
+ strncpy(group, a->ac_group, FR_GROUPLEN);
+ group[FR_GROUPLEN] = '\0';
+ printf("%sgroup = %s", coma, group);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_INTERFACE) != 0) {
+ printf("%siface = %s", coma, a->ac_iface);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_LOGTAG) != 0) {
+ printf("%slogtag = %u", coma, a->ac_logtag);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_NATTAG) != 0) {
+ char tag[17];
+
+ strncpy(tag, a->ac_nattag, 16);
+ tag[16] = '\0';
+ printf("%snattag = %s", coma, tag);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) {
+ printf("%sprotocol = %u", coma, a->ac_proto);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_RESULT) != 0) {
+ printf("%sresult = ", coma);
+ switch (a->ac_result)
+ {
+ case IPMR_LOG :
+ printf("log");
+ break;
+ case IPMR_PASS :
+ printf("pass");
+ break;
+ case IPMR_BLOCK :
+ printf("block");
+ break;
+ case IPMR_NOMATCH :
+ printf("nomatch");
+ break;
+ }
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_RULE) != 0) {
+ printf("%srule = %u", coma, a->ac_rule);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_EVERY) != 0) {
+ if (a->ac_packet > 1) {
+ printf("%severy %d packets", coma, a->ac_packet);
+ coma = ", ";
+ } else if (a->ac_packet == 1) {
+ printf("%severy packet", coma);
+ coma = ", ";
+ }
+ if (a->ac_second > 1) {
+ printf("%severy %d seconds", coma, a->ac_second);
+ coma = ", ";
+ } else if (a->ac_second == 1) {
+ printf("%severy second", coma);
+ coma = ", ";
+ }
+ }
+
+ if ((a->ac_mflag & IPMAC_SRCIP) != 0) {
+ printf("%ssrcip = ", coma);
+ printhostmask(AF_INET, &a->ac_sip, &a->ac_smsk);
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_SRCPORT) != 0) {
+ printf("%ssrcport = %hu", coma, ntohs(a->ac_sport));
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_TYPE) != 0) {
+ printf("%stype = ", coma);
+ switch (a->ac_type)
+ {
+ case IPL_LOGIPF :
+ printf("ipf");
+ break;
+ case IPL_LOGSTATE :
+ printf("state");
+ break;
+ case IPL_LOGNAT :
+ printf("nat");
+ break;
+ }
+ coma = ", ";
+ }
+
+ if ((a->ac_mflag & IPMAC_WITH) != 0) {
+ printf("%swith ", coma);
+ coma = ", ";
+ }
+}
+
+
+static int
+install_saver(name, path)
+ char *name, *path;
+{
+ ipmon_saver_int_t *isi;
+ ipmon_saver_t *is;
+ char nbuf[80];
+
+ if (find_doing(name) == IPM_DOING)
+ return -1;
+
+ isi = calloc(1, sizeof(*isi));
+ if (isi == NULL)
+ return -1;
+
+ is = calloc(1, sizeof(*is));
+ if (is == NULL)
+ goto loaderror;
+
+ is->ims_name = name;
+
+#ifdef RTLD_LAZY
+ isi->imsi_handle = dlopen(path, RTLD_LAZY);
+#endif
+#ifdef DL_LAZY
+ isi->imsi_handle = dlopen(path, DL_LAZY);
+#endif
+
+ if (isi->imsi_handle == NULL)
+ goto loaderror;
+
+ snprintf(nbuf, sizeof(nbuf), "%sdup", name);
+ is->ims_dup = (ims_dup_func_t)dlsym(isi->imsi_handle, nbuf);
+
+ snprintf(nbuf, sizeof(nbuf), "%sdestroy", name);
+ is->ims_destroy = (ims_destroy_func_t)dlsym(isi->imsi_handle, nbuf);
+ if (is->ims_destroy == NULL)
+ goto loaderror;
+
+ snprintf(nbuf, sizeof(nbuf), "%smatch", name);
+ is->ims_match = (ims_match_func_t)dlsym(isi->imsi_handle, nbuf);
+
+ snprintf(nbuf, sizeof(nbuf), "%sparse", name);
+ is->ims_parse = (ims_parse_func_t)dlsym(isi->imsi_handle, nbuf);
+ if (is->ims_parse == NULL)
+ goto loaderror;
+
+ snprintf(nbuf, sizeof(nbuf), "%sprint", name);
+ is->ims_print = (ims_print_func_t)dlsym(isi->imsi_handle, nbuf);
+ if (is->ims_print == NULL)
+ goto loaderror;
+
+ snprintf(nbuf, sizeof(nbuf), "%sstore", name);
+ is->ims_store = (ims_store_func_t)dlsym(isi->imsi_handle, nbuf);
+ if (is->ims_store == NULL)
+ goto loaderror;
+
+ isi->imsi_stor = is;
+ isi->imsi_next = saverlist;
+ saverlist = isi;
+
+ return 0;
+
+loaderror:
+ if (isi->imsi_handle != NULL)
+ dlclose(isi->imsi_handle);
+ free(isi);
+ if (is != NULL)
+ free(is);
+ return -1;
+}
diff --git a/contrib/ipfilter/tools/ipnat.c b/contrib/ipfilter/tools/ipnat.c
new file mode 100644
index 0000000..c3a7156
--- /dev/null
+++ b/contrib/ipfilter/tools/ipnat.c
@@ -0,0 +1,855 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/time.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/file.h>
+#define _KERNEL
+#include <sys/uio.h>
+#undef _KERNEL
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+# include <sys/ioccom.h>
+# include <sys/sysmacros.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <ctype.h>
+#if defined(linux)
+# include <linux/a.out.h>
+#else
+# include <nlist.h>
+#endif
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include "kmem.h"
+
+#ifdef __hpux
+# define nlist nlist64
+#endif
+
+#if defined(sun) && !SOLARIS2
+# define STRERROR(x) sys_errlist[x]
+extern char *sys_errlist[];
+#else
+# define STRERROR(x) strerror(x)
+#endif
+
+#if !defined(lint)
+static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+
+
+#if SOLARIS
+#define bzero(a,b) memset(a,0,b)
+#endif
+int use_inet6 = 0;
+char thishost[MAXHOSTNAMELEN];
+
+extern char *optarg;
+
+void dostats __P((int, natstat_t *, int, int, int *));
+void dotable __P((natstat_t *, int, int, int, char *));
+void flushtable __P((int, int, int *));
+void usage __P((char *));
+int main __P((int, char*[]));
+void showhostmap __P((natstat_t *nsp));
+void natstat_dead __P((natstat_t *, char *));
+void dostats_live __P((int, natstat_t *, int, int *));
+void showhostmap_dead __P((natstat_t *));
+void showhostmap_live __P((int, natstat_t *));
+void dostats_dead __P((natstat_t *, int, int *));
+int nat_matcharray __P((nat_t *, int *));
+
+int opts;
+int nohdrfields = 0;
+wordtab_t *nat_fields = NULL;
+
+void usage(name)
+ char *name;
+{
+ fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name);
+ exit(1);
+}
+
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int fd, c, mode, *natfilter;
+ char *file, *core, *kernel;
+ natstat_t ns, *nsp;
+ ipfobj_t obj;
+
+ fd = -1;
+ opts = 0;
+ nsp = &ns;
+ file = NULL;
+ core = NULL;
+ kernel = NULL;
+ mode = O_RDWR;
+ natfilter = NULL;
+
+ assigndefined(getenv("IPNAT_PREDEFINED"));
+
+ while ((c = getopt(argc, argv, "CdFf:hlm:M:N:nO:prRsv")) != -1)
+ switch (c)
+ {
+ case 'C' :
+ opts |= OPT_CLEAR;
+ break;
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'f' :
+ file = optarg;
+ break;
+ case 'F' :
+ opts |= OPT_FLUSH;
+ break;
+ case 'h' :
+ opts |=OPT_HITS;
+ break;
+ case 'l' :
+ opts |= OPT_LIST;
+ mode = O_RDONLY;
+ break;
+ case 'm' :
+ natfilter = parseipfexpr(optarg, NULL);
+ break;
+ case 'M' :
+ core = optarg;
+ break;
+ case 'N' :
+ kernel = optarg;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ mode = O_RDONLY;
+ break;
+ case 'O' :
+ nat_fields = parsefields(natfields, optarg);
+ break;
+ case 'p' :
+ opts |= OPT_PURGE;
+ break;
+ case 'R' :
+ opts |= OPT_NORESOLVE;
+ break;
+ case 'r' :
+ opts |= OPT_REMOVE;
+ break;
+ case 's' :
+ opts |= OPT_STAT;
+ mode = O_RDONLY;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ usage(argv[0]);
+ }
+
+ if (((opts & OPT_PURGE) != 0) && ((opts & OPT_REMOVE) == 0)) {
+ (void) fprintf(stderr, "%s: -p must be used with -r\n",
+ argv[0]);
+ exit(1);
+ }
+
+ initparse();
+
+ if ((kernel != NULL) || (core != NULL)) {
+ (void) setgid(getgid());
+ (void) setuid(getuid());
+ }
+
+ if (!(opts & OPT_DONOTHING)) {
+ if (((fd = open(IPNAT_NAME, mode)) == -1) &&
+ ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
+ (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
+ STRERROR(errno));
+ exit(1);
+ }
+ }
+
+ bzero((char *)&ns, sizeof(ns));
+
+ if ((opts & OPT_DONOTHING) == 0) {
+ if (checkrev(IPL_NAME) == -1) {
+ fprintf(stderr, "User/kernel version check failed\n");
+ exit(1);
+ }
+ }
+
+ if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_NATSTAT;
+ obj.ipfo_size = sizeof(*nsp);
+ obj.ipfo_ptr = (void *)nsp;
+ if (ioctl(fd, SIOCGNATS, &obj) == -1) {
+ ipferror(fd, "ioctl(SIOCGNATS)");
+ exit(1);
+ }
+ (void) setgid(getgid());
+ (void) setuid(getuid());
+ } else if ((kernel != NULL) || (core != NULL)) {
+ if (openkmem(kernel, core) == -1)
+ exit(1);
+
+ natstat_dead(nsp, kernel);
+ if (opts & (OPT_LIST|OPT_STAT))
+ dostats(fd, nsp, opts, 0, natfilter);
+ exit(0);
+ }
+
+ if (opts & (OPT_FLUSH|OPT_CLEAR))
+ flushtable(fd, opts, natfilter);
+ if (file) {
+ return ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
+ }
+ if (opts & (OPT_LIST|OPT_STAT))
+ dostats(fd, nsp, opts, 1, natfilter);
+ return 0;
+}
+
+
+/*
+ * Read NAT statistic information in using a symbol table and memory file
+ * rather than doing ioctl's.
+ */
+void natstat_dead(nsp, kernel)
+ natstat_t *nsp;
+ char *kernel;
+{
+ struct nlist nat_nlist[10] = {
+ { "nat_table" }, /* 0 */
+ { "nat_list" },
+ { "maptable" },
+ { "ipf_nattable_sz" },
+ { "ipf_natrules_sz" },
+ { "ipf_rdrrules_sz" }, /* 5 */
+ { "ipf_hostmap_sz" },
+ { "nat_instances" },
+ { NULL }
+ };
+ void *tables[2];
+
+ if (nlist(kernel, nat_nlist) == -1) {
+ fprintf(stderr, "nlist error\n");
+ return;
+ }
+
+ /*
+ * Normally the ioctl copies all of these values into the structure
+ * for us, before returning it to userland, so here we must copy each
+ * one in individually.
+ */
+ kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables));
+ nsp->ns_side[0].ns_table = tables[0];
+ nsp->ns_side[1].ns_table = tables[1];
+
+ kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value,
+ sizeof(nsp->ns_list));
+ kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value,
+ sizeof(nsp->ns_maptable));
+ kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value,
+ sizeof(nsp->ns_nattab_sz));
+ kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value,
+ sizeof(nsp->ns_rultab_sz));
+ kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value,
+ sizeof(nsp->ns_rdrtab_sz));
+ kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value,
+ sizeof(nsp->ns_hostmap_sz));
+ kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value,
+ sizeof(nsp->ns_instances));
+}
+
+
+/*
+ * Issue an ioctl to flush either the NAT rules table or the active mapping
+ * table or both.
+ */
+void flushtable(fd, opts, match)
+ int fd, opts, *match;
+{
+ int n = 0;
+
+ if (opts & OPT_FLUSH) {
+ n = 0;
+ if (!(opts & OPT_DONOTHING)) {
+ if (match != NULL) {
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = match[0] * sizeof(int);
+ obj.ipfo_type = IPFOBJ_IPFEXPR;
+ obj.ipfo_ptr = match;
+ if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) {
+ ipferror(fd, "ioctl(SIOCMATCHFLUSH)");
+ n = -1;
+ } else {
+ n = obj.ipfo_retval;
+ }
+ } else if (ioctl(fd, SIOCIPFFL, &n) == -1) {
+ ipferror(fd, "ioctl(SIOCIPFFL)");
+ n = -1;
+ }
+ }
+ if (n >= 0)
+ printf("%d entries flushed from NAT table\n", n);
+ }
+
+ if (opts & OPT_CLEAR) {
+ n = 1;
+ if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1)
+ ipferror(fd, "ioctl(SIOCCNATL)");
+ else
+ printf("%d entries flushed from NAT list\n", n);
+ }
+}
+
+
+/*
+ * Display NAT statistics.
+ */
+void dostats_dead(nsp, opts, filter)
+ natstat_t *nsp;
+ int opts, *filter;
+{
+ nat_t *np, nat;
+ ipnat_t ipn;
+ int i;
+
+ if (nat_fields == NULL) {
+ printf("List of active MAP/Redirect filters:\n");
+ while (nsp->ns_list) {
+ if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
+ sizeof(ipn))) {
+ perror("kmemcpy");
+ break;
+ }
+ if (opts & OPT_HITS)
+ printf("%lu ", ipn.in_hits);
+ printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
+ nsp->ns_list = ipn.in_next;
+ }
+ }
+
+ if (nat_fields == NULL) {
+ printf("\nList of active sessions:\n");
+
+ } else if (nohdrfields == 0) {
+ for (i = 0; nat_fields[i].w_value != 0; i++) {
+ printfieldhdr(natfields, nat_fields + i);
+ if (nat_fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ }
+
+ for (np = nsp->ns_instances; np; np = nat.nat_next) {
+ if (kmemcpy((char *)&nat, (long)np, sizeof(nat)))
+ break;
+ if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
+ continue;
+ if (nat_fields != NULL) {
+ for (i = 0; nat_fields[i].w_value != 0; i++) {
+ printnatfield(&nat, nat_fields[i].w_value);
+ if (nat_fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ } else {
+ printactivenat(&nat, opts, nsp->ns_ticks);
+ if (nat.nat_aps) {
+ int proto;
+
+ if (nat.nat_dir & NAT_OUTBOUND)
+ proto = nat.nat_pr[1];
+ else
+ proto = nat.nat_pr[0];
+ printaps(nat.nat_aps, opts, proto);
+ }
+ }
+ }
+
+ if (opts & OPT_VERBOSE)
+ showhostmap_dead(nsp);
+}
+
+
+void dotable(nsp, fd, alive, which, side)
+ natstat_t *nsp;
+ int fd, alive, which;
+ char *side;
+{
+ int sz, i, used, maxlen, minlen, totallen;
+ ipftable_t table;
+ u_int *buckets;
+ ipfobj_t obj;
+
+ sz = sizeof(*buckets) * nsp->ns_nattab_sz;
+ buckets = (u_int *)malloc(sz);
+ if (buckets == NULL) {
+ fprintf(stderr,
+ "cannot allocate memory (%d) for buckets\n", sz);
+ return;
+ }
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_GTABLE;
+ obj.ipfo_size = sizeof(table);
+ obj.ipfo_ptr = &table;
+
+ if (which == 0) {
+ table.ita_type = IPFTABLE_BUCKETS_NATIN;
+ } else if (which == 1) {
+ table.ita_type = IPFTABLE_BUCKETS_NATOUT;
+ }
+ table.ita_table = buckets;
+
+ if (alive) {
+ if (ioctl(fd, SIOCGTABL, &obj) != 0) {
+ ipferror(fd, "SIOCFTABL");
+ free(buckets);
+ return;
+ }
+ } else {
+ if (kmemcpy((char *)buckets, (u_long)nsp->ns_nattab_sz, sz)) {
+ free(buckets);
+ return;
+ }
+ }
+
+ minlen = nsp->ns_side[which].ns_inuse;
+ totallen = 0;
+ maxlen = 0;
+ used = 0;
+
+ for (i = 0; i < nsp->ns_nattab_sz; i++) {
+ if (buckets[i] > maxlen)
+ maxlen = buckets[i];
+ if (buckets[i] < minlen)
+ minlen = buckets[i];
+ if (buckets[i] != 0)
+ used++;
+ totallen += buckets[i];
+ }
+
+ printf("%d%%\thash efficiency %s\n",
+ totallen ? used * 100 / totallen : 0, side);
+ printf("%2.2f%%\tbucket usage %s\n",
+ ((float)used / nsp->ns_nattab_sz) * 100.0, side);
+ printf("%d\tminimal length %s\n", minlen, side);
+ printf("%d\tmaximal length %s\n", maxlen, side);
+ printf("%.3f\taverage length %s\n",
+ used ? ((float)totallen / used) : 0.0, side);
+
+ free(buckets);
+}
+
+
+void dostats(fd, nsp, opts, alive, filter)
+ natstat_t *nsp;
+ int fd, opts, alive, *filter;
+{
+ /*
+ * Show statistics ?
+ */
+ if (opts & OPT_STAT) {
+ printnatside("in", &nsp->ns_side[0]);
+ dotable(nsp, fd, alive, 0, "in");
+
+ printnatside("out", &nsp->ns_side[1]);
+ dotable(nsp, fd, alive, 1, "out");
+
+ printf("%lu\tlog successes\n", nsp->ns_side[0].ns_log);
+ printf("%lu\tlog failures\n", nsp->ns_side[1].ns_log);
+ printf("%lu\tadded in\n%lu\tadded out\n",
+ nsp->ns_side[0].ns_added,
+ nsp->ns_side[1].ns_added);
+ printf("%u\tactive\n", nsp->ns_active);
+ printf("%lu\ttransparent adds\n", nsp->ns_addtrpnt);
+ printf("%lu\tdivert build\n", nsp->ns_divert_build);
+ printf("%lu\texpired\n", nsp->ns_expire);
+ printf("%lu\tflush all\n", nsp->ns_flush_all);
+ printf("%lu\tflush closing\n", nsp->ns_flush_closing);
+ printf("%lu\tflush queue\n", nsp->ns_flush_queue);
+ printf("%lu\tflush state\n", nsp->ns_flush_state);
+ printf("%lu\tflush timeout\n", nsp->ns_flush_timeout);
+ printf("%lu\thostmap new\n", nsp->ns_hm_new);
+ printf("%lu\thostmap fails\n", nsp->ns_hm_newfail);
+ printf("%lu\thostmap add\n", nsp->ns_hm_addref);
+ printf("%lu\thostmap NULL rule\n", nsp->ns_hm_nullnp);
+ printf("%lu\tlog ok\n", nsp->ns_log_ok);
+ printf("%lu\tlog fail\n", nsp->ns_log_fail);
+ printf("%u\torphan count\n", nsp->ns_orphans);
+ printf("%u\trule count\n", nsp->ns_rules);
+ printf("%u\tmap rules\n", nsp->ns_rules_map);
+ printf("%u\trdr rules\n", nsp->ns_rules_rdr);
+ printf("%u\twilds\n", nsp->ns_wilds);
+ if (opts & OPT_VERBOSE)
+ printf("list %p\n", nsp->ns_list);
+ }
+
+ if (opts & OPT_LIST) {
+ if (alive)
+ dostats_live(fd, nsp, opts, filter);
+ else
+ dostats_dead(nsp, opts, filter);
+ }
+}
+
+
+/*
+ * Display NAT statistics.
+ */
+void dostats_live(fd, nsp, opts, filter)
+ natstat_t *nsp;
+ int fd, opts, *filter;
+{
+ ipfgeniter_t iter;
+ char buffer[2000];
+ ipfobj_t obj;
+ ipnat_t *ipn;
+ nat_t nat;
+ int i;
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_GENITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.igi_type = IPFGENITER_IPNAT;
+ iter.igi_nitems = 1;
+ iter.igi_data = buffer;
+ ipn = (ipnat_t *)buffer;
+
+ /*
+ * Show list of NAT rules and NAT sessions ?
+ */
+ if (nat_fields == NULL) {
+ printf("List of active MAP/Redirect filters:\n");
+ while (nsp->ns_list) {
+ if (ioctl(fd, SIOCGENITER, &obj) == -1)
+ break;
+ if (opts & OPT_HITS)
+ printf("%lu ", ipn->in_hits);
+ printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
+ nsp->ns_list = ipn->in_next;
+ }
+ }
+
+ if (nat_fields == NULL) {
+ printf("\nList of active sessions:\n");
+
+ } else if (nohdrfields == 0) {
+ for (i = 0; nat_fields[i].w_value != 0; i++) {
+ printfieldhdr(natfields, nat_fields + i);
+ if (nat_fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ }
+
+ i = IPFGENITER_IPNAT;
+ (void) ioctl(fd,SIOCIPFDELTOK, &i);
+
+
+ iter.igi_type = IPFGENITER_NAT;
+ iter.igi_nitems = 1;
+ iter.igi_data = &nat;
+
+ while (nsp->ns_instances != NULL) {
+ if (ioctl(fd, SIOCGENITER, &obj) == -1)
+ break;
+ if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0))
+ continue;
+ if (nat_fields != NULL) {
+ for (i = 0; nat_fields[i].w_value != 0; i++) {
+ printnatfield(&nat, nat_fields[i].w_value);
+ if (nat_fields[i + 1].w_value != 0)
+ printf("\t");
+ }
+ printf("\n");
+ } else {
+ printactivenat(&nat, opts, nsp->ns_ticks);
+ if (nat.nat_aps) {
+ int proto;
+
+ if (nat.nat_dir & NAT_OUTBOUND)
+ proto = nat.nat_pr[1];
+ else
+ proto = nat.nat_pr[0];
+ printaps(nat.nat_aps, opts, proto);
+ }
+ }
+ nsp->ns_instances = nat.nat_next;
+ }
+
+ if (opts & OPT_VERBOSE)
+ showhostmap_live(fd, nsp);
+
+ i = IPFGENITER_NAT;
+ (void) ioctl(fd,SIOCIPFDELTOK, &i);
+}
+
+
+/*
+ * Display the active host mapping table.
+ */
+void showhostmap_dead(nsp)
+ natstat_t *nsp;
+{
+ hostmap_t hm, *hmp, **maptable;
+ u_int hv;
+
+ printf("\nList of active host mappings:\n");
+
+ maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) *
+ nsp->ns_hostmap_sz);
+ if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable,
+ sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) {
+ perror("kmemcpy (maptable)");
+ return;
+ }
+
+ for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) {
+ hmp = maptable[hv];
+
+ while (hmp) {
+ if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) {
+ perror("kmemcpy (hostmap)");
+ return;
+ }
+
+ printhostmap(&hm, hv);
+ hmp = hm.hm_next;
+ }
+ }
+ free(maptable);
+}
+
+
+/*
+ * Display the active host mapping table.
+ */
+void showhostmap_live(fd, nsp)
+ int fd;
+ natstat_t *nsp;
+{
+ ipfgeniter_t iter;
+ hostmap_t hm;
+ ipfobj_t obj;
+ int i;
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_GENITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.igi_type = IPFGENITER_HOSTMAP;
+ iter.igi_nitems = 1;
+ iter.igi_data = &hm;
+
+ printf("\nList of active host mappings:\n");
+
+ while (nsp->ns_maplist != NULL) {
+ if (ioctl(fd, SIOCGENITER, &obj) == -1)
+ break;
+ printhostmap(&hm, hm.hm_hv);
+ nsp->ns_maplist = hm.hm_next;
+ }
+
+ i = IPFGENITER_HOSTMAP;
+ (void) ioctl(fd,SIOCIPFDELTOK, &i);
+}
+
+
+int nat_matcharray(nat, array)
+ nat_t *nat;
+ int *array;
+{
+ int i, n, *x, rv, p;
+ ipfexp_t *e;
+
+ rv = 0;
+ n = array[0];
+ x = array + 1;
+
+ for (; n > 0; x += 3 + x[3], rv = 0) {
+ e = (ipfexp_t *)x;
+ if (e->ipfe_cmd == IPF_EXP_END)
+ break;
+ n -= e->ipfe_size;
+
+ p = e->ipfe_cmd >> 16;
+ if ((p != 0) && (p != nat->nat_pr[1]))
+ break;
+
+ switch (e->ipfe_cmd)
+ {
+ case IPF_EXP_IP_PR :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (nat->nat_pr[1] == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_IP_SRCADDR :
+ if (nat->nat_v[0] != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((nat->nat_osrcaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((nat->nat_nsrcaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_DSTADDR :
+ if (nat->nat_v[0] != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((nat->nat_odstaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((nat->nat_ndstaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_ADDR :
+ if (nat->nat_v[0] != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((nat->nat_osrcaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((nat->nat_nsrcaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((nat->nat_odstaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((nat->nat_ndstaddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+#ifdef USE_INET6
+ case IPF_EXP_IP6_SRCADDR :
+ if (nat->nat_v[0] != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&nat->nat_osrc6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&nat->nat_nsrc6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_DSTADDR :
+ if (nat->nat_v[0] != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&nat->nat_odst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&nat->nat_ndst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_ADDR :
+ if (nat->nat_v[0] != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&nat->nat_osrc6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&nat->nat_nsrc6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&nat->nat_odst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&nat->nat_ndst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+#endif
+
+ case IPF_EXP_UDP_PORT :
+ case IPF_EXP_TCP_PORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (nat->nat_osport == e->ipfe_arg0[i]) ||
+ (nat->nat_nsport == e->ipfe_arg0[i]) ||
+ (nat->nat_odport == e->ipfe_arg0[i]) ||
+ (nat->nat_ndport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_SPORT :
+ case IPF_EXP_TCP_SPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (nat->nat_osport == e->ipfe_arg0[i]) ||
+ (nat->nat_nsport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_DPORT :
+ case IPF_EXP_TCP_DPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (nat->nat_odport == e->ipfe_arg0[i]) ||
+ (nat->nat_ndport == e->ipfe_arg0[i]);
+ }
+ break;
+ }
+ rv ^= e->ipfe_not;
+
+ if (rv == 0)
+ break;
+ }
+
+ return rv;
+}
diff --git a/contrib/ipfilter/tools/ipnat_y.y b/contrib/ipfilter/tools/ipnat_y.y
new file mode 100644
index 0000000..39e6a92
--- /dev/null
+++ b/contrib/ipfilter/tools/ipnat_y.y
@@ -0,0 +1,1782 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+%{
+#ifdef __FreeBSD__
+# ifndef __FreeBSD_cc_version
+# include <osreldate.h>
+# else
+# if __FreeBSD_cc_version < 430000
+# include <osreldate.h>
+# endif
+# endif
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include "ipnat_l.h"
+
+#define YYDEBUG 1
+
+extern void yyerror __P((char *));
+extern int yyparse __P((void));
+extern int yylex __P((void));
+extern int yydebug;
+extern FILE *yyin;
+extern int yylineNum;
+
+static ipnat_t *nattop = NULL;
+static ipnat_t *nat = NULL;
+static int natfd = -1;
+static ioctlfunc_t natioctlfunc = NULL;
+static addfunc_t nataddfunc = NULL;
+static int suggest_port = 0;
+static proxyrule_t *prules = NULL;
+static int parser_error = 0;
+
+static void newnatrule __P((void));
+static void setnatproto __P((int));
+static void setmapifnames __P((void));
+static void setrdrifnames __P((void));
+static void proxy_setconfig __P((int));
+static void proxy_unsetconfig __P((void));
+static namelist_t *proxy_dns_add_pass __P((char *, char *));
+static namelist_t *proxy_dns_add_block __P((char *, char *));
+static void proxy_addconfig __P((char *, int, char *, namelist_t *));
+static void proxy_loadconfig __P((int, ioctlfunc_t, char *, int,
+ char *, namelist_t *));
+static void proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *));
+static void setmapifnames __P((void));
+static void setrdrifnames __P((void));
+static void setifname __P((ipnat_t **, int, char *));
+static int addname __P((ipnat_t **, char *));
+%}
+%union {
+ char *str;
+ u_32_t num;
+ struct {
+ i6addr_t a;
+ int f;
+ } ipa;
+ frentry_t fr;
+ frtuc_t *frt;
+ u_short port;
+ struct {
+ int p1;
+ int p2;
+ int pc;
+ } pc;
+ struct {
+ i6addr_t a;
+ i6addr_t m;
+ int t; /* Address type */
+ int u;
+ int f; /* Family */
+ int v; /* IP version */
+ int s; /* 0 = number, 1 = text */
+ int n; /* number */
+ } ipp;
+ union i6addr ip6;
+ namelist_t *names;
+};
+
+%token <num> YY_NUMBER YY_HEX
+%token <str> YY_STR
+%token YY_COMMENT
+%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
+%token YY_RANGE_OUT YY_RANGE_IN
+%token <ip6> YY_IPV6
+
+%token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE
+%token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY
+%token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY
+%token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG
+%token IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO
+%token IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT
+%token IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6
+%token IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE
+%type <port> portspec
+%type <num> hexnumber compare range proto
+%type <num> saddr daddr sobject dobject mapfrom rdrfrom dip
+%type <ipa> hostname ipv4 ipaddr
+%type <ipp> addr rhsaddr rhdaddr erhdaddr
+%type <pc> portstuff portpair comaports srcports dstports
+%type <names> dnslines dnsline
+%%
+file: line
+ | assign
+ | file line
+ | file assign
+ | file pconf ';'
+ ;
+
+line: xx rule { int err;
+ while ((nat = nattop) != NULL) {
+ if (nat->in_v[0] == 0)
+ nat->in_v[0] = 4;
+ if (nat->in_v[1] == 0)
+ nat->in_v[1] = nat->in_v[0];
+ nattop = nat->in_next;
+ err = (*nataddfunc)(natfd, natioctlfunc, nat);
+ free(nat);
+ if (err != 0) {
+ parser_error = err;
+ break;
+ }
+ }
+ if (parser_error == 0 && prules != NULL) {
+ proxy_loadrules(natfd, natioctlfunc, prules);
+ prules = NULL;
+ }
+ resetlexer();
+ }
+ | YY_COMMENT
+ ;
+
+assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
+ resetlexer();
+ free($1);
+ free($3);
+ yyvarnext = 0;
+ }
+ ;
+
+assigning:
+ '=' { yyvarnext = 1; }
+ ;
+
+xx: { newnatrule(); }
+ ;
+
+rule: map eol
+ | mapblock eol
+ | redir eol
+ | rewrite ';'
+ | divert ';'
+ ;
+
+no: IPNY_NO { nat->in_flags |= IPN_NO; }
+ ;
+
+eol: | ';'
+ ;
+
+map: mapit ifnames addr tlate rhsaddr proxy mapoptions
+ { if ($3.f != 0 && $3.f != $5.f && $5.f != 0)
+ yyerror("3.address family mismatch");
+ if (nat->in_v[0] == 0 && $5.v != 0)
+ nat->in_v[0] = $5.v;
+ else if (nat->in_v[0] == 0 && $3.v != 0)
+ nat->in_v[0] = $3.v;
+ if (nat->in_v[1] == 0 && $5.v != 0)
+ nat->in_v[1] = $5.v;
+ else if (nat->in_v[1] == 0 && $3.v != 0)
+ nat->in_v[1] = $3.v;
+ nat->in_osrcatype = $3.t;
+ bcopy(&$3.a, &nat->in_osrc.na_addr[0],
+ sizeof($3.a));
+ bcopy(&$3.m, &nat->in_osrc.na_addr[1],
+ sizeof($3.a));
+ nat->in_nsrcatype = $5.t;
+ nat->in_nsrcafunc = $5.u;
+ bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
+ sizeof($5.a));
+ bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
+ sizeof($5.a));
+
+ setmapifnames();
+ }
+ | mapit ifnames addr tlate rhsaddr mapport mapoptions
+ { if ($3.f != $5.f && $3.f != 0 && $5.f != 0)
+ yyerror("4.address family mismatch");
+ if (nat->in_v[1] == 0 && $5.v != 0)
+ nat->in_v[1] = $5.v;
+ else if (nat->in_v[0] == 0 && $3.v != 0)
+ nat->in_v[0] = $3.v;
+ if (nat->in_v[0] == 0 && $5.v != 0)
+ nat->in_v[0] = $5.v;
+ else if (nat->in_v[1] == 0 && $3.v != 0)
+ nat->in_v[1] = $3.v;
+ nat->in_osrcatype = $3.t;
+ bcopy(&$3.a, &nat->in_osrc.na_addr[0],
+ sizeof($3.a));
+ bcopy(&$3.m, &nat->in_osrc.na_addr[1],
+ sizeof($3.a));
+ nat->in_nsrcatype = $5.t;
+ nat->in_nsrcafunc = $5.u;
+ bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
+ sizeof($5.a));
+ bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
+ sizeof($5.a));
+
+ setmapifnames();
+ }
+ | no mapit ifnames addr setproto ';'
+ { if (nat->in_v[0] == 0)
+ nat->in_v[0] = $4.v;
+ nat->in_osrcatype = $4.t;
+ bcopy(&$4.a, &nat->in_osrc.na_addr[0],
+ sizeof($4.a));
+ bcopy(&$4.m, &nat->in_osrc.na_addr[1],
+ sizeof($4.a));
+
+ setmapifnames();
+ }
+ | mapit ifnames mapfrom tlate rhsaddr proxy mapoptions
+ { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
+ yyerror("5.address family mismatch");
+ if (nat->in_v[0] == 0 && $5.v != 0)
+ nat->in_v[0] = $5.v;
+ else if (nat->in_v[0] == 0 && $3 != 0)
+ nat->in_v[0] = ftov($3);
+ if (nat->in_v[1] == 0 && $5.v != 0)
+ nat->in_v[1] = $5.v;
+ else if (nat->in_v[1] == 0 && $3 != 0)
+ nat->in_v[1] = ftov($3);
+ nat->in_nsrcatype = $5.t;
+ nat->in_nsrcafunc = $5.u;
+ bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
+ sizeof($5.a));
+ bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
+ sizeof($5.a));
+
+ setmapifnames();
+ }
+ | no mapit ifnames mapfrom setproto ';'
+ { nat->in_v[0] = ftov($4);
+ setmapifnames();
+ }
+ | mapit ifnames mapfrom tlate rhsaddr mapport mapoptions
+ { if ($3 != 0 && $5.f != 0 && $3 != $5.f)
+ yyerror("6.address family mismatch");
+ if (nat->in_v[0] == 0 && $5.v != 0)
+ nat->in_v[0] = $5.v;
+ else if (nat->in_v[0] == 0 && $3 != 0)
+ nat->in_v[0] = ftov($3);
+ if (nat->in_v[1] == 0 && $5.v != 0)
+ nat->in_v[1] = $5.v;
+ else if (nat->in_v[1] == 0 && $3 != 0)
+ nat->in_v[1] = ftov($3);
+ nat->in_nsrcatype = $5.t;
+ nat->in_nsrcafunc = $5.u;
+ bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
+ sizeof($5.a));
+ bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
+ sizeof($5.a));
+
+ setmapifnames();
+ }
+ ;
+
+mapblock:
+ mapblockit ifnames addr tlate addr ports mapoptions
+ { if ($3.f != 0 && $5.f != 0 && $3.f != $5.f)
+ yyerror("7.address family mismatch");
+ if (nat->in_v[0] == 0 && $5.v != 0)
+ nat->in_v[0] = $5.v;
+ else if (nat->in_v[0] == 0 && $3.v != 0)
+ nat->in_v[0] = $3.v;
+ if (nat->in_v[1] == 0 && $5.v != 0)
+ nat->in_v[1] = $5.v;
+ else if (nat->in_v[1] == 0 && $3.v != 0)
+ nat->in_v[1] = $3.v;
+ nat->in_osrcatype = $3.t;
+ bcopy(&$3.a, &nat->in_osrc.na_addr[0],
+ sizeof($3.a));
+ bcopy(&$3.m, &nat->in_osrc.na_addr[1],
+ sizeof($3.a));
+ nat->in_nsrcatype = $5.t;
+ nat->in_nsrcafunc = $5.u;
+ bcopy(&$5.a, &nat->in_nsrc.na_addr[0],
+ sizeof($5.a));
+ bcopy(&$5.m, &nat->in_nsrc.na_addr[1],
+ sizeof($5.a));
+
+ setmapifnames();
+ }
+ | no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';'
+ { if (nat->in_v[0] == 0)
+ nat->in_v[0] = $5.v;
+ if (nat->in_v[1] == 0)
+ nat->in_v[1] = $5.v;
+ nat->in_osrcatype = $5.t;
+ bcopy(&$5.a, &nat->in_osrc.na_addr[0],
+ sizeof($5.a));
+ bcopy(&$5.m, &nat->in_osrc.na_addr[1],
+ sizeof($5.a));
+
+ setmapifnames();
+ }
+ ;
+
+redir: rdrit ifnames addr dport tlate dip nport setproto rdroptions
+ { if ($6 != 0 && $3.f != 0 && $6 != $3.f)
+ yyerror("21.address family mismatch");
+ if (nat->in_v[0] == 0) {
+ if ($3.v != AF_UNSPEC)
+ nat->in_v[0] = ftov($3.f);
+ else
+ nat->in_v[0] = ftov($6);
+ }
+ nat->in_odstatype = $3.t;
+ bcopy(&$3.a, &nat->in_odst.na_addr[0],
+ sizeof($3.a));
+ bcopy(&$3.m, &nat->in_odst.na_addr[1],
+ sizeof($3.a));
+
+ setrdrifnames();
+ }
+ | no rdrit ifnames addr dport setproto ';'
+ { if (nat->in_v[0] == 0)
+ nat->in_v[0] = ftov($4.f);
+ nat->in_odstatype = $4.t;
+ bcopy(&$4.a, &nat->in_odst.na_addr[0],
+ sizeof($4.a));
+ bcopy(&$4.m, &nat->in_odst.na_addr[1],
+ sizeof($4.a));
+
+ setrdrifnames();
+ }
+ | rdrit ifnames rdrfrom tlate dip nport setproto rdroptions
+ { if ($5 != 0 && $3 != 0 && $5 != $3)
+ yyerror("20.address family mismatch");
+ if (nat->in_v[0] == 0) {
+ if ($3 != AF_UNSPEC)
+ nat->in_v[0] = ftov($3);
+ else
+ nat->in_v[0] = ftov($5);
+ }
+ setrdrifnames();
+ }
+ | no rdrit ifnames rdrfrom setproto ';'
+ { nat->in_v[0] = ftov($4);
+
+ setrdrifnames();
+ }
+ ;
+
+rewrite:
+ IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts
+ { if (nat->in_v[0] == 0)
+ nat->in_v[0] = ftov($4);
+ if (nat->in_redir & NAT_MAP)
+ setmapifnames();
+ else
+ setrdrifnames();
+ nat->in_redir |= NAT_REWRITE;
+ }
+ ;
+
+divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts
+ { if (nat->in_v[0] == 0)
+ nat->in_v[0] = ftov($4);
+ if (nat->in_redir & NAT_MAP) {
+ setmapifnames();
+ nat->in_pr[0] = IPPROTO_UDP;
+ } else {
+ setrdrifnames();
+ nat->in_pr[1] = IPPROTO_UDP;
+ }
+ nat->in_flags &= ~IPN_TCP;
+ }
+ ;
+
+tlate: IPNY_TLATE { yyexpectaddr = 1; }
+ ;
+
+pconf: IPNY_PROXY { yysetdict(proxies); }
+ IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{'
+ { proxy_setconfig(IPNY_DNS); }
+ dnslines ';' '}'
+ { proxy_addconfig("dns", $5, $7, $10);
+ proxy_unsetconfig();
+ }
+ ;
+
+dnslines:
+ dnsline { $$ = $1; }
+ | dnslines ';' dnsline { $$ = $1; $1->na_next = $3; }
+ ;
+
+dnsline:
+ IPNY_ALLOW YY_STR { $$ = proxy_dns_add_pass(NULL, $2); }
+ | IPNY_DENY YY_STR { $$ = proxy_dns_add_block(NULL, $2); }
+ | IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); }
+ | IPNY_DENY '.' YY_STR { $$ = proxy_dns_add_block(".", $3); }
+ ;
+
+oninout:
+ inout IPNY_ON ifnames { ; }
+ ;
+
+inout: IPNY_IN { nat->in_redir = NAT_REDIRECT; }
+ | IPNY_OUT { nat->in_redir = NAT_MAP; }
+ ;
+
+rwrproto:
+ | IPNY_PROTO setproto
+ ;
+
+newdst: src rhsaddr srcports dst erhdaddr dstports
+ { nat->in_nsrc.na_addr[0] = $2.a;
+ nat->in_nsrc.na_addr[1] = $2.m;
+ nat->in_nsrc.na_atype = $2.t;
+ if ($2.t == FRI_LOOKUP) {
+ nat->in_nsrc.na_type = $2.u;
+ nat->in_nsrc.na_subtype = $2.s;
+ nat->in_nsrc.na_num = $2.n;
+ }
+ nat->in_nsports[0] = $3.p1;
+ nat->in_nsports[1] = $3.p2;
+ nat->in_ndst.na_addr[0] = $5.a;
+ nat->in_ndst.na_addr[1] = $5.m;
+ nat->in_ndst.na_atype = $5.t;
+ if ($5.t == FRI_LOOKUP) {
+ nat->in_ndst.na_type = $5.u;
+ nat->in_ndst.na_subtype = $5.s;
+ nat->in_ndst.na_num = $5.n;
+ }
+ nat->in_ndports[0] = $6.p1;
+ nat->in_ndports[1] = $6.p2;
+ }
+ ;
+
+divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP
+ { nat->in_nsrc.na_addr[0] = $2.a;
+ if ($2.m.in4.s_addr != 0xffffffff)
+ yyerror("divert must have /32 dest");
+ nat->in_nsrc.na_addr[1] = $2.m;
+ nat->in_nsports[0] = $4;
+ nat->in_nsports[1] = $4;
+
+ nat->in_ndst.na_addr[0] = $6.a;
+ nat->in_ndst.na_addr[1] = $6.m;
+ if ($6.m.in4.s_addr != 0xffffffff)
+ yyerror("divert must have /32 dest");
+ nat->in_ndports[0] = $8;
+ nat->in_ndports[1] = $8;
+
+ nat->in_redir |= NAT_DIVERTUDP;
+ }
+ ;
+
+src: IPNY_SRC { yyexpectaddr = 1; }
+ ;
+
+dst: IPNY_DST { yyexpectaddr = 1; }
+ ;
+
+srcports:
+ comaports { $$.p1 = $1.p1;
+ $$.p2 = $1.p2;
+ }
+ | IPNY_PORT '=' portspec
+ { $$.p1 = $3;
+ $$.p2 = $3;
+ nat->in_flags |= IPN_FIXEDSPORT;
+ }
+ ;
+
+dstports:
+ comaports { $$.p1 = $1.p1;
+ $$.p2 = $1.p2;
+ }
+ | IPNY_PORT '=' portspec
+ { $$.p1 = $3;
+ $$.p2 = $3;
+ nat->in_flags |= IPN_FIXEDDPORT;
+ }
+ ;
+
+comaports:
+ { $$.p1 = 0;
+ $$.p2 = 0;
+ }
+ | ',' { if (!(nat->in_flags & IPN_TCPUDP))
+ yyerror("must be TCP/UDP for ports");
+ }
+ portpair { $$.p1 = $3.p1;
+ $$.p2 = $3.p2;
+ }
+ ;
+
+proxy: | IPNY_PROXY port portspec YY_STR '/' proto
+ { int pos;
+ pos = addname(&nat, $4);
+ nat->in_plabel = pos;
+ if (nat->in_dcmp == 0) {
+ nat->in_odport = $3;
+ } else if ($3 != nat->in_odport) {
+ yyerror("proxy port numbers not consistant");
+ }
+ nat->in_ndport = $3;
+ setnatproto($6);
+ free($4);
+ }
+ | IPNY_PROXY port YY_STR YY_STR '/' proto
+ { int pnum, pos;
+ pos = addname(&nat, $4);
+ nat->in_plabel = pos;
+ pnum = getportproto($3, $6);
+ if (pnum == -1)
+ yyerror("invalid port number");
+ nat->in_odport = ntohs(pnum);
+ nat->in_ndport = ntohs(pnum);
+ setnatproto($6);
+ free($3);
+ free($4);
+ }
+ | IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR
+ { int pos;
+ pos = addname(&nat, $4);
+ nat->in_plabel = pos;
+ if (nat->in_dcmp == 0) {
+ nat->in_odport = $3;
+ } else if ($3 != nat->in_odport) {
+ yyerror("proxy port numbers not consistant");
+ }
+ nat->in_ndport = $3;
+ setnatproto($6);
+ nat->in_pconfig = addname(&nat, $8);
+ free($4);
+ free($8);
+ }
+ | IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR
+ { int pnum, pos;
+ pos = addname(&nat, $4);
+ nat->in_plabel = pos;
+ pnum = getportproto($3, $6);
+ if (pnum == -1)
+ yyerror("invalid port number");
+ nat->in_odport = ntohs(pnum);
+ nat->in_ndport = ntohs(pnum);
+ setnatproto($6);
+ pos = addname(&nat, $8);
+ nat->in_pconfig = pos;
+ free($3);
+ free($4);
+ free($8);
+ }
+ ;
+setproto:
+ | proto { if (nat->in_pr[0] != 0 ||
+ nat->in_pr[1] != 0 ||
+ nat->in_flags & IPN_TCPUDP)
+ yyerror("protocol set twice");
+ setnatproto($1);
+ }
+ | IPNY_TCPUDP { if (nat->in_pr[0] != 0 ||
+ nat->in_pr[1] != 0 ||
+ nat->in_flags & IPN_TCPUDP)
+ yyerror("protocol set twice");
+ nat->in_flags |= IPN_TCPUDP;
+ nat->in_pr[0] = 0;
+ nat->in_pr[1] = 0;
+ }
+ | IPNY_TCP '/' IPNY_UDP { if (nat->in_pr[0] != 0 ||
+ nat->in_pr[1] != 0 ||
+ nat->in_flags & IPN_TCPUDP)
+ yyerror("protocol set twice");
+ nat->in_flags |= IPN_TCPUDP;
+ nat->in_pr[0] = 0;
+ nat->in_pr[1] = 0;
+ }
+ ;
+
+rhsaddr:
+ addr { $$ = $1;
+ yyexpectaddr = 0;
+ }
+ | hostname '-' { yyexpectaddr = 1; } hostname
+ { $$.t = FRI_RANGE;
+ if ($1.f != $4.f)
+ yyerror("8.address family "
+ "mismatch");
+ $$.f = $1.f;
+ $$.v = ftov($1.f);
+ $$.a = $1.a;
+ $$.m = $4.a;
+ nat->in_flags |= IPN_SIPRANGE;
+ yyexpectaddr = 0;
+ }
+ | IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname
+ { $$.t = FRI_RANGE;
+ if ($2.f != $5.f)
+ yyerror("9.address family "
+ "mismatch");
+ $$.f = $2.f;
+ $$.v = ftov($2.f);
+ $$.a = $2.a;
+ $$.m = $5.a;
+ nat->in_flags |= IPN_SIPRANGE;
+ yyexpectaddr = 0;
+ }
+ ;
+
+dip:
+ hostname ',' { yyexpectaddr = 1; } hostname
+ { nat->in_flags |= IPN_SPLIT;
+ if ($1.f != $4.f)
+ yyerror("10.address family "
+ "mismatch");
+ $$ = $1.f;
+ nat->in_ndstip6 = $1.a;
+ nat->in_ndstmsk6 = $4.a;
+ nat->in_ndstatype = FRI_SPLIT;
+ yyexpectaddr = 0;
+ }
+ | rhdaddr { int bits;
+ nat->in_ndstip6 = $1.a;
+ nat->in_ndstmsk6 = $1.m;
+ nat->in_ndst.na_atype = $1.t;
+ yyexpectaddr = 0;
+ if ($1.f == AF_INET)
+ bits = count4bits($1.m.in4.s_addr);
+ else
+ bits = count6bits($1.m.i6);
+ if (($1.f == AF_INET) && (bits != 0) &&
+ (bits != 32)) {
+ yyerror("dest ip bitmask not /32");
+ } else if (($1.f == AF_INET6) &&
+ (bits != 0) && (bits != 128)) {
+ yyerror("dest ip bitmask not /128");
+ }
+ $$ = $1.f;
+ }
+ ;
+
+rhdaddr:
+ addr { $$ = $1;
+ yyexpectaddr = 0;
+ }
+ | hostname '-' hostname { bzero(&$$, sizeof($$));
+ $$.t = FRI_RANGE;
+ if ($1.f != 0 && $3.f != 0 &&
+ $1.f != $3.f)
+ yyerror("11.address family "
+ "mismatch");
+ $$.a = $1.a;
+ $$.m = $3.a;
+ nat->in_flags |= IPN_DIPRANGE;
+ yyexpectaddr = 0;
+ }
+ | IPNY_RANGE hostname '-' hostname
+ { bzero(&$$, sizeof($$));
+ $$.t = FRI_RANGE;
+ if ($2.f != 0 && $4.f != 0 &&
+ $2.f != $4.f)
+ yyerror("12.address family "
+ "mismatch");
+ $$.a = $2.a;
+ $$.m = $4.a;
+ nat->in_flags |= IPN_DIPRANGE;
+ yyexpectaddr = 0;
+ }
+ ;
+
+erhdaddr:
+ rhdaddr { $$ = $1; }
+ | IPNY_DSTLIST '/' YY_NUMBER { $$.t = FRI_LOOKUP;
+ $$.u = IPLT_DSTLIST;
+ $$.s = 0;
+ $$.n = $3;
+ }
+ | IPNY_DSTLIST '/' YY_STR { $$.t = FRI_LOOKUP;
+ $$.u = IPLT_DSTLIST;
+ $$.s = 1;
+ $$.n = addname(&nat, $3);
+ }
+ ;
+
+port: IPNY_PORT { suggest_port = 1; }
+ ;
+
+portspec:
+ YY_NUMBER { if ($1 > 65535) /* Unsigned */
+ yyerror("invalid port number");
+ else
+ $$ = $1;
+ }
+ | YY_STR { if (getport(NULL, $1,
+ &($$), NULL) == -1)
+ yyerror("invalid port number");
+ $$ = ntohs($$);
+ }
+ ;
+
+portpair:
+ portspec { $$.p1 = $1; $$.p2 = $1; }
+ | portspec '-' portspec { $$.p1 = $1; $$.p2 = $3; }
+ | portspec ':' portspec { $$.p1 = $1; $$.p2 = $3; }
+ ;
+
+dport: | port portpair { nat->in_odport = $2.p1;
+ if ($2.p2 == 0)
+ nat->in_dtop = $2.p1;
+ else
+ nat->in_dtop = $2.p2;
+ }
+ ;
+
+nport: | port portpair { nat->in_dpmin = $2.p1;
+ nat->in_dpnext = $2.p1;
+ nat->in_dpmax = $2.p2;
+ nat->in_ndport = $2.p1;
+ if (nat->in_dtop == 0)
+ nat->in_dtop = $2.p2;
+ }
+ | port '=' portspec { nat->in_dpmin = $3;
+ nat->in_dpnext = $3;
+ nat->in_ndport = $3;
+ if (nat->in_dtop == 0)
+ nat->in_dtop = nat->in_odport;
+ nat->in_flags |= IPN_FIXEDDPORT;
+ }
+ ;
+
+ports: | IPNY_PORTS YY_NUMBER { nat->in_spmin = $2; }
+ | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; }
+ ;
+
+mapit: IPNY_MAP { nat->in_redir = NAT_MAP; }
+ | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; }
+ ;
+
+rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; }
+ ;
+
+mapblockit:
+ IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; }
+ ;
+
+mapfrom:
+ from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
+ yyerror("13.address family "
+ "mismatch");
+ $$ = $2;
+ }
+ | from sobject '!' to dobject
+ { if ($2 != 0 && $5 != 0 && $2 != $5)
+ yyerror("14.address family "
+ "mismatch");
+ nat->in_flags |= IPN_NOTDST;
+ $$ = $2;
+ }
+ | from sobject to '!' dobject
+ { if ($2 != 0 && $5 != 0 && $2 != $5)
+ yyerror("15.address family "
+ "mismatch");
+ nat->in_flags |= IPN_NOTDST;
+ $$ = $2;
+ }
+ ;
+
+rdrfrom:
+ from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4)
+ yyerror("16.address family "
+ "mismatch");
+ $$ = $2;
+ }
+ | '!' from sobject to dobject
+ { if ($3 != 0 && $5 != 0 && $3 != $5)
+ yyerror("17.address family "
+ "mismatch");
+ nat->in_flags |= IPN_NOTSRC;
+ $$ = $3;
+ }
+ | from '!' sobject to dobject
+ { if ($3 != 0 && $5 != 0 && $3 != $5)
+ yyerror("18.address family "
+ "mismatch");
+ nat->in_flags |= IPN_NOTSRC;
+ $$ = $3;
+ }
+ ;
+
+from: IPNY_FROM { nat->in_flags |= IPN_FILTER;
+ yyexpectaddr = 1;
+ }
+ ;
+
+to: IPNY_TO { yyexpectaddr = 1; }
+ ;
+
+ifnames:
+ ifname family { yyexpectaddr = 1; }
+ | ifname ',' otherifname family { yyexpectaddr = 1; }
+ ;
+
+ifname: YY_STR { setifname(&nat, 0, $1);
+ free($1);
+ }
+ ;
+
+family: | IPNY_INET { nat->in_v[0] = 4; nat->in_v[1] = 4; }
+ | IPNY_INET6 { nat->in_v[0] = 6; nat->in_v[1] = 6; }
+ ;
+
+otherifname:
+ YY_STR { setifname(&nat, 1, $1);
+ free($1);
+ }
+ ;
+
+mapport:
+ IPNY_PORTMAP tcpudp portpair sequential
+ { nat->in_spmin = $3.p1;
+ nat->in_spmax = $3.p2;
+ }
+ | IPNY_PORTMAP portpair tcpudp sequential
+ { nat->in_spmin = $2.p1;
+ nat->in_spmax = $2.p2;
+ }
+ | IPNY_PORTMAP tcpudp IPNY_AUTO sequential
+ { nat->in_flags |= IPN_AUTOPORTMAP;
+ nat->in_spmin = 1024;
+ nat->in_spmax = 65535;
+ }
+ | IPNY_ICMPIDMAP YY_STR portpair sequential
+ { if (strcmp($2, "icmp") != 0 &&
+ strcmp($2, "ipv6-icmp") != 0) {
+ yyerror("icmpidmap not followed by icmp");
+ }
+ free($2);
+ if ($3.p1 < 0 || $3.p1 > 65535)
+ yyerror("invalid 1st ICMP Id number");
+ if ($3.p2 < 0 || $3.p2 > 65535)
+ yyerror("invalid 2nd ICMP Id number");
+ if (strcmp($2, "ipv6-icmp") == 0) {
+ nat->in_pr[0] = IPPROTO_ICMPV6;
+ nat->in_pr[1] = IPPROTO_ICMPV6;
+ } else {
+ nat->in_pr[0] = IPPROTO_ICMP;
+ nat->in_pr[1] = IPPROTO_ICMP;
+ }
+ nat->in_flags = IPN_ICMPQUERY;
+ nat->in_spmin = $3.p1;
+ nat->in_spmax = $3.p2;
+ }
+ ;
+
+sobject:
+ saddr { $$ = $1; }
+ | saddr port portstuff { nat->in_osport = $3.p1;
+ nat->in_stop = $3.p2;
+ nat->in_scmp = $3.pc;
+ $$ = $1;
+ }
+ ;
+
+saddr: addr { nat->in_osrcatype = $1.t;
+ bcopy(&$1.a,
+ &nat->in_osrc.na_addr[0],
+ sizeof($1.a));
+ bcopy(&$1.m,
+ &nat->in_osrc.na_addr[1],
+ sizeof($1.m));
+ $$ = $1.f;
+ }
+ ;
+
+dobject:
+ daddr { $$ = $1; }
+ | daddr port portstuff { nat->in_odport = $3.p1;
+ nat->in_dtop = $3.p2;
+ nat->in_dcmp = $3.pc;
+ $$ = $1;
+ }
+ ;
+
+daddr: addr { nat->in_odstatype = $1.t;
+ bcopy(&$1.a,
+ &nat->in_odst.na_addr[0],
+ sizeof($1.a));
+ bcopy(&$1.m,
+ &nat->in_odst.na_addr[1],
+ sizeof($1.m));
+ $$ = $1.f;
+ }
+ ;
+
+addr: IPNY_ANY { yyexpectaddr = 0;
+ bzero(&$$, sizeof($$));
+ $$.t = FRI_NORMAL;
+ }
+ | hostname { bzero(&$$, sizeof($$));
+ $$.a = $1.a;
+ $$.t = FRI_NORMAL;
+ $$.v = ftov($1.f);
+ $$.f = $1.f;
+ if ($$.f == AF_INET) {
+ $$.m.in4.s_addr = 0xffffffff;
+ } else if ($$.f == AF_INET6) {
+ $$.m.i6[0] = 0xffffffff;
+ $$.m.i6[1] = 0xffffffff;
+ $$.m.i6[2] = 0xffffffff;
+ $$.m.i6[3] = 0xffffffff;
+ }
+ yyexpectaddr = 0;
+ }
+ | hostname slash YY_NUMBER
+ { bzero(&$$, sizeof($$));
+ $$.a = $1.a;
+ $$.f = $1.f;
+ $$.v = ftov($1.f);
+ $$.t = FRI_NORMAL;
+ ntomask($$.f, $3, (u_32_t *)&$$.m);
+ $$.a.i6[0] &= $$.m.i6[0];
+ $$.a.i6[1] &= $$.m.i6[1];
+ $$.a.i6[2] &= $$.m.i6[2];
+ $$.a.i6[3] &= $$.m.i6[3];
+ yyexpectaddr = 0;
+ }
+ | hostname slash ipaddr { bzero(&$$, sizeof($$));
+ if ($1.f != $3.f) {
+ yyerror("1.address family "
+ "mismatch");
+ }
+ $$.a = $1.a;
+ $$.m = $3.a;
+ $$.t = FRI_NORMAL;
+ $$.a.i6[0] &= $$.m.i6[0];
+ $$.a.i6[1] &= $$.m.i6[1];
+ $$.a.i6[2] &= $$.m.i6[2];
+ $$.a.i6[3] &= $$.m.i6[3];
+ $$.f = $1.f;
+ $$.v = ftov($1.f);
+ yyexpectaddr = 0;
+ }
+ | hostname slash hexnumber { bzero(&$$, sizeof($$));
+ $$.a = $1.a;
+ $$.m.in4.s_addr = htonl($3);
+ $$.t = FRI_NORMAL;
+ $$.a.in4.s_addr &= $$.m.in4.s_addr;
+ $$.f = $1.f;
+ $$.v = ftov($1.f);
+ if ($$.f == AF_INET6)
+ yyerror("incorrect inet6 mask");
+ }
+ | hostname mask ipaddr { bzero(&$$, sizeof($$));
+ if ($1.f != $3.f) {
+ yyerror("2.address family "
+ "mismatch");
+ }
+ $$.a = $1.a;
+ $$.m = $3.a;
+ $$.t = FRI_NORMAL;
+ $$.a.i6[0] &= $$.m.i6[0];
+ $$.a.i6[1] &= $$.m.i6[1];
+ $$.a.i6[2] &= $$.m.i6[2];
+ $$.a.i6[3] &= $$.m.i6[3];
+ $$.f = $1.f;
+ $$.v = ftov($1.f);
+ yyexpectaddr = 0;
+ }
+ | hostname mask hexnumber { bzero(&$$, sizeof($$));
+ $$.a = $1.a;
+ $$.m.in4.s_addr = htonl($3);
+ $$.t = FRI_NORMAL;
+ $$.a.in4.s_addr &= $$.m.in4.s_addr;
+ $$.f = AF_INET;
+ $$.v = 4;
+ }
+ | pool slash YY_NUMBER { bzero(&$$, sizeof($$));
+ $$.a.iplookupnum = $3;
+ $$.a.iplookuptype = IPLT_POOL;
+ $$.a.iplookupsubtype = 0;
+ $$.t = FRI_LOOKUP;
+ }
+ | pool slash YY_STR { bzero(&$$, sizeof($$));
+ $$.a.iplookupname = addname(&nat,$3);
+ $$.a.iplookuptype = IPLT_POOL;
+ $$.a.iplookupsubtype = 1;
+ $$.t = FRI_LOOKUP;
+ }
+ | hash slash YY_NUMBER { bzero(&$$, sizeof($$));
+ $$.a.iplookupnum = $3;
+ $$.a.iplookuptype = IPLT_HASH;
+ $$.a.iplookupsubtype = 0;
+ $$.t = FRI_LOOKUP;
+ }
+ | hash slash YY_STR { bzero(&$$, sizeof($$));
+ $$.a.iplookupname = addname(&nat,$3);
+ $$.a.iplookuptype = IPLT_HASH;
+ $$.a.iplookupsubtype = 1;
+ $$.t = FRI_LOOKUP;
+ }
+ ;
+
+slash: '/' { yyexpectaddr = 0; }
+ ;
+
+mask: IPNY_MASK { yyexpectaddr = 0; }
+ ;
+
+pool: IPNY_POOL { if (!(nat->in_flags & IPN_FILTER)) {
+ yyerror("Can only use pool with from/to rules\n");
+ }
+ yyexpectaddr = 0;
+ yyresetdict();
+ }
+ ;
+
+hash: IPNY_HASH { if (!(nat->in_flags & IPN_FILTER)) {
+ yyerror("Can only use hash with from/to rules\n");
+ }
+ yyexpectaddr = 0;
+ yyresetdict();
+ }
+ ;
+
+portstuff:
+ compare portspec { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; }
+ | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; }
+ ;
+
+mapoptions:
+ rr frag age mssclamp nattag setproto purge
+ ;
+
+rdroptions:
+ rr frag age sticky mssclamp rdrproxy nattag purge
+ ;
+
+nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2,
+ sizeof(nat->in_tag.ipt_tag));
+ }
+rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; }
+ ;
+
+frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; }
+ ;
+
+age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2;
+ nat->in_age[1] = $2; }
+ | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2;
+ nat->in_age[1] = $4; }
+ ;
+
+sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) &&
+ !(nat->in_flags & IPN_SPLIT)) {
+ FPRINTF(stderr,
+ "'sticky' for use with round-robin/IP splitting only\n");
+ } else
+ nat->in_flags |= IPN_STICKY;
+ }
+ ;
+
+mssclamp:
+ | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; }
+ ;
+
+tcpudp: IPNY_TCP { setnatproto(IPPROTO_TCP); }
+ | IPNY_UDP { setnatproto(IPPROTO_UDP); }
+ | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP;
+ nat->in_pr[0] = 0;
+ nat->in_pr[1] = 0;
+ }
+ | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP;
+ nat->in_pr[0] = 0;
+ nat->in_pr[1] = 0;
+ }
+ ;
+
+sequential:
+ | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; }
+ ;
+
+purge:
+ | IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
+ ;
+
+rdrproxy:
+ IPNY_PROXY YY_STR
+ { int pos;
+ pos = addname(&nat, $2);
+ nat->in_plabel = pos;
+ nat->in_odport = nat->in_dpnext;
+ nat->in_dtop = nat->in_odport;
+ free($2);
+ }
+ | proxy { if (nat->in_plabel != -1) {
+ nat->in_ndport = nat->in_odport;
+ nat->in_dpmin = nat->in_odport;
+ nat->in_dpmax = nat->in_dpmin;
+ nat->in_dtop = nat->in_dpmin;
+ nat->in_dpnext = nat->in_dpmin;
+ }
+ }
+ ;
+
+newopts:
+ | IPNY_PURGE { nat->in_flags |= IPN_PURGE; }
+ ;
+
+proto: YY_NUMBER { $$ = $1;
+ if ($$ != IPPROTO_TCP &&
+ $$ != IPPROTO_UDP)
+ suggest_port = 0;
+ }
+ | IPNY_TCP { $$ = IPPROTO_TCP; }
+ | IPNY_UDP { $$ = IPPROTO_UDP; }
+ | YY_STR { $$ = getproto($1);
+ free($1);
+ if ($$ == -1)
+ yyerror("unknown protocol");
+ if ($$ != IPPROTO_TCP &&
+ $$ != IPPROTO_UDP)
+ suggest_port = 0;
+ }
+ ;
+
+hexnumber:
+ YY_HEX { $$ = $1; }
+ ;
+
+hostname:
+ YY_STR { i6addr_t addr;
+ int family;
+
+#ifdef USE_INET6
+ if (nat->in_v[0] == 6)
+ family = AF_INET6;
+ else
+#endif
+ family = AF_INET;
+ memset(&($$), 0, sizeof($$));
+ memset(&addr, 0, sizeof(addr));
+ $$.f = family;
+ if (gethost(family, $1,
+ &addr) == 0) {
+ $$.a = addr;
+ } else {
+ FPRINTF(stderr,
+ "Unknown host '%s'\n",
+ $1);
+ }
+ free($1);
+ }
+ | YY_NUMBER { memset(&($$), 0, sizeof($$));
+ $$.a.in4.s_addr = htonl($1);
+ if ($$.a.in4.s_addr != 0)
+ $$.f = AF_INET;
+ }
+ | ipv4 { $$ = $1; }
+ | YY_IPV6 { memset(&($$), 0, sizeof($$));
+ $$.a = $1;
+ $$.f = AF_INET6;
+ }
+ | YY_NUMBER YY_IPV6 { memset(&($$), 0, sizeof($$));
+ $$.a = $2;
+ $$.f = AF_INET6;
+ }
+ ;
+
+compare:
+ '=' { $$ = FR_EQUAL; }
+ | YY_CMP_EQ { $$ = FR_EQUAL; }
+ | YY_CMP_NE { $$ = FR_NEQUAL; }
+ | YY_CMP_LT { $$ = FR_LESST; }
+ | YY_CMP_LE { $$ = FR_LESSTE; }
+ | YY_CMP_GT { $$ = FR_GREATERT; }
+ | YY_CMP_GE { $$ = FR_GREATERTE; }
+
+range:
+ YY_RANGE_OUT { $$ = FR_OUTRANGE; }
+ | YY_RANGE_IN { $$ = FR_INRANGE; }
+ | ':' { $$ = FR_INCRANGE; }
+ ;
+
+ipaddr: ipv4 { $$ = $1; }
+ | YY_IPV6 { $$.a = $1;
+ $$.f = AF_INET6;
+ }
+ ;
+
+ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
+ { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ bzero((char *)&$$, sizeof($$));
+ $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
+ $$.a.in4.s_addr = htonl($$.a.in4.s_addr);
+ $$.f = AF_INET;
+ }
+ ;
+
+%%
+
+
+static wordtab_t proxies[] = {
+ { "dns", IPNY_DNS }
+};
+
+static wordtab_t dnswords[] = {
+ { "allow", IPNY_ALLOW },
+ { "block", IPNY_DENY },
+ { "deny", IPNY_DENY },
+ { "drop", IPNY_DENY },
+ { "pass", IPNY_ALLOW },
+
+};
+
+static wordtab_t yywords[] = {
+ { "age", IPNY_AGE },
+ { "any", IPNY_ANY },
+ { "auto", IPNY_AUTO },
+ { "bimap", IPNY_BIMAP },
+ { "config", IPNY_CONFIG },
+ { "divert", IPNY_DIVERT },
+ { "dst", IPNY_DST },
+ { "dstlist", IPNY_DSTLIST },
+ { "frag", IPNY_FRAG },
+ { "from", IPNY_FROM },
+ { "hash", IPNY_HASH },
+ { "icmpidmap", IPNY_ICMPIDMAP },
+ { "in", IPNY_IN },
+ { "inet", IPNY_INET },
+ { "inet6", IPNY_INET6 },
+ { "mask", IPNY_MASK },
+ { "map", IPNY_MAP },
+ { "map-block", IPNY_MAPBLOCK },
+ { "mssclamp", IPNY_MSSCLAMP },
+ { "netmask", IPNY_MASK },
+ { "no", IPNY_NO },
+ { "on", IPNY_ON },
+ { "out", IPNY_OUT },
+ { "pool", IPNY_POOL },
+ { "port", IPNY_PORT },
+ { "portmap", IPNY_PORTMAP },
+ { "ports", IPNY_PORTS },
+ { "proto", IPNY_PROTO },
+ { "proxy", IPNY_PROXY },
+ { "purge", IPNY_PURGE },
+ { "range", IPNY_RANGE },
+ { "rewrite", IPNY_REWRITE },
+ { "rdr", IPNY_RDR },
+ { "round-robin",IPNY_ROUNDROBIN },
+ { "sequential", IPNY_SEQUENTIAL },
+ { "src", IPNY_SRC },
+ { "sticky", IPNY_STICKY },
+ { "tag", IPNY_TAG },
+ { "tcp", IPNY_TCP },
+ { "tcpudp", IPNY_TCPUDP },
+ { "to", IPNY_TO },
+ { "udp", IPNY_UDP },
+ { "-", '-' },
+ { "->", IPNY_TLATE },
+ { "eq", YY_CMP_EQ },
+ { "ne", YY_CMP_NE },
+ { "lt", YY_CMP_LT },
+ { "gt", YY_CMP_GT },
+ { "le", YY_CMP_LE },
+ { "ge", YY_CMP_GE },
+ { NULL, 0 }
+};
+
+
+int
+ipnat_parsefile(fd, addfunc, ioctlfunc, filename)
+ int fd;
+ addfunc_t addfunc;
+ ioctlfunc_t ioctlfunc;
+ char *filename;
+{
+ FILE *fp = NULL;
+ int rval;
+ char *s;
+
+ yylineNum = 1;
+
+ (void) yysettab(yywords);
+
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ if (strcmp(filename, "-")) {
+ fp = fopen(filename, "r");
+ if (!fp) {
+ FPRINTF(stderr, "fopen(%s) failed: %s\n", filename,
+ STRERROR(errno));
+ return -1;
+ }
+ } else
+ fp = stdin;
+
+ while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0)
+ ;
+ if (fp != NULL)
+ fclose(fp);
+ if (rval == -1)
+ rval = 0;
+ else if (rval != 0)
+ rval = 1;
+ return rval;
+}
+
+
+int
+ipnat_parsesome(fd, addfunc, ioctlfunc, fp)
+ int fd;
+ addfunc_t addfunc;
+ ioctlfunc_t ioctlfunc;
+ FILE *fp;
+{
+ char *s;
+ int i;
+
+ natfd = fd;
+ parser_error = 0;
+ nataddfunc = addfunc;
+ natioctlfunc = ioctlfunc;
+
+ if (feof(fp))
+ return -1;
+ i = fgetc(fp);
+ if (i == EOF)
+ return -1;
+ if (ungetc(i, fp) == EOF)
+ return -1;
+ if (feof(fp))
+ return -1;
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ yyin = fp;
+ yyparse();
+ return parser_error;
+}
+
+
+static void
+newnatrule()
+{
+ ipnat_t *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n == NULL)
+ return;
+
+ if (nat == NULL) {
+ nattop = nat = n;
+ n->in_pnext = &nattop;
+ } else {
+ nat->in_next = n;
+ n->in_pnext = &nat->in_next;
+ nat = n;
+ }
+
+ n->in_flineno = yylineNum;
+ n->in_ifnames[0] = -1;
+ n->in_ifnames[1] = -1;
+ n->in_plabel = -1;
+ n->in_pconfig = -1;
+ n->in_size = sizeof(*n);
+
+ suggest_port = 0;
+}
+
+
+static void
+setnatproto(p)
+ int p;
+{
+ nat->in_pr[0] = p;
+ nat->in_pr[1] = p;
+
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ nat->in_flags |= IPN_TCP;
+ nat->in_flags &= ~IPN_UDP;
+ break;
+ case IPPROTO_UDP :
+ nat->in_flags |= IPN_UDP;
+ nat->in_flags &= ~IPN_TCP;
+ break;
+#ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+#endif
+ case IPPROTO_ICMP :
+ nat->in_flags &= ~IPN_TCPUDP;
+ if (!(nat->in_flags & IPN_ICMPQUERY) &&
+ !(nat->in_redir & NAT_DIVERTUDP)) {
+ nat->in_dcmp = 0;
+ nat->in_scmp = 0;
+ nat->in_dpmin = 0;
+ nat->in_dpmax = 0;
+ nat->in_dpnext = 0;
+ nat->in_spmin = 0;
+ nat->in_spmax = 0;
+ nat->in_spnext = 0;
+ }
+ break;
+ default :
+ if ((nat->in_redir & NAT_MAPBLK) == 0) {
+ nat->in_flags &= ~IPN_TCPUDP;
+ nat->in_dcmp = 0;
+ nat->in_scmp = 0;
+ nat->in_dpmin = 0;
+ nat->in_dpmax = 0;
+ nat->in_dpnext = 0;
+ nat->in_spmin = 0;
+ nat->in_spmax = 0;
+ nat->in_spnext = 0;
+ }
+ break;
+ }
+
+ if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) {
+ nat->in_stop = 0;
+ nat->in_dtop = 0;
+ nat->in_osport = 0;
+ nat->in_odport = 0;
+ nat->in_stop = 0;
+ nat->in_osport = 0;
+ nat->in_dtop = 0;
+ nat->in_odport = 0;
+ }
+ if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT)
+ nat->in_flags &= ~IPN_FIXEDDPORT;
+}
+
+
+int
+ipnat_addrule(fd, ioctlfunc, ptr)
+ int fd;
+ ioctlfunc_t ioctlfunc;
+ void *ptr;
+{
+ ioctlcmd_t add, del;
+ ipfobj_t obj;
+ ipnat_t *ipn;
+
+ ipn = ptr;
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = ipn->in_size;
+ obj.ipfo_type = IPFOBJ_IPNAT;
+ obj.ipfo_ptr = ptr;
+
+ if ((opts & OPT_DONOTHING) != 0)
+ fd = -1;
+
+ if (opts & OPT_ZERORULEST) {
+ add = SIOCZRLST;
+ del = 0;
+ } else if (opts & OPT_PURGE) {
+ add = 0;
+ del = SIOCPURGENAT;
+ } else {
+ add = SIOCADNAT;
+ del = SIOCRMNAT;
+ }
+
+ if ((opts & OPT_VERBOSE) != 0)
+ printnat(ipn, opts);
+
+ if (opts & OPT_DEBUG)
+ binprint(ipn, ipn->in_size);
+
+ if ((opts & OPT_ZERORULEST) != 0) {
+ if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%d:ioctl(zero nat rule)",
+ ipn->in_flineno);
+ return ipf_perror_fd(fd, ioctlfunc, msg);
+ }
+ } else {
+ PRINTF("hits %lu ", ipn->in_hits);
+#ifdef USE_QUAD_T
+ PRINTF("bytes %"PRIu64" ",
+ ipn->in_bytes[0] + ipn->in_bytes[1]);
+#else
+ PRINTF("bytes %lu ",
+ ipn->in_bytes[0] + ipn->in_bytes[1]);
+#endif
+ printnat(ipn, opts);
+ }
+ } else if ((opts & OPT_REMOVE) != 0) {
+ if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%d:ioctl(delete nat rule)",
+ ipn->in_flineno);
+ return ipf_perror_fd(fd, ioctlfunc, msg);
+ }
+ }
+ } else {
+ if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%d:ioctl(add/insert nat rule)",
+ ipn->in_flineno);
+ if (errno == EEXIST) {
+ sprintf(msg + strlen(msg), "(line %d)",
+ ipn->in_flineno);
+ }
+ return ipf_perror_fd(fd, ioctlfunc, msg);
+ }
+ }
+ }
+ return 0;
+}
+
+
+static void
+setmapifnames()
+{
+ if (nat->in_ifnames[1] == -1)
+ nat->in_ifnames[1] = nat->in_ifnames[0];
+
+ if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
+ nat->in_flags |= IPN_TCPUDP;
+
+ if ((nat->in_flags & IPN_TCPUDP) == 0)
+ setnatproto(nat->in_pr[1]);
+
+ if (((nat->in_redir & NAT_MAPBLK) != 0) ||
+ ((nat->in_flags & IPN_AUTOPORTMAP) != 0))
+ nat_setgroupmap(nat);
+}
+
+
+static void
+setrdrifnames()
+{
+ if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0)
+ nat->in_flags |= IPN_TCPUDP;
+
+ if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) &&
+ (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0))
+ setnatproto(IPPROTO_TCP);
+
+ if (nat->in_ifnames[1] == -1)
+ nat->in_ifnames[1] = nat->in_ifnames[0];
+}
+
+
+static void
+proxy_setconfig(proxy)
+ int proxy;
+{
+ if (proxy == IPNY_DNS) {
+ yysetfixeddict(dnswords);
+ }
+}
+
+
+static void
+proxy_unsetconfig()
+{
+ yyresetdict();
+}
+
+
+static namelist_t *
+proxy_dns_add_pass(prefix, name)
+ char *prefix, *name;
+{
+ namelist_t *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n != NULL) {
+ if (prefix == NULL || *prefix == '\0') {
+ n->na_name = strdup(name);
+ } else {
+ n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
+ strcpy(n->na_name, prefix);
+ strcat(n->na_name, name);
+ }
+ }
+ return n;
+}
+
+
+static namelist_t *
+proxy_dns_add_block(prefix, name)
+ char *prefix, *name;
+{
+ namelist_t *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n != NULL) {
+ if (prefix == NULL || *prefix == '\0') {
+ n->na_name = strdup(name);
+ } else {
+ n->na_name = malloc(strlen(name) + strlen(prefix) + 1);
+ strcpy(n->na_name, prefix);
+ strcat(n->na_name, name);
+ }
+ n->na_value = 1;
+ }
+ return n;
+}
+
+
+static void
+proxy_addconfig(proxy, proto, conf, list)
+ char *proxy, *conf;
+ int proto;
+ namelist_t *list;
+{
+ proxyrule_t *pr;
+
+ pr = calloc(1, sizeof(*pr));
+ if (pr != NULL) {
+ pr->pr_proto = proto;
+ pr->pr_proxy = proxy;
+ pr->pr_conf = conf;
+ pr->pr_names = list;
+ pr->pr_next = prules;
+ prules = pr;
+ }
+}
+
+
+static void
+proxy_loadrules(fd, ioctlfunc, rules)
+ int fd;
+ ioctlfunc_t ioctlfunc;
+ proxyrule_t *rules;
+{
+ proxyrule_t *pr;
+
+ while ((pr = rules) != NULL) {
+ proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto,
+ pr->pr_conf, pr->pr_names);
+ rules = pr->pr_next;
+ free(pr->pr_conf);
+ free(pr);
+ }
+}
+
+
+static void
+proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list)
+ int fd;
+ ioctlfunc_t ioctlfunc;
+ char *proxy, *conf;
+ int proto;
+ namelist_t *list;
+{
+ namelist_t *na;
+ ipfobj_t obj;
+ ap_ctl_t pcmd;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_PROXYCTL;
+ obj.ipfo_size = sizeof(pcmd);
+ obj.ipfo_ptr = &pcmd;
+
+ while ((na = list) != NULL) {
+ if ((opts & OPT_REMOVE) != 0)
+ pcmd.apc_cmd = APC_CMD_DEL;
+ else
+ pcmd.apc_cmd = APC_CMD_ADD;
+ pcmd.apc_dsize = strlen(na->na_name) + 1;
+ pcmd.apc_data = na->na_name;
+ pcmd.apc_arg = na->na_value;
+ pcmd.apc_p = proto;
+
+ strncpy(pcmd.apc_label, proxy, APR_LABELLEN);
+ pcmd.apc_label[APR_LABELLEN - 1] = '\0';
+
+ strncpy(pcmd.apc_config, conf, APR_LABELLEN);
+ pcmd.apc_config[APR_LABELLEN - 1] = '\0';
+
+ if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) {
+ if ((opts & OPT_DONOTHING) == 0) {
+ char msg[80];
+
+ sprintf(msg, "%d:ioctl(add/remove proxy rule)",
+ yylineNum);
+ ipf_perror_fd(fd, ioctlfunc, msg);
+ return;
+ }
+ }
+
+ list = na->na_next;
+ free(na->na_name);
+ free(na);
+ }
+}
+
+
+static void
+setifname(np, idx, name)
+ ipnat_t **np;
+ int idx;
+ char *name;
+{
+ int pos;
+
+ pos = addname(np, name);
+ if (pos == -1)
+ return;
+ (*np)->in_ifnames[idx] = pos;
+}
+
+
+static int
+addname(np, name)
+ ipnat_t **np;
+ char *name;
+{
+ ipnat_t *n;
+ int nlen;
+ int pos;
+
+ nlen = strlen(name) + 1;
+ n = realloc(*np, (*np)->in_size + nlen);
+ if (*np == nattop)
+ nattop = n;
+ *np = n;
+ if (n == NULL)
+ return -1;
+ if (n->in_pnext != NULL)
+ *n->in_pnext = n;
+ n->in_size += nlen;
+ pos = n->in_namelen;
+ n->in_namelen += nlen;
+ strcpy(n->in_names + pos, name);
+ n->in_names[n->in_namelen] = '\0';
+ return pos;
+}
diff --git a/contrib/ipfilter/tools/ippool.c b/contrib/ipfilter/tools/ippool.c
new file mode 100644
index 0000000..243932c
--- /dev/null
+++ b/contrib/ipfilter/tools/ippool.c
@@ -0,0 +1,1073 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#if defined(BSD) && (BSD >= 199306)
+# include <sys/cdefs.h>
+#endif
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <unistd.h>
+#ifdef linux
+# include <linux/a.out.h>
+#else
+# include <nlist.h>
+#endif
+
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+#include "netinet/ip_htable.h"
+#include "kmem.h"
+
+
+extern int ippool_yyparse __P((void));
+extern int ippool_yydebug;
+extern FILE *ippool_yyin;
+extern char *optarg;
+extern int lineNum;
+
+void usage __P((char *));
+int main __P((int, char **));
+int poolcommand __P((int, int, char *[]));
+int poolnodecommand __P((int, int, char *[]));
+int loadpoolfile __P((int, char *[], char *));
+int poollist __P((int, char *[]));
+void poollist_dead __P((int, char *, int, char *, char *));
+void poollist_live __P((int, char *, int, int));
+int poolflush __P((int, char *[]));
+int poolstats __P((int, char *[]));
+int gettype __P((char *, u_int *));
+int getrole __P((char *));
+int setnodeaddr __P((int, int, void *ptr, char *arg));
+void showpools_live __P((int, int, ipf_pool_stat_t *, char *));
+void showhashs_live __P((int, int, iphtstat_t *, char *));
+void showdstls_live __P((int, int, ipf_dstl_stat_t *, char *));
+
+int opts = 0;
+int fd = -1;
+int use_inet6 = 0;
+wordtab_t *pool_fields = NULL;
+int nohdrfields = 0;
+
+
+void
+usage(prog)
+ char *prog;
+{
+ fprintf(stderr, "Usage:\t%s\n", prog);
+ fprintf(stderr, "\t-a [-dnv] [-m <name>] [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n");
+ fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
+ fprintf(stderr, "\t-f <file> [-dnuv]\n");
+ fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n");
+ fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-O <fields>]\n");
+ fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n");
+ fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
+ fprintf(stderr, "\t-s [-dtv] [-M <core>] [-N <namelist>]\n");
+ exit(1);
+}
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int err = 1;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ assigndefined(getenv("IPPOOL_PREDEFINED"));
+
+ switch (getopt(argc, argv, "aAf:FlnrRsv"))
+ {
+ case 'a' :
+ err = poolnodecommand(0, argc, argv);
+ break;
+ case 'A' :
+ err = poolcommand(0, argc, argv);
+ break;
+ case 'f' :
+ err = loadpoolfile(argc, argv, optarg);
+ break;
+ case 'F' :
+ err = poolflush(argc, argv);
+ break;
+ case 'l' :
+ err = poollist(argc, argv);
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'r' :
+ err = poolnodecommand(1, argc, argv);
+ break;
+ case 'R' :
+ err = poolcommand(1, argc, argv);
+ break;
+ case 's' :
+ err = poolstats(argc, argv);
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ exit(1);
+ }
+
+ if (err != 0)
+ exit(1);
+ return 0;
+}
+
+
+int
+poolnodecommand(remove, argc, argv)
+ int remove, argc;
+ char *argv[];
+{
+ int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
+ char *poolname = NULL;
+ ip_pool_node_t pnode;
+ iphtent_t hnode;
+ void *ptr = &pnode;
+
+ ipset = 0;
+ role = IPL_LOGIPF;
+ bzero((char *)&pnode, sizeof(pnode));
+ bzero((char *)&hnode, sizeof(hnode));
+
+ while ((c = getopt(argc, argv, "di:m:no:Rt:T:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ ippool_yydebug++;
+ break;
+ case 'i' :
+ if (setnodeaddr(type, role, ptr, optarg) == 0)
+ ipset = 1;
+ break;
+ case 'm' :
+ poolname = optarg;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'o' :
+ if (ipset == 1) {
+ fprintf(stderr,
+ "cannot set role after ip address\n");
+ return -1;
+ }
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE)
+ return -1;
+ break;
+ case 'R' :
+ opts |= OPT_NORESOLVE;
+ break;
+ case 't' :
+ if (ipset == 1) {
+ fprintf(stderr,
+ "cannot set type after ip address\n");
+ return -1;
+ }
+ type = gettype(optarg, NULL);
+ switch (type) {
+ case IPLT_NONE :
+ fprintf(stderr, "unknown type '%s'\n", optarg);
+ return -1;
+ case IPLT_HASH :
+ ptr = &hnode;
+ break;
+ case IPLT_POOL :
+ default :
+ break;
+ }
+ break;
+ case 'T' :
+ ttl = atoi(optarg);
+ if (ttl < 0) {
+ fprintf(stderr, "cannot set negative ttl\n");
+ return -1;
+ }
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (argv[optind] != NULL && ipset == 0) {
+ if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
+ ipset = 1;
+ }
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
+
+ if (ipset == 0) {
+ fprintf(stderr, "no IP address given with -i\n");
+ return -1;
+ }
+
+ if (poolname == NULL) {
+ fprintf(stderr, "poolname not given with add/remove node\n");
+ return -1;
+ }
+
+ switch (type) {
+ case IPLT_POOL :
+ if (remove == 0)
+ err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
+ else
+ err = remove_poolnode(role, poolname, &pnode, ioctl);
+ break;
+ case IPLT_HASH :
+ if (remove == 0)
+ err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
+ else
+ err = remove_hashnode(role, poolname, &hnode, ioctl);
+ break;
+ default :
+ break;
+ }
+ return err;
+}
+
+
+int
+poolcommand(remove, argc, argv)
+ int remove, argc;
+ char *argv[];
+{
+ int type, role, c, err;
+ char *poolname;
+ iphtable_t iph;
+ ip_pool_t pool;
+
+ err = 1;
+ role = 0;
+ type = 0;
+ poolname = NULL;
+ role = IPL_LOGIPF;
+ bzero((char *)&iph, sizeof(iph));
+ bzero((char *)&pool, sizeof(pool));
+
+ while ((c = getopt(argc, argv, "dm:no:RSv")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ ippool_yydebug++;
+ break;
+ case 'm' :
+ poolname = optarg;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'o' :
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE) {
+ fprintf(stderr, "unknown role '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 'R' :
+ opts |= OPT_NORESOLVE;
+ break;
+ case 'S' :
+ iph.iph_seed = atoi(optarg);
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poolcommand: opts = %#x\n", opts);
+
+ if (poolname == NULL) {
+ fprintf(stderr, "poolname not given with add/remove pool\n");
+ return -1;
+ }
+
+ type = gettype(argv[optind], &iph.iph_type);
+ if (type == IPLT_NONE) {
+ fprintf(stderr, "unknown type '%s'\n", argv[optind]);
+ return -1;
+ }
+
+ if (type == IPLT_HASH) {
+ strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
+ iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
+ iph.iph_unit = role;
+ } else if (type == IPLT_POOL) {
+ strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name));
+ pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0';
+ pool.ipo_unit = role;
+ }
+
+ if (remove == 0) {
+ switch (type)
+ {
+ case IPLT_HASH :
+ err = load_hash(&iph, NULL, ioctl);
+ break;
+ case IPLT_POOL :
+ err = load_pool(&pool, ioctl);
+ break;
+ }
+ } else {
+ switch (type)
+ {
+ case IPLT_HASH :
+ err = remove_hash(&iph, ioctl);
+ break;
+ case IPLT_POOL :
+ err = remove_pool(&pool, ioctl);
+ break;
+ }
+ }
+ return err;
+}
+
+
+int
+loadpoolfile(argc, argv, infile)
+ int argc;
+ char *argv[], *infile;
+{
+ int c;
+
+ infile = optarg;
+
+ while ((c = getopt(argc, argv, "dnRuv")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ ippool_yydebug++;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'R' :
+ opts |= OPT_NORESOLVE;
+ break;
+ case 'u' :
+ opts |= OPT_REMOVE;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ if (ippool_parsefile(fd, infile, ioctl) != 0)
+ return -1;
+ return 0;
+}
+
+
+int
+poolstats(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, type, role, live_kernel;
+ ipf_pool_stat_t plstat;
+ ipf_dstl_stat_t dlstat;
+ char *kernel, *core;
+ iphtstat_t htstat;
+ iplookupop_t op;
+
+ core = NULL;
+ kernel = NULL;
+ live_kernel = 1;
+ type = IPLT_ALL;
+ role = IPL_LOGALL;
+
+ bzero((char *)&op, sizeof(op));
+
+ while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'M' :
+ live_kernel = 0;
+ core = optarg;
+ break;
+ case 'N' :
+ live_kernel = 0;
+ kernel = optarg;
+ break;
+ case 'o' :
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE) {
+ fprintf(stderr, "unknown role '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 't' :
+ type = gettype(optarg, NULL);
+ if (type != IPLT_POOL) {
+ fprintf(stderr,
+ "-s not supported for this type yet\n");
+ return -1;
+ }
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poolstats: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_POOL) {
+ op.iplo_type = IPLT_POOL;
+ op.iplo_struct = &plstat;
+ op.iplo_size = sizeof(plstat);
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
+ return -1;
+ }
+ printf("%lu\taddress pools\n", plstat.ipls_pools);
+ printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_HASH) {
+ op.iplo_type = IPLT_HASH;
+ op.iplo_struct = &htstat;
+ op.iplo_size = sizeof(htstat);
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return -1;
+ }
+ printf("%lu\thash tables\n", htstat.iphs_numtables);
+ printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
+ printf("%lu\thash table no memory \n",
+ htstat.iphs_nomem);
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_DSTLIST) {
+ op.iplo_type = IPLT_DSTLIST;
+ op.iplo_struct = &dlstat;
+ op.iplo_size = sizeof(dlstat);
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return -1;
+ }
+ printf("%u\tdestination lists\n",
+ dlstat.ipls_numlists);
+ printf("%u\tdestination list nodes\n",
+ dlstat.ipls_numnodes);
+ printf("%lu\tdestination list no memory\n",
+ dlstat.ipls_nomem);
+ printf("%u\tdestination list zombies\n",
+ dlstat.ipls_numdereflists);
+ printf("%u\tdesetination list node zombies\n",
+ dlstat.ipls_numderefnodes);
+ }
+ }
+ return 0;
+}
+
+
+int
+poolflush(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, role, type, arg;
+ iplookupflush_t flush;
+
+ arg = IPLT_ALL;
+ type = IPLT_ALL;
+ role = IPL_LOGALL;
+
+ while ((c = getopt(argc, argv, "do:t:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'o' :
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE) {
+ fprintf(stderr, "unknown role '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 't' :
+ type = gettype(optarg, NULL);
+ if (type == IPLT_NONE) {
+ fprintf(stderr, "unknown type '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poolflush: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ bzero((char *)&flush, sizeof(flush));
+ flush.iplf_type = type;
+ flush.iplf_unit = role;
+ flush.iplf_arg = arg;
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
+ exit(1);
+ }
+
+ }
+ printf("%u object%s flushed\n", flush.iplf_count,
+ (flush.iplf_count == 1) ? "" : "s");
+
+ return 0;
+}
+
+
+int
+getrole(rolename)
+ char *rolename;
+{
+ int role;
+
+ if (!strcasecmp(rolename, "ipf")) {
+ role = IPL_LOGIPF;
+#if 0
+ } else if (!strcasecmp(rolename, "nat")) {
+ role = IPL_LOGNAT;
+ } else if (!strcasecmp(rolename, "state")) {
+ role = IPL_LOGSTATE;
+ } else if (!strcasecmp(rolename, "auth")) {
+ role = IPL_LOGAUTH;
+ } else if (!strcasecmp(rolename, "sync")) {
+ role = IPL_LOGSYNC;
+ } else if (!strcasecmp(rolename, "scan")) {
+ role = IPL_LOGSCAN;
+ } else if (!strcasecmp(rolename, "pool")) {
+ role = IPL_LOGLOOKUP;
+ } else if (!strcasecmp(rolename, "count")) {
+ role = IPL_LOGCOUNT;
+#endif
+ } else {
+ role = IPL_LOGNONE;
+ }
+
+ return role;
+}
+
+
+int
+gettype(typename, minor)
+ char *typename;
+ u_int *minor;
+{
+ int type;
+
+ if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
+ type = IPLT_POOL;
+ } else if (!strcasecmp(typename, "hash")) {
+ type = IPLT_HASH;
+ if (minor != NULL)
+ *minor = IPHASH_LOOKUP;
+ } else if (!strcasecmp(typename, "group-map")) {
+ type = IPLT_HASH;
+ if (minor != NULL)
+ *minor = IPHASH_GROUPMAP;
+ } else {
+ type = IPLT_NONE;
+ }
+ return type;
+}
+
+
+int
+poollist(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *kernel, *core, *poolname;
+ int c, role, type, live_kernel;
+ iplookupop_t op;
+
+ core = NULL;
+ kernel = NULL;
+ live_kernel = 1;
+ type = IPLT_ALL;
+ poolname = NULL;
+ role = IPL_LOGALL;
+
+ while ((c = getopt(argc, argv, "dm:M:N:o:Rt:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'm' :
+ poolname = optarg;
+ break;
+ case 'M' :
+ live_kernel = 0;
+ core = optarg;
+ break;
+ case 'N' :
+ live_kernel = 0;
+ kernel = optarg;
+ break;
+ case 'o' :
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE) {
+ fprintf(stderr, "unknown role '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 'O' :
+ pool_fields = parsefields(poolfields, optarg);
+ break;
+ case 'R' :
+ opts |= OPT_NORESOLVE;
+ break;
+ case 't' :
+ type = gettype(optarg, NULL);
+ if (type == IPLT_NONE) {
+ fprintf(stderr, "unknown type '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poollist: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ bzero((char *)&op, sizeof(op));
+ if (poolname != NULL) {
+ strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
+ op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
+ }
+ op.iplo_unit = role;
+
+ if (live_kernel)
+ poollist_live(role, poolname, type, fd);
+ else
+ poollist_dead(role, poolname, type, kernel, core);
+ return 0;
+}
+
+
+void
+poollist_dead(role, poolname, type, kernel, core)
+ int role, type;
+ char *poolname, *kernel, *core;
+{
+ iphtable_t *hptr;
+ ip_pool_t *ptr;
+
+ if (openkmem(kernel, core) == -1)
+ exit(-1);
+
+ if (type == IPLT_ALL || type == IPLT_POOL) {
+ ip_pool_t *pools[IPL_LOGSIZE];
+ struct nlist names[2] = { { "ip_pool_list" } , { "" } };
+
+ if (nlist(kernel, names) != 1)
+ return;
+
+ bzero(&pools, sizeof(pools));
+ if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
+ return;
+
+ if (role != IPL_LOGALL) {
+ ptr = pools[role];
+ while (ptr != NULL) {
+ ptr = printpool(ptr, kmemcpywrap, poolname,
+ opts, pool_fields);
+ }
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+ ptr = pools[role];
+ while (ptr != NULL) {
+ ptr = printpool(ptr, kmemcpywrap,
+ poolname, opts,
+ pool_fields);
+ }
+ }
+ role = IPL_LOGALL;
+ }
+ }
+ if (type == IPLT_ALL || type == IPLT_HASH) {
+ iphtable_t *tables[IPL_LOGSIZE];
+ struct nlist names[2] = { { "ipf_htables" } , { "" } };
+
+ if (nlist(kernel, names) != 1)
+ return;
+
+ bzero(&tables, sizeof(tables));
+ if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
+ return;
+
+ if (role != IPL_LOGALL) {
+ hptr = tables[role];
+ while (hptr != NULL) {
+ hptr = printhash(hptr, kmemcpywrap,
+ poolname, opts, pool_fields);
+ }
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+ hptr = tables[role];
+ while (hptr != NULL) {
+ hptr = printhash(hptr, kmemcpywrap,
+ poolname, opts,
+ pool_fields);
+ }
+ }
+ }
+ }
+}
+
+
+void
+poollist_live(role, poolname, type, fd)
+ int role, type, fd;
+ char *poolname;
+{
+ ipf_pool_stat_t plstat;
+ iplookupop_t op;
+ int c;
+
+ if (type == IPLT_ALL || type == IPLT_POOL) {
+ op.iplo_type = IPLT_POOL;
+ op.iplo_size = sizeof(plstat);
+ op.iplo_struct = &plstat;
+ op.iplo_name[0] = '\0';
+ op.iplo_arg = 0;
+
+ if (role != IPL_LOGALL) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showpools_live(fd, role, &plstat, poolname);
+ } else {
+ for (role = -1; role <= IPL_LOGMAX; role++) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showpools_live(fd, role, &plstat, poolname);
+ }
+
+ role = IPL_LOGALL;
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_HASH) {
+ iphtstat_t htstat;
+
+ op.iplo_type = IPLT_HASH;
+ op.iplo_size = sizeof(htstat);
+ op.iplo_struct = &htstat;
+ op.iplo_name[0] = '\0';
+ op.iplo_arg = 0;
+
+ if (role != IPL_LOGALL) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+ showhashs_live(fd, role, &htstat, poolname);
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+
+ op.iplo_unit = role;
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showhashs_live(fd, role, &htstat, poolname);
+ }
+ role = IPL_LOGALL;
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_DSTLIST) {
+ ipf_dstl_stat_t dlstat;
+
+ op.iplo_type = IPLT_DSTLIST;
+ op.iplo_size = sizeof(dlstat);
+ op.iplo_struct = &dlstat;
+ op.iplo_name[0] = '\0';
+ op.iplo_arg = 0;
+
+ if (role != IPL_LOGALL) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+ showdstls_live(fd, role, &dlstat, poolname);
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+
+ op.iplo_unit = role;
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showdstls_live(fd, role, &dlstat, poolname);
+ }
+ role = IPL_LOGALL;
+ }
+ }
+}
+
+
+void
+showpools_live(fd, role, plstp, poolname)
+ int fd, role;
+ ipf_pool_stat_t *plstp;
+ char *poolname;
+{
+ ipflookupiter_t iter;
+ ip_pool_t pool;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.ili_type = IPLT_POOL;
+ iter.ili_otype = IPFLOOKUPITER_LIST;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_nitems = 1;
+ iter.ili_data = &pool;
+ iter.ili_unit = role;
+ *iter.ili_name = '\0';
+
+ bzero((char *)&pool, sizeof(pool));
+
+ while (plstp->ipls_list[role + 1] != NULL) {
+ if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+ ipferror(fd, "ioctl(SIOCLOOKUPITER)");
+ break;
+ }
+ if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
+ ((opts & OPT_DEBUG) != 0))
+ printpool_live(&pool, fd, poolname, opts, pool_fields);
+
+ plstp->ipls_list[role + 1] = pool.ipo_next;
+ }
+}
+
+
+void
+showhashs_live(fd, role, htstp, poolname)
+ int fd, role;
+ iphtstat_t *htstp;
+ char *poolname;
+{
+ ipflookupiter_t iter;
+ iphtable_t table;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.ili_type = IPLT_HASH;
+ iter.ili_otype = IPFLOOKUPITER_LIST;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_nitems = 1;
+ iter.ili_data = &table;
+ iter.ili_unit = role;
+ *iter.ili_name = '\0';
+
+ while (htstp->iphs_tables != NULL) {
+ if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+ ipferror(fd, "ioctl(SIOCLOOKUPITER)");
+ break;
+ }
+
+ printhash_live(&table, fd, poolname, opts, pool_fields);
+
+ htstp->iphs_tables = table.iph_next;
+ }
+}
+
+
+void
+showdstls_live(fd, role, dlstp, poolname)
+ int fd, role;
+ ipf_dstl_stat_t *dlstp;
+ char *poolname;
+{
+ ipflookupiter_t iter;
+ ippool_dst_t table;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.ili_type = IPLT_DSTLIST;
+ iter.ili_otype = IPFLOOKUPITER_LIST;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_nitems = 1;
+ iter.ili_data = &table;
+ iter.ili_unit = role;
+ *iter.ili_name = '\0';
+
+ while (dlstp->ipls_list[role] != NULL) {
+ if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+ ipferror(fd, "ioctl(SIOCLOOKUPITER)");
+ break;
+ }
+
+ printdstl_live(&table, fd, poolname, opts, pool_fields);
+
+ dlstp->ipls_list[role] = table.ipld_next;
+ }
+}
+
+
+int
+setnodeaddr(int type, int role, void *ptr, char *arg)
+{
+ struct in_addr mask;
+ char *s;
+
+ s = strchr(arg, '/');
+ if (s == NULL)
+ mask.s_addr = 0xffffffff;
+ else if (strchr(s, '.') == NULL) {
+ if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
+ return -1;
+ } else {
+ mask.s_addr = inet_addr(s + 1);
+ }
+ if (s != NULL)
+ *s = '\0';
+
+ if (type == IPLT_POOL) {
+ ip_pool_node_t *node = ptr;
+
+ if (node->ipn_addr.adf_family == AF_INET)
+ node->ipn_addr.adf_len = offsetof(addrfamily_t,
+ adf_addr) +
+ sizeof(struct in_addr);
+#ifdef USE_INET6
+ else
+ node->ipn_addr.adf_len = offsetof(addrfamily_t,
+ adf_addr) +
+ sizeof(struct in6_addr);
+#endif
+ node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
+ node->ipn_mask.adf_len = node->ipn_addr.adf_len;
+ node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
+ } else if (type == IPLT_HASH) {
+ iphtent_t *node = ptr;
+
+ node->ipe_addr.in4.s_addr = inet_addr(arg);
+ node->ipe_mask.in4.s_addr = mask.s_addr;
+ node->ipe_family = AF_INET;
+ node->ipe_unit = role;
+ }
+
+ return 0;
+}
diff --git a/contrib/ipfilter/tools/ippool_y.y b/contrib/ipfilter/tools/ippool_y.y
new file mode 100644
index 0000000..93593ce
--- /dev/null
+++ b/contrib/ipfilter/tools/ippool_y.y
@@ -0,0 +1,818 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+%{
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#if defined(BSD) && (BSD >= 199306)
+# include <sys/cdefs.h>
+#endif
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+#include "netinet/ip_htable.h"
+#include "netinet/ip_dstlist.h"
+#include "ippool_l.h"
+#include "kmem.h"
+
+#define YYDEBUG 1
+#define YYSTACKSIZE 0x00ffffff
+
+extern int yyparse __P((void));
+extern int yydebug;
+extern FILE *yyin;
+
+static iphtable_t ipht;
+static iphtent_t iphte;
+static ip_pool_t iplo;
+static ippool_dst_t ipld;
+static ioctlfunc_t poolioctl = NULL;
+static char poolname[FR_GROUPLEN];
+
+static iphtent_t *add_htablehosts __P((char *));
+static ip_pool_node_t *add_poolhosts __P((char *));
+static ip_pool_node_t *read_whoisfile __P((char *));
+static void setadflen __P((addrfamily_t *));
+
+%}
+
+%union {
+ char *str;
+ u_32_t num;
+ struct in_addr ip4;
+ struct alist_s *alist;
+ addrfamily_t adrmsk[2];
+ iphtent_t *ipe;
+ ip_pool_node_t *ipp;
+ ipf_dstnode_t *ipd;
+ addrfamily_t ipa;
+ i6addr_t ip6;
+}
+
+%token <num> YY_NUMBER YY_HEX
+%token <str> YY_STR
+%token <ip6> YY_IPV6
+%token YY_COMMENT
+%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
+%token YY_RANGE_OUT YY_RANGE_IN
+%token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT IPT_ALL
+%token IPT_TABLE IPT_GROUPMAP IPT_HASH IPT_SRCHASH IPT_DSTHASH
+%token IPT_ROLE IPT_TYPE IPT_TREE
+%token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME IPT_POLICY
+%token IPT_POOL IPT_DSTLIST IPT_ROUNDROBIN
+%token IPT_WEIGHTED IPT_RANDOM IPT_CONNECTION
+%token IPT_WHOIS IPT_FILE
+%type <num> role table inout unit dstopts weighting
+%type <ipp> ipftree range addrlist
+%type <adrmsk> addrmask
+%type <ipe> ipfgroup ipfhash hashlist hashentry
+%type <ipe> groupentry setgrouplist grouplist
+%type <ipa> ipaddr mask
+%type <ip4> ipv4
+%type <str> number setgroup name
+%type <ipd> dstentry dstentries dstlist
+
+%%
+file: line
+ | assign
+ | file line
+ | file assign
+ ;
+
+line: table role ipftree eol { ip_pool_node_t *n;
+ iplo.ipo_unit = $2;
+ iplo.ipo_list = $3;
+ load_pool(&iplo, poolioctl);
+ while ((n = $3) != NULL) {
+ $3 = n->ipn_next;
+ free(n);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ }
+ | table role ipfhash eol { iphtent_t *h;
+ ipht.iph_unit = $2;
+ ipht.iph_type = IPHASH_LOOKUP;
+ load_hash(&ipht, $3, poolioctl);
+ while ((h = $3) != NULL) {
+ $3 = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ }
+ | groupmap role number ipfgroup eol
+ { iphtent_t *h;
+ ipht.iph_unit = $2;
+ strncpy(ipht.iph_name, $3,
+ sizeof(ipht.iph_name));
+ ipht.iph_type = IPHASH_GROUPMAP;
+ load_hash(&ipht, $4, poolioctl);
+ while ((h = $4) != NULL) {
+ $4 = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ }
+ | YY_COMMENT
+ | poolline eol
+ ;
+
+eol: ';'
+ ;
+
+assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
+ resetlexer();
+ free($1);
+ free($3);
+ yyvarnext = 0;
+ }
+ ;
+
+assigning:
+ '=' { yyvarnext = 1; }
+ ;
+
+table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht));
+ bzero((char *)&iphte, sizeof(iphte));
+ bzero((char *)&iplo, sizeof(iplo));
+ bzero((char *)&ipld, sizeof(ipld));
+ *ipht.iph_name = '\0';
+ iplo.ipo_flags = IPHASH_ANON;
+ iplo.ipo_name[0] = '\0';
+ }
+ ;
+
+groupmap:
+ IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht));
+ bzero((char *)&iphte, sizeof(iphte));
+ *ipht.iph_name = '\0';
+ ipht.iph_unit = IPHASH_GROUPMAP;
+ ipht.iph_flags = $2;
+ }
+ ;
+
+inout: IPT_IN { $$ = FR_INQUE; }
+ | IPT_OUT { $$ = FR_OUTQUE; }
+ ;
+
+role: IPT_ROLE '=' unit { $$ = $3; }
+ ;
+
+unit: IPT_IPF { $$ = IPL_LOGIPF; }
+ | IPT_NAT { $$ = IPL_LOGNAT; }
+ | IPT_AUTH { $$ = IPL_LOGAUTH; }
+ | IPT_COUNT { $$ = IPL_LOGCOUNT; }
+ | IPT_ALL { $$ = IPL_LOGALL; }
+ ;
+
+ipftree:
+ IPT_TYPE '=' IPT_TREE number start addrlist end
+ { strncpy(iplo.ipo_name, $4,
+ sizeof(iplo.ipo_name));
+ $$ = $6;
+ }
+ ;
+
+ipfhash:
+ IPT_TYPE '=' IPT_HASH number hashopts start hashlist end
+ { strncpy(ipht.iph_name, $4,
+ sizeof(ipht.iph_name));
+ $$ = $7;
+ }
+ ;
+
+ipfgroup:
+ setgroup hashopts start grouplist end
+ { iphtent_t *e;
+ for (e = $4; e != NULL;
+ e = e->ipe_next)
+ if (e->ipe_group[0] == '\0')
+ strncpy(e->ipe_group,
+ $1,
+ FR_GROUPLEN);
+ $$ = $4;
+ free($1);
+ }
+ | hashopts start setgrouplist end
+ { $$ = $3; }
+ ;
+
+number: IPT_NUM '=' YY_NUMBER { sprintf(poolname, "%u", $3);
+ $$ = poolname;
+ }
+ | IPT_NAME '=' YY_STR { strncpy(poolname, $3,
+ FR_GROUPLEN);
+ poolname[FR_GROUPLEN-1]='\0';
+ free($3);
+ $$ = poolname;
+ }
+ | { $$ = ""; }
+ ;
+
+setgroup:
+ IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1];
+ strncpy(tmp, $3, FR_GROUPLEN);
+ $$ = strdup(tmp);
+ free($3);
+ }
+ | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1];
+ sprintf(tmp, "%u", $3);
+ $$ = strdup(tmp);
+ }
+ ;
+
+hashopts:
+ | size
+ | seed
+ | size seed
+ ;
+
+addrlist:
+ ';' { $$ = NULL; }
+ | range next addrlist { $$ = $1;
+ while ($1->ipn_next != NULL)
+ $1 = $1->ipn_next;
+ $1->ipn_next = $3;
+ }
+ | range next { $$ = $1; }
+ ;
+
+grouplist:
+ ';' { $$ = NULL; }
+ | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; }
+ | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+ $$->ipe_family = $1[0].adf_family;
+ $$->ipe_next = $3;
+ }
+ | groupentry next { $$ = $1; }
+ | addrmask next { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+#ifdef AF_INET6
+ if (use_inet6)
+ $$->ipe_family = AF_INET6;
+ else
+#endif
+ $$->ipe_family = AF_INET;
+ }
+ | YY_STR { $$ = add_htablehosts($1);
+ free($1);
+ }
+ ;
+
+setgrouplist:
+ ';' { $$ = NULL; }
+ | groupentry next { $$ = $1; }
+ | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; }
+ ;
+
+groupentry:
+ addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+ strncpy($$->ipe_group, $3,
+ FR_GROUPLEN);
+#ifdef AF_INET6
+ if (use_inet6)
+ $$->ipe_family = AF_INET6;
+ else
+#endif
+ $$->ipe_family = AF_INET;
+ free($3);
+ }
+ ;
+
+range: addrmask { $$ = calloc(1, sizeof(*$$));
+ $$->ipn_info = 0;
+ $$->ipn_addr = $1[0];
+ $$->ipn_mask = $1[1];
+ }
+ | '!' addrmask { $$ = calloc(1, sizeof(*$$));
+ $$->ipn_info = 1;
+ $$->ipn_addr = $2[0];
+ $$->ipn_mask = $2[1];
+ }
+ | YY_STR { $$ = add_poolhosts($1);
+ free($1);
+ }
+ | IPT_WHOIS IPT_FILE YY_STR { $$ = read_whoisfile($3);
+ free($3);
+ }
+ ;
+
+hashlist:
+ ';' { $$ = NULL; }
+ | hashentry next { $$ = $1; }
+ | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; }
+ ;
+
+hashentry:
+ addrmask { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+#ifdef USE_INET6
+ if (use_inet6)
+ $$->ipe_family = AF_INET6;
+ else
+#endif
+ $$->ipe_family = AF_INET;
+ }
+ | YY_STR { $$ = add_htablehosts($1);
+ free($1);
+ }
+ ;
+
+addrmask:
+ ipaddr '/' mask { $$[0] = $1;
+ setadflen(&$$[0]);
+ $$[1] = $3;
+ $$[1].adf_len = $$[0].adf_len;
+ }
+ | ipaddr { $$[0] = $1;
+ setadflen(&$$[1]);
+ $$[1].adf_len = $$[0].adf_len;
+#ifdef USE_INET6
+ if (use_inet6)
+ memset(&$$[1].adf_addr, 0xff,
+ sizeof($$[1].adf_addr.in6));
+ else
+#endif
+ memset(&$$[1].adf_addr, 0xff,
+ sizeof($$[1].adf_addr.in4));
+ }
+ ;
+
+ipaddr: ipv4 { $$.adf_addr.in4 = $1;
+ $$.adf_family = AF_INET;
+ setadflen(&$$);
+ use_inet6 = 0;
+ }
+ | YY_NUMBER { $$.adf_addr.in4.s_addr = htonl($1);
+ $$.adf_family = AF_INET;
+ setadflen(&$$);
+ use_inet6 = 0;
+ }
+ | YY_IPV6 { $$.adf_addr = $1;
+ $$.adf_family = AF_INET6;
+ setadflen(&$$);
+ use_inet6 = 1;
+ }
+ ;
+
+mask: YY_NUMBER { bzero(&$$, sizeof($$));
+ if (use_inet6) {
+ if (ntomask(AF_INET6, $1,
+ (u_32_t *)&$$.adf_addr) == -1)
+ yyerror("bad bitmask");
+ } else {
+ if (ntomask(AF_INET, $1,
+ (u_32_t *)&$$.adf_addr.in4) == -1)
+ yyerror("bad bitmask");
+ }
+ }
+ | ipv4 { bzero(&$$, sizeof($$));
+ $$.adf_addr.in4 = $1;
+ }
+ | YY_IPV6 { bzero(&$$, sizeof($$));
+ $$.adf_addr = $1;
+ }
+ ;
+
+size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; }
+ ;
+
+seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; }
+ ;
+
+ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
+ { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
+ $$.s_addr = htonl($$.s_addr);
+ }
+ ;
+
+next: ';' { yyexpectaddr = 1; }
+ ;
+
+start: '{' { yyexpectaddr = 1; }
+ ;
+
+end: '}' { yyexpectaddr = 0; }
+ ;
+
+poolline:
+ IPT_POOL unit '/' IPT_DSTLIST '(' name ';' dstopts ')'
+ start dstlist end
+ { bzero((char *)&ipld, sizeof(ipld));
+ strncpy(ipld.ipld_name, $6,
+ sizeof(ipld.ipld_name));
+ ipld.ipld_unit = $2;
+ ipld.ipld_policy = $8;
+ load_dstlist(&ipld, poolioctl, $11);
+ resetlexer();
+ use_inet6 = 0;
+ free($6);
+ }
+ | IPT_POOL unit '/' IPT_TREE '(' name ';' ')'
+ start addrlist end
+ { bzero((char *)&iplo, sizeof(iplo));
+ strncpy(iplo.ipo_name, $6,
+ sizeof(iplo.ipo_name));
+ iplo.ipo_list = $10;
+ iplo.ipo_unit = $2;
+ load_pool(&iplo, poolioctl);
+ resetlexer();
+ use_inet6 = 0;
+ free($6);
+ }
+ | IPT_POOL '(' name ';' ')' start addrlist end
+ { bzero((char *)&iplo, sizeof(iplo));
+ strncpy(iplo.ipo_name, $3,
+ sizeof(iplo.ipo_name));
+ iplo.ipo_list = $7;
+ iplo.ipo_unit = IPL_LOGALL;
+ load_pool(&iplo, poolioctl);
+ resetlexer();
+ use_inet6 = 0;
+ free($3);
+ }
+ | IPT_POOL unit '/' IPT_HASH '(' name ';' hashoptlist ')'
+ start hashlist end
+ { iphtent_t *h;
+ bzero((char *)&ipht, sizeof(ipht));
+ strncpy(ipht.iph_name, $6,
+ sizeof(ipht.iph_name));
+ ipht.iph_unit = $2;
+ load_hash(&ipht, $11, poolioctl);
+ while ((h = ipht.iph_list) != NULL) {
+ ipht.iph_list = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ free($6);
+ }
+ | IPT_GROUPMAP '(' name ';' inout ';' ')'
+ start setgrouplist end
+ { iphtent_t *h;
+ bzero((char *)&ipht, sizeof(ipht));
+ strncpy(ipht.iph_name, $3,
+ sizeof(ipht.iph_name));
+ ipht.iph_type = IPHASH_GROUPMAP;
+ ipht.iph_unit = IPL_LOGIPF;
+ ipht.iph_flags = $5;
+ load_hash(&ipht, $9, poolioctl);
+ while ((h = ipht.iph_list) != NULL) {
+ ipht.iph_list = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ free($3);
+ }
+ ;
+
+name: IPT_NAME YY_STR { $$ = $2; }
+ | IPT_NUM YY_NUMBER { char name[80];
+ sprintf(name, "%d", $2);
+ $$ = strdup(name);
+ }
+ ;
+
+hashoptlist:
+ | hashopt ';'
+ | hashoptlist ';' hashopt ';'
+ ;
+hashopt:
+ IPT_SIZE YY_NUMBER
+ | IPT_SEED YY_NUMBER
+ ;
+
+dstlist:
+ dstentries { $$ = $1; }
+ | ';' { $$ = NULL; }
+ ;
+
+dstentries:
+ dstentry next { $$ = $1; }
+ | dstentry next dstentries { $1->ipfd_next = $3; $$ = $1; }
+ ;
+
+dstentry:
+ YY_STR ':' ipaddr { int size = sizeof(*$$) + strlen($1) + 1;
+ $$ = calloc(1, size);
+ if ($$ != NULL) {
+ $$->ipfd_dest.fd_name = strlen($1) + 1;
+ bcopy($1, $$->ipfd_names,
+ $$->ipfd_dest.fd_name);
+ $$->ipfd_dest.fd_addr = $3;
+ $$->ipfd_size = size;
+ }
+ free($1);
+ }
+ | ipaddr { $$ = calloc(1, sizeof(*$$));
+ if ($$ != NULL) {
+ $$->ipfd_dest.fd_name = -1;
+ $$->ipfd_dest.fd_addr = $1;
+ $$->ipfd_size = sizeof(*$$);
+ }
+ }
+ ;
+
+dstopts:
+ { $$ = IPLDP_NONE; }
+ | IPT_POLICY IPT_ROUNDROBIN ';' { $$ = IPLDP_ROUNDROBIN; }
+ | IPT_POLICY IPT_WEIGHTED weighting ';' { $$ = $3; }
+ | IPT_POLICY IPT_RANDOM ';' { $$ = IPLDP_RANDOM; }
+ | IPT_POLICY IPT_HASH ';' { $$ = IPLDP_HASHED; }
+ | IPT_POLICY IPT_SRCHASH ';' { $$ = IPLDP_SRCHASH; }
+ | IPT_POLICY IPT_DSTHASH ';' { $$ = IPLDP_DSTHASH; }
+ ;
+
+weighting:
+ IPT_CONNECTION { $$ = IPLDP_CONNECTION; }
+ ;
+%%
+static wordtab_t yywords[] = {
+ { "all", IPT_ALL },
+ { "auth", IPT_AUTH },
+ { "connection", IPT_CONNECTION },
+ { "count", IPT_COUNT },
+ { "dst-hash", IPT_DSTHASH },
+ { "dstlist", IPT_DSTLIST },
+ { "file", IPT_FILE },
+ { "group", IPT_GROUP },
+ { "group-map", IPT_GROUPMAP },
+ { "hash", IPT_HASH },
+ { "in", IPT_IN },
+ { "ipf", IPT_IPF },
+ { "name", IPT_NAME },
+ { "nat", IPT_NAT },
+ { "number", IPT_NUM },
+ { "out", IPT_OUT },
+ { "policy", IPT_POLICY },
+ { "pool", IPT_POOL },
+ { "random", IPT_RANDOM },
+ { "round-robin", IPT_ROUNDROBIN },
+ { "role", IPT_ROLE },
+ { "seed", IPT_SEED },
+ { "size", IPT_SIZE },
+ { "src-hash", IPT_SRCHASH },
+ { "table", IPT_TABLE },
+ { "tree", IPT_TREE },
+ { "type", IPT_TYPE },
+ { "weighted", IPT_WEIGHTED },
+ { "whois", IPT_WHOIS },
+ { NULL, 0 }
+};
+
+
+int ippool_parsefile(fd, filename, iocfunc)
+int fd;
+char *filename;
+ioctlfunc_t iocfunc;
+{
+ FILE *fp = NULL;
+ char *s;
+
+ yylineNum = 1;
+ (void) yysettab(yywords);
+
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ if (strcmp(filename, "-")) {
+ fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(stderr, "fopen(%s) failed: %s\n", filename,
+ STRERROR(errno));
+ return -1;
+ }
+ } else
+ fp = stdin;
+
+ while (ippool_parsesome(fd, fp, iocfunc) == 1)
+ ;
+ if (fp != NULL)
+ fclose(fp);
+ return 0;
+}
+
+
+int ippool_parsesome(fd, fp, iocfunc)
+int fd;
+FILE *fp;
+ioctlfunc_t iocfunc;
+{
+ char *s;
+ int i;
+
+ poolioctl = iocfunc;
+
+ if (feof(fp))
+ return 0;
+ i = fgetc(fp);
+ if (i == EOF)
+ return 0;
+ if (ungetc(i, fp) == EOF)
+ return 0;
+ if (feof(fp))
+ return 0;
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ yyin = fp;
+ yyparse();
+ return 1;
+}
+
+
+static iphtent_t *
+add_htablehosts(url)
+char *url;
+{
+ iphtent_t *htop, *hbot, *h;
+ alist_t *a, *hlist;
+
+ if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
+ hlist = load_url(url);
+ } else {
+ use_inet6 = 0;
+
+ hlist = calloc(1, sizeof(*hlist));
+ if (hlist == NULL)
+ return NULL;
+
+ if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) {
+ yyerror("Unknown hostname");
+ }
+ }
+
+ hbot = NULL;
+ htop = NULL;
+
+ for (a = hlist; a != NULL; a = a->al_next) {
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ break;
+
+ h->ipe_family = a->al_family;
+ h->ipe_addr = a->al_i6addr;
+ h->ipe_mask = a->al_i6mask;
+
+ if (hbot != NULL)
+ hbot->ipe_next = h;
+ else
+ htop = h;
+ hbot = h;
+ }
+
+ alist_free(hlist);
+
+ return htop;
+}
+
+
+static ip_pool_node_t *
+add_poolhosts(url)
+char *url;
+{
+ ip_pool_node_t *ptop, *pbot, *p;
+ alist_t *a, *hlist;
+
+ if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
+ hlist = load_url(url);
+ } else {
+ use_inet6 = 0;
+
+ hlist = calloc(1, sizeof(*hlist));
+ if (hlist == NULL)
+ return NULL;
+
+ if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) {
+ yyerror("Unknown hostname");
+ }
+ }
+
+ pbot = NULL;
+ ptop = NULL;
+
+ for (a = hlist; a != NULL; a = a->al_next) {
+ p = calloc(1, sizeof(*p));
+ if (p == NULL)
+ break;
+ p->ipn_mask.adf_addr = a->al_i6mask;
+
+ if (a->al_family == AF_INET) {
+ p->ipn_addr.adf_family = AF_INET;
+#ifdef USE_INET6
+ } else if (a->al_family == AF_INET6) {
+ p->ipn_addr.adf_family = AF_INET6;
+#endif
+ }
+ setadflen(&p->ipn_addr);
+ p->ipn_addr.adf_addr = a->al_i6addr;
+ p->ipn_info = a->al_not;
+ p->ipn_mask.adf_len = p->ipn_addr.adf_len;
+
+ if (pbot != NULL)
+ pbot->ipn_next = p;
+ else
+ ptop = p;
+ pbot = p;
+ }
+
+ alist_free(hlist);
+
+ return ptop;
+}
+
+
+ip_pool_node_t *
+read_whoisfile(file)
+ char *file;
+{
+ ip_pool_node_t *ntop, *ipn, node, *last;
+ char line[1024];
+ FILE *fp;
+
+ fp = fopen(file, "r");
+ if (fp == NULL)
+ return NULL;
+
+ last = NULL;
+ ntop = NULL;
+ while (fgets(line, sizeof(line) - 1, fp) != NULL) {
+ line[sizeof(line) - 1] = '\0';
+
+ if (parsewhoisline(line, &node.ipn_addr, &node.ipn_mask))
+ continue;
+ ipn = calloc(1, sizeof(*ipn));
+ if (ipn == NULL)
+ continue;
+ ipn->ipn_addr = node.ipn_addr;
+ ipn->ipn_mask = node.ipn_mask;
+ if (last == NULL)
+ ntop = ipn;
+ else
+ last->ipn_next = ipn;
+ last = ipn;
+ }
+ fclose(fp);
+ return ntop;
+}
+
+
+static void
+setadflen(afp)
+ addrfamily_t *afp;
+{
+ afp->adf_len = offsetof(addrfamily_t, adf_addr);
+ switch (afp->adf_family)
+ {
+ case AF_INET :
+ afp->adf_len += sizeof(struct in_addr);
+ break;
+#ifdef USE_INET6
+ case AF_INET6 :
+ afp->adf_len += sizeof(struct in6_addr);
+ break;
+#endif
+ default :
+ break;
+ }
+}
diff --git a/contrib/ipfilter/tools/ipscan_y.y b/contrib/ipfilter/tools/ipscan_y.y
new file mode 100644
index 0000000..d323f05
--- /dev/null
+++ b/contrib/ipfilter/tools/ipscan_y.y
@@ -0,0 +1,572 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+%{
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "opts.h"
+#include "kmem.h"
+#include "ipscan_l.h"
+#include "netinet/ip_scan.h"
+#include <ctype.h>
+
+#define YYDEBUG 1
+
+extern char *optarg;
+extern void yyerror __P((char *));
+extern int yyparse __P((void));
+extern int yylex __P((void));
+extern int yydebug;
+extern FILE *yyin;
+extern int yylineNum;
+extern void printbuf __P((char *, int, int));
+
+
+void printent __P((ipscan_t *));
+void showlist __P((void));
+int getportnum __P((char *));
+struct in_addr gethostip __P((char *));
+struct in_addr combine __P((int, int, int, int));
+char **makepair __P((char *, char *));
+void addtag __P((char *, char **, char **, struct action *));
+int cram __P((char *, char *));
+void usage __P((char *));
+int main __P((int, char **));
+
+int opts = 0;
+int fd = -1;
+
+
+%}
+
+%union {
+ char *str;
+ char **astr;
+ u_32_t num;
+ struct in_addr ipa;
+ struct action act;
+ union i6addr ip6;
+}
+
+%type <str> tag
+%type <act> action redirect result
+%type <ipa> ipaddr
+%type <num> portnum
+%type <astr> matchup onehalf twohalves
+
+%token <num> YY_NUMBER YY_HEX
+%token <str> YY_STR
+%token YY_COMMENT
+%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
+%token YY_RANGE_OUT YY_RANGE_IN
+%token <ip6> YY_IPV6
+%token IPSL_START IPSL_STARTGROUP IPSL_CONTENT
+
+%token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE
+
+%%
+file: line ';'
+ | assign ';'
+ | file line ';'
+ | file assign ';'
+ | YY_COMMENT
+ ;
+
+line: IPSL_START dline
+ | IPSL_STARTGROUP gline
+ | IPSL_CONTENT oline
+ ;
+
+dline: cline { resetlexer(); }
+ | sline { resetlexer(); }
+ | csline { resetlexer(); }
+ ;
+
+gline: YY_STR ':' glist '=' action
+ ;
+
+oline: cline
+ | sline
+ | csline
+ ;
+
+assign: YY_STR assigning YY_STR
+ { set_variable($1, $3);
+ resetlexer();
+ free($1);
+ free($3);
+ yyvarnext = 0;
+ }
+ ;
+
+assigning:
+ '=' { yyvarnext = 1; }
+ ;
+
+cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); }
+ ;
+
+sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); }
+ ;
+
+csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); }
+ ;
+
+glist: YY_STR
+ | glist ',' YY_STR
+ ;
+
+tag: YY_STR { $$ = $1; }
+ ;
+
+matchup:
+ onehalf { $$ = $1; }
+ | twohalves { $$ = $1; }
+ ;
+
+action: result { $$.act_val = $1.act_val;
+ $$.act_ip = $1.act_ip;
+ $$.act_port = $1.act_port; }
+ | result IPSL_ELSE result { $$.act_val = $1.act_val;
+ $$.act_else = $3.act_val;
+ if ($1.act_val == IPSL_REDIRECT) {
+ $$.act_ip = $1.act_ip;
+ $$.act_port = $1.act_port;
+ }
+ if ($3.act_val == IPSL_REDIRECT) {
+ $$.act_eip = $3.act_eip;
+ $$.act_eport = $3.act_eport;
+ }
+ }
+
+result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; }
+ | IPSL_TRACK { $$.act_val = IPSL_TRACK; }
+ | redirect { $$.act_val = IPSL_REDIRECT;
+ $$.act_ip = $1.act_ip;
+ $$.act_port = $1.act_port; }
+ ;
+
+onehalf:
+ '(' YY_STR ')' { $$ = makepair($2, NULL); }
+ ;
+
+twohalves:
+ '(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); }
+ ;
+
+redirect:
+ IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3;
+ $$.act_port = 0; }
+ | IPSL_REDIRECT '(' ipaddr ',' portnum ')'
+ { $$.act_ip = $3;
+ $$.act_port = $5; }
+ ;
+
+
+ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
+ { $$ = combine($1,$3,$5,$7); }
+ | YY_STR { $$ = gethostip($1);
+ free($1);
+ }
+ ;
+
+portnum:
+ YY_NUMBER { $$ = htons($1); }
+ | YY_STR { $$ = getportnum($1);
+ free($1);
+ }
+ ;
+
+%%
+
+
+static struct wordtab yywords[] = {
+ { "close", IPSL_CLOSE },
+ { "content", IPSL_CONTENT },
+ { "else", IPSL_ELSE },
+ { "start-group", IPSL_STARTGROUP },
+ { "redirect", IPSL_REDIRECT },
+ { "start", IPSL_START },
+ { "track", IPSL_TRACK },
+ { NULL, 0 }
+};
+
+
+int cram(dst, src)
+char *dst;
+char *src;
+{
+ char c, *s, *t, *u;
+ int i, j, k;
+
+ c = *src;
+ s = src + 1;
+ t = strchr(s, c);
+ *t = '\0';
+ for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) {
+ c = *s++;
+ if (c == '\\') {
+ if (s >= t)
+ break;
+ j = k = 0;
+ do {
+ c = *s++;
+ if (j && (!ISDIGIT(c) || (c > '7') ||
+ (k >= 248))) {
+ *u++ = k, i++;
+ j = k = 0;
+ s--;
+ break;
+ }
+ i++;
+
+ if (ISALPHA(c) || (c > '7')) {
+ switch (c)
+ {
+ case 'n' :
+ *u++ = '\n';
+ break;
+ case 'r' :
+ *u++ = '\r';
+ break;
+ case 't' :
+ *u++ = '\t';
+ break;
+ default :
+ *u++ = c;
+ break;
+ }
+ } else if (ISDIGIT(c)) {
+ j = 1;
+ k <<= 3;
+ k |= (c - '0');
+ i--;
+ } else
+ *u++ = c;
+ } while ((i <= ISC_TLEN) && (s <= t) && (j > 0));
+ } else
+ *u++ = c, i++;
+ }
+ return i;
+}
+
+
+void printent(isc)
+ipscan_t *isc;
+{
+ char buf[ISC_TLEN+1];
+ u_char *u;
+ int i, j;
+
+ buf[ISC_TLEN] = '\0';
+ bcopy(isc->ipsc_ctxt, buf, ISC_TLEN);
+ printf("%s : (\"", isc->ipsc_tag);
+ printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0);
+
+ bcopy(isc->ipsc_cmsk, buf, ISC_TLEN);
+ printf("\", \"%s\"), (\"", buf);
+
+ printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0);
+
+ bcopy(isc->ipsc_smsk, buf, ISC_TLEN);
+ printf("\", \"%s\") = ", buf);
+
+ switch (isc->ipsc_action)
+ {
+ case ISC_A_TRACK :
+ printf("track");
+ break;
+ case ISC_A_REDIRECT :
+ printf("redirect");
+ printf("(%s", inet_ntoa(isc->ipsc_ip));
+ if (isc->ipsc_port)
+ printf(",%d", isc->ipsc_port);
+ printf(")");
+ break;
+ case ISC_A_CLOSE :
+ printf("close");
+ break;
+ default :
+ break;
+ }
+
+ if (isc->ipsc_else != ISC_A_NONE) {
+ printf(" else ");
+ switch (isc->ipsc_else)
+ {
+ case ISC_A_TRACK :
+ printf("track");
+ break;
+ case ISC_A_REDIRECT :
+ printf("redirect");
+ printf("(%s", inet_ntoa(isc->ipsc_eip));
+ if (isc->ipsc_eport)
+ printf(",%d", isc->ipsc_eport);
+ printf(")");
+ break;
+ case ISC_A_CLOSE :
+ printf("close");
+ break;
+ default :
+ break;
+ }
+ }
+ printf("\n");
+
+ if (opts & OPT_DEBUG) {
+ for (u = (u_char *)isc, i = sizeof(*isc); i; ) {
+ printf("#");
+ for (j = 32; (j > 0) && (i > 0); j--, i--)
+ printf("%s%02x", (j & 7) ? "" : " ", *u++);
+ printf("\n");
+ }
+ }
+ if (opts & OPT_VERBOSE) {
+ printf("# hits %d active %d fref %d sref %d\n",
+ isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref,
+ isc->ipsc_sref);
+ }
+}
+
+
+void addtag(tstr, cp, sp, act)
+char *tstr;
+char **cp, **sp;
+struct action *act;
+{
+ ipscan_t isc, *iscp;
+
+ bzero((char *)&isc, sizeof(isc));
+
+ strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag));
+ isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0';
+
+ if (cp) {
+ isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]);
+ if (cp[1]) {
+ if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) {
+ fprintf(stderr,
+ "client text/mask strings different length\n");
+ return;
+ }
+ }
+ }
+
+ if (sp) {
+ isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]);
+ if (sp[1]) {
+ if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) {
+ fprintf(stderr,
+ "server text/mask strings different length\n");
+ return;
+ }
+ }
+ }
+
+ if (act->act_val == IPSL_CLOSE) {
+ isc.ipsc_action = ISC_A_CLOSE;
+ } else if (act->act_val == IPSL_TRACK) {
+ isc.ipsc_action = ISC_A_TRACK;
+ } else if (act->act_val == IPSL_REDIRECT) {
+ isc.ipsc_action = ISC_A_REDIRECT;
+ isc.ipsc_ip = act->act_ip;
+ isc.ipsc_port = act->act_port;
+ fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
+ }
+
+ if (act->act_else == IPSL_CLOSE) {
+ isc.ipsc_else = ISC_A_CLOSE;
+ } else if (act->act_else == IPSL_TRACK) {
+ isc.ipsc_else = ISC_A_TRACK;
+ } else if (act->act_else == IPSL_REDIRECT) {
+ isc.ipsc_else = ISC_A_REDIRECT;
+ isc.ipsc_eip = act->act_eip;
+ isc.ipsc_eport = act->act_eport;
+ fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1);
+ }
+
+ if (!(opts & OPT_DONOTHING)) {
+ iscp = &isc;
+ if (opts & OPT_REMOVE) {
+ if (ioctl(fd, SIOCRMSCA, &iscp) == -1)
+ perror("SIOCADSCA");
+ } else {
+ if (ioctl(fd, SIOCADSCA, &iscp) == -1)
+ perror("SIOCADSCA");
+ }
+ }
+
+ if (opts & OPT_VERBOSE)
+ printent(&isc);
+}
+
+
+char **makepair(s1, s2)
+char *s1, *s2;
+{
+ char **a;
+
+ a = malloc(sizeof(char *) * 2);
+ a[0] = s1;
+ a[1] = s2;
+ return a;
+}
+
+
+struct in_addr combine(a1, a2, a3, a4)
+int a1, a2, a3, a4;
+{
+ struct in_addr in;
+
+ a1 &= 0xff;
+ in.s_addr = a1 << 24;
+ a2 &= 0xff;
+ in.s_addr |= (a2 << 16);
+ a3 &= 0xff;
+ in.s_addr |= (a3 << 8);
+ a4 &= 0xff;
+ in.s_addr |= a4;
+ in.s_addr = htonl(in.s_addr);
+ return in;
+}
+
+
+struct in_addr gethostip(host)
+char *host;
+{
+ struct hostent *hp;
+ struct in_addr in;
+
+ in.s_addr = 0;
+
+ hp = gethostbyname(host);
+ if (!hp)
+ return in;
+ bcopy(hp->h_addr, (char *)&in, sizeof(in));
+ return in;
+}
+
+
+int getportnum(port)
+char *port;
+{
+ struct servent *s;
+
+ s = getservbyname(port, "tcp");
+ if (s == NULL)
+ return -1;
+ return s->s_port;
+}
+
+
+void showlist()
+{
+ ipscanstat_t ipsc, *ipscp = &ipsc;
+ ipscan_t isc;
+
+ if (ioctl(fd, SIOCGSCST, &ipscp) == -1)
+ perror("ioctl(SIOCGSCST)");
+ else if (opts & OPT_SHOWLIST) {
+ while (ipsc.iscs_list != NULL) {
+ if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list,
+ sizeof(isc)) == -1) {
+ perror("kmemcpy");
+ break;
+ } else {
+ printent(&isc);
+ ipsc.iscs_list = isc.ipsc_next;
+ }
+ }
+ } else {
+ printf("scan entries loaded\t%d\n", ipsc.iscs_entries);
+ printf("scan entries matches\t%ld\n", ipsc.iscs_acted);
+ printf("negative matches\t%ld\n", ipsc.iscs_else);
+ }
+}
+
+
+void usage(prog)
+char *prog;
+{
+ fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog);
+ fprintf(stderr, "\t%s [-dlv]\n", prog);
+ exit(1);
+}
+
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ FILE *fp = NULL;
+ int c;
+
+ (void) yysettab(yywords);
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ while ((c = getopt(argc, argv, "df:lnrsv")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ yydebug++;
+ break;
+ case 'f' :
+ if (!strcmp(optarg, "-"))
+ fp = stdin;
+ else {
+ fp = fopen(optarg, "r");
+ if (!fp) {
+ perror("open");
+ exit(1);
+ }
+ }
+ yyin = fp;
+ break;
+ case 'l' :
+ opts |= OPT_SHOWLIST;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING;
+ break;
+ case 'r' :
+ opts |= OPT_REMOVE;
+ break;
+ case 's' :
+ opts |= OPT_STAT;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (!(opts & OPT_DONOTHING)) {
+ fd = open(IPL_SCAN, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPL_SCAN)");
+ exit(1);
+ }
+ }
+
+ if (fp != NULL) {
+ yylineNum = 1;
+
+ while (!feof(fp))
+ yyparse();
+ fclose(fp);
+ exit(0);
+ }
+
+ if (opts & (OPT_SHOWLIST|OPT_STAT)) {
+ showlist();
+ exit(0);
+ }
+ exit(1);
+}
diff --git a/contrib/ipfilter/tools/ipsyncm.c b/contrib/ipfilter/tools/ipsyncm.c
new file mode 100644
index 0000000..41513fa
--- /dev/null
+++ b/contrib/ipfilter/tools/ipsyncm.c
@@ -0,0 +1,256 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_sync.h"
+
+
+int main __P((int, char *[]));
+void usage __P((const char *));
+
+int terminate = 0;
+
+void usage(const char *progname) {
+ fprintf(stderr, "Usage: %s <destination IP> <destination port>\n", progname);
+}
+
+#if 0
+static void handleterm(int sig)
+{
+ terminate = sig;
+}
+#endif
+
+
+/* should be large enough to hold header + any datatype */
+#define BUFFERLEN 1400
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin;
+ char buff[BUFFERLEN];
+ synclogent_t *sl;
+ syncupdent_t *su;
+ int nfd = -1, lfd = -1, n1, n2, n3, len;
+ int inbuf;
+ u_32_t magic;
+ synchdr_t *sh;
+ char *progname;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) {
+ progname++;
+ } else {
+ progname = argv[0];
+ }
+
+
+ if (argc < 2) {
+ usage(progname);
+ exit(1);
+ }
+
+#if 0
+ signal(SIGHUP, handleterm);
+ signal(SIGINT, handleterm);
+ signal(SIGTERM, handleterm);
+#endif
+
+ openlog(progname, LOG_PID, LOG_SECURITY);
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(argv[1]);
+ if (argc > 2)
+ sin.sin_port = htons(atoi(argv[2]));
+ else
+ sin.sin_port = htons(43434);
+
+ while (1) {
+
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ lfd = open(IPSYNC_NAME, O_RDONLY);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
+ goto tryagain;
+ }
+
+ nfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (nfd == -1) {
+ syslog(LOG_ERR, "Socket :%m");
+ goto tryagain;
+ }
+
+ if (connect(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ syslog(LOG_ERR, "Connect: %m");
+ goto tryagain;
+ }
+
+ syslog(LOG_INFO, "Sending data to %s",
+ inet_ntoa(sin.sin_addr));
+
+ inbuf = 0;
+ while (1) {
+
+ n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf);
+
+ printf("header : %d bytes read (header = %d bytes)\n",
+ n1, (int) sizeof(*sh));
+
+ if (n1 < 0) {
+ syslog(LOG_ERR, "Read error (header): %m");
+ goto tryagain;
+ }
+
+ if (n1 == 0) {
+ /* XXX can this happen??? */
+ syslog(LOG_ERR,
+ "Read error (header) : No data");
+ sleep(1);
+ continue;
+ }
+
+ inbuf += n1;
+
+moreinbuf:
+ if (inbuf < sizeof(*sh)) {
+ continue; /* need more data */
+ }
+
+ sh = (synchdr_t *)buff;
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR,
+ "Invalid header magic %x", magic);
+ goto tryagain;
+ }
+
+#define IPSYNC_DEBUG
+#ifdef IPSYNC_DEBUG
+ printf("v:%d p:%d len:%d magic:%x", sh->sm_v,
+ sh->sm_p, len, magic);
+
+ if (sh->sm_cmd == SMC_CREATE)
+ printf(" cmd:CREATE");
+ else if (sh->sm_cmd == SMC_UPDATE)
+ printf(" cmd:UPDATE");
+ else
+ printf(" cmd:Unknown(%d)", sh->sm_cmd);
+
+ if (sh->sm_table == SMC_NAT)
+ printf(" table:NAT");
+ else if (sh->sm_table == SMC_STATE)
+ printf(" table:STATE");
+ else
+ printf(" table:Unknown(%d)", sh->sm_table);
+
+ printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num));
+#endif
+
+ if (inbuf < sizeof(*sh) + len) {
+ continue; /* need more data */
+ goto tryagain;
+ }
+
+#ifdef IPSYNC_DEBUG
+ if (sh->sm_cmd == SMC_CREATE) {
+ sl = (synclogent_t *)buff;
+
+ } else if (sh->sm_cmd == SMC_UPDATE) {
+ su = (syncupdent_t *)buff;
+ if (sh->sm_p == IPPROTO_TCP) {
+ printf(" TCP Update: age %lu state %d/%d\n",
+ su->sup_tcp.stu_age,
+ su->sup_tcp.stu_state[0],
+ su->sup_tcp.stu_state[1]);
+ }
+ } else {
+ printf("Unknown command\n");
+ }
+#endif
+
+ n2 = sizeof(*sh) + len;
+ n3 = write(nfd, buff, n2);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "Write error: %m");
+ goto tryagain;
+ }
+
+
+ if (n3 != n2) {
+ syslog(LOG_ERR, "Incomplete write (%d/%d)",
+ n3, n2);
+ goto tryagain;
+ }
+
+ /* signal received? */
+ if (terminate)
+ break;
+
+ /* move buffer to the front,we might need to make
+ * this more efficient, by using a rolling pointer
+ * over the buffer and only copying it, when
+ * we are reaching the end
+ */
+ inbuf -= n2;
+ if (inbuf) {
+ bcopy(buff+n2, buff, inbuf);
+ printf("More data in buffer\n");
+ goto moreinbuf;
+ }
+ }
+
+ if (terminate)
+ break;
+tryagain:
+ sleep(1);
+ }
+
+
+ /* terminate */
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ syslog(LOG_ERR, "signal %d received, exiting...", terminate);
+
+ exit(1);
+}
+
diff --git a/contrib/ipfilter/tools/ipsyncs.c b/contrib/ipfilter/tools/ipsyncs.c
new file mode 100644
index 0000000..43692cd
--- /dev/null
+++ b/contrib/ipfilter/tools/ipsyncs.c
@@ -0,0 +1,274 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if !defined(lint)
+static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
+static const char rcsid[] = "@(#)$Id$";
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_sync.h"
+
+int main __P((int, char *[]));
+void usage __P((const char *progname));
+
+int terminate = 0;
+
+void usage(const char *progname) {
+ fprintf(stderr,
+ "Usage: %s <destination IP> <destination port> [remote IP]\n",
+ progname);
+}
+
+#if 0
+static void handleterm(int sig)
+{
+ terminate = sig;
+}
+#endif
+
+#define BUFFERLEN 1400
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int nfd = -1 , lfd = -1;
+ int n1, n2, n3, magic, len, inbuf;
+ struct sockaddr_in sin;
+ struct sockaddr_in in;
+ char buff[BUFFERLEN];
+ synclogent_t *sl;
+ syncupdent_t *su;
+ synchdr_t *sh;
+ char *progname;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) {
+ progname++;
+ } else {
+ progname = argv[0];
+ }
+
+ if (argc < 2) {
+ usage(progname);
+ exit(1);
+ }
+
+#if 0
+ signal(SIGHUP, handleterm);
+ signal(SIGINT, handleterm);
+ signal(SIGTERM, handleterm);
+#endif
+
+ openlog(progname, LOG_PID, LOG_SECURITY);
+
+ lfd = open(IPSYNC_NAME, O_WRONLY);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
+ exit(1);
+ }
+
+ bzero((char *)&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ if (argc > 1)
+ sin.sin_addr.s_addr = inet_addr(argv[1]);
+ if (argc > 2)
+ sin.sin_port = htons(atoi(argv[2]));
+ else
+ sin.sin_port = htons(43434);
+ if (argc > 3)
+ in.sin_addr.s_addr = inet_addr(argv[3]);
+ else
+ in.sin_addr.s_addr = 0;
+ in.sin_port = 0;
+
+ while(1) {
+
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ lfd = open(IPSYNC_NAME, O_WRONLY);
+ if (lfd == -1) {
+ syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME);
+ goto tryagain;
+ }
+
+ nfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (nfd == -1) {
+ syslog(LOG_ERR, "Socket :%m");
+ goto tryagain;
+ }
+
+ n1 = 1;
+ setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1));
+
+ if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ syslog(LOG_ERR, "Bind: %m");
+ goto tryagain;
+ }
+
+ syslog(LOG_INFO, "Listening to %s", inet_ntoa(sin.sin_addr));
+
+ inbuf = 0;
+ while (1) {
+
+
+ /*
+ * XXX currently we do not check the source address
+ * of a datagram, this can be a security risk
+ */
+ n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf);
+
+ printf("header : %d bytes read (header = %d bytes)\n",
+ n1, (int) sizeof(*sh));
+
+ if (n1 < 0) {
+ syslog(LOG_ERR, "Read error (header): %m");
+ goto tryagain;
+ }
+
+ if (n1 == 0) {
+ /* XXX can this happen??? */
+ syslog(LOG_ERR,
+ "Read error (header) : No data");
+ sleep(1);
+ continue;
+ }
+
+ inbuf += n1;
+
+moreinbuf:
+ if (inbuf < sizeof(*sh)) {
+ continue; /* need more data */
+ }
+
+ sh = (synchdr_t *)buff;
+ len = ntohl(sh->sm_len);
+ magic = ntohl(sh->sm_magic);
+
+ if (magic != SYNHDRMAGIC) {
+ syslog(LOG_ERR, "Invalid header magic %x",
+ magic);
+ goto tryagain;
+ }
+
+#define IPSYNC_DEBUG
+#ifdef IPSYNC_DEBUG
+ printf("v:%d p:%d len:%d magic:%x", sh->sm_v,
+ sh->sm_p, len, magic);
+
+ if (sh->sm_cmd == SMC_CREATE)
+ printf(" cmd:CREATE");
+ else if (sh->sm_cmd == SMC_UPDATE)
+ printf(" cmd:UPDATE");
+ else
+ printf(" cmd:Unknown(%d)", sh->sm_cmd);
+
+ if (sh->sm_table == SMC_NAT)
+ printf(" table:NAT");
+ else if (sh->sm_table == SMC_STATE)
+ printf(" table:STATE");
+ else
+ printf(" table:Unknown(%d)", sh->sm_table);
+
+ printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num));
+#endif
+
+ if (inbuf < sizeof(*sh) + len) {
+ continue; /* need more data */
+ goto tryagain;
+ }
+
+#ifdef IPSYNC_DEBUG
+ if (sh->sm_cmd == SMC_CREATE) {
+ sl = (synclogent_t *)buff;
+
+ } else if (sh->sm_cmd == SMC_UPDATE) {
+ su = (syncupdent_t *)buff;
+ if (sh->sm_p == IPPROTO_TCP) {
+ printf(" TCP Update: age %lu state %d/%d\n",
+ su->sup_tcp.stu_age,
+ su->sup_tcp.stu_state[0],
+ su->sup_tcp.stu_state[1]);
+ }
+ } else {
+ printf("Unknown command\n");
+ }
+#endif
+
+ n2 = sizeof(*sh) + len;
+ n3 = write(lfd, buff, n2);
+ if (n3 <= 0) {
+ syslog(LOG_ERR, "%s: Write error: %m",
+ IPSYNC_NAME);
+ goto tryagain;
+ }
+
+
+ if (n3 != n2) {
+ syslog(LOG_ERR, "%s: Incomplete write (%d/%d)",
+ IPSYNC_NAME, n3, n2);
+ goto tryagain;
+ }
+
+ /* signal received? */
+ if (terminate)
+ break;
+
+ /* move buffer to the front,we might need to make
+ * this more efficient, by using a rolling pointer
+ * over the buffer and only copying it, when
+ * we are reaching the end
+ */
+ inbuf -= n2;
+ if (inbuf) {
+ bcopy(buff+n2, buff, inbuf);
+ printf("More data in buffer\n");
+ goto moreinbuf;
+ }
+ }
+
+ if (terminate)
+ break;
+tryagain:
+ sleep(1);
+ }
+
+
+ /* terminate */
+ if (lfd != -1)
+ close(lfd);
+ if (nfd != -1)
+ close(nfd);
+
+ syslog(LOG_ERR, "signal %d received, exiting...", terminate);
+
+ exit(1);
+}
diff --git a/contrib/ipfilter/tools/lex_var.h b/contrib/ipfilter/tools/lex_var.h
new file mode 100644
index 0000000..eb59f58
--- /dev/null
+++ b/contrib/ipfilter/tools/lex_var.h
@@ -0,0 +1,60 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+extern long string_start;
+extern long string_end;
+extern char *string_val;
+extern long pos;
+
+#define YY_INPUT(buf, result, max_size) \
+ if (pos >= string_start && pos <= string_end) { \
+ buf[0] = string_val[pos - string_start]; \
+ pos++; \
+ result = 1; \
+ } else if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < 1 && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ pos++; \
+ } \
+ else if ( ((result = fread( buf, 1, 1, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+
+#ifdef input
+# undef input
+# define input() (((pos >= string_start) && (pos < string_end)) ? \
+ yysptr = yysbuf, string_val[pos++ - string_start] : \
+ ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \
+ getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \
+ yytchar) == EOF ? (pos++, 0) : (pos++, yytchar))
+#endif
+
+#ifdef lex_input
+# undef lex_input
+# define lex_input() (((pos >= string_start) && (pos < string_end)) ? \
+ yysptr = yysbuf, string_val[pos++ - string_start] : \
+ ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \
+ getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \
+ yytchar) == EOF ? (pos++, 0) : (pos++, yytchar))
+#endif
+
+#ifdef unput
+# undef unput
+# define unput(c) { if (pos > 0) pos--; \
+ yytchar = (c); if (yytchar == '\n') yylineno--; \
+ *yysptr++ = yytchar; }
+#endif
+
diff --git a/contrib/ipfilter/tools/lexer.c b/contrib/ipfilter/tools/lexer.c
new file mode 100644
index 0000000..41b7896
--- /dev/null
+++ b/contrib/ipfilter/tools/lexer.c
@@ -0,0 +1,735 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include <ctype.h>
+#include "ipf.h"
+#ifdef IPFILTER_SCAN
+# include "netinet/ip_scan.h"
+#endif
+#include <sys/ioctl.h>
+#include <syslog.h>
+#ifdef TEST_LEXER
+# define NO_YACC
+union {
+ int num;
+ char *str;
+ struct in_addr ipa;
+ i6addr_t ip6;
+} yylval;
+#endif
+#include "lexer.h"
+#include "y.tab.h"
+
+FILE *yyin;
+
+#define ishex(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \
+ ((c) >= 'A' && (c) <= 'F'))
+#define TOOLONG -3
+
+extern int string_start;
+extern int string_end;
+extern char *string_val;
+extern int pos;
+extern int yydebug;
+
+char *yystr = NULL;
+int yytext[YYBUFSIZ+1];
+char yychars[YYBUFSIZ+1];
+int yylineNum = 1;
+int yypos = 0;
+int yylast = -1;
+int yydictfixed = 0;
+int yyexpectaddr = 0;
+int yybreakondot = 0;
+int yyvarnext = 0;
+int yytokentype = 0;
+wordtab_t *yywordtab = NULL;
+int yysavedepth = 0;
+wordtab_t *yysavewords[30];
+
+
+static wordtab_t *yyfindkey __P((char *));
+static int yygetc __P((int));
+static void yyunputc __P((int));
+static int yyswallow __P((int));
+static char *yytexttostr __P((int, int));
+static void yystrtotext __P((char *));
+static char *yytexttochar __P((void));
+
+static int yygetc(docont)
+ int docont;
+{
+ int c;
+
+ if (yypos < yylast) {
+ c = yytext[yypos++];
+ if (c == '\n')
+ yylineNum++;
+ return c;
+ }
+
+ if (yypos == YYBUFSIZ)
+ return TOOLONG;
+
+ if (pos >= string_start && pos <= string_end) {
+ c = string_val[pos - string_start];
+ yypos++;
+ } else {
+ c = fgetc(yyin);
+ if (docont && (c == '\\')) {
+ c = fgetc(yyin);
+ if (c == '\n') {
+ yylineNum++;
+ c = fgetc(yyin);
+ }
+ }
+ }
+ if (c == '\n')
+ yylineNum++;
+ yytext[yypos++] = c;
+ yylast = yypos;
+ yytext[yypos] = '\0';
+
+ return c;
+}
+
+
+static void yyunputc(c)
+ int c;
+{
+ if (c == '\n')
+ yylineNum--;
+ yytext[--yypos] = c;
+}
+
+
+static int yyswallow(last)
+ int last;
+{
+ int c;
+
+ while (((c = yygetc(0)) > '\0') && (c != last))
+ ;
+
+ if (c != EOF)
+ yyunputc(c);
+ if (c == last)
+ return 0;
+ return -1;
+}
+
+
+static char *yytexttochar()
+{
+ int i;
+
+ for (i = 0; i < yypos; i++)
+ yychars[i] = (char)(yytext[i] & 0xff);
+ yychars[i] = '\0';
+ return yychars;
+}
+
+
+static void yystrtotext(str)
+ char *str;
+{
+ int len;
+ char *s;
+
+ len = strlen(str);
+ if (len > YYBUFSIZ)
+ len = YYBUFSIZ;
+
+ for (s = str; *s != '\0' && len > 0; s++, len--)
+ yytext[yylast++] = *s;
+ yytext[yylast] = '\0';
+}
+
+
+static char *yytexttostr(offset, max)
+ int offset, max;
+{
+ char *str;
+ int i;
+
+ if ((yytext[offset] == '\'' || yytext[offset] == '"') &&
+ (yytext[offset] == yytext[offset + max - 1])) {
+ offset++;
+ max--;
+ }
+
+ if (max > yylast)
+ max = yylast;
+ str = malloc(max + 1);
+ if (str != NULL) {
+ for (i = offset; i < max; i++)
+ str[i - offset] = (char)(yytext[i] & 0xff);
+ str[i - offset] = '\0';
+ }
+ return str;
+}
+
+
+int yylex()
+{
+ static int prior = 0;
+ static int priornum = 0;
+ int c, n, isbuilding, rval, lnext, nokey = 0;
+ char *name;
+ int triedv6 = 0;
+
+ isbuilding = 0;
+ lnext = 0;
+ rval = 0;
+
+ if (yystr != NULL) {
+ free(yystr);
+ yystr = NULL;
+ }
+
+nextchar:
+ c = yygetc(0);
+ if (yydebug > 1)
+ printf("yygetc = (%x) %c [%*.*s]\n",
+ c, c, yypos, yypos, yytexttochar());
+
+ switch (c)
+ {
+ case '\n' :
+ lnext = 0;
+ nokey = 0;
+ case '\t' :
+ case '\r' :
+ case ' ' :
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ if (yylast > yypos) {
+ bcopy(yytext + yypos, yytext,
+ sizeof(yytext[0]) * (yylast - yypos + 1));
+ }
+ yylast -= yypos;
+ if (yyexpectaddr == 2)
+ yyexpectaddr = 0;
+ yypos = 0;
+ lnext = 0;
+ nokey = 0;
+ goto nextchar;
+
+ case '\\' :
+ if (lnext == 0) {
+ lnext = 1;
+ if (yylast == yypos) {
+ yylast--;
+ yypos--;
+ } else
+ yypos--;
+ if (yypos == 0)
+ nokey = 1;
+ goto nextchar;
+ }
+ break;
+ }
+
+ if (lnext == 1) {
+ lnext = 0;
+ if ((isbuilding == 0) && !ISALNUM(c)) {
+ prior = c;
+ return c;
+ }
+ goto nextchar;
+ }
+
+ switch (c)
+ {
+ case '#' :
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ yyswallow('\n');
+ rval = YY_COMMENT;
+ goto done;
+
+ case '$' :
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ n = yygetc(0);
+ if (n == '{') {
+ if (yyswallow('}') == -1) {
+ rval = -2;
+ goto done;
+ }
+ (void) yygetc(0);
+ } else {
+ if (!ISALPHA(n)) {
+ yyunputc(n);
+ break;
+ }
+ do {
+ n = yygetc(1);
+ } while (ISALPHA(n) || ISDIGIT(n) || n == '_');
+ yyunputc(n);
+ }
+
+ name = yytexttostr(1, yypos); /* skip $ */
+
+ if (name != NULL) {
+ string_val = get_variable(name, NULL, yylineNum);
+ free(name);
+ if (string_val != NULL) {
+ name = yytexttostr(yypos, yylast);
+ if (name != NULL) {
+ yypos = 0;
+ yylast = 0;
+ yystrtotext(string_val);
+ yystrtotext(name);
+ free(string_val);
+ free(name);
+ goto nextchar;
+ }
+ free(string_val);
+ }
+ }
+ break;
+
+ case '\'':
+ case '"' :
+ if (isbuilding == 1) {
+ goto done;
+ }
+ do {
+ n = yygetc(1);
+ if (n == EOF || n == TOOLONG) {
+ rval = -2;
+ goto done;
+ }
+ if (n == '\n') {
+ yyunputc(' ');
+ yypos++;
+ }
+ } while (n != c);
+ rval = YY_STR;
+ goto done;
+ /* NOTREACHED */
+
+ case EOF :
+ yylineNum = 1;
+ yypos = 0;
+ yylast = -1;
+ yyexpectaddr = 0;
+ yybreakondot = 0;
+ yyvarnext = 0;
+ yytokentype = 0;
+ if (yydebug)
+ fprintf(stderr, "reset at EOF\n");
+ prior = 0;
+ return 0;
+ }
+
+ if (strchr("=,/;{}()@", c) != NULL) {
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ rval = c;
+ goto done;
+ } else if (c == '.') {
+ if (isbuilding == 0) {
+ rval = c;
+ goto done;
+ }
+ if (yybreakondot != 0) {
+ yyunputc(c);
+ goto done;
+ }
+ }
+
+ switch (c)
+ {
+ case '-' :
+ n = yygetc(0);
+ if (n == '>') {
+ isbuilding = 1;
+ goto done;
+ }
+ yyunputc(n);
+ if (yyexpectaddr) {
+ if (isbuilding == 1)
+ yyunputc(c);
+ else
+ rval = '-';
+ goto done;
+ }
+ if (isbuilding == 1)
+ break;
+ rval = '-';
+ goto done;
+
+ case '!' :
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ n = yygetc(0);
+ if (n == '=') {
+ rval = YY_CMP_NE;
+ goto done;
+ }
+ yyunputc(n);
+ rval = '!';
+ goto done;
+
+ case '<' :
+ if (yyexpectaddr)
+ break;
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ n = yygetc(0);
+ if (n == '=') {
+ rval = YY_CMP_LE;
+ goto done;
+ }
+ if (n == '>') {
+ rval = YY_RANGE_OUT;
+ goto done;
+ }
+ yyunputc(n);
+ rval = YY_CMP_LT;
+ goto done;
+
+ case '>' :
+ if (yyexpectaddr)
+ break;
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ n = yygetc(0);
+ if (n == '=') {
+ rval = YY_CMP_GE;
+ goto done;
+ }
+ if (n == '<') {
+ rval = YY_RANGE_IN;
+ goto done;
+ }
+ yyunputc(n);
+ rval = YY_CMP_GT;
+ goto done;
+ }
+
+ /*
+ * Now for the reason this is here...IPv6 address parsing.
+ * The longest string we can expect is of this form:
+ * 0000:0000:0000:0000:0000:0000:000.000.000.000
+ * not:
+ * 0000:0000:0000:0000:0000:0000:0000:0000
+ */
+#ifdef USE_INET6
+ if (yyexpectaddr != 0 && isbuilding == 0 &&
+ (ishex(c) || isdigit(c) || c == ':')) {
+ char ipv6buf[45 + 1], *s, oc;
+ int start;
+
+buildipv6:
+ start = yypos;
+ s = ipv6buf;
+ oc = c;
+
+ if (prior == YY_NUMBER && c == ':') {
+ sprintf(s, "%d", priornum);
+ s += strlen(s);
+ }
+
+ /*
+ * Perhaps we should implement stricter controls on what we
+ * swallow up here, but surely it would just be duplicating
+ * the code in inet_pton() anyway.
+ */
+ do {
+ *s++ = c;
+ c = yygetc(1);
+ } while ((ishex(c) || c == ':' || c == '.') &&
+ (s - ipv6buf < 46));
+ yyunputc(c);
+ *s = '\0';
+
+ if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) {
+ rval = YY_IPV6;
+ yyexpectaddr = 0;
+ goto done;
+ }
+ yypos = start;
+ c = oc;
+ }
+#endif
+
+ if ((c == ':') && (rval != YY_IPV6) && (triedv6 == 0)) {
+#ifdef USE_INET6
+ yystr = yytexttostr(0, yypos - 1);
+ if (yystr != NULL) {
+ char *s;
+
+ for (s = yystr; *s && ishex(*s); s++)
+ ;
+ if (!*s && *yystr) {
+ isbuilding = 0;
+ c = *yystr;
+ free(yystr);
+ triedv6 = 1;
+ yypos = 1;
+ goto buildipv6;
+ }
+ free(yystr);
+ }
+#endif
+ if (isbuilding == 1) {
+ yyunputc(c);
+ goto done;
+ }
+ rval = ':';
+ goto done;
+ }
+
+ if (isbuilding == 0 && c == '0') {
+ n = yygetc(0);
+ if (n == 'x') {
+ do {
+ n = yygetc(1);
+ } while (ishex(n));
+ yyunputc(n);
+ rval = YY_HEX;
+ goto done;
+ }
+ yyunputc(n);
+ }
+
+ /*
+ * No negative numbers with leading - sign..
+ */
+ if (isbuilding == 0 && ISDIGIT(c)) {
+ do {
+ n = yygetc(1);
+ } while (ISDIGIT(n));
+ yyunputc(n);
+ rval = YY_NUMBER;
+ goto done;
+ }
+
+ isbuilding = 1;
+ goto nextchar;
+
+done:
+ yystr = yytexttostr(0, yypos);
+
+ if (yydebug)
+ printf("isbuilding %d yyvarnext %d nokey %d fixed %d addr %d\n",
+ isbuilding, yyvarnext, nokey, yydictfixed, yyexpectaddr);
+ if (isbuilding == 1) {
+ wordtab_t *w;
+
+ w = NULL;
+ isbuilding = 0;
+
+ if ((yyvarnext == 0) && (nokey == 0)) {
+ w = yyfindkey(yystr);
+ if (w == NULL && yywordtab != NULL && !yydictfixed) {
+ yyresetdict();
+ w = yyfindkey(yystr);
+ }
+ } else
+ yyvarnext = 0;
+ if (w != NULL)
+ rval = w->w_value;
+ else
+ rval = YY_STR;
+ }
+
+ if (rval == YY_STR) {
+ if (yysavedepth > 0 && !yydictfixed)
+ yyresetdict();
+ if (yyexpectaddr != 0)
+ yyexpectaddr = 0;
+ }
+
+ yytokentype = rval;
+
+ if (yydebug)
+ printf("lexed(%s) %d,%d,%d [%d,%d,%d] => %d @%d\n",
+ yystr, isbuilding, yyexpectaddr, yysavedepth,
+ string_start, string_end, pos, rval, yysavedepth);
+
+ switch (rval)
+ {
+ case YY_NUMBER :
+ sscanf(yystr, "%u", &yylval.num);
+ break;
+
+ case YY_HEX :
+ sscanf(yystr, "0x%x", (u_int *)&yylval.num);
+ break;
+
+ case YY_STR :
+ yylval.str = strdup(yystr);
+ break;
+
+ default :
+ break;
+ }
+
+ if (yylast > 0) {
+ bcopy(yytext + yypos, yytext,
+ sizeof(yytext[0]) * (yylast - yypos + 1));
+ yylast -= yypos;
+ yypos = 0;
+ }
+
+ if (rval == YY_NUMBER)
+ priornum = yylval.num;
+ prior = rval;
+ return rval;
+}
+
+
+static wordtab_t *yyfindkey(key)
+ char *key;
+{
+ wordtab_t *w;
+
+ if (yywordtab == NULL)
+ return NULL;
+
+ for (w = yywordtab; w->w_word != 0; w++)
+ if (strcasecmp(key, w->w_word) == 0)
+ return w;
+ return NULL;
+}
+
+
+char *yykeytostr(num)
+ int num;
+{
+ wordtab_t *w;
+
+ if (yywordtab == NULL)
+ return "<unknown>";
+
+ for (w = yywordtab; w->w_word; w++)
+ if (w->w_value == num)
+ return w->w_word;
+ return "<unknown>";
+}
+
+
+wordtab_t *yysettab(words)
+ wordtab_t *words;
+{
+ wordtab_t *save;
+
+ save = yywordtab;
+ yywordtab = words;
+ return save;
+}
+
+
+void yyerror(msg)
+ char *msg;
+{
+ char *txt, letter[2];
+ int freetxt = 0;
+
+ if (yytokentype < 256) {
+ letter[0] = yytokentype;
+ letter[1] = '\0';
+ txt = letter;
+ } else if (yytokentype == YY_STR || yytokentype == YY_HEX ||
+ yytokentype == YY_NUMBER) {
+ if (yystr == NULL) {
+ txt = yytexttostr(yypos, YYBUFSIZ);
+ freetxt = 1;
+ } else
+ txt = yystr;
+ } else {
+ txt = yykeytostr(yytokentype);
+ }
+ fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum);
+ if (freetxt == 1)
+ free(txt);
+ exit(1);
+}
+
+
+void yysetfixeddict(newdict)
+ wordtab_t *newdict;
+{
+ if (yydebug)
+ printf("yysetfixeddict(%lx)\n", (u_long)newdict);
+
+ if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) {
+ fprintf(stderr, "%d: at maximum dictionary depth\n",
+ yylineNum);
+ return;
+ }
+
+ yysavewords[yysavedepth++] = yysettab(newdict);
+ if (yydebug)
+ printf("yysavedepth++ => %d\n", yysavedepth);
+ yydictfixed = 1;
+}
+
+
+void yysetdict(newdict)
+ wordtab_t *newdict;
+{
+ if (yydebug)
+ printf("yysetdict(%lx)\n", (u_long)newdict);
+
+ if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) {
+ fprintf(stderr, "%d: at maximum dictionary depth\n",
+ yylineNum);
+ return;
+ }
+
+ yysavewords[yysavedepth++] = yysettab(newdict);
+ if (yydebug)
+ printf("yysavedepth++ => %d\n", yysavedepth);
+}
+
+void yyresetdict()
+{
+ if (yydebug)
+ printf("yyresetdict(%d)\n", yysavedepth);
+ if (yysavedepth > 0) {
+ yysettab(yysavewords[--yysavedepth]);
+ if (yydebug)
+ printf("yysavedepth-- => %d\n", yysavedepth);
+ }
+ yydictfixed = 0;
+}
+
+
+
+#ifdef TEST_LEXER
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int n;
+
+ yyin = stdin;
+
+ while ((n = yylex()) != 0)
+ printf("%d.n = %d [%s] %d %d\n",
+ yylineNum, n, yystr, yypos, yylast);
+}
+#endif
diff --git a/contrib/ipfilter/tools/lexer.h b/contrib/ipfilter/tools/lexer.h
new file mode 100644
index 0000000..cff24b4
--- /dev/null
+++ b/contrib/ipfilter/tools/lexer.h
@@ -0,0 +1,38 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+
+#ifdef NO_YACC
+#define YY_COMMENT 1000
+#define YY_CMP_NE 1001
+#define YY_CMP_LE 1002
+#define YY_RANGE_OUT 1003
+#define YY_CMP_GE 1004
+#define YY_RANGE_IN 1005
+#define YY_HEX 1006
+#define YY_NUMBER 1007
+#define YY_IPV6 1008
+#define YY_STR 1009
+#define YY_IPADDR 1010
+#endif
+
+#define YYBUFSIZ 8192
+
+extern wordtab_t *yysettab __P((wordtab_t *));
+extern void yysetdict __P((wordtab_t *));
+extern void yysetfixeddict __P((wordtab_t *));
+extern int yylex __P((void));
+extern void yyerror __P((char *));
+extern char *yykeytostr __P((int));
+extern void yyresetdict __P((void));
+
+extern FILE *yyin;
+extern int yylineNum;
+extern int yyexpectaddr;
+extern int yybreakondot;
+extern int yyvarnext;
+
diff --git a/tests/sys/kern/execve/Makefile b/tests/sys/kern/execve/Makefile
new file mode 100644
index 0000000..82c5d4b
--- /dev/null
+++ b/tests/sys/kern/execve/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sys/kern/execve
+
+BINDIR= ${TESTSDIR}
+
+MAN=
+
+ATF_TESTS_SH+= execve_test
+
+PROGS+= good_aout
+PROGS+= execve_helper
+
+LDFLAGS.goodaout+= -static
+
+CLEANFILES+= empty
+CLEANFILES+= sparse_aout
+CLEANFILES+= trunc_aout
+
+SCRIPTS+= bad_interp_len
+SCRIPTS+= dev_null_script
+SCRIPTS+= empty
+SCRIPTS+= good_script
+SCRIPTS+= non_exist_shell
+SCRIPTS+= script_arg
+SCRIPTS+= script_arg_nospace
+SCRIPTS+= sparse_aout
+SCRIPTS+= trunc_aout
+
+empty:
+ @touch $@
+
+sparse_aout:
+ @truncate -s 20480 $@
+
+trunc_aout:
+ @truncate -s 16 $@
+
+.include <bsd.test.mk>
diff --git a/tests/sys/kern/execve/bad_interp_len b/tests/sys/kern/execve/bad_interp_len
new file mode 100644
index 0000000..96c049f
--- /dev/null
+++ b/tests/sys/kern/execve/bad_interp_len
@@ -0,0 +1,4 @@
+#! 456789012345678 0123456789012345 789012345678 012345678901234 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/dev_null_script b/tests/sys/kern/execve/dev_null_script
new file mode 100644
index 0000000..73b1020
--- /dev/null
+++ b/tests/sys/kern/execve/dev_null_script
@@ -0,0 +1,4 @@
+#! /dev/null
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/execve_helper.c b/tests/sys/kern/execve/execve_helper.c
new file mode 100644
index 0000000..164a8f3
--- /dev/null
+++ b/tests/sys/kern/execve/execve_helper.c
@@ -0,0 +1,54 @@
+/* $NetBSD: doexec.c,v 1.8 2003/07/26 19:38:48 salo Exp $ */
+
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * 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 for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char **argv)
+{
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <progname>\n", argv[0]);
+ exit(2);
+ }
+
+ execve(argv[1], &argv[1], NULL);
+ err(1, "");
+}
diff --git a/tests/sys/kern/execve/execve_test.sh b/tests/sys/kern/execve/execve_test.sh
new file mode 100644
index 0000000..ef803a1
--- /dev/null
+++ b/tests/sys/kern/execve/execve_test.sh
@@ -0,0 +1,115 @@
+
+bad_interp_len_head()
+{
+ atf_set "descr" "Bad interpreter length"
+}
+bad_interp_len_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper bad_interp_len"
+}
+
+empty_head()
+{
+ atf_set "descr" "Empty file"
+}
+empty_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper empty"
+}
+
+good_aout_head()
+{
+ atf_set "descr" "Good a.out"
+}
+good_aout_body()
+{
+ atf_check -s exit:0 -e empty -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper ./good_aout"
+}
+
+good_script_head()
+{
+ atf_set "descr" "Good script"
+}
+good_script_body()
+{
+ atf_check -s exit:0 -e empty -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper good_script"
+}
+
+non_exist_head()
+{
+ atf_set "descr" "Non-existent file"
+}
+non_exist_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper non_exist"
+}
+
+non_exist_shell_head()
+{
+ atf_set "descr" "Non-existent shell"
+}
+non_exist_shell_body()
+{
+ atf_check -s exit:1 -e 'match:No such file or directory' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper non_exist_shell"
+}
+
+script_arg_head()
+{
+ atf_set "descr" "-x in the shebang"
+}
+script_arg_body()
+{
+ atf_check -s exit:0 -e 'match:\+ echo succeeded' -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper script_arg"
+}
+
+script_arg_nospace_head()
+{
+ atf_set "descr" '-x in the shebang; no space between #! and /bin/sh'
+}
+script_arg_nospace_body()
+{
+ atf_check -s exit:0 -e 'match:\+ echo succeeded' -o 'match:succeeded' \
+ -x "cd $(atf_get_srcdir) && ./execve_helper script_arg_nospace"
+}
+
+sparse_aout_head()
+{
+ atf_set "descr" 'Sparse file'
+}
+sparse_aout_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper sparse_aout"
+}
+
+trunc_aout_head()
+{
+ atf_set "descr" 'Truncated file'
+}
+trunc_aout_body()
+{
+ atf_check -s exit:1 -e 'match:Exec format error' -o empty \
+ -x "cd $(atf_get_srcdir) && ./execve_helper trunc_aout"
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case bad_interp_len
+ atf_add_test_case empty
+ atf_add_test_case good_aout
+ atf_add_test_case good_script
+ atf_add_test_case non_exist
+ atf_add_test_case non_exist_shell
+ atf_add_test_case script_arg
+ atf_add_test_case script_arg_nospace
+ atf_add_test_case sparse_aout
+ atf_add_test_case trunc_aout
+
+}
diff --git a/tests/sys/kern/execve/good_aout.c b/tests/sys/kern/execve/good_aout.c
new file mode 100644
index 0000000..39e9867
--- /dev/null
+++ b/tests/sys/kern/execve/good_aout.c
@@ -0,0 +1,45 @@
+/* $NetBSD: goodaout.c,v 1.8 2003/07/26 19:38:49 salo Exp $ */
+
+/*-
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * 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 for the
+ * NetBSD Project. See http://www.NetBSD.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main(void)
+{
+ printf("succeeded\n");
+ exit(0);
+}
diff --git a/tests/sys/kern/execve/good_script b/tests/sys/kern/execve/good_script
new file mode 100644
index 0000000..11c7689
--- /dev/null
+++ b/tests/sys/kern/execve/good_script
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/non_exist_shell b/tests/sys/kern/execve/non_exist_shell
new file mode 100644
index 0000000..f9ee705
--- /dev/null
+++ b/tests/sys/kern/execve/non_exist_shell
@@ -0,0 +1,4 @@
+#! /foo/bar/baz
+# $FreeBSD$
+
+echo foo
diff --git a/tests/sys/kern/execve/script_arg b/tests/sys/kern/execve/script_arg
new file mode 100644
index 0000000..2700f1c
--- /dev/null
+++ b/tests/sys/kern/execve/script_arg
@@ -0,0 +1,4 @@
+#! /bin/sh -x
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kern/execve/script_arg_nospace b/tests/sys/kern/execve/script_arg_nospace
new file mode 100644
index 0000000..6731ad5
--- /dev/null
+++ b/tests/sys/kern/execve/script_arg_nospace
@@ -0,0 +1,4 @@
+#!/bin/sh -x
+# $FreeBSD$
+
+echo succeeded
diff --git a/tests/sys/kqueue/Makefile b/tests/sys/kqueue/Makefile
new file mode 100644
index 0000000..43277ca
--- /dev/null
+++ b/tests/sys/kqueue/Makefile
@@ -0,0 +1,26 @@
+# $FreeBSD$
+#
+# svn://mark.heily.com/libkqueue/trunk/test
+# Last update: r114
+#
+# libkqueue and test suite by Mark Heily <mark@heily.com>
+#
+
+TAP_TESTS_SH= kqueue_test
+
+TESTSDIR= ${TESTSBASE}/sys/kqueue
+BINDIR= ${TESTSDIR}
+
+PROGS= kqtest
+
+SRCS.kqtest= \
+ main.c \
+ read.c \
+ timer.c \
+ vnode.c \
+ proc.c \
+ signal.c \
+ user.c
+WARNS?= 2
+
+.include <bsd.test.mk>
diff --git a/tests/sys/kqueue/common.h b/tests/sys/kqueue/common.h
new file mode 100644
index 0000000..aada778
--- /dev/null
+++ b/tests/sys/kqueue/common.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+
+#if HAVE_ERR_H
+# include <err.h>
+#else
+# define err(rc,msg,...) do { perror(msg); exit(rc); } while (0)
+# define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0)
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sys/event.h>
+
+#include "config.h"
+
+extern char *cur_test_id;
+int vnode_fd;
+
+extern const char * kevent_to_str(struct kevent *);
+struct kevent * kevent_get(int);
+
+
+void kevent_cmp(struct kevent *, struct kevent *);
+
+void
+kevent_add(int kqfd, struct kevent *kev,
+ uintptr_t ident,
+ short filter,
+ u_short flags,
+ u_int fflags,
+ intptr_t data,
+ void *udata);
+
+/* DEPRECATED: */
+#define KEV_CMP(kev,_ident,_filter,_flags) do { \
+ if (kev.ident != (_ident) || \
+ kev.filter != (_filter) || \
+ kev.flags != (_flags)) \
+ err(1, "kevent mismatch: got [%d,%d,%d] but expecting [%d,%d,%d]", \
+ (int)_ident, (int)_filter, (int)_flags,\
+ (int)kev.ident, kev.filter, kev.flags);\
+} while (0);
+
+/* Checks if any events are pending, which is an error. */
+extern void test_no_kevents(void);
+
+extern void test_begin(const char *);
+extern void success(void);
+
+#endif /* _COMMON_H */
diff --git a/tests/sys/kqueue/config.h b/tests/sys/kqueue/config.h
new file mode 100644
index 0000000..a204092
--- /dev/null
+++ b/tests/sys/kqueue/config.h
@@ -0,0 +1,13 @@
+/* $FreeBSD$ */
+
+#define HAVE_ERR_H 1
+#define HAVE_SYS_EVENT_H 1
+#define HAVE_EV_DISPATCH 1
+#define HAVE_EV_RECEIPT 1
+#undef HAVE_NOTE_TRUNCATE
+#define HAVE_EVFILT_TIMER 1
+#define HAVE_EVFILT_USER 1
+#define PROGRAM "libkqueue-test"
+#define VERSION "0.1"
+#define TARGET "freebsd"
+#define CFLAGS "-g -O0 -Wall -Werror"
diff --git a/tests/sys/kqueue/kqueue_test.sh b/tests/sys/kqueue/kqueue_test.sh
new file mode 100755
index 0000000..62a7e23
--- /dev/null
+++ b/tests/sys/kqueue/kqueue_test.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+cd $(dirname $0)
+i=1
+./kqtest | while read line; do
+ echo $line | grep -q passed
+ if [ $? -eq 0 ]; then
+ echo "ok - $i $line"
+ : $(( i += 1 ))
+ fi
+
+ echo $line | grep -q 'tests completed'
+ if [ $? -eq 0 ]; then
+ echo -n "1.."
+ echo $line | cut -d' ' -f3
+ fi
+done
diff --git a/tests/sys/kqueue/main.c b/tests/sys/kqueue/main.c
new file mode 100644
index 0000000..f76c4e2
--- /dev/null
+++ b/tests/sys/kqueue/main.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include "config.h"
+#include "common.h"
+
+int testnum = 1;
+char *cur_test_id = NULL;
+int kqfd;
+
+extern void test_evfilt_read();
+extern void test_evfilt_signal();
+extern void test_evfilt_vnode();
+extern void test_evfilt_timer();
+extern void test_evfilt_proc();
+#if HAVE_EVFILT_USER
+extern void test_evfilt_user();
+#endif
+
+/* Checks if any events are pending, which is an error. */
+void
+test_no_kevents(void)
+{
+ int nfds;
+ struct timespec timeo;
+ struct kevent kev;
+
+ puts("confirming that there are no events pending");
+ memset(&timeo, 0, sizeof(timeo));
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
+ if (nfds != 0) {
+ puts("\nUnexpected event:");
+ puts(kevent_to_str(&kev));
+ errx(1, "%d event(s) pending, but none expected:", nfds);
+ }
+}
+
+/* Retrieve a single kevent */
+struct kevent *
+kevent_get(int kqfd)
+{
+ int nfds;
+ struct kevent *kev;
+
+ if ((kev = calloc(1, sizeof(*kev))) == NULL)
+ err(1, "out of memory");
+
+ nfds = kevent(kqfd, NULL, 0, kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "kevent(2)");
+
+ return (kev);
+}
+
+char *
+kevent_fflags_dump(struct kevent *kev)
+{
+ char *buf;
+
+#define KEVFFL_DUMP(attrib) \
+ if (kev->fflags & attrib) \
+ strncat(buf, #attrib" ", 64);
+
+ if ((buf = calloc(1, 1024)) == NULL)
+ abort();
+
+ /* Not every filter has meaningful fflags */
+ if (kev->filter != EVFILT_VNODE) {
+ snprintf(buf, 1024, "fflags = %d", kev->fflags);
+ return (buf);
+ }
+
+ snprintf(buf, 1024, "fflags = %d (", kev->fflags);
+ KEVFFL_DUMP(NOTE_DELETE);
+ KEVFFL_DUMP(NOTE_WRITE);
+ KEVFFL_DUMP(NOTE_EXTEND);
+#if HAVE_NOTE_TRUNCATE
+ KEVFFL_DUMP(NOTE_TRUNCATE);
+#endif
+ KEVFFL_DUMP(NOTE_ATTRIB);
+ KEVFFL_DUMP(NOTE_LINK);
+ KEVFFL_DUMP(NOTE_RENAME);
+#if HAVE_NOTE_REVOKE
+ KEVFFL_DUMP(NOTE_REVOKE);
+#endif
+ buf[strlen(buf) - 1] = ')';
+
+ return (buf);
+}
+
+char *
+kevent_flags_dump(struct kevent *kev)
+{
+ char *buf;
+
+#define KEVFL_DUMP(attrib) \
+ if (kev->flags & attrib) \
+ strncat(buf, #attrib" ", 64);
+
+ if ((buf = calloc(1, 1024)) == NULL)
+ abort();
+
+ snprintf(buf, 1024, "flags = %d (", kev->flags);
+ KEVFL_DUMP(EV_ADD);
+ KEVFL_DUMP(EV_ENABLE);
+ KEVFL_DUMP(EV_DISABLE);
+ KEVFL_DUMP(EV_DELETE);
+ KEVFL_DUMP(EV_ONESHOT);
+ KEVFL_DUMP(EV_CLEAR);
+ KEVFL_DUMP(EV_EOF);
+ KEVFL_DUMP(EV_ERROR);
+#if HAVE_EV_DISPATCH
+ KEVFL_DUMP(EV_DISPATCH);
+#endif
+#if HAVE_EV_RECEIPT
+ KEVFL_DUMP(EV_RECEIPT);
+#endif
+ buf[strlen(buf) - 1] = ')';
+
+ return (buf);
+}
+
+/* Copied from ../kevent.c kevent_dump() and improved */
+const char *
+kevent_to_str(struct kevent *kev)
+{
+ char buf[512];
+
+ snprintf(&buf[0], sizeof(buf),
+ "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]",
+ (u_int) kev->ident,
+ kev->filter,
+ kevent_flags_dump(kev),
+ kevent_fflags_dump(kev),
+ (int) kev->data,
+ kev->udata);
+
+ return (strdup(buf));
+}
+
+void
+kevent_add(int kqfd, struct kevent *kev,
+ uintptr_t ident,
+ short filter,
+ u_short flags,
+ u_int fflags,
+ intptr_t data,
+ void *udata)
+{
+ EV_SET(kev, ident, filter, flags, fflags, data, NULL);
+ if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) {
+ printf("Unable to add the following kevent:\n%s\n",
+ kevent_to_str(kev));
+ err(1, "kevent(): %s", strerror(errno));
+ }
+}
+
+void
+kevent_cmp(struct kevent *k1, struct kevent *k2)
+{
+/* XXX-
+ Workaround for inconsistent implementation of kevent(2)
+ */
+#ifdef __FreeBSD__
+ if (k1->flags & EV_ADD)
+ k2->flags |= EV_ADD;
+#endif
+ if (memcmp(k1, k2, sizeof(*k1)) != 0) {
+ printf("kevent_cmp: mismatch:\n %s !=\n %s\n",
+ kevent_to_str(k1), kevent_to_str(k2));
+ abort();
+ }
+}
+
+void
+test_begin(const char *func)
+{
+ if (cur_test_id)
+ free(cur_test_id);
+ cur_test_id = strdup(func);
+ if (!cur_test_id)
+ err(1, "strdup failed");
+
+ printf("\n\nTest %d: %s\n", testnum++, func);
+}
+
+void
+success(void)
+{
+ printf("%-70s %s\n", cur_test_id, "passed");
+ free(cur_test_id);
+ cur_test_id = NULL;
+}
+
+void
+test_kqueue(void)
+{
+ test_begin("kqueue()");
+ if ((kqfd = kqueue()) < 0)
+ err(1, "kqueue()");
+ test_no_kevents();
+ success();
+}
+
+void
+test_kqueue_close(void)
+{
+ test_begin("close(kq)");
+ if (close(kqfd) < 0)
+ err(1, "close()");
+ success();
+}
+
+int
+main(int argc, char **argv)
+{
+ int test_proc = 1;
+ int test_socket = 1;
+ int test_signal = 1;
+ int test_vnode = 1;
+ int test_timer = 1;
+#ifdef __FreeBSD__
+ int test_user = 1;
+#else
+ /* XXX-FIXME temporary */
+ int test_user = 0;
+#endif
+
+ while (argc) {
+ if (strcmp(argv[0], "--no-proc") == 0)
+ test_proc = 0;
+ if (strcmp(argv[0], "--no-socket") == 0)
+ test_socket = 0;
+ if (strcmp(argv[0], "--no-timer") == 0)
+ test_timer = 0;
+ if (strcmp(argv[0], "--no-signal") == 0)
+ test_signal = 0;
+ if (strcmp(argv[0], "--no-vnode") == 0)
+ test_vnode = 0;
+ if (strcmp(argv[0], "--no-user") == 0)
+ test_user = 0;
+ argv++;
+ argc--;
+ }
+
+ test_kqueue();
+ test_kqueue_close();
+
+ if (test_socket)
+ test_evfilt_read();
+ if (test_signal)
+ test_evfilt_signal();
+ if (test_vnode)
+ test_evfilt_vnode();
+#if HAVE_EVFILT_USER
+ if (test_user)
+ test_evfilt_user();
+#endif
+ if (test_timer)
+ test_evfilt_timer();
+ if (test_proc)
+ test_evfilt_proc();
+
+ printf("\n---\n"
+ "+OK All %d tests completed.\n", testnum - 1);
+ return (0);
+}
diff --git a/tests/sys/kqueue/proc.c b/tests/sys/kqueue/proc.c
new file mode 100644
index 0000000..6288ee6
--- /dev/null
+++ b/tests/sys/kqueue/proc.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/stat.h>
+
+#include <err.h>
+
+#include "config.h"
+#include "common.h"
+
+static int sigusr1_caught = 0;
+
+int kqfd;
+
+static void
+sig_handler(int signum)
+{
+ sigusr1_caught = 1;
+}
+
+static void
+add_and_delete(void)
+{
+ struct kevent kev;
+ pid_t pid;
+
+ /* Create a child that waits to be killed and then exits */
+ pid = fork();
+ if (pid == 0) {
+ struct stat s;
+ if (fstat(kqfd, &s) != -1)
+ errx(1, "kqueue inherited across fork! (%s() at %s:%d)",
+ __func__, __FILE__, __LINE__);
+
+ pause();
+ exit(2);
+ }
+ printf(" -- child created (pid %d)\n", (int) pid);
+
+ test_begin("kevent(EVFILT_PROC, EV_ADD)");
+
+ test_no_kevents();
+ kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
+ test_no_kevents();
+
+ success();
+
+ test_begin("kevent(EVFILT_PROC, EV_DELETE)");
+
+ sleep(1);
+ test_no_kevents();
+ kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
+ if (kill(pid, SIGKILL) < 0)
+ err(1, "kill");
+ sleep(1);
+ test_no_kevents();
+
+ success();
+
+}
+
+#ifdef TODO
+static void
+event_trigger(void)
+{
+ struct kevent kev;
+ pid_t pid;
+
+ test_begin("kevent(EVFILT_PROC, wait)");
+
+ /* Create a child that waits to be killed and then exits */
+ pid = fork();
+ if (pid == 0) {
+ pause();
+ printf(" -- child caught signal, exiting\n");
+ exit(2);
+ }
+ printf(" -- child created (pid %d)\n", (int) pid);
+
+ test_no_kevents();
+ kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
+
+ /* Cause the child to exit, then retrieve the event */
+ printf(" -- killing process %d\n", (int) pid);
+ if (kill(pid, SIGUSR1) < 0)
+ err(1, "kill");
+ kevent_cmp(&kev, kevent_get(kqfd));
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_kevent_signal_disable(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGKILL) < 0)
+ err(1, "kill");
+
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_kevent_signal_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ kev.flags = EV_ADD | EV_CLEAR;
+#if LIBKQUEUE
+ kev.data = 1; /* WORKAROUND */
+#else
+ kev.data = 2; // one extra time from test_kevent_signal_disable()
+#endif
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Delete the watch */
+ kev.flags = EV_DELETE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_signal_del(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ /* Delete the kevent */
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ test_no_kevents();
+ success();
+}
+
+void
+test_kevent_signal_oneshot(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ kev.flags |= EV_CLEAR;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Send another one and make sure we get no events */
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+ test_no_kevents();
+
+ success();
+}
+#endif
+
+void
+test_evfilt_proc()
+{
+ kqfd = kqueue();
+
+ signal(SIGUSR1, sig_handler);
+
+ add_and_delete();
+
+#if TODO
+ event_trigger();
+#endif
+
+ signal(SIGUSR1, SIG_DFL);
+
+#if TODO
+ test_kevent_signal_add();
+ test_kevent_signal_del();
+ test_kevent_signal_get();
+ test_kevent_signal_disable();
+ test_kevent_signal_enable();
+ test_kevent_signal_oneshot();
+#endif
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/read.c b/tests/sys/kqueue/read.c
new file mode 100644
index 0000000..cc65427
--- /dev/null
+++ b/tests/sys/kqueue/read.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+int kqfd;
+int sockfd[2];
+
+static void
+kevent_socket_drain(void)
+{
+ char buf[1];
+
+ /* Drain the read buffer, then make sure there are no more events. */
+ puts("draining the read buffer");
+ if (read(sockfd[0], &buf[0], 1) < 1)
+ err(1, "read(2)");
+}
+
+static void
+kevent_socket_fill(void)
+{
+ puts("filling the read buffer");
+ if (write(sockfd[1], ".", 1) < 1)
+ err(1, "write(2)");
+}
+
+
+void
+test_kevent_socket_add(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, EV_ADD)";
+ struct kevent kev;
+
+ test_begin(test_id);
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_socket_get(void)
+{
+ const char *test_id = "kevent(EVFILT_READ) wait";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kevent_socket_fill();
+
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ kevent_socket_drain();
+ test_no_kevents();
+
+ kev.flags = EV_DELETE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_socket_clear(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, EV_CLEAR)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kevent_socket_fill();
+ kevent_socket_fill();
+
+ kev.data = 2;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* We filled twice, but drain once. Edge-triggered would not generate
+ additional events.
+ */
+ kevent_socket_drain();
+ test_no_kevents();
+
+ kevent_socket_drain();
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_socket_disable_and_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, EV_DISABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ /* Add an event, then disable it. */
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DISABLE, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kevent_socket_fill();
+ test_no_kevents();
+
+ /* Re-enable the knote, then see if an event is generated */
+ kev.flags = EV_ENABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ kev.flags = EV_ADD;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ kevent_socket_drain();
+
+ kev.flags = EV_DELETE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_socket_del(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kevent_socket_fill();
+ test_no_kevents();
+ kevent_socket_drain();
+
+ success();
+}
+
+void
+test_kevent_socket_oneshot(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ /* Re-add the watch and make sure no events are pending */
+ puts("-- re-adding knote");
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ test_no_kevents();
+
+ puts("-- getting one event");
+ kevent_socket_fill();
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ puts("-- checking knote disabled");
+ test_no_kevents();
+
+ /* Try to delete the knote, it should already be deleted */
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
+ err(1, "%s", test_id);
+
+ kevent_socket_drain();
+
+ success();
+}
+
+
+#if HAVE_EV_DISPATCH
+void
+test_kevent_socket_dispatch(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)";
+
+ test_begin(test_id);
+
+ struct kevent kev;
+
+ /* Re-add the watch and make sure no events are pending */
+ puts("-- re-adding knote");
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ test_no_kevents();
+
+ /* The event will occur only once, even though EV_CLEAR is not
+ specified. */
+ kevent_socket_fill();
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+ test_no_kevents();
+
+ /* Since the knote is disabled, the EV_DELETE operation succeeds. */
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kevent_socket_drain();
+
+ success();
+}
+#endif /* HAVE_EV_DISPATCH */
+
+#if BROKEN
+void
+test_kevent_socket_lowat(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ /* Re-add the watch and make sure no events are pending */
+ puts("-- re-adding knote, setting low watermark to 2 bytes");
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ test_no_kevents();
+
+ puts("-- checking that one byte does not trigger an event..");
+ kevent_socket_fill();
+ test_no_kevents();
+
+ puts("-- checking that two bytes triggers an event..");
+ kevent_socket_fill();
+ if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
+ err(1, "%s", test_id);
+ KEV_CMP(kev, sockfd[0], EVFILT_READ, 0);
+ test_no_kevents();
+
+ kevent_socket_drain();
+ kevent_socket_drain();
+
+ success();
+}
+#endif
+
+void
+test_kevent_socket_eof(void)
+{
+ const char *test_id = "kevent(EVFILT_READ, EV_EOF)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ /* Re-add the watch and make sure no events are pending */
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ test_no_kevents();
+
+ if (close(sockfd[1]) < 0)
+ err(1, "close(2)");
+
+ kev.flags |= EV_EOF;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Delete the watch */
+ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_evfilt_read()
+{
+ /* Create a connected pair of full-duplex sockets for testing socket events */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
+ abort();
+
+ kqfd = kqueue();
+ test_kevent_socket_add();
+ test_kevent_socket_del();
+ test_kevent_socket_get();
+ test_kevent_socket_disable_and_enable();
+ test_kevent_socket_oneshot();
+ test_kevent_socket_clear();
+#if HAVE_EV_DISPATCH
+ test_kevent_socket_dispatch();
+#endif
+ test_kevent_socket_eof();
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/signal.c b/tests/sys/kqueue/signal.c
new file mode 100644
index 0000000..14e751d
--- /dev/null
+++ b/tests/sys/kqueue/signal.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+int kqfd;
+
+void
+test_kevent_signal_add(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ADD)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_signal_get(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, wait)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ kev.flags |= EV_CLEAR;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ success();
+}
+
+void
+test_kevent_signal_disable(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_kevent_signal_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ kev.flags = EV_ADD | EV_CLEAR;
+#if LIBKQUEUE
+ kev.data = 1; /* WORKAROUND */
+#else
+ kev.data = 2; // one extra time from test_kevent_signal_disable()
+#endif
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Delete the watch */
+ kev.flags = EV_DELETE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_signal_del(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ /* Delete the kevent */
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ test_no_kevents();
+ success();
+}
+
+void
+test_kevent_signal_oneshot(void)
+{
+ const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Block SIGUSR1, then send it to ourselves */
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
+ err(1, "sigprocmask");
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+
+ kev.flags |= EV_CLEAR;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Send another one and make sure we get no events */
+ if (kill(getpid(), SIGUSR1) < 0)
+ err(1, "kill");
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_evfilt_signal()
+{
+ kqfd = kqueue();
+ test_kevent_signal_add();
+ test_kevent_signal_del();
+ test_kevent_signal_get();
+ test_kevent_signal_disable();
+ test_kevent_signal_enable();
+ test_kevent_signal_oneshot();
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/timer.c b/tests/sys/kqueue/timer.c
new file mode 100644
index 0000000..766125d
--- /dev/null
+++ b/tests/sys/kqueue/timer.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+int kqfd;
+
+void
+test_kevent_timer_add(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_timer_del(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_kevent_timer_get(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, wait)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kev.flags |= EV_CLEAR;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+static void
+test_oneshot(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Retrieve the event */
+ kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Check if the event occurs again */
+ sleep(3);
+ test_no_kevents();
+
+
+ success();
+}
+
+static void
+test_periodic(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, periodic)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Retrieve the event */
+ kev.flags = EV_ADD | EV_CLEAR;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Check if the event occurs again */
+ sleep(1);
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ /* Delete the event */
+ kev.flags = EV_DELETE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+static void
+disable_and_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ /* Add the watch and immediately disable it */
+ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ kev.flags = EV_DISABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ test_no_kevents();
+
+ /* Re-enable and check again */
+ kev.flags = EV_ENABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
+ kev.data = 1;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ success();
+}
+
+void
+test_evfilt_timer()
+{
+ kqfd = kqueue();
+ test_kevent_timer_add();
+ test_kevent_timer_del();
+ test_kevent_timer_get();
+ test_oneshot();
+ test_periodic();
+ disable_and_enable();
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/user.c b/tests/sys/kqueue/user.c
new file mode 100644
index 0000000..9ba25f9
--- /dev/null
+++ b/tests/sys/kqueue/user.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+int kqfd;
+
+static void
+add_and_delete(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, EV_ADD and EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
+ test_no_kevents();
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL);
+ test_no_kevents();
+
+ success();
+}
+
+static void
+event_wait(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, wait)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ /* Add the event, and then trigger it */
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+
+ kev.fflags &= ~NOTE_FFCTRLMASK;
+ kev.fflags &= ~NOTE_TRIGGER;
+ kev.flags = EV_CLEAR;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ test_no_kevents();
+
+ success();
+}
+
+static void
+disable_and_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, EV_DISABLE and EV_ENABLE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL);
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DISABLE, 0, 0, NULL);
+
+ /* Trigger the event, but since it is disabled, nothing will happen. */
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+ test_no_kevents();
+
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ENABLE, 0, 0, NULL);
+ kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+
+ kev.flags = EV_CLEAR;
+ kev.fflags &= ~NOTE_FFCTRLMASK;
+ kev.fflags &= ~NOTE_TRIGGER;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ success();
+}
+
+static void
+oneshot(void)
+{
+ const char *test_id = "kevent(EVFILT_USER, EV_ONESHOT)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ kevent_add(kqfd, &kev, 2, EVFILT_USER, EV_ADD | EV_ONESHOT, 0, 0, NULL);
+
+ puts(" -- event 1");
+ kevent_add(kqfd, &kev, 2, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+
+ kev.flags = EV_ONESHOT;
+ kev.fflags &= ~NOTE_FFCTRLMASK;
+ kev.fflags &= ~NOTE_TRIGGER;
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ test_no_kevents();
+
+ success();
+}
+
+void
+test_evfilt_user()
+{
+ kqfd = kqueue();
+
+ add_and_delete();
+ event_wait();
+ disable_and_enable();
+ oneshot();
+ /* TODO: try different fflags operations */
+
+ close(kqfd);
+}
diff --git a/tests/sys/kqueue/vnode.c b/tests/sys/kqueue/vnode.c
new file mode 100644
index 0000000..dfa0b5e
--- /dev/null
+++ b/tests/sys/kqueue/vnode.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2009 Mark Heily <mark@heily.com>
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include "common.h"
+
+int kqfd;
+int vnode_fd;
+
+void
+test_kevent_vnode_add(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)";
+ const char *testfile = "/tmp/kqueue-test.tmp";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ system("touch /tmp/kqueue-test.tmp");
+ vnode_fd = open(testfile, O_RDONLY);
+ if (vnode_fd < 0)
+ err(1, "open of %s", testfile);
+ else
+ printf("vnode_fd = %d\n", vnode_fd);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD,
+ NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_vnode_note_delete(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (unlink("/tmp/kqueue-test.tmp") < 0)
+ err(1, "unlink");
+
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ success();
+}
+
+void
+test_kevent_vnode_note_write(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("echo hello >> /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ /* BSD kqueue adds NOTE_EXTEND even though it was not requested */
+ /* BSD kqueue removes EV_ENABLE */
+ kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
+ kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
+ kevent_cmp(&kev, kevent_get(kqfd));
+
+ success();
+}
+
+void
+test_kevent_vnode_note_attrib(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != vnode_fd ||
+ kev.filter != EVFILT_VNODE ||
+ kev.fflags != NOTE_ATTRIB)
+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
+
+ success();
+}
+
+void
+test_kevent_vnode_note_rename(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("mv /tmp/kqueue-test.tmp /tmp/kqueue-test2.tmp") < 0)
+ err(1, "system");
+
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != vnode_fd ||
+ kev.filter != EVFILT_VNODE ||
+ kev.fflags != NOTE_RENAME)
+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
+
+ if (system("mv /tmp/kqueue-test2.tmp /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ success();
+}
+
+void
+test_kevent_vnode_del(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)";
+ struct kevent kev;
+
+ test_begin(test_id);
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ success();
+}
+
+void
+test_kevent_vnode_disable_and_enable(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ /* Add the watch and immediately disable it */
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ kev.flags = EV_DISABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ /* Confirm that the watch is disabled */
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+ test_no_kevents();
+
+ /* Re-enable and check again */
+ kev.flags = EV_ENABLE;
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != vnode_fd ||
+ kev.filter != EVFILT_VNODE ||
+ kev.fflags != NOTE_ATTRIB)
+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
+
+ success();
+}
+
+#if HAVE_EV_DISPATCH
+void
+test_kevent_vnode_dispatch(void)
+{
+ const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)";
+ struct kevent kev;
+ int nfds;
+
+ test_begin(test_id);
+
+ test_no_kevents();
+
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "%s", test_id);
+
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+
+ nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
+ if (nfds < 1)
+ err(1, "%s", test_id);
+ if (kev.ident != vnode_fd ||
+ kev.filter != EVFILT_VNODE ||
+ kev.fflags != NOTE_ATTRIB)
+ err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
+ test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
+
+ /* Confirm that the watch is disabled automatically */
+ puts("-- checking that watch is disabled");
+ if (system("touch /tmp/kqueue-test.tmp") < 0)
+ err(1, "system");
+ test_no_kevents();
+
+ /* Delete the watch */
+ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
+ if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+ err(1, "remove watch failed: %s", test_id);
+
+ success();
+}
+#endif /* HAVE_EV_DISPATCH */
+
+void
+test_evfilt_vnode()
+{
+ kqfd = kqueue();
+ test_kevent_vnode_add();
+ test_kevent_vnode_del();
+ test_kevent_vnode_disable_and_enable();
+#if HAVE_EV_DISPATCH
+ test_kevent_vnode_dispatch();
+#endif
+ test_kevent_vnode_note_write();
+ test_kevent_vnode_note_attrib();
+ test_kevent_vnode_note_rename();
+ test_kevent_vnode_note_delete();
+ close(kqfd);
+}
OpenPOWER on IntegriCloud