IP filter 3.0.1
authordm <dm@openbsd.org>
Thu, 25 Jan 1996 05:41:23 +0000 (05:41 +0000)
committerdm <dm@openbsd.org>
Thu, 25 Jan 1996 05:41:23 +0000 (05:41 +0000)
36 files changed:
sbin/ipf/Makefile
sbin/ipf/ipf.1
sbin/ipf/ipf.5
sbin/ipf/ipf.c
sbin/ipf/ipf.h
sbin/ipf/opt.c
sbin/ipf/parse.c
sbin/ipfstat/Makefile
sbin/ipfstat/fils.c
sbin/ipfstat/ipfstat.8
sbin/ipfstat/kmem.c
sys/conf/files
sys/conf/files.oldconf
sys/netinet/fil.c
sys/netinet/ip_fil.c
sys/netinet/ip_fil.h
sys/netinet/ip_frag.c [new file with mode: 0644]
sys/netinet/ip_frag.h [new file with mode: 0644]
sys/netinet/ip_input.c
sys/netinet/ip_nat.c [new file with mode: 0644]
sys/netinet/ip_nat.h [new file with mode: 0644]
sys/netinet/ip_output.c
sys/netinet/ip_state.c [new file with mode: 0644]
sys/netinet/ip_state.h [new file with mode: 0644]
usr.sbin/ipftest/Makefile
usr.sbin/ipftest/fil.c [deleted file]
usr.sbin/ipftest/ipft_ef.c
usr.sbin/ipftest/ipft_pc.c
usr.sbin/ipftest/ipft_sn.c
usr.sbin/ipftest/ipft_td.c
usr.sbin/ipftest/ipft_tx.c
usr.sbin/ipftest/ipt.c
usr.sbin/ipftest/misc.c
usr.sbin/ipmon/Makefile
usr.sbin/ipmon/ipmon.c
usr.sbin/ipsend/Makefile

index 32e77eb..4be887d 100644 (file)
@@ -1,7 +1,7 @@
 PROG=  ipf
 MAN=   ipf.1 ipf.4 ipf.5
 SRCS=  ipf.c parse.c opt.c
-CFLAGS+=-DIPL_NAME=\"/dev/ipl\"
+CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -I${.CURDIR}/../../sys/netinet
 
 
 .include <bsd.prog.mk>
index 1a4abc8..59f8ea2 100644 (file)
@@ -2,8 +2,8 @@
 .SH NAME
 ipf - alters packet filtering lists for IP packet input and ouput
 .SH SYNOPSIS
-ipf [-AEDIsnovdr] [-F <i|o|a>] -f <\fIfilename\fP>
-[ -f <\fIfilename\fP> [...]]
+ipf [-AEDIsnovdr] [-l <block|pass|nomatch>] [-F <i|o|a>]
+-f <\fIfilename\fP> [ -f <\fIfilename\fP> [...]]
 .SH DESCRIPTION
 .PP
 \fBipf\fP opens the filenames listed (treating "-" as stdin) and parses the
@@ -36,6 +36,12 @@ this option specifies which files
 lists.
 .IP -I
 set the list to make changes to the inactive list.
+.IP -l
+Use of the \fB-l\fP flag toggles default logging of packets.  Valid
+arguments to this option are \fBpass\fP, \fBblock\fP and \fBnomatch\fP.
+When an option is set, any packet which exits filtering and matches the
+set category is logged.  This is most useful for causing all packets
+which don't match any of the loaded rules to be logged.
 .IP -n
 This flag (no-change) prevents \fBipf\fP from actually making any ioctl
 calls or doing anything which would alter the currently running kernel.
@@ -57,4 +63,4 @@ Needs to be run as root for the packet filtering lists to actually
 be affected inside the kernel.
 .SH BUGS
 .PP
-If you find any, please send email to me at darrenr@arbld.unimelb.edu.au
+If you find any, please send email to me at darrenr@cyber.com.au
index 2e70be1..84f2023 100644 (file)
@@ -22,16 +22,16 @@ filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ]
               [ proto ] [ ip ] .
 
 insert  = "@" decnumber
-action  = block | "pass" | log .
+action  = block | "pass" | log | "count" .
 in-out  = "in" | "out" .
 options = [ log ] [ "quick" ] [ "on" interface-name] .
 tos     = "tos" decnumber | "tos" hexnumber .
 ttl     = "ttl" decnumber .
 proto   = "proto" protocol .
-ip      = srcdst [ flags ] [ with withopt ] [ icmp ] .
+ip      = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
 
-block   = "block" [ "return-icmp" ] [ "return-rst" ].
-log    = "log" [ "body" ] .
+block   = "block" [ "return-icmp" [ return-code ] | "return-rst" ].
+log    = "log" [ "body" ] [ "first" ] .
 protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber .
 srcdst  = "all" | fromto .
 fromto  = "from" object "to" object .
@@ -43,6 +43,8 @@ port-range = "port" port-num range port-num .
 flags   = "flags" flag { flag } [ "/" flag { flag } ] .
 with    = "with" | "and"  .
 icmp    = "icmp-type" icmp-type .
+return-code = "(" icmp-code ")" .
+keep   = "keep" "state" | "keep" "frags" .
 
 nummask = host-name [ "/" decnumber ] .
 host-name = ipaddr | hostname | "any" .
@@ -59,6 +61,9 @@ seclvl  = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" |
 icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" |
             "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" |
             "inforep" | "maskreq" | "maskrep"  | decnumber .
+icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" |
+           "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
+           "net-prohib" | "host-prohib" | "net-tos" | "host-tos" .
 
 hexnumber = "0" "x" hexstring .
 hexstring = hexdigit [ hexstring ] .
@@ -247,11 +252,17 @@ wich to compare (ie those you deem significant).  This is done by appending
                        # with BOTH SYN and ACK set, but WILL match "SFP".
 .fi
 .PP
-The last parameter set for the filter rule is the optional \fBicmp-type\fP.
+The next parameter set for the filter rule is the optional \fBicmp-type\fP.
 It is only effective when used with \fB"proto icmp"\fP and must NOT be used
 in conjuction with \fBflags\fP.  There are a number of types which can be
 refered to by an abbreviation recognised by this language or the numbers
 with which they are associated can be used.
+.PP
+The last parameter which can be set for a filter rule is whether on not to
+record state information for that packet, and what sort to keep.  Either
+information relating to the packet's `flow' or if fragment details can be
+kept, allowing packets which match these to flow straight through, rather
+than going through the access control list.
 .SH FILES
 /etc/services
 /etc/hosts
index 12e8ff2..92fe2e6 100644 (file)
@@ -27,16 +27,21 @@ extern      char    *index();
 #include <netinet/in_systm.h>
 #include <net/if.h>
 #include <netinet/ip.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include <netdb.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
 #include "ipf.h"
 
 #ifndef        lint
-static char    sccsid[] = "@(#)ipf.c   1.18 11/11/95 (C) 1993-1995 Darren Reed";
+static char    sccsid[] = "@(#)ipf.c   1.21 1/14/96 (C) 1993-1995 Darren Reed";
 #endif
 
+#if    SOLARIS
+void   frsync();
+#endif
+void   zerostats();
+
 extern char    *optarg;
 
 int    opts = 0;
@@ -96,7 +101,7 @@ char *argv[];
                case 'v' :
                        opts |= OPT_VERBOSE;
                        break;
-#if defined(sun) && (defined(__SVR4) || defined(__svr4__))
+#if SOLARIS
                case 'y' :
                        frsync();
                        break;
@@ -136,8 +141,10 @@ char       *file;
 
        if (!strcmp(file, "-"))
                fp = stdin;
-       else if (!(fp = fopen(file, "r")))
-               return;
+       else if (!(fp = fopen(file, "r"))) {
+               perror("fopen");
+               exit(1);;
+       }
 
        while (fgets(line, sizeof(line)-1, fp)) {
                /*
@@ -209,6 +216,11 @@ char       *opt;
                if (opts & OPT_VERBOSE)
                        printf("set log flag: pass\n");
        }
+       if (index(opt, 'm') && (*opt == 'n' || *opt == 'N')) {
+               flag |= FF_LOGNOMATCH;
+               if (opts & OPT_VERBOSE)
+                       printf("set log flag: nomatch\n");
+       }
        if (index(opt, 'b') || index(opt, 'd')) {
                flag |= FF_LOGBLOCK;
                if (opts & OPT_VERBOSE)
@@ -235,11 +247,11 @@ char      *arg;
 
        if (!arg || !*arg)
                return;
-       if (*arg == 'i' || *arg == 'I')
+       if (strchr(arg, 'i') || strchr(arg, 'I'))
                fl = FR_INQUE;
-       else if (*arg == 'o' || *arg == 'O')
+       if (strchr(arg, 'o') || strchr(arg, 'O'))
                fl = FR_OUTQUE;
-       else if (*arg == 'a' || *arg == 'A')
+       if (strchr(arg, 'a') || strchr(arg, 'A'))
                fl = FR_OUTQUE|FR_INQUE;
        fl |= (opts & FR_INACTIVE);
        rem = fl;
@@ -267,7 +279,7 @@ static void swapactive()
 
 
 #if defined(sun) && (defined(__SVR4) || defined(__svr4__))
-frsync()
+void frsync()
 {
        if (ioctl(fd, SIOCFRSYN, 0) == -1)
                perror("SIOCFRSYN");
@@ -277,7 +289,7 @@ frsync()
 #endif
 
 
-zerostats()
+void zerostats()
 {
        struct  friostat        fio;
 
index 537c15b..794f98c 100644 (file)
@@ -1,24 +1,27 @@
 /*
- * (C)opyright 1993,1994,1995 by Darren Reed.
+ * (C)opyright 1993-1996 by Darren Reed.
  *
  * Redistribution and use in source and binary forms are permitted
  * provided that this notice is preserved and due credit is given
  * to the original author and the contributors.
  *
- * @(#)ipf.h   1.7 10/15/95
+ * @(#)ipf.h   1.9 1/7/96
  */
 
-#define        OPT_INQUE       FR_INQUE        /* 0x0001 */
-#define        OPT_REMOVE      0x0002
+#define        OPT_REMOVE      0x0001
+#define        OPT_DEBUG       0x0002
 #define        OPT_OUTQUE      FR_OUTQUE       /* 0x0004 */
-#define        OPT_DEBUG       0x0008
-#define        OPT_SHOWLIST    0x0010
-#define        OPT_VERBOSE     0x0020
-#define        OPT_LOG         FR_LOG          /* 0x0040 */
+#define        OPT_INQUE       FR_INQUE        /* 0x0008 */
+#define        OPT_LOG         FR_LOG          /* 0x0010 */
+#define        OPT_SHOWLIST    0x0020
+#define        OPT_VERBOSE     0x0040
 #define        OPT_DONOTHING   0x0080
-#define        OPT_INACTIVE    FR_INACTIVE     /* 0x0800 */
-#define        OPT_HITS        0x10000
-#define        OPT_BRIEF       0x20000
+#define        OPT_HITS        0x100
+#define        OPT_BRIEF       0x200
+#define OPT_ACCNT      FR_ACCOUNT      /* 0x0800 */
+#define        OPT_FRSTATES    FR_KEEPFRAG     /* 0x1000 */
+#define        OPT_IPSTATES    FR_KEEPSTATE    /* 0x2000 */
+#define        OPT_INACTIVE    FR_INACTIVE     /* 0x4000 */
 
 extern struct  frentry *parse();
 
index 5b7debf..8e90965 100644 (file)
@@ -17,7 +17,7 @@
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include "ipf.h"
 
 #ifndef        lint
index 56cf14d..efea74e 100644 (file)
@@ -23,7 +23,7 @@
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include <netdb.h>
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
 #include <ctype.h>
 
 #ifndef        lint
-static char    sccsid[] ="@(#)parse.c  1.25 11/11/95 (C) 1993 Darren Reed";
+static char    sccsid[] ="@(#)parse.c  1.33 1/14/96 (C) 1993 Darren Reed";
 #endif
 
 extern struct  ipopt_names     ionames[], secclass[];
 extern int     opts;
+extern int     gethostname();
 
 u_long hostnum(), optname();
 u_short        portnum();
 u_char tcp_flags();
 struct frentry *parse();
 void   binprint(), printfr();
-int    addicmp(), extras(), hostmask(), ports();
+int    addicmp(), extras(), hostmask(), ports(), icmpcode(), addkeep();
 
 char   *proto = NULL;
 char   flagset[] = "FSRPAU";
 u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG };
 
+static char    thishost[64];
+
+
+void initparse()
+{
+       gethostname(thishost, sizeof(thishost));
+       thishost[sizeof(thishost) - 1] = '\0';
+}
+
+
 /* parse()
  *
  * parse a line read from the input filter rule file
@@ -86,7 +97,7 @@ char  *line;
         * does it start with one of the two possible first words ?
         */
        if (strcasecmp("block",*cpp) && strcasecmp("pass",*cpp) &&
-           strcasecmp("log",*cpp)) {
+           strcasecmp("log",*cpp) && strcasecmp("count",*cpp)) {
                (void)fprintf(stderr, "unknown keyword (%s)\n", *cpp);
                return NULL;
        }
@@ -95,11 +106,22 @@ char       *line;
                if (!strncasecmp(*(cpp+1), "return-icmp", 11)) {
                        fil.fr_flags |= FR_RETICMP;
                        cpp++;
+                       if (*(*cpp + 11) == '(') {
+                               fil.fr_icode = icmpcode(*cpp + 12);
+                               if (fil.fr_icode == -1) {
+                                       fprintf(stderr,
+                                               "uncrecognised icmp code %s\n",
+                                               *cpp + 12);
+                                       return NULL;
+                               }
+                       }
                } else if (!strncasecmp(*(cpp+1), "return-rst", 10)) {
                        fil.fr_flags |= FR_RETRST;
                        cpp++;
                }
-       } else if (**cpp == 'p')
+       } else if (**cpp == 'c')
+               fil.fr_flags = FR_ACCOUNT;
+       else if (**cpp == 'p')
                fil.fr_flags = FR_PASS;
        else if (**cpp == 'l') {
                fil.fr_flags = FR_LOG;
@@ -107,6 +129,10 @@ char       *line;
                        fil.fr_flags |= FR_LOGBODY;
                        cpp++;
                }
+               if (!strcasecmp(*(cpp+1), "first")) {
+                       fil.fr_flags |= FR_LOGFIRST;
+                       cpp++;
+               }
        }
        cpp++;
 
@@ -115,13 +141,13 @@ char      *line;
        else if (!strcasecmp("out", *cpp))
                fil.fr_flags |= FR_OUTQUE;
        else {
-               (void)fprintf(stderr, "missing 'in'/'out' keyword (%s)\n",
-                       *cpp);
+               (void)fprintf(stderr,
+                       "missing 'in'/'out' keyword (%s)\n", *cpp);
                return NULL;
        }
-
        if (!*++cpp)
                return NULL;
+
        if (!strcasecmp("log", *cpp)) {
                cpp++;
                if (fil.fr_flags & FR_PASS)
@@ -132,6 +158,10 @@ char       *line;
                        fil.fr_flags |= FR_LOGBODY;
                        cpp++;
                }
+               if (!strcasecmp(*cpp, "first")) {
+                       fil.fr_flags |= FR_LOGFIRST;
+                       cpp++;
+               }
        }
 
        if (!strcasecmp("quick", *cpp)) {
@@ -319,6 +349,13 @@ char       *line;
                fil.fr_icmpm = htons(fil.fr_icmpm);
        }
 
+       /*
+        * Keep something...
+        */
+       if (*cpp && !strcasecmp(*cpp, "keep"))
+               if (addkeep(&cpp, &fil))
+                       return NULL;
+
        /*
         * leftovers...yuck
         */
