summaryrefslogtreecommitdiffstats
path: root/contrib/ipfilter/tools
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 /contrib/ipfilter/tools
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...)
Diffstat (limited to 'contrib/ipfilter/tools')
-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
22 files changed, 19162 insertions, 0 deletions
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;
+
OpenPOWER on IntegriCloud