diff options
author | ngie <ngie@FreeBSD.org> | 2015-10-05 03:26:51 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-10-05 03:26:51 +0000 |
commit | e1dd16d965b177f109afb771e59432e36f335d0a (patch) | |
tree | 15db092a5401cf329f1bff9d3bf700d1fde0f121 /contrib/ipfilter/tools | |
parent | 115d008392113efc6f844baa7cc407e9eaae63db (diff) | |
download | FreeBSD-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.ipf | 80 | ||||
-rw-r--r-- | contrib/ipfilter/tools/BNF.ipnat | 28 | ||||
-rw-r--r-- | contrib/ipfilter/tools/Makefile | 104 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipf.c | 601 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipf_y.y | 2749 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipfcomp.c | 1374 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipfs.c | 881 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipfstat.c | 2375 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipfsyncd.c | 671 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipftest.c | 874 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipmon.c | 1910 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipmon_y.y | 1052 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipnat.c | 855 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipnat_y.y | 1782 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ippool.c | 1073 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ippool_y.y | 818 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipscan_y.y | 572 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipsyncm.c | 256 | ||||
-rw-r--r-- | contrib/ipfilter/tools/ipsyncs.c | 274 | ||||
-rw-r--r-- | contrib/ipfilter/tools/lex_var.h | 60 | ||||
-rw-r--r-- | contrib/ipfilter/tools/lexer.c | 735 | ||||
-rw-r--r-- | contrib/ipfilter/tools/lexer.h | 38 |
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(¬hingsaver); +} + + +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; + |