@@ -353,7 +390,7 @@ u_short     *pp, *tp;
 u_char *cp;
 {
        char    *s;
-       int     bits = -1;
+       int     bits = -1, resolved;
 
        /*
         * is it possibly hostname/num ?
@@ -374,7 +411,9 @@ u_char      *cp;
                        }
                        *msk = htonl(*msk);
                }
-               *sa = hostnum(**seg) & *msk;
+               *sa = hostnum(**seg, &resolved) & *msk;
+               if (resolved == -1)
+                       return -1;
                (*seg)++;
                return ports(seg, pp, cp, tp);
        }
@@ -383,17 +422,24 @@ u_char    *cp;
         * look for extra segments if "mask" found in right spot
         */
        if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) {
-               *sa = hostnum(**seg);
+               *sa = hostnum(**seg, &resolved);
+               if (resolved == -1)
+                       return -1;
                (*seg)++;
                (*seg)++;
-               *msk = inet_addr(**seg);
+               if (index(**seg, '.'))
+                       *msk = inet_addr(**seg);
+               else
+                       *msk = (u_long)strtol(**seg, NULL, 0);
                (*seg)++;
                *sa &= *msk;
                return ports(seg, pp, cp, tp);
        }
 
        if (**seg) {
-               *sa = hostnum(**seg);
+               *sa = hostnum(**seg, &resolved);
+               if (resolved == -1)
+                       return -1;
                (*seg)++;
                *msk = (*sa ? inet_addr("255.255.255.255") : 0L);
                *sa &= *msk;
@@ -406,20 +452,27 @@ u_char    *cp;
  * returns an ip address as a long var as a result of either a DNS lookup or
  * straight inet_addr() call
  */
-u_long hostnum(host)
+u_long hostnum(host, resolved)
 char   *host;
+int    *resolved;
 {
        struct  hostent *hp;
        struct  netent  *np;
 
+       *resolved = 0;
        if (!strcasecmp("any",host))
                return 0L;
        if (isdigit(*host))
                return inet_addr(host);
+       if (!strcasecmp("<thishost>", host))
+               host = thishost;
 
        if (!(hp = gethostbyname(host))) {
-               if (!(np = getnetbyname(host)))
+               if (!(np = getnetbyname(host))) {
+                       *resolved = -1;
+                       fprintf(stderr, "can't resolve hostname: %s\n", host);
                        return 0;
+               }
                return np->n_net;
        }
        return *(u_long *)hp->h_addr;
@@ -485,8 +538,10 @@ char       *name;
        struct  servent *sp, *sp2;
        u_short p1 = 0;
 
-       if (isdigit(*name) || !proto)
+       if (isdigit(*name))
                return htons((u_short)atoi(name));
+       if (!proto)
+               proto = "tcp/udp";
        if (strcasecmp(proto, "tcp/udp")) {
                sp = getservbyname(name, proto);
                if (sp)
@@ -740,6 +795,64 @@ struct     frentry *fp;
 }
 
 
+#define        MAX_ICMPCODE    12
+
+char   *icmpcodes[] = {
+       "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail",
+       "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib",
+       "net-tos", "host-tos", NULL };
+/*
+ * Return the number for the associated ICMP unreachable code.
+ */
+int icmpcode(str)
+char *str;
+{
+       char    *s;
+       int     i, len;
+
+       if (!(s = strrchr(str, ')')))
+               return -1;
+       *s = '\0';
+       if (isdigit(*str))
+               return atoi(str);
+       len = strlen(str);
+       for (i = 0; icmpcodes[i]; i++)
+               if (!strncasecmp(str, icmpcodes[i], MIN(len,
+                                strlen(icmpcodes[i])) ))
+                       return i;
+       return -1;
+}
+
+
+/*
+ * set the icmp field to the correct type if "icmp" word is found
+ */
+int    addkeep(cp, fp)
+char   ***cp;
+struct frentry *fp;
+{
+       if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP &&
+           fp->fr_proto != IPPROTO_ICMP) {
+               (void)fprintf(stderr, "Can only use keep with UDP/ICMP/TCP\n");
+               return -1;
+       }
+
+       (*cp)++;
+       if (**cp && strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) {
+               (void)fprintf(stderr, "Unrecognised state keyword \"%s\"\n",
+                       **cp);
+               return -1;
+       }
+
+       if (***cp == 's')
+               fp->fr_flags |= FR_KEEPSTATE;
+       else if (***cp == 'f')
+               fp->fr_flags |= FR_KEEPFRAG;
+       (*cp)++;
+       return 0;
+}
+
+
 /*
  * count consecutive 1's in bit mask.  If the mask generated by counting
  * consecutive 1's is different to that passed, return -1, else return #
@@ -816,23 +929,35 @@ struct    frentry *fp;
                (void)printf("log");
                if (fp->fr_flags & FR_LOGBODY)
                        (void)printf(" body");
+               if (fp->fr_flags & FR_LOGFIRST)
+                       (void)printf(" first");
        } else if (fp->fr_flags & FR_BLOCK) {
                (void)printf("block");
-               if (fp->fr_flags & FR_RETICMP)
+               if (fp->fr_flags & FR_RETICMP) {
                        (void)printf(" return-icmp");
+                       if (fp->fr_icode)
+                               if (fp->fr_icode <= MAX_ICMPCODE)
+                                       printf("(%s)",icmpcodes[fp->fr_icode]);
+                               else
+                                       printf("(%d)", fp->fr_icode);
+               }
                if (fp->fr_flags & FR_RETRST)
                        (void)printf(" return-rst");
-       }
+       } else if (fp->fr_flags & FR_ACCOUNT)
+               (void)printf("count");
 
        if (fp->fr_flags & FR_OUTQUE)
                (void)printf(" out ");
        else
                (void)printf(" in ");
 
-       if (fp->fr_flags & (FR_LOGB|FR_LOGP)) {
+       if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
+           ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
                (void)printf("log ");
                if (fp->fr_flags & FR_LOGBODY)
-                       (void)printf(" body");
+                       (void)printf("body ");
+               if (fp->fr_flags & FR_LOGFIRST)
+                       (void)printf("first ");
        }
        if (fp->fr_flags & FR_QUICK)
                (void)printf("quick ");
@@ -936,6 +1061,9 @@ struct     frentry *fp;
                                        (void)putchar(*s);
                }
        }
+       if (fp->fr_flags & (FR_KEEPFRAG|FR_KEEPSTATE))
+               printf(" keep %s ",
+                       (fp->fr_flags & FR_KEEPFRAG) ? "frags" : "state");
        (void)putchar('\n');
 }
 
index bafd458..ba55b94 100644 (file)
@@ -2,7 +2,7 @@ PROG=   ipfstat
 MAN=   ipfstat.8
 SRCS=  fils.c parse.c opt.c kmem.c 
 .PATH:  ${.CURDIR}/../../sbin/ipf
-CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -I${.CURDIR}/../../sbin/ipf
+CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -I${.CURDIR}/../../sbin/ipf -I${.CURDIR}/../../sys/netinet
 
 
 
index 7f440f6..ff91986 100644 (file)
@@ -5,6 +5,7 @@
  * provided that this notice is preserved and due credit is given
  * to the original author and the contributors.
  */
+
 #include <stdio.h>
 #include <string.h>
 #if !defined(__SVR4) && !defined(__svr4__)
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
+#include "ip_frag.h"
+#include "ip_state.h"
 #include <netdb.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
@@ -35,7 +39,7 @@
 #endif
 
 #ifndef        lint
-static char    sccsid[] = "@(#)fils.c  1.15 11/11/95 (C) 1993 Darren Reed";
+static char    sccsid[] = "@(#)fils.c  1.18 1/12/96 (C) 1993 Darren Reed";
 #endif
 #ifdef _PATH_UNIX
 #define        VMUNIX  _PATH_UNIX
@@ -44,21 +48,27 @@ static      char    sccsid[] = "@(#)fils.c  1.15 11/11/95 (C) 1993 Darren Reed";
 #endif
 
 extern char    *optarg;
-#define        F_ST    0
-#define        F_IN    1
-#define        F_OUT   2
-#define        F_FL    3
+
+#define        PRINTF  (void)printf
+#define        FPRINTF (void)fprintf
+#define        F_IN    0
+#define        F_OUT   1
+#define        F_AC    2
+static char    *filters[4] = { "ipfilter(in)", "ipfilter(out)",
+                               "ipacct(in)", "ipacct(out)" };
 
 int    opts = 0;
 
-static void    showstats();
-static void    showlist();
+static void    showstats(), showfrstates();
+static void    showlist(), showipstates();
 
 int main(argc,argv)
 int argc;
 char *argv[];
 {
-       struct  friostat        fio;
+       friostat_t fio;
+       ips_stat_t ipsst;
+       ipfrstat_t ifrst;
        char    c, *name = NULL, *device = IPL_NAME;
        int     fd;
 
@@ -68,13 +78,19 @@ char *argv[];
        (void)setuid(getuid());
        (void)setgid(getgid());
 
-       while ((c = getopt(argc, argv, "hIiovd:")) != -1)
+       while ((c = getopt(argc, argv, "afhIiosvd:")) != -1)
        {
                switch (c)
                {
+               case 'a' :
+                       opts |= OPT_ACCNT|OPT_SHOWLIST;
+                       break;
                case 'd' :
                        device = optarg;
                        break;
+               case 'f' :
+                       opts |= OPT_FRSTATES;
+                       break;
                case 'h' :
                        opts |= OPT_HITS;
                        break;
@@ -87,6 +103,9 @@ char *argv[];
                case 'o' :
                        opts |= OPT_OUTQUE|OPT_SHOWLIST;
                        break;
+               case 's' :
+                       opts |= OPT_IPSTATES;
+                       break;
                case 'v' :
                        opts |= OPT_VERBOSE;
                        break;
@@ -97,23 +116,40 @@ char *argv[];
                perror("open");
                exit(-1);
        }
+
        bzero((char *)&fio, sizeof(fio));
+       bzero((char *)&ipsst, sizeof(ipsst));
+       bzero((char *)&ifrst, sizeof(ifrst));
+
        if (ioctl(fd, SIOCGETFS, &fio) == -1) {
                perror("ioctl(SIOCGETFS)");
                exit(-1);
        }
+       if ((opts & OPT_IPSTATES) && (ioctl(fd, SIOCGIPST, &ipsst) == -1)) {
+               perror("ioctl(SIOCGIPST)");
+               exit(-1);
+       }
+       if ((opts & OPT_FRSTATES) && (ioctl(fd, SIOCGFRST, &ifrst) == -1)) {
+               perror("ioctl(SIOCGFRST)");
+               exit(-1);
+       }
 
        if (opts & OPT_VERBOSE)
-               printf("opts %#x name %s\n", opts, name ? name : "<>");
-       if (opts & OPT_SHOWLIST){
+               PRINTF("opts %#x name %s\n", opts, name ? name : "<>");
+       if (opts & OPT_SHOWLIST) {
                showlist(&fio);
                if((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){
                        opts &= ~OPT_OUTQUE;
                        showlist(&fio);
                }
+       } else {
+               if (opts & OPT_IPSTATES)
+                       showipstates(fd, &ipsst);
+               else if (opts & OPT_FRSTATES)
+                       showfrstates(fd, &ifrst);
+               else
+                       showstats(fd, &fio);
        }
-       else
-               showstats(fd, &fio);
        return 0;
 }
 
@@ -131,36 +167,46 @@ struct    friostat        *fp;
                perror("ioctl(SIOCGETFF)");
 
 #if SOLARIS
-       (void)printf("dropped packets:\tin %ld\tout %ld\n",
+       PRINTF("dropped packets:\tin %lu\tout %lu\n",
                        fp->f_st[0].fr_drop, fp->f_st[1].fr_drop);
-       (void)printf("non-ip packets:\t\tin %ld\tout %ld\n",
+       PRINTF("non-ip packets:\t\tin %lu\tout %lu\n",
                        fp->f_st[0].fr_notip, fp->f_st[1].fr_notip);
-       (void)printf("   bad packets:\t\tin %ld\tout %ld\n",
+       PRINTF("   bad packets:\t\tin %lu\tout %lu\n",
                        fp->f_st[0].fr_bad, fp->f_st[1].fr_bad);
 #endif
-       (void)printf(" input packets:\t\tblocked %ld passed %ld nomatch %ld\n",
+       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);
-       (void)printf("output packets:\t\tblocked %ld passed %ld nomatch %ld\n",
+       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);
-       (void)printf(" input packets logged:\tblocked %ld passed %ld\n",
+       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);
-       (void)printf("output packets logged:\tblocked %ld passed %ld\n",
+       PRINTF("output packets logged:\tblocked %lu passed %lu\n",
                        fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
-       (void)printf(" packets logged:\tinput %ld-%ld output %ld-%ld\n",
+       PRINTF(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
                        fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
                        fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
-       (void)printf("ICMP replies:\t%ld\tTCP RSTs sent:\t%ld\n",
+       PRINTF("fragment state(in):\tkept %lu\tlost %lu\n",
+                       fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr);
+       PRINTF("fragment state(out):\tkept %lu\tlost %lu\n",
+                       fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr);
+       PRINTF("packet state(in):\tkept %lu\tlost %lu\n",
+                       fp->f_st[0].fr_ads, fp->f_st[0].fr_bads);
+       PRINTF("packet state(out):\tkept %lu\tlost %lu\n",
+                       fp->f_st[1].fr_ads, fp->f_st[1].fr_bads);
+       PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n",
                        fp->f_st[0].fr_ret, fp->f_st[1].fr_ret);
 
-       (void)printf("Packet log flags set: (%#x)\n", frf);
+       PRINTF("Packet log flags set: (%#x)\n", frf);
        if (frf & FF_LOGPASS)
-               printf("\tpackets passed through filter\n");
+               PRINTF("\tpackets passed through filter\n");
        if (frf & FF_LOGBLOCK)
-               printf("\tpackets blocked by filter\n");
+               PRINTF("\tpackets blocked by filter\n");
        if (!frf)
-               printf("\tnone\n");
+               PRINTF("\tnone\n");
 }
 
 /*
@@ -173,25 +219,33 @@ struct    friostat        *fiop;
        struct  frentry *fp = NULL;
        int     i, set;
 
-       if (opts & OPT_OUTQUE)
-               i = F_OUT;
-       else if (opts & OPT_INQUE)
-               i = F_IN;
-       else
-               return;
        set = fiop->f_active;
        if (opts & OPT_INACTIVE)
                set = 1 - set;
-       fp = (i == F_IN) ? (struct frentry *)fiop->f_fin[set] :
-                          (struct frentry *)fiop->f_fout[set];
+       if (opts & OPT_ACCNT) {
+               i = F_AC;
+               if (opts & OPT_INQUE)
+                       fp = (struct frentry *)fiop->f_acctin[set];
+               else {
+                       fp = (struct frentry *)fiop->f_acctout[set];
+                       i++;
+               }
+       } else if (opts & OPT_OUTQUE) {
+               i = F_OUT;
+               fp = (struct frentry *)fiop->f_fout[set];
+       } else if (opts & OPT_INQUE) {
+               i = F_IN;
+               fp = (struct frentry *)fiop->f_fin[set];
+       } else
+               return;
        if (opts & OPT_VERBOSE)
-               (void)fprintf(stderr, "showlist:opts %#x i %d\n", opts, i);
+               FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i);
 
        if (opts & OPT_VERBOSE)
-               printf("fp %#x set %d\n", (u_int)fp, set);
+               PRINTF("fp %#x set %d\n", (u_int)fp, set);
        if (!fp) {
-               (void)fprintf(stderr, "empty list for filter%s\n",
-                       (i == F_IN) ? "in" : "out");
+               FPRINTF(stderr, "empty list for %s%s\n",
+                       (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]);
                return;
        }
        while (fp) {
@@ -203,10 +257,82 @@ struct    friostat        *fiop;
                if (opts & OPT_OUTQUE)
                        fp->fr_flags |= FR_OUTQUE;
                if (opts & (OPT_HITS|OPT_VERBOSE))
-                       printf("%d ", fp->fr_hits);
+                       PRINTF("%ld ", fp->fr_hits);
+               if (opts & (OPT_ACCNT|OPT_VERBOSE))
+                       PRINTF("%ld ", fp->fr_bytes);
                printfr(fp);
                if (opts & OPT_VERBOSE)
                        binprint(fp);
                fp = fp->fr_next;
        }
 }
+
+
+static void showipstates(fd, ipsp)
+int fd;
+ips_stat_t *ipsp;
+{
+       ipstate_t *istab[IPSTATE_SIZE], ips;
+       int i;
+
+       PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n",
+               ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp);
+       PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, ipsp->iss_miss);
+       PRINTF("\t%lu maximum\n\t%lu no memory\n",
+               ipsp->iss_max, ipsp->iss_nomem);
+       PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n",
+               ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin);
+       if (kmemcpy((char *)istab, (u_long)ipsp->iss_table, sizeof(istab)))
+               return;
+       for (i = 0; i < IPSTATE_SIZE; i++)
+               while (istab[i]) {
+                       if (kmemcpy(&ips, istab[i], sizeof(ips)) == -1)
+                               break;
+                       PRINTF("%s -> ", inet_ntoa(ips.is_src));
+                       PRINTF("%s age %d pass %d pr %d\n",
+                               inet_ntoa(ips.is_dst), ips.is_age,
+                               ips.is_pass, ips.is_p);
+                       if (ips.is_p == IPPROTO_TCP)
+                               PRINTF("\t%hu -> %hu %lu:%lu %hu\n",
+                                       ntohs(ips.is_sport),
+                                       ntohs(ips.is_dport),
+                                       ips.is_seq, ips.is_ack, ips.is_win);
+                       else if (ips.is_p == IPPROTO_UDP)
+                               PRINTF("\t%hu -> %hu\n", ntohs(ips.is_sport),
+                                       ntohs(ips.is_dport));
+                       else if (ips.is_p == IPPROTO_ICMP)
+                               PRINTF("\t%hu %hu %d\n", ips.is_icmp.ics_id,
+                                       ips.is_icmp.ics_seq,
+                                       ips.is_icmp.ics_type);
+                       istab[i] = ips.is_next;
+               }
+}
+
+
+static void showfrstates(fd, ifsp)
+int fd;
+ipfrstat_t *ifsp;
+{
+       struct ipfr *ipfrtab[IPFT_SIZE], ifr;
+       int i;
+
+       PRINTF("IP fragment states:\n\t%lu new\n\t%lu expired\n\t%lu hits\n",
+               ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits);
+       PRINTF("\t%lu no memory\n\t%lu already exist\n",
+               ifsp->ifs_nomem, ifsp->ifs_exists);
+       PRINTF("\t%lu inuse\n", ifsp->ifs_inuse);
+       if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab)))
+               return;
+       for (i = 0; i < IPFT_SIZE; i++)
+               while (ipfrtab[i]) {
+                       if (kmemcpy(&ifr, (u_long)ipfrtab[i],
+                                   sizeof(ifr)) == -1)
+                               break;
+                       PRINTF("%s -> ", inet_ntoa(ifr.ipfr_src));
+                       PRINTF("%s %d %d %d %#02x = %#x\n",
+                               inet_ntoa(ifr.ipfr_dst), ifr.ipfr_id,
+                               ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_tos,
+                               ifr.ipfr_pass);
+                       ipfrtab[i] = ifr.ipfr_next;
+               }
+}
index bfc8b2a..1b37854 100644 (file)
@@ -16,20 +16,28 @@ The default behaviour of \fBipfstat\fP
 is to retrieve and display the accumulated statistics which have been
 accumulated over time as the kernel has put packets through the filter.
 .SH OPTIONS
-.IP -o
-display the filter list used for the output side of the kernel IP processing.
-.IP -i
-display the filter list used for the input side of the kernel IP processing.
-.IP -v
-turn verbose mode on.  Displays more debugging information.
+.IP -a
+display the accounting filter list and show bytes counted against each rule.
 .IP -d <device>
 use a device other than \fB/dev/ipl\fP for interfacing with the kernel.
-.IP -I
-swap between retrieving "inactive"/"active" filter list details.  For use
-in combination with \fB-i\fP.
+.IP -f
+show fragment state information (statistics) and held state information (in
+the kernel) if any is present.
 .IP -h
 show per-rule the number of times each one scores a "hit".  For use in
 combination with \fB-i\fP.
+.IP -i
+display the filter list used for the input side of the kernel IP processing.
+.IP -I
+swap between retrieving "inactive"/"active" filter list details.  For use
+in combination with \fB-i\fP.
+.IP -o
+display the filter list used for the output side of the kernel IP processing.
+.IP -s
+show packet/flow state information (statistics) and held state information (in
+the kernel) if any is present.
+.IP -v
+turn verbose mode on.  Displays more debugging information.
 .SH SYNOPSIS
 The role of \fBipfstat\fP is to display current kernel statistics gathered
 as a result of applying the filters in place (if any) to packets going in and
index 4c0dbe3..159ff84 100644 (file)
@@ -10,6 +10,7 @@
  * returns 0 on success, -1 on error.
  */
 
+#include <stdio.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
@@ -19,7 +20,7 @@
 #define KMEM "/dev/kmem"
 
 #ifndef lint
-static  char    sccsid[] = "@(#)kmem.c 1.3 10/15/95 (C) 1992 Darren Reed";
+static  char    sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed";
 #endif
 
 static int     kmemfd = -1;
index 714c28c..9c57fdf 100644 (file)
@@ -232,6 +232,9 @@ file netinet/tcp_usrreq.c           inet
 file netinet/udp_usrreq.c              inet
 file netinet/ip_fil.c                  ipfilter
 file netinet/fil.c                     ipfilter
+file netinet/ip_nat.c                  ipfilter
+file netinet/ip_frag.c                 ipfilter
+file netinet/ip_state.c                        ipfilter
 file netiso/clnp_debug.c               iso
 file netiso/clnp_er.c                  iso
 file netiso/clnp_frag.c                        iso
index d1e0f0f..2a30b85 100644 (file)
@@ -183,6 +183,9 @@ netinet/tcp_usrreq.c        optional inet
 netinet/udp_usrreq.c   optional inet
 netinet/ip_fil.c       optional ipfilter requires inet
 netinet/fil.c          optional ipfilter requires inet
+netinet/ip_nat.c       optional ipfilter requires inet
+netinet/ip_frag.c      optional ipfilter requires inet
+netinet/ip_state.c     optional ipfilter requires inet
 netiso/clnp_debug.c    optional iso
 netiso/clnp_er.c       optional iso
 netiso/clnp_frag.c     optional iso
index b485678..60a3921 100644 (file)
@@ -6,7 +6,7 @@
  * to the original author and the contributors.
  */
 #ifndef        lint
-static char    sccsid[] = "@(#)fil.c   1.18 10/24/95 (C) 1993-1995 Darren Reed";
+static char    sccsid[] = "@(#)fil.c   1.26 1/14/96 (C) 1993-1996 Darren Reed";
 #endif
 
 #ifndef        linux
@@ -17,6 +17,8 @@ static        char    sccsid[] = "@(#)fil.c   1.18 10/24/95 (C) 1993-1995 Darren Reed";
 # include <sys/ioctl.h>
 # if defined(_KERNEL) || defined(KERNEL)
 #  include <sys/systm.h>
+# else
+#  include <string.h>
 # endif
 # include <sys/uio.h>
 # if !defined(__SVR4) && !defined(__svr4__)
@@ -43,7 +45,10 @@ static       char    sccsid[] = "@(#)fil.c   1.18 10/24/95 (C) 1993-1995 Darren Reed";
 # include <netinet/tcpip.h>
 # include <netinet/ip_icmp.h>
 #endif
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
+#include "ip_nat.h"
+#include "ip_frag.h"
+#include "ip_state.h"
 #ifndef        MIN
 #define        MIN(a,b)        (((a)<(b))?(a):(b))
 #endif
@@ -57,20 +62,48 @@ extern      void    debug(), verbose();
 #define        FR_IFDEBUG(ex,second,verb_pr)   if (ex) { debug verb_pr; second; }
 #define        FR_VERBOSE(verb_pr)     verbose verb_pr
 #define        FR_DEBUG(verb_pr)       debug verb_pr
+#define        FR_SCANLIST(p, ip, if, fi, m)   fr_scanlist(p, ip, ifp, fi)
 #else
 #define        FR_IFVERBOSE(ex,second,verb_pr) ;
 #define        FR_IFDEBUG(ex,second,verb_pr)   ;
 #define        FR_VERBOSE(verb_pr)
 #define        FR_DEBUG(verb_pr)
-
+extern int     send_reset();
+# if SOLARIS
+extern int     icmp_error();
+extern kmutex_t        ipf_mutex;
+# define       FR_SCANLIST(p, ip, if, fi, m)   fr_scanlist(p, ip, ifp, fi)
+# else
+# define       FR_SCANLIST(p, ip, if, fi, m)   fr_scanlist(p, ip, ifp, fi, m)
+# endif
 extern int     ipl_unreach, ipllog();
 #endif
 
+#if SOLARIS
+# define       IPLLOG(fl, ip, if, fi, m)       ipllog(fl, ip, if, fi)
+# define       SEND_RESET(ip, if, q)           send_reset(ip, qif, q)
+# define       ICMP_ERROR(b, ip, t, c, if, src) \
+                       icmp_error(b, ip, t, c, if, src)
+#else
+#ifdef _KERNEL
+# define       IPLLOG(fl, ip, if, fi, m)       ipllog(fl, ip, if, fi, m)
+#else
+# define        IPLLOG(fl, ip, if, fi, m)       ipllog()
+#endif
+# define       SEND_RESET(ip, if, q)           send_reset(ip)
+# if BSD < 199103
+#  define      ICMP_ERROR(b, ip, t, c, if, src) \
+                       icmp_error(mtod(b, ip_t *), t, c, if, src)
+# else
+#  define      ICMP_ERROR(b, ip, t, c, if, src) \
+                       icmp_error(b, t, c, (src).s_addr, if)
+# endif
+#endif
+
 struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
-struct frentry *filterin[2] = { NULL, NULL },
-               *filterout[2] = { NULL, NULL };
+struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
+               *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
 int    fr_flags = 0, fr_active = 0;
-int    fr_check();
 
  
 /*
@@ -128,18 +161,28 @@ ip_t *ip;
        int i, mv, ol, off;
        u_char *s, opt;
 
+#ifdef _KERNEL
+       fi.fi_icode = ipl_unreach;
+#endif
        fi.fi_fl = 0;
        fi.fi_v = ip->ip_v;
        fi.fi_tos = ip->ip_tos;
+       fi.fi_hlen = hlen;
        (*(((u_short *)&fi) + 1)) = (*(((u_short *)ip) + 4));
        (*(((u_long *)&fi) + 1)) = (*(((u_long *)ip) + 3));
        (*(((u_long *)&fi) + 2)) = (*(((u_long *)ip) + 4));
 
        if (hlen > sizeof(struct ip))
                fi.fi_fl |= FI_OPTIONS;
+#if    SOLARIS
+       off = (ntohs(ip->ip_off) & 0x1fff) << 3;
+       if (ntohs(ip->ip_off) & 0x3fff)
+               fi.fi_fl |= FI_FRAG;
+#else
        off = (ip->ip_off & 0x1fff) << 3;
        if (ip->ip_off & 0x3fff)
                fi.fi_fl |= FI_FRAG;
+#endif
        switch (ip->ip_p)
        {
        case IPPROTO_ICMP :
@@ -314,24 +357,22 @@ struct frentry *fr;
  * Could be per interface, but this gets real nasty when you don't have
  * kernel sauce.
  */
-int fr_scanlist(pass, ip, hlen, ifp, out, rule)
+int fr_scanlist(pass, ip, ifp, fi, m)
 int pass;
 ip_t *ip;
-int hlen, out;
 struct ifnet *ifp;
-u_short *rule;
+register struct fr_ip *fi;
+void *m;
 {
        register struct frentry *fr;
-       register struct fr_ip *fi;
        tcphdr_t *tcp;
        int     rulen;
 
-       *rule = 1;
-       tcp = (tcphdr_t *)((char *)ip + hlen);
-       fr = (out) ? filterout[fr_active] : filterin[fr_active];
-       fi = fr_makefrip(hlen, ip);
+       fi->fi_rule = 0;
+       tcp = (tcphdr_t *)((char *)ip + fi->fi_hlen);
+       pass |= (fi->fi_fl << 20);
 
-       for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
+       for (rulen = 0, fr = fi->fi_fr; fr; fr = fr->fr_next, rulen++) {
                /*
                 * In all checks below, a null (zero) value in the
                 * filter struture is taken to mean a wildcard.
@@ -345,7 +386,7 @@ u_short *rule;
                if (opts & (OPT_VERBOSE|OPT_DEBUG))
                        printf("\n");
                FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 'b'));
-               if (ifp && *fr->fr_ifname && strcasecmp(ifp->if_name,
+               if (ifp && *fr->fr_ifname && strcasecmp((char *)ifp,
                                                        fr->fr_ifname))
                        continue;
                FR_VERBOSE((":i"));
@@ -380,15 +421,15 @@ u_short *rule;
                 * If a fragment, then only the first has what we're looking
                 * for here...
                 */
-               if (!(ip->ip_off & 0x1fff)) {
+               if (!(ntohs(ip->ip_off) & 0x1fff)) {
                        if ((fi->fi_fl & FI_TCPUDP) &&
                            !fr_tcpudpchk(ip, tcp, fr))
                                continue;
                        else if (ip->ip_p == IPPROTO_ICMP &&
-                                  (*(u_short *)((char *)ip + hlen) &
+                                  (*(u_short *)((char *)ip + fi->fi_hlen) &
                                     fr->fr_icmpm) != fr->fr_icmp) {
                                FR_DEBUG(("i. %#x & %#x != %#x\n",
-                                        *(u_short *)((char *)ip + hlen),
+                                        *(u_short *)((char *)ip + fi->fi_hlen),
                                         fr->fr_icmpm, fr->fr_icmp));
                                continue;
                        }
@@ -401,15 +442,22 @@ u_short *rule;
                 */
                if (fr->fr_flags & FR_LOG) {
 #ifdef IPFILTER_LOG
-                       if (!ipllog(hlen, fr->fr_flags, ip, ifp, *rule))
-                               frstats[out].fr_skip++;
-                       frstats[out].fr_pkl++;
+                       if (!IPLLOG(fr->fr_flags, ip, ifp, fi, m))
+                               frstats[fi->fi_out].fr_skip++;
+                       frstats[fi->fi_out].fr_pkl++;
 #endif /* IPFILTER_LOG */
                } else
                        pass = fr->fr_flags;
                FR_DEBUG(("pass %#x\n", pass));
                fr->fr_hits++;
-               *rule = rulen;
+               fi->fi_rule = rulen;
+               fi->fi_icode = fr->fr_icode;
+               if (pass & FR_ACCOUNT)
+                       fr->fr_bytes += ip->ip_len;
+               else {
+                       fi->fi_rule = rulen;
+                       fi->fi_icode = fr->fr_icode;
+               }
                if (pass & FR_QUICK)
                        break;
        }
@@ -423,10 +471,15 @@ u_short *rule;
  * or not to pass it on or not.
  */
 int fr_check(ip, hlen, ifp, out
-#if SOLARIS && defined(_KERNEL)
+#ifdef _KERNEL
+# if SOLARIS
 , qif, q)
 qif_t *qif;
 queue_t *q;
+# else
+, mp)
+struct mbuf **mp;
+# endif
 #else
 )
 #endif
@@ -435,38 +488,98 @@ int hlen;
 struct ifnet *ifp;
 int out;
 {
-       int pass = FR_NOMATCH;
-       int sl;
-       u_short rule;
+       /*
+        * The above really sucks, but short of writing a diff
+        */
+       register struct fr_ip *fi;
+       int pass;
+
+#if !defined(__SVR4) && !defined(__svr4__) && defined(_KERNEL)
+       register struct mbuf *m = *mp;
+
+       if (!out && (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
+            ip->ip_p == IPPROTO_ICMP)) {
+               register int up = MIN(hlen + 8, ip->ip_len);
+
+               if ((up > m->m_len)) {
+                       if ((*mp = m_pullup(m, up)) == 0)
+                               return -1;
+                       else {
+                               m = *mp;
+                               ip = mtod(m, struct ip *);
+                       }
+               }
+       }
+#endif
+       fi = fr_makefrip(hlen, ip);
+       fi->fi_out = out;
 
-       SPLNET(sl);
+       MUTEX_ENTER(&ipf_mutex);
+       if (!out) {
+               ip_natin(ifp, ip, hlen);
+               if ((fi->fi_fr = ipacct[0][fr_active]) &&
+                   (FR_SCANLIST(FR_NOMATCH, ip, ifp, fi, m) & FR_ACCOUNT))
+                       frstats[0].fr_acct++;
+       }
 
-       pass = fr_scanlist(pass, ip, hlen, ifp, out, &rule);
-       if (pass == FR_NOMATCH) {
-               frstats[out].fr_nom++;
+       if (!(pass = ipfr_knownfrag(ip)) &&
+           !(pass = fr_checkstate(ip, hlen))) {
+               pass = FR_NOMATCH;
+               if ((fi->fi_fr = ipfilter[out][fr_active]))
+                       pass = FR_SCANLIST(FR_NOMATCH, ip, ifp, fi, m);
+               if (pass & FR_NOMATCH) {
+                       frstats[out].fr_nom++;
 #ifdef NOMATCH
-               pass |= NOMATCH;
+                       pass |= NOMATCH;
 #endif
+               }
+               if (pass & FR_KEEPFRAG) {
+                       if (ipfr_newfrag(ip, pass) == -1)
+                               frstats[out].fr_bnfr++;
+                       else
+                               frstats[out].fr_nfr++;
+               }
+               if (pass & FR_KEEPSTATE) {
+                       if (fr_addstate(ip, hlen, pass) == -1)
+                               frstats[out].fr_bads++;
+                       else
+                               frstats[out].fr_ads++;
+               }
+       } else if (pass & FR_LOGFIRST)
+               pass &= ~(FR_LOGFIRST|FR_LOG);
+
+
+       if (out) {
+               if ((fi->fi_fr = ipacct[1][fr_active]) &&
+                   (FR_SCANLIST(FR_NOMATCH, ip, ifp, fi, m) & FR_ACCOUNT))
+                       frstats[1].fr_acct++;
+               ip_natout(ifp, ip, hlen);
        }
+       MUTEX_EXIT(&ipf_mutex);
 
 #ifdef IPFILTER_LOG
-       if ((pass & FR_LOGP) ||
+       if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
+               pass |= FF_LOGNOMATCH;
+               if (!IPLLOG(pass, ip, ifp, fi, m))
+                       frstats[out].fr_skip++;
+               frstats[out].fr_npkl++;
+       } else if (((pass & FR_LOGP) == FR_LOGP) ||
            ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
-               if (!(pass & FR_LOGP))
-                       pass |= FF_LOGPASS << 8;
-               if (!ipllog(hlen, pass, ip, ifp, rule))
+               if ((pass & FR_LOGP) != FR_LOGP)
+                       pass |= FF_LOGPASS;
+               if (!IPLLOG(pass, ip, ifp, fi, m))
                        frstats[out].fr_skip++;
                frstats[out].fr_ppkl++;
-       } else if ((pass & FR_LOGB) ||
+       } else if (((pass & FR_LOGB) == FR_LOGB) ||
                   ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
-               if (!(pass & FR_LOGB))
-                       pass |= FF_LOGBLOCK << 8;
-               if (!ipllog(hlen, pass, ip, ifp, rule))
+               if ((pass & FR_LOGB) != FR_LOGB)
+                       pass |= FF_LOGBLOCK;
+               if (!IPLLOG(pass, ip, ifp, fi, m))
                        frstats[out].fr_skip++;
                frstats[out].fr_bpkl++;
        }
 #endif /* IPFILTER_LOG */
-       SPLX(sl);
+
        if (pass & FR_PASS)
                frstats[out].fr_pass++;
        else if (pass & FR_BLOCK) {
@@ -474,33 +587,21 @@ int out;
                /*
                 * Should we return an ICMP packet to indicate error
                 * status passing through the packet filter ?
-                * XXX - copy mbuf as icmp_error() calls mfree() - fix this
-                * later, but preserve backward compatibility for now.
                 */
 #ifdef _KERNEL
                if (pass & FR_RETICMP) {
 # if SOLARIS
-                       icmp_error(q, ip, ICMP_UNREACH, ipl_unreach, qif,
-                                  ip->ip_src);
+                       ICMP_ERROR(q, ip, ICMP_UNREACH, fi->fi_icode,
+                                  qif, ip->ip_src);
 # else
-                       struct mbuf *copy;
-
-                       copy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64));
-#  if BSD < 199103
-                       icmp_error(mtod(copy, struct ip *),
-                                  ICMP_UNREACH, ipl_unreach, ifp, ip->ip_src);
-#  else
-                       icmp_error(copy, ICMP_UNREACH, ipl_unreach,
-                                  ip->ip_src.s_addr, ifp);
-#  endif
+                       ICMP_ERROR(m, ip, ICMP_UNREACH, fi->fi_icode,
+                                  ifp, ip->ip_src);
+                       m = NULL;       /* freed by icmp_error() */
 # endif
+
                        frstats[0].fr_ret++;
                } else if (pass & FR_RETRST && IPMINLEN(ip, tcphdr)) {
-# if SOLARIS
-                       if (send_reset(ip, qif, q) == 0)
-# else
-                       if (send_reset(ip) == 0)
-# endif
+                       if (SEND_RESET(ip, qif, q) == 0)
                                frstats[1].fr_ret++;
                }
 #else
@@ -514,6 +615,10 @@ int out;
 #endif
        }
 #ifdef _KERNEL
+# if   !SOLARIS
+       if (!(pass & FR_PASS) && m)
+               m_freem(m);
+# endif
        return (pass & FR_PASS) ? 0 : -1;
 #else
        if (pass & FR_NOMATCH)
@@ -529,6 +634,5 @@ int out;
 int ipllog()
 {
        verbose("l");
-       return 1;
 }
 #endif
index f234291..24ab8a5 100644 (file)
@@ -6,7 +6,7 @@
  * to the original author and the contributors.
  */
 #ifndef        lint
-static char    sccsid[] = "@(#)ip_fil.c        2.26 11/8/95 (C) 1993-1995 Darren Reed";
+static char    sccsid[] = "@(#)ip_fil.c        2.31 1/14/96 (C) 1993-1995 Darren Reed";
 #endif
 
 #ifndef        linux
@@ -38,16 +38,23 @@ static      char    sccsid[] = "@(#)ip_fil.c        2.26 11/8/95 (C) 1993-1995 Darren Reed";
 #include <syslog.h>
 #endif
 #include "ip_fil.h"
+#include "ip_frag.h"
+#include "ip_nat.h"
+#include "ip_state.h"
 #ifndef        MIN
 #define        MIN(a,b)        (((a)<(b))?(a):(b))
 #endif
 
 extern fr_flags, fr_active;
-extern int     fr_check(), (*fr_checkp)();
+extern struct  protosw inetsw[];
+extern int     (*fr_checkp)();
 #if    BSD < 199306
+extern int     ipfr_slowtimer();
+static int     (*fr_saveslowtimo)();
 extern int     tcp_ttl;
 #else
-extern int     ip_defttl;
+extern void    ipfr_slowtimer();
+static void    (*fr_saveslowtimo)();
 #endif
 
 int    ipl_inited = 0;
@@ -75,6 +82,7 @@ char *s;
                return 1;
        return 0;
 }
+#endif /* IPFILTER_LKM */
 
 
 int iplattach()
@@ -90,7 +98,13 @@ int iplattach()
        ipl_inited = 1;
        fr_savep = fr_checkp;
        fr_checkp = fr_check;
-
+#if BSD >= 199306
+       fr_saveslowtimo = inetsw[0].pr_slowtimo;
+       inetsw[0].pr_slowtimo = ipfr_slowtimer;
+#else
+       fr_saveslowtimo = inetsw[0].pr_slowtimo;
+       inetsw[0].pr_slowtimo = ipfr_slowtimer;
+#endif
        SPLX(s);
        return 0;
 }
@@ -113,13 +127,17 @@ int ipldetach()
        }
 
        fr_checkp = fr_savep;
+       inetsw[0].pr_slowtimo = fr_saveslowtimo;
        frflush((caddr_t)&i);
        ipl_inited = 0;
 
+       ipfr_unload();
+       ip_natunload();
+       fr_stateunload();
+
        SPLX(s);
        return 0;
 }
-#endif /* IPFILTER_LKM */
 
 
 static void    frzerostats(data)
@@ -129,10 +147,14 @@ caddr_t   data;
 
        bcopy((char *)frstats, (char *)fio.f_st,
                sizeof(struct filterstats) * 2);
-       fio.f_fin[0] = filterin[0];
-       fio.f_fin[1] = filterin[1];
-       fio.f_fout[0] = filterout[0];
-       fio.f_fout[1] = filterout[1];
+       fio.f_fin[0] = ipfilter[0][0];
+       fio.f_fin[1] = ipfilter[0][1];
+       fio.f_fout[0] = ipfilter[1][0];
+       fio.f_fout[1] = ipfilter[1][1];
+       fio.f_acctin[0] = ipacct[0][0];
+       fio.f_acctin[1] = ipacct[0][1];
+       fio.f_acctout[0] = ipacct[1][0];
+       fio.f_acctout[1] = ipacct[1][1];
        fio.f_active = fr_active;
        IWCOPY((caddr_t)&fio, data, sizeof(fio));
        bzero((char *)frstats, sizeof(*frstats));
@@ -143,22 +165,34 @@ static void frflush(data)
 caddr_t data;
 {
        struct frentry *f, **fp;
-       int flags = *(int *)data, flushed = 0, set = fr_active;
+       int flags = *(int *)data, flushed = 0, set = fr_active, in;
 
        if (flags & FR_INACTIVE)
                set = 1 - set;
-       if (flags & FR_OUTQUE)
-               for (fp = &filterout[set]; (f = *fp); ) {
+       if (flags & FR_OUTQUE) {
+               for (fp = &ipfilter[1][set]; (f = *fp); ) {
                        *fp = f->fr_next;
                        KFREE(f);
                        flushed++;
                }
-       if (flags & FR_INQUE)
-               for (fp = &filterin[set]; (f = *fp); ) {
+               for (fp = &ipacct[1][set]; (f = *fp); ) {
+                       *fp = f->fr_next;
+                       KFREE(f);
+                       flushed++;
+               }
+       }
+       if (flags & FR_INQUE) {
+               for (fp = &ipfilter[0][set]; (f = *fp); ) {
                        *fp = f->fr_next;
                        KFREE(f);
                        flushed++;
                }
+               for (fp = &ipacct[0][set]; (f = *fp); ) {
+                       *fp = f->fr_next;
+                       KFREE(f);
+                       flushed++;
+               }
+       }
 
        *(int *)data = flushed;
 }
@@ -187,13 +221,10 @@ int mode;
                u_int   enable;
 
                IRCOPY(data, (caddr_t)&enable, sizeof(enable));
-               if (enable) {
-                       if (fr_checkp != fr_check) {
-                               fr_savep = fr_checkp;
-                               fr_checkp = fr_check;
-                       }
-               } else
-                       fr_checkp = fr_savep;
+               if (enable)
+                       error = iplattach();
+               else
+                       error = ipldetach();
                break;
        }
 #endif
@@ -223,10 +254,14 @@ int mode;
 
                bcopy((char *)frstats, (char *)fio.f_st,
                        sizeof(struct filterstats) * 2);
-               fio.f_fin[0] = filterin[0];
-               fio.f_fin[1] = filterin[1];
-               fio.f_fout[0] = filterout[0];
-               fio.f_fout[1] = filterout[1];
+               fio.f_fin[0] = ipfilter[0][0];
+               fio.f_fin[1] = ipfilter[0][1];
+               fio.f_fout[0] = ipfilter[1][0];
+               fio.f_fout[1] = ipfilter[1][1];
+               fio.f_acctin[0] = ipacct[0][0];
+               fio.f_acctin[1] = ipacct[0][1];
+               fio.f_acctout[0] = ipacct[1][0];
+               fio.f_acctout[1] = ipacct[1][1];
                fio.f_active = fr_active;
                IWCOPY((caddr_t)&fio, data, sizeof(fio));
                break;
@@ -244,6 +279,17 @@ int mode;
                iplused = 0;
                break;
 #endif /* IPFILTER_LOG */
+       case SIOCADNAT :
+       case SIOCRMNAT :
+       case SIOCGNATS :
+               error = nat_ioctl(data, cmd);
+               break;
+       case SIOCGFRST :
+               IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t));
+               break;
+       case SIOCGIPST :
+               IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t));
+               break;
        default :
                error = -EINVAL;
                break;
@@ -260,12 +306,13 @@ register struct frentry *fp;
        register struct frentry *f, **fprev;
        register struct frentry **ftail;
        struct frentry frd;
-       int error = 0;
+       int error = 0, in;
 
-       if (fp->fr_flags & FR_OUTQUE)
-               ftail = fprev = &filterout[set];
-       else if (fp->fr_flags & FR_INQUE)
-               ftail = fprev = &filterin[set];
+       in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
+       if (fp->fr_flags & FR_ACCOUNT) {
+               ftail = fprev = &ipacct[in][set];
+       } else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE))
+               ftail = fprev = &ipfilter[in][set];
        else
                return ESRCH;
 
@@ -411,20 +458,20 @@ register struct uio *uio;
 
 
 #ifdef IPFILTER_LOG
-int ipllog(hlen, flags, ip, ifp, rule)
-register int hlen;
+int ipllog(flags, ip, ifp, fi, m)
 u_int flags;
 ip_t *ip;
 struct ifnet *ifp;
-u_short rule;
+register struct fr_ip *fi;
+struct mbuf *m;
 {
        struct ipl_ci iplci;
        register size_t tail = 0;
-       register int len, mlen;
-       register struct mbuf *m = dtom(ip);
+       register int len, mlen, hlen;
 
+       hlen = fi->fi_hlen;
        if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
-               hlen += sizeof(tcphdr_t);
+               hlen += MIN(sizeof(tcphdr_t), ip->ip_len - hlen);
        else if (ip->ip_p == IPPROTO_ICMP) {
                struct  icmp    *icmp = (struct icmp *)((char *)ip + hlen);
 
@@ -434,9 +481,11 @@ u_short rule;
                case ICMP_REDIRECT :
                case ICMP_TIMXCEED :
                case ICMP_PARAMPROB :
-                       hlen += 8;
+                       hlen += MIN(sizeof(struct icmp) + 8, ip->ip_len - hlen);
+                       break;
                default :
-                       hlen += sizeof(struct icmp);
+                       hlen += MIN(sizeof(struct icmp), ip->ip_len - hlen);
+                       break;
                }
        }
 
@@ -455,7 +504,7 @@ u_short rule;
        iplci.flags = flags;
        iplci.hlen = (u_char)hlen;
        iplci.plen = (flags & FR_LOGBODY) ? (u_char)mlen : 0 ;
-       iplci.rule = rule;
+       iplci.rule = fi->fi_rule;
        iplci.unit = (u_char)ifp->if_unit;
        iplci.ifname[0] = ifp->if_name[0];
        iplci.ifname[1] = ifp->if_name[1];
index 8d4380d..67e985a 100644 (file)
@@ -5,17 +5,20 @@
  * provided that this notice is preserved and due credit is given
  * to the original author and the contributors.
  *
- * @(#)ip_fil.h        1.23 11/11/95
+ * @(#)ip_fil.h        1.29 1/12/96
  */
 
 #ifndef        __IP_FIL_H_
 #define        __IP_FIL_H__
 
 #ifndef IPFILTER_LOG
-#define IPFILTER_LOG 1
+#define IPFILTER_LOG
 #endif
 
+#ifndef        SOLARIS
 #define        SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+
 #if defined(KERNEL) && !defined(_KERNEL)
 #define        _KERNEL
 #endif
@@ -84,18 +87,24 @@ typedef     struct  fr_ip   {
        u_long  fi_optmsk;
        u_short fi_secmsk;
        u_short fi_auth;
+       u_short fi_out;
+       u_short fi_rule;
+       u_short fi_hlen;
+       u_char  fi_icode;
+       struct  frentry *fi_fr;
 } fr_ip_t;
 
-#define        FI_SHORT        0x01
-#define        FI_OPTIONS      0x02
+#define        FI_OPTIONS      0x01
+#define        FI_TCPUDP       0x02    /* TCP/UCP implied comparison involved */
 #define        FI_FRAG         0x04
-#define        FI_TCPUDP       0x08    /* TCP/UCP implied comparison involved */
+#define        FI_SHORT        0x08
 
 typedef        struct  frentry {
        struct  frentry *fr_next;
        struct  ifnet   *fr_ifa;
-       u_int   fr_hits;
-
+       u_long  fr_hits;
+       u_long  fr_bytes;       /* this is only incremented when a packet */
+                               /* stops matching on this rule */
        /*
         * Fields after this may not change whilst in the kernel.
         */
@@ -114,7 +123,8 @@ typedef     struct  frentry {
        u_short fr_sport;
        u_short fr_stop;        /* top port for <> and >< */
        u_short fr_dtop;        /* top port for <> and >< */
-       u_short fr_flags;       /* per-rule flags && options (see below) */
+       u_long  fr_flags;       /* per-rule flags && options (see below) */
+       char    fr_icode;       /* return ICMP code */
        char    fr_ifname[IFNAMSIZ];
 } frentry_t;
 
@@ -133,20 +143,30 @@ typedef   struct  frentry {
 
 /*
  * fr_flags
- */
+*/
 #define        FR_BLOCK        0x0001
 #define        FR_PASS         0x0002
 #define        FR_OUTQUE       0x0004
 #define        FR_INQUE        0x0008
-#define        FR_LOGP         0x0010  /* Log-pass */
-#define        FR_LOGB         0x0020  /* Log-fail */
-#define        FR_LOG          0x0040  /* Log */
-#define        FR_LOGBODY      0x0080  /* Log the body */
-#define        FR_QUICK        0x0100
-#define        FR_RETRST       0x0200
-#define        FR_RETICMP      0x0400
-#define        FR_INACTIVE     0x0800
-#define        FR_NOMATCH      0x1000
+#define        FR_LOG          0x0010  /* Log */
+#define        FR_LOGB         0x0021  /* Log-fail */
+#define        FR_LOGP         0x0022  /* Log-pass */
+#define        FR_LOGBODY      0x0040  /* Log the body */
+#define        FR_LOGFIRST     0x0080
+#define        FR_RETRST       0x0100
+#define        FR_RETICMP      0x0200
+#define        FR_NOMATCH      0x0400
+#define        FR_ACCOUNT      0x0800  /* count packet bytes */
+#define        FR_KEEPFRAG     0x1000
+#define        FR_KEEPSTATE    0x2000
+#define        FR_INACTIVE     0x4000
+#define        FR_QUICK        0x8000
+/*
+ * recognized flags for SIOCGETFF and SIOCSETFF
+ */
+#define        FF_LOGPASS      0x100000
+#define        FF_LOGBLOCK     0x200000
+#define        FF_LOGNOMATCH   0x400000
 
 #define        FR_NONE 0
 #define        FR_EQUAL 1
@@ -164,9 +184,15 @@ typedef    struct  filterstats {
        u_long  fr_nom;         /* packets which don't match any rule */
        u_long  fr_ppkl;        /* packets allowed and logged */
        u_long  fr_bpkl;        /* packets denied and logged */
+       u_long  fr_npkl;        /* packets unmatched and logged */
        u_long  fr_pkl;         /* packets logged */
        u_long  fr_skip;        /* packets to be logged but buffer full */
        u_long  fr_ret;         /* packets for which a return is sent */
+       u_long  fr_acct;        /* packets for which counting was performed */
+       u_long  fr_bnfr;        /* bad attempts to allocate fragment state */
+       u_long  fr_nfr;         /* new fragment state kept */
+       u_long  fr_bads;        /* bad attempts to allocate packet state */
+       u_long  fr_ads;         /* new packet state kept */
 #if SOLARIS
        u_long  fr_bad;         /* bad IP packets to the filter */
        u_long  fr_notip;       /* packets passed through no on ip queue */
@@ -174,12 +200,6 @@ typedef    struct  filterstats {
 #endif
 } filterstats_t;
 
-/*
- * recognized flags for SIOCGETFF and SIOCSETFF
- */
-#define        FF_LOGPASS      1
-#define        FF_LOGBLOCK     2
-
 /*
  * For SIOCGETFS
  */
@@ -187,6 +207,8 @@ typedef     struct  friostat        {
        struct  filterstats     f_st[2];
        struct  frentry         *f_fin[2];
        struct  frentry         *f_fout[2];
+       struct  frentry         *f_acctin[2];
+       struct  frentry         *f_acctout[2];
        int     f_active;
 } friostat_t;
 
@@ -195,11 +217,6 @@ typedef struct  optlist {
        int     ol_bit;
 } optlist_t;
 
-#ifdef _KERNEL
-extern struct frentry *filterin[], *filterout[];
-extern struct filterstats frstats[];
-#endif
-
 typedef        struct ipl_ci   {
        u_long  sec;
        u_long  usec;
@@ -211,26 +228,143 @@ typedef  struct ipl_ci   {
        u_char  ifname[4];
 } ipl_ci_t;
 
-#ifdef _KERNEL
 
-typedef        struct  ipfr    {
-       struct  ipfr    *ipfr_next, *ipfr_prev;
-       struct  in_addr ipfr_src;
-       struct  in_addr ipfr_dst;
-       u_short ipfr_id;
-       u_short ipfr_age;
-       u_char  ipfr_p;
-       u_char  ipfr_tos;
-       u_char  ipfr_pass;
-} ipfr_t;
+#ifndef        ICMP_UNREACH_FILTER
+#define        ICMP_UNREACH_FILTER     13
+#endif
+/*
+ * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108.
+ *
+ * Basic Option
+ *
+ * 00000001   -   (Reserved 4)
+ * 00111101   -   Top Secret
+ * 01011010   -   Secret
+ * 10010110   -   Confidential
+ * 01100110   -   (Reserved 3)
+ * 11001100   -   (Reserved 2)
+ * 10101011   -   Unclassified
+ * 11110001   -   (Reserved 1)
+ */
+#define        IPSO_CLASS_RES4         0x01
+#define        IPSO_CLASS_TOPS         0x3d
+#define        IPSO_CLASS_SECR         0x5a
+#define        IPSO_CLASS_CONF         0x96
+#define        IPSO_CLASS_RES3         0x66
+#define        IPSO_CLASS_RES2         0xcc
+#define        IPSO_CLASS_UNCL         0xab
+#define        IPSO_CLASS_RES1         0xf1
+
+#define        IPSO_AUTH_GENSER        0x80
+#define        IPSO_AUTH_ESI           0x40
+#define        IPSO_AUTH_SCI           0x20
+#define        IPSO_AUTH_NSA           0x10
+#define        IPSO_AUTH_DOE           0x08
+#define        IPSO_AUTH_UN            0x06
+#define        IPSO_AUTH_FTE           0x01
+
+/*#define      IPOPT_RR        7 */
+#define        IPOPT_ZSU       10      /* ZSU */
+#define        IPOPT_MTUP      11      /* MTUP */
+#define        IPOPT_MTUR      12      /* MTUR */
+#define        IPOPT_ENCODE    15      /* ENCODE */
+/*#define      IPOPT_TS        68 */
+#define        IPOPT_TR        82      /* TR */
+/*#define      IPOPT_SECURITY  130 */
+/*#define      IPOPT_LSRR      131 */
+#define        IPOPT_E_SEC     133     /* E-SEC */
+#define        IPOPT_CIPSO     134     /* CIPSO */
+/*#define      IPOPT_SATID     136 */
+#ifndef        IPOPT_SID
+# define       IPOPT_SID       IPOPT_SATID
+#endif
+/*#define      IPOPT_SSRR      137 */
+#define        IPOPT_ADDEXT    147     /* ADDEXT */
+#define        IPOPT_VISA      142     /* VISA */
+#define        IPOPT_IMITD     144     /* IMITD */
+#define        IPOPT_EIP       145     /* EIP */
+#define        IPOPT_FINN      205     /* FINN */
+
+#define        IPMINLEN(i, h)  ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
+
+extern int     fr_check();
+
+#ifdef _KERNEL
+
+extern struct frentry *ipfilter[2][2], *ipacct[2][2];
+extern struct filterstats frstats[];
+# if   SOLARIS
+extern int     ipfsync();
+# endif
+#endif /* _KERNEL */
+
+#ifndef        SOLARIS
+#define        SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+#define        IPMINLEN(i, h)  ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
 
-#define        IPFR_CMPSZ      (4 + 4 + 2 + 1 + 1)
+#ifndef        IP_OFFMASK
+#define        IP_OFFMASK      0x1fff
+#endif
 
-# if defined(sun) && !defined(linux)
+#ifndef        MAX
+#define        MAX(a,b)        (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifdef _KERNEL
+# if SOLARIS
+#  define      MUTEX_ENTER(x)  mutex_enter(x)
+#  define      MUTEX_EXIT(x)   mutex_exit(x)
+#  define      MTOD(m,t)       (t)((m)->b_rptr)
+#  define      IRCOPY(a,b,c)   copyin((a), (b), (c))
+#  define      IWCOPY(a,b,c)   copyout((a), (b), (c))
+# else
+#  define      MUTEX_ENTER(x)  ;
+#  define      MUTEX_EXIT(x)   ;
+#  ifndef linux
+#   define     MTOD(m,t)       mtod(m,t)
+#   define     IRCOPY(a,b,c)   bcopy((a), (b), (c))
+#   define     IWCOPY(a,b,c)   bcopy((a), (b), (c))
+#  endif
+# endif /* SOLARIS */
+
+# ifdef sun
+#  if defined(__svr4__) || defined(__SVR4)
+#   define     GETUNIT(n)      get_unit((n))
+#  else
+#   include    <sys/kmem_alloc.h>
+#   define     GETUNIT(n)      ifunit((n), IFNAMSIZ)
+#  endif
+# else
+#  define      GETUNIT(n)      ifunit((n))
+# endif /* sun */
+
+# if defined(sun) && !defined(linux) && !defined(__NetBSD__) && !defined (__OpenBSD__)
 #  define      UIOMOVE(a,b,c,d)        uiomove(a,b,c,d)
 #  define      SLEEP(id, n)    sleep((id), PZERO+1)
 #  define      KFREE(x)        kmem_free((char *)(x), sizeof(*(x)))
 #  if SOLARIS
+typedef        struct  qif     {
+       struct  qif     *qf_next;
+       ill_t   *qf_ill;
+       kmutex_t        qf_lock;
+       void    *qf_iptr;
+       void    *qf_optr;
+       queue_t *qf_in;
+       queue_t *qf_out;
+       void    *qf_wqinfo;
+       void    *qf_rqinfo;
+       char    qf_name[8];
+       int     (*qf_inp)();
+       int     (*qf_outp)();
+       /*
+        * in case the ILL has disappeared...
+        */
+       int     qf_hl;  /* header length */
+} qif_t;
+#   define     SPLNET(x)       ;
+#   undef      SPLX
+#   define     SPLX(x)         ;
 #   ifdef      sparc
 #    define    ntohs(x)        (x)
 #    define    ntohl(x)        (x)
@@ -242,7 +376,7 @@ typedef     struct  ipfr    {
 #  else
 #   define     KMALLOC(x)      new_kmem_alloc((x), KMEM_SLEEP)
 #  endif /* __svr4__ */
-# endif /* sun && !linux */
+# endif /* sun && !linux && !__NetBSD__ && !__OpenBSD__*/
 # ifndef       GET_MINOR
 #  define      GET_MINOR(x)    minor(x)
 # endif
@@ -260,9 +394,26 @@ extern     vm_map_t        kmem_map;
                                          sizeof(*(x)))
 #  define      UIOMOVE(a,b,c,d)        uiomove(a,b,d)
 #  define      SLEEP(id, n)    tsleep((id), PPAUSE|PCATCH, n, 0)
-# else
 # endif /* BSD */
-#endif /* _KERNEL */
+# if defined(NetBSD1_0) && (NetBSD1_0 > 1)
+#  define      SPLNET(x)       x = splsoftnet()
+# else
+#  if !SOLARIS
+#   define     SPLNET(x)       x = splnet()
+#   define     SPLX(x)         (void) splx(x)
+#  endif
+# endif
+#else
+# define       MUTEX_ENTER(x)  ;
+# define       MUTEX_EXIT(x)   ;
+# define       SPLNET(x)       ;
+# define       SPLX(x)         ;
+# define       KMALLOC(x)      malloc(x)
+# define       KFREE(x)        free(x)
+# define       GETUNIT(x)      (x)
+# define       IRCOPY(a,b,c)   bcopy((a), (b), (c))
+# define       IWCOPY(a,b,c)   bcopy((a), (b), (c))
+#endif /* KERNEL */
 
 #ifdef linux
 # define       ICMP_UNREACH    ICMP_DEST_UNREACH
@@ -292,6 +443,13 @@ typedef    struct  {
        __u16   th_urp;
 } tcphdr_t;
 
+typedef        struct  {
+       __u16   uh_sport;
+       __u16   uh_dport;
+       __u16   uh_ulen;
+       __u16   uh_sun;
+} udphdr_t;
+
 typedef        struct  {
 # if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\
     defined(vax)
@@ -312,8 +470,8 @@ typedef     struct  {
        __u32   ip_dst;
 } ip_t;
 
-# define       SPLX(x)         ;
-# define       SPLNET(x)       ;
+# define       SPLX(x)         (void)
+# define       SPLNET(x)       (void)
 
 # define       bcopy(a,b,c)    memmove(b,a,c)
 # define       bcmp(a,b,c)     memcmp(a,b,c)
@@ -336,128 +494,9 @@ typedef   struct  {
                                        memcpy_tofs((b), (a), (c)); \
                                }
 #else
-
 typedef        struct  tcphdr  tcphdr_t;
+typedef        struct  udphdr  udphdr_t;
 typedef        struct  ip      ip_t;
-
-# if SOLARIS
-#  define      MTOD(m,t)       (t)((m)->b_rptr)
-#  define      IRCOPY(a,b,c)   copyin((a), (b), (c))
-#  define      IWCOPY(a,b,c)   copyout((a), (b), (c))
-#  ifdef       _KERNEL
-typedef        struct  qif     {
-       struct  qif     *qf_next;
-       ill_t   *qf_ill;
-       kmutex_t        qf_lock;
-       void    *qf_iptr;
-       void    *qf_optr;
-       queue_t *qf_in;
-       queue_t *qf_out;
-       void    *qf_wqinfo;
-       void    *qf_rqinfo;
-       char    qf_name[8];
-       int     (*qf_inp)();
-       int     (*qf_outp)();
-       /*
-        * in case the ILL has disappeared...
-        */
-       int     qf_hl;  /* header length */
-} qif_t;
-#  endif /* _KERNEL */
-# else
-#  define      MTOD(m,t)       mtod(m,t)
-#  define      IRCOPY(a,b,c)   bcopy((a), (b), (c))
-#  define      IWCOPY(a,b,c)   bcopy((a), (b), (c))
-# endif /* SOLARIS */
-# ifdef        _KERNEL
-#  if defined(NetBSD1_0) && (NetBSD1_0 > 1)
-#   define     SPLNET(x)       x = splsoftnet()
-#  else
-#   if SOLARIS
-#    define    SPLNET(x)       ;
-#   else
-#    define    SPLNET(x)       x = splnet()
-#   endif
-#  endif
-#  ifdef SPLX
-#   undef      SPLX
-#  endif
-#  if SOLARIS
-#   define     SPLX(x)         ;
-#  else
-#   define     SPLX(x)         (void) splx(x)
-#  endif
-# else
-#  define      SPLNET(x)       ;
-#  define      SPLX(x)         ;
-# endif /* KERNEL */
-
-# ifdef sun
-#  if !defined(__sysv__) && !defined(__SVR4)
-#   define     GETUNIT(n)      ifunit((n), IFNAMSIZ)
-#  endif
-# else
-#  define      GETUNIT(n)      ifunit((n))
-# endif /* sun */
-extern struct ifnet *ifunit();
 #endif /* linux */
 
-#define        IPMINLEN(i, h)  ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
-
-/*#define      IPOPT_RR        7 */
-#define        IPOPT_ZSU       10      /* ZSU */
-#define        IPOPT_MTUP      11      /* MTUP */
-#define        IPOPT_MTUR      12      /* MTUR */
-#define        IPOPT_ENCODE    15      /* ENCODE */
-/*#define      IPOPT_TS        68 */
-#define        IPOPT_TR        82      /* TR */
-/*#define      IPOPT_SECURITY  130 */
-/*#define      IPOPT_LSRR      131 */
-#define        IPOPT_E_SEC     133     /* E-SEC */
-#define        IPOPT_CIPSO     134     /* CIPSO */
-/*#define      IPOPT_SATID     136 */
-#ifndef        IPOPT_SID
-# define       IPOPT_SID       IPOPT_SATID
-#endif
-/*#define      IPOPT_SSRR      137 */
-#define        IPOPT_ADDEXT    147     /* ADDEXT */
-#define        IPOPT_VISA      142     /* VISA */
-#define        IPOPT_IMITD     144     /* IMITD */
-#define        IPOPT_EIP       145     /* EIP */
-#define        IPOPT_FINN      205     /* FINN */
-
-#ifndef        ICMP_UNREACH_FILTER
-#define        ICMP_UNREACH_FILTER     13
-#endif
-/*
- * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108.
- *
- * Basic Option
- *
- * 00000001   -   (Reserved 4)
- * 00111101   -   Top Secret
- * 01011010   -   Secret
- * 10010110   -   Confidential
- * 01100110   -   (Reserved 3)
- * 11001100   -   (Reserved 2)
- * 10101011   -   Unclassified
- * 11110001   -   (Reserved 1)
- */
-#define        IPSO_CLASS_RES4         0x01
-#define        IPSO_CLASS_TOPS         0x3d
-#define        IPSO_CLASS_SECR         0x5a
-#define        IPSO_CLASS_CONF         0x96
-#define        IPSO_CLASS_RES3         0x66
-#define        IPSO_CLASS_RES2         0xcc
-#define        IPSO_CLASS_UNCL         0xab
-#define        IPSO_CLASS_RES1         0xf1
-
-#define        IPSO_AUTH_GENSER        0x80
-#define        IPSO_AUTH_ESI           0x40
-#define        IPSO_AUTH_SCI           0x20
-#define        IPSO_AUTH_NSA           0x10
-#define        IPSO_AUTH_DOE           0x08
-#define        IPSO_AUTH_UN            0x06
-#define        IPSO_AUTH_FTE           0x01
-
 #endif /* __IP_FIL_H__ */
diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c
new file mode 100644 (file)
index 0000000..344423b
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#ifndef        lint
+static char    sccsid[] = "@(#)ip_frag.c       1.5 1/14/96 (C) 1993-1995 Darren Reed";
+#endif
+
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/dir.h>
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+
+#include <net/if.h>
+#ifdef sun
+#include <net/af.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include <syslog.h>
+#include "ip_fil.h"
+#include "ip_frag.h"
+#include "ip_nat.h"
+#include "ip_state.h"
+
+ipfr_t *ipfr_heads[IPFT_SIZE];
+ipfrstat_t ipfr_stats;
+u_long ipfr_inuse = 0;
+#ifdef _KERNEL
+extern int     ipfr_timer_id;
+#endif
+#if    SOLARIS
+# ifdef        _KERNEL
+extern kmutex_t        ipf_frag;
+# else
+#define        bcmp(a,b,c)     memcmp(a,b,c)
+#define        bcopy(a,b,c)    memmove(b,a,c)
+# endif
+#endif
+
+
+ipfrstat_t *ipfr_fragstats()
+{
+       ipfr_stats.ifs_table = ipfr_heads;
+       ipfr_stats.ifs_inuse = ipfr_inuse;
+       return &ipfr_stats;
+}
+
+
+/*
+ * add a new entry to the fragment cache, registering it as having come
+ * through this box, with the result of the filter operation.
+ */
+int ipfr_newfrag(ip, pass)
+ip_t *ip;
+int pass;
+{
+       ipfr_t  **fp, *fr, frag;
+       u_int   idx;
+
+       frag.ipfr_p = ip->ip_p;
+       idx = ip->ip_p;
+       frag.ipfr_id = ip->ip_id;
+       idx += ip->ip_id;
+       frag.ipfr_tos = ip->ip_tos;
+       frag.ipfr_src.s_addr = ip->ip_src.s_addr;
+       idx += ip->ip_src.s_addr;
+       frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
+       idx += ip->ip_dst.s_addr;
+       idx *= 127;
+       idx %= IPFT_SIZE;
+
+       /*
+        * first, make sure it isn't already there...
+        */
+       MUTEX_ENTER(&ipf_frag);
+       for (fp = &ipfr_heads[idx]; (fr = *fp); fp = &fr->ipfr_next)
+               if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src,
+                         IPFR_CMPSZ)) {
+                       ipfr_stats.ifs_exists++;
+                       MUTEX_EXIT(&ipf_frag);
+                       return -1;
+               }
+
+       if (!(fr = (ipfr_t *)KMALLOC(sizeof(*fr)))) {
+               ipfr_stats.ifs_nomem++;
+               MUTEX_EXIT(&ipf_frag);
+               return -1;
+       }
+       if ((fr->ipfr_next = ipfr_heads[idx]))
+               ipfr_heads[idx]->ipfr_prev = fr;
+       fr->ipfr_prev = NULL;
+       ipfr_heads[idx] = fr;
+       bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ);
+       fr->ipfr_ttl = 120;     /* 60 seconds */
+       fr->ipfr_pass = pass;
+       *fp = fr;
+       ipfr_stats.ifs_new++;
+       ipfr_inuse++;
+       MUTEX_EXIT(&ipf_frag);
+       return 0;
+}
+
+
+/*
+ * check the fragment cache to see if there is already a record of this packet
+ * with its filter result known.
+ */
+int ipfr_knownfrag(ip)
+ip_t *ip;
+{
+       ipfr_t  *f, frag;
+       u_int   idx;
+
+       /*
+        * For fragments, we record protocol, packet id, TOS and both IP#'s
+        * (these should all be the same for all fragments of a packet).
+        */
+       frag.ipfr_p = ip->ip_p;
+       idx = ip->ip_p;
+       frag.ipfr_id = ip->ip_id;
+       idx += ip->ip_id;
+       frag.ipfr_tos = ip->ip_tos;
+       frag.ipfr_src.s_addr = ip->ip_src.s_addr;
+       idx += ip->ip_src.s_addr;
+       frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
+       idx += ip->ip_dst.s_addr;
+       idx *= 127;
+       idx %= IPFT_SIZE;
+
+       MUTEX_ENTER(&ipf_frag);
+       for (f = ipfr_heads[idx]; f; f = f->ipfr_next)
+               if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src,
+                         IPFR_CMPSZ)) {
+                       if (f != ipfr_heads[idx]) {
+                               /*
+                                * move fragment info. to the top of the list
+                                * to speed up searches.
+                                */
+                               if ((f->ipfr_prev->ipfr_next = f->ipfr_next))
+                                       f->ipfr_next->ipfr_prev = f->ipfr_prev;
+                               f->ipfr_next = ipfr_heads[idx];
+                               ipfr_heads[idx]->ipfr_prev = f;
+                               f->ipfr_prev = NULL;
+                               ipfr_heads[idx] = f;
+                       }
+                       ipfr_stats.ifs_hits++;
+                       return f->ipfr_pass;
+               }
+       MUTEX_EXIT(&ipf_frag);
+       return 0;
+}
+
+
+/*
+ * Free memory in use by fragment state info. kept.
+ */
+void ipfr_unload()
+{
+       ipfr_t  **fp, *fr;
+       int     idx;
+#if    !SOLARIS
+       int     s;
+#endif
+
+       MUTEX_ENTER(&ipf_frag);
+       SPLNET(s);
+       for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
+               for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
+                       *fp = fr->ipfr_next;
+                       KFREE(fp);
+               }
+       SPLX(s);
+       MUTEX_EXIT(&ipf_frag);
+}
+
+
+#ifdef _KERNEL
+/*
+ * Slowly expire held state for fragments.  Timeouts are set * in expectation
+ * of this being called twice per second.
+ */
+# if BSD < 199306
+int ipfr_slowtimer()
+#else
+void ipfr_slowtimer()
+#endif
+{
+       ipfr_t  **fp, *fr;
+       int     s, idx;
+
+       MUTEX_ENTER(&ipf_frag);
+       SPLNET(s);
+
+       for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
+               for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
+                       --fr->ipfr_ttl;
+                       if (fr->ipfr_ttl == 0) {
+                               if (fr->ipfr_prev)
+                                       fr->ipfr_prev->ipfr_next =
+                                            fr->ipfr_next;
+                               if (fr->ipfr_next)
+                                       fr->ipfr_next->ipfr_prev =
+                                            fr->ipfr_prev;
+                               *fp = fr->ipfr_next;
+                               ipfr_stats.ifs_expire++;
+                               ipfr_inuse--;
+                               KFREE(fp);
+                       } else
+                               fp = &fr->ipfr_next;
+               }
+       SPLX(s);
+#if    SOLARIS
+       MUTEX_EXIT(&ipf_frag);
+       fr_timeoutstate();
+       ip_natexpire();
+       ipfr_timer_id = timeout(ipfr_slowtimer, NULL, HZ/2);
+#else
+       fr_timeoutstate();
+       ip_natexpire();
+       ip_slowtimo();
+#endif
+# if BSD < 199306
+       return 0;
+# endif
+}
+#endif /* defined(_KERNEL) */
diff --git a/sys/netinet/ip_frag.h b/sys/netinet/ip_frag.h
new file mode 100644 (file)
index 0000000..438c839
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * (C)opyright 1993, 1994, 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ip_frag.h       1.3 1/12/96
+ */
+
+#ifndef        __IP_FRAG_H_
+#define        __IP_FRAG_H__
+
+#define        IPFT_SIZE       257
+
+typedef        struct  ipfr    {
+       struct  ipfr    *ipfr_next, *ipfr_prev;
+       struct  in_addr ipfr_src;
+       struct  in_addr ipfr_dst;
+       u_short ipfr_id;
+       u_short ipfr_ttl;
+       u_char  ipfr_p;
+       u_char  ipfr_tos;
+       u_char  ipfr_pass;
+} ipfr_t;
+
+#if defined(__STDC__) || defined(__GNUC__)
+#define        SIOCGFRST       _IOR('r', 76, struct ipfrstat)
+#else
+#define        SIOCGFRST       _IOR(r, 76, struct ipfrstat)
+#endif
+
+typedef        struct  ipfrstat {
+       u_long  ifs_exists;     /* add & already exists */
+       u_long  ifs_nomem;
+       u_long  ifs_new;
+       u_long  ifs_hits;
+       u_long  ifs_expire;
+       u_long  ifs_inuse;
+       struct  ipfr    **ifs_table;
+} ipfrstat_t;
+
+#define        IPFR_CMPSZ      (4 + 4 + 2 + 1 + 1)
+
+extern ipfrstat_t *ipfr_fragstats();
+extern int ipfr_newfrag(), ipfr_knownfrag();
+# ifdef        _KERNEL
+extern void ipfr_unload();
+# endif
+#endif /* __IP_FIL_H__ */
index 897583f..6b446c2 100644 (file)
@@ -83,8 +83,7 @@ int   ipqmaxlen = IFQ_MAXLEN;
 struct in_ifaddrhead in_ifaddr;
 struct ifqueue ipintrq;
 #if defined(IPFILTER) || defined(IPFILTER_LKM)
-int    fr_nullcheck();
-int    (*fr_checkp) __P((struct ip *, int, struct ifnet *, int)) = fr_nullcheck;
+int    (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **));
 #endif
 
 char *
@@ -240,8 +239,13 @@ next:
         * Check if we want to allow this packet to be processed.
         * Consider it to be bad if not.
         */
-       if ((*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0))
-               goto bad;
+       {
+               struct mbuf *m0 = m;
+               if (fr_checkp && (*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m0))
+                       goto next;
+               else
+                 ip = mtod(m = m0, struct ip *);
+       }
 #endif
        /*
         * Process options and, if not destined for us,
@@ -1185,10 +1189,3 @@ ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
        }
        /* NOTREACHED */
 }
-
-#if defined(IPFILTER) || defined(IPFILTER_LKM)
-int    fr_nullcheck()
-{
-       return 0;
-}
-#endif
diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c
new file mode 100644 (file)
index 0000000..52bd755
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#ifndef        lint
+static char    sccsid[] = "@(#)ip_nat.c        1.3 1/12/96 (C) 1995 Darren Reed";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/dir.h>
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+
+#include <net/if.h>
+#ifdef sun
+#include <net/af.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include <syslog.h>
+#include "ip_fil.h"
+#include "ip_nat.h"
+#ifndef        MIN
+#define        MIN(a,b)        (((a)<(b))?(a):(b))
+#endif
+
+nat_t  *nat_table[2][NAT_SIZE];
+ipnat_t        *nat_list = NULL;
+u_long nat_inuse = 0;
+natstat_t nat_stats;
+#if    SOLARIS
+# ifndef       _KERNEL
+#define        bcmp(a,b,c)     memcpy(a,b,c)
+#define        bcopy(a,b,c)    memmove(b,a,c)
+# else
+extern kmutex_t        ipf_nat;
+# endif
+#endif
+
+
+/*
+ * How the NAT is organised and works.
+ *
+ * Inside (interface y) NAT       Outside (interface x)
+ * -------------------- -+- -------------------------------------
+ * Packet going          |   out, processsed by ip_natout() for x
+ * ------------>         |   ------------>
+ * src=10.1.1.1          |   src=192.1.1.1
+ *                       |
+ *                       |   in, processed by ip_natin() for x
+ * <------------         |   <------------
+ * dst=10.1.1.1          |   dst=192.1.1.1
+ * -------------------- -+- -------------------------------------
+ * ip_natout() - changes ip_src and if required, sport
+ *             - creates a new mapping, if required.
+ * ip_natin()  - changes ip_dst and if required, dport
+ *
+ * In the NAT table, internal source is recorded as "in" and externally
+ * seen as "out".
+ */
+
+/*
+ * Handle ioctls which manipulate the NAT.
+ */
+int nat_ioctl(data, cmd)
+caddr_t data;
+int cmd;
+{
+       register ipnat_t *nat, *n, **np;
+
+       /*
+        * For add/delete, look to see if the NAT entry is already present
+        */
+       MUTEX_ENTER(&ipf_nat);
+       if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
+               nat = (ipnat_t *)data;
+               for (np = &nat_list; (n = *np); np = &n->in_next)
+                       if (!bcmp((char *)&nat->in_port, (char *)&n->in_port,
+                                 IPN_CMPSIZ))
+                               break;
+       }
+
+       switch (cmd)
+       {
+       case SIOCADNAT :
+               if (n) {
+                       MUTEX_EXIT(&ipf_nat);
+                       return EEXIST;
+               }
+               if (!(n = (ipnat_t *)KMALLOC(sizeof(*n)))) {
+                       MUTEX_EXIT(&ipf_nat);
+                       return ENOMEM;
+               }
+               IRCOPY((char *)data, (char *)np, sizeof(*np));
+               bcopy((char *)nat, (char *)n, sizeof(*n));
+               n->in_ifp = (void *)GETUNIT(n->in_ifname);
+               n->in_next = *np;
+               n->in_space = ~(0xffffffff & ntohl(n->in_outmsk));
+               n->in_space--;  /* lose 1 for broadcast address */
+               n->in_nip = ntohl(n->in_outip) + 1;
+               n->in_pnext = ntohs(n->in_pmin);
+               *np = n;
+               break;
+       case SIOCRMNAT :
+               if (!n) {
+                       MUTEX_EXIT(&ipf_nat);
+                       return ESRCH;
+               }
+               *np = n->in_next;
+               KFREE(n);
+               break;
+       case SIOCGNATS :
+               nat_stats.ns_table = (nat_t ***)nat_table;
+               nat_stats.ns_list = nat_list;
+               nat_stats.ns_inuse = nat_inuse;
+               IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats));
+               break;
+       }
+       MUTEX_EXIT(&ipf_nat);
+       return 0;
+}
+
+
+/*
+ * Create a new NAT table entry.
+ */
+nat_t *nat_new(ip, hlen, flags)
+ip_t *ip;
+int hlen;
+u_short flags;
+{
+       u_short port = 0, sport = 0;
+       struct in_addr in;
+       tcphdr_t *tcp;
+       ipnat_t *np;
+       nat_t *nat, **natp;
+
+       if (flags) {
+               tcp = (tcphdr_t *)((char *)ip + hlen);
+               sport = tcp->th_sport;
+       }
+
+       MUTEX_ENTER(&ipf_nat);
+       /*
+        * Search the current table for a match.
+        */
+       do {
+               in.s_addr = np->in_nip;
+               if (np->in_flags & IPN_TCPUDP) {
+                       port = htons(np->in_pnext++);
+                       if (np->in_pnext >= ntohs(np->in_pmax)) {
+                               np->in_pnext = ntohs(np->in_pmin);
+                               np->in_nip++;
+                               np->in_space--;
+                       }
+               } else {
+                       np->in_space--;
+                       np->in_nip++;
+               }
+               if ((np->in_nip & ntohl(np->in_outmsk)) > ntohl(np->in_outip))
+                       np->in_nip = ntohl(np->in_outip) + 1;
+       } while (nat_lookupinip(in, sport));
+
+       if (!(nat = (nat_t *)KMALLOC(sizeof(*nat)))) {
+               MUTEX_EXIT(&ipf_nat);
+               return NULL;
+       }
+       nat->nat_use = 0;
+       in.s_addr = htonl(in.s_addr);
+       nat->nat_inip = ip->ip_src;
+       nat->nat_outip = in;
+       nat->nat_sumd = (ntohl(ip->ip_src.s_addr) & 0xffff) +
+                       (ntohl(ip->ip_src.s_addr) >> 16);
+       nat->nat_sumd -= ((ntohl(in.s_addr) & 0xffff) +
+                         (ntohl(in.s_addr) >> 16));
+       if (sport) {
+               nat->nat_inport = sport;
+               nat->nat_outport = port;
+               nat->nat_sumd += (ntohs(sport) - ntohs(port));
+       } else {
+               nat->nat_inport = 0;
+               nat->nat_outport = 0;
+       }
+       natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE];
+       nat->nat_next = *natp;
+       *natp = nat;
+       nat->nat_use++;
+       natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE];
+       nat->nat_next = *natp;
+       *natp = nat;
+       nat->nat_use++;
+       ip->ip_src = in;
+       if (flags)
+               tcp->th_sport = htons(port);
+       nat_stats.ns_added++;
+       nat_inuse++;
+       MUTEX_EXIT(&ipf_nat);
+       return nat;
+}
+
+
+nat_t *nat_lookupoutip(ipaddr, sport)
+struct in_addr ipaddr;
+u_short sport;
+{
+       nat_t *nat;
+
+       nat = nat_table[1][ipaddr.s_addr % NAT_SIZE];
+
+       MUTEX_ENTER(&ipf_nat);
+       for (; nat; nat = nat->nat_next)
+               if (nat->nat_outip.s_addr == ipaddr.s_addr) {
+                       if (nat->nat_outport && (sport != nat->nat_outport))
+                               continue;
+                       return nat;
+               }
+       MUTEX_EXIT(&ipf_nat);
+       return NULL;
+}
+
+
+/*
+ * Packets going out on the external interface go through this.
+ * Here, the source address requires alteration, if anything.
+ */
+void ip_natout(ifp, ip, hlen)
+struct ifnet *ifp;
+ip_t *ip;
+int hlen;
+{
+       register ipnat_t *np;
+       register u_long ipa;
+       register u_long sum1, sum2;
+       tcphdr_t *tcp;
+       nat_t *nat;
+       u_short nflags = 0, sport = 0;
+
+       if (ip->ip_p == IPPROTO_TCP)
+               nflags = IPN_TCP;
+       else if (ip->ip_p == IPPROTO_UDP)
+               nflags = IPN_UDP;
+       if (nflags) {
+               tcp = (tcphdr_t *)((char *)ip + hlen);
+               sport = tcp->th_sport;
+       }
+
+       ipa = ip->ip_src.s_addr;
+
+       MUTEX_ENTER(&ipf_nat);
+       for (np = nat_list; np; np = np->in_next)
+               if ((np->in_ifp == ifp) && np->in_space &&
+                   (!np->in_flags || (np->in_flags & nflags)) &&
+                   ((ipa & np->in_inmsk) == np->in_inip)) {
+                       /*
+                        * If there is no current entry in the nat table for
+                        * this IP#, create one for it.
+                        */
+                       if (!(nat = nat_lookupinip(ip->ip_src, sport))) {
+                               if (!(nat = nat_new(ip, hlen,
+                                                   nflags & np->in_flags))) {
+                                       MUTEX_EXIT(&ipf_nat);
+                                       return;
+                               }
+                       } else
+                               ip->ip_src = nat->nat_outip;
+
+                       nat->nat_age = 1200;    /* 5 mins */
+
+                       /*
+                        * Fix up checksums, not by recalculating them, but
+                        * simply computing adjustments.
+                        */
+                       if (nflags) {
+                               if (nat->nat_outport) {
+                                       sum1 += sport;
+                                       tcp->th_sport = nat->nat_outport;
+                                       sum2 += tcp->th_sport;
+                               }
+
+                               sum2 = nat->nat_sumd;
+
+                               if (ip->ip_p == IPPROTO_TCP) {
+                                       sum2 += ntohs(tcp->th_sum);
+                                       sum2 = (sum2 >> 16) + (sum2 & 0xffff);
+                                       sum2 += (sum2 >> 16);
+                                       tcp->th_sum = htons(sum2);
+                               } else if (ip->ip_p == IPPROTO_UDP) {
+                                       udphdr_t *udp = (udphdr_t *)tcp;
+
+                                       udp->uh_sum = 0;
+                               }
+                       }
+                       nat_stats.ns_mapped[1]++;
+                       MUTEX_EXIT(&ipf_nat);
+                       return;
+               }
+       MUTEX_EXIT(&ipf_nat);
+       return;
+}
+
+nat_t *nat_lookupinip(ipaddr, sport)
+struct in_addr ipaddr;
+u_short sport;
+{
+       nat_t *nat;
+
+       nat = nat_table[0][ipaddr.s_addr % NAT_SIZE];
+
+       MUTEX_ENTER(&ipf_nat);
+       for (; nat; nat = nat->nat_next)
+               if (nat->nat_inip.s_addr == ipaddr.s_addr) {
+                       if (nat->nat_inport && (sport != nat->nat_inport))
+                               continue;
+                       return nat;
+               }
+       MUTEX_EXIT(&ipf_nat);
+       return NULL;
+}
+
+
+/*
+ * Packets coming in from the external interface go through this.
+ * Here, the destination address requires alteration, if anything.
+ */
+void ip_natin(ifp, ip, hlen)
+struct ifnet *ifp;
+ip_t *ip;
+int hlen;
+{
+       register ipnat_t *np;
+       register struct in_addr in;
+       register u_long sum1, sum2;
+       tcphdr_t *tcp;
+       u_short port = 0, nflags;
+       nat_t *nat;
+
+       if (ip->ip_p == IPPROTO_TCP)
+               nflags = IPN_TCP;
+       else if (ip->ip_p == IPPROTO_UDP)
+               nflags = IPN_UDP;
+       if (nflags) {
+               tcp = (tcphdr_t *)((char *)ip + hlen);
+               port = tcp->th_dport;
+       }
+
+       in = ip->ip_dst;
+
+       MUTEX_ENTER(&ipf_nat);
+       for (np = nat_list; np; np = np->in_next)
+               if ((np->in_ifp == ifp) &&
+                   (!np->in_flags || (nflags & np->in_flags)) &&
+                   ((in.s_addr & np->in_outmsk) == np->in_outip)) {
+                       if (!(nat = nat_lookupoutip(in, port)))
+                               continue;
+                       nat->nat_age = 1200;
+                       ip->ip_dst = nat->nat_inip;
+
+                       /*
+                        * Fix up checksums, not by recalculating them, but
+                        * simply computing adjustments.
+                        */
+
+                       if (nflags) {
+                               u_short *sp = NULL;
+
+                               if (nat->nat_inport) {
+                                       sum1 += port;
+                                       tcp->th_dport = nat->nat_inport;
+                                       sum2 += tcp->th_dport;
+                               }
+
+                               sum2 = nat->nat_sumd;
+
+                               if (ip->ip_p == IPPROTO_TCP) {
+                                       sp = &tcp->th_sum;
+                                       if (ntohs(*sp) > sum2)
+                                               sum2--;
+                                       sum2 -= ntohs(*sp);
+                                       sum2 = (sum2 >> 16) + (sum2 & 0xffff);
+                                       sum2 += (sum2 >> 16);
+                                       *sp = htons(~sum2);
+                               } else if (ip->ip_p == IPPROTO_UDP) {
+                                       udphdr_t *udp = (udphdr_t *)tcp;
+
+                                       udp->uh_sum = 0;
+                               }
+                       }
+                       nat_stats.ns_mapped[0]++;
+                       MUTEX_EXIT(&ipf_nat);
+                       return;
+               }
+       MUTEX_EXIT(&ipf_nat);
+       return;
+}
+
+
+/*
+ * Free all memory used by NAT structures allocated at runtime.
+ */
+void ip_natunload()
+{
+       register struct nat *nat, **natp;
+       register struct ipnat *ipn, **ipnp;
+       register int i;
+
+       MUTEX_ENTER(&ipf_nat);
+       for (i = 0; i < NAT_SIZE; i++)
+               for (natp = &nat_table[0][i]; (nat = *natp); ) {
+                       *natp = nat->nat_next;
+                       if (!--nat->nat_use)
+                               KFREE(nat);
+               }
+       for (i = 0; i < NAT_SIZE; i++)
+               for (natp = &nat_table[1][i]; (nat = *natp); ) {
+                       *natp = nat->nat_next;
+                       if (!--nat->nat_use)
+                               KFREE(nat);
+               }
+
+       for (ipnp = &nat_list; (ipn = *ipnp); ) {
+               *ipnp = ipn->in_next;
+               KFREE(ipn);
+       }
+       MUTEX_EXIT(&ipf_nat);
+}
+
+
+/*
+ * Slowly expire held state for NAT entries.  Timeouts are set in
+ * expectation of this being called twice per second.
+ */
+void ip_natexpire()
+{
+       register struct nat *nat, **natp;
+       register int i;
+
+       MUTEX_ENTER(&ipf_nat);
+       for (i = 0; i < NAT_SIZE; i++)
+               for (natp = &nat_table[0][i]; (nat = *natp); ) {
+                       if (nat->nat_age > 0)
+                               nat->nat_age--;
+                       if (!nat->nat_use || !nat->nat_age) {
+                               *natp = nat->nat_next;
+                               if (nat->nat_use)
+                                       nat->nat_use--;
+                               if (!nat->nat_use) {
+                                       KFREE(nat);
+                                       nat_stats.ns_expire++;
+                                       nat_inuse--;
+                               }
+                       } else
+                               natp = &nat->nat_next;
+               }
+
+       for (i = 0; i < NAT_SIZE; i++)
+               for (natp = &nat_table[1][i]; (nat = *natp); ) {
+                       if (nat->nat_age > 0)
+                               nat->nat_age--;
+                       if (!nat->nat_use || !nat->nat_age) {
+                               *natp = nat->nat_next;
+                               if (nat->nat_use)
+                                       nat->nat_use--;
+                               if (!nat->nat_use) {
+                                       KFREE(nat);
+                                       nat_stats.ns_expire++;
+                                       nat_inuse--;
+                               }
+                       } else
+                               natp = &nat->nat_next;
+               }
+       MUTEX_EXIT(&ipf_nat);
+}
diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h
new file mode 100644 (file)
index 0000000..be38821
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ip_nat.h        1.3 1/12/96
+ */
+
+#ifndef        __IP_NAT_H_
+#define        __IP_NAT_H__
+
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
+
+#if defined(__STDC__) || defined(__GNUC__)
+#define        SIOCADNAT       _IOW('r', 80, struct ipnat)
+#define        SIOCRMNAT       _IOW('r', 81, struct ipnat)
+#define        SIOCGNATS       _IOR('r', 82, struct natstat)
+#else
+#define        SIOCADNAT       _IOW(r, 80, struct ipnat)
+#define        SIOCRMNAT       _IOW(r, 81, struct ipnat)
+#define        SIOCGNATS       _IOR(r, 82, struct natstat)
+#endif
+
+#define        NAT_SIZE        367
+
+typedef        struct  nat     {
+       struct  nat     *nat_next;
+       u_short nat_use;
+       short   nat_age;
+       u_long  nat_sumd;
+       struct  in_addr nat_inip;
+       struct  in_addr nat_outip;
+       u_short nat_inport;
+       u_short nat_outport;
+} nat_t;
+
+typedef        struct  ipnat   {
+       struct  ipnat   *in_next;
+       void    *in_ifp;
+       u_short in_flags;
+       u_short in_pnext;
+       u_short in_port[2];
+       struct  in_addr in_in[2];
+       struct  in_addr in_out[2];
+       struct  in_addr in_nextip;
+       int     in_space;
+       char    in_ifname[IFNAMSIZ];
+} ipnat_t;
+
+#define        in_pmin         in_port[0]
+#define        in_pmax         in_port[1]
+#define        in_nip          in_nextip.s_addr
+#define        in_inip         in_in[0].s_addr
+#define        in_inmsk        in_in[1].s_addr
+#define        in_outip        in_out[0].s_addr
+#define        in_outmsk       in_out[1].s_addr
+
+#define        IPN_CMPSIZ      (sizeof(struct in_addr) * 4 + sizeof(u_short) * 2)
+
+typedef        struct  natstat {
+       u_long  ns_mapped[2];
+       u_long  ns_added;
+       u_long  ns_expire;
+       u_long  ns_inuse;
+       nat_t   ***ns_table;
+       ipnat_t *ns_list;
+} natstat_t;
+
+#define        IPN_ANY         0
+#define        IPN_TCP         1
+#define        IPN_UDP         2
+#define        IPN_TCPUDP      3
+
+extern int nat_ioctl();
+extern nat_t *nat_lookupoutip(), *nat_lookupinip();
+extern void ip_natout(), ip_natin(), ip_natunload(), ip_natexpire();
+#endif /* __IP_NAT_H__ */
index 7e7d709..cb399c1 100644 (file)
@@ -61,7 +61,7 @@ static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
 static void ip_mloopback
        __P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
 #if defined(IPFILTER) || defined(IPFILTER_LKM)
-extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int));
+extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **));
 #endif
 
 /*
@@ -283,10 +283,13 @@ ip_output(m0, opt, ro, flags, imo)
        /*
         * looks like most checking has been done now...do a filter check
         */
-       if ((*fr_checkp)(ip, hlen, ifp, 1))
        {
-               error = EHOSTUNREACH;
-               goto bad;
+               struct mbuf *m0 = m;
+               if (fr_checkp && (*fr_checkp)(ip, hlen, ifp, 1, &m0)) {
+                       error = EHOSTUNREACH;
+                       goto done;
+               } else
+                       ip = mtod(m = m0, struct ip *);
        }
 #endif
 sendit:
diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c
new file mode 100644 (file)
index 0000000..69491a9
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#ifndef        lint
+static char    sccsid[] = "@(#)ip_state.c      1.3 1/12/96 (C) 1993-1995 Darren Reed";
+#endif
+
+#include <string.h>
+#ifndef        linux
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/dir.h>
+# include <sys/mbuf.h>
+#else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+
+#include <net/if.h>
+#ifdef sun
+#include <net/af.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/tcpip.h>
+#include <netinet/ip_icmp.h>
+#include <syslog.h>
+#endif
+#include "ip_fil.h"
+#include "ip_state.h"
+#ifndef        MIN
+#define        MIN(a,b)        (((a)<(b))?(a):(b))
+#endif
+
+#define        TCP_CLOSE       (TH_FIN|TH_RST)
+
+ipstate_t *ips_table[IPSTATE_SIZE];
+int    ips_num = 0;
+ips_stat_t ips_stats;
+#if    SOLARIS
+extern kmutex_t        ipf_state;
+# if   !defined(_KERNEL)
+#define        bcopy(a,b,c)    memmove(b,a,c)
+# endif
+#endif
+
+
+ips_stat_t *fr_statetstats()
+{
+       ips_stats.iss_active = ips_num;
+       ips_stats.iss_table = ips_table;
+       return &ips_stats;
+}
+
+
+#define        PAIRS(s1,d1,s2,d2)      ((((s1) == (s2)) && ((d1) == (d2))) ||\
+                                (((s1) == (d2)) && ((d1) == (s2))))
+#define        IPPAIR(s1,d1,s2,d2)     PAIRS((s1).s_addr, (d1).s_addr, \
+                                     (s2).s_addr, (d2).s_addr)
+
+/*
+ * Create a new ipstate structure and hang it off the hash table.
+ */
+int fr_addstate(ip, hlen, pass)
+ip_t *ip;
+int hlen;
+u_int pass;
+{
+       ipstate_t ips;
+       register ipstate_t *is = &ips;
+       register u_int hv;
+
+       if (ips_num == IPSTATE_MAX) {
+               ips_stats.iss_max++;
+               return -1;
+       }
+       /*
+        * Copy and calculate...
+        */
+       hv = (is->is_p = ip->ip_p);
+       hv += (is->is_src.s_addr = ip->ip_src.s_addr);
+       hv += (is->is_dst.s_addr = ip->ip_dst.s_addr);
+
+       switch (ip->ip_p)
+       {
+       case IPPROTO_ICMP :
+           {
+               struct icmp *ic = (struct icmp *)((char *)ip + hlen);
+
+               switch (ic->icmp_type)
+               {
+               case ICMP_ECHO :
+                       is->is_icmp.ics_type = 0;
+                       hv += (is->is_icmp.ics_id = ic->icmp_id);
+                       hv += (is->is_icmp.ics_seq = ic->icmp_seq);
+                       break;
+               case ICMP_TSTAMP :
+               case ICMP_IREQ :
+               case ICMP_MASKREQ :
+                       is->is_icmp.ics_type = ic->icmp_type + 1;
+                       break;
+               default :
+                       return -1;
+               }
+               ips_stats.iss_icmp++;
+               is->is_age = 120;
+               break;
+           }
+       case IPPROTO_TCP :
+           {
+               register tcphdr_t *tcp = (tcphdr_t *)((char *)ip + hlen);
+
+               /*
+                * The endian of the ports doesn't matter, but the ack and
+                * sequence numbers do as we do mathematics on them later.
+                */
+               hv += (is->is_dport = tcp->th_dport);
+               hv += (is->is_sport = tcp->th_sport);
+               is->is_seq = ntohl(tcp->th_seq);
+               is->is_ack = ntohl(tcp->th_ack);
+               is->is_win = ntohs(tcp->th_win);
+               ips_stats.iss_tcp++;
+               /*
+                * If we're creating state for a starting connectoin, start the
+                * timer on it as we'll never see an error if it fails to
+                * connect.
+                */
+               if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN)
+                       is->is_age = 120;
+               else
+                       is->is_age = 0;
+               break;
+           }
+       case IPPROTO_UDP :
+           {
+               register tcphdr_t *tcp = (tcphdr_t *)((char *)ip + hlen);
+
+               hv += (is->is_dport = tcp->th_dport);
+               hv += (is->is_sport = tcp->th_sport);
+               ips_stats.iss_udp++;
+               is->is_age = 120;
+               break;
+           }
+       default :
+               return -1;
+       }
+
+       if (!(is = (ipstate_t *)KMALLOC(sizeof(*is)))) {
+               ips_stats.iss_nomem++;
+               return -1;
+       }
+       bcopy((char *)&ips, (char *)is, sizeof(*is));
+       hv %= IPSTATE_SIZE;
+       MUTEX_ENTER(&ipf_state);
+       is->is_next = ips_table[hv];
+       ips_table[hv] = is;
+       is->is_pass = pass;
+       ips_num++;
+       MUTEX_EXIT(&ipf_state);
+       return 0;
+}
+
+
+/*
+ * Check if a packet has a registered state.
+ */
+int fr_checkstate(ip, hlen)
+ip_t *ip;
+int hlen;
+{
+       register struct in_addr dst, src;
+       register ipstate_t *is, **isp;
+       register u_char pr;
+       struct icmp *ic;
+       tcphdr_t *tcp;
+       u_int hv;
+
+       tcp = (tcphdr_t *)((char *)ip + hlen);
+       ic = (struct icmp *)tcp;
+       hv = (pr = ip->ip_p);
+       hv += (src.s_addr = ip->ip_src.s_addr);
+       hv += (dst.s_addr = ip->ip_dst.s_addr);
+
+       /*
+        * Search the hash table for matching packet header info.
+        */
+       switch (ip->ip_p)
+       {
+       case IPPROTO_ICMP :
+               hv += ic->icmp_id;
+               hv += ic->icmp_seq;
+               hv %= IPSTATE_SIZE;
+               MUTEX_ENTER(&ipf_state);
+               for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next)
+                       if ((is->is_p == pr) &&
+                           (ic->icmp_id == is->is_icmp.ics_id) &&
+                           (ic->icmp_seq == is->is_icmp.ics_seq) &&
+                           IPPAIR(src, dst, is->is_src, is->is_dst)) {
+                               /*
+                                * If we have type 0 stored, allow any icmp
+                                * replies through.
+                                */
+                               if (is->is_icmp.ics_type &&
+                                   is->is_icmp.ics_type != ic->icmp_type)
+                                       continue;
+                               is->is_age = 120;
+                               ips_stats.iss_hits++;
+                               MUTEX_EXIT(&ipf_state);
+                               return is->is_pass;
+                       }
+               MUTEX_EXIT(&ipf_state);
+               break;
+       case IPPROTO_TCP :
+           {
+               register u_short dport = tcp->th_dport, sport = tcp->th_sport;
+               register u_short win = ntohs(tcp->th_win);
+               tcp_seq seq, ack;
+
+               hv += dport;
+               hv += sport;
+               hv %= IPSTATE_SIZE;
+               MUTEX_ENTER(&ipf_state);
+               for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) {
+                       register int dl, seqskew, ackskew;
+
+                       if ((is->is_p == pr) &&
+                           PAIRS(sport, dport, is->is_sport, is->is_dport) &&
+                           IPPAIR(src, dst, is->is_src, is->is_dst)) {
+                               dl = ip->ip_len - hlen - sizeof(tcphdr_t);
+                               /*
+                                * Find difference between last checked packet
+                                * and this packet.
+                                */
+                               seq = ntohl(tcp->th_seq);
+                               ack = ntohl(tcp->th_ack);
+                               if (sport == is->is_sport) {
+                                       seqskew = seq - is->is_seq;
+                                       ackskew = ack - is->is_ack;
+                               } else {
+                                       seqskew = ack - is->is_seq;
+                                       if (!is->is_ack) {
+                                               /*
+                                                * Must be a SYN-ACK in reply
+                                                * to a SYN.  Set age timeout
+                                                * to 0 to stop deletion.
+                                                */
+                                               is->is_ack = seq;
+                                               is->is_age = 0;
+                                       }
+                                       ackskew = seq - is->is_ack;
+                               }
+
+                               /*
+                                * Make skew values absolute
+                                */
+                               if (seqskew < 0)
+                                       seqskew = -seqskew;
+                               if (ackskew < 0)
+                                       ackskew = -ackskew;
+                               /*
+                                * If the difference in sequence and ack
+                                * numbers is within the window size of the
+                                * connection, store these values and match
+                                * the packet.
+                                */
+                               if ((seqskew <= win) && (ackskew <= win)) {
+                                       is->is_win = win;
+                                       if (sport == is->is_sport) {
+                                               is->is_seq = seq;
+                                               is->is_ack = ack;
+                                       } else {
+                                               is->is_seq = ack;
+                                               is->is_ack = seq;
+                                       }
+                                       ips_stats.iss_hits++;
+                                       /*
+                                        * Nearing end of connection, start
+                                        * timeout.
+                                        */
+#ifdef _KERNEL
+                                       if ((tcp->th_flags & TCP_CLOSE) &&
+                                           !is->is_age)
+                                               is->is_age = 120;
+                                       MUTEX_EXIT(&ipf_state);
+                                       return is->is_pass;
+#else
+                                       if (tcp->th_flags & TCP_CLOSE) {
+                                               int pass = is->is_pass;
+
+                                               *isp = is->is_next;
+                                               isp = &ips_table[hv];
+                                               KFREE(is);
+                                               return pass;
+                                       }
+                                       return is->is_pass;
+#endif
+                               }
+                       }
+               }
+               MUTEX_EXIT(&ipf_state);
+               break;
+           }
+       case IPPROTO_UDP :
+           {
+               register u_short dport = tcp->th_dport, sport = tcp->th_sport;
+
+               hv += dport;
+               hv += sport;
+               hv %= IPSTATE_SIZE;
+               /*
+                * Nothing else to match on but ports. and IP#'s
+                */
+               MUTEX_ENTER(&ipf_state);
+               for (is = ips_table[hv]; is; is = is->is_next)
+                       if ((is->is_p == pr) &&
+                           PAIRS(sport, dport, is->is_sport, is->is_dport) &&
+                           IPPAIR(src, dst, is->is_src, is->is_dst)) {
+                               ips_stats.iss_hits++;
+                               is->is_age = 120;
+                               MUTEX_EXIT(&ipf_state);
+                               return is->is_pass;
+                       }
+               MUTEX_EXIT(&ipf_state);
+               break;
+           }
+       default :
+               break;
+       }
+       ips_stats.iss_miss++;
+       return 0;
+}
+
+
+/*
+ * Free memory in use by all state info. kept.
+ */
+void fr_stateunload()
+{
+       register int i;
+       register ipstate_t *is, **isp;
+
+       MUTEX_ENTER(&ipf_state);
+       for (i = 0; i < IPSTATE_SIZE; i++)
+               for (isp = &ips_table[i]; (is = *isp); ) {
+                       *isp = is->is_next;
+                       KFREE(is);
+               }
+       MUTEX_EXIT(&ipf_state);
+}
+
+
+/*
+ * Slowly expire held state for thingslike UDP and ICMP.  Timeouts are set
+ * in expectation of this being called twice per second.
+ */
+void fr_timeoutstate()
+{
+       register int i;
+       register ipstate_t *is, **isp;
+
+       MUTEX_ENTER(&ipf_state);
+       for (i = 0; i < IPSTATE_SIZE; i++)
+               for (isp = &ips_table[i]; (is = *isp); )
+                       if (is->is_age && !--is->is_age) {
+                               *isp = is->is_next;
+                               if (is->is_p == IPPROTO_TCP)
+                                       ips_stats.iss_fin++;
+                               else
+                                       ips_stats.iss_expire++;
+                               KFREE(is);
+                               ips_num--;
+                       } else
+                               isp = &is->is_next;
+       MUTEX_EXIT(&ipf_state);
+}
diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h
new file mode 100644 (file)
index 0000000..d22c930
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ *
+ * @(#)ip_state.h      1.3 1/12/96 (C) 1995 Darren Reed
+ */
+#ifndef        __IP_STATE_H__
+#define        __IP_STATE_H__
+
+#define        IPSTATE_SIZE    257
+#define        IPSTATE_MAX     2048    /* Maximum number of states held */
+
+typedef struct udpstate {
+       u_short us_sport;
+       u_short us_dport;
+} udpstate_t;
+
+typedef struct icmpstate {
+       u_short ics_id;
+       u_short ics_seq;
+       u_char  ics_type;
+} icmpstate_t;
+
+typedef        struct tcpstate {
+       u_short ts_sport;
+       u_short ts_dport;
+       u_long  ts_seq;
+       u_long  ts_ack;
+       u_short ts_win;
+} tcpstate_t;
+
+typedef struct ipstate {
+       struct  ipstate *is_next;
+       int     is_age;
+       u_int   is_pass;
+       struct  in_addr is_src;
+       struct  in_addr is_dst;
+       u_char  is_p;
+       union {
+               icmpstate_t     is_ics;
+               tcpstate_t      is_ts;
+               udpstate_t      is_us;
+       } is_ps;
+} ipstate_t;
+
+#define        is_icmp is_ps.is_ics
+#define        is_tcp  is_ps.is_ts
+#define        is_udp  is_ps.is_us
+#define        is_seq  is_tcp.ts_seq
+#define        is_ack  is_tcp.ts_ack
+#define        is_win  is_tcp.ts_win
+#define        is_sport        is_tcp.ts_sport
+#define        is_dport        is_tcp.ts_dport
+
+#if defined(__STDC__) || defined(__GNUC__)
+#define        SIOCGIPST       _IOR('r', 75, struct ips_stat)
+#else
+#define        SIOCGIPST       _IOR(r, 75, struct ips_stat)
+#endif
+
+typedef        struct  ips_stat {
+       u_long  iss_hits;
+       u_long  iss_miss;
+       u_long  iss_max;
+       u_long  iss_tcp;
+       u_long  iss_udp;
+       u_long  iss_icmp;
+       u_long  iss_nomem;
+       u_long  iss_expire;
+       u_long  iss_fin;
+       u_long  iss_active;
+       ipstate_t **iss_table;
+} ips_stat_t;
+
+extern ips_stat_t *fr_statetstats();
+extern int fr_addstate(), fr_checkstate();
+extern void fr_timeoutstate();
+# ifdef        _KERNEL
+extern void fr_stateunload();
+# endif
+#endif /* __IP_STATE_H__ */
index 723b314..adfc9c0 100644 (file)
@@ -1,8 +1,9 @@
 PROG=  ipftest 
 MAN=   ipftest.1       
-SRCS=  ipt.c fil.c ipft_sn.c ipft_ef.c ipft_td.c ipft_pc.c ipft_tx.c misc.c parse.c opt.c
-.PATH:         ${.CURDIR}/../../sbin/ipf ${.CURDIR}/../../sbin/ipfstat
-CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -I${.CURDIR}/../../sbin/ipf
+SRCS=  ipt.c fil.c ipft_sn.c ipft_ef.c ipft_td.c ipft_pc.c ipft_tx.c \
+       misc.c parse.c opt.c ip_frag.c ip_nat.c ip_state.c
+.PATH:         ${.CURDIR}/../../sbin/ipf ${.CURDIR}/../../sbin/ipfstat ${.CURDIR}/../../sys/netinet
+CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -I${.CURDIR}/../../sbin/ipf -I${.CURDIR}/../../sys/netinet
 
 
 .include <bsd.prog.mk>
diff --git a/usr.sbin/ipftest/fil.c b/usr.sbin/ipftest/fil.c
deleted file mode 100644 (file)
index b485678..0000000
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * (C)opyright 1993,1994,1995 by Darren Reed.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and due credit is given
- * to the original author and the contributors.
- */
-#ifndef        lint
-static char    sccsid[] = "@(#)fil.c   1.18 10/24/95 (C) 1993-1995 Darren Reed";
-#endif
-
-#ifndef        linux
-# include <sys/errno.h>
-# include <sys/types.h>
-# include <sys/param.h>
-# include <sys/file.h>
-# include <sys/ioctl.h>
-# if defined(_KERNEL) || defined(KERNEL)
-#  include <sys/systm.h>
-# endif
-# include <sys/uio.h>
-# if !defined(__SVR4) && !defined(__svr4__)
-#  include <sys/dir.h>
-#  include <sys/mbuf.h>
-# else
-#  include <sys/byteorder.h>
-#  include <sys/dditypes.h>
-#  include <sys/stream.h>
-# endif
-# include <sys/protosw.h>
-# include <sys/socket.h>
-# include <net/if.h>
-# ifdef sun
-#  include <net/af.h>
-# endif
-# include <net/route.h>
-# include <netinet/in.h>
-# include <netinet/in_systm.h>
-# include <netinet/ip.h>
-# include <netinet/ip_var.h>
-# include <netinet/tcp.h>
-# include <netinet/udp.h>
-# include <netinet/tcpip.h>
-# include <netinet/ip_icmp.h>
-#endif
-#include <netinet/ip_fil.h>
-#ifndef        MIN
-#define        MIN(a,b)        (((a)<(b))?(a):(b))
-#endif
-
-#ifndef        _KERNEL
-#include "ipf.h"
-extern int     opts;
-extern void    debug(), verbose();
-
-#define        FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; second; }
-#define        FR_IFDEBUG(ex,second,verb_pr)   if (ex) { debug verb_pr; second; }
-#define        FR_VERBOSE(verb_pr)     verbose verb_pr
-#define        FR_DEBUG(verb_pr)       debug verb_pr
-#else
-#define        FR_IFVERBOSE(ex,second,verb_pr) ;
-#define        FR_IFDEBUG(ex,second,verb_pr)   ;
-#define        FR_VERBOSE(verb_pr)
-#define        FR_DEBUG(verb_pr)
-
-extern int     ipl_unreach, ipllog();
-#endif
-
-struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
-struct frentry *filterin[2] = { NULL, NULL },
-               *filterout[2] = { NULL, NULL };
-int    fr_flags = 0, fr_active = 0;
-int    fr_check();
-
-/*
- * bit values for identifying presence of individual IP options
- */
-struct optlist ipopts[20] = {
-       { IPOPT_NOP,    0x000001 },
-       { IPOPT_RR,     0x000002 },
-       { IPOPT_ZSU,    0x000004 },
-       { IPOPT_MTUP,   0x000008 },
-       { IPOPT_MTUR,   0x000010 },
-       { IPOPT_ENCODE, 0x000020 },
-       { IPOPT_TS,     0x000040 },
-       { IPOPT_TR,     0x000080 },
-       { IPOPT_SECURITY, 0x000100 },
-       { IPOPT_LSRR,   0x000200 },
-       { IPOPT_E_SEC,  0x000400 },
-       { IPOPT_CIPSO,  0x000800 },
-       { IPOPT_SATID,  0x001000 },
-       { IPOPT_SSRR,   0x002000 },
-       { IPOPT_ADDEXT, 0x004000 },
-       { IPOPT_VISA,   0x008000 },
-       { IPOPT_IMITD,  0x010000 },
-       { IPOPT_EIP,    0x020000 },
-       { IPOPT_FINN,   0x040000 },
-       { 0,            0x000000 }
-};
-
-/*
- * bit values for identifying presence of individual IP security options
- */
-struct optlist secopt[8] = {
-       { IPSO_CLASS_RES4,      0x01 },
-       { IPSO_CLASS_TOPS,      0x02 },
-       { IPSO_CLASS_SECR,      0x04 },
-       { IPSO_CLASS_RES3,      0x08 },
-       { IPSO_CLASS_CONF,      0x10 },
-       { IPSO_CLASS_UNCL,      0x20 },
-       { IPSO_CLASS_RES2,      0x40 },
-       { IPSO_CLASS_RES1,      0x80 }
-};
-
-
-/*
- * compact the IP header into a structure which contains just the info.
- * which is useful for comparing IP headers with.
- */
-struct fr_ip *fr_makefrip(hlen, ip)
-int hlen;
-ip_t *ip;
-{
-       static struct fr_ip fi;
-       struct optlist *op;
-       u_short optmsk = 0, secmsk = 0, auth = 0;
-       int i, mv, ol, off;
-       u_char *s, opt;
-
-       fi.fi_fl = 0;
-       fi.fi_v = ip->ip_v;
-       fi.fi_tos = ip->ip_tos;
-       (*(((u_short *)&fi) + 1)) = (*(((u_short *)ip) + 4));
-       (*(((u_long *)&fi) + 1)) = (*(((u_long *)ip) + 3));
-       (*(((u_long *)&fi) + 2)) = (*(((u_long *)ip) + 4));
-
-       if (hlen > sizeof(struct ip))
-               fi.fi_fl |= FI_OPTIONS;
-       off = (ip->ip_off & 0x1fff) << 3;
-       if (ip->ip_off & 0x3fff)
-               fi.fi_fl |= FI_FRAG;
-       switch (ip->ip_p)
-       {
-       case IPPROTO_ICMP :
-               if ((!IPMINLEN(ip, icmp) && !off) ||
-                   (off && off < sizeof(struct icmp)))
-                       fi.fi_fl |= FI_SHORT;
-               break;
-       case IPPROTO_TCP :
-               fi.fi_fl |= FI_TCPUDP;
-               if ((!IPMINLEN(ip, tcphdr) && !off) ||
-                   (off && off < sizeof(struct tcphdr)))
-                       fi.fi_fl |= FI_SHORT;
-               break;
-       case IPPROTO_UDP :
-               fi.fi_fl |= FI_TCPUDP;
-               if ((!IPMINLEN(ip, udphdr) && !off) ||
-                   (off && off < sizeof(struct udphdr)))
-                       fi.fi_fl |= FI_SHORT;
-               break;
-       default :
-               break;
-       }
-
-       for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) {
-               if (!(opt = *s))
-                       break;
-               ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1);
-               if (opt > 1 && (ol < 0 || ol > hlen))
-                       break;
-               for (i = 9, mv = 4; mv >= 0; ) {
-                       op = ipopts + i;
-                       if (opt == (u_char)op->ol_val) {
-                               optmsk |= op->ol_bit;
-                               if (opt == IPOPT_SECURITY) {
-                                       struct optlist *sp;
-                                       u_char  sec;
-                                       int j, m;
-
-                                       sec = *(s + 3); /* classification */
-                                       for (j = 3, m = 2; m >= 0; ) {
-                                               sp = secopt + j;
-                                               if (sec == sp->ol_val) {
-                                                       secmsk |= sp->ol_bit;
-                                                       auth = *(s + 3);
-                                                       auth *= 256;
-                                                       auth += *(s + 4);
-                                                       break;
-                                               }
-                                               if (sec < sp->ol_val)
-                                                       j -= m--;
-                                               else
-                                                       j += m--;
-                                       }
-                               }
-                               break;
-                       }
-                       if (opt < op->ol_val)
-                               i -= mv--;
-                       else
-                               i += mv--;
-               }
-               hlen -= ol;
-               s += ol;
-       }
-       if (auth && !(auth & 0x0100))
-               auth &= 0xff00;
-       fi.fi_optmsk = optmsk;
-       fi.fi_secmsk = secmsk;
-       fi.fi_auth = auth;
-       return &fi;
-}
-
-
-/*
- * check an IP packet for TCP/UDP characteristics such as ports and flags.
- */
-int fr_tcpudpchk(ip, tcp, fr)
-ip_t *ip;
-tcphdr_t *tcp;
-struct frentry *fr;
-{
-       register u_short po, tup;
-       register char i;
-       int err = 1;
-
-       /*
-        * Both ports should *always* be in the first fragment.
-        * So far, I cannot find any cases where they can not be.
-        *
-        * compare destination ports
-        */
-       if ((i = (int)fr->fr_dcmp)) {
-               po = ntohs(fr->fr_dport);
-               tup = ntohs(tcp->th_dport);
-               /*
-                * Do opposite test to that required and
-                * continue if that succeeds.
-                */
-               if (!--i && tup != po) /* EQUAL */
-                       err = 0;
-               else if (!--i && tup == po) /* NOTEQUAL */
-                       err = 0;
-               else if (!--i && tup >= po) /* LESSTHAN */
-                       err = 0;
-               else if (!--i && tup <= po) /* GREATERTHAN */
-                       err = 0;
-               else if (!--i && tup > po) /* LT or EQ */
-                       err = 0;
-               else if (!--i && tup < po) /* GT or EQ */
-                       err = 0;
-               else if (!--i &&           /* Out of range */
-                        (tup >= po && tup <= ntohs(fr->fr_dtop)))
-                       err = 0;
-               else if (!--i &&           /* In range */
-                        (tup <= po || tup >= ntohs(fr->fr_dtop)))
-                       err = 0;
-       }
-       /*
-        * compare source ports
-        */
-       if (err && (i = (int)fr->fr_scmp)) {
-               po = ntohs(fr->fr_sport);
-               tup = ntohs(tcp->th_sport);
-               if (!--i && tup != po)
-                       err = 0;
-               else if (!--i && tup == po)
-                       err = 0;
-               else if (!--i && tup >= po)
-                       err = 0;
-               else if (!--i && tup <= po)
-                       err = 0;
-               else if (!--i && tup > po)
-                       err = 0;
-               else if (!--i && tup < po)
-                       err = 0;
-               else if (!--i &&           /* Out of range */
-                        (tup >= po && tup <= ntohs(fr->fr_stop)))
-                       err = 0;
-               else if (!--i &&           /* In range */
-                        (tup <= po || tup >= ntohs(fr->fr_stop)))
-                       err = 0;
-       }
-
-       /*
-        * If we don't have all the TCP/UDP header, then how can we
-        * expect to do any sort of match on it ?  If we were looking for
-        * TCP flags, then NO match.  If not, then match (which should
-        * satisfy the "short" class too).
-        */
-       if (err)
-               if (ip->ip_p == IPPROTO_TCP) {
-                       if (!IPMINLEN(ip, tcphdr))
-                               return !(fr->fr_tcpf);
-                       /*
-                        * Match the flags ?  If not, abort this match.
-                        */
-                       if (fr->fr_tcpf &&
-                           fr->fr_tcpf != (tcp->th_flags & fr->fr_tcpfm)) {
-                               FR_DEBUG(("f. %#x & %#x != %#x\n",
-                                        tcp->th_flags, fr->fr_tcpfm,
-                                        fr->fr_tcpf));
-                               err = 0;
-                       }
-               }
-               else if (!IPMINLEN(ip, udphdr)) /* must be UDP */
-                       return 1;
-       return err;
-}
-
-/*
- * Check the input/output list of rules for a match and result.
- * Could be per interface, but this gets real nasty when you don't have
- * kernel sauce.
- */
-int fr_scanlist(pass, ip, hlen, ifp, out, rule)
-int pass;
-ip_t *ip;
-int hlen, out;
-struct ifnet *ifp;
-u_short *rule;
-{
-       register struct frentry *fr;
-       register struct fr_ip *fi;
-       tcphdr_t *tcp;
-       int     rulen;
-
-       *rule = 1;
-       tcp = (tcphdr_t *)((char *)ip + hlen);
-       fr = (out) ? filterout[fr_active] : filterin[fr_active];
-       fi = fr_makefrip(hlen, ip);
-
-       for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
-               /*
-                * In all checks below, a null (zero) value in the
-                * filter struture is taken to mean a wildcard.
-                *
-                * check that we are working for the right interface
-                */
-#ifdef _KERNEL
-               if (fr->fr_ifa && fr->fr_ifa != ifp)
-                       continue;
-#else
-               if (opts & (OPT_VERBOSE|OPT_DEBUG))
-                       printf("\n");
-               FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 'b'));
-               if (ifp && *fr->fr_ifname && strcasecmp(ifp->if_name,
-                                                       fr->fr_ifname))
-                       continue;
-               FR_VERBOSE((":i"));
-#endif
-               {
-                       register u_long *ld, *lm, *lip;
-                       register int i;
-
-                       lip = (u_long *)fi;
-                       lm = (u_long *)&fr->fr_mip;
-                       ld = (u_long *)&fr->fr_ip;
-                       i = ((lip[0] & lm[0]) != ld[0]);
-                       FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n",
-                                  lip[0], lm[0], ld[0]));
-                       i |= ((lip[1] & lm[1]) != ld[1]);
-                       FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
-                                  lip[1], lm[1], ld[1]));
-                       i |= ((lip[2] & lm[2]) != ld[2]);
-                       FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
-                                  lip[2], lm[2], ld[2]));
-                       i |= ((lip[3] & lm[3]) != ld[3]);
-                       FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n",
-                                  lip[3], lm[3], ld[3]));
-                       i |= ((lip[4] & lm[4]) != ld[4]);
-                       FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
-                                  lip[4], lm[4], ld[4]));
-                       if (i)
-                               continue;
-               }
-
-               /*
-                * If a fragment, then only the first has what we're looking
-                * for here...
-                */
-               if (!(ip->ip_off & 0x1fff)) {
-                       if ((fi->fi_fl & FI_TCPUDP) &&
-                           !fr_tcpudpchk(ip, tcp, fr))
-                               continue;
-                       else if (ip->ip_p == IPPROTO_ICMP &&
-                                  (*(u_short *)((char *)ip + hlen) &
-                                    fr->fr_icmpm) != fr->fr_icmp) {
-                               FR_DEBUG(("i. %#x & %#x != %#x\n",
-                                        *(u_short *)((char *)ip + hlen),
-                                        fr->fr_icmpm, fr->fr_icmp));
-                               continue;
-                       }
-               } else if (fr->fr_dcmp || fr->fr_scmp || fr->fr_icmpm ||
-                          fr->fr_tcpfm)
-                       continue;
-               FR_VERBOSE(("*"));
-               /*
-                * Just log this packet...
-                */
-               if (fr->fr_flags & FR_LOG) {
-#ifdef IPFILTER_LOG
-                       if (!ipllog(hlen, fr->fr_flags, ip, ifp, *rule))
-                               frstats[out].fr_skip++;
-                       frstats[out].fr_pkl++;
-#endif /* IPFILTER_LOG */
-               } else
-                       pass = fr->fr_flags;
-               FR_DEBUG(("pass %#x\n", pass));
-               fr->fr_hits++;
-               *rule = rulen;
-               if (pass & FR_QUICK)
-                       break;
-       }
-       return pass;
-}
-
-
-/*
- * frcheck - filter check
- * check using source and destination addresses/pors in a packet whether
- * or not to pass it on or not.
- */
-int fr_check(ip, hlen, ifp, out
-#if SOLARIS && defined(_KERNEL)
-, qif, q)
-qif_t *qif;
-queue_t *q;
-#else
-)
-#endif
-ip_t *ip;
-int hlen;
-struct ifnet *ifp;
-int out;
-{
-       int pass = FR_NOMATCH;
-       int sl;
-       u_short rule;
-
-       SPLNET(sl);
-
-       pass = fr_scanlist(pass, ip, hlen, ifp, out, &rule);
-       if (pass == FR_NOMATCH) {
-               frstats[out].fr_nom++;
-#ifdef NOMATCH
-               pass |= NOMATCH;
-#endif
-       }
-
-#ifdef IPFILTER_LOG
-       if ((pass & FR_LOGP) ||
-           ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
-               if (!(pass & FR_LOGP))
-                       pass |= FF_LOGPASS << 8;
-               if (!ipllog(hlen, pass, ip, ifp, rule))
-                       frstats[out].fr_skip++;
-               frstats[out].fr_ppkl++;
-       } else if ((pass & FR_LOGB) ||
-                  ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
-               if (!(pass & FR_LOGB))
-                       pass |= FF_LOGBLOCK << 8;
-               if (!ipllog(hlen, pass, ip, ifp, rule))
-                       frstats[out].fr_skip++;
-               frstats[out].fr_bpkl++;
-       }
-#endif /* IPFILTER_LOG */
-       SPLX(sl);
-       if (pass & FR_PASS)
-               frstats[out].fr_pass++;
-       else if (pass & FR_BLOCK) {
-               frstats[out].fr_block++;
-               /*
-                * Should we return an ICMP packet to indicate error
-                * status passing through the packet filter ?
-                * XXX - copy mbuf as icmp_error() calls mfree() - fix this
-                * later, but preserve backward compatibility for now.
-                */
-#ifdef _KERNEL
-               if (pass & FR_RETICMP) {
-# if SOLARIS
-                       icmp_error(q, ip, ICMP_UNREACH, ipl_unreach, qif,
-                                  ip->ip_src);
-# else
-                       struct mbuf *copy;
-
-                       copy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64));
-#  if BSD < 199103
-                       icmp_error(mtod(copy, struct ip *),
-                                  ICMP_UNREACH, ipl_unreach, ifp, ip->ip_src);
-#  else
-                       icmp_error(copy, ICMP_UNREACH, ipl_unreach,
-                                  ip->ip_src.s_addr, ifp);
-#  endif
-# endif
-                       frstats[0].fr_ret++;
-               } else if (pass & FR_RETRST && IPMINLEN(ip, tcphdr)) {
-# if SOLARIS
-                       if (send_reset(ip, qif, q) == 0)
-# else
-                       if (send_reset(ip) == 0)
-# endif
-                               frstats[1].fr_ret++;
-               }
-#else
-               if (pass & FR_RETICMP) {
-                       verbose("- ICMP unreachable sent\n");
-                       frstats[0].fr_ret++;
-               } else if (pass & FR_RETRST && IPMINLEN(ip, tcphdr)) {
-                       verbose("- TCP RST sent\n");
-                       frstats[1].fr_ret++;
-               }
-#endif
-       }
-#ifdef _KERNEL
-       return (pass & FR_PASS) ? 0 : -1;
-#else
-       if (pass & FR_NOMATCH)
-               return 1;
-       if (pass & FR_PASS)
-               return 0;
-       return -1;
-#endif
-}
-
-
-#ifndef        _KERNEL
-int ipllog()
-{
-       verbose("l");
-       return 1;
-}
-#endif
index fb8f672..8c0df1f 100644 (file)
@@ -41,7 +41,7 @@ etherfind -n -t
 #include <netinet/tcpip.h>
 #include <net/if.h>
 #include <netdb.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include "ipf.h"
 #include "ipt.h"
 
