From caac00b70fac239c5beba53067d8abea22fc4a49 Mon Sep 17 00:00:00 2001 From: dm Date: Thu, 25 Jan 1996 05:41:23 +0000 Subject: [PATCH] IP filter 3.0.1 --- sbin/ipf/Makefile | 2 +- sbin/ipf/ipf.1 | 12 +- sbin/ipf/ipf.5 | 21 +- sbin/ipf/ipf.c | 32 ++- sbin/ipf/ipf.h | 25 +- sbin/ipf/opt.c | 2 +- sbin/ipf/parse.c | 168 ++++++++++-- sbin/ipfstat/Makefile | 2 +- sbin/ipfstat/fils.c | 206 +++++++++++--- sbin/ipfstat/ipfstat.8 | 26 +- sbin/ipfstat/kmem.c | 3 +- sys/conf/files | 3 + sys/conf/files.oldconf | 3 + sys/netinet/fil.c | 226 +++++++++++----- sys/netinet/ip_fil.c | 127 ++++++--- sys/netinet/ip_fil.h | 373 ++++++++++++++------------ sys/netinet/ip_frag.c | 251 +++++++++++++++++ sys/netinet/ip_frag.h | 50 ++++ sys/netinet/ip_input.c | 19 +- sys/netinet/ip_nat.c | 497 ++++++++++++++++++++++++++++++++++ sys/netinet/ip_nat.h | 81 ++++++ sys/netinet/ip_output.c | 11 +- sys/netinet/ip_state.c | 393 +++++++++++++++++++++++++++ sys/netinet/ip_state.h | 84 ++++++ usr.sbin/ipftest/Makefile | 7 +- usr.sbin/ipftest/fil.c | 534 ------------------------------------- usr.sbin/ipftest/ipft_ef.c | 2 +- usr.sbin/ipftest/ipft_pc.c | 4 +- usr.sbin/ipftest/ipft_sn.c | 4 +- usr.sbin/ipftest/ipft_td.c | 6 +- usr.sbin/ipftest/ipft_tx.c | 13 +- usr.sbin/ipftest/ipt.c | 12 +- usr.sbin/ipftest/misc.c | 5 +- usr.sbin/ipmon/Makefile | 3 +- usr.sbin/ipmon/ipmon.c | 34 ++- usr.sbin/ipsend/Makefile | 2 +- 36 files changed, 2291 insertions(+), 952 deletions(-) create mode 100644 sys/netinet/ip_frag.c create mode 100644 sys/netinet/ip_frag.h create mode 100644 sys/netinet/ip_nat.c create mode 100644 sys/netinet/ip_nat.h create mode 100644 sys/netinet/ip_state.c create mode 100644 sys/netinet/ip_state.h delete mode 100644 usr.sbin/ipftest/fil.c diff --git a/sbin/ipf/Makefile b/sbin/ipf/Makefile index 32e77eb18fa..4be887d4890 100644 --- a/sbin/ipf/Makefile +++ b/sbin/ipf/Makefile @@ -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 diff --git a/sbin/ipf/ipf.1 b/sbin/ipf/ipf.1 index 1a4abc8bf44..59f8ea238e9 100644 --- a/sbin/ipf/ipf.1 +++ b/sbin/ipf/ipf.1 @@ -2,8 +2,8 @@ .SH NAME ipf - alters packet filtering lists for IP packet input and ouput .SH SYNOPSIS -ipf [-AEDIsnovdr] [-F ] -f <\fIfilename\fP> -[ -f <\fIfilename\fP> [...]] +ipf [-AEDIsnovdr] [-l ] [-F ] +-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 diff --git a/sbin/ipf/ipf.5 b/sbin/ipf/ipf.5 index 2e70be16e92..84f2023a800 100644 --- a/sbin/ipf/ipf.5 +++ b/sbin/ipf/ipf.5 @@ -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 diff --git a/sbin/ipf/ipf.c b/sbin/ipf/ipf.c index 12e8ff2caef..92fe2e6ee06 100644 --- a/sbin/ipf/ipf.c +++ b/sbin/ipf/ipf.c @@ -27,16 +27,21 @@ extern char *index(); #include #include #include -#include +#include "ip_fil.h" #include #include #include #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; diff --git a/sbin/ipf/ipf.h b/sbin/ipf/ipf.h index 537c15b901d..794f98c71e3 100644 --- a/sbin/ipf/ipf.h +++ b/sbin/ipf/ipf.h @@ -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(); diff --git a/sbin/ipf/opt.c b/sbin/ipf/opt.c index 5b7debfb2b4..8e90965928e 100644 --- a/sbin/ipf/opt.c +++ b/sbin/ipf/opt.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include "ip_fil.h" #include "ipf.h" #ifndef lint diff --git a/sbin/ipf/parse.c b/sbin/ipf/parse.c index 56cf14d0afd..efea74e9d57 100644 --- a/sbin/ipf/parse.c +++ b/sbin/ipf/parse.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include "ip_fil.h" #include #include #include @@ -32,23 +32,34 @@ #include #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("", 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'); } diff --git a/sbin/ipfstat/Makefile b/sbin/ipfstat/Makefile index bafd458b225..ba55b945e9e 100644 --- a/sbin/ipfstat/Makefile +++ b/sbin/ipfstat/Makefile @@ -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 diff --git a/sbin/ipfstat/fils.c b/sbin/ipfstat/fils.c index 7f440f6da39..ff91986d540 100644 --- a/sbin/ipfstat/fils.c +++ b/sbin/ipfstat/fils.c @@ -5,6 +5,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ + #include #include #if !defined(__SVR4) && !defined(__svr4__) @@ -21,10 +22,13 @@ #include #include #include +#include #include #include #include -#include +#include "ip_fil.h" +#include "ip_frag.h" +#include "ip_state.h" #include #include #include @@ -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; + } +} diff --git a/sbin/ipfstat/ipfstat.8 b/sbin/ipfstat/ipfstat.8 index bfc8b2ae262..1b378541580 100644 --- a/sbin/ipfstat/ipfstat.8 +++ b/sbin/ipfstat/ipfstat.8 @@ -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 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 diff --git a/sbin/ipfstat/kmem.c b/sbin/ipfstat/kmem.c index 4c0dbe3b520..159ff8456a1 100644 --- a/sbin/ipfstat/kmem.c +++ b/sbin/ipfstat/kmem.c @@ -10,6 +10,7 @@ * returns 0 on success, -1 on error. */ +#include #include #include #include @@ -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; diff --git a/sys/conf/files b/sys/conf/files index 714c28cee9a..9c57fdf5e17 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -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 diff --git a/sys/conf/files.oldconf b/sys/conf/files.oldconf index d1e0f0fe919..2a30b854d60 100644 --- a/sys/conf/files.oldconf +++ b/sys/conf/files.oldconf @@ -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 diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c index b485678d5a7..60a392119ed 100644 --- a/sys/netinet/fil.c +++ b/sys/netinet/fil.c @@ -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 # if defined(_KERNEL) || defined(KERNEL) # include +# else +# include # endif # include # 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 # include #endif -#include +#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 diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c index f234291a923..24ab8a5deaa 100644 --- a/sys/netinet/ip_fil.c +++ b/sys/netinet/ip_fil.c @@ -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 #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]; diff --git a/sys/netinet/ip_fil.h b/sys/netinet/ip_fil.h index 8d4380dd4cc..67e985af645 100644 --- a/sys/netinet/ip_fil.h +++ b/sys/netinet/ip_fil.h @@ -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 +# 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 index 00000000000..344423b0d71 --- /dev/null +++ b/sys/netinet/ip_frag.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(__SVR4) && !defined(__svr4__) +# include +# include +#else +# include +# include +# include +# include +#endif + +#include +#ifdef sun +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 00000000000..438c8392d73 --- /dev/null +++ b/sys/netinet/ip_frag.h @@ -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__ */ diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 897583fcfb4..6b446c2780f 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -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 index 00000000000..52bd755a1d7 --- /dev/null +++ b/sys/netinet/ip_nat.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(__SVR4) && !defined(__svr4__) +# include +# include +#else +# include +# include +# include +# include +#endif + +#include +#ifdef sun +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 00000000000..be38821806e --- /dev/null +++ b/sys/netinet/ip_nat.h @@ -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__ */ diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 7e7d7097b37..cb399c1cfff 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -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 index 00000000000..69491a9844f --- /dev/null +++ b/sys/netinet/ip_state.c @@ -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 +#ifndef linux +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(__SVR4) && !defined(__svr4__) +# include +# include +#else +# include +# include +# include +# include +#endif + +#include +#ifdef sun +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 00000000000..d22c930504d --- /dev/null +++ b/sys/netinet/ip_state.h @@ -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__ */ diff --git a/usr.sbin/ipftest/Makefile b/usr.sbin/ipftest/Makefile index 723b31469d7..adfc9c02561 100644 --- a/usr.sbin/ipftest/Makefile +++ b/usr.sbin/ipftest/Makefile @@ -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 diff --git a/usr.sbin/ipftest/fil.c b/usr.sbin/ipftest/fil.c deleted file mode 100644 index b485678d5a7..00000000000 --- a/usr.sbin/ipftest/fil.c +++ /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 -# include -# include -# include -# include -# if defined(_KERNEL) || defined(KERNEL) -# include -# endif -# include -# if !defined(__SVR4) && !defined(__svr4__) -# include -# include -# else -# include -# include -# include -# endif -# include -# include -# include -# ifdef sun -# include -# endif -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif -#include -#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 diff --git a/usr.sbin/ipftest/ipft_ef.c b/usr.sbin/ipftest/ipft_ef.c index fb8f67215b8..8c0df1f719f 100644 --- a/usr.sbin/ipftest/ipft_ef.c +++ b/usr.sbin/ipftest/ipft_ef.c @@ -41,7 +41,7 @@ etherfind -n -t #include #include #include -#include +#include "ip_fil.h" #include "ipf.h" #include "ipt.h" diff --git a/usr.sbin/ipftest/ipft_pc.c b/usr.sbin/ipftest/ipft_pc.c index 06af91f4897..18bd29fa95a 100644 --- a/usr.sbin/ipftest/ipft_pc.c +++ b/usr.sbin/ipftest/ipft_pc.c @@ -25,7 +25,7 @@ #include #include #include -#include +#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 /* diff --git a/usr.sbin/ipftest/ipft_sn.c b/usr.sbin/ipftest/ipft_sn.c index b94a477e61b..68978d8dc37 100644 --- a/usr.sbin/ipftest/ipft_sn.c +++ b/usr.sbin/ipftest/ipft_sn.c @@ -28,7 +28,7 @@ #include #include #include -#include +#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 /* diff --git a/usr.sbin/ipftest/ipft_td.c b/usr.sbin/ipftest/ipft_td.c index 3ddee115192..7d9ea2b8849 100644 --- a/usr.sbin/ipftest/ipft_td.c +++ b/usr.sbin/ipftest/ipft_td.c @@ -50,17 +50,17 @@ tcpdump -nqte #include #include #include -#include +#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 #endif diff --git a/usr.sbin/ipftest/ipft_tx.c b/usr.sbin/ipftest/ipft_tx.c index 4ca44a8380e..a77c52b5ff9 100644 --- a/usr.sbin/ipftest/ipft_tx.c +++ b/usr.sbin/ipftest/ipft_tx.c @@ -6,6 +6,7 @@ * to the original author and the contributors. */ #include +#include #include #include #if !defined(__SVR4) && !defined(__svr4__) @@ -29,7 +30,7 @@ #include #include #include -#include +#include "ip_fil.h" #include #include #include @@ -37,10 +38,12 @@ #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[]; diff --git a/usr.sbin/ipftest/ipt.c b/usr.sbin/ipftest/ipt.c index bbb5d2a3e5f..f25165063c8 100644 --- a/usr.sbin/ipftest/ipt.c +++ b/usr.sbin/ipftest/ipt.c @@ -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 #include #include -#include +#include "ip_fil.h" #include #include #include @@ -39,12 +39,12 @@ #include #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; } diff --git a/usr.sbin/ipftest/misc.c b/usr.sbin/ipftest/misc.c index 89a9883c4d7..6329cd483b4 100644 --- a/usr.sbin/ipftest/misc.c +++ b/usr.sbin/ipftest/misc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ #include #include #include -#include +#include "ip_fil.h" #include #include #include @@ -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(); diff --git a/usr.sbin/ipmon/Makefile b/usr.sbin/ipmon/Makefile index 1a743162356..e14e3d60103 100644 --- a/usr.sbin/ipmon/Makefile +++ b/usr.sbin/ipmon/Makefile @@ -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 diff --git a/usr.sbin/ipmon/ipmon.c b/usr.sbin/ipmon/ipmon.c index 0ba67d2f252..101f2aa58eb 100644 --- a/usr.sbin/ipmon/ipmon.c +++ b/usr.sbin/ipmon/ipmon.c @@ -39,10 +39,10 @@ #include #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 +#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; diff --git a/usr.sbin/ipsend/Makefile b/usr.sbin/ipsend/Makefile index 7555119420f..7d279e58224 100644 --- a/usr.sbin/ipsend/Makefile +++ b/usr.sbin/ipsend/Makefile @@ -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 -- 2.20.1