index 06af91f..18bd29f 100644 (file)
@@ -25,7 +25,7 @@
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include "ipf.h"
 #include "ipt.h"
 #include "pcap.h"
@@ -122,6 +122,7 @@ struct      pcap_pkthdr *rec;
 }
 
 
+#ifdef notyet
 /*
  * read an entire pcap packet record.  only the data part is copied into
  * the available buffer, with the number of bytes copied returned.
@@ -149,6 +150,7 @@ int cnt;
        bcopy(bufp, buf, n);
        return n;
 }
+#endif
 
 
 /*
index b94a477..68978d8 100644 (file)
@@ -28,7 +28,7 @@
 #include <netinet/tcp.h>
 #include <netinet/tcpip.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include "ipf.h"
 #include "ipt.h"
 #include "snoop.h"
@@ -125,6 +125,7 @@ struct      snooppkt *rec;
 }
 
 
+#ifdef notyet
 /*
  * read an entire snoop packet record.  only the data part is copied into
  * the available buffer, with the number of bytes copied returned.
@@ -152,6 +153,7 @@ int cnt;
        bcopy(bufp, buf, n);
        return n;
 }
+#endif
 
 
 /*
index 3ddee11..7d9ea2b 100644 (file)
@@ -50,17 +50,17 @@ tcpdump -nqte
 #include <netinet/tcpip.h>
 #include <net/if.h>
 #include <netdb.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include "ipf.h"
 #include "ipt.h"
 
 #ifndef lint
-static char sccsid[] = "@(#)ipft_td.c  1.6 10/15/95 (C)1995 Darren Reed";
+static char sccsid[] = "@(#)ipft_td.c  1.7 1/12/96 (C)1995 Darren Reed";
 #endif
 
 static int     tcpd_open(), tcpd_close(), tcpd_readip();
 #ifdef NEED_INET_ATON
-static u_long  inet_aton();
+extern u_long  inet_aton();
 #else
 #include <arpa/inet.h>
 #endif
index 4ca44a8..a77c52b 100644 (file)
@@ -6,6 +6,7 @@
  * to the original author and the contributors.
  */
 #include <stdio.h>
+#include <ctype.h>
 #include <assert.h>
 #include <string.h>
 #if !defined(__SVR4) && !defined(__svr4__)
@@ -29,7 +30,7 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/tcpip.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include <netdb.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
 #include "ipt.h"
 
 #ifndef        lint
-static char    sccsid[] = "@(#)ipft_tx.c       1.2 10/17/95 (C) 1993 Darren Reed";
+static char    sccsid[] = "@(#)ipft_tx.c       1.5 1/12/96 (C) 1993 Darren Reed";
 #endif
 
 extern int     opts;
+extern u_short portnum();
+extern u_long  buildopts();
 
 static int     text_open(), text_close(), text_readip(), parseline();
 
@@ -120,7 +123,7 @@ int *out;
        tcphdr_t        th, *tcp = &th;
        struct  icmp    icmp, *ic = &icmp;
        char    *cps[20], **cpp, c, opts[68];
-       int     i;
+       int     i, r;
 
        bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip));
        bzero((char *)tcp, sizeof(*tcp));
@@ -184,7 +187,7 @@ int *out;
                *last++ = '\0';
                tcp->th_sport = portnum(last);
        }
-       ip->ip_src.s_addr = hostnum(*cpp);
+       ip->ip_src.s_addr = hostnum(*cpp, &r);
        cpp++;
        if (!*cpp)
                return 1;
@@ -200,7 +203,7 @@ int *out;
                *last++ = '\0';
                tcp->th_dport = portnum(last);
        }
-       ip->ip_dst.s_addr = hostnum(*cpp);
+       ip->ip_dst.s_addr = hostnum(*cpp, &r);
        cpp++;
        if (*cpp && ip->ip_p == IPPROTO_TCP) {
                extern  char    flagset[];
index bbb5d2a..f251650 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C)opyright 1993,1994,1995 by Darren Reed.
+ * (C)opyright 1993-1996 by Darren Reed.
  *
  * Redistribution and use in source and binary forms are permitted
  * provided that this notice is preserved and due credit is given
@@ -29,7 +29,7 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/tcpip.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include <netdb.h>
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
 #include <ctype.h>
 
 #ifndef        lint
-static char    sccsid[] = "@(#)ipt.c   1.13 11/11/95 (C) 1993 Darren Reed";
+static char    sccsid[] = "@(#)ipt.c   1.15 1/7/96 (C) 1993-1996 Darren Reed";
 #endif
 
 extern int     fr_check();
 extern char    *optarg;
-extern struct  frentry *filterin[], *filterout[];
+extern struct  frentry *ipfilter[2][2];
 extern struct  ipread  snoop, etherf, tcpd, pcap, iptext;
 extern void    debug(), verbose();
 
@@ -148,12 +148,12 @@ char *argv[];
                        f = (struct frentry *)malloc(sizeof(*f));
                        if (fr->fr_flags & FR_INQUE) {
                                if (!ft_in)
-                                       ft_in = filterin[0] = f;
+                                       ft_in = ipfilter[0][0] = f;
                                else
                                        ft_in->fr_next = f, ft_in = f;
                        } else if (fr->fr_flags & FR_OUTQUE) {
                                if (!ft_out)
-                                       ft_out = filterout[0] = f;
+                                       ft_out = ipfilter[1][0] = f;
                                else
                                        ft_out->fr_next = f, ft_out = f;
                        }
index 89a9883..6329cd4 100644 (file)
@@ -21,6 +21,7 @@
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip_var.h>
 #include <netinet/ip.h>
@@ -29,7 +30,7 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/tcpip.h>
 #include <net/if.h>
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 #include <netdb.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
@@ -37,7 +38,7 @@
 #include "ipt.h"
 
 #ifndef        lint
-static char    sccsid[] = "@(#)misc.c  1.1 10/15/95 (C) 1995 Darren Reed";
+static char    sccsid[] = "@(#)misc.c  1.2 1/12/96 (C) 1995 Darren Reed";
 #endif
 
 void   debug(), verbose();
index 1a74316..e14e3d6 100644 (file)
@@ -1,6 +1,7 @@
 PROG=  ipmon
 MAN=   ipmon.8 
-CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -DLOGFAC=LOG_LOCAL0
+CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -DLOGFAC=LOG_LOCAL0 \
+       -I${.CURDIR}/../../sys/netinet
 
 
 .include <bsd.prog.mk>
index 0ba67d2..101f2aa 100644 (file)
 #include <arpa/inet.h>
 
 #ifndef        lint
-static char    sccsid[] = "@(#)ipmon.c 1.13 11/11/95 (C)1995 Darren Reed";
+static char    sccsid[] = "@(#)ipmon.c 1.16 1/12/96 (C)1995 Darren Reed";
 #endif
 
-#include <netinet/ip_fil.h>
+#include "ip_fil.h"
 
 struct flags {
        int     value;
@@ -122,7 +122,7 @@ int opts;
                        tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
                t += strlen(t);
        }
-       (void) sprintf(t, "%02d:%02d:%02d.%-.6d %c%c%d @%d ",
+       (void) sprintf(t, "%02d:%02d:%02d.%-.6ld %c%c%ld @%hd ",
                tm->tm_hour, tm->tm_min, tm->tm_sec, lp->usec,
                lp->ifname[0], lp->ifname[1], lp->unit, lp->rule);
        pr = getprotobynumber((int)p);
@@ -132,7 +132,7 @@ int opts;
        } else
                proto = pr->p_name;
 
-       if (lp->flags & (FI_SHORT << 16)) {
+       if (lp->flags & (FI_SHORT << 20)) {
                c[0] = 'S';
                lvl = LOG_ERR;
        } else if (lp->flags & FR_PASS) {
@@ -147,6 +147,9 @@ int opts;
                else
                        c[0] = 'B';
                lvl = LOG_WARNING;
+       } else if (lp->flags & FF_LOGNOMATCH) {
+               c[0] = 'n';
+               lvl = LOG_NOTICE;
        } else {
                c[0] = 'L';
                lvl = LOG_INFO;
@@ -155,6 +158,10 @@ int        opts;
        c[2] = '\0';
        (void) strcat(line, c);
        t = line + strlen(line);
+#if    SOLARIS
+       ip->ip_off = ntohs(ip->ip_off);
+       ip->ip_len = ntohs(ip->ip_len);
+#endif
 
        if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !(ip->ip_off & 0x1fff)) {
                tp = (struct tcphdr *)((char *)ip + hl);
@@ -163,21 +170,23 @@ int       opts;
                                hostname(res, ip->ip_src),
                                portname(res, proto, tp->th_sport));
                        t += strlen(t);
-                       (void) sprintf(t, "%s,%s PR %s len %hu (%hu) ",
+                       (void) sprintf(t, "%s,%s PR %s len %hu %hu ",
                                hostname(res, ip->ip_dst),
                                portname(res, proto, tp->th_dport),
                                proto, hl, ip->ip_len);
                        t += strlen(t);
 
-                       if (p == IPPROTO_TCP)
+                       if (p == IPPROTO_TCP) {
+                               *t++ = '-';
                                for (i = 0; tcpfl[i].value; i++)
                                        if (tp->th_flags & tcpfl[i].value)
                                                *t++ = tcpfl[i].flag;
+                       }
                        *t = '\0';
                } else {
                        (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src));
                        t += strlen(t);
-                       (void) sprintf(t, "%s PR %s len %hu (%hu)",
+                       (void) sprintf(t, "%s PR %s len %hu %hu",
                                hostname(res, ip->ip_dst), proto,
                                hl, ip->ip_len);
                }
@@ -209,7 +218,7 @@ int opts;
                                hostname(res, ipc->ip_src),
                                portname(res, proto, tp->th_sport));
                        t += strlen(t);
-                       (void) sprintf(t, " %s,%s PR %s len %hu (%hu)",
+                       (void) sprintf(t, " %s,%s PR %s len %hu %hu",
                                hostname(res, ipc->ip_dst),
                                portname(res, proto, tp->th_dport),
                                proto, ipc->ip_hl << 2, ipc->ip_len);
@@ -221,8 +230,9 @@ int opts;
                        hostname(res, ip->ip_dst), proto, hl, ip->ip_len);
                t += strlen(t);
                if (ip->ip_off & 0x1fff)
-                       (void) sprintf(t, " frag %s%hu@%hu",
+                       (void) sprintf(t, " frag %s%s%hu@%hu",
                                ip->ip_off & IP_MF ? "+" : "",
+                               ip->ip_off & IP_DF ? "-" : "",
                                ip->ip_len - hl, (ip->ip_off & 0x1fff) << 3);
        }
        t += strlen(t);
@@ -255,7 +265,11 @@ char *argv[];
                switch (c)
                {
                case 'f' :
-                       (void) ioctl(fd, SIOCIPFFB, &flushed);
+                       if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
+                               printf("%d bytes flushed from log buffer\n",
+                                       flushed);
+                               fflush(stdout);
+                       }
                        break;
                case 'N' :
                        opts |= 2;
index 7555119..7d279e5 100644 (file)
@@ -2,7 +2,7 @@ PROG=   ipsend
 NOMAN=         
 SRCS=  iptests.c ip.c ipsend.c ipsopt.c resend.c sbpf.c sock.c 44arp.c ipft_sn.c ipft_pc.c
 .PATH: ${.CURDIR}/../../usr.sbin/ipftest
-CFLAGS+=  -DDOSOCKET -I${.CURDIR}/../../usr.sbin/ipftest -I${.CURDIR}/../../sbin/ipf
+CFLAGS+=  -DDOSOCKET -I${.CURDIR}/../../usr.sbin/ipftest -I${.CURDIR}/../../sbin/ipf -I${.CURDIR}/../../sys/netinet
 LDADD+= -lpcap