From 24d567d60d19176da8e2bad44038679ecf5c2e64 Mon Sep 17 00:00:00 2001 From: martti Date: Sun, 28 Mar 2004 09:00:53 +0000 Subject: [PATCH] Upgraded IPFilter to 4.1.1 --- dist/ipf/BNF | 27 +- dist/ipf/FWTK/fwtk-2.1-transparency.txt | 707 --- dist/ipf/FWTK/fwtk_transparent.diff | 4 +- dist/ipf/FWTK/tproxy.diff | 82 - dist/ipf/HISTORY | 630 +-- dist/ipf/Makefile | 303 +- dist/ipf/OpenBSD/files.diffs | 18 + dist/ipf/OpenBSD/kinstall | 82 + dist/ipf/OpenBSD/mknewipf.sh | 21 + dist/ipf/OpenBSD/patch.1 | 23 + dist/ipf/OpenBSD/unkinstall | 53 + dist/ipf/QNX_OCL.txt | 275 -- dist/ipf/UPGRADE_NOTICE | 10 - dist/ipf/common.c | 614 --- dist/ipf/etc/services | 2 +- dist/ipf/facpri.c | 154 - dist/ipf/facpri.h | 42 - dist/ipf/fils.c | 1536 ------ dist/ipf/ipf.c | 633 --- dist/ipf/ipf.h | 345 +- dist/ipf/ipfs.c | 806 --- dist/ipf/ipft_ef.c | 159 - dist/ipf/ipft_hx.c | 177 - dist/ipf/ipft_pc.c | 238 - dist/ipf/ipft_sn.c | 222 - dist/ipf/ipft_td.c | 197 - dist/ipf/ipft_tx.c | 357 -- dist/ipf/iplang/Makefile | 35 +- dist/ipf/iplang/iplang_l.l | 21 +- dist/ipf/iplang/iplang_y.y | 30 +- dist/ipf/ipmon.c | 1500 ------ dist/ipf/ipnat.c | 394 -- dist/ipf/ipsd/ipsd.c | 7 +- dist/ipf/ipsd/ipsd.h | 5 +- dist/ipf/ipsd/ipsdr.c | 7 +- dist/ipf/ipsd/slinux.c | 5 +- dist/ipf/ipsd/snit.c | 5 +- dist/ipf/ipsend/44arp.c | 30 +- dist/ipf/ipsend/arp.c | 35 +- dist/ipf/ipsend/dlcommon.c | 2 +- dist/ipf/ipsend/hpux.c | 6 +- dist/ipf/ipsend/ip.c | 100 +- dist/ipf/ipsend/ip_var.h | 4 +- dist/ipf/ipsend/ipresend.c | 35 +- dist/ipf/ipsend/ipsend.c | 166 +- dist/ipf/ipsend/ipsend.h | 24 +- dist/ipf/ipsend/ipsopt.c | 35 +- dist/ipf/ipsend/iptest.c | 35 +- dist/ipf/ipsend/iptests.c | 179 +- dist/ipf/ipsend/larp.c | 14 +- dist/ipf/ipsend/linux.h | 6 +- dist/ipf/ipsend/lsock.c | 10 +- dist/ipf/ipsend/resend.c | 43 +- dist/ipf/ipsend/sbpf.c | 37 +- dist/ipf/ipsend/sdlpi.c | 67 +- dist/ipf/ipsend/sirix.c | 12 +- dist/ipf/ipsend/slinux.c | 9 +- dist/ipf/ipsend/snit.c | 9 +- dist/ipf/ipsend/sock.c | 54 +- dist/ipf/ipsend/tcpip.h | 8 +- dist/ipf/ipsend/ultrix.c | 86 - dist/ipf/ipt.c | 512 -- dist/ipf/ipt.h | 14 +- dist/ipf/kmem.c | 244 - dist/ipf/kmem.h | 5 +- dist/ipf/man/Makefile | 11 +- dist/ipf/man/ipf.4 | 8 +- dist/ipf/man/ipf.5 | 31 +- dist/ipf/man/ipf.8 | 36 +- dist/ipf/man/ipfs.8 | 10 +- dist/ipf/man/ipfstat.8 | 14 +- dist/ipf/man/ipftest.1 | 65 +- dist/ipf/man/ipl.4 | 6 +- dist/ipf/man/ipmon.8 | 11 +- dist/ipf/man/ipnat.5 | 125 +- dist/ipf/man/ipnat.8 | 4 +- dist/ipf/misc.c | 211 - dist/ipf/ml_ipl.c | 11 +- dist/ipf/natparse.c | 783 --- dist/ipf/opt.c | 183 - dist/ipf/parse.c | 1431 ------ dist/ipf/pcap.h | 36 - dist/ipf/printnat.c | 485 -- dist/ipf/printstate.c | 149 - dist/ipf/relay.c | 222 - dist/ipf/samples/Makefile | 12 +- dist/ipf/samples/userauth.c | 12 +- dist/ipf/snoop.h | 4 +- dist/ipf/todo | 46 +- sys/lkm/netinet/if_ipl/mln_ipl.c | 101 +- sys/netinet/fil.c | 6038 ++++++++++++++++++----- sys/netinet/ip_auth.c | 611 ++- sys/netinet/ip_auth.h | 29 +- sys/netinet/ip_compat.h | 2380 ++++++--- sys/netinet/ip_fil.c | 2232 --------- sys/netinet/ip_fil.h | 1260 +++-- sys/netinet/ip_fil_netbsd.c | 5 +- sys/netinet/ip_frag.c | 794 +-- sys/netinet/ip_frag.h | 61 +- sys/netinet/ip_ftp_pxy.c | 874 ++-- sys/netinet/ip_h323_pxy.c | 175 +- sys/netinet/ip_ipsec_pxy.c | 212 +- sys/netinet/ip_log.c | 594 ++- sys/netinet/ip_nat.c | 4606 +++++++++++------ sys/netinet/ip_nat.h | 437 +- sys/netinet/ip_netbios_pxy.c | 55 +- sys/netinet/ip_proxy.c | 417 +- sys/netinet/ip_proxy.h | 269 +- sys/netinet/ip_raudio_pxy.c | 142 +- sys/netinet/ip_rcmd_pxy.c | 165 +- sys/netinet/ip_state.c | 3757 +++++++++----- sys/netinet/ip_state.h | 195 +- sys/netinet/ipl.h | 10 +- 113 files changed, 18047 insertions(+), 22785 deletions(-) delete mode 100644 dist/ipf/FWTK/fwtk-2.1-transparency.txt delete mode 100644 dist/ipf/FWTK/tproxy.diff create mode 100644 dist/ipf/OpenBSD/files.diffs create mode 100644 dist/ipf/OpenBSD/kinstall create mode 100644 dist/ipf/OpenBSD/mknewipf.sh create mode 100644 dist/ipf/OpenBSD/patch.1 create mode 100644 dist/ipf/OpenBSD/unkinstall delete mode 100644 dist/ipf/QNX_OCL.txt delete mode 100644 dist/ipf/UPGRADE_NOTICE delete mode 100644 dist/ipf/common.c delete mode 100644 dist/ipf/facpri.c delete mode 100644 dist/ipf/facpri.h delete mode 100644 dist/ipf/fils.c delete mode 100644 dist/ipf/ipf.c delete mode 100644 dist/ipf/ipfs.c delete mode 100644 dist/ipf/ipft_ef.c delete mode 100644 dist/ipf/ipft_hx.c delete mode 100644 dist/ipf/ipft_pc.c delete mode 100644 dist/ipf/ipft_sn.c delete mode 100644 dist/ipf/ipft_td.c delete mode 100644 dist/ipf/ipft_tx.c delete mode 100644 dist/ipf/ipmon.c delete mode 100644 dist/ipf/ipnat.c delete mode 100644 dist/ipf/ipsend/ultrix.c delete mode 100644 dist/ipf/ipt.c delete mode 100644 dist/ipf/kmem.c delete mode 100644 dist/ipf/misc.c delete mode 100644 dist/ipf/natparse.c delete mode 100644 dist/ipf/opt.c delete mode 100644 dist/ipf/parse.c delete mode 100644 dist/ipf/pcap.h delete mode 100644 dist/ipf/printnat.c delete mode 100644 dist/ipf/printstate.c delete mode 100644 dist/ipf/relay.c delete mode 100644 sys/netinet/ip_fil.c diff --git a/dist/ipf/BNF b/dist/ipf/BNF index cf30ab6f1064..404cc281fccf 100644 --- a/dist/ipf/BNF +++ b/dist/ipf/BNF @@ -1,25 +1,26 @@ filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] - [ proto ] [ ip ] [ group ]. + [ proto ] [ ip ] [ group ] [ tag ] [ pps ] . insert = "@" decnumber . -action = block | "no-match" | "pass" | log | "count" | skip | auth | call . +action = block | "pass" | log | "count" | auth | call . in-out = "in" | "out" . -options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] - [ via ] ] . +options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] . tos = "tos" decnumber | "tos" hexnumber . ttl = "ttl" decnumber . proto = "proto" protocol . ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . group = [ "head" decnumber ] [ "group" decnumber ] . +pps = "pps" decnumber . +onif = "on" interface-name [ "out-via" interface-name ] . block = "block" [ return-icmp[return-code] | "return-rst" ] . auth = "auth" | "preauth" . log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . -call = "call" [ "now" ] function-name . -skip = "skip" decnumber . +tag = "tag" tagid . +call = "call" [ "now" ] function-name "/" decnumber. dup = "dup-to" interface-name[":"ipaddr] . -via = "in-via" interface-name | "out-via" interface-name . -froute = "fastroute" | "to" interface-name [ ":" ipaddr ] . +froute = "fastroute" | "to" interface-name . +replyto = "reply-to" interface-name [ ":" ipaddr ] . protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . srcdst = "all" | fromto . fromto = "from" object "to" object . @@ -34,8 +35,7 @@ flags = "flags" flag { flag } [ "/" flag { flag } ] . with = "with" | "and" . icmp = "icmp-type" icmp-type [ "code" decnumber ] . return-code = "("icmp-code")" . -keep = "keep" "state" | "keep" "frags" | "keep" "state-age" state-age . -state-age = decnmber [ "/" decnumber ] . +keep = "keep" "state" [ "limit" number ] | "keep" "frags" . nummask = host-name [ "/" decnumber ] . host-name = ipaddr | hostname | "any" . @@ -43,8 +43,9 @@ ipaddr = host-num "." host-num "." host-num "." host-num . host-num = digit [ digit [ digit ] ] . port-num = service-name | decnumber . -withopt = [ "not" | "no" ] opttype [ withopt ] . -opttype = "ipopts" | "short" | "frag" | "opt" ipopts . +withopt = [ "not" | "no" ] opttype [ [ "," ] withopt ] . +opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" | + "mbcast" | "opt" ipopts . optname = ipopts [ "," optname ] . ipopts = optlist | "sec-class" [ secname ] . secname = seclvl [ "," secname ] . @@ -77,4 +78,4 @@ compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | range = "<>" | "><" . hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . -flag = "F" | "S" | "R" | "P" | "A" | "U" . +flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" . diff --git a/dist/ipf/FWTK/fwtk-2.1-transparency.txt b/dist/ipf/FWTK/fwtk-2.1-transparency.txt deleted file mode 100644 index 2e719383f32b..000000000000 --- a/dist/ipf/FWTK/fwtk-2.1-transparency.txt +++ /dev/null @@ -1,707 +0,0 @@ -diff -c -r ./ftp-gw/ftp-gw.c ../../fwtk-2.1-violated/fwtk/ftp-gw/ftp-gw.c -*** ./ftp-gw/ftp-gw.c Thu Feb 5 19:05:43 1998 ---- ../../fwtk-2.1-violated/fwtk/ftp-gw/ftp-gw.c Thu May 21 17:36:09 1998 -*************** -*** 44,49 **** ---- 44,51 ---- - - extern char *optarg; - -+ char *getdsthost(); -+ - #include "firewall.h" - - -*************** -*** 88,93 **** ---- 90,97 ---- - static int cmdcnt = 0; - static int timeout = PROXY_TIMEOUT; - -+ static int do_transparent = 0; -+ - - static int cmd_user(); - static int cmd_authorize(); -*************** -*** 101,106 **** ---- 105,111 ---- - static int cmd_passthru(); - static void saveline(); - static void flushsaved(); -+ static int connectdest(); - - #define OP_CONN 001 /* only valid if connected */ - #define OP_WCON 002 /* writethrough if connected */ -*************** -*** 173,178 **** ---- 178,184 ---- - char xuf[1024]; - char huf[512]; - char *passuser = (char *)0; /* passed user as av */ -+ char *psychic, *hotline; - - #ifndef LOG_DAEMON - openlog("ftp-gw",LOG_PID); -*************** -*** 317,322 **** ---- 323,332 ---- - } else - timeout = PROXY_TIMEOUT; - -+ psychic = getdsthost(0, NULL); -+ if (psychic) -+ do_transparent++; -+ - /* display a welcome file or message */ - if(passuser == (char *)0) { - if((cf = cfg_get("welcome-msg",confp)) != (Cfg *)0) { -*************** -*** 324,329 **** ---- 334,345 ---- - syslog(LLEV,"fwtkcfgerr: welcome-msg must have one parameter, line %d",cf->ln); - exit(1); - } -+ if (do_transparent) { -+ if (sayfile2(0, cf->argv[0], 220)) { -+ syslog(LLEV,"fwtksyserr: cannot display welcome %.512s: %m",cf->argv[0]); -+ exit(1); -+ } -+ } else - if(sayfile(0,cf->argv[0],220)) { - syslog(LLEV,"fwtksyserr: cannot display welcome %.512s: %m",cf->argv[0]); - exit(1); -*************** -*** 336,341 **** ---- 352,360 ---- - if(say(0,"220-Proxy first requires authentication")) - exit(1); - -+ if (do_transparent) -+ sprintf(xuf, "220-%s FTP proxy (Version %s) ready.",huf, FWTK_VERSION_MINOR); -+ else - sprintf(xuf, "220 %s FTP proxy (Version %s) ready.",huf, FWTK_VERSION_MINOR); - if(say(0,xuf)) - exit(1); -*************** -*** 357,362 **** ---- 376,384 ---- - exit(1); - } - -+ if (do_transparent) -+ connectdest(psychic, 21); -+ - /* main loop */ - while(1) { - FD_ZERO(&rdy); -*************** -*** 653,658 **** ---- 675,696 ---- - return(sayn(0,noad,sizeof(noad)-1)); - } - -+ if (do_transparent) { -+ if((rfd == (-1)) && (x = connectdest(dest,port))) -+ return x; -+ -+ sprintf(buf,"USER %s",user); -+ -+ if (say(rfd, buf)) -+ return(1); -+ -+ x = getresp(rfd, buf, sizeof(buf), 1); -+ if (sendsaved(0, x)) -+ return(1); -+ -+ return(say(0, buf)); -+ } -+ - if(*dest == '\0') - dest = "localhost"; - -*************** -*** 694,705 **** - char ebuf[512]; - - strcpy(ebuf,buf); -! sprintf(buf,"521 %s: %s",dest,ebuf); - rfd = -1; - return(say(0,buf)); - } -! sprintf(buf,"----GATEWAY CONNECTED TO %s----",dest); -! saveline(buf); - - /* we are now connected and need to try the autologin thing */ - x = getresp(rfd,buf,sizeof(buf),1); ---- 732,748 ---- - char ebuf[512]; - - strcpy(ebuf,buf); -! if (do_transparent) -! sprintf(buf, "521 %s,%d: %s", dest, ntohs(port), ebuf); -! else -! sprintf(buf,"521 %s: %s",dest,ebuf); - rfd = -1; - return(say(0,buf)); - } -! if (!do_transparent) { -! sprintf(buf,"----GATEWAY CONNECTED TO %s----",dest); -! saveline(buf); -! } - - /* we are now connected and need to try the autologin thing */ - x = getresp(rfd,buf,sizeof(buf),1); -*************** -*** 1889,1891 **** ---- 1932,2050 ---- - dup(nread); - } - #endif -+ -+ static int connectdest(dest, port) -+ char *dest; -+ short port; -+ { -+ char buf[1024], mbuf[512]; -+ int msg_int, x; -+ -+ if(*dest == '\0') -+ dest = "localhost"; -+ -+ if(validests != (char **)0) { -+ char **xp; -+ int x; -+ -+ for(xp = validests; *xp != (char *)0; xp++) { -+ if(**xp == '!' && hostmatch(*xp + 1,dest)) { -+ return(baddest(0,dest)); -+ } else { -+ if(hostmatch(*xp,dest)) -+ break; -+ } -+ } -+ if(*xp == (char *)0) -+ return(baddest(0,dest)); -+ } -+ -+ /* Extended permissions processing goes in here for destination */ -+ if(extendperm) { -+ msg_int = auth_perm(confp, authuser, "ftp-gw", dest,(char *)0); -+ if(msg_int == 1) { -+ sprintf(mbuf,"Permission denied for user %s to connect to %s",authuser,dest); -+ syslog(LLEV,"deny host=%s/%s connect to %s user=%s",rladdr,riaddr,dest,authuser); -+ say(0,mbuf); -+ return(1); -+ } else { -+ if(msg_int == -1) { -+ sprintf(mbuf,"No match in netperm-table for %s to ftp to %s",authuser,dest); -+ say(0,mbuf); -+ return(1); -+ } -+ } -+ } -+ -+ syslog(LLEV,"permit host=%s/%s connect to %s",rladdr,riaddr,dest); -+ -+ if((rfd = conn_server(dest,port,0,buf)) < 0) { -+ char ebuf[512]; -+ -+ strcpy(ebuf,buf); -+ if (do_transparent) -+ sprintf(buf,"521 %s,%d: %s",dest,ntohs(port),ebuf); -+ else -+ sprintf(buf,"521 %s: %s",dest,ebuf); -+ rfd = -1; -+ return(say(0,buf)); -+ } -+ if (!do_transparent) { -+ sprintf(buf,"----GATEWAY CONNECTED TO %s----",dest); -+ saveline(buf); -+ } -+ -+ /* we are now connected and need to try the autologin thing */ -+ x = getresp(rfd,buf,sizeof(buf),1); -+ if(x / 100 != COMPLETE) { -+ sendsaved(0,-1); -+ return(say(0,buf)); -+ } -+ saveline(buf); -+ -+ sendsaved(0,-1); -+ return 0; -+ } -+ -+ /* quick hack */ -+ sayfile2(fd,fn,code) -+ int fd; -+ char *fn; -+ int code; -+ { -+ FILE *f; -+ char buf[BUFSIZ]; -+ char yuf[BUFSIZ]; -+ char *c; -+ int x; -+ int saidsomething = 0; -+ -+ if((f = fopen(fn,"r")) == (FILE *)0) -+ return(1); -+ while(fgets(buf,sizeof(buf),f) != (char *)0) { -+ if((c = index(buf,'\n')) != (char *)0) -+ *c = '\0'; -+ x = fgetc(f); -+ if(feof(f)) -+ sprintf(yuf,"%3.3d-%s",code,buf); -+ else { -+ sprintf(yuf,"%3.3d-%s",code,buf); -+ ungetc(x,f); -+ } -+ if(say(fd,yuf)) { -+ fclose(f); -+ return(1); -+ } -+ saidsomething++; -+ } -+ fclose(f); -+ if (!saidsomething) { -+ syslog(LLEV,"fwtkcfgerr: sayfile for %d is empty",code); -+ sprintf(yuf, "%3.3d The file to display is empty",code); -+ if(say(fd,yuf)) { -+ fclose(f); -+ return(1); -+ } -+ } -+ return(0); -+ } -diff -c -r ./http-gw/http-gw.c ../../fwtk-2.1-violated/fwtk/http-gw/http-gw.c -*** ./http-gw/http-gw.c Fri Feb 6 18:32:25 1998 ---- ../../fwtk-2.1-violated/fwtk/http-gw/http-gw.c Thu May 21 17:00:47 1998 -*************** -*** 27,32 **** ---- 27,35 ---- - static char http_buffer[8192]; - static char reason[8192]; - static int checkBrowserType = 1; -+ static int do_transparent = 0; -+ -+ char * getdsthost(); - - static void do_logging() - { char *proto = "GOPHER"; -*************** -*** 473,478 **** ---- 476,490 ---- - /*(NOT A SPECIAL FORM)*/ - - if((rem_type & TYPE_LOCAL)== 0){ -+ char * psychic = getdsthost(sockfd, &def_port); -+ if (psychic) { -+ if (strlen(psychic) <= MAXHOSTNAMELEN) { -+ do_transparent ++; -+ strncpy(def_httpd, psychic, strlen(psychic)); -+ strncpy(def_server, psychic, strlen(psychic)); -+ } -+ } -+ - /* See if it can be forwarded */ - - if( can_forward(buf)){ -*************** -*** 1564,1570 **** - parse_vec[0], - parse_vec[1], - ourname, ourport); -! }else{ - sprintf(new_reply,"%s\tgopher://%s:%s/%c%s\t%s\t%u", - parse_vec[0], parse_vec[2], - parse_vec[3], chk_type_ch, ---- 1576,1589 ---- - parse_vec[0], - parse_vec[1], - ourname, ourport); -! } -! else -! if (do_transparent) { -! sprintf(new_reply, "%s\t%s\t%s\t%s", -! parse_vec[0], parse_vec[1], -! parse_vec[2],parse_vec[3]); -! } -! else { - sprintf(new_reply,"%s\tgopher://%s:%s/%c%s\t%s\t%u", - parse_vec[0], parse_vec[2], - parse_vec[3], chk_type_ch, -diff -c -r ./lib/hnam.c ../../fwtk-2.1-violated/fwtk/lib/hnam.c -*** ./lib/hnam.c Tue Dec 10 13:08:48 1996 ---- ../../fwtk-2.1-violated/fwtk/lib/hnam.c Thu May 21 17:10:00 1998 -*************** -*** 23,28 **** ---- 23,33 ---- - - #include "firewall.h" - -+ #ifdef __FreeBSD__ /* or OpenBSD, NetBSD, BSDI, etc. Fix this for your system. */ -+ #include -+ #include "ip_nat.h" -+ #endif /* __FreeBSD__ */ -+ - - char * - maphostname(name) -*************** -*** 49,52 **** ---- 54,132 ---- - } - bcopy(hp->h_addr,&sin.sin_addr,hp->h_length); - return(inet_ntoa(sin.sin_addr)); -+ } -+ -+ char *getdsthost(fd, ptr) -+ int fd; -+ int *ptr; -+ { -+ struct sockaddr_in sin; -+ struct hostent * hp; -+ int sl = sizeof(struct sockaddr_in), err = 0, local_h = 0, i = 0; -+ char buf[255], hostbuf[255]; -+ #ifdef __FreeBSD__ -+ struct sockaddr_in rsin; -+ struct natlookup natlookup; -+ #endif -+ -+ #ifdef linux -+ if (!(err = getsockname(0, &sin, &sl))) { -+ if(ptr) -+ * ptr = ntohs(sin.sin_port); -+ -+ sprintf(buf, "%s", inet_ntoa(sin.sin_addr)); -+ gethostname(hostbuf, 254); -+ hp = gethostbyname(hostbuf); -+ while (hp->h_addr_list[i]) { -+ bzero(&sin, &sl); -+ memcpy(&sin.sin_addr, hp->h_addr_list[i++], -+ sizeof(hp->h_addr_list[i++])); -+ -+ if (!strcmp(buf, inet_ntoa(sin.sin_addr))) -+ local_h++; -+ } -+ -+ if(local_h) -+ return(NULL); -+ else -+ return(buf); -+ } -+ #endif -+ -+ #ifdef __FreeBSD__ -+ /* The basis for this block of code is Darren Reed's -+ * patches to the TIS ftwk's ftp-gw. -+ */ -+ bzero((char*)&sin, sizeof(sin)); -+ bzero((char*)&rsin, sizeof(rsin)); -+ -+ if (getsockname(fd, (struct sockaddr*)&sin, &sl) < 0) -+ return NULL; -+ -+ sl = sizeof(rsin); -+ -+ if(getpeername(fd, (struct sockaddr*)&rsin, &sl) < 0) -+ return NULL; -+ -+ natlookup.nl_inport=sin.sin_port; -+ natlookup.nl_outport=rsin.sin_port; -+ natlookup.nl_inip=sin.sin_addr; -+ natlookup.nl_outip=rsin.sin_addr; -+ -+ if ((natfd = open("/dev/ipl",O_RDONLY)) < 0) -+ return NULL; -+ -+ if (ioctl(natfd, SIOCGNATL,&natlookup) == (-1)) -+ return NULL; -+ -+ close(natfd); -+ -+ if (ptr) -+ *ptr = ntohs(natlookup.nl_inport); -+ -+ sprintf(buf, "%s", inet_ntoa(natlookup.nl_inip)); -+ #endif -+ -+ /* No transparent proxy support */ -+ return(NULL); - } -diff -c -r ./plug-gw/plug-gw.c ../../fwtk-2.1-violated/fwtk/plug-gw/plug-gw.c -*** ./plug-gw/plug-gw.c Thu Feb 5 19:07:35 1998 ---- ../../fwtk-2.1-violated/fwtk/plug-gw/plug-gw.c Thu May 21 17:29:01 1998 -*************** -*** 43,48 **** ---- 43,50 ---- - static char **validdests = (char **)0; - static int net_write(); - -+ static int do_transparent = 0; -+ - main(ac,av) - int ac; - char *av[]; -*************** -*** 198,206 **** ---- 200,220 ---- - char *ptr; - int state = 0; - int ssl_plug = 0; -+ char * getdsthost(); -+ int pport = 0; - - struct timeval timo; - -+ /* Transparent plug-gw is probably a bad idea, but then, plug-gw is a bad -+ * idea .. -+ */ -+ dhost = getdsthost(0, &pport); -+ if (dhost) { -+ do_transparent++; -+ portid = pport; -+ } -+ -+ - if(c->flags & PERM_DENY) { - if (p == -1) - syslog(LLEV,"deny host=%.512s/%.20s port=any",rhost,raddr); -*************** -*** 220,226 **** - syslog(LLEV,"fwtkcfgerr: -plug-to takes an argument, line %d",c->ln); - exit (1); - } -! dhost = av[x]; - continue; - } - ---- 234,241 ---- - syslog(LLEV,"fwtkcfgerr: -plug-to takes an argument, line %d",c->ln); - exit (1); - } -! if (!dhost) -! dhost = av[x]; - continue; - } - -diff -c -r ./rlogin-gw/rlogin-gw.c ../../fwtk-2.1-violated/fwtk/rlogin-gw/rlogin-gw.c -*** ./rlogin-gw/rlogin-gw.c Thu Feb 5 19:08:38 1998 ---- ../../fwtk-2.1-violated/fwtk/rlogin-gw/rlogin-gw.c Thu May 21 17:20:25 1998 -*************** -*** 103,108 **** ---- 103,111 ---- - static int trusted = 0; - static int doX = 0; - static char *prompt; -+ static int do_transparent = 0; -+ -+ char * getdsthost(); - - main(ac,av) - int ac; -*************** -*** 123,128 **** ---- 126,132 ---- - static char *tokav[56]; - int tokac; - struct timeval timo; -+ char * psychic; - - #ifndef LOG_NDELAY - openlog("rlogin-gw",LOG_PID); -*************** -*** 188,194 **** - xforwarder = cf->argv[0]; - } - -! - - if((cf = cfg_get("directory",confp)) != (Cfg *)0) { - if(cf->argc != 1) { ---- 192,203 ---- - xforwarder = cf->argv[0]; - } - -! psychic = getdsthost(0, NULL); -! if (psychic) { -! do_transparent++; -! strncpy(dest, psychic, 511); -! dest[511] = '\0'; -! } - - if((cf = cfg_get("directory",confp)) != (Cfg *)0) { - if(cf->argc != 1) { -*************** -*** 266,271 **** ---- 275,281 ---- - if((p = index(rusername,'@')) != (char *)0) { - char *namp; - -+ dest[0] = '\0'; - *p++ = '\0'; - if(*p == '\0') - p = "localhost"; -*************** -*** 297,302 **** ---- 307,326 ---- - - if(dest[0] != '\0') { - /* Setup connection directly to remote machine */ -+ if ((cf = cfg_get("welcome-msg",confp)) != (Cfg *)0) { -+ if (cf->argc != 1) { -+ syslog(LLEV,"fwtkcfgerr: welcome-msg must have one parameter, line %d",cf->ln); -+ exit(1); -+ } -+ -+ if (sayfile(0, cf->argv[0])) { -+ syslog(LLEV,"fwtksyserr: cannot display welcome %s: %m",cf->argv[0]); -+ exit(1); -+ } -+ } -+ -+ /* Hey fwtk developer people -- this connect_dest thing is *nasty!* */ -+ - sprintf(buf,"connect %.1000s",dest); - tokac = enargv(buf, tokav, 56, tokbuf, sizeof(tokbuf)); - if (cmd_connect(tokac, tokav, buf) != 2) -*************** -*** 535,548 **** - char ebuf[512]; - - syslog(LLEV,"permit host=%.512s/%.20s connect to %.512s",rhost,raddr,namp); -! if(strlen(namp) > 20) -! namp[20] = '\0'; -! if(rusername[0] != '\0') -! sprintf(ebuf,"Trying %s@%s...",rusername,namp); -! else -! sprintf(ebuf,"Trying %s...",namp); -! if(say(0,ebuf)) -! return(1); - } else - syslog(LLEV,"permit host=%.512s/%.20s connect to %.512s",rhost,raddr,av[1]); - if((serfd = conn_server(av[1],RLOGINPORT,1,buf)) < 0) { ---- 559,574 ---- - char ebuf[512]; - - syslog(LLEV,"permit host=%.512s/%.20s connect to %.512s",rhost,raddr,namp); -! if (!do_transparent) { -! if(strlen(namp) > 20) -! namp[20] = '\0'; -! if(rusername[0] != '\0') -! sprintf(ebuf,"Trying %s@%s...",rusername,namp); -! else -! sprintf(ebuf,"Trying %s...",namp); -! if(say(0,ebuf)) -! return(1); -! } - } else - syslog(LLEV,"permit host=%.512s/%.20s connect to %.512s",rhost,raddr,av[1]); - if((serfd = conn_server(av[1],RLOGINPORT,1,buf)) < 0) { -diff -c -r ./tn-gw/tn-gw.c ../../fwtk-2.1-violated/fwtk/tn-gw/tn-gw.c -*** ./tn-gw/tn-gw.c Thu Feb 5 19:11:36 1998 ---- ../../fwtk-2.1-violated/fwtk/tn-gw/tn-gw.c Thu May 21 17:25:06 1998 -*************** -*** 91,96 **** ---- 91,100 ---- - static int cmd_xforward(); - static int cmd_timeout(); - -+ char * getdsthost(); -+ -+ static int do_transparent = 0; -+ - static int tn3270 = 1; /* don't do tn3270 stuff */ - static int doX; - -*************** -*** 144,149 **** ---- 148,155 ---- - char tokbuf[BSIZ]; - char *tokav[56]; - int tokac; -+ int port; -+ char * psychic; - - #ifndef LOG_DAEMON - openlog("tn-gw",LOG_PID); -*************** -*** 325,330 **** ---- 331,362 ---- - } - } - -+ psychic = getdsthost(0, &port); -+ if (psychic) { -+ if ((strlen(psychic) + 10) < 510) { -+ do_transparent++; -+ if (port) -+ sprintf(dest, "%s:%d", psychic, port); -+ else -+ sprintf(dest, "%s", psychic); -+ -+ if (!welcomedone) -+ if ((cf = cfg_get("welcome-msg", confp)) != (Cfg *)0) { -+ if (cf->argc != 1) { -+ syslog(LLEV,"fwtkcfgerr: welcome-msg must have one parameter, line %d",cf->ln); -+ exit(1); -+ } -+ -+ if (sayfile(0, cf->argv[0])) { -+ syslog(LLEV,"fwtksyserr: cannot display welcome %s:%m",cf->argv[0]); -+ exit(1); -+ } -+ -+ welcomedone = 1; -+ } -+ } -+ } -+ - while (argc > 1) { - argc--; - argv++; -*************** -*** 947,955 **** - char ebuf[512]; - - syslog(LLEV,"permit host=%.512s/%.20s destination=%.512s",rladdr,riaddr,namp); -! sprintf(ebuf,"Trying %.100s port %d...",namp,port); -! if(say(0,ebuf)) -! return(1); - } else - syslog(LLEV,"permit host=%.512s/%.20s destination=%.512s",rladdr,riaddr,av[1]); - ---- 979,989 ---- - char ebuf[512]; - - syslog(LLEV,"permit host=%.512s/%.20s destination=%.512s",rladdr,riaddr,namp); -! if (!do_transparent) { -! sprintf(ebuf,"Trying %.100s port %d...",namp,port); -! if(say(0,ebuf)) -! return(1); -! } - } else - syslog(LLEV,"permit host=%.512s/%.20s destination=%.512s",rladdr,riaddr,av[1]); - -*************** -*** 991,998 **** - - syslog(LLEV,"connected host=%.512s/%.20s destination=%.512s",rladdr,riaddr,av[1]); - strncpy(dest,av[1], 511); -! sprintf(buf, "Connected to %.512s.", dest); -! say(0, buf); - return(2); - } - ---- 1025,1034 ---- - - syslog(LLEV,"connected host=%.512s/%.20s destination=%.512s",rladdr,riaddr,av[1]); - strncpy(dest,av[1], 511); -! if (!do_transparent) { -! sprintf(buf, "Connected to %.512s.", dest); -! say(0, buf); -! } - return(2); - } - diff --git a/dist/ipf/FWTK/fwtk_transparent.diff b/dist/ipf/FWTK/fwtk_transparent.diff index 65821489f718..45e29e25c79c 100644 --- a/dist/ipf/FWTK/fwtk_transparent.diff +++ b/dist/ipf/FWTK/fwtk_transparent.diff @@ -124,7 +124,7 @@ diff -cr ../TIS.orig/fwtk/Makefile.config.solaris fwtk/Makefile.config.solaris *************** *** 11,30 **** # - # RcsId: "$Header: /cvsroot/src/dist/ipf/FWTK/Attic/fwtk_transparent.diff,v 1.1.1.2 2004/03/28 08:55:59 martti Exp $" + # RcsId: "$Header: /cvsroot/src/dist/ipf/FWTK/Attic/fwtk_transparent.diff,v 1.2 2004/03/28 09:00:54 martti Exp $" # Your C compiler (eg, "cc" or "gcc") @@ -145,7 +145,7 @@ diff -cr ../TIS.orig/fwtk/Makefile.config.solaris fwtk/Makefile.config.solaris -Dgethostbyaddr=res_gethostbyaddr -Dgetnetbyname=res_getnetbyname \ --- 11,34 ---- # - # RcsId: "$Header: /cvsroot/src/dist/ipf/FWTK/Attic/fwtk_transparent.diff,v 1.1.1.2 2004/03/28 08:55:59 martti Exp $" + # RcsId: "$Header: /cvsroot/src/dist/ipf/FWTK/Attic/fwtk_transparent.diff,v 1.2 2004/03/28 09:00:54 martti Exp $" + # + # Path to sources of ip_filter (ip_nat.h required in lib/hnam.c) diff --git a/dist/ipf/FWTK/tproxy.diff b/dist/ipf/FWTK/tproxy.diff deleted file mode 100644 index 234404bf2364..000000000000 --- a/dist/ipf/FWTK/tproxy.diff +++ /dev/null @@ -1,82 +0,0 @@ -*** tproxy.c.orig Fri Dec 20 10:53:24 1996 ---- tproxy.c Sun Jan 3 11:33:55 1999 -*************** -*** 135,140 **** ---- 135,144 ---- - #include - #include - #include -+ #include -+ #include -+ #include -+ #include - #include "tproxy.h" - - #ifdef AIX -*************** -*** 147,152 **** ---- 151,159 ---- - #define bzero(buf,size) memset(buf, '\0', size); - #endif /* SYSV */ - -+ #include "ip_compat.h" -+ #include "ip_fil.h" -+ #include "ip_nat.h" - - - /* socket to audio server */ -*************** -*** 324,329 **** ---- 331,369 ---- - char localbuf[2048]; - void timeout(); - extern int errno; -+ /* -+ * IP-Filter block -+ */ -+ struct sockaddr_in laddr, faddr; -+ struct natlookup natlookup; -+ int slen, natfd; -+ -+ bzero((char *)&laddr, sizeof(laddr)); -+ bzero((char *)&faddr, sizeof(faddr)); -+ slen = sizeof(laddr); -+ if (getsockname(0, (struct sockaddr *)&laddr, &slen) < 0) -+ return -1; -+ slen = sizeof(faddr); -+ if (getpeername(0, (struct sockaddr *)&faddr, &slen) < 0) -+ return -1; -+ natlookup.nl_inport = laddr.sin_port; -+ natlookup.nl_outport = faddr.sin_port; -+ natlookup.nl_inip = laddr.sin_addr; -+ natlookup.nl_outip = faddr.sin_addr; -+ natlookup.nl_flags = IPN_TCP; -+ if ((natfd = open(IPL_NAT, O_RDONLY)) < 0) -+ return -1; -+ if (ioctl(natfd, SIOCGNATL, &natlookup) == -1) { -+ syslog(LOG_ERR, "SIOCGNATL failed: %m\n"); -+ close(natfd); -+ return -1; -+ } -+ close(natfd); -+ strcpy(hostname, inet_ntoa(natlookup.nl_realip)); -+ serverport = ntohs(natlookup.nl_realport); -+ /* -+ * End of IP-Filter block -+ */ - - /* setup a timeout in case dialog doesn't finish */ - signal(SIGALRM, timeout); -*************** -*** 337,344 **** ---- 377,386 ---- - * and modify the call to (and subroutine) serverconnect() as - * appropriate. - */ -+ #if 0 - strcpy(hostname, "randomhostname"); - serverport = 7070; -+ #endif - /* Can we connect to the server */ - if ( (serverfd = serverconnect(hostname, serverport)) < 0 ) { - /* errno may still be set from previous call */ diff --git a/dist/ipf/HISTORY b/dist/ipf/HISTORY index 75026a0c3eaf..e2dc28ede3fb 100644 --- a/dist/ipf/HISTORY +++ b/dist/ipf/HISTORY @@ -6,11 +6,9 @@ # in providing a very available location for the IP Filter home page and # distribution center. # -# Thanks to Hewlett Packard for making it possible to port IP Filter to -# HP-UX 11.00. -# -# Thanks to Tel.Net Media for supplying me with equipment to ensure that -# IP Filter continues to work on Solaris/sparc64. +# Thanks to Tel.Net Media for allowing me to maintain and further develop +# IP Filter as part of my job and supplying Sun equipment for testing the +# move to 64bits and Gigabit Ethernet. # # Thanks to BSDI for providing object files for BSD/OS 3.1 and the means # to further support development of IP Filter under BSDI. @@ -22,614 +20,134 @@ # and especially those who have found the time to port IP Filter to new # platforms. # -3.4.29 28/8/2002 - Released +4.1.1 - RELEASED - 24 March 2004 -Make substantial changes to the FTP proxy to improve reliability, security -and functionality. +allow new connections with the same port numbers as an existing one +in the state table if the creating packet is a SYN -don't send ICMP errors/TCP RST's in response to blocked proxy packets +timeout values have drifted, incorrectly, from what they were in 3.4 -fix potential memory leaks when unloading ipfilter from kernel +FreeBSD - compatibility changes for 5.2 -fix bug in SIOCGNATL handler that did not preserve the expected -byte order from earlier versions in the port number +don't match on sequence number (as well) for ICMO ECHO/REPLY, just the +ICMP Id. field as otherwise thre is a state/NAT entry per packet pair +rather than per "flow" -set do not fragment flag in generated packets according to system flags, -where available. +fr_cksum() returned the wrong answer for ICMP -preserve filter rule number and group number in state structure +Linux: +- get return-rst and return-icmp working +- treat the interface name the same as if_xname on BSD -fix bug in ipmon printing of p/P/b/B +adjust expectations for TCP urgent bits based on observed traffic in the +wild -make some changes to the kmem.c code for IRIX compatibility +openbsd3.4 has ip_len/ip_off in network byte order when ipfilter is called -add code to specifically handle ip.tun* interfaces on Solaris +fix flushing of hash pool gorups (ippool -F) as well as displaying them +(ippool -l) -3.4.28 6/6/2002 - Released +passing of pointers to interface structures wrong for HP-UX/Solaris with +return-* rules. -Fix for H.323 proxy to work on little endian boxes +Make the solaris boot script able to run on 2.5.1 -IRIX: Update installation documentation - add route lock patch +ippool related files missing from Solaris packages -allow use of groups > 65535 +The name /dev/ippool should be /dev/iplookup -create a new packet info summary for packets going through ipfr_fastroute() -so that where details are different (RST/ICMP errors), the packet now gets -correctly NAT'd, etc. +add regression testing for parsing long interface names in nat rules, +along with mssclamp and tags. Also add test for mssclamp operation. -fix the FTP proxy so that checks for TCP sequence numbers outside the -normal offset due to data changes use absolute numbers +ttl displayed for "ipfstat -t" is wrong because ttl is not computed. -make it possible to remove rules in ipftest +parse logical interface names (Sun) -Update installing onto OpenBSD and split into two directories: -OpenBSD-2 and OpenBSD-3 +unloading LKMs was only working if they were enabled. -fix error in printout out the protocol in NAT rules +sync'ing up NAT sessions when NICs change should cause NAT rules to +re-lookup name->pointer mappings -always unlock ipfilter if locking fails half way through in ipfs +not all of the ippool ioctl's are IOWR and they should be because they +use the ipfobj_t for passing information in/out of the kernel. leave the +old values defined and handle them, for compatibility. -fix problems with TCP window scaling +pool stats wrong: ippoolstate used where ipoolstat should be, hash table + statistics not reported at all -update of man pages for ipnat(4) and ipftest(1) +fr_running not set correctly for OpenBSD when compiled into the kernel -3.4.27 28/04/2002 - Released +Allow SIOCGETFF while disabled -fix calculation of 2's complmenent 16 bit checksum for user space +Fix mssclamp with NAT (pasing and printing of the word, plus wrong bytes +altered. How do you say "untested" ?) -add mbuflen() to usespace compiles. +4.1 - RELEASED - 12 February 2004 -add more #ifdef complexity for platform portability +4.0-BETA1 20 August 2003 -add OpenBSD 3.1 diffs +support 0/32 and 0/0 on the RHS in redirect rules -3.4.26 25/04/2002 - Released +where LHS and RHS netmasks are the same size for redirect, do 1:1 mapping +for bimap rules. -fix parsing and printing of NAT rules with regression tests. +allow NAT rule to match 'all' interfaces with * as interface name -add code to adjust TCP checksums inside ICMP errors where present and as -required for NAT. +do mapping of ICMP sequence id#'s in pings -fix documentation problems in instal documents +allow default age for NAT entries to be set per NAT rule -fix locking problem with auth code on Solaris +provide round robin selection of destination addresses for redirect -fix use of version macros for FreeBSD and make the use of __FreeBSD_version -override previous hacks except when not present +ipmon can load a configuration file with instructions on actions +to take when a matching log entry is received -fix the macros defined for SIOCAUTHR and SIOCAUTHW +now requires pfil to work on Solaris & HP-UX -fix the H.323 proxy so it no longer panics (multiple issues: re-entry into -nat_ioctl with lock held on Solaris, trying to copy data from kernel space -with copyin, unaligned access to get 32bit & 16bit numbers) +supports mapping outbound connections to a specific address/port -use the ip_ttl ndd parameter on Solaris to fill in ip_ttl for packets -generated by IPFilter +support toggling of logging per ipfilter 'device' -fix comparing state information to delete state table entries +use queues to expire data rather than lists -flag packets as being "bad state" if they're outside the window and prevent -them from being able to cause new state to be created - except for SYN packets +add MSN RPC proxy -be stricter about what packets match a TCP state table entry if its creation -was triggered by a SYN packet. +add IRC proxy -add patches to handle TCP window scaling +support rules with dynamic ip addresses -don't update TCP state table entries if the packet is not considered to be -part of the connection +add ability to define a pool of addresses & networks which can then +be placed in a single rule -ipfs wasn't allowing -i command line option in getopt +support passing entire packet back to user program for authentication -IRIX: fix kvm interface, fix compile warnings, compile the kernel with -O2 - regardless of user compile, fix the getkflags script to prune down the - output more so it is acceptable +support master/slave for state information sharing -change building in Makefiles to create links to the application in $(TOP) -at the end of "build" rather than when each is created. +reorganise generic code into a lib directory and make libipf.a -update BSD/kupgrade for FreeBSD +user programs enforce version matching with the kernel -l4check wasn't properly closing things when a connection fails +supports window scaling if seen at TCP session setup -man page updates for ipmon(8) and ipnat(5) +generates C code from filter rules to compile in or load as native +machine code. -more regression tests added. +supports loading rules comprised of BPF bytecode statements -3.4.25 13/03/2002 - Released +HP-UX 11 port completed -retain rule # in state information +and packets-per-second filtering -log the direction of a packet so ipmon gets it right rather than incorrectly -deriving it from the rule flags +add numerical tags to rules for filtering and display in ipmon output -add #ifdef for IPFILTER_LOGSIZE (put options IPFILTER_LOGSIZE=16384 in BSD -kernel config files to increase that buffer size) - -recognise return-* rules differently to block in ipftest - -fix bug in ipmon output for solaris - -add regression testing for skip rules, logging and using head/group - -fix output of ipmon: was displaying large unsigned ints rather than -1 -when no rules matched. - -make logging code compile into ipftest and add -l command line option to -dump binary log file (read with ipmon -f) when it finishes. - -protect rule # and group # from interference when checking accounting rules - -add regression testing for log output (text) from ipmon. - -document -b command line option for ipmon - -fix double-quick in Solaris startup script - -3.4.24 01/03/2002 - Released - -fix how files are installed on SunOS5 - -fix some minor problems in SunOS5 ipfboot script - -by default, compile all OpenBSD tools in 3.0 for IPv6 - -fix NULL-pointer dereference in NAT code - -make a better attempt at replacing the appropriate binaries on BSD systems - -always print IPv6 icmp-types as a number - -impose some rules about what "skip" can be used with - -fix parsing problems with "keep state" and "keep state-age" - -Try to read as much data as is in the log device in ipmon - -remove some redundant checks when searching for rdr/nat rules - -fix bug in handling of ACCT with FTP proxy - -increase array size for interface names, using LIFNAMSIZ - -include H.323 proxy from QNX - -3.4.23 16/01/2002 - Released - -Include patches to install IPFilter into OpenBSD 3.0, both for just kernel -compiles and complete system builds. - -Fix bug in automatic flushing of state table which would cause it to hang -in an infinite loop bug introduced in 3.4.20. - -Modify the sample proxy (samples/proxy.c) so that it ads a NAT mapping for -the outgoing connection to make it look like it comes from the real source. - -Only support ICMPv6 with IPv6. - -Move ipnat.1 to ipnat.8 - -Enhance ipmon to print textual ICMP[v6] types and subtypes where possible. - -Make it possible to do IPv6 regression testing with ipftest. - -Use kvm library for kmem access, rather than trying to do it manually with -open/lseek/read. - -Fix diffs for ip_input.c on BSDOS so it doesn't crash with fastroute. - -Remove Berkeley advertising licence clause. Reference: -ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change - -Add more regression tests: ICMPv6 neighbour discovery, ICMP time exceeded -and fragmentation required. - -Fix ipfboot script on Solaris to deal with no nameservers or no route to -them in a clean manner. - -Support per-rule set timeouts for non-TCP NAT and state - -Add netbios proxy - -Add ICMPv6 stateful checking, including handling multicast destination -addresses for neighbour discovery. - -Fix problems with internals of ICMP messages for MTU discovery and -unreachables not being correctly adjust on little endian boxes. - -Add "in-via" and "out-via" to filtering rules grammar. It is now possible -to bind a rule to both incoming and outgoing interfaces, in both forward -and reverse directions (4 directions in total). allows for asymetric flows -through a firewall. - -Fix ipfstat and ipnat for working on crash dumps. - -Don't let USE_INET6 stay defined for SunOS4 - -Count things we see for each interface on solaris. - -Include when compiling with USE_INET6 defined and -also include a whole bunch of #define's to make sure the symbols expected -can be used. - -Fix up fastroute on BSD systems. - -Make fastrouting work for IPv6 just a bit better. doesn't split up big -packets into fragments like the IPv4 one does. You can now do a -"to :" - -Remove some of the differences between user-space and kernel-space code -that is internal to ipfilter. - -Call ipfr_slowtimer() after each packet is processed in ipftest to artificially -create the illusion of passing time and include the expire functions in the -code compiled for user-space. - -Fix issues with the IPSec proxy not working or leading to a system crash. - -Junk all processing of SPIs and special handling for ESP. - -Add "no-match" as a filter rule action (resets _LAST_ match) - -Add hack to workaround problems with Cassini interface cards on -Solaris and VLANs - -Add some protocols to etc/protocols - -3.4.22 03/12/2001 - Released - -various openbsd changes - -sorting based on IP numbers for ipfstat top output - -fix various IPv6 code & compile problems - -modify ip_fil.c to be more netbsd friendly - -fix fastroute bug where it modified a packet post-sending - -fix get_unit() - don't understand why it was broken. - -add FI_IGNOREPKT and don't count so marked packets when doing stats or -state/nat. - -extend the interface name saved to log output - -make proxies capable of extending the matching done on a packet with a -particular nat session - -change interfaces inside NAT & state code to accomodate redesign to allow -IPsec proxy to work. - -fix bug when free'ing loaded rules that results in a memory leak -(only an issue with "ipf -rf -", not flush) - -make ipftest capable of loading > 1 file or rules, making it now possible -to load both NAT & filter rules - -fix hex input for ipftest to allow interface name & direction to work - -show ipsec proxy details in ipnat output - -if OPT_HEX is set in opts, print a packet out as hex - -don't modify b_next or preseve it or preserve b_prev for solaris - -fix up kinstall scripts to install all the files everywhere they need to - -fix overflowing of bits in ip_off inside iptest - -make userauth and proxy in samples directory compile - -fix minimum size when doing a pullup for ESP & ICMPv6 - -3.4.21 24/10/2001 - Released - -include ipsec proxy - -make state work for non-tcp/udp/icmp in a very simple way - -include diffs for ipv6 firewall on openbsd-2.9 - -add compatibility filter wrapper for NetBSD-current - -fix command line option problems with ipfs - -if we fill the state table and a automated flush doesn't purge any -expiring entries, remove all entries idle for more than half a day - -fix bug with sending resets/icmp errors where the pointer to the data -section of the packet was not being set (BSD only) - -split out validating ftp commands and responses into different halves, -one for each of server & client. - -do not compile in STATETOP support for specific architectures - -fix INSTALL.FreeBSD to no longer provide directions and properly direct -people to the right file for the right version of FreeBSD. - -3.4.20 24/07/2001 - Released - -adjust NAT hashing to give a better spread across the table - -show icmp code/type names in output, where known - -fix bug in altering cached interface names in state when resync'ing - -fix bug in real audio proxy that caused crashs - -fix compiling using sunos4 cc - -patch from casper to address weird exit problem for ipstat in top mode - -patch from Greg Woods to produce names for icmp types/unreach codes, -where they are known - -fix bug where ipfr_fastroute() would use a mblk and it would also get -freed later. - -don't match fragments which would cause 64k length to be exceeded - -ftp proxy fix for port numbers being setup for pasv ftp with state/nat - -change hashing for NAT to include both IP#'s and ports. - -Solaris fixes for IPv6 - -fix compiling iplang bits, under Solaris, for ipsend - -3.4.19 29/06/2001 - Released - -fix to support suspend/resume on solaris8 as well as ipv6 - -include group/group-head in match of filter rules - -fix endian problem reading snoop files - -make all licence comments point to the one place - -fix ftp proxy to only advance state if a reply is received in response to -a recognised command - -3.4.18 05/06/2001 - Released - -fix up parsing of "from ! host" where '!' is separate - -disable hardware checksums for NetBSD - -put ipftest temporary files in . rather than /tmp - -modify ftp proxy to be more intelligent about moving between states -and recognise new authentication commands - -allow state/nat table sizes to be externally influenced - -print out host mapping table for NAT with ipnat -l - -fix handling of hardware checksum'ing on Solaris - -fixup makefiles for Solaris - -update regression tests - -fix surrender of SPL's for failure cases - -include patches for OpenBSD's new timeout mechanism - -default ipl_unreach to ICMP_UNREACH_FILTER_PROHIB if defined, else make it -ICMP_UNREACH_FILTER - -fix up handling of packets matching auth rules and interaction with state - -add -q command line option to ipfstat on Solaris to list bound interfaces - -add command line option to ipfstat/ipnat to select different core image - -don't use ncurses on Solaris for STATETOP - -fix includes to get FreeBSD version - -do not byte swap ip_id - -fix handling success for packets matching the auth rule - -don't double-count short packets - -add ICMP router discovery message size recognition - -fix packet length calculation for IPv6 - -set CPUDIR when for install-sunos5 make target - -SUNWspro -xF causes Solaris 2.5.1 kernel to crash - -3.4.17 06/04/2001 - Released - -fix fragment#0 handling bug where they could get in via cache information -created by state table entries - -use ire_walk to look for ire cache entries with link layer headers cached - -deal with bad SPL assumptions for log reading on BSD - -fix ftp proxy to allow logins with passwords - -some auth rule patches, fixing byte endian problems and returning as an error - -support LOG_SECURITY, where available, in ipmon - -don't return an error for packets which match auth rules - -introduce fr_icmpacktimeout to timeout entries once an ICMP reply has -been seen separately to when created - -3.4.16 15/01/2001 - Released - -fix race condition in flushing of state entries that are timing out - -Add TCP ECN patches - -log all NAT entries created, not just those via rules - -3.4.15 17/12/2000 - Released - -add minimum ttl filtering (to be replaced later by return-icmp-as-dest -for all ICMP packets matching state entries). - -fix NAT'ing of fragments - -fix sanity checks for ICMPV6 - -fix up compiling on IRIX 6.2 with IDF/IDL installed - -3.4.14 02/11/2000 - Released - -cause flushing NAT table to generate log records the same as state flush -does. - -fix ftp proxy port/pasv - -fix problem where nat_{in,out}lookup() would release a write lock when it -didn't need to. - -add check for ipf6.conf in Solaris ipfboot - -3.4.13 28/10/2000 - Released - -fix introduced bug with ICMP packets being rejected when valid - -fix bug with proxy's that don't set fin_dlen correctly when calling -fr_addstate() - -3.4.12 26/10/2000 - Released - -fix installing into FreeBSD-4.1 - -fix FTP proxy bug where it'd hang and make NAT slightly more efficient - -fix general compiling errors/warnings on various platforms - -don't access ICMP data fields that aren't there - -3.4.11 09/10/2000 - Released - -return NULL for IPv6 access control lists if it is disabled rather than -random garbage. - -fix for getting protocol & packet length for IPv6 packets for pullup. - -update plog script from version 0.8 to version 0.10 - -patch from Frank Volf adding fix_datacksum() to NAT code, enhancing the -capabilities for "fixing" checksums. - -3.4.10 03/09/2000 - Released - -merge patch from Frank Volf for ICMP nat handling of TCP/UDP data `errors' - -getline() adjusts linenum now - -add tcphalfclosed timeout - -fill in icmp_nextmtu field if it is defined on the platform - -RST generation fix from guido - -force 32bit compile for gcc on solaris if it can't generate 64bit code - -encase logging when fr_chksrc == 2 in #ifdef IPFILTER_LOG - -fix up line wrap problems in plog script - -fix ICMP packet handling to not drop valid ICMP errors - -freebsd 5.0 compat changes - -3.4.9 08/08/2000 - Released - -implement new aging mechanism in fr_tcp_age() - -fix icmp state checking bug - -revamp buildsunos script and build both sparcv7/sparcv9 for Solaris -if on an Ultra with a 64bit system & compiler (Caseper Dik) - -open ipfilter device read only if we know we can - -print out better information for ICMP packets in ipmon - -move checking for source spoofed packets to a point where we can generate -logs of them - -return EFAULT from ircopyptr/iwcopyptr - -don't do ioctl(SIOCGETFS) for auth stats - -fix up freeing mbufs for post-4.3BSD - -fix returning of inc from ftp proxy - -fix bugs with ipfs -R/-W (Caseper Dik) - -3.4.8 19/07/2000 - Released - -create fake opt_inet6.h for FreeBSD-4 compile as LKM - -add #ifdef's for KLD_MODULE sanity - -NAT fastroute'd packets which come out of return-* - -fix upper/lower case crap in ftp proxy and get seq# checking fixed up. - -3.4.7 08/07/2000 - Released - -make "ipf -y" lookup NAT if's which are unknown - -prepend line numbers to ioctl error messages in ipf/ipnat - -don't apply patches to FreeBSD twice - -allow for ip_len to be on an unaligned boundary early on in fr_precheck - -fix printing of icmp code when it is 0 - -correct printing of port numbers in map rules with from/to - -don't allow fr_func to be called at securelevel > 0 or rules to be added -if securelevel > 0 if they have a non-zero fr_func. - -3.4.6 11/06/2000 - Released - -add extra regression tests for new nat functionality - -place restrictions on using '!' in map/rdr rules - -fix up solaris compile problems - -3.4.5 10/06/2000 - Released - -mention -sl in ipfstat.8 - -fix/support '!' in from/to rules (rdr) for NAT - -add from/to support to rdr NAT rules - -don't send ICMP errors in response to ICMP errors - -fix sunos5 compilation for "ipfstat-top" and cleanup ipfboot - -input accounting list used for both outbound and inbound packets - -3.4.4 23/05/2000 - Released +3.4.4 23/05/2000 - Released don't add TCP state if it is an RST packet and (attempt) to send out RST/ICMP packets in a manner that bypasses IP Filter. add patch to work with 4.0_STABLE delayed checksums -3.4.3 20/05/2000 - Released +3.4.3 20/05/2000 - Released fix ipmon -F diff --git a/dist/ipf/Makefile b/dist/ipf/Makefile index cc80f64125c1..3f46bbd05fcc 100644 --- a/dist/ipf/Makefile +++ b/dist/ipf/Makefile @@ -1,23 +1,27 @@ # # Copyright (C) 1993-2001 by Darren Reed. # -# See the IPFILTER.LICENCE file for details on licencing. +# 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. # -# Id: Makefile,v 2.11.2.13 2002/03/06 09:43:15 darrenr Exp +# Id: Makefile,v 2.76.2.1 2004/03/06 14:32:46 darrenr Exp # +SHELL=/bin/sh BINDEST=/usr/local/bin SBINDEST=/sbin MANDIR=/usr/local/man #To test prototyping -CC=gcc -Wstrict-prototypes -Wmissing-prototypes +#CC=gcc -Wstrict-prototypes -Wmissing-prototypes +# -Wunused -Wuninitialized #CC=gcc #CC=cc -Dconst= DEBUG=-g -TOP=../.. -CFLAGS=-I$$(TOP) +# -O +CFLAGS=-I$$(TOP) -D_BSD_SOURCE CPU=`uname -m` CPUDIR=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m` -IPFILKERN=`/bin/ls -1tr /usr/src/sys/compile | grep -v .bak | tail -1` +OBJ=. # # To enable this to work as a Loadable Kernel Module... # @@ -27,14 +31,48 @@ IPFLKM=-DIPFILTER_LKM # IPFLOG=-DIPFILTER_LOG # +# To enable loading filter rules compiled to C code... +# +#COMPIPF=-DIPFILTER_COMPILED +# +# To enable synchronisation between IPFilter hosts +# +#SYNC=-DIPFILTER_SYNC +# +# To enable extended IPFilter functionality +# +LOOKUP=-DIPFILTER_LOOKUP -DIPFILTER_SCAN +# # The facility you wish to log messages from ipmon to syslogd with. # LOGFAC=-DLOGFAC=LOG_LOCAL0 +# +# To enable rules to be written with BPF syntax, uncomment these two lines. +# +#IPFBPF=-DIPFILTER_BPF -I/usr/local/include +#LIBBPF=-L/usr/local/lib -lpcap +# +# HP-UX and Solaris require this uncommented for BPF. +# +#BPFILTER=bpf_filter.o +# +# LINUXKERNEL is the path to the top of your Linux kernel source tree. +# By default IPFilter looks for /usr/src/linux, but you may have to change +# it to /usr/src/linux-2.4 or similar. +# +LINUXKERNEL=/usr/src/linux-2.4 + +# +# All of the compile-time options are here, used for compiling the userland +# tools for regression testing. Well, all except for IPFILTER_LKM, of course. +# +ALLOPTS=-DIPFILTER_LOG -DIPFILTER_COMPILED -DIPFILTER_LOOKUP \ + -DIPFILTER_SCAN -DIPFILTER_SYNC -DIPFILTER_CKSUM # # Uncomment the next 3 lines if you want to view the state table a la top(1) # (requires that you have installed ncurses). -STATETOP_CFLAGS=-DSTATETOP +#STATETOP_CFLAGS=-DSTATETOP # # Where to find the ncurses include files (if not in default path), # @@ -43,7 +81,7 @@ STATETOP_CFLAGS=-DSTATETOP # # How to link the ncurses library # -STATETOP_LIB=-lcurses +#STATETOP_LIB=-lncurses #STATETOP_LIB=-L/usr/local/lib -lncurses # @@ -59,14 +97,16 @@ STATETOP_LIB=-lcurses # POLICY=-DIPF_DEFAULT_PASS=FR_PASS # -MFLAGS1='CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2) $(INET6) $(IPFLOG)' \ +MFLAGS1='CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2) $(SGIREV) $(INET6)' \ "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \ "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \ - "CPUDIR=$(CPUDIR)" 'STATETOP_CFLAGS=$(STATETOP_CFLAGS)' \ + "LIBBPF=$(LIBBPF)" "CPUDIR=$(CPUDIR)" "IPFBPF=$(IPFBPF)" \ + 'STATETOP_CFLAGS=$(STATETOP_CFLAGS)' "BPFILTER=$(BPFILTER)" \ 'STATETOP_INC=$(STATETOP_INC)' 'STATETOP_LIB=$(STATETOP_LIB)' \ - "BITS=$(BITS)" "OBJ=$(OBJ)" -DEST="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" + "BITS=$(BITS)" "OBJ=$(OBJ)" "LOOKUP=$(LOOKUP)" "COMPIPF=$(COMPIPF)" \ + 'SYNC=$(SYNC)' 'ALLOPTS=$(ALLOPTS)' 'LIBBPF=$(LIBBPF)' MFLAGS=$(MFLAGS1) "IPFLKM=$(IPFLKM)" +MACHASSERT=`find /usr/sys -name mach_assert.h -print` # SHELL=/bin/sh # @@ -88,10 +128,12 @@ all: @echo "freebsd22 - compile for FreeBSD-2.2 or greater" @echo "freebsd3 - compile for FreeBSD-3.x" @echo "freebsd4 - compile for FreeBSD-4.x" + @echo "freebsd5 - compile for FreeBSD-5.x" @echo "bsd - compile for generic 4.4BSD systems" @echo "bsdi - compile for BSD/OS" @echo "irix - compile for SGI IRIX" - @echo "linux - compile for Linux 2.0.31+" + @echo "hpux - compile for HP-UX 11.00" + @echo "osf - compile for OSF/Tru64 5.1" @echo "" tests: @@ -100,185 +142,228 @@ tests: include: if [ ! -f netinet/done ] ; then \ - (cd netinet; ln -s ../*.h .; ln -s ../ip_*_pxy.c .; ); \ + (cd netinet; ln -s ../*.h .; ln -s ../ip_*_pxy.c .;); \ (cd netinet; ln -s ../ipsend/tcpip.h tcpip.h); \ touch netinet/done; \ fi + if [ ! -f net/done ] ; then \ + (cd net; ln -s ../radix_ipf.h .; ); \ + touch net/done; \ + fi sunos solaris: include - CC="$(CC)" ./buildsunos + MAKE="$(MAKE)" MAKEFLAGS="$(MAKEFLAGS)" BPFILTER=$(BPFILTER) \ + CC="$(CC)" DEBUG="$(DEBUG)" ./buildsunos freebsd22: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" -rm -f BSD/$(CPUDIR)/ioconf.h - @if [ -n $(IPFILKERN) ] ; then \ + -if [ x$(IPFILKERN) != x ] ; then \ if [ -f /sys/compile/$(IPFILKERN)/ioconf.h ] ; then \ - ln -s /sys/compile/$(IPFILKERN)/ioconf.h BSD/$(CPUDIR); \ + ln -s /sys/compile/$(IPFILKERN)/ioconf.h BSD/$$y; \ else \ - ln -s /sys/$(IPFILKERN)/ioconf.h BSD/$(CPUDIR); \ + ln -s /sys/$(IPFILKERN)/ioconf.h BSD/$$y; \ fi \ - elif [ ! -f `uname -v|sed -e 's@^.*:\(/[^: ]*\).*@\1@'`/ioconf.h ] ; then \ - echo -n "Can't find ioconf.h in "; \ - echo `uname -v|sed -e 's@^.*:\(/[^: ]*\).*@\1@'`; \ - exit 1;\ else \ - ln -s `uname -v|sed -e 's@^.*:\(/[^: ]*\).*@\1@'`/ioconf.h BSD/$(CPU) ; \ + x=`uname -v|sed -e 's@^.*:\(/[^: ]*\).*$$@\1/ioconf.h@'`; \ + y=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m`; \ + if [ ! -f $$x ] ; then \ + echo -n "Can't find ioconf.h at $$x "; \ + exit 1;\ + else \ + ln -s $$x BSD/$$y ; \ + fi \ fi make freebsd -freebsd4: include - if [ x$INET6 = x ] ; then \ +freebsd5: include + if [ x$(INET6) = x ] ; then \ + echo "#undef INET6" > opt_inet6.h; \ + else \ + echo "#define INET6" > opt_inet6.h; \ + fi + if [ x$(ENABLE_PFIL) = x ] ; then \ + echo "#undef PFIL_HOOKS" > opt_pfil.h; \ + else \ + echo "#define PFIL_HOOKS" > opt_pfil.h; \ + fi + + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko.5" "LKMR=ipfrule.ko.5" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) + +freebsd4 : include + if [ x$(INET6) = x ] ; then \ echo "#undef INET6" > opt_inet6.h; \ else \ echo "#define INET6" > opt_inet6.h; \ fi make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko" "DLKM=-DKLD_MODULE -I/sys"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS1); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko" "LKMR=ipfrule.ko" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) freebsd3 freebsd30: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS1) "ML=mlf_ipl.c" LKM= ; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS1); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS1) "ML=mlf_ipl.c" "MLR=mlf_rule.o" LKM= LKMR=; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) netbsd: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" "MLR=mln_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) openbsd openbsd21: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mlo_ipl.c" "MLR=mlo_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) freebsd freebsd20 freebsd21: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlf_ipl.c"; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlf_ipl.c" "MLR=mlf_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) + +osf tru64: null include + make setup "TARGOS=OSF" "CPUDIR=`OSF/cpurev`" + (cd OSF/`OSF/cpurev`; make build TRU64=`uname -v` TOP=../.. "DEBUG=-g" $(MFLAGS) "MACHASSERT=$(MACHASSERT)" "OSREV=`../cpurev`"; cd ..) + (cd OSF/`OSF/cpurev`; make -f Makefile.ipsend build TRU64=`uname -v` TOP=../.. $(MFLAGS) "OSREV=`../cpurev`"; cd ..) bsd: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS); cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" "MLR=mln_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) bsdi bsdos: include make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" - (cd BSD/$(CPUDIR); make build "CC=$(CC)" TOP=../.. $(MFLAGS) LKM= ; cd ..) - (cd BSD/$(CPUDIR); make -f Makefile.ipsend "CC=$(CC)" TOP=../.. $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make build "CC=$(CC)" TOP=../.. $(MFLAGS) LKM= LKMR= ; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build "CC=$(CC)" TOP=../.. $(MFLAGS); cd ..) irix IRIX: include - make setup "TARGOS=IRIX" "CPUDIR=$(CPUDIR)" - -(cd IRIX/$(CPUDIR); if [ $(MAKE) = make ] ; then make -f Makefile.std build TOP=../.. $(DEST) SGI=`../getrev` $(MFLAGS); else smake build SGI=`../getrev` TOP=../.. $(DEST) $(MFLAGS); fi;) - -(cd IRIX/$(CPUDIR); if [ $(MAKE) = make ] ; then make -f Makefile.ipsend.std SGI=`../getrev` TOP=../.. $(DEST) $(MFLAGS); else smake -f Makefile.ipsend SGI=`../getrev` TOP=../.. $(DEST) $(MFLAGS); fi) - -linux: include - make setup "TARGOS=Linux" "CPUDIR=$(CPUDIR)" - ./buildlinux - -linuxrev: - (cd Linux/$(CPUDIR); make build TOP=../.. $(DEST) $(MFLAGS) LKM= ; cd ..) - (cd Linux/$(CPUDIR); make -f Makefile.ipsend TOP=../.. $(DEST) $(MFLAGS); cd ..) + make setup TARGOS=IRIX CPUDIR=`IRIX/cpurev` + if [ "x${SGIREV}" = "x" ] ; then \ + make irix "SGIREV=-D_KMEMUSER -DIRIX=`IRIX/getrev`"; \ + else \ + (cd IRIX/`IRIX/cpurev`; smake -l -J 1 build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \ + (cd IRIX/`IRIX/cpurev`; make -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \ + fi setup: -if [ ! -d $(TARGOS)/$(CPUDIR) ] ; then mkdir $(TARGOS)/$(CPUDIR); fi -rm -f $(TARGOS)/$(CPUDIR)/Makefile $(TARGOS)/$(CPUDIR)/Makefile.ipsend -ln -s ../Makefile $(TARGOS)/$(CPUDIR)/Makefile - -if [ ! -f $(TARGOS)/$(CPUDIR)/Makefile.std -a \ - -f $(TARGOS)/Makefile.std ] ; then \ - ln -s ../Makefile.std $(TARGOS)/$(CPUDIR)/Makefile.std; \ - fi - -if [ ! -f $(TARGOS)/$(CPUDIR)/Makefile.ipsend.std -a \ - -f $(TARGOS)/Makefile.ipsend.std ] ; then \ - ln -s ../Makefile.ipsend.std $(TARGOS)/$(CPUDIR)/Makefile.ipsend.std; \ - fi -ln -s ../Makefile.ipsend $(TARGOS)/$(CPUDIR)/Makefile.ipsend + -if [ -f $(TARGOS)/Makefile.common ] ; then \ + rm -f $(TARGOS)/$(CPUDIR)/Makefile.common; \ + ln -s ../Makefile.common $(TARGOS)/$(CPUDIR)/Makefile.common;\ + fi clean: clean-include + /bin/rm -rf h y.output ${RM} -f core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl \ vnode_if.h $(LKM) *~ - ${RM} -rf sparcv7 sparcv9 - (cd SunOS4; make clean) - (cd SunOS5; make clean) - (cd BSD; make clean) - (cd Linux; make clean) - if [ "`uname -s`" = "IRIX" ]; then (cd IRIX; make clean); fi - [ -d test ] && (cd test; make clean) - (cd ipsend; make clean) + /bin/rm -rf sparcv7 sparcv9 mdbgen_build + (cd SunOS4; $(MAKE) TOP=.. clean) + -(cd SunOS5; $(MAKE) TOP=.. clean) + (cd BSD; $(MAKE) TOP=.. clean) + (cd HPUX; $(MAKE) BITS=32 TOP=.. clean) + (cd Linux; $(MAKE) TOP=.. clean) + (cd OSF; $(MAKE) TOP=.. clean) + if [ "`uname -s`" = "IRIX" ]; then (cd IRIX; $(MAKE) clean); fi + [ -d test ] && (cd test; $(MAKE) clean) + (cd ipsend; $(MAKE) clean) clean-include: - sh -c 'cd netinet; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done' - ${RM} -f netinet/done + sh -c 'if [ -d netinet ] ; then cd netinet; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi' + sh -c 'if [ -d net ] ; then cd net; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi' + ${RM} -f netinet/done net/done clean-bsd: clean-include - (cd BSD; make clean) + (cd BSD; make TOP=.. clean) + +clean-hpux: clean-include + (cd HPUX; $(MAKE) BITS=32 clean) + +clean-osf: clean-include + (cd OSF; make clean) + +clean-linux: clean-include + (cd Linux; make clean) clean-sunos4: clean-include (cd SunOS4; make clean) clean-sunos5: clean-include - (cd SunOS5; make clean) + (cd SunOS5; $(MAKE) clean) + /bin/rm -rf sparcv? clean-irix: clean-include - (cd IRIX; make clean) + (cd IRIX; $(MAKE) clean) -clean-linux: clean-include - (cd Linux; make clean) +h/xti.h: + mkdir -p h + ln -s /usr/include/sys/xti.h h -get: - -@for i in ipf.c ipt.h solaris.c ipf.h kmem.c ipft_ef.c linux.h \ - ipft_pc.c fil.c ipft_sn.c mln_ipl.c fils.c ipft_td.c \ - mls_ipl.c ip_compat.h ipl.h opt.c ip_fil.c ipl_ldev.c \ - parse.c ip_fil.h ipmon.c pcap.h ip_sfil.c ipt.c snoop.h \ - ip_state.c ip_state.h ip_nat.c ip_nat.h ip_frag.c \ - ip_frag.h ip_sfil.c misc.c; do \ - if [ ! -f $$i ] ; then \ - echo "getting $$i"; \ - sccs get $$i; \ - fi \ - done +hpux: include h/xti.h + make setup CPUDIR=`HPUX/cpurev` TARGOS=HPUX + (cd HPUX/`HPUX/cpurev`; $(MAKE) build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..) + (cd HPUX/`HPUX/cpurev`; $(MAKE) -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..) sunos4 solaris1: (cd SunOS4; make build TOP=.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) - (cd SunOS4; make -f Makefile.ipsend "CC=$(CC)" TOP=.. $(DEST) $(MFLAGS); cd ..) + (cd SunOS4; make -f Makefile.ipsend build "CC=$(CC)" TOP=.. $(DEST) $(MFLAGS); cd ..) -sunos5 solaris2: - (cd SunOS5/$(CPUDIR); make build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Dsparc -D__sparc__"; cd ..) - (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) +sunos5 solaris2: null + (cd SunOS5/$(CPUDIR); $(MAKE) build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Dsparc -D__sparc__"; cd ..) + (cd SunOS5/$(CPUDIR); $(MAKE) -f Makefile.ipsend build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) -sunos5x86 solaris2x86: +sunos5x86 solaris2x86: null (cd SunOS5/$(CPUDIR); make build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" "CPU=-Di86pc -Di386 -D__i386__"; cd ..) - (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) + (cd SunOS5/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) -install-linux: - (cd Linux/$(CPUDIR); make install "TOP=../.." $(DEST) $(MFLAGS); cd ..) - (cd Linux/$(CPUDIR); make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(DEST) $(MFLAGS); cd ..) +linux: null include + (cd Linux; make build LINUX=`uname -r | awk -F. ' { for(i=0;i/dev/null 1>&2 + +null: + -@if [ "`$(MAKE) -v 2>&1 | sed -ne 's/GNU.*/GNU/p'`" = "GNU" ] ; then \ + echo 'Do not use GNU make (gmake) to compile IPFilter'; \ + exit 1; \ + fi + -@echo make ok + +mdb: + /bin/rm -rf mdbgen_build + mdbgen -D_KERNEL -DIPFILTER_LOG -DIPFILTER_LOOKUP -DSUNDDI \ + -DIPFILTER_SCAN -DIPFILTER_LKM -DSOLARIS2=10 -n ipf_mdb -k \ + -I/home/dr146992/pfil -I/home/dr146992/ipf -f \ + /usr/include/netinet/in_systm.h,/usr/include/sys/ethernet.h,/usr/include/netinet/in.h,/usr/include/netinet/ip.h,/usr/include/netinet/ip_var.h,/usr/include/netinet/tcp.h,/usr/include/netinet/tcpip.h,/usr/include/netinet/ip_icmp.h,/usr/include/netinet/udp.h,ip_compat.h,ip_fil.h,ip_nat.h,ip_state.h,ip_proxy.h,ip_scan.h diff --git a/dist/ipf/OpenBSD/files.diffs b/dist/ipf/OpenBSD/files.diffs new file mode 100644 index 000000000000..878f2e0752be --- /dev/null +++ b/dist/ipf/OpenBSD/files.diffs @@ -0,0 +1,18 @@ +*** files.FCS Thu May 1 06:21:14 1997 +--- files Mon Oct 27 14:08:53 1997 +*************** +*** 299,304 **** +--- 299,311 ---- + file netinet/ip_nat.c ipfilter + file netinet/ip_frag.c ipfilter + file netinet/ip_state.c ipfilter ++ file netinet/ip_proxy.c ipfilter ++ file netinet/ip_auth.c ipfilter ++ file netinet/ip_log.c ipfilter ++ file netinet/ip_scan.c ipfilter ++ file netinet/ip_sync.c ipfilter ++ file netinet/ip_pool.c ipfilter_pool ++ file netinet/ip_rules.c ipfilter_compiled + file netinet/ip_ah.c inet & ipsec + file netinet/ip_esp.c inet & ipsec + file netinet/ip_espdes.c inet & ipsec diff --git a/dist/ipf/OpenBSD/kinstall b/dist/ipf/OpenBSD/kinstall new file mode 100644 index 000000000000..9be50d2a4784 --- /dev/null +++ b/dist/ipf/OpenBSD/kinstall @@ -0,0 +1,82 @@ +#! /bin/sh +# +# kinstall/minstall - install patches to kernel sources +# +# WARNING: This script should be run exactly once on a virgin system +# +PATH=/sbin:/usr/sbin:/bin:/usr/bin; export PATH + +argv0=`basename $0` +dir=`pwd` +karch=`uname -m` +archdir="/sys/arch/$karch" +confdir="$archdir/conf" + +case "$dir" in +*/OpenBSD ) + cd .. + ;; +esac + +echo -n "Backing up existing kernel sources ..." +backup="" +for i in fil.c ip_fil.[ch] ip_frag.[ch] ip_nat.[ch] ip_state.[ch] ip_fil_compat.h; do + if [ -e /sys/netinet/$i ] ; then + backup="${backup} ${i}" + fi +done +if [ -n "$backup" ] ; then + ( cd /sys/netinet ; tar cf ipfbackup.tar $backup ) +fi +echo + +echo -n "Installing " +for i in ip_fil.[ch] fil.c ip_nat.[ch] ip_frag.[ch] ip_state.[ch] ip_proxy.[ch] ip_auth.[ch] ip_log.c ip_compat.h ipl.h ip_ftp_pxy.c ip_rcmd_pxy.c ip_raudio_pxy.c; do + echo -n "$i " + cp $i /sys/netinet/ + chmod 644 /sys/netinet/$i +done +echo + +if [ -f /sys/conf/files ] ; then + echo "Patching /sys/conf/files ..." + cat OpenBSD/files.diffs | (cd /sys/conf; patch) + ip_files=`egrep '^file.*ipfilter' /sys/conf/files | wc -l` + if [ $ip_files -lt 8 ] ; then + echo "Patching /sys/conf/files ..." + cat OpenBSD/files.diffs | (cd /sys/conf; patch) + fi +fi +if [ -f /sys/netinet/ip_fil_compat.h ] ; then + echo "Linking /sys/netinet/ip_compat.h to /sys/netinet/ip_fil_compat.h" + rm /sys/netinet/ip_fil_compat.h + ln -s /sys/netinet/ip_compat.h /sys/netinet/ip_fil_compat.h +fi + +echo -n "Kernel configuration to update [GENERIC] " +read newconfig junk + +if [ -n "$newconfig" ] ; then + config="$confdir/$newconfig" +else + newconfig="$confdir/GENERIC" +fi + +if egrep 'option.*IPFILTER' $confdir/$newconfig > /dev/null 2>&1 ; then + echo "$newconfig already contains proper options statement..." + echo 'You will now need to build a new kernel.' +else + echo "Backing up $newconfig to .bak and adding IPFILTER options..." + if [ -f $confdir/$newconfig ]; then + mv $confdir/$newconfig $confdir/$newconfig.bak + fi + if [ -d $archdir/compile/$newconfig ]; then + mv $archdir/compile/$newconfig $archdir/compile/$newconfig.bak + fi + awk '{print $0} $2=="INET"{print "options IPFILTER"}' \ + $confdir/$newconfig.bak > $confdir/$newconfig + + echo 'You will now need to run "config" and build a new kernel.' +fi + +exit 0 diff --git a/dist/ipf/OpenBSD/mknewipf.sh b/dist/ipf/OpenBSD/mknewipf.sh new file mode 100644 index 000000000000..71344babfd5c --- /dev/null +++ b/dist/ipf/OpenBSD/mknewipf.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# documented from +# http://www.tfsb.org/ipf-openbsd/ +ARCH=sparc +KERNEL=MULAN +IPF=ip-fil3.4.17 +rm -rf $IPF +tar zxf $IPF.tar.gz +cd $IPF +perl -pi -e "s/#STATETOP_CFLAGS=/STATETOP_CFLAGS=/" Makefile +perl -pi -e "s/#STATETOP_INC=$/STATETOP_INC=/" Makefile +perl -pi -e "s/#STATETOP_LIB=-lncurses/STATETOP_LIB=-lcurses/" Makefile +perl -pi -e "s/#INET6/INET6/" Makefile +make openbsd +make install-bsd +cd OpenBSD +echo $KERNEL | ./kinstall >/dev/null 2>&1 +cd /usr/src/sys/arch/$ARCH/conf +config $KERNEL +cd /usr/src/sys/arch/$ARCH/compile/$KERNEL +make clean && make depend && make && mv /bsd /bsd.old && mv bsd /bsd && reboot \ No newline at end of file diff --git a/dist/ipf/OpenBSD/patch.1 b/dist/ipf/OpenBSD/patch.1 new file mode 100644 index 000000000000..d550dedd84be --- /dev/null +++ b/dist/ipf/OpenBSD/patch.1 @@ -0,0 +1,23 @@ +.\" $NetBSD: patch.1,v 1.3 2004/03/28 09:00:55 martti Exp $ +.\" +*** net/if_bridge.c.orig Sat Mar 20 07:47:33 1999 +--- net/if_bridge.c Wed Sep 15 22:44:16 1999 +*************** +*** 55,62 **** + #include + #include + #include +! #ifdef IPFILTER +! #include + #include + #endif + #endif +--- 55,62 ---- + #include + #include + #include +! #if (defined(IPFILTER) || defined(IPFILTER_LKM)) +! #include + #include + #endif + #endif diff --git a/dist/ipf/OpenBSD/unkinstall b/dist/ipf/OpenBSD/unkinstall new file mode 100644 index 000000000000..c4f77f7a6441 --- /dev/null +++ b/dist/ipf/OpenBSD/unkinstall @@ -0,0 +1,53 @@ +#! /bin/sh +# +# kinstall/minstall - install patches to kernel sources +# +# WARNING: This script should be run exactly once on a virgin system +# +PATH=/sbin:/usr/sbin:/bin:/usr/bin; export PATH + +# try to bomb out fast if anything fails.... +set -e + +argv0=`basename $0` +dir=`pwd` +karch=`uname -m` +archdir="/sys/arch/$karch" +confdir="$archdir/conf" + +case "$dir" in +*/OpenBSD ) + cd .. + ;; +esac + +echo -n "Removing " +for i in ip_fil.[ch] ip_nat.[ch] ip_frag.[ch] ip_state.[ch] fil.c ip_compat.h ip_proxy.[ch] ip_ftp_pxy.c ip_auth.[ch] ip_log.c +do + echo -n "/sys/netinet/$i " + /bin/rm -f /sys/netinet/$i +done +echo + +if [ -f /sys/netinet/ipfbackup.tar ] ; then + echo -n "Restoring old kernel sources" + ( cd /sys/netinet ; tar xpf ipfbackup.tar ) +fi +echo + +echo "Unpatching /sys/conf/files ..." +cat OpenBSD/files.diffs | (cd /sys/conf; patch -R) + +echo -n "Kernel configuration to update [GENERIC] " +read newconfig junk + +if [ -n "$newconfig" ] ; then + config="$confdir/$newconfig" +else + newconfig="$confdir/GENERIC" +fi + +mv $archdir/compile/$newconfig $archdir/compile/$newconfig.bak +egrep -v 'IPFILTER' $confdir/$newconfig.bak > $confdir/$newconfig +echo 'You will now need to run "config" and build a new kernel.' +exit 0 diff --git a/dist/ipf/QNX_OCL.txt b/dist/ipf/QNX_OCL.txt deleted file mode 100644 index 6aa33eaf6b06..000000000000 --- a/dist/ipf/QNX_OCL.txt +++ /dev/null @@ -1,275 +0,0 @@ - End User License Certificate (EULA) End User License Certificate - (EULA) - Support Support - QNX Source Licenses QNX Source Licenses - License of the month - Confidential Source License - Version 1.0 - -QNX Open Community License Version 1.0 - - THIS QNX OPEN COMMUNITY LICENSE ( "THE OCL", OR "THIS AGREEMENT") - APPLIES TO PROGRAMS THAT QNX SOFTWARE SYSTEMS LTD. ("QSS") EXPRESSLY - ELECTS TO LICENSE UNDER THE OCL TERMS. IT ALSO APPLIES TO DERIVATIVE - WORKS CREATED UNDER THIS AGREEMENT THAT CREATORS ELECT TO LICENSE TO - OTHERS IN SOURCE CODE FORM. ANY USE, REPRODUCTION, MODIFICATION OR - DISTRIBUTION OF SUCH PROGRAMS CONSTITUTES RECIPIENT'S ACCEPTANCE OF - THE OCL. THE LICENSE RIGHTS GRANTED BELOW ARE CONDITIONAL UPON - RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT AND THE FORMATION OF A - BINDING CONTRACT. NOTHING ELSE GRANTS PERMISSION TO USE, REPRODUCE, - MODIFY OR DISTRIBUTE SUCH PROGRAMS OR THEIR DERIVATIVE WORKS. THESE - ACTIONS ARE OTHERWISE PROHIBITED. CONTACT QSS IF OTHER STEPS ARE - REQUIRED LOCALLY TO CREATE A BINDING CONTRACT. - - The OCL is intended to promote the development, use and distribution - of derivative works created from QSS source code. This includes - commercial distribution of object code versions under the terms of - Recipient's own license agreement and, at Recipient's option, sharing - of source code modifications within the QNX developer's community. The - license granted under the OCL is royalty free. Recipient is entitled - to charge royalties for object code versions of derivative works that - originate with Recipient. If Recipient elects to license source code - for its derivative works to others, then it must be licensed under the - OCL. The terms of the OCL are as follows: - -1. DEFINITIONS - - "Contribution" means: - - a. in the case of QSS: (i) the Original Program, where the Original - Program originates from QSS, (ii) changes and/or additions to - Unrestricted Open Source, where the Original Program originates - from Unrestricted Open Source and where such changes and/or - additions originate from QSS, and (iii) changes and/or additions - to the Program where such changes and/or additions originate from - QSS. - b. in the case of each Contributor, changes and/or additions to the - Program, where such changes and/or additions originate from and - are distributed by that particular Contributor. - - A Contribution 'originates' from a Contributor if it was added to the - Program by such Contributor itself or anyone acting on such - Contributor's behalf. Contributions do not include additions to the - Program which: (i) are separate modules of software distributed in - conjunction with the Program under their own license agreement, and - (ii) are not derivative works of the Program. - - "Contributor" means QSS and any other entity that distributes the - Program. - - "Licensed Patents " mean patent claims licensable by Contributor to - others, which are necessarily infringed by the use or sale of its - Contribution alone or when combined with the Program. - - "Unrestricted Open Source" means published source code that is - licensed for free use and distribution under an unrestricted licensing - and distribution model, such as the Berkley Software Design ("BSD") - and "BSD-like" licenses. It specifically excludes any source code - licensed under any version of the GNU General Public License (GPL) or - the GNU Lesser/Library GPL. All "Unrestricted Open Source" license - terms appear or are clearly identified in the header of any affected - source code for the Original Program. - - "Original Program" means the original version of the software - accompanying this Agreement as released by QSS, including source code, - object code and documentation, if any. - - "Program" means the Original Program and Contributions. - - "Recipient" means anyone who receives the Program under this - Agreement, including all Contributors. - -2. GRANT OF RIGHTS - - a. Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free - copyright license to reproduce, prepare derivative works of, - publicly display, publicly perform, and directly and indirectly - sublicense and distribute the Contribution of such Contributor, if - any, and such derivative works, in source code and object code - form. - b. Subject to the terms of this Agreement, each Contributor hereby - grants Recipient a non-exclusive, worldwide, royalty-free patent - license under Licensed Patents to make, use, sell, offer to sell, - import and otherwise transfer the Contribution of such - Contributor, if any, in source code and object code form. This - patent license shall apply to the combination of the Contribution - and the Program if, at the time the Contribution is added by the - Contributor, such addition of the Contribution causes such - combination to be covered by the Licensed Patents. The patent - license shall not apply to any other combinations which include - the Contribution. - c. Recipient understands that although each Contributor grants the - licenses to its Contributions set forth herein, no assurances are - provided by any Contributor that the Program does not infringe the - patent or other intellectual property rights of any other entity. - Each Contributor disclaims any liability to Recipient for claims - brought by any other entity based on infringement of intellectual - property rights or otherwise. As a condition to exercising the - rights and licenses granted hereunder, each Recipient hereby - assumes sole responsibility to secure any other intellectual - property rights needed, if any. For example, if a third party - patent license is required to allow Recipient to distribute the - Program, it is Recipient's responsibility to acquire that license - before distributing the Program. - d. Each Contributor represents that to its knowledge it has - sufficient copyright rights in its Contribution, if any, to grant - the copyright license set forth in this Agreement. - - 3. REQUIREMENTS - - A Contributor may choose to distribute the Program in object code form - under its own license agreement, provided that: - - a. it complies with the terms and conditions of this Agreement; and - b. its license agreement: - i. effectively disclaims on behalf of all Contributors all - warranties and conditions, express and implied, including - warranties or conditions of title and non-infringement, and - implied warranties or conditions of merchantability and - fitness for a particular purpose; - ii. effectively excludes on behalf of all Contributors all - liability for damages, including direct, indirect, special, - incidental and consequential damages, such as lost profits; - and - iii. states that any provisions which differ from this Agreement - are offered by that Contributor alone and not by any other - party. - - If the Program is made available in source code form: - - a. it must be made available under this Agreement; and - b. a copy of this Agreement must be included with each copy of the - Program. Each Contributor must include the following in a - conspicuous location in the Program along with any other copyright - or attribution statements required by the terms of any applicable - Unrestricted Open Source license: - Copyright {date here}, QNX Software Systems Ltd. and others. All - Rights Reserved. - - In addition, each Contributor must identify itself as the originator - of its Contribution, if any, in a manner that reasonably allows - subsequent Recipients to identify the originator of the Contribution. - - 4. COMMERCIAL DISTRIBUTION - - Commercial distributors of software may accept certain - responsibilities with respect to end users, business partners and the - like. While this license is intended to facilitate the commercial use - of the Program, the Contributor who includes the Program in a - commercial product offering should do so in a manner which does not - create potential liability for other Contributors. Therefore, if a - Contributor includes the Program in a commercial product offering, - such Contributor ("Commercial Contributor") hereby agrees to defend - and indemnify every other Contributor ("Indemnified Contributor") - against any losses, damages and costs (collectively "Losses") arising - from claims, lawsuits and other legal actions brought by a third party - against the Indemnified Contributor to the extent caused by the acts - or omissions of such Commercial Contributor in connection with its - distribution of the Program in a commercial product offering. The - obligations in this section do not apply to any claims or Losses - relating to any actual or alleged intellectual property infringement. - In order to qualify, an Indemnified Contributor must: a) promptly - notify the Commercial Contributor in writing of such claim, and b) - allow the Commercial Contributor to control, and cooperate with the - Commercial Contributor in, the defense and any related settlement - negotiations. The Indemnified Contributor may participate in any such - claim at its own expense. - - For example, a Contributor might include the Program in a commercial - product offering, Product X. That Contributor is then a Commercial - Contributor. If that Commercial Contributor then makes performance - claims, or offers warranties related to Product X, those performance - claims and warranties are such Commercial Contributor's responsibility - alone. Under this section, the Commercial Contributor would have to - defend claims against the other Contributors related to those - performance claims and warranties, and if a court requires any other - Contributor to pay any damages as a result, the Commercial Contributor - must pay those damages. - - 5. NO WARRANTY - - Recipient acknowledges that there may be errors or bugs in the Program - and that it is imperative that Recipient conduct thorough testing to - identify and correct any problems prior to the productive use or - commercial release of any products that use the Program, and prior to - the release of any modifications, updates or enhancements thereto. - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS - PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY - WARRANTIES OR CONDITIONS OF TITLE, NON- INFRINGEMENT, MERCHANTABILITY - OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely - responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, compliance with applicable - laws, damage to or loss of data, programs or equipment, and - unavailability or interruption of operations. - - 6. DISCLAIMER OF LIABILITY - - EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR - ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING - WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR - DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - 7. GENERAL - - If any provision of this Agreement is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of - the remainder of the terms of this Agreement, and without further - action by the parties hereto, such provision shall be reformed to the - minimum extent necessary to make such provision valid and enforceable. - - If Recipient institutes patent litigation against a Contributor with - respect to a patent applicable to software (including a cross-claim or - counterclaim in a lawsuit), then any patent licenses granted by that - Contributor to such recipient under this Agreement shall terminate as - of the date such litigation is filed. In addition, If Recipient - institutes patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Program - itself (excluding combinations of the Program with other software or - hardware) infringes such Recipient's patent(s), then such Recipient's - rights granted under Section 2(b) shall terminate as of the date such - litigation is filed. - - All Recipient's rights under this Agreement shall terminate if it - fails to comply with any of the material terms or conditions of this - Agreement and does not cure such failure in a reasonable period of - time after becoming aware of such noncompliance. If all Recipient's - rights under this Agreement terminate, Recipient agrees to cease use - and distribution of the Program as soon as reasonably practicable. - However, Recipient's obligations under this Agreement and any licenses - granted by Recipient relating to the Program shall continue and - survive. - - QSS may publish new versions (including revisions) of this Agreement - from time to time. Each new version of the Agreement will be given a - distinguishing version number. The Program (including Contributions) - may always be distributed subject to the version of the Agreement - under which it was received. In addition, after a new version of the - Agreement is published, Contributor may elect to distribute the - Program (including its Contributions) under the new version. No one - other than QSS has the right to modify this Agreement. Except as - expressly stated in Sections 2(a) and 2(b) above, Recipient receives - no rights or licenses to the intellectual property of any Contributor - under this Agreement, whether expressly, by implication, estoppel or - otherwise. All rights in the Program not expressly granted under this - Agreement are reserved. - - This Agreement is governed by the laws in force in the Province of - Ontario, Canada without regard to the conflict of law provisions - therein. The parties expressly disclaim the provisions of the United - Nations Convention on Contracts for the International Sale of Goods. - No party to this Agreement will bring a legal action under this - Agreement more than one year after the cause of action arose. Each - party waives its rights to a jury trial in any resulting litigation. - - * QNX is a registered trademark of QNX Software Systems Ltd. - - Document Version: ocl1_00 diff --git a/dist/ipf/UPGRADE_NOTICE b/dist/ipf/UPGRADE_NOTICE deleted file mode 100644 index 8b4476072b27..000000000000 --- a/dist/ipf/UPGRADE_NOTICE +++ /dev/null @@ -1,10 +0,0 @@ - -NOTE: To all those upgrading from versions prior to 3.2.11 who used NAT - AND setup ACL's to allow untranslated address through from outside, - - THIS HAS BEEN FIXED - - so your ACL's will now be `broken'. Please correct your ACL's to - match the the untranslated addresses (the way it was meant to work). - -Darren diff --git a/dist/ipf/common.c b/dist/ipf/common.c deleted file mode 100644 index af1083d25bee..000000000000 --- a/dist/ipf/common.c +++ /dev/null @@ -1,614 +0,0 @@ -/* $NetBSD: common.c,v 1.2 2002/04/09 02:32:51 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include "ip_fil.h" -#include "ipf.h" -#include "facpri.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)parse.c 1.44 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 darrenr Exp $"; -#endif - -extern struct ipopt_names ionames[], secclass[]; -extern int opts; -extern int use_inet6; - - -char *proto = NULL; -char flagset[] = "FSRPAUEC"; -u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG, - TH_ECN, TH_CWR }; - -void fill6bits __P((int, u_32_t *)); -int count6bits __P((u_32_t *)); - -static char thishost[MAXHOSTNAMELEN]; - - -void initparse() -{ - gethostname(thishost, sizeof(thishost)); - thishost[sizeof(thishost) - 1] = '\0'; -} - - -int genmask(msk, mskp) -char *msk; -u_32_t *mskp; -{ - char *endptr = NULL; -#ifdef USE_INET6 - u_32_t addr; -#endif - int bits; - - if (index(msk, '.') || index(msk, 'x') || index(msk, ':')) { - /* possibly of the form xxx.xxx.xxx.xxx - * or 0xYYYYYYYY */ -#ifdef USE_INET6 - if (use_inet6) { - if (inet_pton(AF_INET6, msk, &addr) != 1) - return -1; - } else -#endif - if (inet_aton(msk, (struct in_addr *)mskp) == 0) - return -1; - } else { - /* - * set x most significant bits - */ - bits = (int)strtol(msk, &endptr, 0); - if ((*endptr != '\0') || - ((bits > 32) && !use_inet6) || (bits < 0) || - ((bits > 128) && use_inet6)) - return -1; - if (use_inet6) - fill6bits(bits, mskp); - else { - if (bits == 0) - *mskp = 0; - else - *mskp = htonl(0xffffffff << (32 - bits)); - } - } - return 0; -} - - - -void fill6bits(bits, msk) -int bits; -u_32_t *msk; -{ - int i; - - for (i = 0; bits >= 32 && i < 4 ; ++i, bits -= 32) - msk[i] = 0xffffffff; - - if (bits > 0 && i < 4) - msk[i++] = htonl(0xffffffff << (32 - bits)); - - while (i < 4) - msk[i++] = 0; -} - - -/* - * returns -1 if neither "hostmask/num" or "hostmask mask addr" are - * found in the line segments, there is an error processing this information, - * or there is an error processing ports information. - */ -int hostmask(seg, sa, msk, pp, cp, tp, linenum) -char ***seg; -u_32_t *sa, *msk; -u_short *pp, *tp; -int *cp; -int linenum; -{ - struct in_addr maskaddr; - char *s; - - /* - * is it possibly hostname/num ? - */ - if ((s = index(**seg, '/')) || - ((s = index(**seg, ':')) && !index(s + 1, ':'))) { - *s++ = '\0'; - if (genmask(s, msk) == -1) { - fprintf(stderr, "%d: bad mask (%s)\n", linenum, s); - return -1; - } - if (hostnum(sa, **seg, linenum) == -1) { - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; - } - *sa &= *msk; - (*seg)++; - return ports(seg, pp, cp, tp, linenum); - } - - /* - * look for extra segments if "mask" found in right spot - */ - if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) { - if (hostnum(sa, **seg, linenum) == -1) { - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; - } - (*seg)++; - (*seg)++; - if (inet_aton(**seg, &maskaddr) == 0) { - fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg); - return -1; - } - *msk = maskaddr.s_addr; - (*seg)++; - *sa &= *msk; - return ports(seg, pp, cp, tp, linenum); - } - - if (**seg) { - if (hostnum(sa, **seg, linenum) == -1) { - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; - } - (*seg)++; - if (use_inet6) { - u_32_t k = 0; - if (sa[0] || sa[1] || sa[2] || sa[3]) - k = 0xffffffff; - msk[0] = msk[1] = msk[2] = msk[3] = k; - } - else - *msk = *sa ? 0xffffffff : 0; - return ports(seg, pp, cp, tp, linenum); - } - fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg); - return -1; -} - -/* - * returns an ip address as a long var as a result of either a DNS lookup or - * straight inet_addr() call - */ -int hostnum(ipa, host, linenum) -u_32_t *ipa; -char *host; -int linenum; -{ - struct hostent *hp; - struct netent *np; - struct in_addr ip; - - if (!strcasecmp("any", host)) - return 0; -#ifdef USE_INET6 - if (use_inet6) { - if (inet_pton(AF_INET6, host, ipa) == 1) - return 0; - else - return -1; - } -#endif - if (isdigit(*host) && inet_aton(host, &ip)) { - *ipa = ip.s_addr; - return 0; - } - - if (!strcasecmp("", host)) - host = thishost; - - if (!(hp = gethostbyname(host))) { - if (!(np = getnetbyname(host))) { - fprintf(stderr, "%d: can't resolve hostname: %s\n", - linenum, host); - return -1; - } - *ipa = htonl(np->n_net); - return 0; - } - *ipa = *(u_32_t *)hp->h_addr; - return 0; -} - - -/* - * check for possible presence of the port fields in the line - */ -int ports(seg, pp, cp, tp, linenum) -char ***seg; -u_short *pp, *tp; -int *cp; -int linenum; -{ - int comp = -1; - - if (!*seg || !**seg || !***seg) - return 0; - if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) { - (*seg)++; - if (isalnum(***seg) && *(*seg + 2)) { - if (portnum(**seg, pp, linenum) == 0) - return -1; - (*seg)++; - if (!strcmp(**seg, "<>")) - comp = FR_OUTRANGE; - else if (!strcmp(**seg, "><")) - comp = FR_INRANGE; - else { - fprintf(stderr, - "%d: unknown range operator (%s)\n", - linenum, **seg); - return -1; - } - (*seg)++; - if (**seg == NULL) { - fprintf(stderr, "%d: missing 2nd port value\n", - linenum); - return -1; - } - if (portnum(**seg, tp, linenum) == 0) - return -1; - } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq")) - comp = FR_EQUAL; - else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne")) - comp = FR_NEQUAL; - else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt")) - comp = FR_LESST; - else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt")) - comp = FR_GREATERT; - else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le")) - comp = FR_LESSTE; - else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge")) - comp = FR_GREATERTE; - else { - fprintf(stderr, "%d: unknown comparator (%s)\n", - linenum, **seg); - return -1; - } - if (comp != FR_OUTRANGE && comp != FR_INRANGE) { - (*seg)++; - if (portnum(**seg, pp, linenum) == 0) - return -1; - } - *cp = comp; - (*seg)++; - } - return 0; -} - - -/* - * find the port number given by the name, either from getservbyname() or - * straight atoi(). Return 1 on success, 0 on failure - */ -int portnum(name, port, linenum) -char *name; -u_short *port; -int linenum; -{ - struct servent *sp, *sp2; - u_short p1 = 0; - int i; - - if (isdigit(*name)) { - if (ratoi(name, &i, 0, USHRT_MAX)) { - *port = (u_short)i; - return 1; - } - fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name); - return 0; - } - if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) { - sp = getservbyname(name, proto); - if (sp) { - *port = ntohs(sp->s_port); - return 1; - } - fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name); - return 0; - } - sp = getservbyname(name, "tcp"); - if (sp) - p1 = sp->s_port; - sp2 = getservbyname(name, "udp"); - if (!sp || !sp2) { - fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n", - linenum, name); - return 0; - } - if (p1 != sp2->s_port) { - fprintf(stderr, "%d: %s %d/tcp is a different port to ", - linenum, name, p1); - fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port); - return 0; - } - *port = ntohs(p1); - return 1; -} - - -u_char tcp_flags(flgs, mask, linenum) -char *flgs; -u_char *mask; -int linenum; -{ - u_char tcpf = 0, tcpfm = 0, *fp = &tcpf; - char *s, *t; - - if (*flgs == '0') { - s = strchr(flgs, '/'); - if (s) - *s++ = '\0'; - tcpf = strtol(flgs, NULL, 0); - fp = &tcpfm; - } else - s = flgs; - - for (; *s; s++) { - if (*s == '/' && fp == &tcpf) { - fp = &tcpfm; - if (*(s + 1) == '0') - break; - continue; - } - if (!(t = index(flagset, *s))) { - fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s); - return 0; - } - *fp |= flags[t - flagset]; - } - - if (s && *s == '0') - tcpfm = strtol(s, NULL, 0); - - if (!tcpfm) { - if (tcpf == TH_SYN) - tcpfm = 0xff & ~(TH_ECN|TH_CWR); - else - tcpfm = 0xff & ~(TH_ECN); - } - *mask = tcpfm; - return tcpf; -} - - -/* - * count consecutive 1's in bit mask. If the mask generated by counting - * consecutive 1's is different to that passed, return -1, else return # - * of bits. - */ -int countbits(ip) -u_32_t ip; -{ - u_32_t ipn; - int cnt = 0, i, j; - - ip = ipn = ntohl(ip); - for (i = 32; i; i--, ipn *= 2) - if (ipn & 0x80000000) - cnt++; - else - break; - ipn = 0; - for (i = 32, j = cnt; i; i--, j--) { - ipn *= 2; - if (j > 0) - ipn++; - } - if (ipn == ip) - return cnt; - return -1; -} - - -int count6bits(msk) -u_32_t *msk; -{ - int i = 0, k; - u_32_t j; - - for (k = 3; k >= 0; k--) - if (msk[k] == 0xffffffff) - i += 32; - else { - for (j = msk[k]; j; j <<= 1) - if (j & 0x80000000) - i++; - } - return i; -} - - -char *portname(pr, port) -int pr, port; -{ - static char buf[32]; - struct protoent *p = NULL; - struct servent *sv = NULL, *sv1 = NULL; - - if (pr == -1) { - if ((sv = getservbyport(htons(port), "tcp"))) { - strncpy(buf, sv->s_name, sizeof(buf)-1); - buf[sizeof(buf)-1] = '\0'; - sv1 = getservbyport(htons(port), "udp"); - sv = strncasecmp(buf, sv->s_name, strlen(buf)) ? - NULL : sv1; - } - if (sv) - return buf; - } else if (pr && (p = getprotobynumber(pr))) { - if ((sv = getservbyport(htons(port), p->p_name))) { - strncpy(buf, sv->s_name, sizeof(buf)-1); - buf[sizeof(buf)-1] = '\0'; - return buf; - } - } - - (void) sprintf(buf, "%d", port); - return buf; -} - - -int ratoi(ps, pi, min, max) -char *ps; -int *pi, min, max; -{ - int i; - char *pe; - - i = (int)strtol(ps, &pe, 0); - if (*pe != '\0' || i < min || i > max) - return 0; - *pi = i; - return 1; -} - - -int ratoui(ps, pi, min, max) -char *ps; -u_int *pi, min, max; -{ - u_int i; - char *pe; - - i = (u_int)strtol(ps, &pe, 0); - if (*pe != '\0' || i < min || i > max) - return 0; - *pi = i; - return 1; -} - - -void printhostmask(v, addr, mask) -int v; -u_32_t *addr, *mask; -{ - struct in_addr ipa; - int ones; - -#ifdef USE_INET6 - if (v == 6) { - ones = count6bits(mask); - if (ones == 0 && !addr[0] && !addr[1] && !addr[2] && !addr[3]) - printf("any"); - else { - char ipbuf[64]; - printf("%s/%d", - inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf)), - ones); - } - } - else -#endif - if (!*addr && !*mask) - printf("any"); - else { - ipa.s_addr = *addr; - printf("%s", inet_ntoa(ipa)); - if ((ones = countbits(*mask)) == -1) { - ipa.s_addr = *mask; - printf("/%s", inet_ntoa(ipa)); - } else - printf("/%d", ones); - } -} - - -void printportcmp(pr, frp) -int pr; -frpcmp_t *frp; -{ - static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=", - "<>", "><"}; - - if (frp->frp_cmp == FR_INRANGE || frp->frp_cmp == FR_OUTRANGE) - printf(" port %d %s %d", frp->frp_port, - pcmp1[frp->frp_cmp], frp->frp_top); - else - printf(" port %s %s", pcmp1[frp->frp_cmp], - portname(pr, frp->frp_port)); -} - - -void printbuf(buf, len, zend) -char *buf; -int len, zend; -{ - char *s, c; - int i; - - for (s = buf, i = len; i; i--) { - c = *s++; - if (isprint(c)) - putchar(c); - else - printf("\\%03o", c); - if ((c == '\0') && zend) - break; - } -} - - - -char *hostname(v, ip) -int v; -void *ip; -{ -#ifdef USE_INET6 - static char hostbuf[MAXHOSTNAMELEN+1]; -#endif - struct in_addr ipa; - - if (v == 4) { - ipa.s_addr = *(u_32_t *)ip; - return inet_ntoa(ipa); - } -#ifdef USE_INET6 - (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); - hostbuf[MAXHOSTNAMELEN] = '\0'; - return hostbuf; -#else - return "IPv6"; -#endif -} diff --git a/dist/ipf/etc/services b/dist/ipf/etc/services index 01c4b782e29e..d8aa0d5ae223 100644 --- a/dist/ipf/etc/services +++ b/dist/ipf/etc/services @@ -2359,8 +2359,8 @@ dpserve 7020/tcp # DP Serve dpserve 7020/udp # DP Serve dpserveadmin 7021/tcp # DP Serve Admin dpserveadmin 7021/udp # DP Serve Admin +raudio 7070/tcp @ Real Audio arcp 7070/tcp # ARCP -raudio 7070/tcp # Real Audio arcp 7070/udp # ARCP clutild 7174/tcp # Clutild clutild 7174/udp # Clutild diff --git a/dist/ipf/facpri.c b/dist/ipf/facpri.c deleted file mode 100644 index 31bf6a60f7ef..000000000000 --- a/dist/ipf/facpri.c +++ /dev/null @@ -1,154 +0,0 @@ -/* $NetBSD: facpri.c,v 1.4 2002/04/09 02:32:51 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#endif -#include -#include -#include -#include -#include "facpri.h" - -#ifndef __STDC__ -# define const -#endif - -#if !defined(lint) -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: facpri.c,v 1.3.2.4 2001/07/15 22:06:12 darrenr Exp"; -#endif - -typedef struct table { - char *name; - int value; -} table_t; - -table_t facs[] = { - { "kern", LOG_KERN }, { "user", LOG_USER }, - { "mail", LOG_MAIL }, { "daemon", LOG_DAEMON }, - { "auth", LOG_AUTH }, { "syslog", LOG_SYSLOG }, - { "lpr", LOG_LPR }, { "news", LOG_NEWS }, - { "uucp", LOG_UUCP }, -#if LOG_CRON == LOG_CRON2 - { "cron2", LOG_CRON1 }, -#else - { "cron", LOG_CRON1 }, -#endif -#ifdef LOG_FTP - { "ftp", LOG_FTP }, -#endif -#ifdef LOG_AUTHPRIV - { "authpriv", LOG_AUTHPRIV }, -#endif -#ifdef LOG_AUDIT - { "audit", LOG_AUDIT }, -#endif -#ifdef LOG_LFMT - { "logalert", LOG_LFMT }, -#endif -#if LOG_CRON == LOG_CRON1 - { "cron", LOG_CRON2 }, -#else - { "cron2", LOG_CRON2 }, -#endif -#ifdef LOG_SECURITY - { "security", LOG_SECURITY }, -#endif - { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, - { NULL, 0 } -}; - - -/* - * map a facility number to its name - */ -char * -fac_toname(facpri) - int facpri; -{ - int i, j, fac; - - fac = facpri & LOG_FACMASK; - j = fac >> 3; - if (j < 24) { - if (facs[j].value == fac) - return facs[j].name; - for (i = 0; facs[i].name; i++) - if (fac == facs[i].value) - return facs[i].name; - } - - return NULL; -} - - -/* - * map a facility name to its number - */ -int -fac_findname(name) - char *name; -{ - int i; - - for (i = 0; facs[i].name; i++) - if (!strcmp(facs[i].name, name)) - return facs[i].value; - return -1; -} - - -table_t pris[] = { - { "emerg", LOG_EMERG }, { "alert", LOG_ALERT }, - { "crit", LOG_CRIT }, { "err", LOG_ERR }, - { "warn", LOG_WARNING }, { "notice", LOG_NOTICE }, - { "info", LOG_INFO }, { "debug", LOG_DEBUG }, - { NULL, 0 } -}; - - -/* - * map a priority name to its number - */ -int -pri_findname(name) - char *name; -{ - int i; - - for (i = 0; pris[i].name; i++) - if (!strcmp(pris[i].name, name)) - return pris[i].value; - return -1; -} - - -/* - * map a priority number to its name - */ -char * -pri_toname(facpri) - int facpri; -{ - int i, pri; - - pri = facpri & LOG_PRIMASK; - if (pris[pri].value == pri) - return pris[pri].name; - for (i = 0; pris[i].name; i++) - if (pri == pris[i].value) - return pris[i].name; - return NULL; -} diff --git a/dist/ipf/facpri.h b/dist/ipf/facpri.h deleted file mode 100644 index 38b54c66e416..000000000000 --- a/dist/ipf/facpri.h +++ /dev/null @@ -1,42 +0,0 @@ -/* $NetBSD: facpri.h,v 1.3 2002/01/24 08:21:31 martti Exp $ */ - -/* - * Copyright (C) 1999-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * Id: facpri.h,v 1.3.2.1 2001/06/26 10:43:11 darrenr Exp - */ - -#ifndef __FACPRI_H__ -#define __FACPRI_H__ - -#ifndef __P -# define P_DEF -# ifdef __STDC__ -# define __P(x) x -# else -# define __P(x) () -# endif -#endif - -extern char *fac_toname __P((int)); -extern int fac_findname __P((char *)); - -extern char *pri_toname __P((int)); -extern int pri_findname __P((char *)); - -#ifdef P_DEF -# undef __P -# undef P_DEF -#endif - -#if LOG_CRON == (9<<3) -# define LOG_CRON1 LOG_CRON -# define LOG_CRON2 (15<<3) -#endif -#if LOG_CRON == (15<<3) -# define LOG_CRON1 (9<<3) -# define LOG_CRON2 LOG_CRON -#endif - -#endif /* __FACPRI_H__ */ diff --git a/dist/ipf/fils.c b/dist/ipf/fils.c deleted file mode 100644 index 55d6ab74a797..000000000000 --- a/dist/ipf/fils.c +++ /dev/null @@ -1,1536 +0,0 @@ -/* $NetBSD: fils.c,v 1.22 2003/08/15 08:10:09 martti Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __FreeBSD__ -# ifndef __FreeBSD_cc_version -# include -# else -# if __FreeBSD_cc_version < 430000 -# include -# endif -# endif -#endif -#ifdef __sgi -# include -#endif -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -# include -#endif -#include -#include -#include -#include -#if defined(STATETOP) -# if defined(_BSDI_VERSION) -# undef STATETOP) -# endif -# if defined(__FreeBSD__) && \ - (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000)) -# undef STATETOP -# endif -# if defined(__NetBSD_Version__) -# if (__NetBSD_Version__ < 105000000) -# undef STATETOP -# else -# include -# define USE_POLL -# endif -# endif -# if defined(sun) -# if defined(__svr4__) || defined(__SVR4) -# include -# else -# undef STATETOP /* NOT supported on SunOS4 */ -# endif -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#if defined(STATETOP) && !defined(linux) -# include -# include -#endif -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "ipf.h" -#include "netinet/ip_nat.h" -#include "netinet/ip_frag.h" -#include "netinet/ip_state.h" -#include "netinet/ip_proxy.h" -#include "netinet/ip_auth.h" -#ifdef STATETOP -# include "netinet/ipl.h" -# include -# if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \ - defined(__sgi) -# ifdef ERR -# undef ERR -# endif -# include -# else /* SOLARIS */ -# include -# endif /* SOLARIS */ -#endif /* STATETOP */ -#include "kmem.h" -#if defined(__NetBSD__) || (__OpenBSD__) -# include -#endif - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: fils.c,v 2.21.2.36 2002/06/27 14:29:16 darrenr Exp"; -#endif - -extern char *optarg; -extern int optind; - -#define PRINTF (void)printf -#define FPRINTF (void)fprintf -#define F_IN 0 -#define F_OUT 1 -#define F_ACIN 2 -#define F_ACOUT 3 -static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", - "ipacct(in)", "ipacct(out)" }; - -int opts = 0; -int use_inet6 = 0; -int live_kernel = 1; - -#ifdef STATETOP -#define STSTRSIZE 80 -#define STGROWSIZE 16 -#define HOSTNMLEN 40 - -#define STSORT_PR 0 -#define STSORT_PKTS 1 -#define STSORT_BYTES 2 -#define STSORT_TTL 3 -#define STSORT_SRCIP 4 -#define STSORT_DSTIP 5 -#define STSORT_MAX STSORT_DSTIP -#define STSORT_DEFAULT STSORT_BYTES - - -typedef struct statetop { - union i6addr st_src; - union i6addr st_dst; - u_short st_sport; - u_short st_dport; - u_char st_p; - u_char st_state[2]; - U_QUAD_T st_pkts; - U_QUAD_T st_bytes; - u_long st_age; -} statetop_t; -#endif - -extern int main __P((int, char *[])); -static void showstats __P((friostat_t *, u_32_t)); -static void showfrstates __P((ipfrstat_t *)); -static void showlist __P((friostat_t *)); -static void showipstates __P((ips_stat_t *)); -static void showauthstates __P((fr_authstat_t *)); -static void showgroups __P((friostat_t *)); -static void Usage __P((char *)); -static void printlist __P((frentry_t *)); -static void parse_ipportstr __P((const char *, struct in_addr *, int *)); -static int ipfstate_live __P((char *, friostat_t **, ips_stat_t **, - ipfrstat_t **, fr_authstat_t **, u_32_t *)); -static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **, - ipfrstat_t **, fr_authstat_t **, u_32_t *)); -#ifdef STATETOP -static void topipstates __P((struct in_addr, struct in_addr, int, int, int, int, int)); -static char *ttl_to_string __P((long)); -static int sort_p __P((const void *, const void *)); -static int sort_pkts __P((const void *, const void *)); -static int sort_bytes __P((const void *, const void *)); -static int sort_ttl __P((const void *, const void *)); -static int sort_srcip __P((const void *, const void *)); -static int sort_dstip __P((const void *, const void *)); -#endif -#if SOLARIS -void showqiflist __P((char *)); -#endif - - -static void Usage(name) -char *name; -{ -#ifdef USE_INET6 - fprintf(stderr, "Usage: %s [-6aAfhIinosv] [-d ]\n", name); -#else - fprintf(stderr, "Usage: %s [-aAfhIinosv] [-d ]\n", name); -#endif - fprintf(stderr, "\t\t[-M corefile] [-N symbol-list]\n"); - fprintf(stderr, " %s -t [-S source address] [-D destination address] [-P protocol] [-T refreshtime] [-C] [-d ]\n", name); - exit(1); -} - - -int main(argc,argv) -int argc; -char *argv[]; -{ - fr_authstat_t frauthst; - fr_authstat_t *frauthstp = &frauthst; - friostat_t fio; - friostat_t *fiop = &fio; - ips_stat_t ipsst; - ips_stat_t *ipsstp = &ipsst; - ipfrstat_t ifrst; - ipfrstat_t *ifrstp = &ifrst; - char *device = IPL_NAME, *memf = NULL; - char *kern = NULL; - int c, myoptind; - struct protoent *proto; - - int protocol = -1; /* -1 = wild card for any protocol */ - int refreshtime = 1; /* default update time */ - int sport = -1; /* -1 = wild card for any source port */ - int dport = -1; /* -1 = wild card for any dest port */ - int topclosed = 0; /* do not show closed tcp sessions */ - struct in_addr saddr, daddr; - u_32_t frf; - - saddr.s_addr = INADDR_ANY; /* default any source addr */ - daddr.s_addr = INADDR_ANY; /* default any dest addr */ - - /* - * Parse these two arguments now lest there be any buffer overflows - * in the parsing of the rest. - */ - myoptind = optind; - while ((c = getopt(argc, argv, "6aACfghIilnoqstvd:D:M:N:P:S:T:")) != -1) - switch (c) - { - case 'M' : - memf = optarg; - live_kernel = 0; - break; - case 'N' : - kern = optarg; - live_kernel = 0; - break; - } - optind = myoptind; - - if (kern != NULL || memf != NULL) - { - (void)setuid(getuid()); - (void)setgid(getgid()); - } - - if (openkmem(kern, memf) == -1) - exit(-1); - - (void)setuid(getuid()); - (void)setgid(getgid()); - - while ((c = getopt(argc, argv, "6aACfghIilnoqstvd:D:M:N:P:S:T:")) != -1) - { - switch (c) - { -#ifdef USE_INET6 - case '6' : - use_inet6 = 1; - break; -#endif - case 'a' : - opts |= OPT_ACCNT|OPT_SHOWLIST; - break; - case 'A' : - device = IPAUTH_NAME; - opts |= OPT_AUTHSTATS; - break; - case 'C' : - topclosed = 1; - break; - case 'd' : - device = optarg; - break; - case 'D' : - parse_ipportstr(optarg, &daddr, &dport); - break; - case 'f' : - opts |= OPT_FRSTATES; - break; - case 'g' : - opts |= OPT_GROUPS; - break; - case 'h' : - opts |= OPT_HITS; - break; - case 'i' : - opts |= OPT_INQUE|OPT_SHOWLIST; - break; - case 'I' : - opts |= OPT_INACTIVE; - break; - case 'l' : - opts |= OPT_SHOWLIST; - break; - case 'M' : - break; - case 'N' : - break; - case 'n' : - opts |= OPT_SHOWLINENO; - break; - case 'o' : - opts |= OPT_OUTQUE|OPT_SHOWLIST; - break; - case 'P' : - if ((proto = getprotobyname(optarg)) != NULL) { - protocol = proto->p_proto; - } else if (!sscanf(optarg, "%ud", &protocol) || - (protocol < 0)) { - fprintf(stderr, "%s : Invalid protocol: %s\n", - argv[0], optarg); - exit(-2); - } - break; - case 'q' : -#if SOLARIS - showqiflist(kern); - exit(0); - break; -#else - fprintf(stderr, "-q only availble on Solaris\n"); - exit(1); - break; -#endif - case 's' : - opts |= OPT_IPSTATES; - break; - case 'S' : - parse_ipportstr(optarg, &saddr, &sport); - break; - case 't' : -#ifdef STATETOP - opts |= OPT_STATETOP; - break; -#else - fprintf(stderr, - "%s : state top facility not compiled in\n", - argv[0]); - exit(-2); -#endif - case 'T' : - if (!sscanf(optarg, "%d", &refreshtime) || - (refreshtime <= 0)) { - fprintf(stderr, - "%s : Invalid refreshtime < 1 : %s\n", - argv[0], optarg); - exit(-2); - } - break; - case 'v' : - opts |= OPT_VERBOSE; - break; - default : - Usage(argv[0]); - break; - } - } - - if (live_kernel == 1) { - bzero((char *)&fio, sizeof(fio)); - bzero((char *)&ipsst, sizeof(ipsst)); - bzero((char *)&ifrst, sizeof(ifrst)); - - ipfstate_live(device, &fiop, &ipsstp, &ifrstp, - &frauthstp, &frf); - } else - ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); - - if (opts & OPT_IPSTATES) { - showipstates(ipsstp); - } else if (opts & OPT_SHOWLIST) { - showlist(fiop); - if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ - opts &= ~OPT_OUTQUE; - showlist(fiop); - } - } else { - if (opts & OPT_FRSTATES) - showfrstates(ifrstp); -#ifdef STATETOP - else if (opts & OPT_STATETOP) - topipstates(saddr, daddr, sport, dport, - protocol, refreshtime, topclosed); -#endif - else if (opts & OPT_AUTHSTATS) - showauthstates(frauthstp); - else if (opts & OPT_GROUPS) - showgroups(fiop); - else - showstats(fiop, frf); - } - return 0; -} - - -/* - * Fill in the stats structures from the live kernel, using a combination - * of ioctl's and copying directly from kernel memory. - */ -int ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) -char *device; -friostat_t **fiopp; -ips_stat_t **ipsstpp; -ipfrstat_t **ifrstpp; -fr_authstat_t **frauthstpp; -u_32_t *frfp; -{ - int fd; - - if ((fd = open(device, O_RDONLY)) < 0) { - perror("open"); - exit(-1); - } - - if (!(opts & OPT_AUTHSTATS) && ioctl(fd, SIOCGETFS, fiopp) == -1) { - perror("ioctl(ipf:SIOCGETFS)"); - exit(-1); - } - - if ((opts & OPT_IPSTATES)) { - int sfd = open(IPL_STATE, O_RDONLY); - - if (sfd == -1) { - perror("open"); - exit(-1); - } - if ((ioctl(sfd, SIOCGETFS, ipsstpp) == -1)) { - perror("ioctl(state:SIOCGETFS)"); - exit(-1); - } - close(sfd); - } - if ((opts & OPT_FRSTATES) && (ioctl(fd, SIOCGFRST, ifrstpp) == -1)) { - perror("ioctl(SIOCGFRST)"); - exit(-1); - } - - if (opts & OPT_VERBOSE) - PRINTF("opts %#x name %s\n", opts, device); - - if ((opts & OPT_AUTHSTATS) && - (ioctl(fd, SIOCATHST, frauthstpp) == -1)) { - perror("ioctl(SIOCATHST)"); - exit(-1); - } - - if (ioctl(fd, SIOCGETFF, frfp) == -1) - perror("ioctl(SIOCGETFF)"); - - return fd; -} - - -/* - * Build up the stats structures from data held in the "core" memory. - * This is mainly useful when looking at data in crash dumps and ioctl's - * just won't work any more. - */ -void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) -char *kernel; -friostat_t **fiopp; -ips_stat_t **ipsstpp; -ipfrstat_t **ifrstpp; -fr_authstat_t **frauthstpp; -u_32_t *frfp; -{ - static fr_authstat_t frauthst, *frauthstp; - static ips_stat_t ipsst, *ipsstp; - static ipfrstat_t ifrst, *ifrstp; - static friostat_t fio, *fiop; - - void *rules[2][2]; - struct nlist deadlist[42] = { - { "fr_authstats" }, /* 0 */ - { "fae_list" }, - { "ipauth" }, - { "fr_authlist" }, - { "fr_authstart" }, - { "fr_authend" }, /* 5 */ - { "fr_authnext" }, - { "fr_auth" }, - { "fr_authused" }, - { "fr_authsize" }, - { "fr_defaultauthage" }, /* 10 */ - { "fr_authpkts" }, - { "fr_auth_lock" }, - { "frstats" }, - { "ips_stats" }, - { "ips_num" }, /* 15 */ - { "ips_wild" }, - { "ips_list" }, - { "ips_table" }, - { "fr_statemax" }, - { "fr_statesize" }, /* 20 */ - { "fr_state_doflush" }, - { "fr_state_lock" }, - { "ipfr_heads" }, - { "ipfr_nattab" }, - { "ipfr_stats" }, /* 25 */ - { "ipfr_inuse" }, - { "fr_ipfrttl" }, - { "fr_frag_lock" }, - { "ipfr_timer_id" }, - { "fr_nat_lock" }, /* 30 */ - { "ipfilter" }, - { "ipfilter6" }, - { "ipacct" }, - { "ipacct6" }, - { "ipl_frouteok" }, /* 35 */ - { "fr_running" }, - { "ipfgroups" }, - { "fr_active" }, - { "fr_pass" }, - { "fr_flags" }, /* 40 */ - { NULL } - }; - - - frauthstp = &frauthst; - ipsstp = &ipsst; - ifrstp = &ifrst; - fiop = &fio; - - *frfp = 0; - *fiopp = fiop; - *ipsstpp = ipsstp; - *ifrstpp = ifrstp; - *frauthstpp = frauthstp; - - bzero((char *)fiop, sizeof(*fiop)); - bzero((char *)ipsstp, sizeof(*ipsstp)); - bzero((char *)ifrstp, sizeof(*ifrstp)); - bzero((char *)frauthstp, sizeof(*frauthstp)); - - if (nlist(kernel, deadlist) == -1) { - fprintf(stderr, "nlist error\n"); - return; - } - - /* - * This is for SIOCGETFF. - */ - kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp)); - - /* - * f_locks is a combination of the lock variable from each part of - * ipfilter (state, auth, nat, fragments). - */ - kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop)); - kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value, - sizeof(fiop->f_locks[0])); - kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value, - sizeof(fiop->f_locks[1])); - kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value, - sizeof(fiop->f_locks[2])); - kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value, - sizeof(fiop->f_locks[3])); - - /* - * Get pointers to each list of rules (active, inactive, in, out) - */ - kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules)); - fiop->f_fin[0] = rules[0][0]; - fiop->f_fin[1] = rules[0][1]; - fiop->f_fout[0] = rules[1][0]; - fiop->f_fout[1] = rules[1][1]; - - /* - * Same for IPv6, except make them null if support for it is not - * being compiled in. - */ -#ifdef USE_INET6 - kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules)); - fiop->f_fin6[0] = rules[0][0]; - fiop->f_fin6[1] = rules[0][1]; - fiop->f_fout6[0] = rules[1][0]; - fiop->f_fout6[1] = rules[1][1]; -#else - fiop->f_fin6[0] = NULL; - fiop->f_fin6[1] = NULL; - fiop->f_fout6[0] = NULL; - fiop->f_fout6[1] = NULL; -#endif - - /* - * Now get accounting rules pointers. - */ - kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules)); - fiop->f_acctin[0] = rules[0][0]; - fiop->f_acctin[1] = rules[0][1]; - fiop->f_acctout[0] = rules[1][0]; - fiop->f_acctout[1] = rules[1][1]; - -#ifdef USE_INET6 - kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules)); - fiop->f_acctin6[0] = rules[0][0]; - fiop->f_acctin6[1] = rules[0][1]; - fiop->f_acctout6[0] = rules[1][0]; - fiop->f_acctout6[1] = rules[1][1]; -#else - fiop->f_acctin6[0] = NULL; - fiop->f_acctin6[1] = NULL; - fiop->f_acctout6[0] = NULL; - fiop->f_acctout6[1] = NULL; -#endif - - /* - * A collection of "global" variables used inside the kernel which - * are all collected in friostat_t via ioctl. - */ - kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[35].n_value, - sizeof(fiop->f_froute)); - kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value, - sizeof(fiop->f_running)); - kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value, - sizeof(fiop->f_groups)); - kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value, - sizeof(fiop->f_active)); - kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].n_value, - sizeof(fiop->f_defpass)); - - /* - * Build up the state information stats structure. - */ - kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp)); - kmemcpy((char *)&ipsstp->iss_active, (u_long)deadlist[15].n_value, - sizeof(ipsstp->iss_active)); - ipsstp->iss_table = (void *)deadlist[18].n_value; - ipsstp->iss_list = (void *)deadlist[17].n_value; - - /* - * Build up the authentiation information stats structure. - */ - kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value, - sizeof(*frauthstp)); - frauthstp->fas_faelist = (void *)deadlist[1].n_value; - - /* - * Build up the fragment information stats structure. - */ - kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value, - sizeof(*ifrstp)); - ifrstp->ifs_table = (void *)deadlist[23].n_value; - ifrstp->ifs_nattab = (void *)deadlist[24].n_value; - kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value, - sizeof(ifrstp->ifs_inuse)); -} - - -/* - * Display the kernel stats for packets blocked and passed and other - * associated running totals which are kept. - */ -static void showstats(fp, frf) -struct friostat *fp; -u_32_t frf; -{ - -#if SOLARIS - PRINTF("dropped packets:\tin %lu\tout %lu\n", - fp->f_st[0].fr_drop, fp->f_st[1].fr_drop); - PRINTF("non-data packets:\tin %lu\tout %lu\n", - fp->f_st[0].fr_notdata, fp->f_st[1].fr_notdata); - PRINTF("no-data packets:\tin %lu\tout %lu\n", - fp->f_st[0].fr_nodata, fp->f_st[1].fr_nodata); - PRINTF("non-ip packets:\t\tin %lu\tout %lu\n", - fp->f_st[0].fr_notip, fp->f_st[1].fr_notip); - PRINTF(" bad packets:\t\tin %lu\tout %lu\n", - fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); - PRINTF("copied messages:\tin %lu\tout %lu\n", - fp->f_st[0].fr_copy, fp->f_st[1].fr_copy); -#endif -#ifdef USE_INET6 - PRINTF(" IPv6 packets:\t\tin %lu out %lu\n", - fp->f_st[0].fr_ipv6[0], fp->f_st[0].fr_ipv6[1]); -#endif - PRINTF(" input packets:\t\tblocked %lu passed %lu nomatch %lu", - fp->f_st[0].fr_block, fp->f_st[0].fr_pass, - fp->f_st[0].fr_nom); - PRINTF(" counted %lu short %lu\n", - fp->f_st[0].fr_acct, fp->f_st[0].fr_short); - PRINTF("output packets:\t\tblocked %lu passed %lu nomatch %lu", - fp->f_st[1].fr_block, fp->f_st[1].fr_pass, - fp->f_st[1].fr_nom); - PRINTF(" counted %lu short %lu\n", - fp->f_st[1].fr_acct, fp->f_st[1].fr_short); - PRINTF(" input packets logged:\tblocked %lu passed %lu\n", - fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); - PRINTF("output packets logged:\tblocked %lu passed %lu\n", - fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); - PRINTF(" packets logged:\tinput %lu output %lu\n", - fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl); - PRINTF(" log failures:\t\tinput %lu output %lu\n", - fp->f_st[0].fr_skip, fp->f_st[1].fr_skip); - 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); - PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc); - PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n", - fp->f_st[0].fr_chit, fp->f_st[1].fr_chit); - PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n", - fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]); - PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n", - fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]); - PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n", - fp->f_froute[0], fp->f_froute[1]); - PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n", - fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad); - - PRINTF("Packet log flags set: (%#x)\n", frf); - if (frf & FF_LOGPASS) - PRINTF("\tpackets passed through filter\n"); - if (frf & FF_LOGBLOCK) - PRINTF("\tpackets blocked by filter\n"); - if (frf & FF_LOGNOMATCH) - PRINTF("\tpackets not matched by filter\n"); - if (!frf) - PRINTF("\tnone\n"); -} - - -/* - * Print out a list of rules from the kernel, starting at the one passed. - */ -static void printlist(fp) -frentry_t *fp; -{ - struct frentry fb; - int n; - - for (n = 1; fp; n++) { - if (kmemcpy((char *)&fb, (u_long)fp, sizeof(fb)) == -1) { - perror("kmemcpy"); - return; - } - fp = &fb; - if (opts & OPT_OUTQUE) - fp->fr_flags |= FR_OUTQUE; - if (opts & (OPT_HITS|OPT_VERBOSE)) -#ifdef USE_QUAD_T - PRINTF("%qu ", (unsigned long long) fp->fr_hits); -#else - PRINTF("%lu ", fp->fr_hits); -#endif - if (opts & (OPT_ACCNT|OPT_VERBOSE)) -#ifdef USE_QUAD_T - PRINTF("%qu ", (unsigned long long) fp->fr_bytes); -#else - PRINTF("%lu ", fp->fr_bytes); -#endif - if (opts & OPT_SHOWLINENO) - PRINTF("@%d ", n); - printfr(fp); - if (opts & OPT_VERBOSE) - binprint(fp); - if (fp->fr_grp) - printlist(fp->fr_grp); - fp = fp->fr_next; - } -} - -/* - * print out all of the asked for rule sets, using the stats struct as - * the base from which to get the pointers. - */ -static void showlist(fiop) -struct friostat *fiop; -{ - struct frentry *fp = NULL; - int i, set; - - set = fiop->f_active; - if (opts & OPT_INACTIVE) - set = 1 - set; - if (opts & OPT_ACCNT) { -#ifdef USE_INET6 - if ((use_inet6) && (opts & OPT_OUTQUE)) { - i = F_ACOUT; - fp = (struct frentry *)fiop->f_acctout6[set]; - } else if ((use_inet6) && (opts & OPT_INQUE)) { - i = F_ACIN; - fp = (struct frentry *)fiop->f_acctin6[set]; - } else -#endif - if (opts & OPT_OUTQUE) { - i = F_ACOUT; - fp = (struct frentry *)fiop->f_acctout[set]; - } else if (opts & OPT_INQUE) { - i = F_ACIN; - fp = (struct frentry *)fiop->f_acctin[set]; - } else { - FPRINTF(stderr, "No -i or -o given with -a\n"); - return; - } - } else { -#ifdef USE_INET6 - if ((use_inet6) && (opts & OPT_OUTQUE)) { - i = F_OUT; - fp = (struct frentry *)fiop->f_fout6[set]; - } else if ((use_inet6) && (opts & OPT_INQUE)) { - i = F_IN; - fp = (struct frentry *)fiop->f_fin6[set]; - } else -#endif - 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) - FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); - - if (opts & OPT_VERBOSE) - PRINTF("fp %p set %d\n", fp, set); - if (!fp) { - FPRINTF(stderr, "empty list for %s%s\n", - (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); - return; - } - printlist(fp); -} - - -/* - * Display ipfilter stateful filtering information - */ -static void showipstates(ipsp) -ips_stat_t *ipsp; -{ - ipstate_t *istab[IPSTATE_SIZE]; - - /* - * If a list of states hasn't been asked for, only print out stats - */ - if (!(opts & OPT_SHOWLIST)) { - 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\t%lu bkts in use\n", - ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse); - PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n", - ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin); - return; - } - - if (kmemcpy((char *)istab, (u_long)ipsp->iss_table, sizeof(istab))) - return; - - /* - * Print out all the state information currently held in the kernel. - */ - while (ipsp->iss_list != NULL) { - ipsp->iss_list = printstate(ipsp->iss_list, opts); - } -} - - -#if SOLARIS -/* - * Displays the list of interfaces of which IPFilter has taken control in - * Solaris. - */ -void showqiflist(kern) -char *kern; -{ - struct nlist qifnlist[2] = { - { "qif_head" }, - { NULL } - }; - qif_t qif, *qf; - ill_t ill; - - if (kern == NULL) - kern = "/dev/ksyms"; - - if (nlist(kern, qifnlist) == -1) { - fprintf(stderr, "nlist error\n"); - return; - } - - printf("List of interfaces bound by IPFilter:\n"); - if (kmemcpy((char *)&qf, (u_long)qifnlist[0].n_value, sizeof(qf))) - return; - while (qf) { - if (kmemcpy((char *)&qif, (u_long)qf, sizeof(qif))) - break; - if (kmemcpy((char *)&ill, (u_long)qif.qf_ill, sizeof(ill))) - ill.ill_ppa = -1; - printf("Name: %-8s Header Length: %2d SAP: %s (%04x) PPA %d", - qif.qf_name, qif.qf_hl, -#ifdef IP6_DL_SAP - (qif.qf_sap == IP6_DL_SAP) ? "IPv6" : "IPv4" -#else - "IPv4" -#endif - , qif.qf_sap, ill.ill_ppa); - printf(" %ld %ld", qif.qf_incnt, qif.qf_outcnt); - qf = qif.qf_next; - putchar('\n'); - } -} -#endif - - -#ifdef STATETOP -static void topipstates(saddr, daddr, sport, dport, protocol, - refreshtime, topclosed) -struct in_addr saddr; -struct in_addr daddr; -int sport; -int dport; -int protocol; -int refreshtime; -int topclosed; -{ - char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; - int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; - int i, j, sfd, winx, tsentry, maxx, maxy, redraw = 0; - ipstate_t *istab[IPSTATE_SIZE], ips; - ips_stat_t ipsst, *ipsstp = &ipsst; - statetop_t *tstable = NULL, *tp; - char hostnm[HOSTNMLEN]; - struct protoent *proto; -#ifdef USE_POLL - struct pollfd set[1]; -#else - struct timeval selecttimeout; - fd_set readfd; -#endif - int c = 0; - time_t t; - - /* open state device */ - if ((sfd = open(IPL_STATE, O_RDONLY)) == -1) { - perror("open"); - exit(-1); - } - - /* init ncurses stuff */ - initscr(); - cbreak(); - noecho(); - - /* init hostname */ - gethostname(hostnm, sizeof(hostnm) - 1); - hostnm[sizeof(hostnm) - 1] = '\0'; - - /* repeat until user aborts */ - while ( 1 ) { - - /* get state table */ - bzero((char *)&ipsst, sizeof(&ipsst)); - if ((ioctl(sfd, SIOCGETFS, &ipsstp) == -1)) { - perror("ioctl(SIOCGETFS)"); - exit(-1); - } - if (kmemcpy((char *)istab, (u_long)ipsstp->iss_table, - sizeof(ips))) - return; - - /* clear the history */ - tsentry = -1; - - /* read the state table and store in tstable */ - while (ipsstp->iss_list) { - if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, - sizeof(ips))) - break; - ipsstp->iss_list = ips.is_next; - - if (((saddr.s_addr == INADDR_ANY) || - (saddr.s_addr == ips.is_saddr)) && - ((daddr.s_addr == INADDR_ANY) || - (daddr.s_addr == ips.is_daddr)) && - ((protocol < 0) || (protocol == ips.is_p)) && - (((ips.is_p != IPPROTO_TCP) && - (ips.is_p != IPPROTO_UDP)) || - (((sport < 0) || - (htons(sport) == ips.is_sport)) && - ((dport < 0) || - (htons(dport) == ips.is_dport)))) && - (topclosed || (ips.is_p != IPPROTO_TCP) || - (ips.is_state[0] < TCPS_LAST_ACK) || - (ips.is_state[1] < TCPS_LAST_ACK))) { - /* - * if necessary make room for this state - * entry - */ - tsentry++; - if (!maxtsentries || - (tsentry == maxtsentries)) { - - maxtsentries += STGROWSIZE; - tstable = realloc(tstable, maxtsentries * sizeof(statetop_t)); - if (!tstable) { - perror("malloc"); - exit(-1); - } - } - - /* fill structure */ - tp = tstable + tsentry; - tp->st_src = ips.is_src; - tp->st_dst = ips.is_dst; - tp->st_p = ips.is_p; - tp->st_state[0] = ips.is_state[0]; - tp->st_state[1] = ips.is_state[1]; - tp->st_pkts = ips.is_pkts; - tp->st_bytes = ips.is_bytes; - tp->st_age = ips.is_age; - if ((ips.is_p == IPPROTO_TCP) || - (ips.is_p == IPPROTO_UDP)) { - tp->st_sport = ips.is_sport; - tp->st_dport = ips.is_dport; - } - - } - } - - - /* sort the array */ - if (tsentry != -1) - switch (sorting) - { - case STSORT_PR: - qsort(tstable, tsentry + 1, - sizeof(statetop_t), sort_p); - break; - case STSORT_PKTS: - qsort(tstable, tsentry + 1, - sizeof(statetop_t), sort_pkts); - break; - case STSORT_BYTES: - qsort(tstable, tsentry + 1, - sizeof(statetop_t), sort_bytes); - break; - case STSORT_TTL: - qsort(tstable, tsentry + 1, - sizeof(statetop_t), sort_ttl); - break; - case STSORT_SRCIP: - qsort(tstable, tsentry + 1, - sizeof(statetop_t), sort_srcip); - break; - case STSORT_DSTIP: - qsort(tstable, tsentry + 1, - sizeof(statetop_t), sort_dstip); - break; - default: - break; - } - - /* print title */ - erase(); - getmaxyx(stdscr, maxy, maxx); - attron(A_BOLD); - winx = 0; - move(winx,0); - sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION); - for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) - printw(" "); - printw("%s", str1); - attroff(A_BOLD); - - /* just for fun add a clock */ - move(winx, maxx - 8); - t = time(NULL); - strftime(str1, 80, "%T", localtime(&t)); - printw("%s\n", str1); - - /* - * print the display filters, this is placed in the loop, - * because someday I might add code for changing these - * while the programming is running :-) - */ - if (sport >= 0) - sprintf(str1, "%s,%d", inet_ntoa(saddr), sport); - else - sprintf(str1, "%s", inet_ntoa(saddr)); - - if (dport >= 0) - sprintf(str2, "%s,%d", inet_ntoa(daddr), dport); - else - sprintf(str2, "%s", inet_ntoa(daddr)); - - if (protocol < 0) - strcpy(str3, "any"); - else if ((proto = getprotobynumber(protocol)) != NULL) - sprintf(str3, "%s", proto->p_name); - else - sprintf(str3, "%d", protocol); - - switch (sorting) - { - case STSORT_PR: - sprintf(str4, "proto"); - break; - case STSORT_PKTS: - sprintf(str4, "# pkts"); - break; - case STSORT_BYTES: - sprintf(str4, "# bytes"); - break; - case STSORT_TTL: - sprintf(str4, "ttl"); - break; - case STSORT_SRCIP: - sprintf(str4, "srcip"); - break; - case STSORT_DSTIP: - sprintf(str4, "dstip"); - break; - default: - sprintf(str4, "unknown"); - break; - } - - if (reverse) - strcat(str4, " (reverse)"); - - winx += 2; - move(winx,0); - printw("Src = %s Dest = %s Proto = %s Sorted by = %s\n\n", - str1, str2, str3, str4); - - /* print column description */ - winx += 2; - move(winx,0); - attron(A_BOLD); - printw("%-21s %-21s %3s %4s %7s %9s %9s\n", "Source IP", - "Destination IP", "ST", "PR", "#pkts", "#bytes", "ttl"); - attroff(A_BOLD); - - /* print all the entries */ - tp = tstable; - if (reverse) - tp += tsentry; - - if (tsentry > maxy - 6) - tsentry = maxy - 6; - for (i = 0; i <= tsentry; i++) { - /* print src/dest and port */ - if ((tp->st_p == IPPROTO_TCP) || - (tp->st_p == IPPROTO_UDP)) { - sprintf(str1, "%s,%hu", - inet_ntoa(tp->st_src.in4), - ntohs(tp->st_sport)); - sprintf(str2, "%s,%hu", - inet_ntoa(tp->st_dst.in4), - ntohs(tp->st_dport)); - } else { - sprintf(str1, "%s", inet_ntoa(tp->st_src.in4)); - sprintf(str2, "%s", inet_ntoa(tp->st_dst.in4)); - } - winx++; - move(winx, 0); - printw("%-21s %-21s", str1, str2); - - /* print state */ - sprintf(str1, "%X/%X", tp->st_state[0], - tp->st_state[1]); - printw(" %3s", str1); - - /* print proto */ - proto = getprotobynumber(tp->st_p); - if (proto) { - strncpy(str1, proto->p_name, 4); - str1[4] = '\0'; - } else { - sprintf(str1, "%d", tp->st_p); - } - printw(" %4s", str1); - /* print #pkt/#bytes */ -#ifdef USE_QUAD_T - printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, - (unsigned long long) tp->st_bytes); -#else - printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); -#endif - printw(" %9s", ttl_to_string(tp->st_age)); - - if (reverse) - tp--; - else - tp++; - } - - /* screen data structure is filled, now update the screen */ - if (redraw) - clearok(stdscr,1); - - refresh(); - if (redraw) { - clearok(stdscr,0); - redraw = 0; - } - - /* wait for key press or a 1 second time out period */ -#ifdef USE_POLL - set[0].fd = 0; - set[0].events = POLLIN; - poll(set, 1, refreshtime * 1000); - - if (set[0].revents & POLLIN) { -#else - selecttimeout.tv_sec = refreshtime; - selecttimeout.tv_usec = 0; - FD_ZERO(&readfd); - FD_SET(0, &readfd); - select(1, &readfd, NULL, NULL, &selecttimeout); - - /* if key pressed, read all waiting keys */ - if (FD_ISSET(0, &readfd)) { -#endif - c = wgetch(stdscr); - if (c == ERR) - continue; - - if (isalpha(c) && isupper(c)) - c = tolower(c); - if (c == 'l') { - redraw = 1; - } else if (c == 'q') { - break; /* exits while() loop */ - } else if (c == 'r') { - reverse = !reverse; - } else if (c == 's') { - sorting++; - if (sorting > STSORT_MAX) - sorting = 0; - } - } - } /* while */ - - close(sfd); - - printw("\n"); - nocbreak(); - endwin(); -} -#endif - - -/* - * Show fragment cache information that's held in the kernel. - */ -static void showfrstates(ifsp) -ipfrstat_t *ifsp; -{ - struct ipfr *ipfrtab[IPFT_SIZE], ifr; - frentry_t fr; - int i; - - /* - * print out the numeric statistics - */ - 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; - - /* - * Print out the contents (if any) of the fragment cache table. - */ - for (i = 0; i < IPFT_SIZE; i++) - while (ipfrtab[i]) { - if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], - sizeof(ifr)) == -1) - break; - PRINTF("%s -> ", hostname(4, &ifr.ipfr_src)); - if (kmemcpy((char *)&fr, (u_long)ifr.ipfr_rule, - sizeof(fr)) == -1) - break; - PRINTF("%s %d %d %d %#02x = %#x\n", - hostname(4, &ifr.ipfr_dst), ifr.ipfr_id, - ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_tos, - fr.fr_flags); - ipfrtab[i] = ifr.ipfr_next; - } - if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab))) - return; - for (i = 0; i < IPFT_SIZE; i++) - while (ipfrtab[i]) { - if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], - sizeof(ifr)) == -1) - break; - PRINTF("NAT: %s -> ", hostname(4, &ifr.ipfr_src)); - if (kmemcpy((char *)&fr, (u_long)ifr.ipfr_rule, - sizeof(fr)) == -1) - break; - PRINTF("%s %d %d %d %#02x = %#x\n", - hostname(4, &ifr.ipfr_dst), ifr.ipfr_id, - ifr.ipfr_ttl, ifr.ipfr_p, ifr.ipfr_tos, - fr.fr_flags); - ipfrtab[i] = ifr.ipfr_next; - } -} - - -/* - * Show stats on how auth within IPFilter has been used - */ -static void showauthstates(asp) -fr_authstat_t *asp; -{ - frauthent_t *frap, fra; - -#ifdef USE_QUAD_T - printf("Authorisation hits: %qu\tmisses %qu\n", - (unsigned long long) asp->fas_hits, - (unsigned long long) asp->fas_miss); -#else - printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits, - asp->fas_miss); -#endif - printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n", - asp->fas_nospace, asp->fas_added, asp->fas_sendfail, - asp->fas_sendok); - printf("queok %ld\nquefail %ld\nexpire %ld\n", - asp->fas_queok, asp->fas_quefail, asp->fas_expire); - - frap = asp->fas_faelist; - while (frap) { - if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1) - break; - - printf("age %ld\t", fra.fae_age); - printfr(&fra.fae_fr); - frap = fra.fae_next; - } -} - - -/* - * Display groups used for each of filter rules, accounting rules and - * authentication, separately. - */ -static void showgroups(fiop) -struct friostat *fiop; -{ - static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; - frgroup_t *fp, grp; - int on, off, i; - - on = fiop->f_active; - off = 1 - on; - - for (i = 0; i < 3; i++) { - printf("%s groups (active):\n", gnames[i]); - for (fp = fiop->f_groups[i][on]; fp; fp = grp.fg_next) - if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) - break; - else - printf("%hu\n", grp.fg_num); - printf("%s groups (inactive):\n", gnames[i]); - for (fp = fiop->f_groups[i][off]; fp; fp = grp.fg_next) - if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) - break; - else - printf("%hu\n", grp.fg_num); - } -} - -static void parse_ipportstr(argument, ip, port) -const char *argument; -struct in_addr *ip; -int *port; -{ - - char *s, *comma; - - /* make working copy of argument, Theoretically you must be able - * to write to optarg, but that seems very ugly to me.... - */ - if ((s = malloc(strlen(argument) + 1)) == NULL) - perror("malloc"); - strcpy(s, argument); - - /* get port */ - if ((comma = strchr(s, ',')) != NULL) { - if (!strcasecmp(s, "any")) { - *port = -1; - } else if (!sscanf(comma + 1, "%d", port) || - (*port < 0) || (*port > 65535)) { - fprintf(stderr, "Invalid port specfication in %s\n", - argument); - exit(-2); - } - *comma = '\0'; - } - - - /* get ip address */ - if (!strcasecmp(s, "any")) { - ip->s_addr = INADDR_ANY; - } else if (!inet_aton(s, ip)) { - fprintf(stderr, "Invalid IP address: %s\n", s); - exit(-2); - } - - /* free allocated memory */ - free(s); -} - - -#ifdef STATETOP -static char ttlbuf[STSTRSIZE]; - -static char *ttl_to_string(ttl) -long int ttl; -{ - - int hours, minutes, seconds; - - /* ttl is in half seconds */ - ttl /= 2; - - hours = ttl / 3600; - ttl = ttl % 3600; - minutes = ttl / 60; - seconds = ttl % 60; - - if (hours > 0 ) - sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds); - else - sprintf(ttlbuf, "%2d:%02d", minutes, seconds); - return ttlbuf; -} - - -static int sort_pkts(a, b) -const void *a; -const void *b; -{ - - register const statetop_t *ap = a; - register const statetop_t *bp = b; - - if (ap->st_pkts == bp->st_pkts) - return 0; - else if (ap->st_pkts < bp->st_pkts) - return 1; - return -1; -} - - -static int sort_bytes(a, b) -const void *a; -const void *b; -{ - register const statetop_t *ap = a; - register const statetop_t *bp = b; - - if (ap->st_bytes == bp->st_bytes) - return 0; - else if (ap->st_bytes < bp->st_bytes) - return 1; - return -1; -} - - -static int sort_p(a, b) -const void *a; -const void *b; -{ - register const statetop_t *ap = a; - register const statetop_t *bp = b; - - if (ap->st_p == bp->st_p) - return 0; - else if (ap->st_p < bp->st_p) - return 1; - return -1; -} - - -static int sort_ttl(a, b) -const void *a; -const void *b; -{ - register const statetop_t *ap = a; - register const statetop_t *bp = b; - - if (ap->st_age == bp->st_age) - return 0; - else if (ap->st_age < bp->st_age) - return 1; - return -1; -} - -static int sort_srcip(a, b) -const void *a; -const void *b; -{ - register const statetop_t *ap = a; - register const statetop_t *bp = b; - - if (ntohl(ap->st_src.in4.s_addr) == ntohl(bp->st_src.in4.s_addr)) - return 0; - else if (ntohl(ap->st_src.in4.s_addr) > ntohl(bp->st_src.in4.s_addr)) - return 1; - return -1; -} - -static int sort_dstip(a, b) -const void *a; -const void *b; -{ - register const statetop_t *ap = a; - register const statetop_t *bp = b; - - if (ntohl(ap->st_dst.in4.s_addr) == ntohl(bp->st_dst.in4.s_addr)) - return 0; - else if (ntohl(ap->st_dst.in4.s_addr) > ntohl(bp->st_dst.in4.s_addr)) - return 1; - return -1; -} -#endif diff --git a/dist/ipf/ipf.c b/dist/ipf/ipf.c deleted file mode 100644 index 7f9932962597..000000000000 --- a/dist/ipf/ipf.c +++ /dev/null @@ -1,633 +0,0 @@ -/* $NetBSD: ipf.c,v 1.13 2002/09/19 08:10:38 martti Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __FreeBSD__ -# ifndef __FreeBSD_cc_version -# include -# else -# if __FreeBSD_cc_version < 430000 -# include -# endif -# endif -#endif -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__GNUC__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include "ip_compat.h" -#include "ip_fil.h" -#include "ip_nat.h" -#include "ip_state.h" -#include "ipf.h" -#include "ipl.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipf.c,v 2.10.2.17 2002/06/27 14:29:17 darrenr Exp"; -#endif - -#if SOLARIS -static void blockunknown __P((void)); -#endif -#if !defined(__SVR4) && defined(__GNUC__) -extern char *index __P((const char *, int)); -#endif - -extern char *optarg; - -void frsync __P((void)); -void zerostats __P((void)); -int main __P((int, char *[])); - -int opts = 0; -int use_inet6 = 0; - -static int fd = -1; - -static void procfile __P((char *, char *)), flushfilter __P((char *)); -static void set_state __P((u_int)), showstats __P((friostat_t *)); -static void packetlogon __P((char *)), swapactive __P((void)); -static int opendevice __P((char *)); -static void closedevice __P((void)); -static char *getline __P((char *, size_t, FILE *, int *)); -static char *ipfname = IPL_NAME; -static void usage __P((void)); -static int showversion __P((void)); -static int get_flags __P((void)); - - -#if SOLARIS -# define OPTS "6AdDEf:F:Il:noPrsUvVyzZ" -#else -# define OPTS "6AdDEf:F:Il:noPrsvVyzZ" -#endif - -static void usage() -{ - fprintf(stderr, "usage: ipf [-%s] %s %s %s\n", OPTS, - "[-l block|pass|nomatch]", "[-F i|o|a|s|S]", "[-f filename]"); - exit(1); -} - - -int main(argc,argv) -int argc; -char *argv[]; -{ - int c; - - while ((c = getopt(argc, argv, OPTS)) != -1) { - switch (c) - { - case '6' : - use_inet6 = 1; - break; - case 'A' : - opts &= ~OPT_INACTIVE; - break; - case 'E' : - set_state((u_int)1); - break; - case 'D' : - set_state((u_int)0); - break; - case 'd' : - opts |= OPT_DEBUG; - break; - case 'f' : - procfile(argv[0], optarg); - break; - case 'F' : - flushfilter(optarg); - break; - case 'I' : - opts |= OPT_INACTIVE; - break; - case 'l' : - packetlogon(optarg); - break; - case 'n' : - opts |= OPT_DONOTHING; - break; - case 'o' : - break; - case 'P' : - ipfname = IPL_AUTH; - break; - case 'r' : - opts |= OPT_REMOVE; - break; - case 's' : - swapactive(); - break; -#if SOLARIS - case 'U' : - blockunknown(); - break; -#endif - case 'v' : - opts += OPT_VERBOSE; - break; - case 'V' : - if (showversion()) - exit(1); - break; - case 'y' : - frsync(); - break; - case 'z' : - opts |= OPT_ZERORULEST; - break; - case 'Z' : - zerostats(); - break; - default : - usage(); - break; - } - } - - if (fd != -1) - (void) close(fd); - - exit(0); - /* NOTREACHED */ -} - - -static int opendevice(ipfdev) -char *ipfdev; -{ - if (opts & OPT_DONOTHING) - return -2; - - if (!ipfdev) - ipfdev = ipfname; - - if (!(opts & OPT_DONOTHING) && fd == -1) - if ((fd = open(ipfdev, O_RDWR)) == -1) - if ((fd = open(ipfdev, O_RDONLY)) == -1) { - perror("open device"); - if (errno == ENODEV) - fprintf(stderr, "IPFilter enabled?\n"); - } - return fd; -} - - -static void closedevice() -{ - close(fd); - fd = -1; -} - - -static int get_flags() -{ - int i; - - if ((opendevice(ipfname) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) { - perror("SIOCGETFF"); - return 0; - } - return i; -} - - -static void set_state(enable) -u_int enable; -{ - if (opendevice(ipfname) != -2) - if (ioctl(fd, SIOCFRENB, &enable) == -1) { - if (errno == EBUSY) - fprintf(stderr, - "IP Filter: already initialized\n"); - else - perror("SIOCFRENB"); - } - return; -} - -static void procfile(name, file) -char *name, *file; -{ - FILE *fp; - char line[513], *s; - struct frentry *fr; - u_int add, del; - int linenum = 0; - - (void) opendevice(ipfname); - - if (opts & OPT_INACTIVE) { - add = SIOCADIFR; - del = SIOCRMIFR; - } else { - add = SIOCADAFR; - del = SIOCRMAFR; - } - if (opts & OPT_DEBUG) - printf("add %x del %x\n", add, del); - - initparse(); - - if (!strcmp(file, "-")) - fp = stdin; - else if (!(fp = fopen(file, "r"))) { - fprintf(stderr, "%s: fopen(%s) failed: %s\n", name, file, - STRERROR(errno)); - exit(1); - } - - while (getline(line, sizeof(line), fp, &linenum)) { - /* - * treat CR as EOL. LF is converted to NUL by getline(). - */ - if ((s = index(line, '\r'))) - *s = '\0'; - /* - * # is comment marker, everything after is a ignored - */ - if ((s = index(line, '#'))) - *s = '\0'; - - if (!*line) - continue; - - if (opts & OPT_VERBOSE) - (void)fprintf(stderr, "[%s]\n", line); - - fr = parse(line, linenum); - (void)fflush(stdout); - - if (fr) { - if (opts & OPT_ZERORULEST) - add = SIOCZRLST; - else if (opts & OPT_INACTIVE) - add = (u_int)fr->fr_hits ? SIOCINIFR : - SIOCADIFR; - else - add = (u_int)fr->fr_hits ? SIOCINAFR : - SIOCADAFR; - if (fr->fr_hits) - fr->fr_hits--; - if (fr && (opts & OPT_VERBOSE)) - printfr(fr); - if (fr && (opts & OPT_OUTQUE)) - fr->fr_flags |= FR_OUTQUE; - - if (opts & OPT_DEBUG) - binprint(fr); - - if ((opts & OPT_ZERORULEST) && - !(opts & OPT_DONOTHING)) { - if (ioctl(fd, add, &fr) == -1) { - fprintf(stderr, "%d:", linenum); - perror("ioctl(SIOCZRLST)"); - } else { -#ifdef USE_QUAD_T - printf("hits %qd bytes %qd ", - (long long)fr->fr_hits, - (long long)fr->fr_bytes); -#else - printf("hits %ld bytes %ld ", - fr->fr_hits, fr->fr_bytes); -#endif - printfr(fr); - } - } else if ((opts & OPT_REMOVE) && - !(opts & OPT_DONOTHING)) { - if (ioctl(fd, del, &fr) == -1) { - fprintf(stderr, "%d:", linenum); - perror("ioctl(delete rule)"); - } - } else if (!(opts & OPT_DONOTHING)) { - if (ioctl(fd, add, &fr) == -1) { - fprintf(stderr, "%d:", linenum); - perror("ioctl(add/insert rule)"); - } - } - } - } - if (ferror(fp) || !feof(fp)) { - fprintf(stderr, "%s: %s: file error or line too long\n", - name, file); - exit(1); - } - (void)fclose(fp); -} - -/* - * Similar to fgets(3) but can handle '\\' and NL is converted to NUL. - * Returns NULL if error occured, EOF encounterd or input line is too long. - */ -static char *getline(str, size, file, linenum) -register char *str; -size_t size; -FILE *file; -int *linenum; -{ - char *p; - int s, len; - - do { - for (p = str, s = size;; p += (len - 1), s -= (len - 1)) { - /* - * if an error occured, EOF was encounterd, or there - * was no room to put NUL, return NULL. - */ - if (fgets(p, s, file) == NULL) - return (NULL); - len = strlen(p); - if (p[len - 1] != '\n') { - p[len] = '\0'; - break; - } - (*linenum)++; - p[len - 1] = '\0'; - if (len < 2 || p[len - 2] != '\\') - break; - else - /* - * Convert '\\' to a space so words don't - * run together - */ - p[len - 2] = ' '; - } - } while (*str == '\0'); - return (str); -} - - -static void packetlogon(opt) -char *opt; -{ - int flag; - - flag = get_flags(); - if (flag != 0) { - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) - printf("log flag is currently %#x\n", flag); - } - - flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); - - if (index(opt, 'p')) { - flag |= FF_LOGPASS; - 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) - printf("set log flag: block\n"); - } - - if (opendevice(ipfname) != -2 && (ioctl(fd, SIOCSETFF, &flag) != 0)) - perror("ioctl(SIOCSETFF)"); - - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { - flag = get_flags(); - printf("log flag is now %#x\n", flag); - } -} - - -static void flushfilter(arg) -char *arg; -{ - int fl = 0, rem; - - if (!arg || !*arg) - return; - if (!strcmp(arg, "s") || !strcmp(arg, "S")) { - if (*arg == 'S') - fl = 0; - else - fl = 1; - rem = fl; - - closedevice(); - if (opendevice(IPL_STATE) != -2 && - ioctl(fd, SIOCIPFFL, &fl) == -1) - perror("ioctl(SIOCIPFFL)"); - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { - printf("remove flags %s (%d)\n", arg, rem); - printf("removed %d filter rules\n", fl); - } - closedevice(); - return; - } - if (strchr(arg, 'i') || strchr(arg, 'I')) - fl = FR_INQUE; - if (strchr(arg, 'o') || strchr(arg, 'O')) - fl = FR_OUTQUE; - if (strchr(arg, 'a') || strchr(arg, 'A')) - fl = FR_OUTQUE|FR_INQUE; - fl |= (opts & FR_INACTIVE); - rem = fl; - - if (opendevice(ipfname) != -2 && ioctl(fd, SIOCIPFFL, &fl) == -1) - perror("ioctl(SIOCIPFFL)"); - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { - printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", - (rem & FR_OUTQUE) ? "O" : "", rem); - printf("removed %d filter rules\n", fl); - } - return; -} - - -static void swapactive() -{ - int in = 2; - - if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) - perror("ioctl(SIOCSWAPA)"); - else - printf("Set %d now inactive\n", in); -} - - -void frsync() -{ - int frsyn = 0; - - if (opendevice(ipfname) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1) - perror("SIOCFRSYN"); - else - printf("filter sync'd\n"); -} - - -void zerostats() -{ - friostat_t fio; - friostat_t *fiop = &fio; - - if (opendevice(ipfname) != -2) { - if (ioctl(fd, SIOCFRZST, &fiop) == -1) { - perror("ioctl(SIOCFRZST)"); - exit(-1); - } - showstats(fiop); - } - -} - - -/* - * read the kernel stats for packets blocked and passed - */ -static void showstats(fp) -friostat_t *fp; -{ -#if SOLARIS - printf("dropped packets:\tin %lu\tout %lu\n", - fp->f_st[0].fr_drop, fp->f_st[1].fr_drop); - printf("non-ip packets:\t\tin %lu\tout %lu\n", - fp->f_st[0].fr_notip, fp->f_st[1].fr_notip); - printf(" bad packets:\t\tin %lu\tout %lu\n", - fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); -#endif - printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", - fp->f_st[0].fr_block, fp->f_st[0].fr_pass, - fp->f_st[0].fr_nom); - printf(" counted %lu\n", fp->f_st[0].fr_acct); - printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", - fp->f_st[1].fr_block, fp->f_st[1].fr_pass, - fp->f_st[1].fr_nom); - printf(" counted %lu\n", fp->f_st[0].fr_acct); - printf(" input packets logged:\tblocked %lu passed %lu\n", - fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl); - printf("output packets logged:\tblocked %lu passed %lu\n", - fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl); - 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); -} - - -#if SOLARIS -static void blockunknown() -{ - u_32_t flag; - - if (opendevice(ipfname) == -1) - return; - - flag = get_flags(); - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) - printf("log flag is currently %#x\n", flag); - - flag ^= FF_BLOCKNONIP; - - if (opendevice(ipfname) != -2 && ioctl(fd, SIOCSETFF, &flag)) - perror("ioctl(SIOCSETFF)"); - - if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { - if (ioctl(fd, SIOCGETFF, &flag)) - perror("ioctl(SIOCGETFF)"); - - printf("log flag is now %#x\n", flag); - } -} -#endif - - -static int showversion() -{ - struct friostat fio; - struct friostat *fiop=&fio; - u_32_t flags; - char *s; - int vfd; - - printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); - - if ((vfd = open(ipfname, O_RDONLY)) == -1) { - perror("open device"); - return 1; - } - - if (ioctl(vfd, SIOCGETFS, &fiop)) { - perror("ioctl(SIOCGETFS)"); - close(vfd); - return 1; - } - close(vfd); - flags = get_flags(); - - printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), - (int)sizeof(fio.f_version), fio.f_version); - printf("Running: %s\n", fio.f_running ? "yes" : "no"); - printf("Log Flags: %#x = ", flags); - s = ""; - if (flags & FF_LOGPASS) { - printf("pass"); - s = ", "; - } - if (flags & FF_LOGBLOCK) { - printf("%sblock", s); - s = ", "; - } - if (flags & FF_LOGNOMATCH) { - printf("%snomatch", s); - s = ", "; - } - if (flags & FF_BLOCKNONIP) { - printf("%snonip", s); - s = ", "; - } - if (!*s) - printf("none set"); - putchar('\n'); - - printf("Default: "); - if (fio.f_defpass & FR_PASS) - s = "pass"; - else if (fio.f_defpass & FR_BLOCK) - s = "block"; - else - s = "nomatch -> block"; - printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); - printf("Active list: %d\n", fio.f_active); - - return 0; -} diff --git a/dist/ipf/ipf.h b/dist/ipf/ipf.h index fc02c8ea961c..cb15db8af62d 100644 --- a/dist/ipf/ipf.h +++ b/dist/ipf/ipf.h @@ -1,74 +1,123 @@ -/* $NetBSD: ipf.h,v 1.4 2002/01/24 08:21:32 martti Exp $ */ +/* $NetBSD: ipf.h,v 1.5 2004/03/28 09:00:53 martti Exp $ */ /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ipf.h 1.12 6/5/96 - * Id: ipf.h,v 2.9.2.6 2002/01/03 08:00:12 darrenr Exp + * Id: ipf.h,v 2.71.2.2 2004/03/19 23:02:50 darrenr Exp */ #ifndef __IPF_H__ #define __IPF_H__ -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#if defined(__osf__) +# define radix_mask ipf_radix_mask +# define radix_node ipf_radix_node +# define radix_node_head ipf_radix_node_head #endif -#define OPT_REMOVE 0x000001 -#define OPT_DEBUG 0x000002 -#define OPT_OUTQUE FR_OUTQUE /* 0x00004 */ -#define OPT_INQUE FR_INQUE /* 0x00008 */ -#define OPT_LOG FR_LOG /* 0x00010 */ -#define OPT_SHOWLIST 0x000020 -#define OPT_VERBOSE 0x000040 -#define OPT_DONOTHING 0x000080 -#define OPT_HITS 0x000100 -#define OPT_BRIEF 0x000200 -#define OPT_ACCNT FR_ACCOUNT /* 0x0400 */ -#define OPT_FRSTATES FR_KEEPFRAG /* 0x0800 */ -#define OPT_IPSTATES FR_KEEPSTATE /* 0x1000 */ -#define OPT_INACTIVE FR_INACTIVE /* 0x2000 */ -#define OPT_SHOWLINENO 0x004000 -#define OPT_PRINTFR 0x008000 -#define OPT_ZERORULEST 0x010000 -#define OPT_SAVEOUT 0x020000 -#define OPT_AUTHSTATS 0x040000 -#define OPT_RAW 0x080000 -#define OPT_NAT 0x100000 -#define OPT_GROUPS 0x200000 -#define OPT_STATETOP 0x400000 -#define OPT_FLUSH 0x800000 -#define OPT_CLEAR 0x1000000 -#define OPT_HEX 0x2000000 -#define OPT_NODO 0x80000000 -#define OPT_STAT OPT_FRSTATES -#define OPT_LIST OPT_SHOWLIST +#include +#include +#include +/* + * This is a workaround for troubles on FreeBSD, HPUX, OpenBSD. + * Needed here because on some systems gets included by things + * like + */ +#ifndef _KERNEL +# define ADD_KERNEL +# define _KERNEL +# define KERNEL +#endif +#ifdef __OpenBSD__ +struct file; +#endif +#include +#ifdef ADD_KERNEL +# undef _KERNEL +# undef KERNEL +#endif +#include +#include +#include +#if __FreeBSD_version >= 300000 +# include +#endif +#include +#include +#include +#include +#ifndef TCP_PAWS_IDLE /* IRIX */ +# include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#if !defined(__SVR4) && !defined(__svr4__) && defined(sun) +# include +#endif +#include +#include + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_auth.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_scan.h" +#include "netinet/ip_htable.h" + +#include "opts.h" #ifndef __P -# ifdef __STDC__ +# ifdef __STDC__ # define __P(x) x # else # define __P(x) () # endif #endif - -struct ipstate; -struct frpcmp; -struct ipnat; -struct nat; - -#ifdef ultrix -extern char *strdup __P((char *)); +#ifndef __STDC__ +# undef const +# define const #endif -extern struct frentry *parse __P((char *, int)); +#ifndef U_32_T +# define U_32_T 1 +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ + defined(__sgi) +typedef u_int32_t u_32_t; +# else +# if defined(__alpha__) || defined(__alpha) || defined(_LP64) +typedef unsigned int u_32_t; +# else +# if SOLARIS2 >= 6 +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; +# endif +# endif +# endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */ +#endif /* U_32_T */ -extern void printfr __P((struct frentry *)); -extern void binprint __P((struct frentry *)), initparse __P((void)); -extern int portnum __P((char *, u_short *, int)); +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +#define MAX_ICMPCODE 16 +#define MAX_ICMPTYPE 19 struct ipopt_names { @@ -79,47 +128,177 @@ struct ipopt_names { }; -extern char *proto; +typedef struct alist_s { + struct alist_s *al_next; + int al_not; + i6addr_t al_i6addr; + i6addr_t al_i6mask; +} alist_t; + +#define al_addr al_i6addr.in4_addr +#define al_mask al_i6mask.in4_addr +#define al_1 al_addr +#define al_2 al_mask + + +typedef struct { + u_short fb_c; + u_char fb_t; + u_char fb_f; + u_32_t fb_k; +} fakebpf_t; + + +#if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ + SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux) +# include +typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...)); +#else +typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *)); +#endif +typedef void (* addfunc_t) __P((int, ioctlfunc_t, void *)); +typedef int (* copyfunc_t) __P((void *, void *, size_t)); + + +/* + * SunOS4 + */ +#if defined(sun) && !defined(__SVR4) && !defined(__svr4__) +extern int ioctl __P((int, int, void *)); +#endif + +extern char thishost[]; extern char flagset[]; extern u_char flags[]; +extern struct ipopt_names ionames[]; +extern struct ipopt_names secclass[]; +extern char *icmpcodes[MAX_ICMPCODE + 1]; +extern char *icmptypes[MAX_ICMPTYPE + 1]; +extern int use_inet6; +extern int lineNum; +extern struct ipopt_names v6ionames[]; -extern u_char tcp_flags __P((char *, u_char *, int)); -extern int countbits __P((u_32_t)); -extern int ratoi __P((char *, int *, int, int)); -extern int ratoui __P((char *, u_int *, u_int, u_int)); -extern int hostmask __P((char ***, u_32_t *, u_32_t *, u_short *, int *, - u_short *, int)); -extern int ports __P((char ***, u_short *, int *, u_short *, int)); -extern char *portname __P((int, int)); -extern u_32_t buildopts __P((char *, char *, int)); -extern int genmask __P((char *, u_32_t *)); -extern int hostnum __P((u_32_t *, char *, int)); -extern u_32_t optname __P((char ***, u_short *, int)); -extern void printpacket __P((ip_t *)); -extern void printpacket6 __P((ip_t *)); -extern void printportcmp __P((int, struct frpcmp *)); -extern void printhostmask __P((int, u_32_t *, u_32_t *)); -extern void printbuf __P((char *, int, int)); -extern char *hostname __P((int, void *)); -extern struct ipstate *printstate __P((struct ipstate *, int)); -extern void printnat __P((struct ipnat *, int)); -extern void printactivenat __P((struct nat *, int)); + +extern int addicmp __P((char ***, struct frentry *, int)); +extern int addipopt __P((char *, struct ipopt_names *, int, char *)); +extern int addkeep __P((char ***, struct frentry *, int)); +extern int bcopywrap __P((void *, void *, size_t)); +extern void binprint __P((void *, size_t)); +extern void initparse __P((void)); +extern u_32_t buildopts __P((char *, char *, int)); +extern int checkrev __P((char *)); +extern int count6bits __P((u_32_t *)); +extern int count4bits __P((u_32_t)); +extern int extras __P((char ***, struct frentry *, int)); +extern char *fac_toname __P((int)); +extern int fac_findname __P((char *)); +extern void fill6bits __P((int, u_int *)); +extern int gethost __P((char *, u_32_t *)); +extern int getport __P((char *)); +extern int getportproto __P((char *, int)); +extern int getproto __P((char *)); +extern char *getline __P((char *, size_t, FILE *, int *)); +extern int genmask __P((char *, u_32_t *)); +extern char *getnattype __P((struct ipnat *)); +extern char *getsumd __P((u_32_t)); +extern u_32_t getoptbyname __P((char *)); +extern u_32_t getoptbyvalue __P((int)); +extern u_32_t getv6optbyname __P((char *)); +extern u_32_t getv6optbyvalue __P((int)); +extern void hexdump __P((FILE *, void *, int, int)); +extern int hostmask __P((char ***, char *, char *, u_32_t *, u_32_t *, int)); +extern int hostnum __P((u_32_t *, char *, int, char *)); +extern int icmpcode __P((char *)); +extern int icmpidnum __P((char *, u_short *, int)); +extern void initparse __P((void)); +extern void ipf_dotuning __P((int, char *, ioctlfunc_t)); +extern void ipf_addrule __P((int, ioctlfunc_t, void *)); +extern int ipf_parsefile __P((int, addfunc_t, ioctlfunc_t *, char *)); +extern int ipf_parsesome __P((int, addfunc_t, ioctlfunc_t *, FILE *)); +extern int ipmon_parsefile __P((char *)); +extern int ipmon_parsesome __P((FILE *)); +extern void ipnat_addrule __P((int, ioctlfunc_t, void *)); +extern int ipnat_parsefile __P((int, addfunc_t, ioctlfunc_t, char *)); +extern int ipnat_parsesome __P((int, addfunc_t, ioctlfunc_t, FILE *)); +extern int ippool_parsefile __P((int, char *, ioctlfunc_t)); +extern int ippool_parsesome __P((int, FILE *, ioctlfunc_t)); +extern int kmemcpywrap __P((void *, void *, size_t)); +extern char *kvatoname __P((ipfunc_t, ioctlfunc_t)); +extern int load_hash __P((struct iphtable_s *, struct iphtent_s *, + ioctlfunc_t)); +extern int load_hashnode __P((int, char *, struct iphtent_s *, ioctlfunc_t)); +extern int load_pool __P((struct ip_pool_s *list, ioctlfunc_t)); +extern int load_poolnode __P((int, char *, ip_pool_node_t *, ioctlfunc_t)); +extern int loglevel __P((char **, u_int *, int)); +extern alist_t *make_range __P((int, struct in_addr, struct in_addr)); +extern ipfunc_t nametokva __P((char *, ioctlfunc_t)); +extern ipnat_t *natparse __P((char *, int)); +extern void natparsefile __P((int, char *, int)); +extern void nat_setgroupmap __P((struct ipnat *)); +extern int ntomask __P((int, int, u_32_t *)); +extern u_32_t optname __P((char ***, u_short *, int)); +extern struct frentry *parse __P((char *, int)); +extern char *portname __P((int, int)); +extern int portnum __P((char *, char *, u_short *, int)); +extern int ports __P((char ***, char *, u_short *, int *, u_short *, int)); +extern int pri_findname __P((char *)); +extern char *pri_toname __P((int)); +extern void print_toif __P((char *, struct frdest *)); +extern void printaps __P((ap_session_t *, int)); +extern void printbuf __P((char *, int, int)); +extern void printfr __P((struct frentry *, ioctlfunc_t)); +extern void printtunable __P((ipftune_t *)); +extern struct iphtable_s *printhash __P((struct iphtable_s *, + copyfunc_t, int)); +extern struct iphtent_s *printhashnode __P((struct iphtable_s *, + struct iphtent_s *, + copyfunc_t, int)); +extern void printhostmask __P((int, u_32_t *, u_32_t *)); +extern void printip __P((u_32_t *)); +extern void printlog __P((struct frentry *)); +extern void printlookup __P((i6addr_t *addr, i6addr_t *mask)); +extern void printmask __P((u_32_t *)); +extern void printpacket __P((struct ip *)); +extern void printpacket6 __P((struct ip *)); +extern struct ip_pool_s *printpool __P((struct ip_pool_s *, copyfunc_t, int)); +extern struct ip_pool_node *printpoolnode __P((struct ip_pool_node *, int)); +extern void printportcmp __P((int, struct frpcmp *)); +extern void optprint __P((u_short *, u_long, u_long)); +#ifdef USE_INET6 +extern void optprintv6 __P((u_short *, u_long, u_long)); +#endif +extern int ratoi __P((char *, int *, int, int)); +extern int ratoui __P((char *, u_int *, u_int, u_int)); +extern int remove_hash __P((struct iphtable_s *, ioctlfunc_t)); +extern int remove_hashnode __P((int, char *, struct iphtent_s *, ioctlfunc_t)); +extern int remove_pool __P((ip_pool_t *, ioctlfunc_t)); +extern int remove_poolnode __P((int, char *, ip_pool_node_t *, ioctlfunc_t)); +extern u_char tcp_flags __P((char *, u_char *, int)); +extern u_char tcpflags __P((char *)); +extern int to_interface __P((struct frdest *, char *, int)); +extern void printc __P((struct frentry *)); +extern void printC __P((int)); +extern void emit __P((int, int, void *, struct frentry *)); +extern u_char secbit __P((int)); +extern u_char seclevel __P((char *)); +extern void printfraginfo __P((char *, struct ipfr *)); +extern void printifname __P((char *, char *, void *)); +extern char *hostname __P((int, void *)); +extern struct ipstate *printstate __P((struct ipstate *, int, u_long)); +extern void printsbuf __P((char *)); +extern void printnat __P((struct ipnat *, int)); +extern void printactivenat __P((struct nat *, int)); +extern void printhostmap __P((struct hostmap *, u_int)); +extern void printpacket __P((struct ip *)); + +extern void set_variable __P((char *, char *)); +extern char *get_variable __P((char *, char **, int)); +extern void resetlexer __P((void)); #if SOLARIS -extern int inet_aton __P((const char *, struct in_addr *)); -extern int gethostname __P((char *, int )); -extern void sync __P((void)); -#endif - -#if defined(sun) && !SOLARIS -# define STRERROR(x) sys_errlist[x] -extern char *sys_errlist[]; -#else -# define STRERROR(x) strerror(x) -#endif - -#ifndef MIN -#define MIN(a,b) ((a) > (b) ? (b) : (a)) +extern int gethostname __P((char *, int )); +extern void sync __P((void)); #endif #endif /* __IPF_H__ */ diff --git a/dist/ipf/ipfs.c b/dist/ipf/ipfs.c deleted file mode 100644 index 51cf3343d903..000000000000 --- a/dist/ipf/ipfs.c +++ /dev/null @@ -1,806 +0,0 @@ -/* $NetBSD: ipfs.c,v 1.10 2002/09/19 08:10:39 martti Exp $ */ - -/* - * Copyright (C) 1999-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __FreeBSD__ -# ifndef __FreeBSD_cc_version -# include -# else -# if __FreeBSD_cc_version < 430000 -# include -# endif -# endif -#endif -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__GNUC__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include "ip_compat.h" -#include "ip_fil.h" -#include "ip_nat.h" -#include "ip_state.h" -#include "ipf.h" - -#if !defined(lint) -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipfs.c,v 2.6.2.11 2002/06/04 14:44:05 darrenr Exp"; -#endif - -#ifndef IPF_SAVEDIR -# define IPF_SAVEDIR "/var/db/ipf" -#endif -#ifndef IPF_NATFILE -# define IPF_NATFILE "ipnat.ipf" -#endif -#ifndef IPF_STATEFILE -# define IPF_STATEFILE "ipstate.ipf" -#endif - -#if !defined(__SVR4) && defined(__GNUC__) -extern char *index __P((const char *, int)); -#endif - -extern char *optarg; - -int main __P((int, char *[])); -void usage __P((void)); -int changestateif __P((char *, char *)); -int changenatif __P((char *, char *)); -int readstate __P((int, char *)); -int readnat __P((int, char *)); -int writestate __P((int, char *)); -int opendevice __P((char *)); -void closedevice __P((int)); -int setlock __P((int, int)); -int writeall __P((char *)); -int readall __P((char *)); -int writenat __P((int, char *)); - -int opts = 0; - - -void usage() -{ - fprintf(stderr, "usage: ipfs [-nv] -l\n"); - fprintf(stderr, "usage: ipfs [-nv] -u\n"); - fprintf(stderr, "usage: ipfs [-nv] [-d ] -R\n"); - fprintf(stderr, "usage: ipfs [-nv] [-d ] -W\n"); - fprintf(stderr, "usage: ipfs [-nNSv] [-f ] -r\n"); - fprintf(stderr, "usage: ipfs [-nNSv] [-f ] -w\n"); - fprintf(stderr, "usage: ipfs [-nNSv] -f -i ,\n"); - exit(1); -} - - -/* - * Change interface names in state information saved out to disk. - */ -int changestateif(ifs, fname) -char *ifs, *fname; -{ - int fd, olen, nlen, rw; - ipstate_save_t ips; - off_t pos; - char *s; - - s = strchr(ifs, ','); - if (!s) - usage(); - *s++ = '\0'; - nlen = strlen(s); - olen = strlen(ifs); - if (nlen >= sizeof(ips.ips_is.is_ifname) || - olen >= sizeof(ips.ips_is.is_ifname)) - usage(); - - fd = open(fname, O_RDWR); - if (fd == -1) { - perror("open"); - exit(1); - } - - for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { - rw = 0; - if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { - strcpy(ips.ips_is.is_ifname[0], s); - rw = 1; - } - if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { - strcpy(ips.ips_is.is_ifname[1], s); - rw = 1; - } - if (rw == 1) { - if (lseek(fd, pos, SEEK_SET) != pos) { - perror("lseek"); - exit(1); - } - if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { - perror("write"); - exit(1); - } - } - pos = lseek(fd, 0, SEEK_CUR); - } - close(fd); - - return 0; -} - - -/* - * Change interface names in NAT information saved out to disk. - */ -int changenatif(ifs, fname) -char *ifs, *fname; -{ - int fd, olen, nlen, rw; - nat_save_t ipn; - nat_t *nat; - off_t pos; - char *s; - - s = strchr(ifs, ','); - if (!s) - usage(); - *s++ = '\0'; - nlen = strlen(s); - olen = strlen(ifs); - nat = &ipn.ipn_nat; - if (nlen >= sizeof(nat->nat_ifname) || olen >= sizeof(nat->nat_ifname)) - usage(); - - fd = open(fname, O_RDWR); - if (fd == -1) { - perror("open"); - exit(1); - } - - for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { - rw = 0; - if (!strncmp(nat->nat_ifname, ifs, olen + 1)) { - strcpy(nat->nat_ifname, s); - rw = 1; - } - if (rw == 1) { - if (lseek(fd, pos, SEEK_SET) != pos) { - perror("lseek"); - exit(1); - } - if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { - perror("write"); - exit(1); - } - } - pos = lseek(fd, 0, SEEK_CUR); - } - close(fd); - - return 0; -} - - -int main(argc,argv) -int argc; -char *argv[]; -{ - int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; - char *dirname = NULL, *filename = NULL, *ifs = NULL; - - while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1) - switch (c) - { - case 'd' : - if ((set == 0) && !dirname && !filename) - dirname = optarg; - else - usage(); - break; - case 'f' : - if ((set == 0) && !dirname && !filename) - filename = optarg; - else - usage(); - break; - case 'i' : - ifs = optarg; - set = 1; - break; - case 'l' : - if (filename || dirname || set) - usage(); - lock = 1; - set = 1; - break; - case 'n' : - opts |= OPT_DONOTHING; - break; - case 'N' : - if ((ns >= 0) || dirname || (rw != -1) || set) - usage(); - ns = 0; - set = 1; - break; - case 'r' : - if ((ns >= 0) || dirname || (rw != -1)) - usage(); - rw = 0; - set = 1; - break; - case 'R' : - rw = 2; - set = 1; - break; - case 'S' : - if ((ns >= 0) || dirname || (rw != -1) || set) - usage(); - ns = 1; - set = 1; - break; - case 'u' : - if (filename || dirname || set) - usage(); - lock = 0; - set = 1; - break; - case 'v' : - opts |= OPT_VERBOSE; - break; - case 'w' : - if (dirname || (rw != -1) || (ns == -1)) - usage(); - rw = 1; - set = 1; - break; - case 'W' : - rw = 3; - set = 1; - break; - case '?' : - default : - usage(); - } - - if (ifs) { - if (!filename || ns < 0) - usage(); - if (ns == 0) - return changenatif(ifs, filename); - else - return changestateif(ifs, filename); - } - - if ((ns >= 0) || (lock >= 0)) { - if (lock >= 0) - devfd = opendevice(NULL); - else if (ns >= 0) { - if (ns == 1) - devfd = opendevice(IPL_STATE); - else if (ns == 0) - devfd = opendevice(IPL_NAT); - } - if (devfd == -1) - exit(1); - } - - if (lock >= 0) - err = setlock(devfd, lock); - else if (rw >= 0) { - if (rw & 1) { /* WRITE */ - if (rw & 2) - err = writeall(dirname); - else { - if (ns == 0) - err = writenat(devfd, filename); - else if (ns == 1) - err = writestate(devfd, filename); - } - } else { - if (rw & 2) - err = readall(dirname); - else { - if (ns == 0) - err = readnat(devfd, filename); - else if (ns == 1) - err = readstate(devfd, filename); - } - } - } - return err; -} - - -int opendevice(ipfdev) -char *ipfdev; -{ - int fd = -1; - - if (opts & OPT_DONOTHING) - return -2; - - if (!ipfdev) - ipfdev = IPL_NAME; - - if ((fd = open(ipfdev, O_RDWR)) == -1) - if ((fd = open(ipfdev, O_RDONLY)) == -1) - perror("open device"); - return fd; -} - - -void closedevice(fd) -int fd; -{ - close(fd); -} - - -int setlock(fd, lock) -int fd, lock; -{ - if (opts & OPT_VERBOSE) - printf("Turn lock %s\n", lock ? "on" : "off"); - if (!(opts & OPT_DONOTHING)) { - if (ioctl(fd, SIOCSTLCK, &lock) == -1) { - perror("SIOCSTLCK"); - return 1; - } - if (opts & OPT_VERBOSE) - printf("Lock now %s\n", lock ? "on" : "off"); - } - return 0; -} - - -int writestate(fd, file) -int fd; -char *file; -{ - ipstate_save_t ips, *ipsp; - int wfd = -1; - - if (!file) - file = IPF_STATEFILE; - - wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); - if (wfd == -1) { - fprintf(stderr, "%s ", file); - perror("state:open"); - return 1; - } - - ipsp = &ips; - bzero((char *)ipsp, sizeof(ips)); - - do { - if (opts & OPT_VERBOSE) - printf("Getting state from addr %p\n", ips.ips_next); - if (ioctl(fd, SIOCSTGET, &ipsp)) { - if (errno == ENOENT) - break; - perror("state:SIOCSTGET"); - close(wfd); - return 1; - } - if (opts & OPT_VERBOSE) - printf("Got state next %p\n", ips.ips_next); - if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { - perror("state:write"); - close(wfd); - return 1; - } - } while (ips.ips_next != NULL); - close(wfd); - - return 0; -} - - -int readstate(fd, file) -int fd; -char *file; -{ - ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; - int sfd = -1, i; - - if (!file) - file = IPF_STATEFILE; - - sfd = open(file, O_RDONLY, 0600); - if (sfd == -1) { - fprintf(stderr, "%s ", file); - perror("open"); - return 1; - } - - bzero((char *)&ips, sizeof(ips)); - - /* - * 1. Read all state information in. - */ - do { - i = read(sfd, &ips, sizeof(ips)); - if (i == -1) { - perror("read"); - close(sfd); - return 1; - } - if (i == 0) - break; - if (i != sizeof(ips)) { - fprintf(stderr, "incomplete read: %d != %d\n", i, - (int)sizeof(ips)); - close(sfd); - return 1; - } - is = (ipstate_save_t *)malloc(sizeof(*is)); - if(!is) { - fprintf(stderr, "malloc failed\n"); - return 1; - } - - bcopy((char *)&ips, (char *)is, sizeof(ips)); - - /* - * Check to see if this is the first state entry that will - * reference a particular rule and if so, flag it as such - * else just adjust the rule pointer to become a pointer to - * the other. We do this so we have a means later for tracking - * who is referencing us when we get back the real pointer - * in is_rule after doing the ioctl. - */ - for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) - if (is1->ips_rule == is->ips_rule) - break; - if (is1 == NULL) - is->ips_is.is_flags |= FI_NEWFR; - else - is->ips_rule = (void *)&is1->ips_rule; - - /* - * Use a tail-queue type list (add things to the end).. - */ - is->ips_next = NULL; - if (!ipshead) - ipshead = is; - if (ipstail) - ipstail->ips_next = is; - ipstail = is; - } while (1); - - close(sfd); - - for (is = ipshead; is; is = is->ips_next) { - if (opts & OPT_VERBOSE) - printf("Loading new state table entry\n"); - if (is->ips_is.is_flags & FI_NEWFR) { - if (opts & OPT_VERBOSE) - printf("Loading new filter rule\n"); - } - if (!(opts & OPT_DONOTHING)) - if (ioctl(fd, SIOCSTPUT, &is)) { - perror("SIOCSTPUT"); - return 1; - } - - if (is->ips_is.is_flags & FI_NEWFR) { - if (opts & OPT_VERBOSE) - printf("Real rule addr %p\n", is->ips_rule); - for (is1 = is->ips_next; is1; is1 = is1->ips_next) - if (is1->ips_rule == (frentry_t *)&is->ips_rule) - is1->ips_rule = is->ips_rule; - } - } - - return 0; -} - - -int readnat(fd, file) -int fd; -char *file; -{ - nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL, *ipnp; - int nfd = -1, i; - nat_t *nat; - - if (!file) - file = IPF_NATFILE; - - nfd = open(file, O_RDONLY); - if (nfd == -1) { - fprintf(stderr, "%s ", file); - perror("nat:open"); - return 1; - } - - bzero((char *)&ipn, sizeof(ipn)); - ipnp = &ipn; - - /* - * 1. Read all state information in. - */ - do { - i = read(nfd, &ipn, sizeof(ipn)); - if (i == -1) { - perror("read"); - close(nfd); - return 1; - } - if (i == 0) - break; - if (i != sizeof(ipn)) { - fprintf(stderr, "incomplete read: %d != %d\n", i, - (int)sizeof(ipn)); - close(nfd); - return 1; - } - - if (ipn.ipn_dsize > 0) { - char *s = ipnp->ipn_data; - int n = ipnp->ipn_dsize; - - n -= sizeof(ipnp->ipn_data); - in = malloc(sizeof(*in) + n); - if (!in) - break; - - s += sizeof(ipnp->ipn_data); - i = read(nfd, s, n); - if (i == 0) - break; - if (i != n) { - fprintf(stderr, "incomplete read: %d != %d\n", - i, n); - close(nfd); - return 1; - } - } else - in = (nat_save_t *)malloc(sizeof(*in)); - bcopy((char *)ipnp, (char *)in, sizeof(ipn)); - - /* - * Check to see if this is the first state entry that will - * reference a particular rule and if so, flag it as such - * else just adjust the rule pointer to become a pointer to - * the other. We do this so we have a means later for tracking - * who is referencing us when we get back the real pointer - * in is_rule after doing the ioctl. - */ - nat = &in->ipn_nat; - if (nat->nat_fr != NULL) { - for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) - if (in1->ipn_rule == nat->nat_fr) - break; - if (in1 == NULL) - nat->nat_flags |= FI_NEWFR; - else - nat->nat_fr = &in1->ipn_fr; - } - - /* - * Use a tail-queue type list (add things to the end).. - */ - in->ipn_next = NULL; - if (!ipnhead) - ipnhead = in; - if (ipntail) - ipntail->ipn_next = in; - ipntail = in; - } while (1); - - close(nfd); - - for (in = ipnhead; in; in = in->ipn_next) { - if (opts & OPT_VERBOSE) - printf("Loading new NAT table entry\n"); - nat = &in->ipn_nat; - if (nat->nat_flags & FI_NEWFR) { - if (opts & OPT_VERBOSE) - printf("Loading new filter rule\n"); - } - if (!(opts & OPT_DONOTHING)) - if (ioctl(fd, SIOCSTPUT, &in)) { - perror("SIOCSTPUT"); - return 1; - } - - if (nat->nat_flags & FI_NEWFR) { - if (opts & OPT_VERBOSE) - printf("Real rule addr %p\n", nat->nat_fr); - for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) - if (in1->ipn_rule == &in->ipn_fr) - in1->ipn_rule = nat->nat_fr; - } - } - - return 0; -} - - -int writenat(fd, file) -int fd; -char *file; -{ - nat_save_t *ipnp = NULL, *next = NULL; - int nfd = -1; - natget_t ng; - - if (!file) - file = IPF_NATFILE; - - nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); - if (nfd == -1) { - fprintf(stderr, "%s ", file); - perror("nat:open"); - return 1; - } - - - do { - if (opts & OPT_VERBOSE) - printf("Getting nat from addr %p\n", ipnp); - ng.ng_ptr = next; - ng.ng_sz = 0; - if (ioctl(fd, SIOCSTGSZ, &ng)) { - perror("nat:SIOCSTGSZ"); - close(nfd); - return 1; - } - - if (opts & OPT_VERBOSE) - printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); - - if (ng.ng_sz == 0) - break; - - if (!ipnp) - ipnp = malloc(ng.ng_sz); - else - ipnp = realloc((char *)ipnp, ng.ng_sz); - if (!ipnp) { - fprintf(stderr, - "malloc for %d bytes failed\n", ng.ng_sz); - break; - } - - bzero((char *)ipnp, ng.ng_sz); - ipnp->ipn_next = next; - if (ioctl(fd, SIOCSTGET, &ipnp)) { - if (errno == ENOENT) - break; - perror("nat:SIOCSTGET"); - close(nfd); - return 1; - } - - if (opts & OPT_VERBOSE) - printf("Got nat next %p\n", ipnp->ipn_next); - if (write(nfd, ipnp, ng.ng_sz) != ng.ng_sz) { - perror("nat:write"); - close(nfd); - return 1; - } - next = ipnp->ipn_next; - } while (ipnp && next); - close(nfd); - - return 0; -} - - -int writeall(dirname) -char *dirname; -{ - int fd, devfd; - - if (!dirname) - dirname = IPF_SAVEDIR; - - if (chdir(dirname)) { - perror("chdir(IPF_SAVEDIR)"); - return 1; - } - - fd = opendevice(NULL); - if (fd == -1) - return 1; - if (setlock(fd, 1)) { - close(fd); - return 1; - } - - devfd = opendevice(IPL_STATE); - if (devfd == -1) - goto bad; - if (writestate(devfd, NULL)) - goto bad; - close(devfd); - - devfd = opendevice(IPL_NAT); - if (devfd == -1) - goto bad; - if (writenat(devfd, NULL)) - goto bad; - close(devfd); - - if (setlock(fd, 0)) { - close(fd); - return 1; - } - - return 0; - -bad: - setlock(fd, 0); - close(fd); - return 1; -} - - -int readall(dirname) -char *dirname; -{ - int fd, devfd; - - if (!dirname) - dirname = IPF_SAVEDIR; - - if (chdir(dirname)) { - perror("chdir(IPF_SAVEDIR)"); - return 1; - } - - fd = opendevice(NULL); - if (fd == -1) - return 1; - if (setlock(fd, 1)) { - close(fd); - return 1; - } - - devfd = opendevice(IPL_STATE); - if (devfd == -1) - return 1; - if (readstate(devfd, NULL)) - return 1; - close(devfd); - - devfd = opendevice(IPL_NAT); - if (devfd == -1) - return 1; - if (readnat(devfd, NULL)) - return 1; - close(devfd); - - if (setlock(fd, 0)) { - close(fd); - return 1; - } - - return 0; -} diff --git a/dist/ipf/ipft_ef.c b/dist/ipf/ipft_ef.c deleted file mode 100644 index ba7def909da7..000000000000 --- a/dist/ipf/ipft_ef.c +++ /dev/null @@ -1,159 +0,0 @@ -/* $NetBSD: ipft_ef.c,v 1.8 2003/05/17 01:11:52 itojun Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ - -/* - icmp type - lnth proto source destination src port dst port - -etherfind -n - - 60 tcp 128.250.20.20 128.250.133.13 2419 telnet - -etherfind -n -t - - 0.32 91 04 131.170.1.10 128.250.133.13 - 0.33 566 udp 128.250.37.155 128.250.133.3 901 901 -*/ -#ifdef __sgi -# include -#endif -#include -#include -#if !defined(__SVR4) && !defined(__GNUC__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include -#include "ipf.h" -#include "ipt.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipft_ef.c 1.6 2/4/96 (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipft_ef.c,v 2.2.2.3 2002/06/27 14:29:17 darrenr Exp"; -#endif - -static int etherf_open __P((char *)); -static int etherf_close __P((void)); -static int etherf_readip __P((char *, int, char **, int *)); - -struct ipread etherf = { etherf_open, etherf_close, etherf_readip }; - -static FILE *efp = NULL; -static int efd = -1; - - -static int etherf_open(fname) -char *fname; -{ - if (efd != -1) - return efd; - - if (!strcmp(fname, "-")) { - efd = 0; - efp = stdin; - } else { - efd = open(fname, O_RDONLY); - efp = fdopen(efd, "r"); - } - return efd; -} - - -static int etherf_close() -{ - return close(efd); -} - - -static int etherf_readip(buf, cnt, ifn, dir) -char *buf, **ifn; -int cnt, *dir; -{ - struct tcpiphdr pkt; - ip_t *ip = (ip_t *)&pkt; - struct protoent *p = NULL; - char src[16], dst[16], sprt[16], dprt[16]; - char lbuf[128], len[8], prot[8], time[8], *s; - int slen, extra = 0, i; - - if (!fgets(lbuf, sizeof(lbuf) - 1, efp)) - return 0; - - if ((s = strchr(lbuf, '\n'))) - *s = '\0'; - lbuf[sizeof(lbuf)-1] = '\0'; - - bzero(&pkt, sizeof(pkt)); - - if (sscanf(lbuf, "%7s %7s %15s %15s %15s %15s", len, prot, src, dst, - sprt, dprt) != 6) - if (sscanf(lbuf, "%7s %7s %7s %15s %15s %15s %15s", time, - len, prot, src, dst, sprt, dprt) != 7) - return -1; - - ip->ip_p = atoi(prot); - if (ip->ip_p == 0) { - if (!(p = getprotobyname(prot))) - return -1; - ip->ip_p = p->p_proto; - } - - switch (ip->ip_p) { - case IPPROTO_TCP : - case IPPROTO_UDP : - s = strtok(NULL, " :"); - ip->ip_len += atoi(s); - if (p->p_proto == IPPROTO_TCP) - extra = sizeof(struct tcphdr); - else if (p->p_proto == IPPROTO_UDP) - extra = sizeof(struct udphdr); - break; -#ifdef IGMP - case IPPROTO_IGMP : - extra = sizeof(struct igmp); - break; -#endif - case IPPROTO_ICMP : - extra = sizeof(struct icmp); - break; - default : - break; - } - - (void) inet_aton(src, &ip->ip_src); - (void) inet_aton(dst, &ip->ip_dst); - ip->ip_len = atoi(len); - ip->ip_hl = sizeof(ip_t); - - slen = ip->ip_hl + extra; - i = MIN(cnt, slen); - bcopy((char *)&pkt, buf, i); - return i; -} diff --git a/dist/ipf/ipft_hx.c b/dist/ipf/ipft_hx.c deleted file mode 100644 index 21c6a6098ba3..000000000000 --- a/dist/ipf/ipft_hx.c +++ /dev/null @@ -1,177 +0,0 @@ -/* $NetBSD: ipft_hx.c,v 1.5 2002/04/09 02:32:52 thorpej Exp $ */ - -/* - * Copyright (C) 1995-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include -#include "ipf.h" -#include "ipt.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipft_hx.c,v 2.2.2.5 2002/02/22 15:32:54 darrenr Exp"; -#endif - -extern int opts; - -static int hex_open __P((char *)); -static int hex_close __P((void)); -static int hex_readip __P((char *, int, char **, int *)); -static char *readhex __P((char *, char *)); - -struct ipread iphex = { hex_open, hex_close, hex_readip }; -static FILE *tfp = NULL; -static int tfd = -1; - -static int hex_open(fname) -char *fname; -{ - if (tfp && tfd != -1) { - rewind(tfp); - return tfd; - } - - if (!strcmp(fname, "-")) { - tfd = 0; - tfp = stdin; - } else { - tfd = open(fname, O_RDONLY); - if (tfd != -1) - tfp = fdopen(tfd, "r"); - } - return tfd; -} - - -static int hex_close() -{ - int cfd = tfd; - - tfd = -1; - return close(cfd); -} - - -static int hex_readip(buf, cnt, ifn, dir) -char *buf, **ifn; -int cnt, *dir; -{ - register char *s, *t, *u; - char line[513]; - ip_t *ip; - - /* - * interpret start of line as possibly "[ifname]" or - * "[in/out,ifname]". - */ - if (ifn) - *ifn = NULL; - if (dir) - *dir = 0; - ip = (ip_t *)buf; - while (fgets(line, sizeof(line)-1, tfp)) { - if ((s = index(line, '\n'))) { - if (s == line) - return (char *)ip - buf; - *s = '\0'; - } - if ((s = index(line, '#'))) - *s = '\0'; - if (!*line) - continue; - if (!(opts & OPT_BRIEF)) { - printf("input: %s\n", line); - fflush(stdout); - } - - if ((*line == '[') && (s = index(line, ']'))) { - t = line + 1; - if (s - t > 0) { - *s++ = '\0'; - if ((u = index(t, ',')) && (u < s)) { - u++; - if (ifn) - *ifn = strdup(u); - if (dir) { - if (*t == 'i') - *dir = 0; - else if (*t == 'o') - *dir = 1; - } - } else if (ifn) - *ifn = t; - } - } else - s = line; - ip = (ip_t *)readhex(s, (char *)ip); - } - return -1; -} - - -static char *readhex(src, dst) -register char *src, *dst; -{ - int state = 0; - char c; - - while ((c = *src++)) { - if (isspace(c)) { - if (state) { - dst++; - state = 0; - } - continue; - } else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F')) { - c = isdigit(c) ? (c - '0') : (toupper(c) - 55); - if (state == 0) { - *dst = (c << 4); - state++; - } else { - *dst++ |= c; - state = 0; - } - } else - break; - } - return dst; -} diff --git a/dist/ipf/ipft_pc.c b/dist/ipf/ipft_pc.c deleted file mode 100644 index 58f93e313c8a..000000000000 --- a/dist/ipf/ipft_pc.c +++ /dev/null @@ -1,238 +0,0 @@ -/* $NetBSD: ipft_pc.c,v 1.5 2002/04/09 02:32:52 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#include -#if !defined(__SVR4) && !defined(__GNUC__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include "ip_compat.h" -#include -#include "ipf.h" -#include "pcap.h" -#include "ipt.h" - -#if !defined(lint) -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipft_pc.c,v 2.2.2.3 2002/02/22 15:32:54 darrenr Exp"; -#endif - -struct llc { - int lc_sz; /* LLC header length */ - int lc_to; /* LLC Type offset */ - int lc_tl; /* LLC Type length */ -}; - -/* - * While many of these maybe the same, some do have different header formats - * which make this useful. - */ -#define DLT_MAX 14 - -static struct llc llcs[DLT_MAX+1] = { - { 0, 0, 0 }, /* DLT_NULL */ - { 14, 12, 2 }, /* DLT_E10MB */ - { 0, 0, 0 }, /* DLT_EN3MB */ - { 0, 0, 0 }, /* DLT_AX25 */ - { 0, 0, 0 }, /* DLT_PRONET */ - { 0, 0, 0 }, /* DLT_CHAOS */ - { 0, 0, 0 }, /* DLT_IEEE802 */ - { 0, 0, 0 }, /* DLT_ARCNET */ - { 0, 0, 0 }, /* DLT_SLIP */ - { 0, 0, 0 }, /* DLT_PPP */ - { 0, 0, 0 }, /* DLT_FDDI */ - { 0, 0, 0 }, /* DLT_ATMRFC1483 */ - { 0, 0, 0 }, /* DLT_LOOP */ - { 0, 0, 0 } /* DLT_ENC */ -}; - -static int pcap_open __P((char *)); -static int pcap_close __P((void)); -static int pcap_readip __P((char *, int, char **, int *)); -static void swap_hdr __P((pcaphdr_t *)); -static int pcap_read_rec __P((struct pcap_pkthdr *)); - -static int pfd = -1, s_type = -1, swapped = 0; - -struct ipread pcap = { pcap_open, pcap_close, pcap_readip }; - -#define SWAPLONG(y) \ - ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) -#define SWAPSHORT(y) \ - ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) ) - -static void swap_hdr(p) -pcaphdr_t *p; -{ - p->pc_v_maj = SWAPSHORT(p->pc_v_maj); - p->pc_v_min = SWAPSHORT(p->pc_v_min); - p->pc_zone = SWAPLONG(p->pc_zone); - p->pc_sigfigs = SWAPLONG(p->pc_sigfigs); - p->pc_slen = SWAPLONG(p->pc_slen); - p->pc_type = SWAPLONG(p->pc_type); -} - -static int pcap_open(fname) -char *fname; -{ - pcaphdr_t ph; - int fd; - - if (pfd != -1) - return pfd; - - if (!strcmp(fname, "-")) - fd = 0; - else if ((fd = open(fname, O_RDONLY)) == -1) - return -1; - - if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph)) - return -2; - - if (ph.pc_id != TCPDUMP_MAGIC) { - if (SWAPLONG(ph.pc_id) != TCPDUMP_MAGIC) { - (void) close(fd); - return -2; - } - swapped = 1; - swap_hdr(&ph); - } - - if (ph.pc_v_maj != PCAP_VERSION_MAJ || ph.pc_type >= DLT_MAX) { - (void) close(fd); - return -2; - } - - pfd = fd; - s_type = ph.pc_type; - printf("opened pcap file %s:\n", fname); - printf("\tid: %08x version: %d.%d type: %d snap %d\n", - ph.pc_id, ph.pc_v_maj, ph.pc_v_min, ph.pc_type, ph.pc_slen); - - return fd; -} - - -static int pcap_close() -{ - return close(pfd); -} - - -/* - * read in the header (and validate) which should be the first record - * in a pcap file. - */ -static int pcap_read_rec(rec) -struct pcap_pkthdr *rec; -{ - int n, p; - - if (read(pfd, (char *)rec, sizeof(*rec)) != sizeof(*rec)) - return -2; - - if (swapped) { - rec->ph_clen = SWAPLONG(rec->ph_clen); - rec->ph_len = SWAPLONG(rec->ph_len); - rec->ph_ts.tv_sec = SWAPLONG(rec->ph_ts.tv_sec); - rec->ph_ts.tv_usec = SWAPLONG(rec->ph_ts.tv_usec); - } - p = rec->ph_clen; - n = MIN(p, rec->ph_len); - if (!n || n < 0) - return -3; - - return p; -} - - -#ifdef notyet -/* - * read an entire pcap packet record. only the data part is copied into - * the available buffer, with the number of bytes copied returned. - */ -static int pcap_read(buf, cnt) -char *buf; -int cnt; -{ - struct pcap_pkthdr rec; - static char *bufp = NULL; - int i, n; - - if ((i = pcap_read_rec(&rec)) <= 0) - return i; - - if (!bufp) - bufp = malloc(i); - else - bufp = realloc(bufp, i); - - if (read(pfd, bufp, i) != i) - return -2; - - n = MIN(i, cnt); - bcopy(bufp, buf, n); - return n; -} -#endif - - -/* - * return only an IP packet read into buf - */ -static int pcap_readip(buf, cnt, ifn, dir) -char *buf, **ifn; -int cnt, *dir; -{ - static char *bufp = NULL; - struct pcap_pkthdr rec; - struct llc *l; - char *s, ty[4]; - int i, n; - - do { - if ((i = pcap_read_rec(&rec)) <= 0) - return i; - - if (!bufp) - bufp = malloc(i); - else - bufp = realloc(bufp, i); - s = bufp; - - if (read(pfd, s, i) != i) - return -2; - - l = &llcs[s_type]; - i -= l->lc_sz; - s += l->lc_to; - bcopy(s, ty, l->lc_tl); - s += l->lc_tl; - } while (ty[0] != 0x8 && ty[1] != 0); - n = MIN(i, cnt); - bcopy(s, buf, n); - return n; -} diff --git a/dist/ipf/ipft_sn.c b/dist/ipf/ipft_sn.c deleted file mode 100644 index ae54725a10e5..000000000000 --- a/dist/ipf/ipft_sn.c +++ /dev/null @@ -1,222 +0,0 @@ -/* $NetBSD: ipft_sn.c,v 1.5 2002/04/09 02:32:52 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ - -/* - * Written to comply with the recent RFC 1761 from Sun. - */ -#ifdef __sgi -# include -#endif -#include -#include -#if !defined(__SVR4) && !defined(__GNUC__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include "ip_compat.h" -#include -#include "ipf.h" -#include "snoop.h" -#include "ipt.h" - -#if !defined(lint) -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipft_sn.c,v 2.2.2.3 2002/02/22 15:32:54 darrenr Exp"; -#endif - -struct llc { - int lc_sz; /* LLC header length */ - int lc_to; /* LLC Type offset */ - int lc_tl; /* LLC Type length */ -}; - -/* - * While many of these maybe the same, some do have different header formats - * which make this useful. - */ -static struct llc llcs[SDL_MAX+1] = { - { 0, 0, 0 }, /* SDL_8023 */ - { 0, 0, 0 }, /* SDL_8024 */ - { 0, 0, 0 }, /* SDL_8025 */ - { 0, 0, 0 }, /* SDL_8026 */ - { 14, 12, 2 }, /* SDL_ETHER */ - { 0, 0, 0 }, /* SDL_HDLC */ - { 0, 0, 0 }, /* SDL_CHSYNC */ - { 0, 0, 0 }, /* SDL_IBMCC */ - { 0, 0, 0 }, /* SDL_FDDI */ - { 0, 0, 0 }, /* SDL_OTHER */ -}; - -static int snoop_open __P((char *)); -static int snoop_close __P((void)); -static int snoop_readip __P((char *, int, char **, int *)); - -static int sfd = -1, s_type = -1; -static int snoop_read_rec __P((struct snooppkt *)); - -struct ipread snoop = { snoop_open, snoop_close, snoop_readip }; - - -static int snoop_open(fname) -char *fname; -{ - struct snoophdr sh; - int fd; - int s_v; - - if (sfd != -1) - return sfd; - - if (!strcmp(fname, "-")) - fd = 0; - else if ((fd = open(fname, O_RDONLY)) == -1) - return -1; - - if (read(fd, (char *)&sh, sizeof(sh)) != sizeof(sh)) - return -2; - - s_v = (int)ntohl(sh.s_v); - s_type = (int)ntohl(sh.s_type); - - if (s_v != SNOOP_VERSION || - s_type < 0 || s_type > SDL_MAX) { - (void) close(fd); - return -2; - } - - sfd = fd; - printf("opened snoop file %s:\n", fname); - printf("\tid: %8.8s version: %d type: %d\n", sh.s_id, s_v, s_type); - - return fd; -} - - -static int snoop_close() -{ - return close(sfd); -} - - -/* - * read in the header (and validate) which should be the first record - * in a snoop file. - */ -static int snoop_read_rec(rec) -struct snooppkt *rec; -{ - int n, plen, ilen; - - if (read(sfd, (char *)rec, sizeof(*rec)) != sizeof(*rec)) - return -2; - - ilen = (int)ntohl(rec->sp_ilen); - plen = (int)ntohl(rec->sp_plen); - if (ilen > plen || plen < sizeof(*rec)) - return -2; - - plen -= sizeof(*rec); - n = MIN(plen, ilen); - if (!n || n < 0) - return -3; - - return plen; -} - - -#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. - */ -static int snoop_read(buf, cnt) -char *buf; -int cnt; -{ - struct snooppkt rec; - static char *bufp = NULL; - int i, n; - - if ((i = snoop_read_rec(&rec)) <= 0) - return i; - - if (!bufp) - bufp = malloc(i); - else - bufp = realloc(bufp, i); - - if (read(sfd, bufp, i) != i) - return -2; - - n = MIN(i, cnt); - bcopy(bufp, buf, n); - return n; -} -#endif - - -/* - * return only an IP packet read into buf - */ -static int snoop_readip(buf, cnt, ifn, dir) -char *buf, **ifn; -int cnt, *dir; -{ - static char *bufp = NULL; - struct snooppkt rec; - struct llc *l; - char ty[4], *s; - int i, n; - - do { - if ((i = snoop_read_rec(&rec)) <= 0) - return i; - - if (!bufp) - bufp = malloc(i); - else - bufp = realloc(bufp, i); - s = bufp; - - if (read(sfd, s, i) != i) - return -2; - - l = &llcs[s_type]; - i -= l->lc_to; - s += l->lc_to; - /* - * XXX - bogus assumption here on the part of the time field - * that it won't be greater than 4 bytes and the 1st two will - * have the values 8 and 0 for IP. Should be a table of - * these too somewhere. Really only works for SDL_ETHER. - */ - bcopy(s, ty, l->lc_tl); - } while (ty[0] != 0x8 && ty[1] != 0); - - i -= l->lc_tl; - s += l->lc_tl; - n = MIN(i, cnt); - bcopy(s, buf, n); - - return n; -} diff --git a/dist/ipf/ipft_td.c b/dist/ipf/ipft_td.c deleted file mode 100644 index 7754bc4b713b..000000000000 --- a/dist/ipf/ipft_td.c +++ /dev/null @@ -1,197 +0,0 @@ -/* $NetBSD: ipft_td.c,v 1.8 2003/05/17 01:11:53 itojun Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ - -/* -tcpdump -n - -00:05:47.816843 128.231.76.76.3291 > 224.2.252.231.36573: udp 36 (encap) - -tcpdump -nq - -00:33:48.410771 192.73.213.11.1463 > 224.2.248.153.59360: udp 31 (encap) - -tcpdump -nqt - -128.250.133.13.23 > 128.250.20.20.2419: tcp 27 - -tcpdump -nqtt - -123456789.1234567 128.250.133.13.23 > 128.250.20.20.2419: tcp 27 - -tcpdump -nqte - -8:0:20:f:65:f7 0:0:c:1:8a:c5 81: 128.250.133.13.23 > 128.250.20.20.2419: tcp 27 - -*/ -#ifdef __sgi -# include -#endif -#include -#include -#if !defined(__SVR4) && !defined(__GNUC__) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include -#include "ipf.h" -#include "ipt.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipft_td.c 1.8 2/4/96 (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipft_td.c,v 2.2.2.3 2002/06/27 14:29:17 darrenr Exp"; -#endif - -static int tcpd_open __P((char *)); -static int tcpd_close __P((void)); -static int tcpd_readip __P((char *, int, char **, int *)); -static int count_dots __P((char *)); - -struct ipread tcpd = { tcpd_open, tcpd_close, tcpd_readip }; - -static FILE *tfp = NULL; -static int tfd = -1; - - -static int tcpd_open(fname) -char *fname; -{ - if (tfd != -1) - return tfd; - - if (!strcmp(fname, "-")) { - tfd = 0; - tfp = stdin; - } else { - tfd = open(fname, O_RDONLY); - tfp = fdopen(tfd, "r"); - } - return tfd; -} - - -static int tcpd_close() -{ - (void) fclose(tfp); - return close(tfd); -} - - -static int count_dots(str) -char *str; -{ - int i = 0; - - while (*str) - if (*str++ == '.') - i++; - return i; -} - - -static int tcpd_readip(buf, cnt, ifn, dir) -char *buf, **ifn; -int cnt, *dir; -{ - struct tcpiphdr pkt; - ip_t *ip = (ip_t *)&pkt; - struct protoent *p; - char src[32], dst[32], misc[256], time[32], link1[32], link2[32]; - char lbuf[160], *s; - int n, slen, extra = 0; - - if (!fgets(lbuf, sizeof(lbuf) - 1, tfp)) - return 0; - - if ((s = strchr(lbuf, '\n'))) - *s = '\0'; - lbuf[sizeof(lbuf)-1] = '\0'; - - bzero(&pkt, sizeof(pkt)); - - if ((n = sscanf(lbuf, "%31s > %31s: %255s", src, dst, misc)) != 3) - if ((n = sscanf(lbuf, "%31s %31s > %31s: %255s", - time, src, dst, misc)) != 4) - if ((n = sscanf(lbuf, "%31s %31s: %31s > %31s: %255s", - link1, link2, src, dst, misc)) != 5) { - n = sscanf(lbuf, - "%31s %31s %31s: %31s > %31s: %255s", - time, link1, link2, src, dst, misc); - if (n != 6) - return -1; - } - - if (count_dots(dst) == 4) { - s = strrchr(src, '.'); - *s++ = '\0'; - (void) inet_aton(src, &ip->ip_src); - pkt.ti_sport = htons(atoi(s)); - *--s = '.'; - s = strrchr(dst, '.'); - - *s++ = '\0'; - (void) inet_aton(src, &ip->ip_dst); - pkt.ti_dport = htons(atoi(s)); - *--s = '.'; - - } else { - (void) inet_aton(src, &ip->ip_src); - (void) inet_aton(src, &ip->ip_dst); - } - ip->ip_len = ip->ip_hl = sizeof(ip_t); - - s = strtok(misc, " :"); - if ((p = getprotobyname(s))) { - ip->ip_p = p->p_proto; - - switch (p->p_proto) { - case IPPROTO_TCP : - case IPPROTO_UDP : - s = strtok(NULL, " :"); - ip->ip_len += atoi(s); - if (p->p_proto == IPPROTO_TCP) - extra = sizeof(struct tcphdr); - else if (p->p_proto == IPPROTO_UDP) - extra = sizeof(struct udphdr); - break; -#ifdef IGMP - case IPPROTO_IGMP : - extra = sizeof(struct igmp); - break; -#endif - case IPPROTO_ICMP : - extra = sizeof(struct icmp); - break; - default : - break; - } - } - slen = ip->ip_hl + extra + ip->ip_len; - return slen; -} diff --git a/dist/ipf/ipft_tx.c b/dist/ipf/ipft_tx.c deleted file mode 100644 index b667b4baaa31..000000000000 --- a/dist/ipf/ipft_tx.c +++ /dev/null @@ -1,357 +0,0 @@ -/* $NetBSD: ipft_tx.c,v 1.8 2002/09/19 08:10:40 martti Exp $ */ - -/* - * Copyright (C) 1995-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include -#include "ipf.h" -#include "ipt.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipft_tx.c,v 2.3.2.7 2002/06/27 14:29:17 darrenr Exp"; -#endif - -extern int opts; - -static char *tx_proto = ""; - -static int text_open __P((char *)), text_close __P((void)); -static int text_readip __P((char *, int, char **, int *)); -static int parseline __P((char *, ip_t *, char **, int *)); - -static char _tcp_flagset[] = "FSRPAUEC"; -static u_char _tcp_flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, - TH_ACK, TH_URG, TH_ECN, TH_CWR }; - -struct ipread iptext = { text_open, text_close, text_readip }; -static FILE *tfp = NULL; -static int tfd = -1; - -static u_32_t tx_hostnum __P((char *, int *)); -static u_short tx_portnum __P((char *)); - - -/* - * returns an ip address as a long var as a result of either a DNS lookup or - * straight inet_addr() call - */ -static u_32_t tx_hostnum(host, resolved) -char *host; -int *resolved; -{ - struct hostent *hp; - struct netent *np; - - *resolved = 0; - if (!strcasecmp("any",host)) - return 0L; - if (isdigit(*host)) - return inet_addr(host); - - if (!(hp = gethostbyname(host))) { - if (!(np = getnetbyname(host))) { - *resolved = -1; - fprintf(stderr, "can't resolve hostname: %s\n", host); - return 0; - } - return htonl(np->n_net); - } - return *(u_32_t *)hp->h_addr; -} - - -/* - * find the port number given by the name, either from getservbyname() or - * straight atoi() - */ -static u_short tx_portnum(name) -char *name; -{ - struct servent *sp, *sp2; - u_short p1 = 0; - - if (isdigit(*name)) - return (u_short)atoi(name); - if (!tx_proto) - tx_proto = "tcp/udp"; - if (strcasecmp(tx_proto, "tcp/udp")) { - sp = getservbyname(name, tx_proto); - if (sp) - return ntohs(sp->s_port); - (void) fprintf(stderr, "unknown service \"%s\".\n", name); - return 0; - } - sp = getservbyname(name, "tcp"); - if (sp) - p1 = sp->s_port; - sp2 = getservbyname(name, "udp"); - if (!sp || !sp2) { - (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n", - name); - return 0; - } - if (p1 != sp2->s_port) { - (void) fprintf(stderr, "%s %d/tcp is a different port to ", - name, p1); - (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port); - return 0; - } - return ntohs(p1); -} - - -char *tx_icmptypes[] = { - "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", - "redir", (char *)NULL, (char *)NULL, "echo", "routerad", - "routersol", "timex", "paramprob", "timest", "timestrep", - "inforeq", "inforep", "maskreq", "maskrep", "END" -}; - -static int text_open(fname) -char *fname; -{ - if (tfp && tfd != -1) { - rewind(tfp); - return tfd; - } - - if (!strcmp(fname, "-")) { - tfd = 0; - tfp = stdin; - } else { - tfd = open(fname, O_RDONLY); - if (tfd != -1) - tfp = fdopen(tfd, "r"); - } - return tfd; -} - - -static int text_close() -{ - int cfd = tfd; - - tfd = -1; - return close(cfd); -} - - -static int text_readip(buf, cnt, ifn, dir) -char *buf, **ifn; -int cnt, *dir; -{ - register char *s; - char line[513]; - - *ifn = NULL; - while (fgets(line, sizeof(line)-1, tfp)) { - if ((s = index(line, '\n'))) - *s = '\0'; - if ((s = index(line, '\r'))) - *s = '\0'; - if ((s = index(line, '#'))) - *s = '\0'; - if (!*line) - continue; - if (!(opts & OPT_BRIEF)) - printf("input: %s\n", line); - *ifn = NULL; - *dir = 0; - if (!parseline(line, (ip_t *)buf, ifn, dir)) -#if 0 - return sizeof(ip_t) + sizeof(tcphdr_t); -#else - return sizeof(ip_t); -#endif - } - return -1; -} - -static int parseline(line, ip, ifn, out) -char *line; -ip_t *ip; -char **ifn; -int *out; -{ - tcphdr_t th, *tcp = &th; - struct icmp icmp, *ic = &icmp; - char *cps[20], **cpp, c, ipopts[68]; - int i, r; - - if (*ifn) - free(*ifn); - bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip)); - bzero((char *)tcp, sizeof(*tcp)); - bzero((char *)ic, sizeof(*ic)); - bzero(ipopts, sizeof(ipopts)); - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; - for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && (i < 19); ) - cps[++i] = strtok(NULL, " \b\t\r\n"); - - cpp = cps; - if (!*cpp) - return 1; - - c = **cpp; - if (!isalpha(c) || (tolower(c) != 'o' && tolower(c) != 'i')) { - fprintf(stderr, "bad direction \"%s\"\n", *cpp); - return 1; - } - *out = (tolower(c) == 'o') ? 1 : 0; - cpp++; - if (!*cpp) - return 1; - - if (!strcasecmp(*cpp, "on")) { - cpp++; - if (!*cpp) - return 1; - *ifn = strdup(*cpp++); - if (!*cpp) - return 1; - } - - c = **cpp; - ip->ip_len = sizeof(ip_t); - if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") || - !strcasecmp(*cpp, "icmp")) { - if (c == 't') { - ip->ip_p = IPPROTO_TCP; - ip->ip_len += sizeof(struct tcphdr); - tx_proto = "tcp"; - } else if (c == 'u') { - ip->ip_p = IPPROTO_UDP; - ip->ip_len += sizeof(struct udphdr); - tx_proto = "udp"; - } else { - ip->ip_p = IPPROTO_ICMP; - ip->ip_len += ICMPERR_IPICMPHLEN; - tx_proto = "icmp"; - } - cpp++; - } else if (isdigit(**cpp) && !index(*cpp, '.')) { - ip->ip_p = atoi(*cpp); - cpp++; - } else - ip->ip_p = IPPROTO_IP; - - if (!*cpp) - return 1; - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { - char *last; - - last = index(*cpp, ','); - if (!last) { - fprintf(stderr, "tcp/udp with no source port\n"); - return 1; - } - *last++ = '\0'; - tcp->th_sport = htons(tx_portnum(last)); - } - ip->ip_src.s_addr = tx_hostnum(*cpp, &r); - cpp++; - if (!*cpp) - return 1; - - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { - char *last; - - last = index(*cpp, ','); - if (!last) { - fprintf(stderr, "tcp/udp with no destination port\n"); - return 1; - } - *last++ = '\0'; - tcp->th_dport = htons(tx_portnum(last)); - } - ip->ip_dst.s_addr = tx_hostnum(*cpp, &r); - cpp++; - if (*cpp && ip->ip_p == IPPROTO_TCP) { - extern char _tcp_flagset[]; - extern u_char _tcp_flags[]; - char *s, *t; - - for (s = *cpp; *s; s++) - if ((t = index(_tcp_flagset, *s))) - tcp->th_flags |= _tcp_flags[t - _tcp_flagset]; - if (tcp->th_flags) - cpp++; - assert(tcp->th_flags != 0); - tcp->th_win = htons(4096); - tcp->th_off = sizeof(*tcp) >> 2; - } else if (*cpp && ip->ip_p == IPPROTO_ICMP) { - extern char *tx_icmptypes[]; - char **s, *t; - int i; - - for (s = tx_icmptypes, i = 0; !*s || strcmp(*s, "END"); - s++, i++) - if (*s && !strncasecmp(*cpp, *s, strlen(*s))) { - ic->icmp_type = i; - if ((t = index(*cpp, ','))) - ic->icmp_code = atoi(t+1); - cpp++; - break; - } - } - - if (*cpp && !strcasecmp(*cpp, "opt")) { - u_long olen; - - cpp++; - olen = buildopts(*cpp, ipopts, (ip->ip_hl - 5) << 2); - if (olen) { - bcopy(ipopts, (char *)(ip + 1), olen); - ip->ip_hl += olen >> 2; - } - } - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) - bcopy((char *)tcp, ((char *)ip) + (ip->ip_hl << 2), - sizeof(*tcp)); - else if (ip->ip_p == IPPROTO_ICMP) - bcopy((char *)ic, ((char *)ip) + (ip->ip_hl << 2), - sizeof(*ic)); - ip->ip_len = htons(ip->ip_len); - return 0; -} diff --git a/dist/ipf/iplang/Makefile b/dist/ipf/iplang/Makefile index f97bf1901307..5b53e9a43609 100644 --- a/dist/ipf/iplang/Makefile +++ b/dist/ipf/iplang/Makefile @@ -1,36 +1,31 @@ # -# 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. +# See the IPFILTER.LICENCE file for details on licencing. # #CC=gcc -Wuninitialized -Wstrict-prototypes -Werror -O CFLAGS=-I.. -all: $(DESTDIR)/y.tab.o $(DESTDIR)/lex.yy.o +all: $(DESTDIR)/iplang_y.o $(DESTDIR)/iplang_l.o -$(DESTDIR)/y.tab.o: $(DESTDIR)/y.tab.c - $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/y.tab.c -o $@ +$(DESTDIR)/iplang_y.o: $(DESTDIR)/iplang_y.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_y.c -o $@ -$(DESTDIR)/$(OBJ)/y.tab.o: $(DESTDIR)/y.tab.c - $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/y.tab.c -o $@ +$(DESTDIR)/iplang_l.o: $(DESTDIR)/iplang_l.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_l.c -o $@ -$(DESTDIR)/lex.yy.o: $(DESTDIR)/lex.yy.c - $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/lex.yy.c -o $@ +iplang_y.o: iplang_y.c + $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@ -y.tab.o: y.tab.c - $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c y.tab.c -o $@ +iplang_l.o: iplang_l.c + $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@ -lex.yy.o: lex.yy.c - $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c lex.yy.c -o $@ - -$(DESTDIR)/lex.yy.c: iplang_l.l $(DESTDIR)/y.tab.h +$(DESTDIR)/iplang_l.c: iplang_l.l $(DESTDIR)/iplang_y.h lex iplang_l.l - mv lex.yy.c $(DESTDIR) + mv lex.yy.c $(DESTDIR)/iplang_l.c -$(DESTDIR)/y.tab.c $(DESTDIR)/y.tab.h: iplang_y.y +$(DESTDIR)/iplang_y.c $(DESTDIR)/iplang_y.h: iplang_y.y yacc -d iplang_y.y - mv y.tab.c $(DESTDIR) - mv y.tab.h $(DESTDIR) + mv y.tab.c $(DESTDIR)/iplang_y.c + mv y.tab.h $(DESTDIR)/iplang_y.h clean: /bin/rm -f *.o lex.yy.c y.tab.c y.tab.h diff --git a/dist/ipf/iplang/iplang_l.l b/dist/ipf/iplang/iplang_l.l index 340c04c33e86..b72aa8ccda51 100644 --- a/dist/ipf/iplang/iplang_l.l +++ b/dist/ipf/iplang/iplang_l.l @@ -1,14 +1,12 @@ -/* $NetBSD: iplang_l.l,v 1.4 2003/07/20 03:14:40 lukem Exp $ */ +/* $NetBSD: iplang_l.l,v 1.5 2004/03/28 09:00:55 martti Exp $ */ %{ /* * Copyright (C) 1997-1998 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. + * See the IPFILTER.LICENCE file for details on licencing. * - * Id: iplang_l.l,v 2.2 2000/02/18 00:18:05 darrenr Exp + * Id: iplang_l.l,v 2.8 2003/07/28 01:15:31 darrenr Exp */ #include #include @@ -20,7 +18,6 @@ #include #include #include "iplang_y.h" -#include "ip_compat.h" #include "ipf.h" #ifndef __P @@ -45,13 +42,13 @@ int save_token __P((void)); void swallow __P((void)); int yylex __P((void)); -struct wordtab { +struct lwordtab { char *word; int state; int next; }; -struct wordtab words[] = { +struct lwordtab words[] = { { "interface", IL_INTERFACE, -1 }, { "iface", IL_INTERFACE, -1 }, { "name", IL_IFNAME, IL_TOKEN }, @@ -219,7 +216,7 @@ void pop_proto() int save_token() { - yylval.str = strdup(yytext); + yylval.str = strdup((char *)yytext); return IL_TOKEN; } @@ -227,7 +224,7 @@ int save_token() int next_item(nstate) int nstate; { - struct wordtab *wt; + struct lwordtab *wt; if (opts & OPT_DEBUG) printf("text=[%s] id=%d next=%d\n", yytext, nstate, next); @@ -238,13 +235,13 @@ int nstate; token++; for (wt = words; wt->word; wt++) - if (!strcasecmp(wt->word, yytext)) + if (!strcasecmp(wt->word, (char *)yytext)) return next_state(wt->state, wt->next); if (opts & OPT_DEBUG) printf("unknown keyword=[%s]\n", yytext); next = -1; if (nstate == IL_NUMBER) - yylval.num = atoi(yytext); + yylval.num = atoi((char *)yytext); token++; return nstate; } diff --git a/dist/ipf/iplang/iplang_y.y b/dist/ipf/iplang/iplang_y.y index 1d429dfc8a88..a9f1307a8131 100644 --- a/dist/ipf/iplang/iplang_y.y +++ b/dist/ipf/iplang/iplang_y.y @@ -1,19 +1,14 @@ -/* $NetBSD: iplang_y.y,v 1.4 2002/03/14 12:32:39 martti Exp $ */ +/* $NetBSD: iplang_y.y,v 1.5 2004/03/28 09:00:55 martti Exp $ */ %{ /* * Copyright (C) 1997-1998 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. + * See the IPFILTER.LICENCE file for details on licencing. * - * Id: iplang_y.y,v 2.2.2.2 2002/02/22 15:32:57 darrenr Exp + * Id: iplang_y.y,v 2.9.2.1 2004/03/23 12:58:38 darrenr Exp */ -#ifdef __sgi -# include -#endif #include #include #include @@ -33,12 +28,9 @@ #include #include #include -#include #ifndef linux #include #endif -#include -#include #include #ifndef linux #include @@ -54,7 +46,7 @@ #include "iplang.h" #if !defined(__NetBSD__) && (!defined(__FreeBSD_version) && \ - __FreeBSD_version < 400020) + __FreeBSD_version < 400020) && (!SOLARIS || SOLARIS2 < 10) extern struct ether_addr *ether_aton __P((char *)); #endif @@ -1296,7 +1288,7 @@ void prep_packet() return; } if (ifp->if_fd == -1) - ifp->if_fd = initdevice(ifp->if_name, 0, 5); + ifp->if_fd = initdevice(ifp->if_name, 5); gwip = sending.snd_gw; if (!gwip.s_addr) gwip = aniphead->ah_ip->ip_dst; @@ -1520,11 +1512,6 @@ int type; } -static 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 }; - void set_icmpcodetok(code) char **code; { @@ -1543,13 +1530,6 @@ char **code; } -static char *icmptypes[] = { - "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", - "redir", (char *)NULL, (char *)NULL, "echo", (char *)NULL, - (char *)NULL, "timex", "paramprob", "timest", "timestrep", - "inforeq", "inforep", "maskreq", "maskrep", "END" -}; - void set_icmptypetok(type) char **type; { diff --git a/dist/ipf/ipmon.c b/dist/ipf/ipmon.c deleted file mode 100644 index d3c1700bf299..000000000000 --- a/dist/ipf/ipmon.c +++ /dev/null @@ -1,1500 +0,0 @@ -/* $NetBSD: ipmon.c,v 1.17 2002/09/25 06:43:17 martti Exp $ */ - -/* - * Copyright (C) 1993-2002 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifndef SOLARIS -#define SOLARIS (defined(__SVR4) || defined(__svr4__)) && defined(sun) -#endif - -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -# if (__FreeBSD_version >= 300000) -# include -# else -# include -# endif -#else -# include -# include -#endif -#if !defined(__SVR4) && !defined(__GNUC__) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef linux -# include -# include -#endif - -#include -#include - -#include -#include - -#include "netinet/ip_compat.h" -#include -#include "netinet/ip_fil.h" -#include "netinet/ip_nat.h" -#include "netinet/ip_state.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipmon.c,v 2.12.2.36 2002/08/22 15:12:23 darrenr Exp"; -#endif - - -#if defined(sun) && !defined(SOLARIS2) -#define STRERROR(x) sys_errlist[x] -extern char *sys_errlist[]; -#else -#define STRERROR(x) strerror(x) -#endif - - -struct flags { - int value; - char flag; -}; - - -typedef struct icmp_subtype { - int ist_val; - char *ist_name; -} icmp_subtype_t; - -typedef struct icmp_type { - int it_val; - struct icmp_subtype *it_subtable; - size_t it_stsize; - char *it_name; -} icmp_type_t; - - -#define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t)) - - -struct flags tcpfl[] = { - { TH_ACK, 'A' }, - { TH_RST, 'R' }, - { TH_SYN, 'S' }, - { TH_FIN, 'F' }, - { TH_URG, 'U' }, - { TH_PUSH,'P' }, - { TH_ECN, 'E' }, - { TH_CWR, 'C' }, - { 0, '\0' } -}; - -#if SOLARIS -static char *pidfile = "/etc/opt/ipf/ipmon.pid"; -#else -# if BSD >= 199306 -static char *pidfile = "/var/run/ipmon.pid"; -# else -static char *pidfile = "/etc/ipmon.pid"; -# endif -#endif - -static char line[2048]; -static int opts = 0; -static FILE *newlog = NULL; -static char *logfile = NULL; -static int donehup = 0; -static void usage __P((char *)); -static void handlehup __P((int)); -static void flushlogs __P((char *, FILE *)); -static void print_log __P((int, FILE *, char *, int)); -static void print_ipflog __P((FILE *, char *, int)); -static void print_natlog __P((FILE *, char *, int)); -static void print_statelog __P((FILE *, char *, int)); -static void dumphex __P((FILE *, u_char *, int)); -static int read_log __P((int, int *, char *, int)); -static void write_pid __P((char *)); -static char *icmpname __P((u_int, u_int)); -static char *icmpname6 __P((u_int, u_int)); -static icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t)); -static icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t)); - -char *hostname __P((int, int, u_32_t *)); -char *portname __P((int, char *, u_int)); -int main __P((int, char *[])); - -static void logopts __P((int, char *)); -static void init_tabs __P((void)); -static char *getproto __P((u_int)); - -static char **protocols = NULL; -static char **udp_ports = NULL; -static char **tcp_ports = NULL; - -#define OPT_SYSLOG 0x001 -#define OPT_RESOLVE 0x002 -#define OPT_HEXBODY 0x004 -#define OPT_VERBOSE 0x008 -#define OPT_HEXHDR 0x010 -#define OPT_TAIL 0x020 -#define OPT_NAT 0x080 -#define OPT_STATE 0x100 -#define OPT_FILTER 0x200 -#define OPT_PORTNUM 0x400 -#define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) -#define OPT_LOGBODY 0x800 - -#define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) - -#ifndef LOGFAC -#define LOGFAC LOG_LOCAL0 -#endif - - -static icmp_subtype_t icmpunreachnames[] = { - { ICMP_UNREACH_NET, "net" }, - { ICMP_UNREACH_HOST, "host" }, - { ICMP_UNREACH_PROTOCOL, "protocol" }, - { ICMP_UNREACH_PORT, "port" }, - { ICMP_UNREACH_NEEDFRAG, "needfrag" }, - { ICMP_UNREACH_SRCFAIL, "srcfail" }, - { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" }, - { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" }, - { ICMP_UNREACH_NET, "isolated" }, - { ICMP_UNREACH_NET_PROHIB, "net_prohib" }, - { ICMP_UNREACH_NET_PROHIB, "host_prohib" }, - { ICMP_UNREACH_TOSNET, "tosnet" }, - { ICMP_UNREACH_TOSHOST, "toshost" }, - { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" }, - { -2, NULL } -}; - -static icmp_subtype_t redirectnames[] = { - { ICMP_REDIRECT_NET, "net" }, - { ICMP_REDIRECT_HOST, "host" }, - { ICMP_REDIRECT_TOSNET, "tosnet" }, - { ICMP_REDIRECT_TOSHOST, "toshost" }, - { -2, NULL } -}; - -static icmp_subtype_t timxceednames[] = { - { ICMP_TIMXCEED_INTRANS, "transit" }, - { ICMP_TIMXCEED_REASS, "reassem" }, - { -2, NULL } -}; - -static icmp_subtype_t paramnames[] = { - { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" }, - { ICMP_PARAMPROB_OPTABSENT, "optmissing" }, - { ICMP_PARAMPROB_LENGTH, "length" }, - { -2, NULL } -}; - -static icmp_type_t icmptypes[] = { - { ICMP_ECHOREPLY, NULL, 0, "echoreply" }, - { -1, NULL, 0, NULL }, - { -1, NULL, 0, NULL }, - { ICMP_UNREACH, icmpunreachnames, - IST_SZ(icmpunreachnames),"unreach" }, - { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" }, - { ICMP_REDIRECT, redirectnames, - IST_SZ(redirectnames), "redirect" }, - { -1, NULL, 0, NULL }, - { -1, NULL, 0, NULL }, - { ICMP_ECHO, NULL, 0, "echo" }, - { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" }, - { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" }, - { ICMP_TIMXCEED, timxceednames, - IST_SZ(timxceednames), "timxceed" }, - { ICMP_PARAMPROB, paramnames, - IST_SZ(paramnames), "paramprob" }, - { ICMP_TSTAMP, NULL, 0, "timestamp" }, - { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" }, - { ICMP_IREQ, NULL, 0, "inforeq" }, - { ICMP_IREQREPLY, NULL, 0, "inforeply" }, - { ICMP_MASKREQ, NULL, 0, "maskreq" }, - { ICMP_MASKREPLY, NULL, 0, "maskreply" }, - { -2, NULL, 0, NULL } -}; - -static icmp_subtype_t icmpredirect6[] = { - { ICMP6_DST_UNREACH_NOROUTE, "noroute" }, - { ICMP6_DST_UNREACH_ADMIN, "admin" }, - { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" }, - { ICMP6_DST_UNREACH_ADDR, "address" }, - { ICMP6_DST_UNREACH_NOPORT, "noport" }, - { -2, NULL } -}; - -static icmp_subtype_t icmptimexceed6[] = { - { ICMP6_TIME_EXCEED_TRANSIT, "intransit" }, - { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" }, - { -2, NULL } -}; - -static icmp_subtype_t icmpparamprob6[] = { - { ICMP6_PARAMPROB_HEADER, "header" }, - { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" }, - { ICMP6_PARAMPROB_OPTION, "option" }, - { -2, NULL } -}; - -static icmp_subtype_t icmpquerysubject6[] = { - { ICMP6_NI_SUBJ_IPV6, "ipv6" }, - { ICMP6_NI_SUBJ_FQDN, "fqdn" }, - { ICMP6_NI_SUBJ_IPV4, "ipv4" }, - { -2, NULL }, -}; - -static icmp_subtype_t icmpnodeinfo6[] = { - { ICMP6_NI_SUCCESS, "success" }, - { ICMP6_NI_REFUSED, "refused" }, - { ICMP6_NI_UNKNOWN, "unknown" }, - { -2, NULL } -}; - -static icmp_subtype_t icmprenumber6[] = { - { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" }, - { ICMP6_ROUTER_RENUMBERING_RESULT, "result" }, - { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" }, - { -2, NULL } -}; - -static icmp_type_t icmptypes6[] = { - { 0, NULL, 0, NULL }, - { ICMP6_DST_UNREACH, icmpredirect6, - IST_SZ(icmpredirect6), "unreach" }, - { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" }, - { ICMP6_TIME_EXCEEDED, icmptimexceed6, - IST_SZ(icmptimexceed6), "timxceed" }, - { ICMP6_PARAM_PROB, icmpparamprob6, - IST_SZ(icmpparamprob6), "paramprob" }, - { ICMP6_ECHO_REQUEST, NULL, 0, "echo" }, - { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" }, - { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6, - IST_SZ(icmpquerysubject6), "groupmemberquery" }, - { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" }, - { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" }, - { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" }, - { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" }, - { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" }, - { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" }, - { ND_REDIRECT, NULL, 0, "redirect" }, - { ICMP6_ROUTER_RENUMBERING, icmprenumber6, - IST_SZ(icmprenumber6), "routerrenumber" }, - { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" }, - { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" }, - { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" }, - { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" }, - { ICMP6_NI_QUERY, icmpnodeinfo6, - IST_SZ(icmpnodeinfo6), "nodeinforequest" }, - { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" }, - { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" }, - { MLD6_MTRACE, NULL, 0, "mtracerequest" }, - { -2, NULL, 0, NULL } -}; - -static icmp_subtype_t *find_icmpsubtype(type, table, tablesz) -int type; -icmp_subtype_t *table; -size_t tablesz; -{ - icmp_subtype_t *ist; - int i; - - if (tablesz < 2) - return NULL; - - if ((type < 0) || (type > table[tablesz - 2].ist_val)) - return NULL; - - i = type; - if (table[type].ist_val == type) - return table + type; - - for (i = 0, ist = table; ist->ist_val != -2; i++, ist++) - if (ist->ist_val == type) - return ist; - return NULL; -} - - -static icmp_type_t *find_icmptype(type, table, tablesz) -int type; -icmp_type_t *table; -size_t tablesz; -{ - icmp_type_t *it; - int i; - - if (tablesz < 2) - return NULL; - - if ((type < 0) || (type > table[tablesz - 2].it_val)) - return NULL; - - i = type; - if (table[type].it_val == type) - return table + type; - - for (i = 0, it = table; it->it_val != -2; i++, it++) - if (it->it_val == type) - return it; - return NULL; -} - - -static void handlehup(sig) -int sig; -{ - FILE *fp; - - signal(SIGHUP, handlehup); - if (logfile && (fp = fopen(logfile, "a"))) - newlog = fp; - init_tabs(); - donehup = 1; -} - - -static void init_tabs() -{ - struct protoent *p; - struct servent *s; - char *name, **tab; - int port; - - if (protocols != NULL) { - free(protocols); - protocols = NULL; - } - protocols = (char **)malloc(256 * sizeof(*protocols)); - if (protocols != NULL) { - bzero((char *)protocols, 256 * sizeof(*protocols)); - - setprotoent(1); - while ((p = getprotoent()) != NULL) - if (p->p_proto >= 0 && p->p_proto <= 255 && - p->p_name != NULL && protocols[p->p_proto] == NULL) - protocols[p->p_proto] = strdup(p->p_name); - endprotoent(); - } - - if (udp_ports != NULL) { - free(udp_ports); - udp_ports = NULL; - } - udp_ports = (char **)malloc(65536 * sizeof(*udp_ports)); - if (udp_ports != NULL) - bzero((char *)udp_ports, 65536 * sizeof(*udp_ports)); - - if (tcp_ports != NULL) { - free(tcp_ports); - tcp_ports = NULL; - } - tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports)); - if (tcp_ports != NULL) - bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports)); - - setservent(1); - while ((s = getservent()) != NULL) { - if (s->s_proto == NULL) - continue; - else if (!strcmp(s->s_proto, "tcp")) { - port = ntohs(s->s_port); - name = s->s_name; - tab = tcp_ports; - } else if (!strcmp(s->s_proto, "udp")) { - port = ntohs(s->s_port); - name = s->s_name; - tab = udp_ports; - } else - continue; - if ((port < 0 || port > 65535) || (name == NULL)) - continue; - tab[port] = strdup(name); - } - endservent(); -} - - -static char *getproto(p) -u_int p; -{ - static char pnum[4]; - char *s; - - p &= 0xff; - s = protocols ? protocols[p] : NULL; - if (s == NULL) { - sprintf(pnum, "%u", p); - s = pnum; - } - return s; -} - - -static int read_log(fd, lenp, buf, bufsize) -int fd, bufsize, *lenp; -char *buf; -{ - int nr; - - nr = read(fd, buf, bufsize); - if (!nr) - return 2; - if ((nr < 0) && (errno != EINTR)) - return -1; - *lenp = nr; - return 0; -} - - -char *hostname(res, v, ip) -int res, v; -u_32_t *ip; -{ -# define MAX_INETA 16 - static char hname[MAXHOSTNAMELEN + MAX_INETA + 3]; -#ifdef USE_INET6 - static char hostbuf[MAXHOSTNAMELEN+1]; -#endif - struct hostent *hp; - struct in_addr ipa; - - if (v == 4) { - ipa.s_addr = *ip; - if (!res) - return inet_ntoa(ipa); - hp = gethostbyaddr((char *)ip, sizeof(*ip), AF_INET); - if (!hp) - return inet_ntoa(ipa); - sprintf(hname, "%.*s[%s]", MAXHOSTNAMELEN, hp->h_name, - inet_ntoa(ipa)); - return hname; - } -#ifdef USE_INET6 - (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); - hostbuf[MAXHOSTNAMELEN] = '\0'; - return hostbuf; -#else - return "IPv6"; -#endif -} - - -char *portname(res, proto, port) -int res; -char *proto; -u_int port; -{ - static char pname[8]; - char *s; - - port = ntohs(port); - port &= 0xffff; - (void) sprintf(pname, "%u", port); - if (!res || (opts & OPT_PORTNUM)) - return pname; - s = NULL; - if (!strcmp(proto, "tcp")) - s = tcp_ports[port]; - else if (!strcmp(proto, "udp")) - s = udp_ports[port]; - if (s == NULL) - s = pname; - return s; -} - - -static char *icmpname(type, code) -u_int type; -u_int code; -{ - static char name[80]; - icmp_subtype_t *ist; - icmp_type_t *it; - char *s; - - s = NULL; - it = find_icmptype(type, icmptypes, sizeof(icmptypes) / sizeof(*it)); - if (it != NULL) - s = it->it_name; - - if (s == NULL) - sprintf(name, "icmptype(%d)/", type); - else - sprintf(name, "%s/", s); - - ist = NULL; - if (it != NULL && it->it_subtable != NULL) - ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); - - if (ist != NULL && ist->ist_name != NULL) - strcat(name, ist->ist_name); - else - sprintf(name + strlen(name), "%d", code); - - return name; -} - -static char *icmpname6(type, code) -u_int type; -u_int code; -{ - static char name[80]; - icmp_subtype_t *ist; - icmp_type_t *it; - char *s; - - s = NULL; - it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it)); - if (it != NULL) - s = it->it_name; - - if (s == NULL) - sprintf(name, "icmpv6type(%d)/", type); - else - sprintf(name, "%s/", s); - - ist = NULL; - if (it != NULL && it->it_subtable != NULL) - ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); - - if (ist != NULL && ist->ist_name != NULL) - strcat(name, ist->ist_name); - else - sprintf(name + strlen(name), "%d", code); - - return name; -} - - -static void dumphex(log, buf, len) -FILE *log; -u_char *buf; -int len; -{ - char line[80]; - int i, j, k; - u_char *s = buf, *t = (u_char *)line; - - if (len == 0 || buf == 0) - return; - *line = '\0'; - - for (i = len, j = 0; i; i--, j++, s++) { - if (j && !(j & 0xf)) { - *t++ = '\n'; - *t = '\0'; - if (!(opts & OPT_SYSLOG)) - fputs(line, log); - else - syslog(LOG_INFO, "%s", line); - t = (u_char *)line; - *t = '\0'; - } - sprintf((char *)t, "%02x", *s & 0xff); - t += 2; - if (!((j + 1) & 0xf)) { - s -= 15; - sprintf((char *)t, " "); - t += 8; - for (k = 16; k; k--, s++) - *t++ = (isprint(*s) ? *s : '.'); - s--; - } - - if ((j + 1) & 0xf) - *t++ = ' ';; - } - - if (j & 0xf) { - for (k = 16 - (j & 0xf); k; k--) { - *t++ = ' '; - *t++ = ' '; - *t++ = ' '; - } - sprintf((char *)t, " "); - t += 7; - s -= j & 0xf; - for (k = j & 0xf; k; k--, s++) - *t++ = (isprint(*s) ? *s : '.'); - *t++ = '\n'; - *t = '\0'; - } - if (!(opts & OPT_SYSLOG)) { - fputs(line, log); - fflush(log); - } else - syslog(LOG_INFO, "%s", line); -} - -static void print_natlog(log, buf, blen) -FILE *log; -char *buf; -int blen; -{ - struct natlog *nl; - iplog_t *ipl = (iplog_t *)buf; - char *t = line; - struct tm *tm; - int res, i, len; - char *proto; - time_t ipl_time; - - nl = (struct natlog *)((char *)ipl + IPLOG_SIZE); - res = (opts & OPT_RESOLVE) ? 1 : 0; - ipl_time = (time_t) ipl->ipl_time.tv_sec; - tm = localtime(&ipl_time); - len = sizeof(line); - if (!(opts & OPT_SYSLOG)) { - (void) strftime(t, len, "%d/%m/%Y ", tm); - i = strlen(t); - len -= i; - t += i; - } - (void) strftime(t, len, "%T", tm); - t += strlen(t); - (void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_time.tv_usec, nl->nl_rule + 1); - t += strlen(t); - - if (nl->nl_type == NL_NEWMAP) - strcpy(t, "NAT:MAP "); - else if (nl->nl_type == NL_NEWRDR) - strcpy(t, "NAT:RDR "); - else if (nl->nl_type == NL_EXPIRE) - strcpy(t, "NAT:EXPIRE "); - else if (nl->nl_type == NL_FLUSH) - strcpy(t, "NAT:FLUSH "); - else if (nl->nl_type == NL_NEWBIMAP) - strcpy(t, "NAT:BIMAP "); - else if (nl->nl_type == NL_NEWBLOCK) - strcpy(t, "NAT:MAPBLOCK "); - else - sprintf(t, "Type: %d ", nl->nl_type); - t += strlen(t); - - proto = getproto(nl->nl_p); - - (void) sprintf(t, "%s,%s <- -> ", HOSTNAME_V4(res, nl->nl_inip), - portname(res, proto, (u_int)nl->nl_inport)); - t += strlen(t); - (void) sprintf(t, "%s,%s ", HOSTNAME_V4(res, nl->nl_outip), - portname(res, proto, (u_int)nl->nl_outport)); - t += strlen(t); - (void) sprintf(t, "[%s,%s]", HOSTNAME_V4(res, nl->nl_origip), - portname(res, proto, (u_int)nl->nl_origport)); - t += strlen(t); - if (nl->nl_type == NL_EXPIRE) { -#ifdef USE_QUAD_T - (void) sprintf(t, " Pkts %qd Bytes %qd", - (long long)nl->nl_pkts, - (long long)nl->nl_bytes); -#else - (void) sprintf(t, " Pkts %ld Bytes %ld", - nl->nl_pkts, nl->nl_bytes); -#endif - t += strlen(t); - } - - *t++ = '\n'; - *t++ = '\0'; - if (opts & OPT_SYSLOG) - syslog(LOG_INFO, "%s", line); - else - (void) fprintf(log, "%s", line); -} - - -static void print_statelog(log, buf, blen) -FILE *log; -char *buf; -int blen; -{ - struct ipslog *sl; - iplog_t *ipl = (iplog_t *)buf; - char *t = line, *proto; - struct tm *tm; - int res, i, len; - time_t ipl_time; - - sl = (struct ipslog *)((char *)ipl + IPLOG_SIZE); - res = (opts & OPT_RESOLVE) ? 1 : 0; - ipl_time = (time_t) ipl->ipl_time.tv_sec; - tm = localtime(&ipl_time); - len = sizeof(line); - if (!(opts & OPT_SYSLOG)) { - (void) strftime(t, len, "%d/%m/%Y ", tm); - i = strlen(t); - len -= i; - t += i; - } - (void) strftime(t, len, "%T", tm); - t += strlen(t); - (void) sprintf(t, ".%-.6ld ", ipl->ipl_time.tv_usec); - t += strlen(t); - - if (sl->isl_type == ISL_NEW) - strcpy(t, "STATE:NEW "); - else if (sl->isl_type == ISL_EXPIRE) { - if ((sl->isl_p == IPPROTO_TCP) && - (sl->isl_state[0] > TCPS_ESTABLISHED || - sl->isl_state[1] > TCPS_ESTABLISHED)) - strcpy(t, "STATE:CLOSE "); - else - strcpy(t, "STATE:EXPIRE "); - } else if (sl->isl_type == ISL_FLUSH) - strcpy(t, "STATE:FLUSH "); - else if (sl->isl_type == ISL_REMOVE) - strcpy(t, "STATE:REMOVE "); - else - sprintf(t, "Type: %d ", sl->isl_type); - t += strlen(t); - - proto = getproto(sl->isl_p); - - if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { - (void) sprintf(t, "%s,%s -> ", - hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src), - portname(res, proto, (u_int)sl->isl_sport)); - t += strlen(t); - (void) sprintf(t, "%s,%s PR %s", - hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), - portname(res, proto, (u_int)sl->isl_dport), proto); - } else if (sl->isl_p == IPPROTO_ICMP) { - (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, - (u_32_t *)&sl->isl_src)); - t += strlen(t); - (void) sprintf(t, "%s PR icmp %d", - hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), - sl->isl_itype); - } else if (sl->isl_p == IPPROTO_ICMPV6) { - (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, - (u_32_t *)&sl->isl_src)); - t += strlen(t); - (void) sprintf(t, "%s PR icmpv6 %d", - hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), - sl->isl_itype); - } - t += strlen(t); - if (sl->isl_type != ISL_NEW) { -#ifdef USE_QUAD_T - (void) sprintf(t, " Pkts %qd Bytes %qd", - (long long)sl->isl_pkts, - (long long)sl->isl_bytes); -#else - (void) sprintf(t, " Pkts %ld Bytes %ld", - sl->isl_pkts, sl->isl_bytes); -#endif - t += strlen(t); - } - - *t++ = '\n'; - *t++ = '\0'; - if (opts & OPT_SYSLOG) - syslog(LOG_INFO, "%s", line); - else - (void) fprintf(log, "%s", line); -} - - -static void print_log(logtype, log, buf, blen) -FILE *log; -char *buf; -int logtype, blen; -{ - iplog_t *ipl; - char *bp = NULL, *bpo = NULL; - int psize; - - while (blen > 0) { - ipl = (iplog_t *)buf; - if ((u_long)ipl & (sizeof(long)-1)) { - if (bp) - bpo = bp; - bp = (char *)malloc(blen); - bcopy((char *)ipl, bp, blen); - if (bpo) { - free(bpo); - bpo = NULL; - } - buf = bp; - continue; - } - if (ipl->ipl_magic != IPL_MAGIC) { - /* invalid data or out of sync */ - break; - } - psize = ipl->ipl_dsize; - switch (logtype) - { - case IPL_LOGIPF : - print_ipflog(log, buf, psize); - break; - case IPL_LOGNAT : - print_natlog(log, buf, psize); - break; - case IPL_LOGSTATE : - print_statelog(log, buf, psize); - break; - } - - blen -= psize; - buf += psize; - } - if (bp) - free(bp); - return; -} - - -static void print_ipflog(log, buf, blen) -FILE *log; -char *buf; -int blen; -{ - tcphdr_t *tp; - struct icmp *ic; - struct icmp *icmp; - struct tm *tm; - char *t, *proto; - int i, v, lvl, res, len, off, plen, ipoff; - ip_t *ipc, *ip; - u_short hl, p; - ipflog_t *ipf; - iplog_t *ipl; - u_32_t *s, *d; -#ifdef USE_INET6 - ip6_t *ip6; -#endif - time_t ipl_time; - - ipl = (iplog_t *)buf; - ipf = (ipflog_t *)((char *)buf + IPLOG_SIZE); - ip = (ip_t *)((char *)ipf + sizeof(*ipf)); - v = ip->ip_v; - res = (opts & OPT_RESOLVE) ? 1 : 0; - t = line; - *t = '\0'; - ipl_time = (time_t) ipl->ipl_time.tv_sec; - tm = localtime(&ipl_time); -#ifdef linux - if (v == 4) - ip->ip_len = ntohs(ip->ip_len); -#endif - - len = sizeof(line); - if (!(opts & OPT_SYSLOG)) { - (void) strftime(t, len, "%d/%m/%Y ", tm); - i = strlen(t); - len -= i; - t += i; - } - (void) strftime(t, len, "%T", tm); - t += strlen(t); - (void) sprintf(t, ".%-.6ld ", ipl->ipl_time.tv_usec); - t += strlen(t); - if (ipl->ipl_count > 1) { - (void) sprintf(t, "%dx ", ipl->ipl_count); - t += strlen(t); - } -#if (SOLARIS || \ - (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) - { - char ifname[sizeof(ipf->fl_ifname) + 1]; - - strncpy(ifname, (char *)ipf->fl_ifname, sizeof(ipf->fl_ifname)); - ifname[sizeof(ipf->fl_ifname)] = '\0'; - (void) sprintf(t, "%s", ifname); - t += strlen(t); -# if SOLARIS - if (isalpha(*(t - 1))) { - sprintf(t, "%d", ipf->fl_unit); - t += strlen(t); - } -# endif - } -#else - for (len = 0; len < 3; len++) - if (ipf->fl_ifname[len] == '\0') - break; - if (ipf->fl_ifname[len]) - len++; - (void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); - t += strlen(t); -#endif - if (ipf->fl_group == 0xffffffff) - strcat(t, " @-1:"); - else - (void) sprintf(t, " @%u:", ipf->fl_group); - t += strlen(t); - if (ipf->fl_rule == 0xffffffff) - strcat(t, "-1 "); - else - (void) sprintf(t, "%u ", ipf->fl_rule + 1); - t += strlen(t); - - if (ipf->fl_flags & FF_SHORT) { - *t++ = 'S'; - lvl = LOG_ERR; - } else if (ipf->fl_flags & FR_PASS) { - if (ipf->fl_flags & FR_LOG) - *t++ = 'p'; - else - *t++ = 'P'; - lvl = LOG_NOTICE; - } else if (ipf->fl_flags & FR_BLOCK) { - if (ipf->fl_flags & FR_LOG) - *t++ = 'b'; - else - *t++ = 'B'; - lvl = LOG_WARNING; - } else if (ipf->fl_flags & FF_LOGNOMATCH) { - *t++ = 'n'; - lvl = LOG_NOTICE; - } else { - *t++ = 'L'; - lvl = LOG_INFO; - } - if (ipf->fl_loglevel != 0xffff) - lvl = ipf->fl_loglevel; - *t++ = ' '; - *t = '\0'; - - if (v == 6) { -#ifdef USE_INET6 - off = 0; - ipoff = 0; - hl = sizeof(ip6_t); - ip6 = (ip6_t *)ip; - p = (u_short)ip6->ip6_nxt; - s = (u_32_t *)&ip6->ip6_src; - d = (u_32_t *)&ip6->ip6_dst; - plen = ntohs(ip6->ip6_plen); -#else - sprintf(t, "ipv6"); - goto printipflog; -#endif - } else if (v == 4) { - hl = (ip->ip_hl << 2); - ipoff = ip->ip_off; - off = ipoff & IP_OFFMASK; - p = (u_short)ip->ip_p; - s = (u_32_t *)&ip->ip_src; - d = (u_32_t *)&ip->ip_dst; - plen = ip->ip_len; - } else { - goto printipflog; - } - proto = getproto(p); - - if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { - tp = (tcphdr_t *)((char *)ip + hl); - if (!(ipf->fl_flags & FF_SHORT)) { - (void) sprintf(t, "%s,%s -> ", hostname(res, v, s), - portname(res, proto, (u_int)tp->th_sport)); - t += strlen(t); - (void) sprintf(t, "%s,%s PR %s len %hu %hu", - hostname(res, v, d), - portname(res, proto, (u_int)tp->th_dport), - proto, hl, plen); - t += strlen(t); - - if (p == IPPROTO_TCP) { - *t++ = ' '; - *t++ = '-'; - for (i = 0; tcpfl[i].value; i++) - if (tp->th_flags & tcpfl[i].value) - *t++ = tcpfl[i].flag; - if (opts & OPT_VERBOSE) { - (void) sprintf(t, " %lu %lu %hu", - (u_long)(ntohl(tp->th_seq)), - (u_long)(ntohl(tp->th_ack)), - ntohs(tp->th_win)); - t += strlen(t); - } - } - *t = '\0'; - } else { - (void) sprintf(t, "%s -> ", hostname(res, v, s)); - t += strlen(t); - (void) sprintf(t, "%s PR %s len %hu %hu", - hostname(res, v, d), proto, hl, plen); - } - } else if ((p == IPPROTO_ICMPV6) && !off && (v == 6)) { - ic = (struct icmp *)((char *)ip + hl); - (void) sprintf(t, "%s -> ", hostname(res, v, s)); - t += strlen(t); - (void) sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", - hostname(res, v, d), hl, plen, - icmpname6(ic->icmp_type, ic->icmp_code)); - } else if ((p == IPPROTO_ICMP) && !off && (v == 4)) { - ic = (struct icmp *)((char *)ip + hl); - (void) sprintf(t, "%s -> ", hostname(res, v, s)); - t += strlen(t); - (void) sprintf(t, "%s PR icmp len %hu %hu icmp %s", - hostname(res, v, d), hl, plen, - icmpname(ic->icmp_type, ic->icmp_code)); - if (ic->icmp_type == ICMP_UNREACH || - ic->icmp_type == ICMP_SOURCEQUENCH || - ic->icmp_type == ICMP_PARAMPROB || - ic->icmp_type == ICMP_REDIRECT || - ic->icmp_type == ICMP_TIMXCEED) { - ipc = &ic->icmp_ip; - i = ntohs(ipc->ip_len); - ipoff = ntohs(ipc->ip_off); - proto = getproto(ipc->ip_p); - - if (!(ipoff & IP_OFFMASK) && - ((ipc->ip_p == IPPROTO_TCP) || - (ipc->ip_p == IPPROTO_UDP))) { - tp = (tcphdr_t *)((char *)ipc + hl); - t += strlen(t); - (void) sprintf(t, " for %s,%s -", - HOSTNAME_V4(res, ipc->ip_src), - portname(res, proto, - (u_int)tp->th_sport)); - t += strlen(t); - (void) sprintf(t, " %s,%s PR %s len %hu %hu", - HOSTNAME_V4(res, ipc->ip_dst), - portname(res, proto, - (u_int)tp->th_dport), - proto, ipc->ip_hl << 2, i); - } else if (!(ipoff & IP_OFFMASK) && - (ipc->ip_p == IPPROTO_ICMP)) { - icmp = (icmphdr_t *)((char *)ipc + hl); - - t += strlen(t); - (void) sprintf(t, " for %s -", - HOSTNAME_V4(res, ipc->ip_src)); - t += strlen(t); - (void) sprintf(t, - " %s PR icmp len %hu %hu icmp %d/%d", - HOSTNAME_V4(res, ipc->ip_dst), - ipc->ip_hl << 2, i, - icmp->icmp_type, icmp->icmp_code); - - } else { - t += strlen(t); - (void) sprintf(t, " for %s -", - HOSTNAME_V4(res, ipc->ip_src)); - t += strlen(t); - (void) sprintf(t, " %s PR %s len %hu (%hu)", - HOSTNAME_V4(res, ipc->ip_dst), proto, - ipc->ip_hl << 2, i); - t += strlen(t); - if (ipoff & IP_OFFMASK) { - (void) sprintf(t, " frag %s%s%hu@%hu", - ipoff & IP_MF ? "+" : "", - ipoff & IP_DF ? "-" : "", - i - (ipc->ip_hl<<2), - (ipoff & IP_OFFMASK) << 3); - } - } - } - } else { - (void) sprintf(t, "%s -> ", hostname(res, v, s)); - t += strlen(t); - (void) sprintf(t, "%s PR %s len %hu (%hu)", - hostname(res, v, d), proto, hl, plen); - t += strlen(t); - if (off & IP_OFFMASK) - (void) sprintf(t, " frag %s%s%hu@%hu", - ipoff & IP_MF ? "+" : "", - ipoff & IP_DF ? "-" : "", - plen - hl, (off & IP_OFFMASK) << 3); - } - t += strlen(t); - - if (ipf->fl_flags & FR_KEEPSTATE) { - (void) strcpy(t, " K-S"); - t += strlen(t); - } - - if (ipf->fl_flags & FR_KEEPFRAG) { - (void) strcpy(t, " K-F"); - t += strlen(t); - } - - if (ipf->fl_dir == 0) - strcpy(t, " IN"); - else if (ipf->fl_dir == 1) - strcpy(t, " OUT"); - t += strlen(t); -printipflog: - *t++ = '\n'; - *t++ = '\0'; - if (opts & OPT_SYSLOG) - syslog(lvl, "%s", line); - else - (void) fprintf(log, "%s", line); - if (opts & OPT_HEXHDR) - dumphex(log, (u_char *)buf, sizeof(iplog_t) + sizeof(*ipf)); - if (opts & OPT_HEXBODY) - dumphex(log, (u_char *)ip, ipf->fl_plen + ipf->fl_hlen); - else if ((opts & OPT_LOGBODY) && (ipf->fl_flags & FR_LOGBODY)) - dumphex(log, (u_char *)ip + ipf->fl_hlen, ipf->fl_plen); -} - - -static void usage(prog) -char *prog; -{ - fprintf(stderr, "%s: [-NFhstvxX] [-f ]\n", prog); - exit(1); -} - - -static void write_pid(file) -char *file; -{ - FILE *fp = NULL; - int fd; - - if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) - fp = fdopen(fd, "w"); - if (!fp) { - close(fd); - fprintf(stderr, "unable to open/create pid file: %s\n", file); - return; - } - fprintf(fp, "%d\n", getpid()); - fclose(fp); - close(fd); -} - - -static void flushlogs(file, log) -char *file; -FILE *log; -{ - int fd, flushed = 0; - - if ((fd = open(file, O_RDWR)) == -1) { - (void) fprintf(stderr, "%s: open: %s\n", - file, STRERROR(errno)); - exit(1); - } - - if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { - printf("%d bytes flushed from log buffer\n", - flushed); - fflush(stdout); - } else - perror("SIOCIPFFB"); - (void) close(fd); - - if (flushed) { - if (opts & OPT_SYSLOG) - syslog(LOG_INFO, "%d bytes flushed from log\n", - flushed); - else if (log != stdout) - fprintf(log, "%d bytes flushed from log\n", flushed); - } -} - - -static void logopts(turnon, options) -int turnon; -char *options; -{ - int flags = 0; - char *s; - - for (s = options; *s; s++) - { - switch (*s) - { - case 'N' : - flags |= OPT_NAT; - break; - case 'S' : - flags |= OPT_STATE; - break; - case 'I' : - flags |= OPT_FILTER; - break; - default : - fprintf(stderr, "Unknown log option %c\n", *s); - exit(1); - } - } - - if (turnon) - opts |= flags; - else - opts &= ~(flags); -} - - -int main(argc, argv) -int argc; -char *argv[]; -{ - int fdt[3], devices = 0, make_daemon = 0; - char buf[IPLLOGSIZE], *iplfile[3], *s; - int fd[3], doread, n, i; - extern char *optarg; - extern int optind; - int regular[3], c; - FILE *log = stdout; - struct stat sb; - size_t nr, tr; - - fd[0] = fd[1] = fd[2] = -1; - fdt[0] = fdt[1] = fdt[2] = -1; - iplfile[0] = IPL_NAME; - iplfile[1] = IPNAT_NAME; - iplfile[2] = IPSTATE_NAME; - - while ((c = getopt(argc, argv, "?abDf:FhnN:o:O:pP:sS:tvxX")) != -1) - switch (c) - { - case 'a' : - opts |= OPT_LOGALL; - fdt[0] = IPL_LOGIPF; - fdt[1] = IPL_LOGNAT; - fdt[2] = IPL_LOGSTATE; - break; - case 'b' : - opts |= OPT_LOGBODY; - break; - case 'D' : - make_daemon = 1; - break; - case 'f' : case 'I' : - opts |= OPT_FILTER; - fdt[0] = IPL_LOGIPF; - iplfile[0] = optarg; - break; - case 'F' : - flushlogs(iplfile[0], log); - flushlogs(iplfile[1], log); - flushlogs(iplfile[2], log); - break; - case 'n' : - opts |= OPT_RESOLVE; - break; - case 'N' : - opts |= OPT_NAT; - fdt[1] = IPL_LOGNAT; - iplfile[1] = optarg; - break; - case 'o' : case 'O' : - logopts(c == 'o', optarg); - fdt[0] = fdt[1] = fdt[2] = -1; - if (opts & OPT_FILTER) - fdt[0] = IPL_LOGIPF; - if (opts & OPT_NAT) - fdt[1] = IPL_LOGNAT; - if (opts & OPT_STATE) - fdt[2] = IPL_LOGSTATE; - break; - case 'p' : - opts |= OPT_PORTNUM; - break; - case 'P' : - pidfile = optarg; - break; - case 's' : - s = strrchr(argv[0], '/'); - if (s == NULL) - s = argv[0]; - else - s++; - openlog(s, LOG_NDELAY|LOG_PID, LOGFAC); - opts |= OPT_SYSLOG; - log = NULL; - break; - case 'S' : - opts |= OPT_STATE; - fdt[2] = IPL_LOGSTATE; - iplfile[2] = optarg; - break; - case 't' : - opts |= OPT_TAIL; - break; - case 'v' : - opts |= OPT_VERBOSE; - break; - case 'x' : - opts |= OPT_HEXBODY; - break; - case 'X' : - opts |= OPT_HEXHDR; - break; - default : - case 'h' : - case '?' : - usage(argv[0]); - } - - init_tabs(); - - /* - * Default action is to only open the filter log file. - */ - if ((fdt[0] == -1) && (fdt[1] == -1) && (fdt[2] == -1)) - fdt[0] = IPL_LOGIPF; - - for (i = 0; i < 3; i++) { - if (fdt[i] == -1) - continue; - if (!strcmp(iplfile[i], "-")) - fd[i] = 0; - else { - if ((fd[i] = open(iplfile[i], O_RDONLY)) == -1) { - (void) fprintf(stderr, - "%s: open: %s\n", iplfile[i], - STRERROR(errno)); - exit(1); - /* NOTREACHED */ - } - if (fstat(fd[i], &sb) == -1) { - (void) fprintf(stderr, "%d: fstat: %s\n", - fd[i], STRERROR(errno)); - exit(1); - /* NOTREACHED */ - } - if (!(regular[i] = !S_ISCHR(sb.st_mode))) - devices++; - } - } - - if (!(opts & OPT_SYSLOG)) { - logfile = argv[optind]; - log = logfile ? fopen(logfile, "a") : stdout; - if (log == NULL) { - (void) fprintf(stderr, "%s: fopen: %s\n", - argv[optind], STRERROR(errno)); - exit(1); - /* NOTREACHED */ - } - setvbuf(log, NULL, _IONBF, 0); - } else - log = NULL; - - if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) { -#if BSD - daemon(0, !(opts & OPT_SYSLOG)); -#else - int pid; - if ((pid = fork()) > 0) - exit(0); - if (pid < 0) { - (void) fprintf(stderr, "%s: fork() failed: %s\n", - argv[0], STRERROR(errno)); - exit(1); - /* NOTREACHED */ - } - setsid(); - if ((opts & OPT_SYSLOG)) - close(2); -#endif /* !BSD */ - close(0); - close(1); - } - write_pid(pidfile); - - signal(SIGHUP, handlehup); - - for (doread = 1; doread; ) { - nr = 0; - - for (i = 0; i < 3; i++) { - tr = 0; - if (fdt[i] == -1) - continue; - if (!regular[i]) { - if (ioctl(fd[i], FIONREAD, &tr) == -1) { - if (opts & OPT_SYSLOG) - syslog(LOG_CRIT, - "ioctl(FIONREAD): %m"); - else - perror("ioctl(FIONREAD)"); - exit(1); - /* NOTREACHED */ - } - } else { - tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size); - if (!tr && !(opts & OPT_TAIL)) - doread = 0; - } - if (!tr) - continue; - nr += tr; - - tr = read_log(fd[i], &n, buf, sizeof(buf)); - if (donehup) { - donehup = 0; - if (newlog) { - fclose(log); - log = newlog; - newlog = NULL; - } - } - - switch (tr) - { - case -1 : - if (opts & OPT_SYSLOG) - syslog(LOG_CRIT, "read: %m\n"); - else - perror("read"); - doread = 0; - break; - case 1 : - if (opts & OPT_SYSLOG) - syslog(LOG_CRIT, "aborting logging\n"); - else - fprintf(log, "aborting logging\n"); - doread = 0; - break; - case 2 : - break; - case 0 : - if (n > 0) { - print_log(fdt[i], log, buf, n); - if (!(opts & OPT_SYSLOG)) - fflush(log); - } - break; - } - } - if (!nr && ((opts & OPT_TAIL) || devices)) - sleep(1); - } - exit(0); - /* NOTREACHED */ -} diff --git a/dist/ipf/ipnat.c b/dist/ipf/ipnat.c deleted file mode 100644 index c2dca7dc74fe..000000000000 --- a/dist/ipf/ipnat.c +++ /dev/null @@ -1,394 +0,0 @@ -/* $NetBSD: ipnat.c,v 1.12 2002/09/19 08:10:40 martti Exp $ */ - -/* - * Copyright (C) 1993-2002 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) - */ -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) -# include -# include -#endif -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include -#include -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_nat.h" -#include "netinet/ip_state.h" -#include "netinet/ip_proxy.h" -#include "ipf.h" -#include "kmem.h" - -#if defined(sun) && !SOLARIS2 -# define STRERROR(x) sys_errlist[x] -extern char *sys_errlist[]; -#else -# define STRERROR(x) strerror(x) -#endif - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipnat.c,v 2.16.2.21 2002/06/06 10:49:19 darrenr Exp"; -#endif - - -#if SOLARIS -#define bzero(a,b) memset(a,0,b) -#endif -int use_inet6 = 0; -char thishost[MAXHOSTNAMELEN]; - -extern char *optarg; -extern ipnat_t *natparse __P((char *, int)); -extern void natparsefile __P((int, char *, int)); -extern void printnat __P((ipnat_t *, int)); -extern void printactivenat __P((nat_t *, int)); -extern void printhostmap __P((hostmap_t *, u_int)); -extern char *getsumd __P((u_32_t)); - -void dostats __P((natstat_t *, int)), flushtable __P((int, int)); -void usage __P((char *)); -int countbits __P((u_32_t)); -char *getnattype __P((ipnat_t *)); -int main __P((int, char*[])); -void printaps __P((ap_session_t *, int)); -void showhostmap __P((natstat_t *nsp)); -void natstat_dead __P((natstat_t *, char *)); - - -void usage(name) -char *name; -{ - fprintf(stderr, "%s: [-CFhlnrsv] [-f filename]\n", name); - exit(1); -} - - -int main(argc, argv) -int argc; -char *argv[]; -{ - natstat_t ns, *nsp = &ns; - char *file, *core, *kernel; - int fd, opts, c, mode; - - fd = -1; - opts = 0; - file = NULL; - core = NULL; - kernel = NULL; - mode = O_RDWR; - - while ((c = getopt(argc, argv, "CdFf:hlM:N:nrsv")) != -1) - switch (c) - { - case 'C' : - opts |= OPT_CLEAR; - break; - case 'd' : - opts |= OPT_DEBUG; - break; - case 'f' : - file = optarg; - break; - case 'F' : - opts |= OPT_FLUSH; - break; - case 'h' : - opts |=OPT_HITS; - break; - case 'l' : - opts |= OPT_LIST; - mode = O_RDONLY; - break; - case 'M' : - core = optarg; - break; - case 'N' : - kernel = optarg; - break; - case 'n' : - opts |= OPT_NODO; - mode = O_RDONLY; - break; - case 'r' : - opts |= OPT_REMOVE; - break; - case 's' : - opts |= OPT_STAT; - mode = O_RDONLY; - break; - case 'v' : - opts |= OPT_VERBOSE; - break; - default : - usage(argv[0]); - } - - if ((kernel != NULL) || (core != NULL)) { - (void) setgid(getgid()); - (void) setuid(getuid()); - } - - bzero((char *)&ns, sizeof(ns)); - - gethostname(thishost, sizeof(thishost)); - thishost[sizeof(thishost) - 1] = '\0'; - - if (!(opts & OPT_NODO) && (kernel == NULL) && (core == NULL)) { - if (openkmem(kernel, core) == -1) - exit(1); - - if (((fd = open(IPL_NAT, mode)) == -1) && - ((fd = open(IPL_NAT, O_RDONLY)) == -1)) { - (void) fprintf(stderr, "%s: open: %s\n", IPL_NAT, - STRERROR(errno)); - if (errno == ENODEV) - fprintf(stderr, "IPFilter enabled?\n"); - exit(1); - } - if (ioctl(fd, SIOCGNATS, &nsp) == -1) { - perror("ioctl(SIOCGNATS)"); - exit(1); - } - (void) setgid(getgid()); - (void) setuid(getuid()); - } else if ((kernel != NULL) || (core != NULL)) { - if (openkmem(kernel, core) == -1) - exit(1); - - natstat_dead(nsp, kernel); - if (opts & (OPT_LIST|OPT_STAT)) - dostats(nsp, opts); - exit(0); - } - - if (opts & (OPT_FLUSH|OPT_CLEAR)) - flushtable(fd, opts); - if (file) - natparsefile(fd, file, opts); - if (opts & (OPT_LIST|OPT_STAT)) - dostats(nsp, opts); - return 0; -} - - -/* - * Read nat statistic information in using a symbol table and memory file - * rather than doing ioctl's. - */ -void natstat_dead(nsp, kernel) -natstat_t *nsp; -char *kernel; -{ - struct nlist nat_nlist[10] = { - { "nat_table" }, /* 0 */ - { "nat_list" }, - { "maptable" }, - { "ipf_nattable_sz" }, - { "ipf_natrules_sz" }, - { "ipf_rdrrules_sz" }, /* 5 */ - { "ipf_hostmap_sz" }, - { "nat_instances" }, - { "ap_sess_list" }, - { NULL } - }; - void *tables[2]; - - if (nlist(kernel, nat_nlist) == -1) { - fprintf(stderr, "nlist error\n"); - return; - } - - /* - * Normally the ioctl copies all of these values into the structure - * for us, before returning it to useland, so here we must copy each - * one in individually. - */ - kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables)); - nsp->ns_table[0] = tables[0]; - nsp->ns_table[1] = tables[1]; - - kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, - sizeof(nsp->ns_list)); - kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, - sizeof(nsp->ns_maptable)); - kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, - sizeof(nsp->ns_nattab_sz)); - kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, - sizeof(nsp->ns_rultab_sz)); - kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, - sizeof(nsp->ns_rdrtab_sz)); - kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, - sizeof(nsp->ns_hostmap_sz)); - kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, - sizeof(nsp->ns_instances)); - kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, - sizeof(nsp->ns_apslist)); -} - - -/* - * Display NAT statistics. - */ -void dostats(nsp, opts) -natstat_t *nsp; -int opts; -{ - nat_t **nt[2], *np, nat; - ipnat_t ipn; - - /* - * Show statistics ? - */ - if (opts & OPT_STAT) { - printf("mapped\tin\t%lu\tout\t%lu\n", - nsp->ns_mapped[0], nsp->ns_mapped[1]); - printf("added\t%lu\texpired\t%lu\n", - nsp->ns_added, nsp->ns_expire); - printf("no memory\t%lu\tbad nat\t%lu\n", - nsp->ns_memfail, nsp->ns_badnat); - printf("inuse\t%lu\nrules\t%lu\n", - nsp->ns_inuse, nsp->ns_rules); - printf("wilds\t%u\n", nsp->ns_wilds); - if (opts & OPT_VERBOSE) - printf("table %p list %p\n", - nsp->ns_table, nsp->ns_list); - } - - /* - * Show list of NAT rules and NAT sessions ? - */ - if (opts & OPT_LIST) { - printf("List of active MAP/Redirect filters:\n"); - while (nsp->ns_list) { - if (kmemcpy((char *)&ipn, (long)nsp->ns_list, - sizeof(ipn))) { - perror("kmemcpy"); - break; - } - if (opts & OPT_HITS) - printf("%d ", ipn.in_hits); - printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); - nsp->ns_list = ipn.in_next; - } - - nt[0] = (nat_t **)malloc(sizeof(*nt) * NAT_SIZE); - if (kmemcpy((char *)nt[0], (long)nsp->ns_table[0], - sizeof(**nt) * NAT_SIZE)) { - perror("kmemcpy"); - return; - } - - printf("\nList of active sessions:\n"); - - for (np = nsp->ns_instances; np; np = nat.nat_next) { - if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) - break; - printactivenat(&nat, opts); - } - - if (opts & OPT_VERBOSE) - showhostmap(nsp); - free(nt[0]); - } -} - - -/* - * display the active host mapping table. - */ -void showhostmap(nsp) -natstat_t *nsp; -{ - hostmap_t hm, *hmp, **maptable; - u_int hv; - - printf("\nList of active host mappings:\n"); - - maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) * - nsp->ns_hostmap_sz); - if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable, - sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) { - perror("kmemcpy (maptable)"); - return; - } - - for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { - hmp = maptable[hv]; - - while (hmp) { - if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) { - perror("kmemcpy (hostmap)"); - return; - } - - printhostmap(&hm, hv); - hmp = hm.hm_next; - } - } - free(maptable); -} - - -/* - * Issue an ioctl to flush either the NAT rules table or the active mapping - * table or both. - */ -void flushtable(fd, opts) -int fd, opts; -{ - int n = 0; - - if (opts & OPT_FLUSH) { - n = 0; - if (!(opts & OPT_NODO) && ioctl(fd, SIOCIPFFL, &n) == -1) - perror("ioctl(SIOCFLNAT)"); - else - printf("%d entries flushed from NAT table\n", n); - } - - if (opts & OPT_CLEAR) { - n = 1; - if (!(opts & OPT_NODO) && ioctl(fd, SIOCIPFFL, &n) == -1) - perror("ioctl(SIOCCNATL)"); - else - printf("%d entries flushed from NAT list\n", n); - } -} diff --git a/dist/ipf/ipsd/ipsd.c b/dist/ipf/ipsd/ipsd.c index 730a39da635b..12c7d73fbb2f 100644 --- a/dist/ipf/ipsd/ipsd.c +++ b/dist/ipf/ipsd/ipsd.c @@ -1,13 +1,10 @@ -/* $NetBSD: ipsd.c,v 1.2 2002/01/24 08:21:37 martti Exp $ */ +/* $NetBSD: ipsd.c,v 1.3 2004/03/28 09:00:55 martti Exp $ */ /* * (C)opyright 1995-1998 Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include #include @@ -37,7 +34,7 @@ #ifndef lint static const char sccsid[] = "@(#)ipsd.c 1.3 12/3/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: ipsd.c,v 2.1.4.1 2001/06/26 10:43:21 darrenr Exp"; +static const char rcsid[] = "@(#)Id: ipsd.c,v 2.2 2001/06/09 17:09:25 darrenr Exp"; #endif extern char *optarg; diff --git a/dist/ipf/ipsd/ipsd.h b/dist/ipf/ipsd/ipsd.h index cf07b12a952e..d195fc7f933c 100644 --- a/dist/ipf/ipsd/ipsd.h +++ b/dist/ipf/ipsd/ipsd.h @@ -1,13 +1,10 @@ -/* $NetBSD: ipsd.h,v 1.2 2002/01/24 08:21:37 martti Exp $ */ +/* $NetBSD: ipsd.h,v 1.3 2004/03/28 09:00:55 martti Exp $ */ /* * (C)opyright 1995-1998 Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * * @(#)ipsd.h 1.3 12/3/95 */ diff --git a/dist/ipf/ipsd/ipsdr.c b/dist/ipf/ipsd/ipsdr.c index 251ca9b3f49a..05da37b75555 100644 --- a/dist/ipf/ipsd/ipsdr.c +++ b/dist/ipf/ipsd/ipsdr.c @@ -1,13 +1,10 @@ -/* $NetBSD: ipsdr.c,v 1.2 2002/01/24 08:21:38 martti Exp $ */ +/* $NetBSD: ipsdr.c,v 1.3 2004/03/28 09:00:55 martti Exp $ */ /* * (C)opyright 1995-1998 Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include #include @@ -38,7 +35,7 @@ #ifndef lint static const char sccsid[] = "@(#)ipsdr.c 1.3 12/3/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: ipsdr.c,v 2.1.4.1 2001/06/26 10:43:21 darrenr Exp"; +static const char rcsid[] = "@(#)Id: ipsdr.c,v 2.2 2001/06/09 17:09:25 darrenr Exp"; #endif extern char *optarg; diff --git a/dist/ipf/ipsd/slinux.c b/dist/ipf/ipsd/slinux.c index 754e07460a92..6770db0a5178 100644 --- a/dist/ipf/ipsd/slinux.c +++ b/dist/ipf/ipsd/slinux.c @@ -1,13 +1,10 @@ -/* $NetBSD: slinux.c,v 1.2 2002/01/24 08:21:38 martti Exp $ */ +/* $NetBSD: slinux.c,v 1.3 2004/03/28 09:00:55 martti Exp $ */ /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include diff --git a/dist/ipf/ipsd/snit.c b/dist/ipf/ipsd/snit.c index a1b3ace347bc..7889b2bc6115 100644 --- a/dist/ipf/ipsd/snit.c +++ b/dist/ipf/ipsd/snit.c @@ -1,13 +1,10 @@ -/* $NetBSD: snit.c,v 1.2 2002/01/24 08:21:38 martti Exp $ */ +/* $NetBSD: snit.c,v 1.3 2004/03/28 09:00:55 martti Exp $ */ /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. * - * The author of this software makes no garuntee about the - * performance of this package or its suitability to fulfill any purpose. - * */ #include diff --git a/dist/ipf/ipsend/44arp.c b/dist/ipf/ipsend/44arp.c index 715ef15b42ef..1aaaca74f014 100644 --- a/dist/ipf/ipsend/44arp.c +++ b/dist/ipf/ipsend/44arp.c @@ -1,35 +1,37 @@ -/* $NetBSD: 44arp.c,v 1.3 2002/03/14 12:32:39 martti Exp $ */ +/* $NetBSD: 44arp.c,v 1.4 2004/03/28 09:00:55 martti Exp $ */ /* * Based upon 4.4BSD's /usr/sbin/arp */ -#ifdef __sgi -# include -#endif -#include -#include -#include #include #include #include #include #include +#if __FreeBSD_version >= 300000 +# include +#endif #include #include +#if defined(__FreeBSD__) +# include "radix_ipf.h" +#endif #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif #include "ipsend.h" #include "iplang/iplang.h" @@ -39,7 +41,7 @@ * its IP address in address * (4 bytes) */ -int resolve(host, address) +int resolve(host, address) char *host, *address; { struct hostent *hp; diff --git a/dist/ipf/ipsend/arp.c b/dist/ipf/ipsend/arp.c index a8f77475a8de..bfb8f06c2278 100644 --- a/dist/ipf/ipsend/arp.c +++ b/dist/ipf/ipsend/arp.c @@ -1,22 +1,21 @@ -/* $NetBSD: arp.c,v 1.3 2002/03/14 12:32:39 martti Exp $ */ +/* $NetBSD: arp.c,v 1.4 2004/03/28 09:00:55 martti Exp $ */ /* * arp.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "@(#)arp.c 1.4 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: arp.c,v 2.8 2003/12/01 02:01:15 darrenr Exp"; #endif -#include -#include #include #include -#if !defined(ultrix) && !defined(hpux) +#if !defined(ultrix) && !defined(hpux) && !defined(__hpux) && !defined(__osf__) #include #endif #include -#include +#include #include #include #include @@ -24,23 +23,22 @@ #include #endif #include +#include #include #include +#include +#include +#include #include "ipsend.h" #include "iplang/iplang.h" -#if !defined(lint) -static const char sccsid[] = "@(#)arp.c 1.4 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: arp.c,v 2.1.4.3 2002/02/22 15:32:57 darrenr Exp"; -#endif - /* * lookup host and return * its IP address in address * (4 bytes) */ -int resolve(host, address) +int resolve(host, address) char *host, *address; { struct hostent *hp; @@ -92,7 +90,11 @@ char *ether; bcopy(ip, (char *)&sin->sin_addr.s_addr, 4); #ifndef hpux if ((hp = gethostbyaddr(ip, 4, AF_INET))) +# if SOLARIS && (SOLARIS2 >= 10) + if (!(ether_hostton(hp->h_name, (struct ether_addr *)ether))) +# else if (!(ether_hostton(hp->h_name, ether))) +# endif goto savearp; #endif @@ -124,6 +126,13 @@ tryagain: return -1; } + if ((ar.arp_ha.sa_data[0] == 0) && (ar.arp_ha.sa_data[1] == 0) && + (ar.arp_ha.sa_data[2] == 0) && (ar.arp_ha.sa_data[3] == 0) && + (ar.arp_ha.sa_data[4] == 0) && (ar.arp_ha.sa_data[5] == 0)) { + fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr)); + return -1; + } + bcopy(ar.arp_ha.sa_data, ether, 6); savearp: bcopy(ether, ethersave, 6); diff --git a/dist/ipf/ipsend/dlcommon.c b/dist/ipf/ipsend/dlcommon.c index b4a874bf3376..a4811b3576a8 100644 --- a/dist/ipf/ipsend/dlcommon.c +++ b/dist/ipf/ipsend/dlcommon.c @@ -1,4 +1,4 @@ -/* $NetBSD: dlcommon.c,v 1.1.1.2 2004/03/28 08:56:14 martti Exp $ */ +/* $NetBSD: dlcommon.c,v 1.2 2004/03/28 09:00:55 martti Exp $ */ /* * Common (shared) DLPI test routines. diff --git a/dist/ipf/ipsend/hpux.c b/dist/ipf/ipsend/hpux.c index 91cce9e4c88e..c54b89c9f4d5 100644 --- a/dist/ipf/ipsend/hpux.c +++ b/dist/ipf/ipsend/hpux.c @@ -1,9 +1,11 @@ -/* $NetBSD: hpux.c,v 1.2 2002/01/24 08:21:39 martti Exp $ */ +/* $NetBSD: hpux.c,v 1.3 2004/03/28 09:00:55 martti Exp $ */ /* * (C)opyright 1997-1998 Darren Reed. (from tcplog) * - * See the IPFILTER.LICENCE file for details on licencing. + * 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. */ #include #include diff --git a/dist/ipf/ipsend/ip.c b/dist/ipf/ipsend/ip.c index 46b5ccd50201..d08370948cb6 100644 --- a/dist/ipf/ipsend/ip.c +++ b/dist/ipf/ipsend/ip.c @@ -1,27 +1,21 @@ -/* $NetBSD: ip.c,v 1.5 2002/04/09 02:32:54 thorpej Exp $ */ +/* $NetBSD: ip.c,v 1.6 2004/03/28 09:00:55 martti Exp $ */ /* * ip.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995"; +static const char rcsid[] = "@(#)Id: ip.c,v 2.8 2004/01/08 13:34:31 darrenr Exp"; #endif -#include -#include -#include -#include -#include +#include #include #include #include #include #include #include -#include -#include -#include #include #ifndef linux # include @@ -30,14 +24,13 @@ # include # endif #endif +#include +#include +#include +#include +#include #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "%W% %G% (C)1995"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ip.c,v 2.1.4.4 2002/02/22 15:32:57 darrenr Exp"; -#endif static char *ipbuf = NULL, *ethbuf = NULL; @@ -96,7 +89,8 @@ ip_t *ip; struct in_addr gwip; int frag; { - static struct in_addr last_gw; + static struct in_addr last_gw, local_ip; + static char local_arp[6] = { 0, 0, 0, 0, 0, 0}; static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; static u_short id = 0; ether_header_t *eh; @@ -106,7 +100,7 @@ int frag; if (!ipbuf) { ipbuf = (char *)malloc(65536); - if(!ipbuf) + if (!ipbuf) { perror("malloc failed"); return -2; @@ -131,18 +125,29 @@ int frag; iplen = ip->ip_len; ip->ip_len = htons(iplen); if (!(frag & 2)) { - if (!ip->ip_v) - ip->ip_v = IPVERSION; + if (!IP_V(ip)) + IP_V_A(ip, IPVERSION); if (!ip->ip_id) ip->ip_id = htons(id++); if (!ip->ip_ttl) ip->ip_ttl = 60; } + if (ip->ip_src.s_addr != local_ip.s_addr) { + if (arp((char *)&ip->ip_src, (char *)A_A local_arp) == -1) + { + perror("arp"); + return -2; + } + bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp)); + local_ip = ip->ip_src; + } else + bcopy(local_arp, (char *)A_A eh->ether_shost, 6); + if (!frag || (sizeof(*eh) + iplen < mtu)) { ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); @@ -159,14 +164,14 @@ int frag; char *s; int i, sent = 0, ts, hlen, olen; - hlen = ip->ip_hl << 2; + hlen = IP_HL(ip) << 2; if (mtu < (hlen + 8)) { fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", mtu, hlen); fprintf(stderr, "can't fragment data\n"); return -2; } - ol = (ip->ip_hl << 2) - sizeof(*ip); + ol = (IP_HL(ip) << 2) - sizeof(*ip); for (i = 0, s = (char*)(ip + 1); ol > 0; ) if (*s == IPOPT_EOL) { optcpy[i++] = *s; @@ -227,7 +232,7 @@ int frag; else if (!(ip->ip_off & htons(0x1fff))) { hlen = i + sizeof(*ip); - ip->ip_hl = (sizeof(*ip) + i) >> 2; + IP_HL_A(ip, (sizeof(*ip) + i) >> 2); bcopy(optcpy, (char *)(ip + 1), i); } } @@ -247,45 +252,46 @@ ip_t *ip; struct in_addr gwip; { static tcp_seq iss = 2; - struct tcpiphdr *ti; - tcphdr_t *t; + tcphdr_t *t, *t2; int thlen, i, iplen, hlen; u_32_t lbuf[20]; + ip_t *ip2; iplen = ip->ip_len; - hlen = ip->ip_hl << 2; + hlen = IP_HL(ip) << 2; t = (tcphdr_t *)((char *)ip + hlen); - ti = (struct tcpiphdr *)lbuf; - thlen = t->th_off << 2; + ip2 = (struct ip *)lbuf; + t2 = (tcphdr_t *)((char *)ip2 + hlen); + thlen = TCP_OFF(t) << 2; if (!thlen) thlen = sizeof(tcphdr_t); - bzero((char *)ti, sizeof(*ti)); + bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2)); ip->ip_p = IPPROTO_TCP; - ti->ti_pr = ip->ip_p; - ti->ti_src = ip->ip_src; - ti->ti_dst = ip->ip_dst; - bcopy((char *)ip + hlen, (char *)&ti->ti_sport, thlen); + ip2->ip_p = ip->ip_p; + ip2->ip_src = ip->ip_src; + ip2->ip_dst = ip->ip_dst; + bcopy((char *)ip + hlen, (char *)t2, thlen); - if (!ti->ti_win) - ti->ti_win = htons(4096); + if (!t2->th_win) + t2->th_win = htons(4096); iss += 63; i = sizeof(struct tcpiphdr) / sizeof(long); - if ((ti->ti_flags == TH_SYN) && !ntohs(ip->ip_off) && + if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) && (lbuf[i] != htonl(0x020405b4))) { lbuf[i] = htonl(0x020405b4); bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, iplen - thlen - hlen); thlen += 4; } - ti->ti_off = thlen >> 2; - ti->ti_len = htons(thlen); + TCP_OFF_A(t2, thlen >> 2); + ip2->ip_len = htons(thlen); ip->ip_len = hlen + thlen; - ti->ti_sum = 0; - ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); + t2->th_sum = 0; + t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t)); - bcopy((char *)&ti->ti_sport, (char *)ip + hlen, thlen); + bcopy((char *)t2, (char *)ip + hlen, thlen); return send_ip(nfd, mtu, ip, gwip, 1); } @@ -308,16 +314,16 @@ struct in_addr gwip; ti->ti_pr = ip->ip_p; ti->ti_src = ip->ip_src; ti->ti_dst = ip->ip_dst; - bcopy((char *)ip + (ip->ip_hl << 2), + bcopy((char *)ip + (IP_HL(ip) << 2), (char *)&ti->ti_sport, sizeof(udphdr_t)); ti->ti_len = htons(thlen); - ip->ip_len = (ip->ip_hl << 2) + thlen; + ip->ip_len = (IP_HL(ip) << 2) + thlen; ti->ti_sum = 0; ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); bcopy((char *)&ti->ti_sport, - (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); + (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t)); return send_ip(nfd, mtu, ip, gwip, 1); } @@ -332,7 +338,7 @@ struct in_addr gwip; { struct icmp *ic; - ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); + ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); ic->icmp_cksum = 0; ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); diff --git a/dist/ipf/ipsend/ip_var.h b/dist/ipf/ipsend/ip_var.h index a6c5cc4199db..157ac015c73b 100644 --- a/dist/ipf/ipsend/ip_var.h +++ b/dist/ipf/ipsend/ip_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip_var.h,v 1.2 2002/09/19 08:08:21 martti Exp $ */ +/* $NetBSD: ip_var.h,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* @(#)ip_var.h 1.11 88/08/19 SMI; from UCB 7.1 6/5/86 */ @@ -46,7 +46,7 @@ struct ipq { * Note: ipf_next must be at same offset as ipq_next above */ struct ipasfrag { -#if defined(vax) || defined(i386) || defined(__i386__) +#if defined(vax) || defined(i386) u_char ip_hl:4, ip_v:4; #endif diff --git a/dist/ipf/ipsend/ipresend.c b/dist/ipf/ipsend/ipresend.c index 1ed4edcf296d..cb6ecd4a462d 100644 --- a/dist/ipf/ipsend/ipresend.c +++ b/dist/ipf/ipsend/ipresend.c @@ -1,46 +1,33 @@ -/* $NetBSD: ipresend.c,v 1.4 2002/04/09 02:32:54 thorpej Exp $ */ +/* $NetBSD: ipresend.c,v 1.5 2004/03/28 09:00:56 martti Exp $ */ /* * ipresend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipresend.c,v 2.4 2004/01/08 13:34:31 darrenr Exp"; #endif -#include -#include -#include -#include -#include -#include #include +#include #include #include #include #include #include #include -#include -#include -#include #ifndef linux #include #endif +#include +#include +#include +#include +#include #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "%W% %G% (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipresend.c,v 2.1.4.3 2002/02/22 15:32:57 darrenr Exp"; -#endif - extern char *optarg; extern int optind; diff --git a/dist/ipf/ipsend/ipsend.c b/dist/ipf/ipsend/ipsend.c index 708819d60560..dd95f3a9b304 100644 --- a/dist/ipf/ipsend/ipsend.c +++ b/dist/ipf/ipsend/ipsend.c @@ -1,23 +1,14 @@ -/* $NetBSD: ipsend.c,v 1.8 2002/05/30 18:10:32 thorpej Exp $ */ +/* $NetBSD: ipsend.c,v 1.9 2004/03/28 09:00:56 martti Exp $ */ /* * ipsend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipsend.c,v 2.8.2.1 2004/03/23 12:58:05 darrenr Exp"; #endif -#include -#include -#include -#include -#include #include #include #include @@ -25,20 +16,19 @@ #include #include #include +#include +#include +#include +#include +#include #include -#include -#include -#include #ifndef linux -#include +# include #endif #include "ipsend.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipsend.c,v 2.2.2.5 2002/04/23 14:58:57 darrenr Exp"; +#include "ipf.h" +#ifndef linux +# include #endif @@ -48,31 +38,32 @@ extern void iplang __P((FILE *)); char options[68]; int opts; -#ifdef linux +#ifdef linux char default_device[] = "eth0"; #else -# ifdef sun -char default_device[] = "le0"; -# else -# ifdef ultrix +# ifdef ultrix char default_device[] = "ln0"; -# else -# ifdef __bsdi__ +# else +# ifdef __bsdi__ char default_device[] = "ef0"; -# else -# ifdef __sgi +# else +# ifdef __sgi char default_device[] = "ec0"; -# else +# else +# ifdef __hpux char default_device[] = "lan0"; -# endif -# endif -# endif -# endif -#endif +# else +char default_device[] = "le0"; +# endif /* __hpux */ +# endif /* __sgi */ +# endif /* __bsdi__ */ +# endif /* ultrix */ +#endif /* linux */ static void usage __P((char *)); static void do_icmp __P((ip_t *, char *)); +void udpcksum(ip_t *, struct udphdr *, int); int main __P((int, char **)); @@ -162,25 +153,52 @@ int mtu; ip_t *ip; struct in_addr gwip; { - u_short sport = 0; - int wfd; - - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) - sport = ((struct tcpiphdr *)ip)->ti_sport; - wfd = initdevice(dev, sport, 5); + int wfd; + wfd = initdevice(dev, 5); return send_packet(wfd, mtu, ip, gwip); } +void +udpcksum(ip_t *ip, struct udphdr *udp, int len) +{ + union pseudoh { + struct hdr { + u_short len; + u_char ttl; + u_char proto; + u_32_t src; + u_32_t dst; + } h; + u_short w[6]; + } ph; + u_32_t temp32; + u_short cksum, *opts; + + ph.h.len = htons(len); + ph.h.ttl = 0; + ph.h.proto = IPPROTO_UDP; + ph.h.src = ip->ip_src.s_addr; + ph.h.dst = ip->ip_dst.s_addr; + temp32 = 0; + opts = &ph.w[0]; + temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5]; + temp32 = (temp32 >> 16) + (temp32 & 65535); + temp32 += (temp32 >> 16); + udp->uh_sum = temp32 & 65535; + udp->uh_sum = chksum((u_short *)udp, len); + if (udp->uh_sum == 0) + udp->uh_sum = 0xffff; +} int main(argc, argv) int argc; char **argv; { FILE *langfile = NULL; - struct tcpiphdr *ti; struct in_addr gwip; tcphdr_t *tcp; + udphdr_t *udp; ip_t *ip; char *name = argv[0], host[MAXHOSTNAMELEN + 1]; char *gateway = NULL, *dev = NULL; @@ -191,12 +209,12 @@ char **argv; * 65535 is maximum packet size...you never know... */ ip = (ip_t *)calloc(1, 65536); - ti = (struct tcpiphdr *)ip; - tcp = (tcphdr_t *)&ti->ti_sport; + tcp = (tcphdr_t *)(ip + 1); + udp = (udphdr_t *)tcp; ip->ip_len = sizeof(*ip); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); - while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) + while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) { switch (c) { case 'I' : @@ -290,7 +308,7 @@ char **argv; break; case 'o' : nonl++; - olen = buildopts(optarg, options, (ip->ip_hl - 5) << 2); + olen = buildopts(optarg, options, (IP_HL(ip) - 5) << 2); break; case 's' : nonl++; @@ -315,6 +333,7 @@ char **argv; fprintf(stderr, "Unknown option \"%c\"\n", c); usage(name); } + } if (argc - optind < 1) usage(name); @@ -348,25 +367,30 @@ char **argv; if (olen) { - caddr_t ipo = (caddr_t)ip; + int hlen; + char *p; printf("Options: %d\n", olen); - ti = (struct tcpiphdr *)malloc(olen + ip->ip_len); - if(!ti) - { - fprintf(stderr,"malloc failed\n"); - exit(2); - } - - bcopy((char *)ip, (char *)ti, sizeof(*ip)); - ip = (ip_t *)ti; - ip->ip_hl = (olen >> 2); - bcopy(options, (char *)(ip + 1), olen); - bcopy((char *)tcp, (char *)(ip + 1) + olen, sizeof(*tcp)); + hlen = sizeof(*ip) + olen; + IP_HL_A(ip, hlen >> 2); ip->ip_len += olen; - bcopy((char *)ip, (char *)ipo, ip->ip_len); - ip = (ip_t *)ipo; - tcp = (tcphdr_t *)((char *)(ip + 1) + olen); + p = (char *)malloc(65536); + if (p == NULL) + { + fprintf(stderr, "malloc failed\n"); + exit(2); + } + + bcopy(ip, p, sizeof(*ip)); + bcopy(options, p + sizeof(*ip), olen); + bcopy(ip + 1, p + hlen, ip->ip_len - hlen); + ip = (ip_t *)p; + + if (ip->ip_p == IPPROTO_TCP) { + tcp = (tcphdr_t *)(p + hlen); + } else if (ip->ip_p == IPPROTO_UDP) { + udp = (udphdr_t *)(p + hlen); + } } if (ip->ip_p == IPPROTO_TCP) @@ -403,9 +427,13 @@ char **argv; printf("Flags: %#x\n", tcp->th_flags); printf("mtu: %d\n", mtu); + if (ip->ip_p == IPPROTO_UDP) { + udp->uh_sum = 0; + udpcksum(ip, udp, ip->ip_len - (IP_HL(ip) << 2)); + } #ifdef DOSOCKET - if (tcp->th_dport) - return do_socket(dev, mtu, ti, gwip); + if (ip->ip_p == IPPROTO_TCP && tcp->th_dport) + return do_socket(dev, mtu, ip, gwip); #endif - return send_packets(dev, mtu, (ip_t *)ti, gwip); + return send_packets(dev, mtu, ip, gwip); } diff --git a/dist/ipf/ipsend/ipsend.h b/dist/ipf/ipsend/ipsend.h index f2bf09f29209..5d403d115d94 100644 --- a/dist/ipf/ipsend/ipsend.h +++ b/dist/ipf/ipsend/ipsend.h @@ -1,4 +1,4 @@ -/* $NetBSD: ipsend.h,v 1.2 2002/01/24 08:21:39 martti Exp $ */ +/* $NetBSD: ipsend.h,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* * ipsend.h (C) 1997-1998 Darren Reed @@ -8,7 +8,11 @@ * conditions, enough of the TCP header is missing for unpredictable * results unless the filter is aware that this can happen. * - * See the IPFILTER.LICENCE file for details on licencing. + * The author provides this program as-is, with no gaurantee for its + * suitability for any specific purpose. The author takes no responsibility + * for the misuse/abuse of this program and provides it for the sole purpose + * of testing packet filter policies. This file maybe distributed freely + * providing it is not modified and that this notice remains in tact. * */ #ifndef __P @@ -19,13 +23,14 @@ # endif #endif -#include "ip_compat.h" +#include + +#include "ipf.h" #ifdef linux #include #endif #include "tcpip.h" #include "ipt.h" -#include "ipf.h" extern int resolve __P((char *, char *)); extern int arp __P((char *, char *)); @@ -37,10 +42,10 @@ extern int send_udp __P((int, int, ip_t *, struct in_addr)); extern int send_icmp __P((int, int, ip_t *, struct in_addr)); extern int send_packet __P((int, int, ip_t *, struct in_addr)); extern int send_packets __P((char *, int, ip_t *, struct in_addr)); -extern u_short seclevel __P((char *)); +extern u_short ipseclevel __P((char *)); extern u_32_t buildopts __P((char *, char *, int)); extern int addipopt __P((char *, struct ipopt_names *, int, char *)); -extern int initdevice __P((char *, int, int)); +extern int initdevice __P((char *, int)); extern int sendip __P((int, char *, int)); #ifdef linux extern struct sock *find_tcp __P((int, struct tcpiphdr *)); @@ -57,7 +62,6 @@ extern void ip_test5 __P((char *, int, ip_t *, struct in_addr, int)); extern void ip_test6 __P((char *, int, ip_t *, struct in_addr, int)); extern void ip_test7 __P((char *, int, ip_t *, struct in_addr, int)); extern int do_socket __P((char *, int, struct tcpiphdr *, struct in_addr)); -extern int openkmem __P((void)); extern int kmemcpy __P((char *, void *, int)); #define KMCPY(a,b,c) kmemcpy((char *)(a), (void *)(b), (int)(c)) @@ -65,9 +69,3 @@ extern int kmemcpy __P((char *, void *, int)); #ifndef OPT_RAW #define OPT_RAW 0x80000 #endif - -#ifndef __STDC__ -# ifndef const -# define const -# endif -#endif diff --git a/dist/ipf/ipsend/ipsopt.c b/dist/ipf/ipsend/ipsopt.c index 3fd0905242b4..d3a0288b05f2 100644 --- a/dist/ipf/ipsend/ipsopt.c +++ b/dist/ipf/ipsend/ipsopt.c @@ -1,23 +1,25 @@ -/* $NetBSD: ipsopt.c,v 1.4 2002/04/09 02:32:54 thorpej Exp $ */ +/* $NetBSD: ipsopt.c,v 1.5 2004/03/28 09:00:56 martti Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: ipsopt.c,v 2.4.4.1 2004/03/23 12:58:05 darrenr Exp"; #endif #include -#include -#include -#include #include #include #include #include #include #include +#include +#include +#include #ifndef linux #include #endif @@ -25,11 +27,13 @@ #include #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipsopt.c,v 2.1.4.3 2002/02/22 15:32:58 darrenr Exp"; + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif #endif @@ -57,7 +61,7 @@ struct ipopt_names secnames[] = { }; -u_short seclevel(slevel) +u_short ipseclevel(slevel) char *slevel; { struct ipopt_names *so; @@ -102,14 +106,17 @@ char *class; len += val; } else *op++ = io->on_siz; - *op++ = IPOPT_MINOFF; + if (io->on_value == IPOPT_TS) + *op++ = IPOPT_MINOFF + 1; + else + *op++ = IPOPT_MINOFF; while (class && *class) { t = NULL; switch (io->on_value) { case IPOPT_SECURITY : - lvl = seclevel(class); + lvl = ipseclevel(class); *(op - 1) = lvl; break; case IPOPT_LSRR : diff --git a/dist/ipf/ipsend/iptest.c b/dist/ipf/ipsend/iptest.c index 1087ed6a07d9..f9dae5de55d4 100644 --- a/dist/ipf/ipsend/iptest.c +++ b/dist/ipf/ipsend/iptest.c @@ -1,23 +1,15 @@ -/* $NetBSD: iptest.c,v 1.5 2002/04/09 02:32:54 thorpej Exp $ */ +/* $NetBSD: iptest.c,v 1.6 2004/03/28 09:00:56 martti Exp $ */ /* * ipsend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: iptest.c,v 2.6 2004/01/08 13:34:31 darrenr Exp"; #endif -#include -#include -#include -#include -#include #include #include #include @@ -26,24 +18,19 @@ #include #include #include -#include -#include -#include #ifndef linux #include #endif #ifdef linux #include #endif +#include +#include +#include +#include +#include #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "%W% %G% (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: iptest.c,v 2.2.2.3 2002/02/22 15:32:58 darrenr Exp"; -#endif - extern char *optarg; extern int optind; @@ -115,7 +102,7 @@ char **argv; ip = (ip_t *)calloc(1, 65536); ti = (struct tcpiphdr *)ip; ip->ip_len = sizeof(*ip); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); while ((c = getopt(argc, argv, "1234567d:g:m:p:s:")) != -1) switch (c) diff --git a/dist/ipf/ipsend/iptests.c b/dist/ipf/ipsend/iptests.c index 4d9bdd1ef529..d421e13d00f9 100644 --- a/dist/ipf/ipsend/iptests.c +++ b/dist/ipf/ipsend/iptests.c @@ -1,37 +1,38 @@ -/* $NetBSD: iptests.c,v 1.5 2002/09/20 15:00:06 mycroft Exp $ */ +/* $NetBSD: iptests.c,v 1.6 2004/03/28 09:00:56 martti Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: iptests.c,v 2.8.2.1 2004/03/23 12:58:06 darrenr Exp"; #endif -#include -#include -#include -#include +#include #include #include -#include -#define _KERNEL -#define KERNEL -#if !defined(solaris) && !defined(linux) && !defined(__sgi) -# include -#else -# ifdef solaris -# include +#if !defined(__osf__) +# define _KERNEL +# define KERNEL +# if !defined(solaris) && !defined(linux) && !defined(__sgi) && !defined(hpux) +# include +# else +# ifdef solaris +# include +# endif # endif +# undef _KERNEL +# undef KERNEL #endif -#undef _KERNEL -#undef KERNEL #if !defined(solaris) && !defined(linux) && !defined(__sgi) # include # include # include #endif -#if !defined(ultrix) && !defined(hpux) && !defined(linux) && !defined(__sgi) +#if !defined(ultrix) && !defined(hpux) && !defined(linux) && \ + !defined(__sgi) && !defined(__osf__) # include #endif #ifndef ultrix @@ -52,11 +53,17 @@ #endif #include #include +#ifdef __hpux +# define _NET_ROUTE_INCLUDED +#endif #include #if defined(linux) && (LINUX >= 0200) # include #endif #if !defined(linux) +# if defined(__FreeBSD__) +# include "radix_ipf.h" +# endif # include #else # define __KERNEL__ /* because there's a macro not wrapped by this */ @@ -65,28 +72,29 @@ #include #include #include -#include -#include -#include -#ifndef linux +#if !defined(linux) # include -# include -# include -# include +# if !defined(__hpux) +# include +# endif #endif #if defined(__SVR4) || defined(__svr4__) || defined(__sgi) # include #endif -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000000) -# define USE_NANOSLEEP +#include +#include +#include +#include +#ifdef __hpux +# undef _NET_ROUTE_INCLUDED #endif #include "ipsend.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "%W% %G% (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: iptests.c,v 2.1.4.5 2002/02/22 15:32:58 darrenr Exp"; +#if !defined(linux) && !defined(__hpux) +# include +# include +#endif +#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000000) +# define USE_NANOSLEEP #endif @@ -114,8 +122,8 @@ int ptest; udphdr_t *u; int nfd, i = 0, len, id = getpid(); - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; @@ -128,7 +136,7 @@ int ptest; u->uh_ulen = htons(sizeof(*u) + 4); ip->ip_len = sizeof(*ip) + ntohs(u->uh_ulen); len = ip->ip_len; - nfd = initdevice(dev, u->uh_sport, 1); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* @@ -137,7 +145,7 @@ int ptest; ip->ip_id = 0; printf("1.1. sending packets with ip_hl < ip_len\n"); for (i = 0; i < ((sizeof(*ip) + ntohs(u->uh_ulen)) >> 2); i++) { - ip->ip_hl = i >> 2; + IP_HL_A(ip, i >> 2); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -153,7 +161,7 @@ int ptest; ip->ip_id = 0; printf("1.2. sending packets with ip_hl > ip_len\n"); for (; i < ((sizeof(*ip) * 2 + ntohs(u->uh_ulen)) >> 2); i++) { - ip->ip_hl = i >> 2; + IP_HL_A(ip, i >> 2); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -168,9 +176,9 @@ int ptest; */ ip->ip_id = 0; printf("1.3. ip_v < 4\n"); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); for (i = 0; i < 4; i++) { - ip->ip_v = i; + IP_V_A(ip, i); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -186,7 +194,7 @@ int ptest; ip->ip_id = 0; printf("1.4. ip_v > 4\n"); for (i = 5; i < 16; i++) { - ip->ip_v = i; + IP_V_A(ip, i); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d\r", i); fflush(stdout); @@ -200,13 +208,13 @@ int ptest; * Part5: len < packet */ ip->ip_id = 0; - ip->ip_v = IPVERSION; + IP_V_A(ip, IPVERSION); i = ip->ip_len + 1; printf("1.5.0 ip_len < packet size (size++, long packets)\n"); for (; i < (ip->ip_len * 2); i++) { ip->ip_id = htons(id++); ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, i, gwip); printf("%d\r", i); fflush(stdout); @@ -218,7 +226,7 @@ int ptest; ip->ip_id = htons(id++); ip->ip_len = i; ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, len, gwip); printf("%d\r", i); fflush(stdout); @@ -237,7 +245,7 @@ int ptest; ip->ip_id = htons(id++); ip->ip_len = i; ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, len, gwip); printf("%d\r", i); fflush(stdout); @@ -249,7 +257,7 @@ int ptest; for (i = len; i > 0; i--) { ip->ip_id = htons(id++); ip->ip_sum = 0; - ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); (void) send_ether(nfd, (char *)ip, i, gwip); printf("%d\r", i); fflush(stdout); @@ -318,14 +326,14 @@ int ptest; ip->ip_len = MIN(768 + 20, mtu - 68); i = 512; for (; i < (63 * 1024 + 768); i += 768) { - ip->ip_off = htons(IP_MF | ((i >> 3) & 0x1fff)); + ip->ip_off = htons(IP_MF | (i >> 3)); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); fflush(stdout); PAUSE(); } ip->ip_len = 896 + 20; - ip->ip_off = htons((i >> 3) & 0x1fff); + ip->ip_off = htons(i >> 3); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); putchar('\n'); @@ -352,7 +360,7 @@ int ptest; ip->ip_len = MIN(768 + 20, mtu - 68); i = 512; for (; i < (63 * 1024 + 768); i += 768) { - ip->ip_off = htons(IP_MF | ((i >> 3) & 0x1fff)); + ip->ip_off = htons(IP_MF | (i >> 3)); if ((rand() & 0x1f) != 0) { (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); @@ -362,7 +370,7 @@ int ptest; PAUSE(); } ip->ip_len = 896 + 20; - ip->ip_off = htons((i >> 3) & 0x1fff); + ip->ip_off = htons(i >> 3); if ((rand() & 0x1f) != 0) { (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); @@ -389,14 +397,14 @@ int ptest; ip->ip_len = MIN(768 + 20, mtu - 68); i = 512; for (; i < (32 * 1024 + 768); i += 768) { - ip->ip_off = htons(IP_MF | ((i >> 3) & 0x1fff)); + ip->ip_off = htons(IP_MF | (i >> 3)); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); fflush(stdout); PAUSE(); } ip->ip_len = 896 + 20; - ip->ip_off = htons((i >> 3) & 0x1fff); + ip->ip_off = htons(i >> 3); (void) send_ip(nfd, mtu, ip, gwip, 1); printf("%d\r", i); putchar('\n'); @@ -463,10 +471,10 @@ int ptest; u_char *s; s = (u_char *)(ip + 1); - nfd = initdevice(dev, htons(1), 1); + nfd = initdevice(dev, 1); - ip->ip_hl = 6; - ip->ip_len = ip->ip_hl << 2; + IP_HL_A(ip, 6); + ip->ip_len = IP_HL(ip) << 2; s[IPOPT_OPTVAL] = IPOPT_NOP; s++; if (!ptest || (ptest == 1)) { @@ -484,8 +492,8 @@ int ptest; PAUSE(); } - ip->ip_hl = 7; - ip->ip_len = ip->ip_hl << 2; + IP_HL_A(ip, 7); + ip->ip_len = IP_HL(ip) << 2; if (!ptest || (ptest == 1)) { /* * Test 2: options have length = 0 @@ -557,16 +565,16 @@ int ptest; struct icmp *icp; int nfd, i; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; ip->ip_p = IPPROTO_ICMP; ip->ip_sum = 0; ip->ip_len = sizeof(*ip) + sizeof(*icp); - icp = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); - nfd = initdevice(dev, htons(1), 1); + icp = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* @@ -754,25 +762,25 @@ int ptest; int nfd, i; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_v = IPVERSION; + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; ip->ip_p = IPPROTO_UDP; ip->ip_sum = 0; - u = (udphdr_t *)((char *)ip + (ip->ip_hl << 2)); + u = (udphdr_t *)((char *)ip + (IP_HL(ip) << 2)); u->uh_sport = htons(1); u->uh_dport = htons(1); u->uh_ulen = htons(sizeof(*u) + 4); - nfd = initdevice(dev, u->uh_sport, 1); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* * Test 1. ulen > packet */ u->uh_ulen = htons(sizeof(*u) + 4); - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.1 UDP uh_ulen > packet size - short packets\n"); for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) { u->uh_ulen = htons(i); @@ -789,7 +797,7 @@ int ptest; * Test 2. ulen < packet */ u->uh_ulen = htons(sizeof(*u) + 4); - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.2 UDP uh_ulen < packet size - short packets\n"); for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) { ip->ip_len = i; @@ -807,7 +815,7 @@ int ptest; * sport = 32768, sport = 65535 */ u->uh_ulen = sizeof(*u) + 4; - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.3.1 UDP sport = 0\n"); u->uh_sport = 0; (void) send_udp(nfd, 1500, ip, gwip); @@ -848,7 +856,7 @@ int ptest; */ u->uh_ulen = ntohs(sizeof(*u) + 4); u->uh_sport = htons(1); - ip->ip_len = (ip->ip_hl << 2) + ntohs(u->uh_ulen); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); printf("4.4.1 UDP dport = 0\n"); u->uh_dport = 0; (void) send_udp(nfd, 1500, ip, gwip); @@ -915,11 +923,11 @@ int ptest; tcphdr_t *t; int nfd, i; - t = (tcphdr_t *)((char *)ip + (ip->ip_hl << 2)); -#ifndef linux + t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); +#if !defined(linux) && !defined(__osf__) t->th_x2 = 0; #endif - t->th_off = 0; + TCP_OFF_A(t, 0); t->th_sport = htons(1); t->th_dport = htons(1); t->th_win = htons(4096); @@ -928,13 +936,13 @@ int ptest; t->th_seq = htonl(1); t->th_ack = 0; ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t); - nfd = initdevice(dev, t->th_sport, 1); + nfd = initdevice(dev, 1); if (!ptest || (ptest == 1)) { /* * Test 1: flags variations, 0 - 3f */ - t->th_off = sizeof(*t) >> 2; + TCP_OFF_A(t, sizeof(*t) >> 2); printf("5.1 Test TCP flag combinations\n"); for (i = 0; i <= (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN); i++) { @@ -1058,14 +1066,13 @@ int ptest; } #if !defined(linux) && !defined(__SVR4) && !defined(__svr4__) && \ - !defined(__sgi) + !defined(__sgi) && !defined(__hpux) && !defined(__osf__) { struct tcpcb *tcbp, tcb; struct tcpiphdr ti; struct sockaddr_in sin; int fd, slen; - fd = -1; bzero((char *)&sin, sizeof(sin)); for (i = 1; i < 63; i++) { @@ -1134,7 +1141,7 @@ int ptest; t->th_flags = TH_ACK; printf("5.6.1 TCP off = 1-15, len = 40\n"); for (i = 1; i < 16; i++) { - ti.ti_off = ntohs(i); + TCP_OFF_A(t, ntohs(i)); (void) send_tcp(nfd, mtu, ip, gwip); printf("%d\r", i); fflush(stdout); @@ -1150,7 +1157,7 @@ skip_five_and_six: #endif t->th_seq = htonl(1); t->th_ack = htonl(1); - t->th_off = 0; + TCP_OFF_A(t, 0); if (!ptest || (ptest == 7)) { t->th_flags = TH_SYN; @@ -1262,7 +1269,7 @@ int ptest; udphdr_t *u; int nfd, i, j, k; - ip->ip_v = IPVERSION; + IP_V_A(ip, IPVERSION); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_ttl = 60; @@ -1273,7 +1280,7 @@ int ptest; u->uh_dport = htons(9); u->uh_sum = 0; - nfd = initdevice(dev, u->uh_sport, 1); + nfd = initdevice(dev, 1); u->uh_ulen = htons(7168); printf("6. Exhaustive mbuf test.\n"); @@ -1284,7 +1291,7 @@ int ptest; * First send the entire packet in 768 byte chunks. */ ip->ip_len = sizeof(*ip) + 768 + sizeof(*u); - ip->ip_hl = sizeof(*ip) >> 2; + IP_HL_A(ip, sizeof(*ip) >> 2); ip->ip_off = htons(IP_MF); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d %d\r", i, 0); @@ -1302,7 +1309,7 @@ int ptest; for (j = 768; j < 3584; j += 768) { ip->ip_len = sizeof(*ip) + 768; - ip->ip_off = htons(IP_MF|((j>>3) & 0x1fff)); + ip->ip_off = htons(IP_MF|(j>>3)); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d %d\r", i, j); fflush(stdout); @@ -1310,7 +1317,7 @@ int ptest; ip->ip_len = sizeof(*ip) + 128; for (k = j - 768; k < j; k += 128) { - ip->ip_off = htons(IP_MF|((k>>3) & 0x1fff)); + ip->ip_off = htons(IP_MF|(k>>3)); (void) send_ip(nfd, 1500, ip, gwip, 1); printf("%d %d\r", i, k); fflush(stdout); @@ -1342,7 +1349,7 @@ int ptest; int nfd, i, j; u_char *s; - nfd = initdevice(dev, 0, 1); + nfd = initdevice(dev, 1); pip = (ip_t *)tbuf; srand(time(NULL) ^ (getpid() * getppid())); @@ -1352,7 +1359,7 @@ int ptest; for (i = 0; i < 512; i++) { for (s = (u_char *)pip, j = 0; j < sizeof(tbuf); j++, s++) *s = (rand() >> 13) & 0xff; - pip->ip_v = IPVERSION; + IP_V_A(pip, IPVERSION); bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst, sizeof(struct in_addr)); pip->ip_sum = 0; @@ -1367,7 +1374,7 @@ int ptest; for (i = 0; i < 512; i++) { for (s = (u_char *)pip, j = 0; j < sizeof(tbuf); j++, s++) *s = (rand() >> 13) & 0xff; - pip->ip_v = IPVERSION; + IP_V_A(pip, IPVERSION); pip->ip_off &= htons(0xc000); bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst, sizeof(struct in_addr)); diff --git a/dist/ipf/ipsend/larp.c b/dist/ipf/ipsend/larp.c index 65ff2cf0e857..eb6d1f9c882e 100644 --- a/dist/ipf/ipsend/larp.c +++ b/dist/ipf/ipsend/larp.c @@ -1,23 +1,25 @@ -/* $NetBSD: larp.c,v 1.2 2002/01/24 08:21:40 martti Exp $ */ +/* $NetBSD: larp.c,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* * larp.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. + * */ #if !defined(lint) static const char sccsid[] = "@(#)larp.c 1.1 8/19/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: larp.c,v 2.1.4.1 2001/06/26 10:43:22 darrenr Exp"; +static const char rcsid[] = "@(#)Id: larp.c,v 2.4 2003/12/01 02:01:16 darrenr Exp"; #endif -#include -#include +#include #include #include #include -#include #include #include #include +#include +#include +#include #include "ip_compat.h" #include "iplang/iplang.h" @@ -27,7 +29,7 @@ static const char rcsid[] = "@(#)Id: larp.c,v 2.1.4.1 2001/06/26 10:43:22 darren * its IP address in address * (4 bytes) */ -int resolve(host, address) +int resolve(host, address) char *host, *address; { struct hostent *hp; diff --git a/dist/ipf/ipsend/linux.h b/dist/ipf/ipsend/linux.h index ad71b8194c16..63e0c2c51c08 100644 --- a/dist/ipf/ipsend/linux.h +++ b/dist/ipf/ipsend/linux.h @@ -1,9 +1,11 @@ -/* $NetBSD: linux.h,v 1.2 2002/01/24 08:21:40 martti Exp $ */ +/* $NetBSD: linux.h,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. * - * See the IPFILTER.LICENCE file for details on licencing. + * This code may be freely distributed as long as it retains this notice + * and is not changed in any way. The author accepts no responsibility + * for the use of this software. I hate legaleese, don't you ? * * @(#)linux.h 1.1 8/19/95 */ diff --git a/dist/ipf/ipsend/lsock.c b/dist/ipf/ipsend/lsock.c index d5c8a51deb4b..9ff16a9d0939 100644 --- a/dist/ipf/ipsend/lsock.c +++ b/dist/ipf/ipsend/lsock.c @@ -1,16 +1,14 @@ -/* $NetBSD: lsock.c,v 1.3 2002/03/14 12:32:40 martti Exp $ */ +/* $NetBSD: lsock.c,v 1.4 2004/03/28 09:00:56 martti Exp $ */ /* * lsock.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. + * */ #if !defined(lint) static const char sccsid[] = "@(#)lsock.c 1.2 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: lsock.c,v 2.1.4.2 2002/02/22 15:32:58 darrenr Exp"; -#endif -#ifdef __sgi -# include +static const char rcsid[] = "@(#)Id: lsock.c,v 2.3 2001/06/09 17:09:26 darrenr Exp"; #endif #include #include @@ -228,7 +226,7 @@ struct in_addr gwip; (void) getsockname(fd, (struct sockaddr *)&lsin, &len); ti->ti_sport = lsin.sin_port; printf("sport %d\n", ntohs(lsin.sin_port)); - nfd = initdevice(dev, ntohs(lsin.sin_port), 0); + nfd = initdevice(dev, 0); if (!(s = find_tcp(fd, ti))) return -1; diff --git a/dist/ipf/ipsend/resend.c b/dist/ipf/ipsend/resend.c index f4cbb65fb904..ce7be6a04645 100644 --- a/dist/ipf/ipsend/resend.c +++ b/dist/ipf/ipsend/resend.c @@ -1,23 +1,16 @@ -/* $NetBSD: resend.c,v 1.5 2002/04/09 02:32:54 thorpej Exp $ */ +/* $NetBSD: resend.c,v 1.6 2004/03/28 09:00:56 martti Exp $ */ /* * resend.c (C) 1995-1998 Darren Reed * - * This was written to test what size TCP fragments would get through - * various TCP/IP packet filters, as used in IP firewalls. In certain - * conditions, enough of the TCP header is missing for unpredictable - * results unless the filter is aware that this can happen. - * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: resend.c,v 2.8 2004/01/08 13:34:31 darrenr Exp"; #endif -#include -#include -#include -#include -#include +#include #include #include #include @@ -26,9 +19,6 @@ #include #include #include -#include -#include -#include #ifndef linux # include # include @@ -36,16 +26,13 @@ # include # endif #endif +#include +#include +#include +#include +#include #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: resend.c,v 2.1.4.4 2002/02/22 15:32:58 darrenr Exp"; -#endif - - extern int opts; static u_char pbuf[65536]; /* 1 big packet */ @@ -58,7 +45,7 @@ ip_t *ip; tcphdr_t *t; int i, j; - t = (tcphdr_t *)((char *)ip + (ip->ip_hl << 2)); + t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); if (ip->ip_tos) printf("tos %#x ", ip->ip_tos); if (ip->ip_off & 0x3fff) @@ -92,13 +79,13 @@ char *datain; ether_header_t *eh; char dhost[6]; ip_t *ip; - int fd, wfd = initdevice(dev, 0, 5), len, i; + int fd, wfd = initdevice(dev, 5), len, i; if (datain) fd = (*r->r_open)(datain); else fd = (*r->r_open)("-"); - + if (fd < 0) exit(-1); @@ -134,7 +121,7 @@ char *datain; sizeof(dhost)); if (!ip->ip_sum) ip->ip_sum = chksum((u_short *)ip, - ip->ip_hl << 2); + IP_HL(ip) << 2); bcopy(ip, (char *)(eh + 1), len); len += sizeof(*eh); printpacket(ip); diff --git a/dist/ipf/ipsend/sbpf.c b/dist/ipf/ipsend/sbpf.c index 513e28c06fed..e9c3b583e557 100644 --- a/dist/ipf/ipsend/sbpf.c +++ b/dist/ipf/ipsend/sbpf.c @@ -1,20 +1,13 @@ -/* $NetBSD: sbpf.c,v 1.3 2002/04/09 02:32:55 thorpej Exp $ */ +/* $NetBSD: sbpf.c,v 1.4 2004/03/28 09:00:56 martti Exp $ */ /* * (C)opyright 1995-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include #include #include @@ -39,13 +32,21 @@ #include #include #include + +#include +#include +#include +#include +#include +#include +#include +#include + #include "ipsend.h" #if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)sbpf.c 1.3 8/25/95 (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: sbpf.c,v 2.1.4.2 2001/09/30 04:04:28 darrenr Exp"; +static const char sccsid[] = "@(#)sbpf.c 1.3 8/25/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: sbpf.c,v 2.5 2002/02/24 07:30:03 darrenr Exp"; #endif /* @@ -55,17 +56,15 @@ static u_char *buf = NULL; static int bufsize = 0, timeout = 1; -int initdevice(device, sport, tout) +int initdevice(device, tout) char *device; -int sport, tout; +int tout; { struct bpf_version bv; struct timeval to; struct ifreq ifr; char bpfname[16]; - int fd, i; - - fd = -1; + int fd = 0, i; for (i = 0; i < 16; i++) { diff --git a/dist/ipf/ipsend/sdlpi.c b/dist/ipf/ipsend/sdlpi.c index 109d202157e6..ca6ed511c558 100644 --- a/dist/ipf/ipsend/sdlpi.c +++ b/dist/ipf/ipsend/sdlpi.c @@ -1,9 +1,10 @@ -/* $NetBSD: sdlpi.c,v 1.2 2002/01/24 08:21:41 martti Exp $ */ +/* $NetBSD: sdlpi.c,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ #include @@ -21,10 +22,17 @@ #include #ifdef sun -#include -#include +# include +# include +#endif +#ifdef __osf__ +# include +#else +# include +#endif +#ifdef __hpux +# include #endif -#include #include #include @@ -40,7 +48,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)sdlpi.c 1.3 10/30/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: sdlpi.c,v 2.1.4.2 2001/06/26 10:43:22 darrenr Exp"; +static const char rcsid[] = "@(#)Id: sdlpi.c,v 2.8 2004/01/05 14:17:07 darrenr Exp"; #endif #define CHUNKSIZE 8192 @@ -51,9 +59,9 @@ static const char rcsid[] = "@(#)Id: sdlpi.c,v 2.1.4.2 2001/06/26 10:43:22 darre * Be careful to only include those defined in the flags option for the * interface are included in the header size. */ -int initdevice(device, sport, tout) +int initdevice(device, tout) char *device; -int sport, tout; +int tout; { char devname[16], *s, buf[256]; int i, fd; @@ -81,24 +89,43 @@ int sport, tout; exit(-1); } - if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1) + if (dlattachreq(fd, i) == -1) { - fprintf(stderr, "DLPI error\n"); + fprintf(stderr, "dlattachreq: DLPI error\n"); exit(-1); } + else if (dlokack(fd, buf) == -1) + { + fprintf(stderr, "dlokack(attach): DLPI error\n"); + exit(-1); + } +#ifdef DL_HP_RAWDLS + if (dlpromisconreq(fd, DL_PROMISC_SAP) < 0) + { + fprintf(stderr, "dlpromisconreq: DL_PROMISC_PHYS error\n"); + exit(-1); + } + else if (dlokack(fd, buf) < 0) + { + fprintf(stderr, "dlokack(promisc): DLPI error\n"); + exit(-1); + } + /* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */ + + dlbindreq(fd, 22, 1, DL_HP_RAWDLS, 0, 0); +#else dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0); +#endif dlbindack(fd, buf); /* * write full headers */ -#ifdef sun /* we require RAW DLPI mode, which is a Sun extension */ +#ifdef DLIOCRAW /* we require RAW DLPI mode, which is a Sun extension */ if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1) { fprintf(stderr, "DLIOCRAW error\n"); exit(-1); } -#else -you lose #endif return fd; } @@ -111,8 +138,19 @@ int sendip(fd, pkt, len) int fd, len; char *pkt; { - struct strbuf dbuf, *dp = &dbuf; + struct strbuf dbuf, *dp = &dbuf, *cp = NULL; + int pri = 0; +#ifdef DL_HP_RAWDLS + struct strbuf cbuf; + dl_hp_rawdata_req_t raw; + cp = &cbuf; + raw.dl_primitive = DL_HP_RAWDATA_REQ; + cp->len = sizeof(raw); + cp->buf = (char *)&raw; + cp->maxlen = cp->len; + pri = MSG_HIPRI; +#endif /* * construct NIT STREAMS messages, first control then data. */ @@ -120,7 +158,7 @@ char *pkt; dp->len = len; dp->maxlen = dp->len; - if (putmsg(fd, NULL, dp, 0) == -1) + if (putmsg(fd, cp, dp, pri) == -1) { perror("putmsg"); return -1; @@ -132,3 +170,4 @@ char *pkt; } return len; } + diff --git a/dist/ipf/ipsend/sirix.c b/dist/ipf/ipsend/sirix.c index eec33e63277d..bf6060310355 100644 --- a/dist/ipf/ipsend/sirix.c +++ b/dist/ipf/ipsend/sirix.c @@ -1,14 +1,12 @@ -/* $NetBSD: sirix.c,v 1.3 2002/03/14 12:32:40 martti Exp $ */ +/* $NetBSD: sirix.c,v 1.4 2004/03/28 09:00:56 martti Exp $ */ /* * (C)opyright 1992-1998 Darren Reed. * (C)opyright 1997 Marc Boucher. * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#ifdef __sgi -# include -#endif #include #include #include @@ -25,17 +23,15 @@ #include #include #include -#include -#include -#include #include "ipsend.h" +#include #if !defined(lint) && defined(LIBC_SCCS) static char sirix[] = "@(#)sirix.c 1.0 10/9/97 (C)1997 Marc Boucher"; #endif -int initdevice(char *device, int sport, int tout) +int initdevice(char *device, int tout) { int fd; struct sockaddr_raw sr; diff --git a/dist/ipf/ipsend/slinux.c b/dist/ipf/ipsend/slinux.c index 60560ba710bd..7c9a08460109 100644 --- a/dist/ipf/ipsend/slinux.c +++ b/dist/ipf/ipsend/slinux.c @@ -1,9 +1,10 @@ -/* $NetBSD: slinux.c,v 1.2 2002/01/24 08:21:41 martti Exp $ */ +/* $NetBSD: slinux.c,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ #include @@ -29,7 +30,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)slinux.c 1.2 8/25/95"; -static const char rcsid[] = "@(#)Id: slinux.c,v 2.1.4.1 2001/06/26 10:43:22 darrenr Exp"; +static const char rcsid[] = "@(#)Id: slinux.c,v 2.3 2001/06/09 17:09:26 darrenr Exp"; #endif #define CHUNKSIZE 8192 @@ -44,9 +45,9 @@ static int timeout; static char *eth_dev = NULL; -int initdevice(dev, sport, spare) +int initdevice(dev, spare) char *dev; -int sport, spare; +int spare; { int fd; diff --git a/dist/ipf/ipsend/snit.c b/dist/ipf/ipsend/snit.c index b9d0772b1eed..4a93ab36ae65 100644 --- a/dist/ipf/ipsend/snit.c +++ b/dist/ipf/ipsend/snit.c @@ -1,9 +1,10 @@ -/* $NetBSD: snit.c,v 1.2 2002/01/24 08:21:41 martti Exp $ */ +/* $NetBSD: snit.c,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* * (C)opyright 1992-1998 Darren Reed. (from tcplog) * * See the IPFILTER.LICENCE file for details on licencing. + * */ #include @@ -40,7 +41,7 @@ #if !defined(lint) static const char sccsid[] = "@(#)snit.c 1.5 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: snit.c,v 2.1.4.1 2001/06/26 10:43:22 darrenr Exp"; +static const char rcsid[] = "@(#)Id: snit.c,v 2.3 2001/06/09 17:09:26 darrenr Exp"; #endif #define CHUNKSIZE 8192 @@ -56,9 +57,9 @@ static const char rcsid[] = "@(#)Id: snit.c,v 2.1.4.1 2001/06/26 10:43:22 darren static int timeout; -int initdevice(device, sport, tout) +int initdevice(device, tout) char *device; -int sport, tout; +int tout; { struct strioctl si; struct timeval to; diff --git a/dist/ipf/ipsend/sock.c b/dist/ipf/ipsend/sock.c index d40841133c20..6ddf5b9be9b8 100644 --- a/dist/ipf/ipsend/sock.c +++ b/dist/ipf/ipsend/sock.c @@ -1,22 +1,18 @@ -/* $NetBSD: sock.c,v 1.5 2002/04/09 02:32:55 thorpej Exp $ */ +/* $NetBSD: sock.c,v 1.6 2004/03/28 09:00:56 martti Exp $ */ /* * sock.c (C) 1995-1998 Darren Reed * * See the IPFILTER.LICENCE file for details on licencing. + * */ -#ifdef __sgi -# include +#if !defined(lint) +static const char sccsid[] = "@(#)sock.c 1.2 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)Id: sock.c,v 2.8.4.1 2004/03/23 12:58:06 darrenr Exp"; #endif -#include -#include -#include -#include -#include -#include +#include #include #include -#include #include #ifndef ultrix #include @@ -26,21 +22,23 @@ #else # include #endif -#define _KERNEL -#define KERNEL -#ifdef ultrix -# undef LOCORE -# include +#if !defined(__osf__) +# define _KERNEL +# define KERNEL +# ifdef ultrix +# undef LOCORE +# include +# endif +# include +# undef _KERNEL +# undef KERNEL #endif -#include -#undef _KERNEL -#undef KERNEL #include #include #include #include #include -#if !defined(ultrix) && !defined(hpux) +#if !defined(ultrix) && !defined(hpux) && !defined(__osf__) # include #endif #ifdef sun @@ -58,20 +56,22 @@ #include #include #include +#if defined(__FreeBSD__) +# include "radix_ipf.h" +#endif #include #include #include #include #include +#include +#include +#include +#include +#include +#include #include "ipsend.h" -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)sock.c 1.2 1/11/96 (C)1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: sock.c,v 2.1.4.5 2002/02/22 15:32:58 darrenr Exp"; -#endif - int nproc; struct proc *proc; @@ -383,7 +383,7 @@ struct in_addr gwip; (void) getsockname(fd, (struct sockaddr *)&lsin, &len); ti->ti_sport = lsin.sin_port; printf("sport %d\n", ntohs(lsin.sin_port)); - nfd = initdevice(dev, ntohs(lsin.sin_port), 1); + nfd = initdevice(dev, 1); if (!(t = find_tcp(fd, ti))) return -1; diff --git a/dist/ipf/ipsend/tcpip.h b/dist/ipf/ipsend/tcpip.h index ff2f0ccbee8d..e14f9e3b1f65 100644 --- a/dist/ipf/ipsend/tcpip.h +++ b/dist/ipf/ipsend/tcpip.h @@ -1,4 +1,4 @@ -/* $NetBSD: tcpip.h,v 1.2 2003/08/07 09:21:11 agc Exp $ */ +/* $NetBSD: tcpip.h,v 1.3 2004/03/28 09:00:56 martti Exp $ */ /* * Copyright (c) 1982, 1986, 1993 @@ -29,7 +29,7 @@ * SUCH DAMAGE. * * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 - * Id: tcpip.h,v 2.1 1999/08/04 17:31:16 darrenr Exp + * Id: tcpip.h,v 2.2.2.1 2004/03/23 12:58:06 darrenr Exp */ #ifndef _NETINET_TCPIP_H_ @@ -52,11 +52,7 @@ struct ipovly { */ struct tcpiphdr { struct ipovly ti_i; /* overlaid ip structure */ -#ifdef linux - tcphdr_t ti_t; -#else struct tcphdr ti_t; /* tcp header */ -#endif }; #ifdef notyet /* diff --git a/dist/ipf/ipsend/ultrix.c b/dist/ipf/ipsend/ultrix.c deleted file mode 100644 index 0ba5fab6d48a..000000000000 --- a/dist/ipf/ipsend/ultrix.c +++ /dev/null @@ -1,86 +0,0 @@ -/* $NetBSD: ultrix.c,v 1.2 2002/01/24 08:21:41 martti Exp $ */ - -/* - * (C)opyright 1998 Darren Reed. (from tcplog) - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static struct dli_devid dli_devid; - - -int initdevice(device, sport, tout) -char *device; -int sport, tout; -{ - u_char *s; - int fd; - - fd = socket(AF_DLI, SOCK_DGRAM, 0); - if (fd == -1) - perror("socket(AF_DLI,SOCK_DGRAM)"); - else { - strncpy(dli_devid.dli_devname, device, DLI_DEVSIZE); - dli_devid.dli_devname[DLI_DEVSIZE] ='\0'; - for (s = dli_devid.dli_devname; *s && isalpha((char)*s); s++) - ; - if (*s && isdigit((char)*s)) { - dli_devid.dli_devnumber = atoi(s); - } - } - return fd; -} - - -/* - * output an IP packet onto a fd opened for /dev/bpf - */ -int sendip(fd, pkt, len) -int fd, len; -char *pkt; -{ - struct sockaddr_dl dl; - struct sockaddr_edl *edl = &dl.choose_addr.dli_eaddr; - - dl.dli_family = AF_DLI; - dl.dli_substructype = DLI_ETHERNET; - bcopy((char *)&dli_devid, (char *)&dl.dli_device, sizeof(dli_devid)); - bcopy(pkt, edl->dli_target, DLI_EADDRSIZE); - bcopy(pkt, edl->dli_dest, DLI_EADDRSIZE); - bcopy(pkt + DLI_EADDRSIZE * 2, (char *)&edl->dli_protype, 2); - edl->dli_ioctlflg = 0; - - if (sendto(fd, pkt, len, 0, (struct sockaddr *)&dl, sizeof(dl)) == -1) - { - perror("send"); - return -1; - } - - return len; -} - - -char *strdup(str) -char *str; -{ - char *s; - - if ((s = (char *)malloc(strlen(str) + 1))) - return strcpy(s, str); - return NULL; -} diff --git a/dist/ipf/ipt.c b/dist/ipf/ipt.c deleted file mode 100644 index 58c66fff8039..000000000000 --- a/dist/ipf/ipt.c +++ /dev/null @@ -1,512 +0,0 @@ -/* $NetBSD: ipt.c,v 1.11 2002/12/06 04:43:53 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2002 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __FreeBSD__ -# ifndef __FreeBSD_cc_version -# include -# else -# if __FreeBSD_cc_version < 430000 -# include -# endif -# endif -#endif -#ifdef __sgi -# define _KMEMUSER -# include -#endif -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) && !defined(__sgi) -#include -#else -#if !defined(__sgi) -#include -#endif -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include -#include "ip_fil.h" -#include "ip_nat.h" -#include "ip_state.h" -#include "ip_frag.h" -#include "ipf.h" -#include "ipt.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipt.c 1.19 6/3/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: ipt.c,v 2.6.2.22 2002/06/04 14:52:58 darrenr Exp"; -#endif - -extern char *optarg; -extern struct frentry *ipfilter[2][2]; -extern struct ipread snoop, etherf, tcpd, pcap, iptext, iphex; -extern struct ifnet *get_unit __P((char *, int)); -extern void init_ifp __P((void)); -extern ipnat_t *natparse __P((char *, int)); -extern int fr_running; - -int opts = 0; -int rremove = 0; -int use_inet6 = 0; -int main __P((int, char *[])); -int loadrules __P((char *)); -int kmemcpy __P((char *, long, int)); -void dumpnat __P((void)); -void dumpstate __P((void)); -char *getifname __P((void *)); -void drain_log __P((char *)); - -int main(argc,argv) -int argc; -char *argv[]; -{ - char *datain, *iface, *ifname, *packet, *logout; - int fd, i, dir, c, loaded, dump, hlen; - struct ifnet *ifp; - struct ipread *r; - u_long buf[2048]; - ip_t *ip; - - dir = 0; - dump = 0; - loaded = 0; - r = &iptext; - iface = NULL; - logout = NULL; - ifname = "anon0"; - datain = NULL; - - nat_init(); - fr_stateinit(); - initparse(); - ipflog_init(); - fr_running = 1; - - while ((c = getopt(argc, argv, "6bdDEHi:I:l:NoPr:RSTvxX")) != -1) - switch (c) - { - case '6' : -#ifdef USE_INET6 - use_inet6 = 1; - break; -#else - fprintf(stderr, "IPv6 not supported\n"); - exit(1); -#endif - case 'b' : - opts |= OPT_BRIEF; - break; - case 'd' : - opts |= OPT_DEBUG; - break; - case 'D' : - dump = 1; - break; - case 'i' : - datain = optarg; - break; - case 'I' : - ifname = optarg; - break; - case 'l' : - logout = optarg; - break; - case 'o' : - opts |= OPT_SAVEOUT; - break; - case 'r' : - if (loadrules(optarg) == -1) - return -1; - loaded = 1; - break; - case 'v' : - opts |= OPT_VERBOSE; - break; - case 'E' : - r = ðerf; - break; - case 'H' : - r = &iphex; - break; - case 'N' : - opts |= OPT_NAT; - break; - case 'P' : - r = &pcap; - break; - case 'R' : - rremove = 1; - break; - case 'S' : - r = &snoop; - break; - case 'T' : - r = &tcpd; - break; - case 'x' : - opts |= OPT_HEX; - break; - case 'X' : - r = &iptext; - break; - } - - if (loaded == 0) { - (void)fprintf(stderr,"no rules loaded\n"); - exit(-1); - } - - if (opts & OPT_SAVEOUT) - init_ifp(); - - if (datain) - fd = (*r->r_open)(datain); - else - fd = (*r->r_open)("-"); - - if (fd < 0) - exit(-1); - - ip = (ip_t *)buf; - while ((i = (*r->r_readip)((char *)buf, sizeof(buf), - &iface, &dir)) > 0) { - if (iface == NULL || *iface == '\0') - iface = ifname; - ifp = get_unit(iface, ip->ip_v); - hlen = 0; - if (!use_inet6) { - ip->ip_off = ntohs(ip->ip_off); - ip->ip_len = ntohs(ip->ip_len); - hlen = ip->ip_hl << 2; - } -#ifdef USE_INET6 - else - hlen = sizeof(ip6_t); -#endif - packet = (char *)buf; - /* ipfr_slowtimer(); */ - i = fr_check(ip, hlen, ifp, dir, (void *)&packet); - if ((opts & OPT_NAT) == 0) - switch (i) - { - case -5 : - (void)printf("block return-icmp-as-dest"); - break; - case -4 : - (void)printf("block return-icmp"); - break; - case -3 : - (void)printf("block return-rst"); - break; - case -2 : - (void)printf("auth"); - break; - case -1 : - (void)printf("block"); - break; - case 0 : - (void)printf("pass"); - break; - case 1 : - (void)printf("nomatch"); - break; - } - if (!use_inet6) { - ip->ip_off = htons(ip->ip_off); - ip->ip_len = htons(ip->ip_len); - } - - if (!(opts & OPT_BRIEF)) { - putchar(' '); - printpacket((ip_t *)buf); - printf("--------------"); - } else if ((opts & (OPT_BRIEF|OPT_NAT)) == (OPT_NAT|OPT_BRIEF)) - printpacket((ip_t *)buf); -#ifndef linux - if (dir && (ifp != NULL) && ip->ip_v && (packet != NULL)) -# if defined(__sgi) && (IRIX < 605) - (*ifp->if_output)(ifp, (void *)packet, NULL); -# else - (*ifp->if_output)(ifp, (void *)packet, NULL, 0); -# endif -#endif - if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF)) - putchar('\n'); - dir = 0; - if (iface != ifname) { - free(iface); - iface = ifname; - } - } - (*r->r_close)(); - - if (logout != NULL) { - drain_log(logout); - } - - if (dump == 1) { - dumpnat(); - dumpstate(); - } - - return 0; -} - - -/* - * Load in either NAT or ipf rules from a file, which is treated as stdin - * if the name is "-". NOTE, stdin can only be used once as the file is - * closed after use. - */ -int loadrules(file) -char *file; -{ - char line[513], *s; - int linenum, i; - void *fr; - FILE *fp; - - if (!strcmp(file, "-")) - fp = stdin; - else if (!(fp = fopen(file, "r"))) { - (void)fprintf(stderr, "couldn't open %s\n", file); - return (-1); - } - - if (!(opts & OPT_BRIEF)) - (void)printf("opening rule file \"%s\"\n", file); - - linenum = 0; - - while (fgets(line, sizeof(line) - 1, fp)) { - linenum++; - - /* - * treat both CR and LF as EOL - */ - if ((s = index(line, '\n'))) - *s = '\0'; - if ((s = index(line, '\r'))) - *s = '\0'; - - /* - * # is comment marker, everything after is a ignored - */ - if ((s = index(line, '#'))) - *s = '\0'; - - if (!*line) - continue; - - /* fake an `ioctl' call :) */ - - if ((opts & OPT_NAT) != 0) { - if (!(fr = natparse(line, linenum))) - continue; - - if (rremove == 0) { - i = IPL_EXTERN(ioctl)(IPL_LOGNAT, SIOCADNAT, - (caddr_t)&fr, - FWRITE|FREAD); - if (opts & OPT_DEBUG) - fprintf(stderr, - "iplioctl(ADNAT,%p,1) = %d\n", - fr, i); - } else { - i = IPL_EXTERN(ioctl)(IPL_LOGNAT, SIOCRMNAT, - (caddr_t)&fr, - FWRITE|FREAD); - if (opts & OPT_DEBUG) - fprintf(stderr, - "iplioctl(RMNAT,%p,1) = %d\n", - fr, i); - } - } else { - if (!(fr = parse(line, linenum))) - continue; - - if (rremove == 0) { - i = IPL_EXTERN(ioctl)(0, SIOCADAFR, - (caddr_t)&fr, - FWRITE|FREAD); - if (opts & OPT_DEBUG) - fprintf(stderr, - "iplioctl(ADAFR,%p,1) = %d\n", - fr, i); - } else { - i = IPL_EXTERN(ioctl)(0, SIOCRMAFR, - (caddr_t)&fr, - FWRITE|FREAD); - if (opts & OPT_DEBUG) - fprintf(stderr, - "iplioctl(RMAFR,%p,1) = %d\n", - fr, i); - } - } - } - (void)fclose(fp); - - return 0; -} - - -int kmemcpy(addr, offset, size) -char *addr; -long offset; -int size; -{ - bcopy((char *)offset, addr, size); - return 0; -} - - -/* - * Display the built up NAT table rules and mapping entries. - */ -void dumpnat() -{ - ipnat_t *ipn; - nat_t *nat; - - printf("List of active MAP/Redirect filters:\n"); - for (ipn = nat_list; ipn != NULL; ipn = ipn->in_next) - printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); - printf("\nList of active sessions:\n"); - for (nat = nat_instances; nat; nat = nat->nat_next) - printactivenat(nat, opts); -} - - -/* - * Display the built up state table rules and mapping entries. - */ -void dumpstate() -{ - ipstate_t *ips; - - printf("List of active state sessions:\n"); - for (ips = ips_list; ips != NULL; ) - ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE)); -} - - -/* - * Given a pointer to an interface in the kernel, return a pointer to a - * string which is the interface name. - */ -char *getifname(ptr) -void *ptr; -{ -#if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ - defined(__OpenBSD__) -#else - char buf[32], *s; - int len; -#endif - struct ifnet netif; - - if (ptr == (void *)-1) - return "!"; - if (ptr == NULL) - return "-"; - - if (kmemcpy((char *)&netif, (u_long)ptr, sizeof(netif)) == -1) - return "X"; -#if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ - defined(__OpenBSD__) - return strdup(netif.if_xname); -#else - if (kmemcpy(buf, (u_long)netif.if_name, sizeof(buf)) == -1) - return "X"; - if (netif.if_unit < 10) - len = 2; - else if (netif.if_unit < 1000) - len = 3; - else if (netif.if_unit < 10000) - len = 4; - else - len = 5; - buf[sizeof(buf) - len] = '\0'; - for (s = buf; *s && !isdigit(*s); s++) - ; - if (isdigit(*s)) - *s = '\0'; - sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000); - return strdup(buf); -#endif -} - - -void drain_log(filename) -char *filename; -{ - char buffer[IPLLOGSIZE]; - struct iovec iov; - struct uio uio; - size_t resid; - int fd; - - fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644); - if (fd == -1) { - perror("drain_log:open"); - return; - } - - while (1) { - bzero((char *)&iov, sizeof(iov)); - iov.iov_base = buffer; - iov.iov_len = sizeof(buffer); - - bzero((char *)&uio, sizeof(uio)); - uio.uio_iov = &iov; - uio.uio_iovcnt = 1; - uio.uio_resid = iov.iov_len; - resid = uio.uio_resid; - - if (ipflog_read(0, &uio) == 0) { - /* - * If nothing was read then break out. - */ - if (uio.uio_resid == resid) - break; - write(fd, buffer, resid - uio.uio_resid); - } else - break; - } - - close(fd); -} diff --git a/dist/ipf/ipt.h b/dist/ipf/ipt.h index b725da8858b9..ab065a48f644 100644 --- a/dist/ipf/ipt.h +++ b/dist/ipf/ipt.h @@ -1,10 +1,11 @@ -/* $NetBSD: ipt.h,v 1.4 2002/01/24 08:21:34 martti Exp $ */ +/* $NetBSD: ipt.h,v 1.5 2004/03/28 09:00:54 martti Exp $ */ /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. - * Id: ipt.h,v 2.2.2.1 2001/06/26 10:43:19 darrenr Exp + * + * Id: ipt.h,v 2.6 2003/02/16 02:33:09 darrenr Exp */ #ifndef __IPT_H__ @@ -26,12 +27,13 @@ struct ipread { int (*r_open) __P((char *)); int (*r_close) __P((void)); int (*r_readip) __P((char *, int, char **, int *)); + int r_flags; }; -extern void debug __P((char *, ...)) - __attribute__((__format__(__printf__, 1, 2))); -extern void verbose __P((char *, ...)) - __attribute__((__format__(__printf__, 1, 2))); +#define R_DO_CKSUM 0x01 + +extern void debug __P((char *, ...)); +extern void verbose __P((char *, ...)); #ifdef P_DEF # undef __P diff --git a/dist/ipf/kmem.c b/dist/ipf/kmem.c deleted file mode 100644 index 84889aa89442..000000000000 --- a/dist/ipf/kmem.c +++ /dev/null @@ -1,244 +0,0 @@ -/* $NetBSD: kmem.c,v 1.10 2002/09/19 08:10:41 martti Exp $ */ - -/* - * Copyright (C) 1993-2002 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -/* - * kmemcpy() - copies n bytes from kernel memory into user buffer. - * returns 0 on success, -1 on error. - */ - -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef __sgi -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif - -#include "kmem.h" -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "ipf.h" - - -#ifndef __STDC__ -# define const -#endif - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: kmem.c,v 2.2.2.15 2002/07/27 15:59:37 darrenr Exp"; -#endif - -#ifdef __sgi -typedef int kvm_t; - -static int kvm_fd = -1; -static char *kvm_errstr; - -kvm_t *kvm_open(kernel, core, swap, mode, errstr) -char *kernel, *core, *swap; -int mode; -char *errstr; -{ - kvm_errstr = errstr; - - if (core == NULL) - core = "/dev/kmem"; - kvm_fd = open(core, mode); - return (kvm_fd >= 0) ? (kvm_t *)&kvm_fd : NULL; -} - -int kvm_read(kvm, pos, buffer, size) -kvm_t *kvm; -u_long pos; -char *buffer; -size_t size; -{ - size_t left; - char *bufp; - int r; - - if (lseek(*kvm, pos, 0) == -1) { - fprintf(stderr, "%s", kvm_errstr); - perror("lseek"); - return -1; - } - - for (bufp = buffer, left = size; left > 0; bufp += r, left -= r) { - r = read(*kvm, bufp, 1); - if (r <= 0) - return -1; - } - return size; -} -#endif - -static kvm_t *kvm_f = NULL; - -int openkmem(kern, core) -char *kern, *core; -{ - union { - int ui; - kvm_t *uk; - } k; - - kvm_f = kvm_open(kern, core, NULL, O_RDONLY, ""); - if (kvm_f == NULL) - { - perror("openkmem:open"); - return -1; - } - k.uk = kvm_f; - return k.ui; -} - -int kmemcpy(buf, pos, n) -register char *buf; -long pos; -register int n; -{ - register int r; - - if (!n) - return 0; - - if (kvm_f == NULL) - if (openkmem(NULL, NULL) == -1) - return -1; - - while ((r = kvm_read(kvm_f, pos, buf, (size_t)n)) < n) - if (r <= 0) - { - fprintf(stderr, "pos=0x%x ", (u_int)pos); - perror("kmemcpy:read"); - return -1; - } - else - { - buf += r; - pos += r; - n -= r; - } - return 0; -} - -int kstrncpy(buf, pos, n) -register char *buf; -long pos; -register int n; -{ - register int r; - - if (!n) - return 0; - - if (kvm_f == NULL) - if (openkmem(NULL, NULL) == -1) - return -1; - - while (n > 0) - { - r = kvm_read(kvm_f, pos, buf, (size_t)1); - if (r <= 0) - { - fprintf(stderr, "pos=0x%x ", (u_int)pos); - perror("kstrncpy:read"); - return -1; - } - else - { - if (*buf == '\0') - break; - buf++; - pos++; - n--; - } - } - return 0; -} - - -/* - * Given a pointer to an interface in the kernel, return a pointer to a - * string which is the interface name. - */ -char *getifname(ptr) -void *ptr; -{ -#if SOLARIS - char *ifname; - ill_t ill; - - if (ptr == (void *)-1) - return "!"; - if (ptr == NULL) - return "-"; - - if (kmemcpy((char *)&ill, (u_long)ptr, sizeof(ill)) == -1) - return "X"; - ifname = malloc(ill.ill_name_length + 1); - if (kmemcpy(ifname, (u_long)ill.ill_name, - ill.ill_name_length) == -1) - return "X"; - return ifname; -#else -# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ - defined(__OpenBSD__) -#else - char buf[32]; - int len; -# endif - struct ifnet netif; - - if (ptr == (void *)-1) - return "!"; - if (ptr == NULL) - return "-"; - - if (kmemcpy((char *)&netif, (u_long)ptr, sizeof(netif)) == -1) - return "X"; -# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ - defined(__OpenBSD__) - return strdup(netif.if_xname); -# else - if (kstrncpy(buf, (u_long)netif.if_name, sizeof(buf)) == -1) - return "X"; - if (netif.if_unit < 10) - len = 2; - else if (netif.if_unit < 1000) - len = 3; - else if (netif.if_unit < 10000) - len = 4; - else - len = 5; - buf[sizeof(buf) - len] = '\0'; - sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000); - return strdup(buf); -# endif -#endif -} diff --git a/dist/ipf/kmem.h b/dist/ipf/kmem.h index 71d19972b601..25bec20c6c5a 100644 --- a/dist/ipf/kmem.h +++ b/dist/ipf/kmem.h @@ -1,10 +1,10 @@ -/* $NetBSD: kmem.h,v 1.3 2002/01/24 08:21:34 martti Exp $ */ +/* $NetBSD: kmem.h,v 1.4 2004/03/28 09:00:54 martti Exp $ */ /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. - * Id: kmem.h,v 2.2.2.4 2002/01/01 13:43:48 darrenr Exp + * Id: kmem.h,v 2.5 2002/08/21 22:57:36 darrenr Exp */ #ifndef __KMEM_H__ @@ -20,7 +20,6 @@ extern int openkmem __P((char *, char *)); extern int kmemcpy __P((char *, long, int)); extern int kstrncpy __P((char *, long, int)); -extern char *getifname __P((void *)); #if defined(__NetBSD__) || defined(__OpenBSD) # include diff --git a/dist/ipf/man/Makefile b/dist/ipf/man/Makefile index 05164d7c818f..3f12ccbe87b4 100644 --- a/dist/ipf/man/Makefile +++ b/dist/ipf/man/Makefile @@ -1,9 +1,7 @@ # # Copyright (C) 1993-1998 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. +# See the IPFILTER.LICENCE file for details on licencing. # all: @@ -12,12 +10,19 @@ install: $(INSTALL) -m 0644 -c -o root -g bin ipftest.1 $(MANDIR)/man1 $(INSTALL) -m 0644 -c -o root -g bin ipnat.8 $(MANDIR)/man8 $(INSTALL) -m 0644 -c -o root -g bin ipf.4 $(MANDIR)/man4 + $(INSTALL) -m 0644 -c -o root -g bin ipfilter.4 $(MANDIR)/man4 $(INSTALL) -m 0644 -c -o root -g bin ipl.4 $(MANDIR)/man4 $(INSTALL) -m 0644 -c -o root -g bin ipnat.4 $(MANDIR)/man4 $(INSTALL) -m 0644 -c -o root -g bin ipf.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipfilter.5 $(MANDIR)/man5 $(INSTALL) -m 0644 -c -o root -g bin ipnat.5 $(MANDIR)/man5 $(INSTALL) -m 0644 -c -o root -g bin ipf.8 $(MANDIR)/man8 $(INSTALL) -m 0644 -c -o root -g bin ipfs.8 $(MANDIR)/man8 $(INSTALL) -m 0644 -c -o root -g bin ipmon.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipmon.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ippool.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ippool.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipscan.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipscan.5 $(MANDIR)/man5 $(INSTALL) -m 0644 -c -o root -g bin ipfstat.8 $(MANDIR)/man8 @echo "Remember to rebuild the whatis database." diff --git a/dist/ipf/man/ipf.4 b/dist/ipf/man/ipf.4 index 2770c48f9267..cea20f876cc3 100644 --- a/dist/ipf/man/ipf.4 +++ b/dist/ipf/man/ipf.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipf.4,v 1.10 2002/09/04 00:09:23 wiz Exp $ +.\" $NetBSD: ipf.4,v 1.11 2004/03/28 09:00:56 martti Exp $ .\" .TH IPF 4 .SH NAME @@ -37,8 +37,8 @@ However, the full complement is as follows: ioctl(fd, SIOCFRSYN, u_int *) ioctl(fd, SIOCFRZST, struct friostat **) ioctl(fd, SIOCZRLST, struct frentry **) - ioctl(fd, SIOCAUTHW, struct frauth_t **) - ioctl(fd, SIOCAUTHR, struct frauth_t **) + ioctl(fd, SIOCAUTHW, struct fr_info **) + ioctl(fd, SIOCAUTHR, struct fr_info **) ioctl(fd, SIOCATHST, struct fr_authstat **) .fi .PP @@ -124,7 +124,7 @@ Flags which are recognised in fr_flags: FR_RETRST 0x000080 /* return a TCP RST packet if blocked */ FR_RETICMP 0x000100 /* return an ICMP packet if blocked */ FR_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */ - FR_NOMATCH 0x000200 /* No match occurred */ + FR_NOMATCH 0x000200 /* no match occured */ FR_ACCOUNT 0x000400 /* count packet bytes */ FR_KEEPFRAG 0x000800 /* keep fragment information */ FR_KEEPSTATE 0x001000 /* keep `connection' state information */ diff --git a/dist/ipf/man/ipf.5 b/dist/ipf/man/ipf.5 index 64aca940d9e6..c5f112ceaefe 100644 --- a/dist/ipf/man/ipf.5 +++ b/dist/ipf/man/ipf.5 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipf.5,v 1.9 2002/12/21 13:28:25 wiz Exp $ +.\" $NetBSD: ipf.5,v 1.10 2004/03/28 09:00:56 martti Exp $ .\" .TH IPF 5 .SH NAME @@ -21,12 +21,13 @@ described using the following grammar in BNF: \fC .nf filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] - [ proto ] [ ip ] [ group ]. + [ proto ] ip [ group ]. insert = "@" decnumber . action = block | "pass" | log | "count" | skip | auth | call . in-out = "in" | "out" . -options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] ] . +options = [ log ] [ tag ] [ "quick" ] [ "on" interface-name [ dup ] + [ froute ] [ replyto ] ] . tos = "tos" decnumber | "tos" hexnumber . ttl = "ttl" decnumber . proto = "proto" protocol . @@ -34,19 +35,24 @@ ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . group = [ "head" decnumber ] [ "group" decnumber ] . block = "block" [ return-icmp[return-code] | "return-rst" ] . -auth = "auth" | "preauth" . log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . -call = "call" [ "now" ] function-name . +tag = "tag" tagid . skip = "skip" decnumber . -dup = "dup-to" interface-name[":"ipaddr] . -froute = "fastroute" | "to" interface-name . +auth = "auth" | "preauth" . +call = "call" [ "now" ] function-name . +dup = "dup-to" interface-name [ ":" ipaddr ] . +froute = "fastroute" | "to" interface-name [ ":" ipaddr ] . +replyto = "reply-to" interface-name [ ":" ipaddr ] . protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . srcdst = "all" | fromto . fromto = "from" [ "!" ] object "to" [ "!" ] object . return-icmp = "return-icmp" | "return-icmp-as-dest" . +return-code = "(" icmp-code ")" . object = addr [ port-comp | port-range ] . addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +addr = "any" | "" | nummask | + host-name [ "mask" ipaddr | "mask" hexnumber ] . port-comp = "port" compare port-num . port-range = "port" port-num range port-num . flags = "flags" flag { flag } [ "/" flag { flag } ] . @@ -63,7 +69,7 @@ host-num = digit [ digit [ digit ] ] . port-num = service-name | decnumber . withopt = [ "not" | "no" ] opttype [ withopt ] . -opttype = "ipopts" | "short" | "frag" | "opt" optname . +opttype = "ipopts" | "short" | "frag" | "opt" optname . optname = ipopts [ "," optname ] . ipopts = optlist | "sec-class" [ secname ] . secname = seclvl [ "," secname ] . @@ -207,6 +213,13 @@ indicates that, should this be the last matching rule, the packet header will be written to the \fBipl\fP log (as described in the LOGGING section below). .TP +.B tag tagid +indicates that, if this rule causes the packet to be logged or entered +in the state table, the tagid will be logged as part of the log entry. +This can be used to quickly match "similar" rules in scripts that post +process the log files for e.g. generation of security reports or accounting +purposes. The tagid is a 32 bit unsigned integer. +.TP .B quick allows "short-cut" rules in order to speed up the filter or override later rules. If a packet matches a filter rule which is marked as @@ -376,7 +389,7 @@ against, e.g.: # packets with ONLY the SYN flag set. ... flags SA - # becomes "flags SA/AUPRFSC" and will match any + # becomes "flags SA/AUPRFS" and will match any # packet with only the SYN and ACK flags set. ... flags S/SA diff --git a/dist/ipf/man/ipf.8 b/dist/ipf/man/ipf.8 index e99cbe30f331..bf937fb9812d 100644 --- a/dist/ipf/man/ipf.8 +++ b/dist/ipf/man/ipf.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipf.8,v 1.8 2003/05/17 13:58:07 itojun Exp $ +.\" $NetBSD: ipf.8,v 1.9 2004/03/28 09:00:56 martti Exp $ .\" .TH IPF 8 .SH NAME @@ -6,11 +6,14 @@ ipf \- alters packet filtering lists for IP packet input and output .SH SYNOPSIS .B ipf [ -.B \-6AdDEInoPrsUvVyzZ +.B \-6AcdDEInoPrsvVyzZ ] [ .B \-l ] [ +.B \-T + +] [ .B \-F ] @@ -38,6 +41,15 @@ This option is required to parse IPv6 rules and to have them loaded. .B \-A Set the list to make changes to the active list (default). .TP +.B \-c +This option causes \fBipf\fP to generate output files for a compiler that +supports \fBlanguage\fI. At present, the only target language supported is +\fBC\fB (-cc) for which two files - \fBip_rules.c\fP +and \fBip_rules.h\fP are generated in the \fBCURRENT DIRECTORY\fP when +\fBipf\fP is being run. These files can be used with the +\fBIPFILTER_COMPILED\fP kernel option to build filter rules staticly into +the kernel. +.TP .B \-d Turn debug mode on. Causes a hexdump of filter rules to be generated as it processes each one. @@ -94,10 +106,22 @@ Remove matching filter rules rather than add them to the internal lists .TP .B \-s Swap the active filter list in use to be the "other" one. -.TP -.B \-U -(SOLARIS 2 ONLY) Block packets travelling along the data stream which aren't -recognised as IP packets. They will be printed out on the console. +.B \-T +This option allows run-time changing of IPFilter kernel variables. Some +variables require IPFilter to be in a disabled state (\fB-D\fP) for changing, +others do not. The optionlist parameter is a comma separated list of tuning +commands. A tuning command is either "list" (retrieve a list of all variables +in the kernel, their maximum, minimum and current value), a single variable +name (retrieve its current value) and a variable name with a following +assignment to set a new value. Some examples follow. +.nf +# Print out all IPFilter kernel tunable parameters +ipf -T list +# Display the current TCP idle timeout and then set it to 3600 +ipf -D -T fr_tcpidletimeout,fr_tcpidletimeout=3600 -E +# Display current values for fr_pass and fr_chksrc, then set fr_chksrc to 1. +ipf -T fr_pass,fr_chksrc,fr_chksrc=1 +.fi .TP .B \-v Turn verbose mode on. Displays information relating to rule processing. diff --git a/dist/ipf/man/ipfs.8 b/dist/ipf/man/ipfs.8 index 7530b05c1e3b..891ae3d08d6b 100644 --- a/dist/ipf/man/ipfs.8 +++ b/dist/ipf/man/ipfs.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipfs.8,v 1.3 2003/01/04 01:18:02 wiz Exp $ +.\" $NetBSD: ipfs.8,v 1.4 2004/03/28 09:00:56 martti Exp $ .\" .TH IPFS 8 .SH NAME @@ -54,7 +54,6 @@ Change the default directory used with and .B \-W options for saving state information. -.TP .B \-n Don't actually take any action that would effect information stored in the kernel or on disk. @@ -62,11 +61,6 @@ the kernel or on disk. .B \-v Provides a verbose description of what's being done. .TP -.B \-i , -Change all instances of interface name ifname1 in the state save file to -ifname2. Useful if you're restoring state information after a hardware -reconfiguration or change. -.TP .B \-N Operate on NAT information. .TP @@ -77,7 +71,7 @@ Operate on filtering state information. Unlock state tables in the kernel. .TP .B \-l -Lock state tables in the kernel. +Unlock state tables in the kernel. .TP .B \-r Read information in from the specified file and load it into the diff --git a/dist/ipf/man/ipfstat.8 b/dist/ipf/man/ipfstat.8 index 3bf6a04348fd..d18dfebf48cb 100644 --- a/dist/ipf/man/ipfstat.8 +++ b/dist/ipf/man/ipfstat.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipfstat.8,v 1.9 2003/03/30 17:10:31 wiz Exp $ +.\" $NetBSD: ipfstat.8,v 1.10 2004/03/28 09:00:56 martti Exp $ .\" .TH ipfstat 8 .SH NAME @@ -6,10 +6,7 @@ ipfstat \- reports on packet filter statistics and filter list .SH SYNOPSIS .B ipfstat [ -.B \-6aAfghIinosv -] [ -.B \-d - +.B \-6aACdfghIinosv ] .B ipfstat -t @@ -27,9 +24,6 @@ ipfstat \- reports on packet filter statistics and filter list ] [ .B \-T -] [ -.B \-d - ] .SH DESCRIPTION .PP @@ -58,8 +52,8 @@ Display "closed" states as well in the top. Normally, a TCP connection is not displayed when it reaches the CLOSE_WAIT protocol state. With this option enabled, all state entries are displayed. .TP -.BR \-d \0 -Use a device other than \fB/dev/ipl\fP for interfacing with the kernel. +.BR \-d +Produce debugging output when displaying data. .TP .BR \-D \0 This option is only valid in combination with \fB\-t\fP. Limit the state top diff --git a/dist/ipf/man/ipftest.1 b/dist/ipf/man/ipftest.1 index 1490d98934eb..1723be8cc177 100644 --- a/dist/ipf/man/ipftest.1 +++ b/dist/ipf/man/ipftest.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipftest.1,v 1.4 2002/12/21 13:14:38 wiz Exp $ +.\" $NetBSD: ipftest.1,v 1.5 2004/03/28 09:00:56 martti Exp $ .\" .TH ipftest 1 .SH NAME @@ -6,7 +6,10 @@ ipftest \- test packet filter rules with arbitrary input. .SH SYNOPSIS .B ipftest [ -.B \-vbdPRSTEHX +.B \-6bdDNovxX +] [ +.B \-F +input-format ] [ .B \-I interface @@ -73,21 +76,42 @@ This is useful with the \fB\-P, \-S, \-T\fP and \fB\-E\fP options, where it is not otherwise possible to associate a packet with an interface. Normal "text packets" can override this setting. .TP -.B \-P +.B \-F +This option is used to select which input format the input file is in. +The following formats are available: etherfind, hex, pcap, snoop, tcpdump. +.RS +.TP +.B etherfind +The input file is to be text output from etherfind. The text formats which +are currently supported are those which result from the following etherfind +option combinations: +.PP +.nf + etherfind -n + etherfind -n -t +.fi +.TP +.B hex +The input file is to be hex digits, representing the binary makeup of the +packet. No length correction is made, if an incorrect length is put in +the IP header. A packet may be broken up over several lines of hex digits, +a blank line indicating the end of the packet. It is possible to specify +both the interface name and direction of the packet (for filtering purposes) +at the start of the line using this format: [direction,interface] To define +a packet going in on le0, we would use \fB[in,le0]\fP - the []'s are required +and part of the input syntax. +.HP +.B pcap The input file specified by \fB\-i\fP is a binary file produced using libpcap (i.e., tcpdump version 3). Packets are read from this file as being input (for rule purposes). An interface maybe specified using \fB\-I\fP. .TP -.B \-R -Remove rules rather than load them. This is not a toggle option, so once -set, it cannot be reset by further use of -R. -.TP -.B \-S +.B snoop The input file is to be in "snoop" format (see RFC 1761). Packets are read from this file and used as input from any interface. This is perhaps the most useful input type, currently. .TP -.B \-T +.B tcpdump The input file is to be text output from tcpdump. The text formats which are currently supported are those which result from the following tcpdump option combinations: @@ -100,31 +124,12 @@ option combinations: tcpdump -nqte .fi .LP -.TP -.B \-H -The input file is to be hex digits, representing the binary makeup of the -packet. No length correction is made, if an incorrect length is put in -the IP header. A packet may be broken up over several lines of hex digits, -a blank line indicating the end of the packet. It is possible to specify -both the interface name and direction of the packet (for filtering purposes) -at the start of the line using this format: [direction,interface] To define -a packet going in on le0, we would use \fB[in,le0]\fP - the []'s are required -and part of the input syntax. +.RE +.DT .TP .B \-X The input file is composed of text descriptions of IP packets. .TP -.B \-E -The input file is to be text output from etherfind. The text formats which -are currently supported are those which result from the following etherfind -option combinations: -.PP -.nf - etherfind -n - etherfind -n -t -.fi -.LP -.TP .BR \-i \0 Specify the filename from which to take input. Default is stdin. .TP diff --git a/dist/ipf/man/ipl.4 b/dist/ipf/man/ipl.4 index d94895a16079..7ebd308dabef 100644 --- a/dist/ipf/man/ipl.4 +++ b/dist/ipf/man/ipl.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipl.4,v 1.5 2003/01/04 01:18:02 wiz Exp $ +.\" $NetBSD: ipl.4,v 1.6 2004/03/28 09:00:56 martti Exp $ .\" .TH IPL 4 .SH NAME @@ -51,7 +51,7 @@ When reading from the \fBipl\fP device, it is necessary to call read(2) with a buffer big enough to hold at least 1 complete log record - reading of partial log records is not supported. .PP -If the packet contents are more than 128 bytes when \fBlog body\fP is used, +If the packet contents is more then 128 bytes when \fBlog body\fP is used, then only 128 bytes of the packet contents is logged. .PP Although it is only possible to read from the \fBipl\fP device, opening it @@ -78,4 +78,4 @@ ipf(4) .SH BUGS Packet headers are dropped when the internal buffer (static size) fills. .SH FILES -/dev/ipl +/dev/ipl0 diff --git a/dist/ipf/man/ipmon.8 b/dist/ipf/man/ipmon.8 index 474420dadb88..019a769dd1d0 100644 --- a/dist/ipf/man/ipmon.8 +++ b/dist/ipf/man/ipmon.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipmon.8,v 1.14 2004/01/28 20:15:52 kleink Exp $ +.\" $NetBSD: ipmon.8,v 1.15 2004/03/28 09:00:56 martti Exp $ .\" .TH ipmon 8 .SH NAME @@ -48,11 +48,8 @@ long). 4. The group and rule number of the rule, e.g., \fB@0:17\fP. These can be viewed with \fBipfstat -n\fP. .LP -5. The action: \fBp\fP for passed, \fBb\fP for blocked, \fBS\fP for a short -packet, \fBn\fP did not match any rules, \fBL\fP for a log rule. The order -of precedence in showing flags is: S, p, b, n, L. A capital \fBP\fP or -\fBB\fP means that the packet has been logged due to a global logging -setting, not a particular rule. +5. The action: \fBp\fP for passed, \fBb\fP for blocked, \fB\fP for a short +packet, \fBn\fP did not match any rules or \fBL\fP for a log rule. .LP 6. The addresses. This is actually three fields: the source address and port @@ -172,3 +169,5 @@ recorded data. .SH SEE ALSO ipl(4), ipf(8), ipfstat(8), ipnat(8) .SH BUGS +.PP +If you find any, please send email to me at darrenr@pobox.com diff --git a/dist/ipf/man/ipnat.5 b/dist/ipf/man/ipnat.5 index 88053b9c1a02..4ab8a5a8913c 100644 --- a/dist/ipf/man/ipnat.5 +++ b/dist/ipf/man/ipnat.5 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipnat.5,v 1.14 2003/07/02 13:26:26 wiz Exp $ +.\" $NetBSD: ipnat.5,v 1.15 2004/03/28 09:00:56 martti Exp $ .\" .TH IPNAT 5 .SH NAME @@ -9,11 +9,11 @@ The format for files accepted by ipnat is described by the following grammar: .nf ipmap :: = mapblock | redir | map . -map ::= mapit ifname ipmask "->" dstipmask [ mapport ] [ clamp ] . -map ::= mapit ifname fromto "->" dstipmask [ mapport ] [ clamp ] . -mapblock ::= "map-block" ifname ipmask "->" ipmask [ ports ] [ clamp ] . -redir ::= "rdr" ifname ipmask dport "->" ip [ "," ip ] rdrport options . +map ::= mapit ifname lhs "->" dstipmask [ mapport | mapproxy ] mapoptions. +mapblock ::= "map-block" ifname lhs "->" ipmask [ ports ] mapoptions. +redir ::= "rdr" ifname ipmask dport "->" ip [ "," ip ] rdrport rdroptions . +lhs ::= ipmask | fromto . dport ::= "port" portnum [ "-" portnum ] . ports ::= "ports" numports | "auto" . rdrport ::= "port" portnum . @@ -22,28 +22,32 @@ fromto ::= "from" object "to" object . ipmask ::= ip "/" bits | ip "/" mask | ip "netmask" mask . dstipmask ::= ipmask | "range" ip "-" ip . mapport ::= "portmap" tcpudp portspec . -clamp ::= "mssclamp" number . -options ::= [ tcpudp ] [ rr ] . +mapoptions ::= [ tcpudp ] [ "frag" ] [ age ] [ clamp ] . +rdroptions ::= rdrproto [ rr ] [ "frag" ] [ age ] [ clamp ] [ rdrproxy ] . -object :: = addr [ port-comp | port-range ] . -addr :: = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +object :: = addr [ port-comp | port-range ] . +addr :: = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . port-comp :: = "port" compare port-num . port-range :: = "port" port-num range port-num . +rdrproto ::= tcpudp | protocol . rr ::= "round-robin" . -nummask = host-name [ "/" decnumber ] . -tcpudp ::= "tcp" | "udp" | "tcp/udp" . +age ::= "age" decnumber [ "/" decnumber ] . +clamp ::= "mssclamp" decnumber . +tcpudp ::= "tcp/udp" | protocol . +mapproxy ::= "proxy" "port" port proxy-name '/' protocol +rdrproxy ::= "proxy" proxy-name . + +protocol ::= protocol-name | decnumber . +nummask ::= host-name [ "/" decnumber ] . portspec ::= "auto" | portnumber ":" portnumber . +port ::= portnumber | port-name . portnumber ::= number { numbers } . ifname ::= 'A' - 'Z' { 'A' - 'Z' } numbers . numbers ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' . .fi .PP -In addition to this, # is used to mark the start of a comment and may -appear at the end of a line with a NAT rule (as described above) or on its -own lines. Blank lines are ignored. -.PP For standard NAT functionality, a rule should start with \fBmap\fP and then proceeds to specify the interface for which outgoing packets will have their source address rewritten. @@ -99,15 +103,6 @@ or as map de0 from 10.1.0.0/16 to any -> 201.2.3.4/32 .fi .LP -For even greater control, one may negate either of the "from" or "to" clauses -with a preceding exclamation mark ("!"). Please note that one may not use a -negated "from" within a \fBmap\fP rule or a negated "to" within a \fBrdr\fP -rule. Such a rule might look like the following: -.LP -.nf -+map de0 from 10.1.0.0/16 ! to 10.1.0.0/16 -> 201.2.3.4/32 -.fi -.PP Only IP address and port numbers can be compared against. This is available with all NAT rules. .SH TRANSLATION @@ -128,11 +123,74 @@ how it searches for a new, free and unique tuple, in that it will used an algorithm to determine what the new source address should be, along with the range of available ports - the IP address is never changed and nor does the port number ever exceed its allotted range. +.SH ICMPIDMAP +.PP +ICMP messages can be divided into two groups: "errors" and "queries". ICMP +errors are generated as a response of another IP packet. IP Filter will take +care that ICMP errors that are the response of a NAT-ed IP packet are +handled properly. +.PP +For 4 types of ICMP queries (echo request, timestamp request, information +request and address mask request) IP Filter supports an additional mapping +called "ICMP id mapping". All these 4 types of ICMP queries use a unique +identifier called the ICMP id. This id is set by the process sending the +ICMP query and it is usually equal to the process id. The receiver of the +ICMP query will use the same id in its response, thus enabling the +sender to recognize that the incoming ICMP reply is intended for him and is +an answer to a query that he made. The "ICMP id mapping" feature modifies +these ICMP id in a way identical to \fBportmap\fP for TCP or UDP. +.PP +The reason that you might want this, is that using this feature you don't +need an IP address per host behind the NAT box, that wants to do ICMP queries. +The two numbers behind the \fBicmpidmap\fP keyword are the first and the +last icmp id number that can be used. There is one important caveat: if you +map to an IP address that belongs to the NAT box itself (notably if you have +only a single public IP address), then you must ensure that the NAT box does +not use the \fBicmpidmap\fP range that you specified in the \fBmap\fP rule. +Since the ICMP id is usually the process id, it is wise to restrict the +largest permittable process id (PID) on your operating system to e.g. 63999 and +use the range 64000:65535 for ICMP id mapping. Changing the maximal PID is +system dependent. For most BSD derived systems can be done by changing +PID_MAX in /usr/include/sys/proc.h and then rebuild the system. .SH KERNEL PROXIES .PP IP Filter comes with a few, simple, proxies built into the code that is loaded into the kernel to allow secondary channels to be opened without forcing the -packets through a user program. +packets through a user program. The current state of the proxies is listed +below, as one of three states: +.HP +Aging - protocol is roughly understood from +the time at which the proxy was written but it is not well tested or +maintained; +.HP +Developmental - basic functionality exists, works most of the time but +may be problematic in extended real use; +.HP +Experimental - rough support for the protocol at best, may or may not +work as testing has been at best sporadic, possible large scale changes +to the code in order to properly support the protocol. +.HP +Mature - well tested, protocol is properly +understood by the proxy; +.PP +The currently compiled in proxy list is as follows: +.HP +FTP - Mature +.HP +IRC - Experimental +.HP +rpcbind - Experimental +.HP +H.323 - Experimental +.HP +Real Audio (PNA) - Aging +.HP +IPsec - Developmental +.HP +netbios - Experimental +.HP +R-command - Mature + .SH TRANSPARENT PROXIES .PP True transparent proxying should be performed using the redirect (\fBrdr\fP) @@ -219,23 +277,6 @@ own. As opposed to the above use of \fBmap\fP, if for some reason the user of (say) 172.192.0.2 wanted 260 simultaneous connections going out, they would be limited to 252 with \fBmap-block\fP but would just \fImove on\fP to the next IP address with the \fBmap\fP command. -.LP -.nf -map pppoe0 10.0.0.0/8 -> 209.1.2.0/24 mssclamp 1452 -.fi -.PP -The mssclamp clause tells the NAT processor to scan for TCP packets in the -three-way handshake and limit their negotiated MSS value to the number -given in the rule. This is useful to make hosts behind a connection with -low MTU (like PPPoE or tunnels) communicate without any outside proxies -with broken sites that use a misconfigured firewall. Unfortunately such -sites are not rare. -.PP -The value for the clamping clause is calculated as interface-MTU less -40 bytes (size of IP header plus maximal IP options size), so for a -PPPoE interface it is 1492 - 40 = 1452. Some sites seem to require clamping -to even smaller values, but there is no rationale for this behaviour. -.SH FILES /dev/ipnat .br /etc/services diff --git a/dist/ipf/man/ipnat.8 b/dist/ipf/man/ipnat.8 index 85dc19a19134..cb80b5d8240f 100644 --- a/dist/ipf/man/ipnat.8 +++ b/dist/ipf/man/ipnat.8 @@ -1,8 +1,8 @@ -.\" $NetBSD: ipnat.8,v 1.4 2002/09/12 06:58:13 jdolecek Exp $ +.\" $NetBSD: ipnat.8,v 1.5 2004/03/28 09:00:56 martti Exp $ .\" .TH IPNAT 8 .SH NAME -ipnat \- user interface to the NAT +ipnat \- user interface to the NAT subsystem .SH SYNOPSIS .Nm ipnat .B ipnat diff --git a/dist/ipf/misc.c b/dist/ipf/misc.c deleted file mode 100644 index bf1b49dd4d16..000000000000 --- a/dist/ipf/misc.c +++ /dev/null @@ -1,211 +0,0 @@ -/* $NetBSD: misc.c,v 1.7 2002/05/30 18:10:29 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2002 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#if (SOLARIS2 >= 7) -# define _SYS_VARARGS_H -# define _VARARGS_H -#endif -#if defined(__STDC__) -# include -#else -# include -#endif -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include -#include "ip_fil.h" -#include "ipf.h" -#include "ipt.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)misc.c 1.3 2/4/96 (C) 1995 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: misc.c,v 2.2.2.8 2002/04/26 10:24:24 darrenr Exp"; -#endif - -extern int opts; - - -void printpacket(ip) -ip_t *ip; -{ - tcphdr_t *tcp; - u_short len; - - if (ip->ip_v == 4) - len = ntohs(ip->ip_len); - else if (ip->ip_v == 6) - len = ntohs(((u_short *)ip)[2]) + 40; - else - len = 0; - - if ((opts & OPT_HEX) == OPT_HEX) { - u_char *s; - int i; - - for (s = (u_char *)ip, i = 0; i < len; i++) { - printf("%02x", *s++ & 0xff); - if (len - i > 1) { - i++; - printf("%02x", *s++ & 0xff); - } - if (i + 1 != len) - putchar(' '); - } - putchar('\n'); - return; - } - - if (ip->ip_v == 6) { - printpacket6(ip); - return; - } - - tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2)); - printf("ip %d(%d) %d", ntohs(ip->ip_len), ip->ip_hl << 2, ip->ip_p); - if (ip->ip_off & IP_OFFMASK) - printf(" @%d", ip->ip_off << 3); - (void)printf(" %s", inet_ntoa(ip->ip_src)); - if (!(ip->ip_off & IP_OFFMASK)) - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) - (void)printf(",%d", ntohs(tcp->th_sport)); - (void)printf(" > "); - (void)printf("%s", inet_ntoa(ip->ip_dst)); - if (!(ip->ip_off & IP_OFFMASK)) { - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) - (void)printf(",%d", ntohs(tcp->th_dport)); - if ((ip->ip_p == IPPROTO_TCP) && (tcp->th_flags)) { - putchar(' '); - if (tcp->th_flags & TH_FIN) - putchar('F'); - if (tcp->th_flags & TH_SYN) - putchar('S'); - if (tcp->th_flags & TH_RST) - putchar('R'); - if (tcp->th_flags & TH_PUSH) - putchar('P'); - if (tcp->th_flags & TH_ACK) - putchar('A'); - if (tcp->th_flags & TH_URG) - putchar('U'); - if (tcp->th_flags & TH_ECN) - putchar('E'); - if (tcp->th_flags & TH_CWR) - putchar('C'); - } - } - putchar('\n'); -} - - -/* - * This is meant to work without the IPv6 header files being present or - * the inet_ntop() library. - */ -void printpacket6(ip) -ip_t *ip; -{ - u_char *buf, p, hops; - u_short plen, *addrs; - tcphdr_t *tcp; - u_32_t flow; - - buf = (u_char *)ip; - tcp = (tcphdr_t *)(buf + 40); - p = buf[6]; - hops = buf[7]; - flow = ntohl(*(u_32_t *)buf); - flow &= 0xfffff; - plen = ntohs(*((u_short *)buf +2)); - addrs = (u_short *)buf + 4; - - printf("ip6/%d %d %#x %d", buf[0] & 0xf, plen, flow, p); - printf(" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]), - ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]), - ntohs(addrs[6]), ntohs(addrs[7])); - if (plen >= 4) - if (p == IPPROTO_TCP || p == IPPROTO_UDP) - (void)printf(",%d", ntohs(tcp->th_sport)); - printf(" >"); - addrs += 8; - printf(" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]), - ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]), - ntohs(addrs[6]), ntohs(addrs[7])); - if (plen >= 4) - if (p == IPPROTO_TCP || p == IPPROTO_UDP) - (void)printf(",%d", ntohs(tcp->th_dport)); - putchar('\n'); -} - - -#if defined(__STDC__) -void verbose(char *fmt, ...) -#else -void verbose(fmt, va_alist) -char *fmt; -va_dcl -#endif -{ - va_list pvar; - - va_start(pvar, fmt); - if (opts & OPT_VERBOSE) - vprintf(fmt, pvar); - va_end(pvar); -} - - -#ifdef __STDC__ -void debug(char *fmt, ...) -#else -void debug(fmt, va_alist) -char *fmt; -va_dcl -#endif -{ - va_list pvar; - - va_start(pvar, fmt); - if (opts & OPT_DEBUG) - vprintf(fmt, pvar); - va_end(pvar); -} diff --git a/dist/ipf/ml_ipl.c b/dist/ipf/ml_ipl.c index 96dcfffd2086..40faa19d15fa 100644 --- a/dist/ipf/ml_ipl.c +++ b/dist/ipf/ml_ipl.c @@ -1,12 +1,9 @@ -/* $NetBSD: ml_ipl.c,v 1.3 2002/01/24 08:21:35 martti Exp $ */ +/* $NetBSD: ml_ipl.c,v 1.4 2004/03/28 09:00:54 martti Exp $ */ /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. - * responsibility and is not changed in any way. - * - * I hate legaleese, don't you ? */ /* * 29/12/94 Added code from Marc Huber to allow it to allocate @@ -37,7 +34,7 @@ extern int iplattach(), iplopen(), iplclose(), iplioctl(), iplread(); extern int nulldev(), iplidentify(), errno; -struct cdevsw ipldevsw = +struct cdevsw ipldevsw = { iplopen, iplclose, iplread, nulldev, iplioctl, nulldev, nulldev, nulldev, @@ -45,7 +42,7 @@ struct cdevsw ipldevsw = }; -struct dev_ops ipl_ops = +struct dev_ops ipl_ops = { 1, iplidentify, @@ -65,7 +62,7 @@ struct dev_ops ipl_ops = int ipl_major = 0; #ifdef sun4m -struct vdldrv vd = +struct vdldrv vd = { VDMAGIC_PSEUDO, "ipl", diff --git a/dist/ipf/natparse.c b/dist/ipf/natparse.c deleted file mode 100644 index 584e71d9609c..000000000000 --- a/dist/ipf/natparse.c +++ /dev/null @@ -1,783 +0,0 @@ -/* $NetBSD: natparse.c,v 1.10 2002/05/30 18:10:30 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2002 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) -# include -# include -#endif -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_nat.h" -#include "netinet/ip_state.h" -#include "netinet/ip_proxy.h" -#include "ipf.h" - -#if defined(sun) && !SOLARIS2 -# define STRERROR(x) sys_errlist[x] -extern char *sys_errlist[]; -#else -# define STRERROR(x) strerror(x) -#endif - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: natparse.c,v 1.17.2.24 2002/04/24 17:30:51 darrenr Exp"; -#endif - - -#if SOLARIS -#define bzero(a,b) memset(a,0,b) -#endif - -extern void printnat __P((ipnat_t *, int)); -extern int countbits __P((u_32_t)); -extern char *proto; - -ipnat_t *natparse __P((char *, int)); -void natparsefile __P((int, char *, int)); -void nat_setgroupmap __P((struct ipnat *)); - - -void nat_setgroupmap(n) -ipnat_t *n; -{ - if (n->in_outmsk == n->in_inmsk) - n->in_ippip = 1; - else if (n->in_flags & IPN_AUTOPORTMAP) { - n->in_ippip = ~ntohl(n->in_inmsk); - if (n->in_outmsk != 0xffffffff) - n->in_ippip /= (~ntohl(n->in_outmsk) + 1); - n->in_ippip++; - if (n->in_ippip == 0) - n->in_ippip = 1; - n->in_ppip = USABLE_PORTS / n->in_ippip; - } else { - n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); - n->in_nip = 0; - if (!(n->in_ppip = n->in_pmin)) - n->in_ppip = 1; - n->in_ippip = USABLE_PORTS / n->in_ppip; - } -} - - -/* - * Parse a line of input from the ipnat configuration file - */ -ipnat_t *natparse(line, linenum) -char *line; -int linenum; -{ - static ipnat_t ipn; - struct protoent *pr; - char *dnetm = NULL, *dport = NULL; - char *s, *t, *cps[31], **cpp; - int i, cnt; - char *port1a = NULL, *port1b = NULL, *port2a = NULL; - - proto = NULL; - - /* - * Search for end of line and comment marker, advance of leading spaces - */ - if ((s = strchr(line, '\n'))) - *s = '\0'; - if ((s = strchr(line, '#'))) - *s = '\0'; - while (*line && isspace(*line)) - line++; - if (!*line) - return NULL; - - bzero((char *)&ipn, sizeof(ipn)); - cnt = 0; - - /* - * split line upto into segments. - */ - for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++) - cps[++i] = strtok(NULL, " \b\t\r\n"); - - cps[i] = NULL; - - if (cnt < 3) { - fprintf(stderr, "%d: not enough segments in line\n", linenum); - return NULL; - } - - cpp = cps; - - /* - * Check first word is a recognised keyword and then is the interface - */ - if (!strcasecmp(*cpp, "map")) - ipn.in_redir = NAT_MAP; - else if (!strcasecmp(*cpp, "map-block")) - ipn.in_redir = NAT_MAPBLK; - else if (!strcasecmp(*cpp, "rdr")) - ipn.in_redir = NAT_REDIRECT; - else if (!strcasecmp(*cpp, "bimap")) - ipn.in_redir = NAT_BIMAP; - else { - fprintf(stderr, "%d: unknown mapping: \"%s\"\n", - linenum, *cpp); - return NULL; - } - - cpp++; - - strncpy(ipn.in_ifname, *cpp, sizeof(ipn.in_ifname) - 1); - ipn.in_ifname[sizeof(ipn.in_ifname) - 1] = '\0'; - cpp++; - - /* - * If the first word after the interface is "from" or is a ! then - * the expanded syntax is being used so parse it differently. - */ - if (!strcasecmp(*cpp, "from") || (**cpp == '!')) { - if (!strcmp(*cpp, "!")) { - cpp++; - if (strcasecmp(*cpp, "from")) { - fprintf(stderr, "Missing from after !\n"); - return NULL; - } - ipn.in_flags |= IPN_NOTSRC; - } else if (**cpp == '!') { - if (strcasecmp(*cpp + 1, "from")) { - fprintf(stderr, "Missing from after !\n"); - return NULL; - } - ipn.in_flags |= IPN_NOTSRC; - } - if ((ipn.in_flags & IPN_NOTSRC) && - (ipn.in_redir & (NAT_MAP|NAT_MAPBLK))) { - fprintf(stderr, "Cannot use '! from' with map\n"); - return NULL; - } - - ipn.in_flags |= IPN_FILTER; - cpp++; - if (ipn.in_redir == NAT_REDIRECT) { - if (hostmask(&cpp, (u_32_t *)&ipn.in_srcip, - (u_32_t *)&ipn.in_srcmsk, &ipn.in_sport, - &ipn.in_scmp, &ipn.in_stop, linenum)) { - return NULL; - } - } else { - if (hostmask(&cpp, (u_32_t *)&ipn.in_inip, - (u_32_t *)&ipn.in_inmsk, &ipn.in_sport, - &ipn.in_scmp, &ipn.in_stop, linenum)) { - return NULL; - } - } - - if (!strcmp(*cpp, "!")) { - cpp++; - ipn.in_flags |= IPN_NOTDST; - } else if (**cpp == '!') { - (*cpp)++; - ipn.in_flags |= IPN_NOTDST; - } - - if (strcasecmp(*cpp, "to")) { - fprintf(stderr, "%d: unexpected keyword (%s) - to\n", - linenum, *cpp); - return NULL; - } - if ((ipn.in_flags & IPN_NOTDST) && - (ipn.in_redir & (NAT_REDIRECT))) { - fprintf(stderr, "Cannot use '! to' with rdr\n"); - return NULL; - } - - if (!*++cpp) { - fprintf(stderr, "%d: missing host after to\n", linenum); - return NULL; - } - if (ipn.in_redir == NAT_REDIRECT) { - if (hostmask(&cpp, (u_32_t *)&ipn.in_outip, - (u_32_t *)&ipn.in_outmsk, &ipn.in_dport, - &ipn.in_dcmp, &ipn.in_dtop, linenum)) { - return NULL; - } - ipn.in_pmin = htons(ipn.in_dport); - } else { - if (hostmask(&cpp, (u_32_t *)&ipn.in_srcip, - (u_32_t *)&ipn.in_srcmsk, &ipn.in_dport, - &ipn.in_dcmp, &ipn.in_dtop, linenum)) { - return NULL; - } - } - } else { - s = *cpp; - if (!s) { - fprintf(stderr, "%d: short line\n", linenum); - return NULL; - } - t = strchr(s, '/'); - if (!t) { - fprintf(stderr, "%d: no netmask on LHS\n", linenum); - return NULL; - } - *t++ = '\0'; - if (ipn.in_redir == NAT_REDIRECT) { - if (hostnum((u_32_t *)&ipn.in_outip, s, linenum) == -1) - return NULL; - if (genmask(t, (u_32_t *)&ipn.in_outmsk) == -1) { - return NULL; - } - } else { - if (hostnum((u_32_t *)&ipn.in_inip, s, linenum) == -1) - return NULL; - if (genmask(t, (u_32_t *)&ipn.in_inmsk) == -1) { - return NULL; - } - } - cpp++; - if (!*cpp) { - fprintf(stderr, "%d: short line\n", linenum); - return NULL; - } - } - - /* - * If it is a standard redirect then we expect it to have a port - * match after the hostmask. - */ - if ((ipn.in_redir == NAT_REDIRECT) && !(ipn.in_flags & IPN_FILTER)) { - if (strcasecmp(*cpp, "port")) { - fprintf(stderr, "%d: missing fields - 1st port\n", - linenum); - return NULL; - } - - cpp++; - - if (!*cpp) { - fprintf(stderr, - "%d: missing fields (destination port)\n", - linenum); - return NULL; - } - - if (isdigit(**cpp) && (s = strchr(*cpp, '-'))) - *s++ = '\0'; - else - s = NULL; - - port1a = *cpp++; - - if (!strcmp(*cpp, "-")) { - cpp++; - s = *cpp++; - } - - if (s) - port1b = s; - else - ipn.in_pmax = ipn.in_pmin; - } - - /* - * In the middle of the NAT rule syntax is -> to indicate the - * direction of translation. - */ - if (!*cpp) { - fprintf(stderr, "%d: missing fields (->)\n", linenum); - return NULL; - } - if (strcmp(*cpp, "->")) { - fprintf(stderr, "%d: missing ->\n", linenum); - return NULL; - } - cpp++; - - if (!*cpp) { - fprintf(stderr, "%d: missing fields (%s)\n", - linenum, ipn.in_redir ? "destination" : "target"); - return NULL; - } - - if (ipn.in_redir == NAT_MAP) { - if (!strcasecmp(*cpp, "range")) { - cpp++; - ipn.in_flags |= IPN_IPRANGE; - if (!*cpp) { - fprintf(stderr, "%d: missing fields (%s)\n", - linenum, - ipn.in_redir ? "destination":"target"); - return NULL; - } - } - } - - if (ipn.in_flags & IPN_IPRANGE) { - dnetm = strrchr(*cpp, '-'); - if (dnetm == NULL) { - cpp++; - if (*cpp && !strcmp(*cpp, "-") && *(cpp + 1)) - dnetm = *(cpp + 1); - } else - *dnetm++ = '\0'; - if (dnetm == NULL || *dnetm == '\0') { - fprintf(stderr, - "%d: desination range not specified\n", - linenum); - return NULL; - } - } else if (ipn.in_redir != NAT_REDIRECT) { - dnetm = strrchr(*cpp, '/'); - if (dnetm == NULL) { - cpp++; - if (*cpp && !strcasecmp(*cpp, "netmask")) - dnetm = *++cpp; - } - if (dnetm == NULL) { - fprintf(stderr, - "%d: missing fields (dest netmask)\n", - linenum); - return NULL; - } - if (*dnetm == '/') - *dnetm++ = '\0'; - } - - if (ipn.in_redir == NAT_REDIRECT) { - dnetm = strchr(*cpp, ','); - if (dnetm != NULL) { - ipn.in_flags |= IPN_SPLIT; - *dnetm++ = '\0'; - } - if (hostnum((u_32_t *)&ipn.in_inip, *cpp, linenum) == -1) - return NULL; - } else { - if (!strcmp(*cpp, ipn.in_ifname)) - *cpp = "0"; - if (hostnum((u_32_t *)&ipn.in_outip, *cpp, linenum) == -1) - return NULL; - } - cpp++; - - if (ipn.in_redir & NAT_MAPBLK) { - if (*cpp) { - if (strcasecmp(*cpp, "ports")) { - fprintf(stderr, - "%d: expected \"ports\" - got \"%s\"\n", - linenum, *cpp); - return NULL; - } - cpp++; - if (*cpp == NULL) { - fprintf(stderr, - "%d: missing argument to \"ports\"\n", - linenum); - return NULL; - } - if (!strcasecmp(*cpp, "auto")) - ipn.in_flags |= IPN_AUTOPORTMAP; - else - ipn.in_pmin = atoi(*cpp); - cpp++; - } else - ipn.in_pmin = 0; - } else if ((ipn.in_redir & NAT_BIMAP) == NAT_REDIRECT) { - if (*cpp && (strrchr(*cpp, '/') != NULL)) { - fprintf(stderr, "%d: No netmask supported in %s\n", - linenum, "destination host for redirect"); - return NULL; - } - - if (!*cpp) { - fprintf(stderr, "%d: Missing destination port %s\n", - linenum, "in redirect"); - return NULL; - } - - /* If it's a in_redir, expect target port */ - - if (strcasecmp(*cpp, "port")) { - fprintf(stderr, "%d: missing fields - 2nd port (%s)\n", - linenum, *cpp); - return NULL; - } - cpp++; - if (!*cpp) { - fprintf(stderr, - "%d: missing fields (destination port)\n", - linenum); - return NULL; - } - - port2a = *cpp++; - } - if (dnetm && *dnetm == '/') - *dnetm++ = '\0'; - - if (ipn.in_redir & (NAT_MAP|NAT_MAPBLK)) { - if (ipn.in_flags & IPN_IPRANGE) { - if (hostnum((u_32_t *)&ipn.in_outmsk, dnetm, - linenum) == -1) - return NULL; - } else if (genmask(dnetm, (u_32_t *)&ipn.in_outmsk)) - return NULL; - } else { - if (ipn.in_flags & IPN_SPLIT) { - if (hostnum((u_32_t *)&ipn.in_inmsk, dnetm, - linenum) == -1) - return NULL; - } else if (genmask("255.255.255.255", (u_32_t *)&ipn.in_inmsk)) - return NULL; - if (!*cpp) { - ipn.in_flags |= IPN_TCP; /* XXX- TCP only by default */ - proto = "tcp"; - } else { - proto = *cpp++; - if (!strcasecmp(proto, "tcp")) - ipn.in_flags |= IPN_TCP; - else if (!strcasecmp(proto, "udp")) - ipn.in_flags |= IPN_UDP; - else if (!strcasecmp(proto, "tcp/udp")) - ipn.in_flags |= IPN_TCPUDP; - else if (!strcasecmp(proto, "tcpudp")) { - ipn.in_flags |= IPN_TCPUDP; - proto = "tcp/udp"; - } else if (!strcasecmp(proto, "ip")) - ipn.in_flags |= IPN_ANY; - else { - ipn.in_flags |= IPN_ANY; - if ((pr = getprotobyname(proto))) - ipn.in_p = pr->p_proto; - else { - if (!isdigit(*proto)) { - fprintf(stderr, - "%d: Unknown protocol %s\n", - linenum, proto); - return NULL; - } else - ipn.in_p = atoi(proto); - } - } - if ((ipn.in_flags & IPN_TCPUDP) == 0) { - port1a = "0"; - port2a = "0"; - } - - if (*cpp && !strcasecmp(*cpp, "round-robin")) { - cpp++; - ipn.in_flags |= IPN_ROUNDR; - } - - if (*cpp && !strcasecmp(*cpp, "frag")) { - cpp++; - ipn.in_flags |= IPN_FRAG; - } - - if (*cpp && !strcasecmp(*cpp, "age")) { - cpp++; - if (!*cpp) { - fprintf(stderr, - "%d: age with no parameters\n", - linenum); - return NULL; - } - - ipn.in_age[0] = atoi(*cpp); - s = index(*cpp, '/'); - if (s != NULL) - ipn.in_age[1] = atoi(s + 1); - else - ipn.in_age[1] = ipn.in_age[0]; - cpp++; - } - - if (*cpp) { - fprintf(stderr, - "%d: extra junk at the end of the line: %s\n", - linenum, *cpp); - return NULL; - } - } - } - - if ((ipn.in_redir == NAT_REDIRECT) && !(ipn.in_flags & IPN_FILTER)) { - if (!portnum(port1a, &ipn.in_pmin, linenum)) - return NULL; - ipn.in_pmin = htons(ipn.in_pmin); - if (port1b != NULL) { - if (!portnum(port1b, &ipn.in_pmax, linenum)) - return NULL; - ipn.in_pmax = htons(ipn.in_pmax); - } else - ipn.in_pmax = ipn.in_pmin; - } - - if ((ipn.in_redir & NAT_BIMAP) == NAT_REDIRECT) { - if (!portnum(port2a, &ipn.in_pnext, linenum)) - return NULL; - ipn.in_pnext = htons(ipn.in_pnext); - } - - if (!(ipn.in_flags & IPN_SPLIT)) - ipn.in_inip &= ipn.in_inmsk; - if ((ipn.in_flags & IPN_IPRANGE) == 0) - ipn.in_outip &= ipn.in_outmsk; - ipn.in_srcip &= ipn.in_srcmsk; - - if ((ipn.in_redir & NAT_MAPBLK) != 0) - nat_setgroupmap(&ipn); - - if (*cpp && !*(cpp+1) && !strcasecmp(*cpp, "frag")) { - cpp++; - ipn.in_flags |= IPN_FRAG; - } - - if (!*cpp) - return &ipn; - - if (ipn.in_redir == NAT_BIMAP) { - fprintf(stderr, - "%d: extra words at the end of bimap line: %s\n", - linenum, *cpp); - return NULL; - } - - if (!strcasecmp(*cpp, "proxy")) { - if (ipn.in_redir == NAT_BIMAP) { - fprintf(stderr, "%d: cannot use proxy with bimap\n", - linenum); - return NULL; - } - cpp++; - if (!*cpp) { - fprintf(stderr, - "%d: missing parameter for \"proxy\"\n", - linenum); - return NULL; - } - dport = NULL; - - if (!strcasecmp(*cpp, "port")) { - cpp++; - if (!*cpp) { - fprintf(stderr, - "%d: missing parameter for \"port\"\n", - linenum); - return NULL; - } - - dport = *cpp; - cpp++; - - if (!*cpp) { - fprintf(stderr, - "%d: missing parameter for \"proxy\"\n", - linenum); - return NULL; - } - } else { - fprintf(stderr, - "%d: missing keyword \"port\"\n", linenum); - return NULL; - } - - if ((proto = index(*cpp, '/'))) { - *proto++ = '\0'; - if ((pr = getprotobyname(proto))) - ipn.in_p = pr->p_proto; - else - ipn.in_p = atoi(proto); - } else - ipn.in_p = 0; - - if (dport && !portnum(dport, &ipn.in_dport, linenum)) - return NULL; - ipn.in_dport = htons(ipn.in_dport); - - (void) strncpy(ipn.in_plabel, *cpp, sizeof(ipn.in_plabel)); - cpp++; - - } else if (!strcasecmp(*cpp, "portmap")) { - if (ipn.in_redir == NAT_BIMAP) { - fprintf(stderr, "%d: cannot use portmap with bimap\n", - linenum); - return NULL; - } - cpp++; - if (!*cpp) { - fprintf(stderr, - "%d: missing expression following portmap\n", - linenum); - return NULL; - } - - if (!strcasecmp(*cpp, "tcp")) - ipn.in_flags |= IPN_TCP; - else if (!strcasecmp(*cpp, "udp")) - ipn.in_flags |= IPN_UDP; - else if (!strcasecmp(*cpp, "tcpudp")) - ipn.in_flags |= IPN_TCPUDP; - else if (!strcasecmp(*cpp, "tcp/udp")) - ipn.in_flags |= IPN_TCPUDP; - else { - fprintf(stderr, - "%d: expected protocol name - got \"%s\"\n", - linenum, *cpp); - return NULL; - } - proto = *cpp; - cpp++; - - if (!*cpp) { - fprintf(stderr, "%d: no port range found\n", linenum); - return NULL; - } - - if (!strcasecmp(*cpp, "auto")) { - ipn.in_flags |= IPN_AUTOPORTMAP; - ipn.in_pmin = htons(1024); - ipn.in_pmax = htons(65535); - nat_setgroupmap(&ipn); - cpp++; - } else { - if (!(t = strchr(*cpp, ':'))) { - fprintf(stderr, - "%d: no port range in \"%s\"\n", - linenum, *cpp); - return NULL; - } - *t++ = '\0'; - if (!portnum(*cpp, &ipn.in_pmin, linenum) || - !portnum(t, &ipn.in_pmax, linenum)) - return NULL; - ipn.in_pmin = htons(ipn.in_pmin); - ipn.in_pmax = htons(ipn.in_pmax); - cpp++; - } - } - - if (*cpp && !strcasecmp(*cpp, "frag")) { - cpp++; - ipn.in_flags |= IPN_FRAG; - } - - if (*cpp && !strcasecmp(*cpp, "age")) { - cpp++; - if (!*cpp) { - fprintf(stderr, "%d: age with no parameters\n", - linenum); - return NULL; - } - ipn.in_age[0] = atoi(*cpp); - s = index(*cpp, '/'); - if (s != NULL) - ipn.in_age[1] = atoi(s + 1); - else - ipn.in_age[1] = ipn.in_age[0]; - cpp++; - } - - if (*cpp && !strcasecmp(*cpp, "mssclamp")) { - cpp++; - if (*cpp) { - ipn.in_mssclamp = atoi(*cpp); - cpp++; - } - } - - if (*cpp) { - fprintf(stderr, "%d: extra junk at the end of the line: %s\n", - linenum, *cpp); - return NULL; - } - return &ipn; -} - - -void natparsefile(fd, file, opts) -int fd; -char *file; -int opts; -{ - char line[512], *s; - ipnat_t *np; - FILE *fp; - int linenum = 0; - - if (strcmp(file, "-")) { - if (!(fp = fopen(file, "r"))) { - fprintf(stderr, "%s: open: %s\n", file, - STRERROR(errno)); - exit(1); - } - } else - fp = stdin; - - while (fgets(line, sizeof(line) - 1, fp)) { - linenum++; - line[sizeof(line) - 1] = '\0'; - if ((s = strchr(line, '\n'))) - *s = '\0'; - - if (!(np = natparse(line, linenum))) { - if (*line) - fprintf(stderr, "%d: syntax error in \"%s\"\n", - linenum, line); - } else { - if ((opts & OPT_VERBOSE) && np) - printnat(np, opts); - if (!(opts & OPT_NODO)) { - if (!(opts & OPT_REMOVE)) { - if (ioctl(fd, SIOCADNAT, &np) == -1) { - fprintf(stderr, "%d:", - linenum); - perror("ioctl(SIOCADNAT)"); - } - } else if (ioctl(fd, SIOCRMNAT, &np) == -1) { - fprintf(stderr, "%d:", linenum); - perror("ioctl(SIOCRMNAT)"); - } - } - } - } - if (fp != stdin) - fclose(fp); -} diff --git a/dist/ipf/opt.c b/dist/ipf/opt.c deleted file mode 100644 index 733c0d190936..000000000000 --- a/dist/ipf/opt.c +++ /dev/null @@ -1,183 +0,0 @@ -/* $NetBSD: opt.c,v 1.5 2002/04/09 02:32:53 thorpej Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef linux -#include -#endif -#include -#include -#include -#include "ip_compat.h" -#include -#include "ip_fil.h" -#include "ipf.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)opt.c 1.8 4/10/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: opt.c,v 2.2.2.2 2002/02/22 15:32:56 darrenr Exp"; -#endif - -extern int opts; - -struct ipopt_names ionames[] ={ - { IPOPT_NOP, 0x000001, 1, "nop" }, - { IPOPT_RR, 0x000002, 7, "rr" }, /* 1 route */ - { IPOPT_ZSU, 0x000004, 3, "zsu" }, - { IPOPT_MTUP, 0x000008, 3, "mtup" }, - { IPOPT_MTUR, 0x000010, 3, "mtur" }, - { IPOPT_ENCODE, 0x000020, 3, "encode" }, - { IPOPT_TS, 0x000040, 8, "ts" }, /* 1 TS */ - { IPOPT_TR, 0x000080, 3, "tr" }, - { IPOPT_SECURITY,0x000100, 11, "sec" }, - { IPOPT_SECURITY,0x000100, 11, "sec-class" }, - { IPOPT_LSRR, 0x000200, 7, "lsrr" }, /* 1 route */ - { IPOPT_E_SEC, 0x000400, 3, "e-sec" }, - { IPOPT_CIPSO, 0x000800, 3, "cipso" }, - { IPOPT_SATID, 0x001000, 4, "satid" }, - { IPOPT_SSRR, 0x002000, 7, "ssrr" }, /* 1 route */ - { IPOPT_ADDEXT, 0x004000, 3, "addext" }, - { IPOPT_VISA, 0x008000, 3, "visa" }, - { IPOPT_IMITD, 0x010000, 3, "imitd" }, - { IPOPT_EIP, 0x020000, 3, "eip" }, - { IPOPT_FINN, 0x040000, 3, "finn" }, - { 0, 0, 0, (char *)NULL } /* must be last */ -}; - -struct ipopt_names secclass[] = { - { IPSO_CLASS_RES4, 0x01, 0, "reserv-4" }, - { IPSO_CLASS_TOPS, 0x02, 0, "topsecret" }, - { IPSO_CLASS_SECR, 0x04, 0, "secret" }, - { IPSO_CLASS_RES3, 0x08, 0, "reserv-3" }, - { IPSO_CLASS_CONF, 0x10, 0, "confid" }, - { IPSO_CLASS_UNCL, 0x20, 0, "unclass" }, - { IPSO_CLASS_RES2, 0x40, 0, "reserv-2" }, - { IPSO_CLASS_RES1, 0x80, 0, "reserv-1" }, - { 0, 0, 0, NULL } /* must be last */ -}; - - -static u_char seclevel __P((char *)); -int addipopt __P((char *, struct ipopt_names *, int, char *)); - -static u_char seclevel(slevel) -char *slevel; -{ - struct ipopt_names *so; - - for (so = secclass; so->on_name; so++) - if (!strcasecmp(slevel, so->on_name)) - break; - - if (!so->on_name) { - fprintf(stderr, "no such security level: %s\n", slevel); - return 0; - } - return (u_char)so->on_value; -} - - -int addipopt(op, io, len, class) -char *op; -struct ipopt_names *io; -int len; -char *class; -{ - int olen = len; - struct in_addr ipadr; - u_short val; - u_char lvl; - char *s; - - if ((len + io->on_siz) > 48) { - fprintf(stderr, "options too long\n"); - return 0; - } - len += io->on_siz; - *op++ = io->on_value; - if (io->on_siz > 1) { - s = op; - *op++ = io->on_siz; - *op++ = IPOPT_MINOFF; - - if (class) { - switch (io->on_value) - { - case IPOPT_SECURITY : - lvl = seclevel(class); - *(op - 1) = lvl; - break; - case IPOPT_LSRR : - case IPOPT_SSRR : - ipadr.s_addr = inet_addr(class); - s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4; - bcopy((char *)&ipadr, op, sizeof(ipadr)); - break; - case IPOPT_SATID : - val = atoi(class); - bcopy((char *)&val, op, 2); - break; - } - } - - op += io->on_siz - 3; - if (len & 3) { - *op++ = IPOPT_NOP; - len++; - } - } - if (opts & OPT_DEBUG) - fprintf(stderr, "bo: %s %d %#x: %d\n", - io->on_name, io->on_value, io->on_bit, len); - return len - olen; -} - - -u_32_t buildopts(cp, op, len) -char *cp, *op; -int len; -{ - struct ipopt_names *io; - u_32_t msk = 0; - char *s, *t; - int inc; - - for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { - if ((t = strchr(s, '='))) - *t++ = '\0'; - for (io = ionames; io->on_name; io++) { - if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) - continue; - if ((inc = addipopt(op, io, len, t))) { - op += inc; - len += inc; - } - msk |= io->on_bit; - break; - } - if (!io->on_name) { - fprintf(stderr, "unknown IP option name %s\n", s); - return 0; - } - } - *op++ = IPOPT_EOL; - len++; - return len; -} diff --git a/dist/ipf/parse.c b/dist/ipf/parse.c deleted file mode 100644 index 3699f92e60de..000000000000 --- a/dist/ipf/parse.c +++ /dev/null @@ -1,1431 +0,0 @@ -/* $NetBSD: parse.c,v 1.13 2002/09/19 08:08:20 martti Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ip_compat.h" -#include "ip_fil.h" -#include "ipf.h" -#include "facpri.h" - -#if !defined(lint) -static const char sccsid[] __attribute__((__unused__)) = - "@(#)parse.c 1.44 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] __attribute__((__unused__)) = - "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 darrenr Exp $"; -#endif - -extern struct ipopt_names ionames[], secclass[]; -extern int opts; -extern int use_inet6; - -int addicmp __P((char ***, struct frentry *, int)); -int extras __P((char ***, struct frentry *, int)); - -int icmpcode __P((char *)), addkeep __P((char ***, struct frentry *, int)); -int to_interface __P((frdest_t *, char *, int)); -void print_toif __P((char *, frdest_t *)); -void optprint __P((u_short *, u_long, u_long)); -int loglevel __P((char **, u_int *, int)); -void printlog __P((frentry_t *)); -void printifname __P((char *, char *, void *)); - -extern char *proto; -extern char flagset[]; -extern u_char flags[]; - - -/* parse() - * - * parse a line read from the input filter rule file - */ -struct frentry *parse(line, linenum) -char *line; -int linenum; -{ - static struct frentry fil; - char *cps[31], **cpp, *endptr, *s; - struct protoent *p = NULL; - int i, cnt = 1, j, ch; - u_int k; - - while (*line && isspace(*line)) - line++; - if (!*line) - return NULL; - - bzero((char *)&fil, sizeof(fil)); - fil.fr_mip.fi_v = 0xf; - fil.fr_ip.fi_v = use_inet6 ? 6 : 4; - fil.fr_loglevel = 0xffff; - - /* - * break line up into max of 20 segments - */ - if (opts & OPT_DEBUG) - fprintf(stderr, "parse [%s]\n", line); - for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++) - cps[++i] = strtok(NULL, " \b\t\r\n"); - cps[i] = NULL; - - if (cnt < 3) { - fprintf(stderr, "%d: not enough segments in line\n", linenum); - return NULL; - } - - cpp = cps; - /* - * The presence of an '@' followed by a number gives the position in - * the current rule list to insert this one. - */ - if (**cpp == '@') - fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1; - - - /* - * Check the first keyword in the rule and any options that are - * expected to follow it. - */ - if (!strcasecmp("block", *cpp)) { - fil.fr_flags |= FR_BLOCK; - if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) && - (i = 19)) - fil.fr_flags |= FR_FAKEICMP; - else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11)) - fil.fr_flags |= FR_RETICMP; - if (fil.fr_flags & FR_RETICMP) { - cpp++; - if (strlen(*cpp) == i) { - if (*(cpp + 1) && **(cpp +1) == '(') { - cpp++; - i = 0; - } else - i = -1; - } - - /* - * The ICMP code is not required to follow in ()'s - */ - if ((i >= 0) && (*(*cpp + i) == '(')) { - i++; - j = icmpcode(*cpp + i); - if (j == -1) { - fprintf(stderr, - "%d: unrecognised icmp code %s\n", - linenum, *cpp + 20); - return NULL; - } - fil.fr_icode = j; - } - } else if (!strcasecmp(*(cpp+1), "return-rst")) { - fil.fr_flags |= FR_RETRST; - cpp++; - } - } else if (!strcasecmp("count", *cpp)) { - fil.fr_flags |= FR_ACCOUNT; - } else if (!strcasecmp("pass", *cpp)) { - fil.fr_flags |= FR_PASS; - } else if (!strcasecmp("nomatch", *cpp)) { - fil.fr_flags |= FR_NOMATCH; - } else if (!strcasecmp("auth", *cpp)) { - fil.fr_flags |= FR_AUTH; - } else if (!strcasecmp("preauth", *cpp)) { - fil.fr_flags |= FR_PREAUTH; - } else if (!strcasecmp("skip", *cpp)) { - cpp++; - if (ratoui(*cpp, &k, 0, UINT_MAX)) - fil.fr_skip = k; - else { - fprintf(stderr, "%d: integer must follow skip\n", - linenum); - return NULL; - } - } else if (!strcasecmp("log", *cpp)) { - fil.fr_flags |= FR_LOG; - if (!strcasecmp(*(cpp+1), "body")) { - fil.fr_flags |= FR_LOGBODY; - cpp++; - } - if (!strcasecmp(*(cpp+1), "first")) { - fil.fr_flags |= FR_LOGFIRST; - cpp++; - } - if (*cpp && !strcasecmp(*(cpp+1), "or-block")) { - fil.fr_flags |= FR_LOGORBLOCK; - cpp++; - } - if (!strcasecmp(*(cpp+1), "level")) { - cpp++; - if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) - return NULL; - cpp++; - } - } else { - /* - * Doesn't start with one of the action words - */ - fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp); - return NULL; - } - if (!*++cpp) { - fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum); - return NULL; - } - - /* - * Get the direction for filtering. Impose restrictions on direction - * if blocking with returning ICMP or an RST has been requested. - */ - if (!strcasecmp("in", *cpp)) - fil.fr_flags |= FR_INQUE; - else if (!strcasecmp("out", *cpp)) { - fil.fr_flags |= FR_OUTQUE; - if (fil.fr_flags & FR_RETICMP) { - fprintf(stderr, - "%d: Can only use return-icmp with 'in'\n", - linenum); - return NULL; - } else if (fil.fr_flags & FR_RETRST) { - fprintf(stderr, - "%d: Can only use return-rst with 'in'\n", - linenum); - return NULL; - } - } - if (!*++cpp) { - fprintf(stderr, "%d: missing source specification\n", linenum); - return NULL; - } - - if (!strcasecmp("log", *cpp)) { - if (!*++cpp) { - fprintf(stderr, "%d: missing source specification\n", - linenum); - return NULL; - } - if (fil.fr_flags & FR_PASS) - fil.fr_flags |= FR_LOGP; - else if (fil.fr_flags & FR_BLOCK) - fil.fr_flags |= FR_LOGB; - if (*cpp && !strcasecmp(*cpp, "body")) { - fil.fr_flags |= FR_LOGBODY; - cpp++; - } - if (*cpp && !strcasecmp(*cpp, "first")) { - fil.fr_flags |= FR_LOGFIRST; - cpp++; - } - if (*cpp && !strcasecmp(*cpp, "or-block")) { - if (!(fil.fr_flags & FR_PASS)) { - fprintf(stderr, - "%d: or-block must be used with pass\n", - linenum); - return NULL; - } - fil.fr_flags |= FR_LOGORBLOCK; - cpp++; - } - if (*cpp && !strcasecmp(*cpp, "level")) { - if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) - return NULL; - cpp++; - cpp++; - } - } - - if (*cpp && !strcasecmp("quick", *cpp)) { - if (fil.fr_skip != 0) { - fprintf(stderr, "%d: cannot use skip with quick\n", - linenum); - return NULL; - } - cpp++; - fil.fr_flags |= FR_QUICK; - } - - /* - * Parse rule options that are available if a rule is tied to an - * interface. - */ - *fil.fr_ifname = '\0'; - *fil.fr_oifname = '\0'; - if (*cpp && !strcasecmp(*cpp, "on")) { - if (!*++cpp) { - fprintf(stderr, "%d: interface name missing\n", - linenum); - return NULL; - } - - s = index(*cpp, ','); - if (s != NULL) { - *s++ = '\0'; - (void)strncpy(fil.fr_ifnames[1], s, IFNAMSIZ - 1); - fil.fr_ifnames[1][IFNAMSIZ - 1] = '\0'; - } else - strcpy(fil.fr_ifnames[1], "*"); - - (void)strncpy(fil.fr_ifnames[0], *cpp, IFNAMSIZ - 1); - fil.fr_ifnames[0][IFNAMSIZ - 1] = '\0'; - - cpp++; - if (!*cpp) { - if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) { - fprintf(stderr, - "%d: %s can only be used with TCP\n", - linenum, "return-rst"); - return NULL; - } - return &fil; - } - - if (*cpp) { - if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) { - cpp++; - if (to_interface(&fil.fr_dif, *cpp, linenum)) - return NULL; - cpp++; - } - if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) { - cpp++; - if (to_interface(&fil.fr_tif, *cpp, linenum)) - return NULL; - cpp++; - } else if (*cpp && !strcasecmp(*cpp, "fastroute")) { - if (!(fil.fr_flags & FR_INQUE)) { - fprintf(stderr, - "can only use %s with 'in'\n", - "fastroute"); - return NULL; - } - fil.fr_flags |= FR_FASTROUTE; - cpp++; - } - } - - /* - * Set the "other" interface name. Lets you specify both - * inbound and outbound interfaces for state rules. Do not - * prevent both interfaces from being the same. - */ - strcpy(fil.fr_ifnames[3], "*"); - if ((*cpp != NULL) && (*(cpp + 1) != NULL) && - ((((fil.fr_flags & FR_INQUE) != 0) && - (strcasecmp(*cpp, "out-via") == 0)) || - (((fil.fr_flags & FR_OUTQUE) != 0) && - (strcasecmp(*cpp, "in-via") == 0)))) { - cpp++; - - s = index(*cpp, ','); - if (s != NULL) { - *s++ = '\0'; - (void)strncpy(fil.fr_ifnames[3], s, - IFNAMSIZ - 1); - fil.fr_ifnames[3][IFNAMSIZ - 1] = '\0'; - } - - (void)strncpy(fil.fr_ifnames[2], *cpp, IFNAMSIZ - 1); - fil.fr_ifnames[2][IFNAMSIZ - 1] = '\0'; - cpp++; - } else - strcpy(fil.fr_ifnames[2], "*"); - } - if (*cpp && !strcasecmp(*cpp, "tos")) { - if (!*++cpp) { - fprintf(stderr, "%d: tos missing value\n", linenum); - return NULL; - } - fil.fr_tos = strtol(*cpp, NULL, 0); - fil.fr_mip.fi_tos = 0xff; - cpp++; - } - - if (*cpp && !strcasecmp(*cpp, "ttl")) { - if (!*++cpp) { - fprintf(stderr, "%d: ttl missing hopcount value\n", - linenum); - return NULL; - } - if (ratoi(*cpp, &i, 0, 255)) - fil.fr_ttl = i; - else { - fprintf(stderr, "%d: invalid ttl (%s)\n", - linenum, *cpp); - return NULL; - } - fil.fr_mip.fi_ttl = 0xff; - cpp++; - } - - /* - * check for "proto " only decode udp/tcp/icmp as protoname - */ - proto = NULL; - if (*cpp && !strcasecmp(*cpp, "proto")) { - if (!*++cpp) { - fprintf(stderr, "%d: protocol name missing\n", linenum); - return NULL; - } - proto = *cpp++; - if (!strcasecmp(proto, "tcp/udp")) { - fil.fr_ip.fi_fl |= FI_TCPUDP; - fil.fr_mip.fi_fl |= FI_TCPUDP; - } else if (use_inet6 && !strcasecmp(proto, "icmp")) { - fprintf(stderr, -"%d: use proto ipv6-icmp with IPv6 (or use proto 1 if you really mean icmp)\n", - linenum); - } else { - if (!(p = getprotobyname(proto)) && !isdigit(*proto)) { - fprintf(stderr, - "%d: unknown protocol (%s)\n", - linenum, proto); - return NULL; - } - if (p) - fil.fr_proto = p->p_proto; - else if (isdigit(*proto)) { - i = (int)strtol(proto, &endptr, 0); - if (*endptr != '\0' || i < 0 || i > 255) { - fprintf(stderr, - "%d: unknown protocol (%s)\n", - linenum, proto); - return NULL; - } - fil.fr_proto = i; - } - fil.fr_mip.fi_p = 0xff; - } - } - if ((fil.fr_proto != IPPROTO_TCP) && - ((fil.fr_flags & FR_RETMASK) == FR_RETRST)) { - fprintf(stderr, "%d: %s can only be used with TCP\n", - linenum, "return-rst"); - return NULL; - } - - /* - * get the from host and bit mask to use against packets - */ - - if (!*cpp) { - fprintf(stderr, "%d: missing source specification\n", linenum); - return NULL; - } - if (!strcasecmp(*cpp, "all")) { - cpp++; - if (!*cpp) - return &fil; - } else { - if (strcasecmp(*cpp, "from")) { - fprintf(stderr, "%d: unexpected keyword (%s) - from\n", - linenum, *cpp); - return NULL; - } - if (!*++cpp) { - fprintf(stderr, "%d: missing host after from\n", - linenum); - return NULL; - } - if (!strcmp(*cpp, "!")) { - fil.fr_flags |= FR_NOTSRCIP; - if (!*++cpp) { - fprintf(stderr, - "%d: missing host after from\n", - linenum); - return NULL; - } - } else if (**cpp == '!') { - fil.fr_flags |= FR_NOTSRCIP; - (*cpp)++; - } - ch = 0; - if (hostmask(&cpp, (u_32_t *)&fil.fr_src, - (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch, - &fil.fr_stop, linenum)) { - return NULL; - } - - if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) && - (fil.fr_proto != IPPROTO_UDP) && - !(fil.fr_ip.fi_fl & FI_TCPUDP)) { - fprintf(stderr, - "%d: cannot use port and neither tcp or udp\n", - linenum); - return NULL; - } - - fil.fr_scmp = ch; - if (!*cpp) { - fprintf(stderr, "%d: missing to fields\n", linenum); - return NULL; - } - - /* - * do the same for the to field (destination host) - */ - if (strcasecmp(*cpp, "to")) { - fprintf(stderr, "%d: unexpected keyword (%s) - to\n", - linenum, *cpp); - return NULL; - } - if (!*++cpp) { - fprintf(stderr, "%d: missing host after to\n", linenum); - return NULL; - } - ch = 0; - if (!strcmp(*cpp, "!")) { - fil.fr_flags |= FR_NOTDSTIP; - if (!*++cpp) { - fprintf(stderr, - "%d: missing host after from\n", - linenum); - return NULL; - } - } else if (**cpp == '!') { - fil.fr_flags |= FR_NOTDSTIP; - (*cpp)++; - } - if (hostmask(&cpp, (u_32_t *)&fil.fr_dst, - (u_32_t *)&fil.fr_dmsk, &fil.fr_dport, &ch, - &fil.fr_dtop, linenum)) { - return NULL; - } - if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) && - (fil.fr_proto != IPPROTO_UDP) && - !(fil.fr_ip.fi_fl & FI_TCPUDP)) { - fprintf(stderr, - "%d: cannot use port and neither tcp or udp\n", - linenum); - return NULL; - } - - fil.fr_dcmp = ch; - } - - /* - * check some sanity, make sure we don't have icmp checks with tcp - * or udp or visa versa. - */ - if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) && - fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) { - fprintf(stderr, "%d: port operation on non tcp/udp\n", linenum); - return NULL; - } - if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) { - fprintf(stderr, "%d: icmp comparisons on wrong protocol\n", - linenum); - return NULL; - } - - if (!*cpp) - return &fil; - - if (*cpp && !strcasecmp(*cpp, "flags")) { - if (!*++cpp) { - fprintf(stderr, "%d: no flags present\n", linenum); - return NULL; - } - fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum); - cpp++; - } - - /* - * extras... - */ - if ((fil.fr_v == 4) && *cpp && (!strcasecmp(*cpp, "with") || - !strcasecmp(*cpp, "and"))) - if (extras(&cpp, &fil, linenum)) - return NULL; - - /* - * icmp types for use with the icmp protocol - */ - if (*cpp && !strcasecmp(*cpp, "icmp-type")) { - if (fil.fr_proto != IPPROTO_ICMP && - fil.fr_proto != IPPROTO_ICMPV6) { - fprintf(stderr, - "%d: icmp with wrong protocol (%d)\n", - linenum, fil.fr_proto); - return NULL; - } - if (addicmp(&cpp, &fil, linenum)) - return NULL; - fil.fr_icmp = htons(fil.fr_icmp); - fil.fr_icmpm = htons(fil.fr_icmpm); - } - - /* - * Keep something... - */ - while (*cpp && !strcasecmp(*cpp, "keep")) - if (addkeep(&cpp, &fil, linenum)) - return NULL; - - /* - * This is here to enforce the old interface binding behaviour. - * That is, "on X" is equivalent to " on X -via -,X" - */ - if (fil.fr_flags & FR_KEEPSTATE) { - if (*fil.fr_ifnames[0] && !*fil.fr_ifnames[3]) { - bcopy(fil.fr_ifnames[0], fil.fr_ifnames[3], - sizeof(fil.fr_ifnames[3])); - strncpy(fil.fr_ifnames[2], "*", - sizeof(fil.fr_ifnames[3])); - } - } - - /* - * head of a new group ? - */ - if (*cpp && !strcasecmp(*cpp, "head")) { - if (fil.fr_skip != 0) { - fprintf(stderr, "%d: cannot use skip with head\n", - linenum); - return NULL; - } - if (!*++cpp) { - fprintf(stderr, "%d: head without group #\n", linenum); - return NULL; - } - if (ratoui(*cpp, &k, 0, UINT_MAX)) - fil.fr_grhead = (u_32_t)k; - else { - fprintf(stderr, "%d: invalid group (%s)\n", - linenum, *cpp); - return NULL; - } - cpp++; - } - - /* - * head of a new group ? - */ - if (*cpp && !strcasecmp(*cpp, "group")) { - if (!*++cpp) { - fprintf(stderr, "%d: group without group #\n", - linenum); - return NULL; - } - if (ratoui(*cpp, &k, 0, UINT_MAX)) - fil.fr_group = k; - else { - fprintf(stderr, "%d: invalid group (%s)\n", - linenum, *cpp); - return NULL; - } - cpp++; - } - - /* - * leftovers...yuck - */ - if (*cpp && **cpp) { - fprintf(stderr, "%d: unknown words at end: [", linenum); - for (; *cpp; cpp++) - fprintf(stderr, "%s ", *cpp); - fprintf(stderr, "]\n"); - return NULL; - } - - /* - * lazy users... - */ - if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) { - fprintf(stderr, "%d: TCP protocol not specified\n", linenum); - return NULL; - } - if (!(fil.fr_ip.fi_fl & FI_TCPUDP) && (fil.fr_proto != IPPROTO_TCP) && - (fil.fr_proto != IPPROTO_UDP) && (fil.fr_dcmp || fil.fr_scmp)) { - if (!fil.fr_proto) { - fil.fr_ip.fi_fl |= FI_TCPUDP; - fil.fr_mip.fi_fl |= FI_TCPUDP; - } else { - fprintf(stderr, - "%d: port comparisons for non-TCP/UDP\n", - linenum); - return NULL; - } - } -/* - if ((fil.fr_flags & FR_KEEPFRAG) && - (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) { - fprintf(stderr, - "%d: must use 'with frags' with 'keep frags'\n", - linenum); - return NULL; - } -*/ - return &fil; -} - - -int loglevel(cpp, facpri, linenum) -char **cpp; -u_int *facpri; -int linenum; -{ - int fac, pri; - char *s; - - fac = 0; - pri = 0; - if (!*++cpp) { - fprintf(stderr, "%d: %s\n", linenum, - "missing identifier after level"); - return -1; - } - - s = index(*cpp, '.'); - if (s) { - *s++ = '\0'; - fac = fac_findname(*cpp); - if (fac == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown facility", *cpp); - return -1; - } - pri = pri_findname(s); - if (pri == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown priority", s); - return -1; - } - } else { - pri = pri_findname(*cpp); - if (pri == -1) { - fprintf(stderr, "%d: %s %s\n", linenum, - "Unknown priority", *cpp); - return -1; - } - } - *facpri = fac|pri; - return 0; -} - - -int to_interface(fdp, to, linenum) -frdest_t *fdp; -char *to; -int linenum; -{ - char *s; - - s = index(to, ':'); - fdp->fd_ifp = NULL; - if (s) { - *s++ = '\0'; - if (hostnum((u_32_t *)&fdp->fd_ip, s, linenum) == -1) - return -1; - } - (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1); - fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0'; - return 0; -} - - -void print_toif(tag, fdp) -char *tag; -frdest_t *fdp; -{ - printf("%s %s%s", tag, fdp->fd_ifname, - (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)"); -#ifdef USE_INET6 - if (use_inet6 && IP6_NOTZERO(&fdp->fd_ip6.in6)) { - char ipv6addr[80]; - - inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr, - sizeof(fdp->fd_ip6)); - printf(":%s", ipv6addr); - } else -#endif - if (fdp->fd_ip.s_addr) - printf(":%s", inet_ntoa(fdp->fd_ip)); - putchar(' '); -} - - -/* - * deal with extra bits on end of the line - */ -int extras(cp, fr, linenum) -char ***cp; -struct frentry *fr; -int linenum; -{ - u_short secmsk; - u_long opts; - int notopt; - char oflags; - - opts = 0; - secmsk = 0; - notopt = 0; - (*cp)++; - if (!**cp) - return -1; - - while (**cp && (!strncasecmp(**cp, "ipopt", 5) || - !strcasecmp(**cp, "not") || !strncasecmp(**cp, "opt", 3) || - !strncasecmp(**cp, "frag", 4) || !strcasecmp(**cp, "no") || - !strcasecmp(**cp, "short"))) { - if (***cp == 'n' || ***cp == 'N') { - notopt = 1; - (*cp)++; - continue; - } else if (***cp == 'i' || ***cp == 'I') { - if (!notopt) - fr->fr_ip.fi_fl |= FI_OPTIONS; - fr->fr_mip.fi_fl |= FI_OPTIONS; - goto nextopt; - } else if (***cp == 'f' || ***cp == 'F') { - if (!notopt) - fr->fr_ip.fi_fl |= FI_FRAG; - fr->fr_mip.fi_fl |= FI_FRAG; - goto nextopt; - } else if (***cp == 'o' || ***cp == 'O') { - if (!*(*cp + 1)) { - fprintf(stderr, - "%d: opt missing arguements\n", - linenum); - return -1; - } - (*cp)++; - if (!(opts = optname(cp, &secmsk, linenum))) - return -1; - oflags = FI_OPTIONS; - } else if (***cp == 's' || ***cp == 'S') { - if (fr->fr_tcpf) { - fprintf(stderr, - "%d: short cannot be used with TCP flags\n", - linenum); - return -1; - } - - if (!notopt) - fr->fr_ip.fi_fl |= FI_SHORT; - fr->fr_mip.fi_fl |= FI_SHORT; - goto nextopt; - } else - return -1; - - if (!notopt || !opts) - fr->fr_mip.fi_fl |= oflags; - if (notopt) { - if (!secmsk) { - fr->fr_mip.fi_optmsk |= opts; - } else { - fr->fr_mip.fi_optmsk |= (opts & ~0x0100); - } - } else { - fr->fr_mip.fi_optmsk |= opts; - } - fr->fr_mip.fi_secmsk |= secmsk; - - if (notopt) { - fr->fr_ip.fi_fl &= (~oflags & 0xf); - fr->fr_ip.fi_optmsk &= ~opts; - fr->fr_ip.fi_secmsk &= ~secmsk; - } else { - fr->fr_ip.fi_fl |= oflags; - fr->fr_ip.fi_optmsk |= opts; - fr->fr_ip.fi_secmsk |= secmsk; - } -nextopt: - notopt = 0; - opts = 0; - oflags = 0; - secmsk = 0; - (*cp)++; - } - return 0; -} - - -u_32_t optname(cp, sp, linenum) -char ***cp; -u_short *sp; -int linenum; -{ - struct ipopt_names *io, *so; - u_long msk = 0; - u_short smsk = 0; - char *s; - int sec = 0; - - for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { - for (io = ionames; io->on_name; io++) - if (!strcasecmp(s, io->on_name)) { - msk |= io->on_bit; - break; - } - if (!io->on_name) { - fprintf(stderr, "%d: unknown IP option name %s\n", - linenum, s); - return 0; - } - if (!strcasecmp(s, "sec-class")) - sec = 1; - } - - if (sec && !*(*cp + 1)) { - fprintf(stderr, "%d: missing security level after sec-class\n", - linenum); - return 0; - } - - if (sec) { - (*cp)++; - for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { - for (so = secclass; so->on_name; so++) - if (!strcasecmp(s, so->on_name)) { - smsk |= so->on_bit; - break; - } - if (!so->on_name) { - fprintf(stderr, - "%d: no such security level: %s\n", - linenum, s); - return 0; - } - } - if (smsk) - *sp = smsk; - } - return msk; -} - - -#ifdef __STDC__ -void optprint(u_short *sec, u_long optmsk, u_long optbits) -#else -void optprint(sec, optmsk, optbits) -u_short *sec; -u_long optmsk, optbits; -#endif -{ - u_short secmsk = sec[0], secbits = sec[1]; - struct ipopt_names *io, *so; - char *s; - - s = " opt "; - for (io = ionames; io->on_name; io++) - if ((io->on_bit & optmsk) && - ((io->on_bit & optmsk) == (io->on_bit & optbits))) { - if ((io->on_value != IPOPT_SECURITY) || - (!secmsk && !secbits)) { - printf("%s%s", s, io->on_name); - if (io->on_value == IPOPT_SECURITY) - io++; - s = ","; - } - } - - - if (secmsk & secbits) { - printf("%ssec-class", s); - s = " "; - for (so = secclass; so->on_name; so++) - if ((secmsk & so->on_bit) && - ((so->on_bit & secmsk) == (so->on_bit & secbits))) { - printf("%s%s", s, so->on_name); - s = ","; - } - } - - if ((optmsk && (optmsk != optbits)) || - (secmsk && (secmsk != secbits))) { - s = " "; - printf(" not opt"); - if (optmsk != optbits) { - for (io = ionames; io->on_name; io++) - if ((io->on_bit & optmsk) && - ((io->on_bit & optmsk) != - (io->on_bit & optbits))) { - if ((io->on_value != IPOPT_SECURITY) || - (!secmsk && !secbits)) { - printf("%s%s", s, io->on_name); - s = ","; - if (io->on_value == - IPOPT_SECURITY) - io++; - } else - io++; - } - } - - if (secmsk != secbits) { - printf("%ssec-class", s); - s = " "; - for (so = secclass; so->on_name; so++) - if ((so->on_bit & secmsk) && - ((so->on_bit & secmsk) != - (so->on_bit & secbits))) { - printf("%s%s", s, so->on_name); - s = ","; - } - } - } -} - -char *icmptypes[] = { - "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", - "redir", (char *)NULL, (char *)NULL, "echo", "routerad", - "routersol", "timex", "paramprob", "timest", "timestrep", - "inforeq", "inforep", "maskreq", "maskrep", "END" -}; - -/* - * set the icmp field to the correct type if "icmp" word is found - */ -int addicmp(cp, fp, linenum) -char ***cp; -struct frentry *fp; -int linenum; -{ - char **t; - int i; - - (*cp)++; - if (!**cp) - return -1; - - if (isdigit(***cp)) { - if (!ratoi(**cp, &i, 0, 255)) { - fprintf(stderr, - "%d: Invalid icmp-type (%s) specified\n", - linenum, **cp); - return -1; - } - } else if (fp->fr_proto == IPPROTO_ICMPV6) { - fprintf(stderr, "%d: Unknown ICMPv6 type (%s) specified, %s", - linenum, **cp, "(use numeric value instead\n"); - return -1; - } else { - for (t = icmptypes, i = 0; ; t++, i++) { - if (!*t) - continue; - if (!strcasecmp("END", *t)) { - i = -1; - break; - } - if (!strcasecmp(*t, **cp)) - break; - } - if (i == -1) { - fprintf(stderr, - "%d: Invalid icmp-type (%s) specified\n", - linenum, **cp); - return -1; - } - } - fp->fr_icmp = (u_short)(i << 8); - fp->fr_icmpm = (u_short)0xff00; - (*cp)++; - if (!**cp) - return 0; - - if (**cp && strcasecmp("code", **cp)) - return 0; - (*cp)++; - if (isdigit(***cp)) { - if (!ratoi(**cp, &i, 0, 255)) { - fprintf(stderr, - "%d: Invalid icmp code (%s) specified\n", - linenum, **cp); - return -1; - } - } else { - i = icmpcode(**cp); - if (i == -1) { - fprintf(stderr, - "%d: Invalid icmp code (%s) specified\n", - linenum, **cp); - return -1; - } - } - i &= 0xff; - fp->fr_icmp |= (u_short)i; - fp->fr_icmpm = (u_short)0xffff; - (*cp)++; - return 0; -} - - -#define MAX_ICMPCODE 15 - -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", "filter-prohib", "host-preced", - "preced-cutoff", NULL }; -/* - * Return the number for the associated ICMP unreachable code. - */ -int icmpcode(str) -char *str; -{ - char *s; - int i, len; - - if ((s = strrchr(str, ')'))) - *s = '\0'; - if (isdigit(*str)) { - if (!ratoi(str, &i, 0, 255)) - return -1; - else - return i; - } - 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, linenum) -char ***cp; -struct frentry *fp; -int linenum; -{ - char *s; - - (*cp)++; - if (!**cp) { - fprintf(stderr, "%d: Missing keyword after keep\n", - linenum); - return -1; - } - - if (strcasecmp(**cp, "state") == 0) - fp->fr_flags |= FR_KEEPSTATE; - else if (strncasecmp(**cp, "frag", 4) == 0) - fp->fr_flags |= FR_KEEPFRAG; - else if (strcasecmp(**cp, "state-age") == 0) { - if (fp->fr_ip.fi_p == IPPROTO_TCP) { - fprintf(stderr, "%d: cannot use state-age with tcp\n", - linenum); - return -1; - } - if ((fp->fr_flags & FR_KEEPSTATE) == 0) { - fprintf(stderr, "%d: state-age with no 'keep state'\n", - linenum); - return -1; - } - (*cp)++; - if (!**cp) { - fprintf(stderr, "%d: state-age with no arg\n", - linenum); - return -1; - } - fp->fr_age[0] = atoi(**cp); - s = index(**cp, '/'); - if (s != NULL) { - s++; - fp->fr_age[1] = atoi(s); - } else - fp->fr_age[1] = fp->fr_age[0]; - } else { - fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n", - linenum, **cp); - return -1; - } - (*cp)++; - return 0; -} - - -void printifname(format, name, ifp) -char *format, *name; -void *ifp; -{ - printf("%s%s", format, name); - if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*")) - printf("(!)"); -} - - -/* - * print the filter structure in a useful way - */ -void printfr(fp) -struct frentry *fp; -{ - struct protoent *p; - u_short sec[2]; - char *s; - u_char *t; - int pr; - - if (fp->fr_flags & FR_PASS) - printf("pass"); - if (fp->fr_flags & FR_NOMATCH) - printf("nomatch"); - else if (fp->fr_flags & FR_BLOCK) { - printf("block"); - if (fp->fr_flags & FR_RETICMP) { - if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP) - printf(" return-icmp-as-dest"); - else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP) - printf(" return-icmp"); - if (fp->fr_icode) { - if (fp->fr_icode <= MAX_ICMPCODE) - printf("(%s)", - icmpcodes[(int)fp->fr_icode]); - else - printf("(%d)", fp->fr_icode); - } - } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST) - printf(" return-rst"); - } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) { - printlog(fp); - } else if (fp->fr_flags & FR_ACCOUNT) - printf("count"); - else if (fp->fr_flags & FR_AUTH) - printf("auth"); - else if (fp->fr_flags & FR_PREAUTH) - printf("preauth"); - else if (fp->fr_skip) - printf("skip %hu", fp->fr_skip); - - if (fp->fr_flags & FR_OUTQUE) - printf(" out "); - else - printf(" in "); - - if (((fp->fr_flags & FR_LOGB) == FR_LOGB) || - ((fp->fr_flags & FR_LOGP) == FR_LOGP)) { - printlog(fp); - putchar(' '); - } - - if (fp->fr_flags & FR_QUICK) - printf("quick "); - - if (*fp->fr_ifname) { - printifname("on ", fp->fr_ifname, fp->fr_ifa); - if (*fp->fr_ifnames[1] && strcmp(fp->fr_ifnames[1], "*")) - printifname(",", fp->fr_ifnames[1], fp->fr_ifas[1]); - putchar(' '); - - if (*fp->fr_dif.fd_ifname) - print_toif("dup-to", &fp->fr_dif); - if (*fp->fr_tif.fd_ifname) - print_toif("to", &fp->fr_tif); - if (fp->fr_flags & FR_FASTROUTE) - printf("fastroute "); - - if ((*fp->fr_ifnames[2] && strcmp(fp->fr_ifnames[2], "*")) || - (*fp->fr_ifnames[3] && strcmp(fp->fr_ifnames[3], "*"))) { - if (fp->fr_flags & FR_OUTQUE) - printf("in-via "); - else - printf("out-via "); - - if (*fp->fr_ifnames[2]) { - printifname("", fp->fr_ifnames[2], - fp->fr_ifas[2]); - putchar(','); - } - - if (*fp->fr_ifnames[3]) - printifname("", fp->fr_ifnames[3], - fp->fr_ifas[3]); - putchar(' '); - } - } - - if (fp->fr_mip.fi_tos) - printf("tos %#x ", fp->fr_tos); - if (fp->fr_mip.fi_ttl) - printf("ttl %d ", fp->fr_ttl); - if (fp->fr_ip.fi_fl & FI_TCPUDP) { - printf("proto tcp/udp "); - pr = -1; - } else if ((pr = fp->fr_mip.fi_p)) { - if ((p = getprotobynumber(fp->fr_proto))) - printf("proto %s ", p->p_name); - else - printf("proto %d ", fp->fr_proto); - } - - printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : ""); - printhostmask(fp->fr_v, (u_32_t *)&fp->fr_src.s_addr, - (u_32_t *)&fp->fr_smsk.s_addr); - if (fp->fr_scmp) - printportcmp(pr, &fp->fr_tuc.ftu_src); - - printf(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : ""); - printhostmask(fp->fr_v, (u_32_t *)&fp->fr_dst.s_addr, - (u_32_t *)&fp->fr_dmsk.s_addr); - if (fp->fr_dcmp) - printportcmp(pr, &fp->fr_tuc.ftu_dst); - - if ((fp->fr_ip.fi_fl & ~FI_TCPUDP) || - (fp->fr_mip.fi_fl & ~FI_TCPUDP) || - fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk || - fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) { - printf(" with"); - if (fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk || - fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) { - sec[0] = fp->fr_mip.fi_secmsk; - sec[1] = fp->fr_ip.fi_secmsk; - optprint(sec, - fp->fr_mip.fi_optmsk, fp->fr_ip.fi_optmsk); - } else if (fp->fr_mip.fi_fl & FI_OPTIONS) { - if (!(fp->fr_ip.fi_fl & FI_OPTIONS)) - printf(" not"); - printf(" ipopt"); - } - if (fp->fr_mip.fi_fl & FI_SHORT) { - if (!(fp->fr_ip.fi_fl & FI_SHORT)) - printf(" not"); - printf(" short"); - } - if (fp->fr_mip.fi_fl & FI_FRAG) { - if (!(fp->fr_ip.fi_fl & FI_FRAG)) - printf(" not"); - printf(" frag"); - } - } - if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm != 0) { - int type = fp->fr_icmp, code; - - type = ntohs(fp->fr_icmp); - code = type & 0xff; - type /= 256; - if (type < (sizeof(icmptypes) / sizeof(char *) - 1) && - icmptypes[type]) - printf(" icmp-type %s", icmptypes[type]); - else - printf(" icmp-type %d", type); - if (ntohs(fp->fr_icmpm) & 0xff) - printf(" code %d", code); - } - if (fp->fr_proto == IPPROTO_ICMPV6 && fp->fr_icmpm != 0) { - int type = fp->fr_icmp, code; - - type = ntohs(fp->fr_icmp); - code = type & 0xff; - type /= 256; - printf(" icmp-type %d", type); - if (ntohs(fp->fr_icmpm) & 0xff) - printf(" code %d", code); - } - if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) { - printf(" flags "); - if (fp->fr_tcpf & ~TCPF_ALL) - printf("0x%x", fp->fr_tcpf); - else - for (s = flagset, t = flags; *s; s++, t++) - if (fp->fr_tcpf & *t) - (void)putchar(*s); - if (fp->fr_tcpfm) { - (void)putchar('/'); - if (fp->fr_tcpfm & ~TCPF_ALL) - printf("0x%x", fp->fr_tcpfm); - else - for (s = flagset, t = flags; *s; s++, t++) - if (fp->fr_tcpfm & *t) - (void)putchar(*s); - } - } - - if (fp->fr_flags & FR_KEEPSTATE) - printf(" keep state"); - if (fp->fr_flags & FR_KEEPFRAG) - printf(" keep frags"); - if (fp->fr_age[0] != 0 || fp->fr_age[1]!= 0) - printf(" state-age %u/%u", fp->fr_age[0], fp->fr_age[1]); - if (fp->fr_grhead) - printf(" head %d", fp->fr_grhead); - if (fp->fr_group) - printf(" group %d", fp->fr_group); - (void)putchar('\n'); -} - -void binprint(fp) -struct frentry *fp; -{ - int i = sizeof(*fp), j = 0; - u_char *s; - - for (s = (u_char *)fp; i; i--, s++) { - j++; - printf("%02x ", *s); - if (j == 16) { - printf("\n"); - j = 0; - } - } - putchar('\n'); - (void)fflush(stdout); -} - - -void printlog(fp) -frentry_t *fp; -{ - char *s, *u; - - printf("log"); - if (fp->fr_flags & FR_LOGBODY) - printf(" body"); - if (fp->fr_flags & FR_LOGFIRST) - printf(" first"); - if (fp->fr_flags & FR_LOGORBLOCK) - printf(" or-block"); - if (fp->fr_loglevel != 0xffff) { - printf(" level "); - if (fp->fr_loglevel & LOG_FACMASK) { - s = fac_toname(fp->fr_loglevel); - if (s == NULL) - s = "!!!"; - } else - s = ""; - u = pri_toname(fp->fr_loglevel); - if (u == NULL) - u = "!!!"; - if (*s) - printf("%s.%s", s, u); - else - printf("%s", u); - } -} diff --git a/dist/ipf/pcap.h b/dist/ipf/pcap.h deleted file mode 100644 index ad4ffa62ffb0..000000000000 --- a/dist/ipf/pcap.h +++ /dev/null @@ -1,36 +0,0 @@ -/* $NetBSD: pcap.h,v 1.3 2002/01/24 08:21:35 martti Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Id: pcap.h,v 2.2.2.1 2001/06/26 10:43:20 darrenr Exp - */ -/* - * This header file is constructed to match the version described by - * PCAP_VERSION_MAJ. - * - * The structure largely derives from libpcap which wouldn't include - * nicely without bpf. - */ -typedef struct pcap_filehdr { - u_int pc_id; - u_short pc_v_maj; - u_short pc_v_min; - u_int pc_zone; - u_int pc_sigfigs; - u_int pc_slen; - u_int pc_type; -} pcaphdr_t; - -#define TCPDUMP_MAGIC 0xa1b2c3d4 - -#define PCAP_VERSION_MAJ 2 - -typedef struct pcap_pkthdr { - struct timeval ph_ts; - u_int ph_clen; - u_int ph_len; -} pcappkt_t; - diff --git a/dist/ipf/printnat.c b/dist/ipf/printnat.c deleted file mode 100644 index 1a035bd4fa8f..000000000000 --- a/dist/ipf/printnat.c +++ /dev/null @@ -1,485 +0,0 @@ -/* $NetBSD: printnat.c,v 1.10 2002/09/19 08:11:38 martti Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) - */ -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#if !defined(__SVR4) && !defined(__svr4__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) -# include -# include -#endif -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include -#include -#include -#include -#include -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_nat.h" -#include "netinet/ip_state.h" -#include "netinet/ip_proxy.h" -#include "ipf.h" -#include "kmem.h" - -#if defined(sun) && !SOLARIS2 -# define STRERROR(x) sys_errlist[x] -extern char *sys_errlist[]; -#else -# define STRERROR(x) strerror(x) -#endif - -#if !defined(lint) -static const char rcsid[] __attribute__((__unused__)) = - "@(#)Id: printnat.c,v 1.1.2.10 2002/08/28 12:45:51 darrenr Exp"; -#endif - - -#if SOLARIS -#define bzero(a,b) memset(a,0,b) -#endif -#ifdef USE_INET6 -extern int use_inet6; -#endif - -extern char thishost[MAXHOSTNAMELEN]; - -extern int countbits __P((u_32_t)); - -void printnat __P((ipnat_t *, int)); -char *getnattype __P((ipnat_t *)); -void printactivenat __P((nat_t *, int)); -void printhostmap __P((hostmap_t *, u_int)); -char *getsumd __P((u_32_t)); - -static void printaps __P((ap_session_t *, int)); - -static void printaps(aps, opts) -ap_session_t *aps; -int opts; -{ - ipsec_pxy_t ipsec; - ap_session_t ap; - ftpinfo_t ftp; - aproxy_t apr; - raudio_t ra; - - if (kmemcpy((char *)&ap, (long)aps, sizeof(ap))) - return; - if (kmemcpy((char *)&apr, (long)ap.aps_apr, sizeof(apr))) - return; - printf("\tproxy %s/%d use %d flags %x\n", apr.apr_label, - apr.apr_p, apr.apr_ref, apr.apr_flags); - printf("\t\tproto %d flags %#x bytes ", ap.aps_p, ap.aps_flags); -#ifdef USE_QUAD_T - printf("%qu pkts %qu", (unsigned long long)ap.aps_bytes, - (unsigned long long)ap.aps_pkts); -#else - printf("%lu pkts %lu", ap.aps_bytes, ap.aps_pkts); -#endif - printf(" data %s size %d\n", ap.aps_data ? "YES" : "NO", ap.aps_psiz); - if ((ap.aps_p == IPPROTO_TCP) && (opts & OPT_VERBOSE)) { - printf("\t\tstate[%u,%u], sel[%d,%d]\n", - ap.aps_state[0], ap.aps_state[1], - ap.aps_sel[0], ap.aps_sel[1]); -#if (defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011)) || \ - (__FreeBSD_version >= 300000) || defined(OpenBSD) - printf("\t\tseq: off %hd/%hd min %x/%x\n", - ap.aps_seqoff[0], ap.aps_seqoff[1], - ap.aps_seqmin[0], ap.aps_seqmin[1]); - printf("\t\tack: off %hd/%hd min %x/%x\n", - ap.aps_ackoff[0], ap.aps_ackoff[1], - ap.aps_ackmin[0], ap.aps_ackmin[1]); -#else - printf("\t\tseq: off %hd/%hd min %lx/%lx\n", - ap.aps_seqoff[0], ap.aps_seqoff[1], - ap.aps_seqmin[0], ap.aps_seqmin[1]); - printf("\t\tack: off %hd/%hd min %lx/%lx\n", - ap.aps_ackoff[0], ap.aps_ackoff[1], - ap.aps_ackmin[0], ap.aps_ackmin[1]); -#endif - } - - if (!strcmp(apr.apr_label, "raudio") && ap.aps_psiz == sizeof(ra)) { - if (kmemcpy((char *)&ra, (long)ap.aps_data, sizeof(ra))) - return; - printf("\tReal Audio Proxy:\n"); - printf("\t\tSeen PNA: %d\tVersion: %d\tEOS: %d\n", - ra.rap_seenpna, ra.rap_version, ra.rap_eos); - printf("\t\tMode: %#x\tSBF: %#x\n", ra.rap_mode, ra.rap_sbf); - printf("\t\tPorts:pl %hu, pr %hu, sr %hu\n", - ra.rap_plport, ra.rap_prport, ra.rap_srport); - } else if (!strcmp(apr.apr_label, "ftp") && - (ap.aps_psiz == sizeof(ftp))) { - if (kmemcpy((char *)&ftp, (long)ap.aps_data, sizeof(ftp))) - return; - printf("\tFTP Proxy:\n"); - printf("\t\tpassok: %d\n", ftp.ftp_passok); - ftp.ftp_side[0].ftps_buf[FTP_BUFSZ - 1] = '\0'; - ftp.ftp_side[1].ftps_buf[FTP_BUFSZ - 1] = '\0'; - printf("\tClient:\n"); - printf("\t\tseq %08x%08x len %d junk %d cmds %d\n", - ftp.ftp_side[0].ftps_seq[1], - ftp.ftp_side[0].ftps_seq[0], - ftp.ftp_side[0].ftps_len, - ftp.ftp_side[0].ftps_junk, ftp.ftp_side[0].ftps_cmds); - printf("\t\tbuf ["); - printbuf(ftp.ftp_side[0].ftps_buf, FTP_BUFSZ, 1); - printf("]\n\tServer:\n"); - printf("\t\tseq %08x%08x len %d junk %d cmds %d\n", - ftp.ftp_side[1].ftps_seq[1], - ftp.ftp_side[1].ftps_seq[0], - ftp.ftp_side[1].ftps_len, - ftp.ftp_side[1].ftps_junk, ftp.ftp_side[1].ftps_cmds); - printf("\t\tbuf ["); - printbuf(ftp.ftp_side[1].ftps_buf, FTP_BUFSZ, 1); - printf("]\n"); - } else if (!strcmp(apr.apr_label, "ipsec") && - (ap.aps_psiz == sizeof(ipsec))) { - if (kmemcpy((char *)&ipsec, (long)ap.aps_data, sizeof(ipsec))) - return; - printf("\tIPSec Proxy:\n"); - printf("\t\tICookie %08x%08x RCookie %08x%08x %s\n", - (u_int)ntohl(ipsec.ipsc_icookie[0]), - (u_int)ntohl(ipsec.ipsc_icookie[1]), - (u_int)ntohl(ipsec.ipsc_rcookie[0]), - (u_int)ntohl(ipsec.ipsc_rcookie[1]), - ipsec.ipsc_rckset ? "(Set)" : "(Not set)"); - } -} - - -/* - * Get a nat filter type given its kernel address. - */ -char *getnattype(ipnat) -ipnat_t *ipnat; -{ - static char unknownbuf[20]; - ipnat_t ipnatbuff; - char *which; - - if (!ipnat || (ipnat && kmemcpy((char *)&ipnatbuff, (long)ipnat, - sizeof(ipnatbuff)))) - return "???"; - - switch (ipnatbuff.in_redir) - { - case NAT_MAP : - which = "MAP"; - break; - case NAT_MAPBLK : - which = "MAP-BLOCK"; - break; - case NAT_REDIRECT : - which = "RDR"; - break; - case NAT_BIMAP : - which = "BIMAP"; - break; - default : - sprintf(unknownbuf, "unknown(%04x)", - ipnatbuff.in_redir & 0xffffffff); - which = unknownbuf; - break; - } - return which; -} - - -void printactivenat(nat, opts) -nat_t *nat; -int opts; -{ - u_int hv1, hv2; - - printf("%s %-15s", getnattype(nat->nat_ptr), inet_ntoa(nat->nat_inip)); - - if ((nat->nat_flags & IPN_TCPUDP) != 0) - printf(" %-5hu", ntohs(nat->nat_inport)); - - printf(" <- -> %-15s",inet_ntoa(nat->nat_outip)); - - if ((nat->nat_flags & IPN_TCPUDP) != 0) - printf(" %-5hu", ntohs(nat->nat_outport)); - - printf(" [%s", inet_ntoa(nat->nat_oip)); - if ((nat->nat_flags & IPN_TCPUDP) != 0) - printf(" %hu", ntohs(nat->nat_oport)); - printf("]"); - - if (opts & OPT_VERBOSE) { - printf("\n\tage %lu use %hu sumd %s/", - nat->nat_age, nat->nat_use, getsumd(nat->nat_sumd[0])); - hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, - 0xffffffff), - hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, - NAT_TABLE_SZ), - hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, - 0xffffffff), - hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, - NAT_TABLE_SZ), - printf("%s pr %u bkt %d/%d flags %x drop %d/%d\n", - getsumd(nat->nat_sumd[1]), nat->nat_p, - hv1, hv2, nat->nat_flags, - nat->nat_drop[0], nat->nat_drop[1]); - printf("\tifp %s ", getifname(nat->nat_ifp)); -#ifdef USE_QUAD_T - printf("bytes %qu pkts %qu", - (unsigned long long)nat->nat_bytes, - (unsigned long long)nat->nat_pkts); -#else - printf("bytes %lu pkts %lu", nat->nat_bytes, nat->nat_pkts); -#endif -#if SOLARIS - printf(" %lx", nat->nat_ipsumd); -#endif - } - - putchar('\n'); - if (nat->nat_aps) - printaps(nat->nat_aps, opts); -} - - -void printhostmap(hmp, hv) -hostmap_t *hmp; -u_int hv; -{ - printf("%s -> ", inet_ntoa(hmp->hm_realip)); - printf("%s ", inet_ntoa(hmp->hm_mapip)); - printf("(use = %d hv = %u)\n", hmp->hm_ref, hv); -} - - -char *getsumd(sum) -u_32_t sum; -{ - static char sumdbuf[17]; - - if (sum & NAT_HW_CKSUM) - sprintf(sumdbuf, "hw(%#0x)", sum & 0xffff); - else - sprintf(sumdbuf, "%#0x", sum); - return sumdbuf; -} - - -/* - * Print out a NAT rule - */ -void printnat(np, opts) -ipnat_t *np; -int opts; -{ - struct protoent *pr; - struct servent *sv; - int bits; - - pr = getprotobynumber(np->in_p); - - switch (np->in_redir) - { - case NAT_REDIRECT : - printf("rdr"); - break; - case NAT_MAP : - printf("map"); - break; - case NAT_MAPBLK : - printf("map-block"); - break; - case NAT_BIMAP : - printf("bimap"); - break; - default : - fprintf(stderr, "unknown value for in_redir: %#x\n", - np->in_redir); - break; - } - - printf(" %s ", np->in_ifname); - - if (np->in_flags & IPN_FILTER) { - if (np->in_flags & IPN_NOTSRC) - printf("! "); - printf("from "); - if (np->in_redir == NAT_REDIRECT) { - printhostmask(4, (u_32_t *)&np->in_srcip, - (u_32_t *)&np->in_srcmsk); - } else { - printhostmask(4, (u_32_t *)&np->in_inip, - (u_32_t *)&np->in_inmsk); - } - if (np->in_scmp) - printportcmp(np->in_p, &np->in_tuc.ftu_src); - - if (np->in_flags & IPN_NOTDST) - printf(" !"); - printf(" to "); - if (np->in_redir == NAT_REDIRECT) { - printhostmask(4, (u_32_t *)&np->in_outip, - (u_32_t *)&np->in_outmsk); - } else { - printhostmask(4, (u_32_t *)&np->in_srcip, - (u_32_t *)&np->in_srcmsk); - } - if (np->in_dcmp) - printportcmp(np->in_p, &np->in_tuc.ftu_dst); - } - - if (np->in_redir == NAT_REDIRECT) { - if (!(np->in_flags & IPN_FILTER)) { - printf("%s", inet_ntoa(np->in_out[0])); - bits = countbits(np->in_out[1].s_addr); - if (bits != -1) - printf("/%d ", bits); - else - printf("/%s ", inet_ntoa(np->in_out[1])); - printf("port %d", ntohs(np->in_pmin)); - if (np->in_pmax != np->in_pmin) - printf("- %d", ntohs(np->in_pmax)); - } - printf(" -> %s", inet_ntoa(np->in_in[0])); - if (np->in_flags & IPN_SPLIT) - printf(",%s", inet_ntoa(np->in_in[1])); - printf(" port %d", ntohs(np->in_pnext)); - if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) - printf(" tcp/udp"); - else if ((np->in_flags & IPN_TCP) == IPN_TCP) - printf(" tcp"); - else if ((np->in_flags & IPN_UDP) == IPN_UDP) - printf(" udp"); - else if (np->in_p == 0) - printf(" ip"); - else if (np->in_p != 0) { - if (pr != NULL) - printf(" %s", pr->p_name); - else - printf(" %d", np->in_p); - } - if (np->in_flags & IPN_ROUNDR) - printf(" round-robin"); - if (np->in_flags & IPN_FRAG) - printf(" frag"); - if (np->in_age[0]) - printf(" age %d/%d", np->in_age[0], np->in_age[1]); - printf("\n"); - if (opts & OPT_DEBUG) - printf("\tspc %lu flg %#x max %u use %d\n", - np->in_space, np->in_flags, - np->in_pmax, np->in_use); - } else { - np->in_nextip.s_addr = htonl(np->in_nextip.s_addr); - if (!(np->in_flags & IPN_FILTER)) { - printf("%s/", inet_ntoa(np->in_in[0])); - bits = countbits(np->in_in[1].s_addr); - if (bits != -1) - printf("%d", bits); - else - printf("%s", inet_ntoa(np->in_in[1])); - } - printf(" -> "); - if (np->in_flags & IPN_IPRANGE) { - printf("range %s-", inet_ntoa(np->in_out[0])); - printf("%s", inet_ntoa(np->in_out[1])); - } else { - printf("%s/", inet_ntoa(np->in_out[0])); - bits = countbits(np->in_out[1].s_addr); - if (bits != -1) - printf("%d", bits); - else - printf("%s", inet_ntoa(np->in_out[1])); - } - if (*np->in_plabel) { - printf(" proxy port"); - if (np->in_dport != 0) { - if (pr != NULL) - sv = getservbyport(np->in_dport, - pr->p_name); - else - sv = getservbyport(np->in_dport, NULL); - if (sv != NULL) - printf(" %s", sv->s_name); - else - printf(" %hu", ntohs(np->in_dport)); - } - printf(" %.*s/", (int)sizeof(np->in_plabel), - np->in_plabel); - if (pr != NULL) - fputs(pr->p_name, stdout); - else - printf("%d", np->in_p); - } else if (np->in_redir == NAT_MAPBLK) { - if ((np->in_pmin == 0) && - (np->in_flags & IPN_AUTOPORTMAP)) - printf(" ports auto"); - else - printf(" ports %d", np->in_pmin); - if (opts & OPT_DEBUG) - printf("\n\tip modulous %d", np->in_pmax); - } else if (np->in_pmin || np->in_pmax) { - printf(" portmap"); - if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP) - printf(" tcp/udp"); - else if (np->in_flags & IPN_TCP) - printf(" tcp"); - else if (np->in_flags & IPN_UDP) - printf(" udp"); - if (np->in_flags & IPN_AUTOPORTMAP) { - printf(" auto"); - if (opts & OPT_DEBUG) - printf(" [%d:%d %d %d]", - ntohs(np->in_pmin), - ntohs(np->in_pmax), - np->in_ippip, np->in_ppip); - } else { - printf(" %d:%d", ntohs(np->in_pmin), - ntohs(np->in_pmax)); - } - } - if (np->in_flags & IPN_FRAG) - printf(" frag"); - if (np->in_mssclamp) - printf(" mssclamp %u", (unsigned)np->in_mssclamp); - if (np->in_age[0]) - printf(" age %d/%d", np->in_age[0], np->in_age[1]); - printf("\n"); - if (opts & OPT_DEBUG) { - printf("\tspace %lu nextip %s pnext %d", np->in_space, - inet_ntoa(np->in_nextip), np->in_pnext); - printf(" flags %x use %u\n", - np->in_flags, np->in_use); - } - } -} diff --git a/dist/ipf/printstate.c b/dist/ipf/printstate.c deleted file mode 100644 index 7cb451787a2d..000000000000 --- a/dist/ipf/printstate.c +++ /dev/null @@ -1,149 +0,0 @@ -/* $NetBSD: printstate.c,v 1.3 2002/05/02 17:11:38 martti Exp $ */ - -/* - * Copyright (C) 2002 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef __sgi -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if __FreeBSD_version >= 300000 -# include -#endif -#include "kmem.h" -#include "netinet/ip_compat.h" -#include "ipf.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_state.h" - -#define PRINTF (void)printf -#define FPRINTF (void)fprintf - -ipstate_t *printstate(sp, opts) -ipstate_t *sp; -int opts; -{ - ipstate_t ips; - - if (kmemcpy((char *)&ips, (u_long)sp, sizeof(ips))) - return NULL; - - PRINTF("%s -> ", hostname(ips.is_v, &ips.is_src.in4)); - PRINTF("%s ttl %ld pass %#x pr %d state %d/%d\n", - hostname(ips.is_v, &ips.is_dst.in4), - ips.is_age, ips.is_pass, ips.is_p, - ips.is_state[0], ips.is_state[1]); -#ifdef USE_QUAD_T - PRINTF("\tpkts %qu bytes %qu", (unsigned long long) ips.is_pkts, - (unsigned long long) ips.is_bytes); -#else - PRINTF("\tpkts %ld bytes %ld", ips.is_pkts, ips.is_bytes); -#endif - if (ips.is_p == IPPROTO_TCP) -#if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ -(__FreeBSD_version >= 220000) || defined(__OpenBSD__) - PRINTF("\t%hu -> %hu %x:%x %u<<%d:%u<<%d", - ntohs(ips.is_sport), ntohs(ips.is_dport), - ips.is_send, ips.is_dend, - ips.is_maxswin>>ips.is_swscale, ips.is_swscale, - ips.is_maxdwin>>ips.is_dwscale, ips.is_dwscale); -#else - PRINTF("\t%hu -> %hu %x:%x %u<<%d:%u<<%d", - ntohs(ips.is_sport), ntohs(ips.is_dport), - ips.is_send, ips.is_dend, - ips.is_maxswin>>ips.is_swscale, ips.is_swscale, - ips.is_maxdwin>>ips.is_dwscale, ips.is_dwscale); -#endif - else if (ips.is_p == IPPROTO_UDP) - PRINTF(" %hu -> %hu", ntohs(ips.is_sport), - ntohs(ips.is_dport)); - else if (ips.is_p == IPPROTO_ICMP -#ifdef USE_INET6 - || ips.is_p == IPPROTO_ICMPV6 -#endif - ) - PRINTF(" id %hu seq %hu type %d", ntohs(ips.is_icmp.ics_id), - ntohs(ips.is_icmp.ics_seq), ips.is_icmp.ics_type); - - PRINTF("\n\t"); - - /* - * Print out bits set in the result code for the state being - * kept as they would for a rule. - */ - if (ips.is_pass & FR_PASS) { - PRINTF("pass"); - } else if (ips.is_pass & FR_BLOCK) { - PRINTF("block"); - switch (ips.is_pass & FR_RETMASK) - { - case FR_RETICMP : - PRINTF(" return-icmp"); - break; - case FR_FAKEICMP : - PRINTF(" return-icmp-as-dest"); - break; - case FR_RETRST : - PRINTF(" return-rst"); - break; - default : - break; - } - } else if ((ips.is_pass & FR_LOGMASK) == FR_LOG) { - PRINTF("log"); - if (ips.is_pass & FR_LOGBODY) - PRINTF(" body"); - if (ips.is_pass & FR_LOGFIRST) - PRINTF(" first"); - } else if (ips.is_pass & FR_ACCOUNT) - PRINTF("count"); - - if (ips.is_pass & FR_OUTQUE) - PRINTF(" out"); - else - PRINTF(" in"); - - if ((ips.is_pass & FR_LOG) != 0) { - PRINTF(" log"); - if (ips.is_pass & FR_LOGBODY) - PRINTF(" body"); - if (ips.is_pass & FR_LOGFIRST) - PRINTF(" first"); - if (ips.is_pass & FR_LOGORBLOCK) - PRINTF(" or-block"); - } - if (ips.is_pass & FR_QUICK) - PRINTF(" quick"); - if (ips.is_pass & FR_KEEPFRAG) - PRINTF(" keep frags"); - /* a given; no? */ - if (ips.is_pass & FR_KEEPSTATE) - PRINTF(" keep state"); - PRINTF("\tIPv%d", ips.is_v); - PRINTF("\n"); - - PRINTF("\tpkt_flags & %x(%x) = %x,\t", - ips.is_flags & 0xf, ips.is_flags, - ips.is_flags >> 4); - PRINTF("\tpkt_options & %x = %x\n", ips.is_optmsk, - ips.is_opt); - PRINTF("\tpkt_security & %x = %x, pkt_auth & %x = %x\n", - ips.is_secmsk, ips.is_sec, ips.is_authmsk, - ips.is_auth); - PRINTF("\tinterfaces: in %s", getifname(ips.is_ifp[0])); - PRINTF(",%s", getifname(ips.is_ifp[1])); - PRINTF(" out %s", getifname(ips.is_ifp[2])); - PRINTF(",%s\n", getifname(ips.is_ifp[3])); - - return ips.is_next; -} diff --git a/dist/ipf/relay.c b/dist/ipf/relay.c deleted file mode 100644 index 672d94e21d4a..000000000000 --- a/dist/ipf/relay.c +++ /dev/null @@ -1,222 +0,0 @@ -/* $NetBSD: relay.c,v 1.6 2002/09/29 08:19:16 martti Exp $ */ - -/* - * Sample program to be used as a transparent proxy. - * - * Must be executed with permission enough to do an ioctl on /dev/ipl - * or equivalent. This is just a sample and is only alpha quality. - * - Darren Reed (8 April 1996) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000) -# include -# define USE_POLL -#endif -#include "ip_nat.h" - -#define RELAY_BUFSZ 8192 - -char ibuff[RELAY_BUFSZ]; -char obuff[RELAY_BUFSZ]; - -int relay(ifd, ofd, rfd) -int ifd, ofd, rfd; -{ - char *irh, *irt, *rrh, *rrt; - char *iwh, *iwt, *rwh, *rwt; - int nfd, n, rw; -#ifdef USE_POLL - struct pollfd set[3]; -#else - fd_set rfds, wfds; -#endif - - irh = irt = ibuff; - iwh = iwt = obuff; - nfd = ifd; - if (nfd < ofd) - nfd = ofd; - if (nfd < rfd) - nfd = rfd; - -#ifdef USE_POLL - set[0].fd = rfd; - set[1].fd = ifd; - set[2].fd = ofd; -#endif - while (1) { -#ifdef USE_POLL - set[0].events = (iwh < (obuff + RELAY_BUFSZ) ? POLLIN : 0) | - (irh > irt ? POLLOUT : 0); - set[1].events = (irh < (ibuff + RELAY_BUFSZ) ? POLLIN : 0); - set[2].events = (iwh > iwt ? POLLOUT : 0); -#else - FD_ZERO(&rfds); - FD_ZERO(&wfds); - if (irh > irt) - FD_SET(rfd, &wfds); - if (irh < (ibuff + RELAY_BUFSZ)) - FD_SET(ifd, &rfds); - if (iwh > iwt) - FD_SET(ofd, &wfds); - if (iwh < (obuff + RELAY_BUFSZ)) - FD_SET(rfd, &rfds); -#endif - -#ifdef USE_POLL - switch ((n = poll(set, 3, INFTIM))) -#else - switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL))) -#endif - { - case -1 : - case 0 : - return -1; - default : -#ifdef USE_POLL - if (set[1].revents & POLLIN) { -#else - if (FD_ISSET(ifd, &rfds)) { -#endif - rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh); - if (rw == -1) - return -1; - if (rw == 0) - return 0; - irh += rw; - } -#ifdef USE_POLL - if (set[2].revents & POLLOUT) { -#else - if (FD_ISSET(ofd, &wfds)) { -#endif - rw = write(ofd, iwt, iwh - iwt); - if (rw == -1) - return -1; - iwt += rw; - } -#ifdef USE_POLL - if (set[0].revents & POLLIN) { -#else - if (FD_ISSET(rfd, &rfds)) { -#endif - rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh); - if (rw == -1) - return -1; - if (rw == 0) - return 0; - iwh += rw; - } -#ifdef USE_POLL - if (set[0].revents & POLLOUT) { -#else - if (FD_ISSET(rfd, &wfds)) { -#endif - rw = write(rfd, irt, irh - irt); - if (rw == -1) - return -1; - irt += rw; - } - if (irh == irt) - irh = irt = ibuff; - if (iwh == iwt) - iwh = iwt = obuff; - } - } -} - -main(argc, argv) -int argc; -char *argv[]; -{ - struct sockaddr_in sin; - natlookup_t nl; - natlookup_t *nlp = &nl; - int fd, sl = sizeof(sl), se; - - openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON); - if ((fd = open("/dev/ipnat", O_RDONLY)) == -1) { - se = errno; - perror("open"); - errno = se; - syslog(LOG_ERR, "open: %m\n"); - exit(-1); - } - - bzero(&nl, sizeof(nl)); - nl.nl_flags = IPN_TCP; - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sl = sizeof(sin); - if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) { - se = errno; - perror("getsockname"); - errno = se; - syslog(LOG_ERR, "getsockname: %m\n"); - exit(-1); - } else { - nl.nl_inip.s_addr = sin.sin_addr.s_addr; - nl.nl_inport = sin.sin_port; - } - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sl = sizeof(sin); - if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) { - se = errno; - perror("getpeername"); - errno = se; - syslog(LOG_ERR, "getpeername: %m\n"); - exit(-1); - } else { - nl.nl_outip.s_addr = sin.sin_addr.s_addr; - nl.nl_outport = sin.sin_port; - } - - if (ioctl(fd, SIOCGNATL, &nlp) == -1) { - se = errno; - perror("ioctl"); - errno = se; - syslog(LOG_ERR, "ioctl: %m\n"); - exit(-1); - } - - sin.sin_port = nl.nl_realport; - sin.sin_addr = nl.nl_realip; - sl = sizeof(sin); - - fd = socket(AF_INET, SOCK_STREAM, 0); - if (connect(fd, (struct sockaddr *)&sin, sl) == -1) { - se = errno; - perror("connect"); - errno = se; - syslog(LOG_ERR, "connect: %m\n"); - exit(-1); - } - - (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); - (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); - (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); - - syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr), - ntohs(sin.sin_port)); - if (relay(0, 1, fd) == -1) { - se = errno; - perror("relay"); - errno = se; - syslog(LOG_ERR, "relay: %m\n"); - exit(-1); - } - exit(0); -} diff --git a/dist/ipf/samples/Makefile b/dist/ipf/samples/Makefile index 1dad07900c86..d36d7f018588 100644 --- a/dist/ipf/samples/Makefile +++ b/dist/ipf/samples/Makefile @@ -11,14 +11,16 @@ all: @echo "make sunos5" sunos5: - $(CC) -DSOLARIS2=`uname -r | sh -c 'IFS=. read j n x; echo $$n'` \ - -I.. userauth.c -o userauth -lsocket -lnsl - $(CC) -DSOLARIS2=`uname -r | sh -c 'IFS=. read j n x; echo $$n'` \ - -I.. proxy.c -o proxy -lsocket -lnsl + $(CC) -I.. userauth.c -o userauth -lsocket -lnsl + $(CC) -I.. proxy.c -o proxy -lsocket -lnsl + $(CC) -I.. relay.c -o relay -lsocket -lnsl + $(CC) -I.. trans_relay.c -o trans_relay -lsocket -lnsl freebsd freebsd22 netbsd bsd bsdi sunos4 openbsd: $(CC) -I.. userauth.c -o userauth $(CC) -I.. proxy.c -o proxy + $(CC) -I.. relay.c -o relay + $(CC) -I.. trans_relay.c -o trans_relay clean: - /bin/rm -f userauth proxy + /bin/rm -f userauth proxy relay trans_relay diff --git a/dist/ipf/samples/userauth.c b/dist/ipf/samples/userauth.c index ab9d40b1eea2..b2729d1e3ea5 100644 --- a/dist/ipf/samples/userauth.c +++ b/dist/ipf/samples/userauth.c @@ -1,4 +1,4 @@ -/* $NetBSD: userauth.c,v 1.3 2001/03/26 06:11:48 mike Exp $ */ +/* $NetBSD: userauth.c,v 1.4 2004/03/28 09:00:56 martti Exp $ */ #include #include @@ -23,7 +23,9 @@ main() char yn[16]; int fd; - fd = open(IPL_AUTH, O_RDWR); + fd = open(IPL_NAME, O_RDWR); + fra.fra_len = 0; + fra.fra_buf = NULL; while (ioctl(fd, SIOCAUTHW, &frap) == 0) { if (fra.fra_info.fin_out) fra.fra_pass = FR_OUTQUE; @@ -31,10 +33,10 @@ main() fra.fra_pass = FR_INQUE; printf("%s ", inet_ntoa(fi->fi_src)); - if (fi->fi_fl & FI_TCPUDP) + if (fi->fi_flx & FI_TCPUDP) printf("port %d ", fin->fin_data[0]); printf("-> %s ", inet_ntoa(fi->fi_dst)); - if (fi->fi_fl & FI_TCPUDP) + if (fi->fi_flx & FI_TCPUDP) printf("port %d ", fin->fin_data[1]); printf("\n"); printf("Allow packet through ? [y/n]"); @@ -46,7 +48,7 @@ main() fra.fra_pass |= FR_BLOCK; else if (yn[0] == 'y' || yn[0] == 'Y') { fra.fra_pass |= FR_PASS; - if (fra.fra_info.fin_fi.fi_fl & FI_TCPUDP) + if (fra.fra_info.fin_fi.fi_flx & FI_TCPUDP) fra.fra_pass |= FR_KEEPSTATE; } else fra.fra_pass |= FR_NOMATCH; diff --git a/dist/ipf/snoop.h b/dist/ipf/snoop.h index 2532f6a228bc..a8238179d3ab 100644 --- a/dist/ipf/snoop.h +++ b/dist/ipf/snoop.h @@ -1,4 +1,4 @@ -/* $NetBSD: snoop.h,v 1.3 2002/01/24 08:21:36 martti Exp $ */ +/* $NetBSD: snoop.h,v 1.4 2004/03/28 09:00:54 martti Exp $ */ /* * Copyright (C) 1993-2001 by Darren Reed. @@ -11,7 +11,7 @@ /* * written to comply with the RFC (1761) from Sun. - * Id: snoop.h,v 2.2.2.1 2001/06/26 10:43:20 darrenr Exp + * Id: snoop.h,v 2.3 2001/06/09 17:09:23 darrenr Exp */ struct snoophdr { char s_id[8]; diff --git a/dist/ipf/todo b/dist/ipf/todo index 4c2adf1e9868..5b2c05905214 100644 --- a/dist/ipf/todo +++ b/dist/ipf/todo @@ -7,9 +7,14 @@ fastroute works GENERAL: -------- +* support redirection like "rdr tun0 0/32 port 80 ..." + * use fr_tcpstate() with NAT code for increased NAT usage security or even fr_checkstate() - suspect this is not possible. +* add another alias for for interfaces ? as well as + all IP#'s associated with the box ? + time permitting: * load balancing across interfaces @@ -17,21 +22,13 @@ time permitting: * record buffering for TCP/UDP * modular application proxying -available +-done * allow multiple ip addresses in a source route list for ipsend -* complete Linux port to implement all the IP Filter features -return-rst done, to/dup-to/fastroute remain - ip_forward() problems :-( -on hold until rewrite +* port IP Filter to Linux +Not in this century. -* add a flag to automate src spoofing -done - -* ipfsync() should change IP#'s in current mappings as well as what's - in rules. -done - * document bimap * document NAT rule order processing @@ -43,22 +40,23 @@ in progress XDDD. I agree. Bandwidth Shapping and QoS (Quality of Service, AKA traffic priorization) should be *TOP* in the TO DO list. -* irc proxy for dcc * Bandwidth limiting!!! +maybe for solaris, otherwise "ALTQ" * More examples * More documentation -* And did I mention bandwidth limiting??? * Load balancing features added to the NAT code, so that I can have something coming in for 20.20.20.20:80 and it gets shuffled around between internal addresses 10.10.10.1:8000 and 10.10.10.2:8000. or whatever. - done, stage 1 (round robin/split) The one thing that Cisco's PIX has on IPF that I can see is that rewrites the sequence numbers with semi-random ones. +- done I would also love to see a more extensive NAT. It can choose to do rdr and map based on saddr, daddr, sport and dport. (Does the kernel module already have functionality for that and it just needs support in the userland ipnat?) +-sort of done * intrusion detection detection of port scans @@ -76,23 +74,25 @@ the userland ipnat?) large packets of garbage or other packets to otherwise confuse the intruder (ping of death?) -* I ran into your solaris streams stuff and noticed you are -playing with mblk's in an unsafe way. You seem to be modifying the -underlying datab without checking db_ref. If db_ref is greater than one, -you'll need to copy the mblk, -- fixed - -* fix up where manual pages go for Solaris2 - - IPv6: ----- * NAT is yet not available, either as a null proxy or address translation BSD: * "to " and "to :" are not supported, but "fastroute" is. -fixed. Solaris: * "to :" is not supported, but "fastroute" is and "to " are. +Tru64: +------ +* IPv6 checksum calculation for RST's and ICMP packets is not done (there + are routines in the Tru64 kernel to do this but what is the interface?) + +does bimap allow equal sized subnets? + +make return-icmp 'intelligent' if no type is given about what type to use? + +reply-to - enforce packets to pass through interfaces in particular +combinations - opposite to "to", set reverse path interface + diff --git a/sys/lkm/netinet/if_ipl/mln_ipl.c b/sys/lkm/netinet/if_ipl/mln_ipl.c index 1fb0291450d1..19ed606fb577 100644 --- a/sys/lkm/netinet/if_ipl/mln_ipl.c +++ b/sys/lkm/netinet/if_ipl/mln_ipl.c @@ -1,9 +1,10 @@ -/* $NetBSD: mln_ipl.c,v 1.32 2003/06/29 22:31:37 fvdl Exp $ */ +/* $NetBSD: mln_ipl.c,v 1.33 2004/03/28 09:00:57 martti Exp $ */ /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. + * */ /* * 29/12/94 Added code from Marc Huber to allow it to allocate @@ -11,7 +12,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: mln_ipl.c,v 1.32 2003/06/29 22:31:37 fvdl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mln_ipl.c,v 1.33 2004/03/28 09:00:57 martti Exp $"); #include @@ -58,29 +59,29 @@ __KERNEL_RCSID(0, "$NetBSD: mln_ipl.c,v 1.32 2003/06/29 22:31:37 fvdl Exp $"); #define VOP_LEASE LEASE_CHECK #endif + +extern int lkmenodev __P((void)); + #if NetBSD >= 199706 int if_ipl_lkmentry __P((struct lkm_table *, int, int)); #else -#if defined(OpenBSD) -int if_ipl __P((struct lkm_table *, int, int)); -#else int xxxinit __P((struct lkm_table *, int, int)); #endif -#endif static int ipl_unload __P((void)); static int ipl_load __P((void)); static int ipl_remove __P((void)); static int iplaction __P((struct lkm_table *, int)); -static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, - NULL }; +static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, + IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, + IPLOOKUP_NAME, NULL }; #if (defined(NetBSD1_0) && (NetBSD1_0 > 1)) || \ (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199511)) -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) extern const struct cdevsw ipl_cdevsw; -#else -struct cdevsw ipldevsw = +# else +struct cdevsw ipldevsw = { iplopen, /* open */ iplclose, /* close */ @@ -93,9 +94,9 @@ struct cdevsw ipldevsw = 0, /* mmap */ NULL /* strategy */ }; -#endif +# endif #else -struct cdevsw ipldevsw = +struct cdevsw ipldevsw = { iplopen, /* open */ iplclose, /* close */ @@ -103,9 +104,7 @@ struct cdevsw ipldevsw = (void *)nullop, /* write */ iplioctl, /* ioctl */ (void *)nullop, /* stop */ -#ifndef OpenBSD (void *)nullop, /* reset */ -#endif (void *)NULL, /* tty */ (void *)nullop, /* select */ (void *)nullop, /* mmap */ @@ -128,21 +127,14 @@ extern int nchrdev; #if NetBSD >= 199706 int if_ipl_lkmentry(lkmtp, cmd, ver) #else -#if defined(OpenBSD) -int if_ipl(lkmtp, cmd, ver) -#else int xxxinit(lkmtp, cmd, ver) #endif -#endif struct lkm_table *lkmtp; int cmd, ver; { DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); } -#ifdef OpenBSD -int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */ -#endif static int iplaction(lkmtp, cmd) struct lkm_table *lkmtp; @@ -210,16 +202,19 @@ static int ipl_remove() int error, i; for (i = 0; (name = ipf_devfiles[i]); i++) { +#if (__NetBSD_Version__ > 106009999) + NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, + name, curproc); +#else NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); +#endif if ((error = namei(&nd))) return (error); - VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); -#ifdef OpenBSD - VOP_LOCK(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY, curproc); -#else + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); +#if !defined(__NetBSD_Version__) || (__NetBSD_Version__ < 106000000) vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); #endif - VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); } return 0; @@ -234,10 +229,16 @@ static int ipl_unload() * Unloading - remove the filter rule check from the IP * input/output stream. */ - error = ipl_disable(); + if (fr_refcnt) + error = EBUSY; + else if (fr_running >= 0) + error = ipldetach(); - if (!error) + if (error == 0) { + fr_running = -2; error = ipl_remove(); + printf("%s unloaded\n", ipfilter_version); + } return error; } @@ -256,14 +257,12 @@ static int ipl_load() */ (void)ipl_remove(); - error = ipl_enable(); - if (error) - return error; + error = iplattach(); - for (i = 0; (name = ipf_devfiles[i]); i++) { + for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) { NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); if ((error = namei(&nd))) - return error; + break; if (nd.ni_vp != NULL) { VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); if (nd.ni_dvp == nd.ni_vp) @@ -271,7 +270,8 @@ static int ipl_load() else vput(nd.ni_dvp); vrele(nd.ni_vp); - return (EEXIST); + error = EEXIST; + break; } VATTR_NULL(&vattr); vattr.va_type = VCHR; @@ -279,9 +279,34 @@ static int ipl_load() vattr.va_rdev = (ipl_major << 8) | i; VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); - if (error) - return error; - vput(nd.ni_vp); + if (error == 0) + vput(nd.ni_vp); + } + + if (error == 0) { + char *defpass; + + if (FR_ISPASS(fr_pass)) + defpass = "pass"; + else if (FR_ISBLOCK(fr_pass)) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s%s\n", + ipfilter_version, defpass, +#ifdef IPFILTER_LOG + "enabled", +#else + "disabled", +#endif +#ifdef IPFILTER_COMPILED + " (COMPILED)" +#else + "" +#endif + ); + fr_running = 1; } return error; } diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c index f133be5de48a..c30a858a234d 100644 --- a/sys/netinet/fil.c +++ b/sys/netinet/fil.c @@ -1,26 +1,29 @@ -/* $NetBSD: fil.c,v 1.59 2003/08/07 16:33:07 agc Exp $ */ +/* $NetBSD: fil.c,v 1.60 2004/03/28 09:00:56 martti Exp $ */ /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#ifdef __sgi -# include +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include #include #include #include -#include -#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ - defined(_KERNEL) -# include "opt_ipfilter_log.h" +#if defined(__NetBSD__) +# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) +# include "opt_ipfilter_log.h" +# endif #endif -#if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \ +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ (__FreeBSD_version >= 220000) # if (__FreeBSD_version >= 400000) -# ifndef KLD_MODULE +# if !defined(IPFILTER_LKM) # include "opt_inet6.h" # endif # if (__FreeBSD_version == 400019) @@ -28,41 +31,56 @@ # endif # endif # include -# include #else # include #endif -#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +#include +#if defined(_KERNEL) # include +# include #else # include # include # include -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux -# include +# include +# include +# define _KERNEL +# ifdef __OpenBSD__ +struct file; # endif +# include +# undef _KERNEL +#endif +#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ + !defined(linux) +# include #else -# include -# if SOLARIS2 < 5 +# if !defined(linux) +# include +# endif +# if (SOLARIS2 < 5) && defined(sun) # include # endif -# include #endif -#ifndef linux +#ifdef __hpux +# define _NET_ROUTE_INCLUDED +#endif +#if !defined(linux) # include -# include #endif +#include #include #ifdef sun # include #endif +#if !defined(_KERNEL) && defined(__FreeBSD__) +# include "radix_ipf.h" +#endif #include #include #include #include -#ifndef linux +#if !defined(linux) # include #endif #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ @@ -70,12 +88,17 @@ # include #endif #include -#include -#include +#if !defined(__sgi) || defined(_KERNEL) +# include +# include +#endif +#ifdef __hpux +# undef _NET_ROUTE_INCLUDED +#endif #include "netinet/ip_compat.h" #ifdef USE_INET6 # include -# if !SOLARIS && defined(_KERNEL) +# if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) # include # endif #endif @@ -86,72 +109,139 @@ #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" #include "netinet/ip_auth.h" -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) -# include -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include "opt_ipfilter.h" -# endif +#ifdef IPFILTER_SCAN +# include "netinet/ip_scan.h" +#endif +#ifdef IPFILTER_SYNC +# include "netinet/ip_sync.h" +#endif +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#ifdef IPFILTER_COMPILED +# include "netinet/ip_rules.h" +#endif +#if defined(IPFILTER_BPF) && defined(_KERNEL) +# include +#endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" # endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) #endif #include "netinet/ipl.h" +/* END OF INCLUDES */ #if !defined(lint) #if defined(__NetBSD__) #include -__KERNEL_RCSID(0, "$NetBSD: fil.c,v 1.59 2003/08/07 16:33:07 agc Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fil.c,v 1.60 2004/03/28 09:00:56 martti Exp $"); #else static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)Id: fil.c,v 2.35.2.63 2002/08/28 12:40:08 darrenr Exp"; +static const char rcsid[] = "@(#)Id: fil.c,v 2.243.2.7 2004/03/23 12:06:56 darrenr Exp"; #endif #endif #ifndef _KERNEL # include "ipf.h" # include "ipt.h" +# include "bpf-ipf.h" extern int opts; # define FR_VERBOSE(verb_pr) verbose verb_pr # define FR_DEBUG(verb_pr) debug verb_pr -# define IPLLOG(a, c, d, e) ipflog(a, c, d, e) #else /* #ifndef _KERNEL */ # define FR_VERBOSE(verb_pr) # define FR_DEBUG(verb_pr) -# define IPLLOG(a, c, d, e) ipflog(a, c, d, e) -# if SOLARIS || defined(__sgi) -extern KRWLOCK_T ipf_mutex, ipf_auth, ipf_nat; -extern kmutex_t ipf_rw; -# endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ -struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}}; +fr_info_t frcache[2][8]; +struct filterstats frstats[2] = { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } }, -#ifdef USE_INET6 *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } }, *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } }, -#endif - *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }; -struct frgroup *ipfgroups[3][2]; + *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }, + *ipnatrules[2][2] = { { NULL, NULL }, { NULL, NULL } }; +struct frgroup *ipfgroups[IPL_LOGSIZE][2]; +char ipfilter_version[] = IPL_VERSION; +int fr_refcnt = 0; +/* + * For fr_running: + * 0 == loading, 1 = running, -1 = disabled, -2 = unloading + */ +int fr_running = 0; int fr_flags = IPF_LOGGING; int fr_active = 0; -int fr_chksrc = 0; -int fr_minttl = 3; -int fr_minttllog = 1; +int fr_control_forwarding = 0; +int fr_update_ipid = 0; +u_short fr_ip_id = 0; +int fr_chksrc = 0; /* causes a system crash if enabled */ +int fr_minttl = 4; +u_long fr_frouteok[2] = {0, 0}; +u_long fr_userifqs = 0; +u_char ipf_iss_secret[32]; #if defined(IPFILTER_DEFAULT_BLOCK) -int fr_pass = FR_NOMATCH|FR_BLOCK; +int fr_pass = FR_BLOCK|FR_NOMATCH; #else -int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH); +int fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; #endif -char ipfilter_version[] = IPL_VERSION; - -fr_info_t frcache[2]; - -static int frflushlist __P((int, minor_t, int *, frentry_t **)); -#ifdef _KERNEL -static void frsynclist __P((frentry_t *)); +#ifdef ICMP_UNREACH_FILTER_PROHIB +int fr_unreach = ICMP_UNREACH_FILTER_PROHIB; +#else +int fr_unreach = ICMP_UNREACH_FILTER; #endif +int fr_features = 0 +#ifdef IPFILTER_LKM + | IPF_FEAT_LKM +#endif +#ifdef IPFILTER_LOG + | IPF_FEAT_LOG +#endif +#ifdef IPFILTER_LOOKUP + | IPF_FEAT_LOOKUP +#endif +#ifdef IPFILTER_BPF + | IPF_FEAT_BPF +#endif +#ifdef IPFILTER_COMPILED + | IPF_FEAT_COMPILED +#endif +#ifdef IPFILTER_CKSUM + | IPF_FEAT_CKSUM +#endif +#ifdef IPFILTER_SYNC + | IPF_FEAT_SYNC +#endif +#ifdef IPFILTER_SCAN + | IPF_FEAT_SCAN +#endif +#ifdef USE_INET6 + | IPF_FEAT_IPV6 +#endif + ; + +static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); +static int fr_portcheck __P((frpcmp_t *, u_short *)); +static int frflushlist __P((int, minor_t, int *, frentry_t **)); +static ipfunc_t fr_findfunc __P((ipfunc_t)); +static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *)); +static int fr_funcinit __P((frentry_t *fr)); +static INLINE void frpr_esp __P((fr_info_t *)); +static INLINE void frpr_gre __P((fr_info_t *)); +static INLINE void frpr_udp __P((fr_info_t *)); +static INLINE void frpr_tcp __P((fr_info_t *)); +static INLINE void frpr_icmp __P((fr_info_t *)); +static INLINE void frpr_ipv4hdr __P((fr_info_t *)); +static INLINE void frpr_short __P((fr_info_t *, int)); +static INLINE void frpr_tcpcommon __P((fr_info_t *)); +static INLINE void frpr_udpcommon __P((fr_info_t *)); +static INLINE int fr_updateipid __P((fr_info_t *)); +#ifdef IPFILTER_LOOKUP +static int fr_grpmapinit __P((frentry_t *fr)); +static INLINE void *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *)); +#endif +static void frsynclist __P((frentry_t *)); /* @@ -180,6 +270,29 @@ const struct optlist ipopts[20] = { { 0, 0x000000 } }; +#ifdef USE_INET6 +struct optlist ip6exthdr[] = { + { IPPROTO_HOPOPTS, 0x000001 }, + { IPPROTO_DSTOPTS, 0x000002 }, + { IPPROTO_ESP, 0x000004 }, + { IPPROTO_AH, 0x000008 }, + { IPPROTO_ROUTING, 0x000010 }, + { IPPROTO_IPV6, 0x000020 }, + { IPPROTO_FRAGMENT, 0x000040 }, + { IPPROTO_NONE, 0x000080 } +}; +#endif + +struct optlist tcpopts[] = { + { TCPOPT_NOP, 0x000001 }, + { TCPOPT_MAXSEG, 0x000002 }, + { TCPOPT_WINDOW, 0x000004 }, + { TCPOPT_SACK_PERMITTED, 0x000008 }, + { TCPOPT_SACK, 0x000010 }, + { TCPOPT_TIMESTAMP, 0x000020 }, + { 0, 0x000000 } +}; + /* * bit values for identifying presence of individual IP security options */ @@ -196,223 +309,918 @@ const struct optlist secopt[8] = { /* - * compact the IP header into a structure which contains just the info. - * which is useful for comparing IP headers with. + * Table of functions available for use with call rules. */ -void fr_makefrip(hlen, ip, fin) -int hlen; -ip_t *ip; +static ipfunc_resolve_t fr_availfuncs[] = { +#ifdef IPFILTER_LOOKUP + { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit }, + { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit }, +#endif + { "", NULL } +}; + + +/* + * The next section of code is a a collection of small routines that set + * fields in the fr_info_t structure passed based on properties of the + * current packet. There are different routines for the same protocol + * for each of IPv4 and IPv6. Adding a new protocol, for which there + * will "special" inspection for setup, is now more easily done by adding + * a new routine and expanding the frpr_ipinit*() function rather than by + * adding more code to a growing switch statement. + */ +#ifdef USE_INET6 +static INLINE void frpr_udp6 __P((fr_info_t *)); +static INLINE void frpr_tcp6 __P((fr_info_t *)); +static INLINE void frpr_icmp6 __P((fr_info_t *)); +static INLINE void frpr_ipv6hdr __P((fr_info_t *)); +static INLINE void frpr_short6 __P((fr_info_t *, int)); +static INLINE void frpr_hopopts6 __P((fr_info_t *)); +static INLINE void frpr_routing6 __P((fr_info_t *)); +static INLINE void frpr_dstopts6 __P((fr_info_t *)); +static INLINE void frpr_fragment6 __P((fr_info_t *)); + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_short6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function enforces the 'is a packet too short to be legit' rule */ +/* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ +/* for frpr_short() for more details. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_short6(fin, min) +fr_info_t *fin; +int min; +{ + fr_ip_t *fi = &fin->fin_fi; + int off; + + off = fin->fin_off; + if (off == 0) { + if (fin->fin_plen < fin->fin_hlen + min) + fi->fi_flx |= FI_SHORT; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_ipv6hdr */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Copy values from the IPv6 header into the fr_info_t struct and call the */ +/* per-protocol analyzer if it exists. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_ipv6hdr(fin) +fr_info_t *fin; +{ + int p, go = 1, i, hdrcount, coalesced; + ip6_t *ip6 = (ip6_t *)fin->fin_ip; + fr_ip_t *fi = &fin->fin_fi; + + fin->fin_off = 0; + + fi->fi_tos = 0; + fi->fi_optmsk = 0; + fi->fi_secmsk = 0; + fi->fi_auth = 0; + + coalesced = 0; + p = ip6->ip6_nxt; + fi->fi_p = p; + fi->fi_ttl = ip6->ip6_hlim; + fi->fi_src.in6 = ip6->ip6_src; + fi->fi_dst.in6 = ip6->ip6_dst; + fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff); + + hdrcount = 0; + while(go && (~fin->fin_flx & FI_SHORT) && (~fin->fin_flx & FI_BAD)) { + switch (p) + { + case IPPROTO_UDP : + frpr_udp6(fin); + go = 0; + break; + case IPPROTO_TCP : + frpr_tcp6(fin); + go = 0; + break; + case IPPROTO_ICMPV6 : + frpr_icmp6(fin); + go = 0; + break; + case IPPROTO_HOPOPTS : + /* + * Actually, hop by hop header is only allowed right + * after IPv6 header! + */ + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced == -1) + return; + } + if (hdrcount != 0) + fin->fin_flx |= FI_BAD; + else + frpr_hopopts6(fin); + break; + case IPPROTO_DSTOPTS : + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced == -1) + return; + } + frpr_dstopts6(fin); + break; + case IPPROTO_ROUTING : + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced == -1) + return; + } + frpr_routing6(fin); + break; + case IPPROTO_ESP : + frpr_esp(fin); + /*FALLTHROUGH*/ + case IPPROTO_AH : + case IPPROTO_IPV6 : + for(i = 0; ip6exthdr[i].ol_val != IPPROTO_NONE; i++) + if(ip6exthdr[i].ol_val == fin->fin_p) + break; + fin->fin_flx |= ip6exthdr[i].ol_bit; + go = 0; + break; + case IPPROTO_NONE : + go = 0; + break; + case IPPROTO_FRAGMENT : + if (coalesced == 0) { + coalesced = fr_coalesce(fin); + if (coalesced == -1) + return; + } + frpr_fragment6(fin); + break; + default : + go = 0; + break; + } + p = fi->fi_p; + hdrcount++; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_hopopts6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function checks pending hop by hop options extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_hopopts6(fin) +fr_info_t *fin; +{ + struct ip6_ext *hdr; + u_short shift; + int i; + + fin->fin_flx |= FI_V6EXTHDR; + + /* 8 is default length of extension hdr */ + if ((fin->fin_dlen - 8) < 0) { + fin->fin_flx |= FI_SHORT; + return; + } + + hdr = fin->fin_dp; + shift = 8 + (hdr->ip6e_len << 3); + if (shift > fin->fin_dlen) { /* Nasty extension header length? */ + fin->fin_flx |= FI_BAD; + return; + } + + for (i = 0; ip6exthdr[i].ol_val != IPPROTO_NONE; i++) + if(ip6exthdr[i].ol_val == fin->fin_p) + break; + + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + fin->fin_dp = (char *)fin->fin_dp + shift; + fin->fin_dlen -= shift; + fin->fin_p = hdr->ip6e_nxt; + + return; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_routing6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function checks pending routing extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_routing6(fin) +fr_info_t *fin; +{ + struct ip6_ext *hdr; + u_short shift; + int i; + + fin->fin_flx |= FI_V6EXTHDR; + + /* 8 is default length of extension hdr */ + if ((fin->fin_dlen - 8) < 0) { + fin->fin_flx |= FI_SHORT; + return; + } + + hdr = fin->fin_dp; + shift = 8 + (hdr->ip6e_len << 3); + /* + * Nasty extension header length? + */ + if ((shift > fin->fin_dlen) || (shift < sizeof(struct ip6_hdr)) || + ((shift - sizeof(struct ip6_hdr)) & 15)) { + fin->fin_flx |= FI_BAD; + return; + } + + for (i = 0; ip6exthdr[i].ol_val != IPPROTO_NONE; i++) + if(ip6exthdr[i].ol_val == fin->fin_p) + break; + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + fin->fin_dp = (char *)fin->fin_dp + shift; + fin->fin_dlen -= shift; + fin->fin_p = hdr->ip6e_nxt; + + return; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_fragment6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Examine the IPv6 fragment header and extract fragment offset information.*/ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_fragment6(fin) +fr_info_t *fin; +{ + struct ip6_frag *frag; + struct ip6_ext *hdr; + int i; + + /* + * Only one frgament header is allowed per IPv6 packet but it need + * not be the first nor last (not possible in some cases.) + */ + for (i = 0; ip6exthdr[i].ol_val != IPPROTO_NONE; i++) + if (ip6exthdr[i].ol_val == fin->fin_p) + break; + + if (fin->fin_optmsk & ip6exthdr[i].ol_bit) { + fin->fin_flx |= FI_BAD; + return; + } + fin->fin_flx |= (FI_FRAG|FI_V6EXTHDR); + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + + hdr = fin->fin_dp; + + /* + * Length must be zero, i.e. it is no length. + */ + if (hdr->ip6e_len != 0) { + fin->fin_flx |= FI_BAD; + return; + } + + if ((int)(fin->fin_dlen - sizeof(*frag)) < 0) { + fin->fin_flx |= FI_SHORT; + return; + } + + frag = fin->fin_dp; + fin->fin_off = frag->ip6f_offlg & IP6F_OFF_MASK; + if (!(frag->ip6f_offlg & IP6F_MORE_FRAG)) + fin->fin_flx |= FI_FRAGTAIL; + + fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag); + fin->fin_dlen -= sizeof(*frag); + fin->fin_p = frag->ip6f_nxt; + + return; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_dstopts6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* nextheader(I) - stores next header value */ +/* */ +/* IPv6 Only */ +/* This is function checks pending destination options extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_dstopts6(fin) +fr_info_t *fin; +{ + struct ip6_ext *hdr; + u_short shift; + int i; + + /* 8 is default length of extension hdr */ + if ((fin->fin_dlen - 8) < 0) { + fin->fin_flx |= FI_SHORT; + return; + } + hdr = fin->fin_dp; + shift = 8 + (hdr->ip6e_len << 3); + if (shift > fin->fin_dlen) { /* Nasty extension header length? */ + fin->fin_flx |= FI_BAD; + return; + } + + for (i = 0; ip6exthdr[i].ol_val != IPPROTO_NONE; i++) + if(ip6exthdr[i].ol_val == fin->fin_p) + break; + fin->fin_optmsk |= ip6exthdr[i].ol_bit; + fin->fin_dp = (char *)fin->fin_dp + shift; + fin->fin_dlen -= shift; + fin->fin_p = hdr->ip6e_nxt; + + return; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_icmp6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This routine is mainly concerned with determining the minimum valid size */ +/* for an ICMPv6 packet. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_icmp6(fin) +fr_info_t *fin; +{ + int minicmpsz = sizeof(struct icmp6_hdr); + struct icmp6_hdr *icmp6; + + if (fin->fin_dlen > 1) { + icmp6 = fin->fin_dp; + + fin->fin_data[0] = *(u_short *)icmp6; + + switch (icmp6->icmp6_type) + { + case ICMP6_ECHO_REPLY : + case ICMP6_ECHO_REQUEST : + minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); + break; + case ICMP6_DST_UNREACH : + case ICMP6_PACKET_TOO_BIG : + case ICMP6_TIME_EXCEEDED : + case ICMP6_PARAM_PROB : + if ((fin->fin_m != NULL) && + (M_LEN(fin->fin_m) < fin->fin_plen)) { + if (fr_coalesce(fin) == -1) + return; + } + fin->fin_flx |= FI_ICMPERR; + minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); + break; + default : + break; + } + } + + frpr_short(fin, minicmpsz); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_udp6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Analyse the packet for IPv6/UDP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_udp6(fin) +fr_info_t *fin; +{ + + fr_checkv6sum(fin); + + frpr_short(fin, sizeof(struct udphdr)); + + frpr_udpcommon(fin); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_tcp6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Analyse the packet for IPv6/TCP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_tcp6(fin) +fr_info_t *fin; +{ + + fr_checkv6sum(fin); + + frpr_short(fin, sizeof(struct tcphdr)); + + frpr_tcpcommon(fin); +} +#endif /* USE_INET6 */ + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_short */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* min(I) - minimum header size */ +/* */ +/* Check if a packet is "short" as defined by min. The rule we are */ +/* applying here is that the packet must not be fragmented within the layer */ +/* 4 header. That is, it must not be a fragment that has its offset set to */ +/* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ +/* entire layer 4 header must be present (min). */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_short(fin, min) +fr_info_t *fin; +int min; +{ + fr_ip_t *fi = &fin->fin_fi; + int off; + + off = fin->fin_off; + if (off == 0) { + if (fin->fin_plen < fin->fin_hlen + min) + fi->fi_flx |= FI_SHORT; + } else if (off < min) { + fi->fi_flx |= FI_SHORT; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_icmp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ +/* except extrememly bad packets, both type and code will be present. */ +/* The expected minimum size of an ICMP packet is very much dependant on */ +/* the type of it. */ +/* */ +/* XXX - other ICMP sanity checks? */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_icmp(fin) +fr_info_t *fin; +{ + int minicmpsz = sizeof(struct icmp); + icmphdr_t *icmp; + + fr_checkv4sum(fin); + + if (!fin->fin_off && (fin->fin_dlen > 1)) { + icmp = fin->fin_dp; + + fin->fin_data[0] = *(u_short *)icmp; + + switch (icmp->icmp_type) + { + case ICMP_ECHOREPLY : + case ICMP_ECHO : + /* Router discovery messaes - RFC 1256 */ + case ICMP_ROUTERADVERT : + case ICMP_ROUTERSOLICIT : + minicmpsz = ICMP_MINLEN; + break; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + + * 3 * timestamp(3 * 4) + */ + case ICMP_TSTAMP : + case ICMP_TSTAMPREPLY : + minicmpsz = 20; + break; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + + * mask(4) + */ + case ICMP_MASKREQ : + case ICMP_MASKREPLY : + minicmpsz = 12; + break; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) + */ + case ICMP_UNREACH : + case ICMP_SOURCEQUENCH : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_PARAMPROB : + if ((fin->fin_m != NULL) && + (M_LEN(fin->fin_m) < fin->fin_plen)) { + if (fr_coalesce(fin) == -1) + return; + } + fin->fin_flx |= FI_ICMPERR; + break; + default : + break; + } + + if (fin->fin_dlen >= 6) /* ID field */ + fin->fin_data[1] = icmp->icmp_id; + } + + frpr_short(fin, minicmpsz); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_tcpcommon */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* TCP header sanity checking. Look for bad combinations of TCP flags, */ +/* and make some checks with how they interact with other fields. */ +/* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ +/* valid and mark the packet as bad if not. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_tcpcommon(fin) +fr_info_t *fin; +{ + int flags, tlen; + tcphdr_t *tcp; + fr_ip_t *fi; + + fi = &fin->fin_fi; + fi->fi_flx |= FI_TCPUDP; + if (fin->fin_off != 0) + return; + +#if defined(_KERNEL) && !defined(__sgi) + if ((fin->fin_m != NULL) && !(fi->fi_flx & FI_SHORT)) { + if (M_LEN(fin->fin_m) < sizeof(*tcp) + fin->fin_hlen) { + if (fr_pullup(fin->fin_m, fin, + sizeof(*tcp) + fin->fin_hlen) == NULL) + return; + } + } +#endif + + tcp = fin->fin_dp; + if (fin->fin_dlen > 3) { + fin->fin_sport = ntohs(tcp->th_sport); + fin->fin_dport = ntohs(tcp->th_dport); + } + + if ((fi->fi_flx & FI_SHORT) != 0) + return; + + /* + * Use of the TCP data offset *must* result in a value that is at + * least the same size as the TCP header. + */ + tlen = TCP_OFF(tcp) << 2; + if (tlen < sizeof(tcphdr_t)) { + fin->fin_flx |= FI_BAD; + return; + } + + flags = tcp->th_flags; + fin->fin_tcpf = tcp->th_flags; + + /* + * If the urgent flag is set, then the urgent pointer must + * also be set and vice versa. Good TCP packets do not have + * just one of these set. + */ + if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { + fin->fin_flx |= FI_BAD; + } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { + /* Ignore this case, it shows up in "real" traffic with */ + /* bogus values in the urgent pointer field. */ + ; + } else if (((flags & (TH_SYN|TH_FIN)) != 0) && + ((flags & (TH_RST|TH_ACK)) == TH_RST)) { + /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ + fin->fin_flx |= FI_BAD; + } else if (!(flags & TH_ACK)) { + /* + * If the ack bit isn't set, then either the SYN or + * RST bit must be set. If the SYN bit is set, then + * we expect the ACK field to be 0. If the ACK is + * not set and if URG, PSH or FIN are set, consdier + * that to indicate a bad TCP packet. + */ + if ((flags == TH_SYN) && (tcp->th_ack != 0)) { + fin->fin_flx |= FI_BAD; + } else if (!(flags & (TH_RST|TH_SYN))) { + fin->fin_flx |= FI_BAD; + } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { + fin->fin_flx |= FI_BAD; + } + } + +#if 0 + /* + * At this point, it's not exactly clear what is to be gained by + * marking up which TCP options are and are not present. The one we + * are most interested in is the TCP window scale. This is only in + * a SYN packet [RFC1323] so we don't need this here...? + * Now if we were to analyse the header for passive fingerprinting, + * then that might add some weight to adding this... + */ + if (tlen == sizeof(tcphdr_t)) + return; + +#if defined(_KERNEL) && !defined(__sgi) + if (fin->fin_m != NULL) { + if (M_LEN(fin->fin_m) < tlen + fin->fin_hlen) { + if (fr_pullup(fin->fin_m, fin, + tlen + fin->fin_hlen) == NULL) + return; + } + } +#endif + + s = (u_char *)(tcp + 1); + off = IP_HL(ip) << 2; +# ifdef _KERNEL + if (fin->fin_mp != NULL) { + mb_t *m = *fin->fin_mp; + + if (off + tlen > M_LEN(m)) + return; + } +# endif + for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { + opt = *s; + if (opt == '\0') + break; + else if (opt == TCPOPT_NOP) + ol = 1; + else { + if (tlen < 2) + break; + ol = (int)*(s + 1); + if (ol < 2 || ol > tlen) + break; + } + + for (i = 9, mv = 4; mv >= 0; ) { + op = ipopts + i; + if (opt == (u_char)op->ol_val) { + optmsk |= op->ol_bit; + break; + } + } + tlen -= ol; + s += ol; + } +#endif /* 0 */ +} + + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_udpcommon */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Extract the UDP source and destination ports, if present. If compiled */ +/* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_udpcommon(fin) +fr_info_t *fin; +{ + udphdr_t *udp; + fr_ip_t *fi; + + fi = &fin->fin_fi; + fi->fi_flx |= FI_TCPUDP; + udp = fin->fin_dp; + + if (!fin->fin_off && (fin->fin_dlen > 3)) { + fin->fin_sport = ntohs(udp->uh_sport); + fin->fin_dport = ntohs(udp->uh_dport); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_tcp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Analyse the packet for IPv4/TCP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_tcp(fin) +fr_info_t *fin; +{ + + fr_checkv4sum(fin); + + frpr_short(fin, sizeof(struct tcphdr)); + + frpr_tcpcommon(fin); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_udp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Analyse the packet for IPv4/UDP properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_udp(fin) +fr_info_t *fin; +{ + + fr_checkv4sum(fin); + + frpr_short(fin, sizeof(struct udphdr)); + + frpr_udpcommon(fin); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_esp */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Analyse the packet for ESP properties. */ +/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ +/* even though the newer ESP packets must also have a sequence number that */ +/* is 32bits as well, it is not possible(?) to determine the version from a */ +/* simple packet header. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_esp(fin) +fr_info_t *fin; +{ + + frpr_short(fin, 8); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_gre */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Analyse the packet for GRE properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_gre(fin) +fr_info_t *fin; +{ + + frpr_short(fin, sizeof(grehdr_t)); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_ipv4hdr */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv4 Only */ +/* Analyze the IPv4 header and set fields in the fr_info_t structure. */ +/* Check all options present and flag their presence if any exist. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_ipv4hdr(fin) fr_info_t *fin; { u_short optmsk = 0, secmsk = 0, auth = 0; - int i, mv, ol, off, p, plen, v; - fr_ip_t *fi = &fin->fin_fi; - const struct optlist *op; + int hlen, ol, mv, p, i; + struct optlist *op; u_char *s, opt; - tcphdr_t *tcp; + u_short off; + fr_ip_t *fi; + ip_t *ip; - fin->fin_rev = 0; - fin->fin_fr = NULL; - fin->fin_tcpf = 0; - fin->fin_data[0] = 0; - fin->fin_data[1] = 0; - fin->fin_rule = -1; - fin->fin_group = -1; - fin->fin_icode = ipl_unreach; - v = fin->fin_v; - fi->fi_v = v; - fin->fin_hlen = hlen; - if (v == 4) { - fin->fin_id = ip->ip_id; - fi->fi_tos = ip->ip_tos; - off = (ip->ip_off & IP_OFFMASK); - tcp = (tcphdr_t *)((char *)ip + hlen); - (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); - fi->fi_src.i6[1] = 0; - fi->fi_src.i6[2] = 0; - fi->fi_src.i6[3] = 0; - fi->fi_dst.i6[1] = 0; - fi->fi_dst.i6[2] = 0; - fi->fi_dst.i6[3] = 0; - fi->fi_saddr = ip->ip_src.s_addr; - fi->fi_daddr = ip->ip_dst.s_addr; - p = ip->ip_p; - fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; - if (ip->ip_off & (IP_MF|IP_OFFMASK)) - fi->fi_fl |= FI_FRAG; - plen = ip->ip_len; - fin->fin_dlen = plen - hlen; - } -#ifdef USE_INET6 - else if (v == 6) { - ip6_t *ip6 = (ip6_t *)ip; + fi = &fin->fin_fi; + hlen = fin->fin_hlen; - off = 0; - p = ip6->ip6_nxt; - fi->fi_p = p; - fi->fi_ttl = ip6->ip6_hlim; - tcp = (tcphdr_t *)(ip6 + 1); - fi->fi_src.in6 = ip6->ip6_src; - fi->fi_dst.in6 = ip6->ip6_dst; - fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff); - fi->fi_tos = 0; - fi->fi_fl = 0; - plen = ntohs(ip6->ip6_plen); - fin->fin_dlen = plen; - plen += sizeof(*ip6); - } + ip = fin->fin_ip; + p = ip->ip_p; + fi->fi_p = p; + fi->fi_tos = ip->ip_tos; + fin->fin_id = ip->ip_id; + off = ip->ip_off; + + /* Get both TTL and protocol */ + fi->fi_p = ip->ip_p; + fi->fi_ttl = ip->ip_ttl; +#if 0 + (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); #endif - else - return; + /* Zero out bits not used in IPv6 address */ + fi->fi_src.i6[1] = 0; + fi->fi_src.i6[2] = 0; + fi->fi_src.i6[3] = 0; + fi->fi_dst.i6[1] = 0; + fi->fi_dst.i6[2] = 0; + fi->fi_dst.i6[3] = 0; + + fi->fi_saddr = ip->ip_src.s_addr; + fi->fi_daddr = ip->ip_dst.s_addr; + + /* + * set packet attribute flags based on the offset and + * calculate the byte offset that it represents. + */ + if ((off & IP_MF) != 0) { + fi->fi_flx |= FI_FRAG; + if (fin->fin_dlen == 0) + fi->fi_flx |= FI_BAD; + } + + off &= IP_MF|IP_OFFMASK; + if (off != 0) { + fi->fi_flx |= FI_FRAG; + if ((off & IP_MF) == 0) + fi->fi_flx |= FI_FRAGTAIL; + off &= IP_OFFMASK; + if (off != 0) { + off <<= 3; + if (off + fin->fin_dlen > 0xffff) + fi->fi_flx |= FI_BAD; + } + } fin->fin_off = off; - fin->fin_plen = plen; - fin->fin_dp = (char *)tcp; - fin->fin_misc = 0; - off <<= 3; + /* + * Call per-protocol setup and checking + */ switch (p) { -#ifdef USE_INET6 - case IPPROTO_ICMPV6 : - { - int minicmpsz = sizeof(struct icmp6_hdr); - struct icmp6_hdr *icmp6; - - if (fin->fin_dlen > 1) { - fin->fin_data[0] = *(u_short *)tcp; - - icmp6 = (struct icmp6_hdr *)tcp; - - switch (icmp6->icmp6_type) - { - case ICMP6_ECHO_REPLY : - case ICMP6_ECHO_REQUEST : - minicmpsz = ICMP6_MINLEN; - break; - case ICMP6_DST_UNREACH : - case ICMP6_PACKET_TOO_BIG : - case ICMP6_TIME_EXCEEDED : - case ICMP6_PARAM_PROB : - minicmpsz = ICMP6ERR_IPICMPHLEN; - break; - default : - break; - } - } - - if (!(plen >= minicmpsz)) - fi->fi_fl |= FI_SHORT; - - break; - } -#endif - case IPPROTO_ICMP : - { - int minicmpsz = sizeof(struct icmp); - icmphdr_t *icmp; - - if (!off && (fin->fin_dlen > 1)) { - fin->fin_data[0] = *(u_short *)tcp; - - icmp = (icmphdr_t *)tcp; - - switch (icmp->icmp_type) - { - case ICMP_ECHOREPLY : - case ICMP_ECHO : - /* Router discovery messages - RFC 1256 */ - case ICMP_ROUTERADVERT : - case ICMP_ROUTERSOLICIT : - minicmpsz = ICMP_MINLEN; - break; - /* - * type(1) + code(1) + cksum(2) + id(2) seq(2) + - * 3*timestamp(3*4) - */ - case ICMP_TSTAMP : - case ICMP_TSTAMPREPLY : - minicmpsz = 20; - break; - /* - * type(1) + code(1) + cksum(2) + id(2) seq(2) + - * mask(4) - */ - case ICMP_MASKREQ : - case ICMP_MASKREPLY : - minicmpsz = 12; - break; - default : - break; - } - } - - if ((!(plen >= hlen + minicmpsz) && !off) || - (off && off < sizeof(struct icmp))) - fi->fi_fl |= FI_SHORT; - - break; - } - case IPPROTO_TCP : - fi->fi_fl |= FI_TCPUDP; -#ifdef USE_INET6 - if (v == 6) { - if (plen < sizeof(struct tcphdr)) - fi->fi_fl |= FI_SHORT; - } else -#endif - if (v == 4) { - if ((!IPMINLEN(ip, tcphdr) && !off) || - (off && off < sizeof(struct tcphdr))) - fi->fi_fl |= FI_SHORT; - } - if (!(fi->fi_fl & FI_SHORT) && !off) - fin->fin_tcpf = tcp->th_flags; - goto getports; case IPPROTO_UDP : - fi->fi_fl |= FI_TCPUDP; -#ifdef USE_INET6 - if (v == 6) { - if (plen < sizeof(struct udphdr)) - fi->fi_fl |= FI_SHORT; - } else -#endif - if (v == 4) { - if ((!IPMINLEN(ip, udphdr) && !off) || - (off && off < sizeof(struct udphdr))) - fi->fi_fl |= FI_SHORT; - } -getports: - if (!off && (fin->fin_dlen > 3)) { - fin->fin_data[0] = ntohs(tcp->th_sport); - fin->fin_data[1] = ntohs(tcp->th_dport); - } + frpr_udp(fin); + break; + case IPPROTO_TCP : + frpr_tcp(fin); + break; + case IPPROTO_ICMP : + frpr_icmp(fin); break; case IPPROTO_ESP : -#ifdef USE_INET6 - if (v == 6) { - if (plen < 8) - fi->fi_fl |= FI_SHORT; - } else -#endif - if (v == 4) { - if (((ip->ip_len < hlen + 8) && !off) || - (off && off < 8)) - fi->fi_fl |= FI_SHORT; - } + frpr_esp(fin); break; - default : + case IPPROTO_GRE : + frpr_gre(fin); break; } -#ifdef USE_INET6 - if (v == 6) { + ip = fin->fin_ip; + if (ip == NULL) + return; + + /* + * If it is a standard IP header (no options), set the flag fields + * which relate to options to 0. + */ + if (hlen == sizeof(*ip)) { fi->fi_optmsk = 0; fi->fi_secmsk = 0; fi->fi_auth = 0; return; } -#endif + + /* + * So the IP header has some IP options attached. Walk the entire + * list of options present with this packet and set flags to indicate + * which ones are here and which ones are not. For the somewhat out + * of date and obscure security classification options, set a flag to + * represent which classification is present. + */ + fi->fi_flx |= FI_OPTIONS; for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { opt = *s; @@ -429,10 +1237,10 @@ getports: } for (i = 9, mv = 4; mv >= 0; ) { op = ipopts + i; - if (opt == (u_char)op->ol_val) { + if ((opt == (u_char)op->ol_val) && (ol > 4)) { optmsk |= op->ol_bit; if (opt == IPOPT_SECURITY) { - const struct optlist *sp; + struct optlist *sp; u_char sec; int j, m; @@ -447,21 +1255,27 @@ getports: break; } if (sec < sp->ol_val) - j -= m--; + j -= m; else - j += m--; + j += m; + m--; } } break; } if (opt < op->ol_val) - i -= mv--; + i -= mv; else - i += mv--; + i += mv; + mv--; } hlen -= ol; s += ol; } + + /* + * + */ if (auth && !(auth & 0x0100)) auth &= 0xff00; fi->fi_optmsk = optmsk; @@ -470,16 +1284,130 @@ getports: } -/* - * check an IP packet for TCP/UDP characteristics such as ports and flags. - */ -int fr_tcpudpchk(ft, fin) -frtuc_t *ft; +/* ------------------------------------------------------------------------ */ +/* Function: fr_makefrip */ +/* Returns: void */ +/* Parameters: hlen(I) - length of IP packet header */ +/* ip(I) - pointer to the IP header */ +/* fin(IO) - pointer to packet information */ +/* */ +/* Compact the IP header into a structure which contains just the info. */ +/* which is useful for comparing IP headers with and store this information */ +/* in the fr_info_t structure pointer to by fin. At present, it is assumed */ +/* this function will be called with either an IPv4 or IPv6 packet. */ +/* ------------------------------------------------------------------------ */ +int fr_makefrip(hlen, ip, fin) +int hlen; +ip_t *ip; fr_info_t *fin; { - register u_short po, tup; - register char i; - register int err = 1; + int v; + + fin->fin_nat = NULL; + fin->fin_state = NULL; + fin->fin_depth = 0; + fin->fin_hlen = (u_short)hlen; + fin->fin_ip = ip; + fin->fin_rule = 0xffffffff; + fin->fin_group[0] = -1; + fin->fin_group[1] = '\0'; + fin->fin_dlen = fin->fin_plen - hlen; + fin->fin_dp = (char *)ip + hlen; + + v = fin->fin_v; + if (v == 4) + frpr_ipv4hdr(fin); +#ifdef USE_INET6 + else if (v == 6) + frpr_ipv6hdr(fin); +#endif + if (fin->fin_ip == NULL) + return -1; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_portcheck */ +/* Returns: int - 1 == port matched, 0 == port match failed */ +/* Parameters: frp(I) - pointer to port check `expression' */ +/* pop(I) - pointer to port number to evaluate */ +/* */ +/* Perform a comparison of a port number against some other(s), using a */ +/* structure with compare information stored in it. */ +/* ------------------------------------------------------------------------ */ +static INLINE int fr_portcheck(frp, pop) +frpcmp_t *frp; +u_short *pop; +{ + u_short tup, po; + int err = 1; + + tup = *pop; + po = frp->frp_port; + + /* + * Do opposite test to that required and continue if that succeeds. + */ + switch (frp->frp_cmp) + { + case FR_EQUAL : + if (tup != po) /* EQUAL */ + err = 0; + break; + case FR_NEQUAL : + if (tup == po) /* NOTEQUAL */ + err = 0; + break; + case FR_LESST : + if (tup >= po) /* LESSTHAN */ + err = 0; + break; + case FR_GREATERT : + if (tup <= po) /* GREATERTHAN */ + err = 0; + break; + case FR_LESSTE : + if (tup > po) /* LT or EQ */ + err = 0; + break; + case FR_GREATERTE : + if (tup < po) /* GT or EQ */ + err = 0; + break; + case FR_OUTRANGE : + if (tup >= po && tup <= frp->frp_top) /* Out of range */ + err = 0; + break; + case FR_INRANGE : + if (tup <= po || tup >= frp->frp_top) /* In range */ + err = 0; + break; + case FR_INCRANGE : + if (tup < po || tup > frp->frp_top) /* Inclusive range */ + err = 0; + break; + default : + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpudpchk */ +/* Returns: int - 1 == protocol matched, 0 == check failed */ +/* Parameters: fin(I) - pointer to packet information */ +/* ft(I) - pointer to structure with comparison data */ +/* */ +/* Compares the current pcket (assuming it is TCP/UDP) information with a */ +/* structure containing information that we want to match against. */ +/* ------------------------------------------------------------------------ */ +int fr_tcpudpchk(fin, ft) +fr_info_t *fin; +frtuc_t *ft; +{ + int err = 1; /* * Both ports should *always* be in the first fragment. @@ -487,57 +1415,14 @@ fr_info_t *fin; * * compare destination ports */ - if ((i = (int)ft->ftu_dcmp)) { - po = ft->ftu_dport; - tup = fin->fin_data[1]; - /* - * 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 <= ft->ftu_dtop)) - err = 0; - else if (!--i && /* In range */ - (tup <= po || tup >= ft->ftu_dtop)) - err = 0; - } + if (ft->ftu_dcmp) + err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport); + /* * compare source ports */ - if (err && (i = (int)ft->ftu_scmp)) { - po = ft->ftu_sport; - tup = fin->fin_data[0]; - 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 <= ft->ftu_stop)) - err = 0; - else if (!--i && /* In range */ - (tup <= po || tup >= ft->ftu_stop)) - err = 0; - } + if (err && ft->ftu_scmp) + err = fr_portcheck(&ft->ftu_src, &fin->fin_sport); /* * If we don't have all the TCP/UDP header, then how can we @@ -545,8 +1430,8 @@ fr_info_t *fin; * TCP flags, then NO match. If not, then match (which should * satisfy the "short" class too). */ - if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { - if (fin->fin_fl & FI_SHORT) + if (err && (fin->fin_p == IPPROTO_TCP)) { + if (fin->fin_flx & FI_SHORT) return !(ft->ftu_tcpf | ft->ftu_tcpfm); /* * Match the flags ? If not, abort this match. @@ -561,38 +1446,246 @@ fr_info_t *fin; 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(passin, ip, fin, m) -u_32_t passin; -ip_t *ip; -register fr_info_t *fin; -void *m; -{ - register struct frentry *fr; - register fr_ip_t *fi = &fin->fin_fi; - int rulen, portcmp = 0, off, skip = 0, logged = 0; - u_32_t pass, passt, passl; - frentry_t *frl; - frl = NULL; - pass = passin; +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipfcheck */ +/* Returns: int - 0 == match, 1 == no match */ +/* Parameters: fin(I) - pointer to packet information */ +/* fr(I) - pointer to filter rule */ +/* portcmp(I) - flag indicating whether to attempt matching on */ +/* TCP/UDP port data. */ +/* */ +/* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ +/* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ +/* this function. */ +/* ------------------------------------------------------------------------ */ +static INLINE int fr_ipfcheck(fin, fr, portcmp) +fr_info_t *fin; +frentry_t *fr; +int portcmp; +{ + u_32_t *ld, *lm, *lip; + fripf_t *fri; + fr_ip_t *fi; + int i; + + fi = &fin->fin_fi; + fri = fr->fr_ipf; + lip = (u_32_t *)fi; + lm = (u_32_t *)&fri->fri_mip; + ld = (u_32_t *)&fri->fri_ip; + + /* + * first 32 bits to check coversion: + * IP version, TOS, TTL, protocol + */ + i = ((*lip & *lm) != *ld); + FR_DEBUG(("0. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + return 1; + + /* + * Next 32 bits is a constructed bitmask indicating which IP options + * are present (if any) in this packet. + */ + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("1. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + return 1; + + lip++, lm++, ld++; + /* + * Unrolled loops (4 each, for 32 bits) for address checks. + */ + /* + * Check the source address. + */ +#ifdef IPFILTER_LOOKUP + if (fr->fr_satype == FRI_LOOKUP) { + i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip); + if (i == -1) + return 1; + lip += 3; + lm += 3; + ld += 3; + } else { +#endif + i = ((*lip & *lm) != *ld); + FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } +#ifdef IPFILTER_LOOKUP + } +#endif + i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; + if (i) + return 1; + + /* + * Check the destination address. + */ + lip++, lm++, ld++; +#ifdef IPFILTER_LOOKUP + if (fr->fr_datype == FRI_LOOKUP) { + i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip); + if (i == -1) + return 1; + lip += 3; + lm += 3; + ld += 3; + } else { +#endif + i = ((*lip & *lm) != *ld); + FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } +#ifdef IPFILTER_LOOKUP + } +#endif + i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; + if (i) + return 1; + /* + * IP addresses matched. The next 32bits contains: + * mast of old IP header security & authentication bits. + */ + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("4. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + + /* + * Next we have 32 bits of packet flags. + */ + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("5. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + + if (i == 0) { + /* + * If a fragment, then only the first has what we're + * looking for here... + */ + if (portcmp) { + if (!fr_tcpudpchk(fin, &fr->fr_tuc)) + i = 1; + } else { + if (fr->fr_dcmp || fr->fr_scmp || + fr->fr_tcpf || fr->fr_tcpfm) + i = 1; + if (fr->fr_icmpm || fr->fr_icmp) { + if (((fi->fi_p != IPPROTO_ICMP) && + (fi->fi_p != IPPROTO_ICMPV6)) || + fin->fin_off || (fin->fin_dlen < 2)) + i = 1; + else if ((fin->fin_data[0] & fr->fr_icmpm) != + fr->fr_icmp) { + FR_DEBUG(("i. %#x & %#x != %#x\n", + fin->fin_data[0], + fr->fr_icmpm, fr->fr_icmp)); + i = 1; + } + } + } + } + return i; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_scanlist */ +/* Returns: int - result flags of scanning filter list */ +/* Parameters: fin(I) - pointer to packet information */ +/* pass(I) - default result to return for filtering */ +/* */ +/* Check the input/output list of rules for a match to the current packet. */ +/* If a match is found, the value of fr_flags from the rule becomes the */ +/* return value and fin->fin_fr points to the matched rule. */ +/* */ +/* This function may be called recusively upto 16 times (limit inbuilt.) */ +/* When unwinding, it should finish up with fin_depth as 0. */ +/* */ +/* Could be per interface, but this gets real nasty when you don't have, */ +/* or can't easily change, the kernel source code to . */ +/* ------------------------------------------------------------------------ */ +int fr_scanlist(fin, pass) +fr_info_t *fin; +u_32_t pass; +{ + int rulen, portcmp, off, logged, skip; + struct frentry *fr, *fnext; + u_32_t passt; + + /* + * Do not allow nesting deeper than 16 levels. + */ + if (fin->fin_depth >= 16) + return pass; + fr = fin->fin_fr; + + /* + * If there are no rules in this list, return now. + */ + if (fr == NULL) + return pass; + + skip = 0; + logged = 0; + portcmp = 0; + fin->fin_depth++; fin->fin_fr = NULL; off = fin->fin_off; - if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) + if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) portcmp = 1; - for (rulen = 0; fr; fr = fr->fr_next, rulen++) { - if (skip) { + for (rulen = 0; fr; fr = fnext, rulen++) { + fnext = fr->fr_next; + if (skip != 0) { FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags)); skip--; continue; } + /* * In all checks below, a null (zero) value in the * filter struture is taken to mean a wildcard. @@ -600,197 +1693,363 @@ void *m; * check that we are working for the right interface */ #ifdef _KERNEL -# if (BSD >= 199306) - if (fin->fin_out != 0) { - if ((fr->fr_oifa && - (fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif))) - continue; - } -# endif + if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) + continue; #else if (opts & (OPT_VERBOSE|OPT_DEBUG)) printf("\n"); -#endif - - FR_VERBOSE(("%c", fr->fr_skip ? 's' : - (pass & FR_PASS) ? 'p' : - (pass & FR_AUTH) ? 'a' : - (pass & FR_ACCOUNT) ? 'A' : - (pass & FR_NOMATCH) ? 'n' : 'b')); - + FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : + FR_ISPASS(pass) ? 'p' : + FR_ISACCOUNT(pass) ? 'A' : + FR_ISAUTH(pass) ? 'a' : + (pass & FR_NOMATCH) ? 'n' :'b')); if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) continue; - FR_VERBOSE((":i")); - { - register u_32_t *ld, *lm, *lip; - register int i; +#endif - lip = (u_32_t *)fi; - lm = (u_32_t *)&fr->fr_mip; - ld = (u_32_t *)&fr->fr_ip; - i = ((*lip & *lm) != *ld); - FR_DEBUG(("0. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - if (i) + switch (fr->fr_type) + { + case FR_T_IPF : + case FR_T_IPF|FR_T_BUILTIN : + if (fr_ipfcheck(fin, fr, portcmp)) continue; - /* - * We now know whether the packet version and the - * rule version match, along with protocol, ttl and - * tos. - */ - lip++, lm++, ld++; - /* - * Unrolled loops (4 each, for 32 bits). - */ - FR_DEBUG(("1a. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - if (fi->fi_v == 6) { - FR_DEBUG(("1b. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - FR_DEBUG(("1c. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - FR_DEBUG(("1d. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 5; - } else { - lip += 3; - lm += 3; - ld += 3; - } - i ^= (fr->fr_flags & FR_NOTSRCIP); - if (i) + break; +#if defined(IPFILTER_BPF) + case FR_T_BPFOPC : + case FR_T_BPFOPC|FR_T_BUILTIN : + { + u_char *mc; + int wlen; + + if (*fin->fin_mp == NULL) continue; - FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - if (fi->fi_v == 6) { - FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++) << 6; - } else { - lip += 3; - lm += 3; - ld += 3; - } - i ^= (fr->fr_flags & FR_NOTDSTIP); - if (i) + if (fin->fin_v != fr->fr_v) continue; - FR_DEBUG(("3. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip++ & *lm++) != *ld++); - FR_DEBUG(("4. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); - i |= ((*lip & *lm) != *ld); - if (i) + mc = (u_char *)fin->fin_m; + wlen = fin->fin_dlen + fin->fin_hlen; + if (!bpf_filter(fr->fr_data, mc, wlen, 0)) + continue; + break; + } +#endif + case FR_T_CALLFUNC|FR_T_BUILTIN : + { + frentry_t *f; + + f = (*fr->fr_func)(fin, &pass); + if (f != NULL) + fr = f; + else + continue; + break; + } + default : + break; + } + + if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { + if (fin->fin_nattag == NULL) + continue; + if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) continue; } + FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen)); + + passt = fr->fr_flags; /* - * If a fragment, then only the first has what we're looking - * for here... + * If the rule is a "call now" rule, then call the function + * in the rule, if it exists and use the results from that. + * If the function pointer is bad, just make like we ignore + * it, except for increasing the hit counter. */ - if (!portcmp && (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf || - fr->fr_tcpfm)) - continue; - if (fi->fi_fl & FI_TCPUDP) { - if (!fr_tcpudpchk(&fr->fr_tuc, fin)) - continue; - } else if (fr->fr_icmpm || fr->fr_icmp) { - if ((fi->fi_p != IPPROTO_ICMP) || off || - (fin->fin_dlen < 2)) - continue; - if ((fin->fin_data[0] & fr->fr_icmpm) != fr->fr_icmp) { - FR_DEBUG(("i. %#x & %#x != %#x\n", - fin->fin_data[0], fr->fr_icmpm, - fr->fr_icmp)); - continue; + if ((passt & FR_CALLNOW) != 0) { + ATOMIC_INCL(fr->fr_hits); + if ((fr->fr_func != NULL) && + (fr->fr_func != (ipfunc_t)-1)) { + frentry_t *frs; + + frs = fin->fin_fr; + fin->fin_fr = fr; + fr = (*fr->fr_func)(fin, &passt); + if (fr == NULL) { + fin->fin_fr = frs; + continue; + } + passt = fr->fr_flags; + fin->fin_fr = fr; } - } - FR_VERBOSE(("*")); - - if (fr->fr_flags & FR_NOMATCH) { - passt = passl; - passl = passin; - fin->fin_fr = frl; - frl = NULL; - if (fr->fr_flags & FR_QUICK) - break; - continue; + } else { + fin->fin_fr = fr; } - passl = passt; - passt = fr->fr_flags; - frl = fin->fin_fr; - fin->fin_fr = fr; -#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL)) - if (securelevel <= 0) -#endif - if ((passt & FR_CALLNOW) && fr->fr_func) - passt = (*fr->fr_func)(passt, ip, fin); #ifdef IPFILTER_LOG /* * Just log this packet... */ if ((passt & FR_LOGMASK) == FR_LOG) { - if (!IPLLOG(passt, ip, fin, m)) { - if (passt & FR_LOGORBLOCK) + if (ipflog(fin, passt) == -1) { + if (passt & FR_LOGORBLOCK) { + passt &= ~FR_CMDMASK; passt |= FR_BLOCK|FR_QUICK; + } ATOMIC_INCL(frstats[fin->fin_out].fr_skip); } ATOMIC_INCL(frstats[fin->fin_out].fr_pkl); logged = 1; } #endif /* IPFILTER_LOG */ - ATOMIC_INCL(fr->fr_hits); - if (passt & FR_ACCOUNT) - fr->fr_bytes += (U_QUAD_T)ip->ip_len; - else + fr->fr_bytes += (U_QUAD_T)fin->fin_plen; + if (FR_ISSKIP(passt)) + skip = fr->fr_arg; + else if ((passt & FR_LOGMASK) != FR_LOG) + pass = passt; + if (passt & (FR_RETICMP|FR_FAKEICMP)) fin->fin_icode = fr->fr_icode; + FR_DEBUG(("pass %#x\n", pass)); + ATOMIC_INCL(fr->fr_hits); fin->fin_rule = rulen; - fin->fin_group = fr->fr_group; + (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN); if (fr->fr_grp != NULL) { - fin->fin_fr = fr->fr_grp; - passt = fr_scanlist(passt, ip, fin, m); + fin->fin_fr = *fr->fr_grp; + pass = fr_scanlist(fin, pass); if (fin->fin_fr == NULL) { fin->fin_rule = rulen; - fin->fin_group = fr->fr_group; + (void) strncpy(fin->fin_group, fr->fr_group, + FR_GROUPLEN); fin->fin_fr = fr; } - if (passt & FR_DONTCACHE) + if (fin->fin_flx & FI_DONTCACHE) logged = 1; } - if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG) - pass = passt; - FR_DEBUG(("pass %#x\n", pass)); - if (passt & FR_QUICK) + if (pass & FR_QUICK) break; } if (logged) - pass |= FR_DONTCACHE; - pass |= (fi->fi_fl << 24); + fin->fin_flx |= FI_DONTCACHE; + fin->fin_depth--; return pass; } -/* - * frcheck - filter check - * check using source and destination addresses/ports in a packet whether - * or not to pass it on or not. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_acctpkt */ +/* Returns: frentry_t* - always returns NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Checks a packet against accounting rules, if there are any for the given */ +/* IP protocol version. */ +/* */ +/* N.B.: this function returns NULL to match the prototype used by other */ +/* functions called from the IPFilter "mainline" in fr_check(). */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_acctpkt(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + char group[FR_GROUPLEN]; + frentry_t *fr, *frsave; + u_32_t pass, rulen; + + passp = passp; +#ifdef USE_INET6 + if (fin->fin_v == 6) + fr = ipacct6[fin->fin_out][fr_active]; + else +#endif + fr = ipacct[fin->fin_out][fr_active]; + + if (fr != NULL) { + frsave = fin->fin_fr; + bcopy(fin->fin_group, group, FR_GROUPLEN); + rulen = fin->fin_rule; + fin->fin_fr = fr; + pass = fr_scanlist(fin, FR_NOMATCH); + if (FR_ISACCOUNT(pass)) { + ATOMIC_INCL(frstats[0].fr_acct); + } + fin->fin_fr = frsave; + bcopy(group, fin->fin_group, FR_GROUPLEN); + fin->fin_rule = rulen; + } + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_firewall */ +/* Returns: frentry_t* - returns pointer to matched rule, if no matches */ +/* were found, returns NULL. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Applies an appropriate set of firewall rules to the packet, to see if */ +/* there are any matches. The first check is to see if a match can be seen */ +/* in the cache. If not, then search an appropriate list of rules. Once a */ +/* matching rule is found, take any appropriate actions as defined by the */ +/* rule - except logging. */ +/* ------------------------------------------------------------------------ */ +static frentry_t *fr_firewall(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + frentry_t *fr; + fr_info_t *fc; + u_32_t pass; + int out; + + out = fin->fin_out; + pass = *passp; + + /* + * If a packet is found in the auth table, then skip checking + * the access lists for permission but we do need to consider + * the result as if it were from the ACL's. + */ + fc = &frcache[out][CACHE_HASH(fin)]; + if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { + /* + * copy cached data so we can unlock the mutex + * earlier. + */ + bcopy((char *)fc, (char *)fin, FI_COPYSIZE); + ATOMIC_INCL(frstats[out].fr_chit); + if ((fr = fin->fin_fr) != NULL) { + ATOMIC_INCL(fr->fr_hits); + pass = fr->fr_flags; + } + } else { +#ifdef USE_INET6 + if (fin->fin_v == 6) + fin->fin_fr = ipfilter6[out][fr_active]; + else +#endif + fin->fin_fr = ipfilter[out][fr_active]; + if (fin->fin_fr != NULL) + pass = fr_scanlist(fin, fr_pass); + if (((pass & FR_KEEPSTATE) == 0) && + ((fin->fin_flx & FI_DONTCACHE) == 0)) + bcopy((char *)fin, (char *)fc, FI_COPYSIZE); + if ((pass & FR_NOMATCH)) { + ATOMIC_INCL(frstats[out].fr_nom); + } + fr = fin->fin_fr; + } + + /* + * Apply packets per second rate-limiting to a rule as required. + */ + if ((fr != NULL) && (fr->fr_pps != 0) && + !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { + pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST); + pass |= FR_BLOCK; + ATOMIC_INCL(frstats[out].fr_ppshit); + } + + /* + * If we fail to add a packet to the authorization queue, then we + * drop the packet later. However, if it was added then pretend + * we've dropped it already. + */ + if (FR_ISAUTH(pass)) { + if (fr_newauth(fin->fin_m, fin) != 0) { +#ifdef _KERNEL + fin->fin_m = *fin->fin_mp = NULL; +#else + ; +#endif + fin->fin_error = 0; + } else + fin->fin_error = ENOSPC; + } + + if ((fr != NULL) && (fr->fr_func != NULL) && + (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) + (void) (*fr->fr_func)(fin, &pass); + + /* + * If a rule is a pre-auth rule, check again in the list of rules + * loaded for authenticated use. It does not particulary matter + * if this search fails because a "preauth" result, from a rule, + * is treated as "not a pass", hence the packet is blocked. + */ + if (FR_ISPREAUTH(pass)) { + if ((fin->fin_fr = ipauth) != NULL) + pass = fr_scanlist(fin, fr_pass); + } + + /* + * If the rule has "keep frag" and the packet is actually a fragment, + * then create a fragment state entry. + */ + if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { + if (fin->fin_flx & FI_FRAG) { + if (fr_newfrag(fin, pass) == -1) { + ATOMIC_INCL(frstats[out].fr_bnfr); + } else { + ATOMIC_INCL(frstats[out].fr_nfr); + } + } else { + ATOMIC_INCL(frstats[out].fr_cfr); + } + } + + /* + * Finally, if we've asked to track state for this packet, set it up. + */ + if (pass & FR_KEEPSTATE) { + if (fr_addstate(fin, NULL, 0) != NULL) { + ATOMIC_INCL(frstats[out].fr_ads); + } else { + ATOMIC_INCL(frstats[out].fr_bads); + } + } + + fr = fin->fin_fr; + + if (passp != NULL) + *passp = pass; + + return fr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_check */ +/* Returns: int - 0 == packet allowed through, */ +/* User space: */ +/* -1 == packet blocked */ +/* 1 == packet not matched */ +/* -2 == requires authantication */ +/* Kernel: */ +/* > 0 == filter error # for packet */ +/* Parameters: ip(I) - pointer to start of IPv4/6 packet */ +/* hlen(I) - length of header */ +/* ifp(I) - pointer to interface this packet is on */ +/* out(I) - 0 == packet going in, 1 == packet going out */ +/* mp(IO) - pointer to caller's buffer pointer that holds this */ +/* IP packet. */ +/* Solaris & HP-UX ONLY : */ +/* qpi(I) - pointer to STREAMS queue information for this */ +/* interface & direction. */ +/* */ +/* fr_check() is the master function for all IPFilter packet processing. */ +/* It orchestrates: Network Address Translation (NAT), checking for packet */ +/* authorisation (or pre-authorisation), presence of related state info., */ +/* generating log entries, IP packet accounting, routing of packets as */ +/* directed by firewall rules and of course whether or not to allow the */ +/* packet to be further processed by the kernel. */ +/* */ +/* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ +/* freed. Packets passed may be returned with the pointer pointed to by */ +/* by "mp" changed to a new buffer. */ +/* ------------------------------------------------------------------------ */ int fr_check(ip, hlen, ifp, out -#if defined(_KERNEL) && SOLARIS +#if defined(_KERNEL) && defined(MENTAT) , qif, mp) -qif_t *qif; +void *qif; #else , mp) #endif @@ -803,24 +2062,60 @@ int out; /* * The above really sucks, but short of writing a diff */ - fr_info_t frinfo, *fc; - register fr_info_t *fin = &frinfo; - int changed, error = EHOSTUNREACH, v = ip->ip_v; - frentry_t *fr = NULL, *list; - u_32_t pass, apass; -#if !SOLARIS || !defined(_KERNEL) - register mb_t *m = *mp; -#endif - -#ifdef _KERNEL - int p, len, drop = 0, logit = 0; + fr_info_t frinfo; + fr_info_t *fin = &frinfo; + int v = IP_V(ip), len, p; + frentry_t *fr = NULL; mb_t *mc = NULL; -# if !defined(__SVR4) && !defined(__svr4__) -# ifdef __sgi - char hbuf[128]; -# endif - int up; + u_32_t pass; + mb_t *m; + /* + * The first part of fr_check() deals with making sure that what goes + * into the filtering engine makes some sense. Information about the + * the packet is distilled, collected into a fr_info_t structure and + * the an attempt to ensure the buffer the packet is in is big enough + * to hold all the required packet headers. + */ +#ifdef _KERNEL +# ifdef __sgi + char hbuf[MAX_IPV4HDR]; +# endif + int up = 0; +# ifdef MENTAT + qpktinfo_t *qpi = qif; + + if ((u_int)ip & 0x3) + return 2; +# endif + + READ_ENTER(&ipf_global); + + if (fr_running <= 0) { + RWLOCK_EXIT(&ipf_global); + return 0; + } + + bzero((char *)fin, sizeof(*fin)); + +# ifdef MENTAT + if (qpi->qpi_flags & QF_GROUP) + fin->fin_flx |= FI_MBCAST; + m = qpi->qpi_m; + fin->fin_qfm = m; + fin->fin_qpi = qpi; +# else /* MENTAT */ + + m = *mp; + +# if defined(M_MCAST) + if ((m->m_flags & M_MCAST) != 0) + fin->fin_flx |= FI_MBCAST|FI_MULTICAST; +# endif +# if defined(M_BCAST) + if ((m->m_flags & M_BCAST) != 0) + fin->fin_flx |= FI_MBCAST|FI_BROADCAST; +# endif # ifdef M_CANFASTFWD /* * XXX For now, IP Filter and fast-forwarding of cached flows @@ -833,35 +2128,63 @@ int out; /* * disable delayed checksums. */ - if ((out != 0) && (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)) { + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { in_delayed_cksum(m); m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } # endif /* CSUM_DELAY_DATA */ +# endif /* MENTAT */ +#else + READ_ENTER(&ipf_global); -# ifdef USE_INET6 + bzero((char *)fin, sizeof(*fin)); + m = *mp; +#endif /* _KERNEL */ + +#ifdef USE_INET6 if (v == 6) { len = ntohs(((ip6_t*)ip)->ip6_plen); - if (!len) - return -1; /* potential jumbo gram */ + /* + * Jumbo grams are quite likely too big for internal buffer + * structures to handle comfortably, for now, so just drop + * them for now. + */ + if (len == 0) { + pass = FR_BLOCK|FR_NOMATCH; + goto filtered; + } len += sizeof(ip6_t); p = ((ip6_t *)ip)->ip6_nxt; } else -# endif +#endif { p = ip->ip_p; +#if OpenBSD >= 200311 + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); +#endif len = ip->ip_len; } - if ((p == IPPROTO_TCP || p == IPPROTO_UDP || + fin->fin_v = v; + fin->fin_m = m; + fin->fin_mp = mp; + fin->fin_out = out; + fin->fin_ifp = ifp; + fin->fin_plen = len; + fin->fin_hlen = (u_short )hlen; + fin->fin_dp = (char *)ip + hlen; + + if (p == IPPROTO_TCP || p == IPPROTO_UDP || (v == 4 && p == IPPROTO_ICMP) -# ifdef USE_INET6 +#ifdef USE_INET6 || (v == 6 && p == IPPROTO_ICMPV6) -# endif - )) { +#endif + ) { +#if defined(_KERNEL) int plen = 0; - if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0) + if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0) { switch(p) { case IPPROTO_TCP: @@ -877,109 +2200,116 @@ int out; case IPPROTO_ESP: plen = 8; break; + case IPPROTO_GRE: + plen = sizeof(grehdr_t); + break; # ifdef USE_INET6 - case IPPROTO_ICMPV6 : + case IPPROTO_ICMPV6 : /* * XXX does not take intermediate header - * into account + * into account. */ plen = ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t); break; # endif } - up = MIN(hlen + plen, len); + } - if (up > m->m_len) { -# ifdef __sgi + up = MIN(hlen + plen, len); + if (up > M_LEN(m)) { +# ifdef __sgi /* Under IRIX, avoid m_pullup as it makes ping panic */ if ((up > sizeof(hbuf)) || (m_length(m) < up)) { ATOMIC_INCL(frstats[out].fr_pull[1]); - return -1; + pass = FR_BLOCK|FR_NOMATCH; + goto filtered; } m_copydata(m, 0, up, hbuf); ATOMIC_INCL(frstats[out].fr_pull[0]); ip = (ip_t *)hbuf; -# else /* __ sgi */ -# ifndef linux - if ((*mp = m_pullup(m, up)) == 0) { - ATOMIC_INCL(frstats[out].fr_pull[1]); - return -1; - } else { - ATOMIC_INCL(frstats[out].fr_pull[0]); - m = *mp; - ip = mtod(m, ip_t *); - } -# endif /* !linux */ -# endif /* __sgi */ - } else - up = 0; - } else - up = 0; -# endif /* !defined(__SVR4) && !defined(__svr4__) */ -# if SOLARIS - mb_t *m = qif->qf_m; - - if ((u_int)ip & 0x3) - return 2; - fin->fin_qfm = m; - fin->fin_qif = qif; -# endif +# else /* __ sgi */ + /* + * Having determined that we need to pullup some data, + * try to bring as much of the packet up into a single + * buffer with the first pullup. This hopefully means + * less need for doing futher pullups. Not needed for + * Solaris because fr_precheck() does it anyway. + * + * The main potential for trouble here is if MLEN/MHLEN + * become quite small, lets say < 64 bytes...but if + * that did happen, BSD networking as a whole would be + * slow/inefficient. + */ +# ifdef MHLEN + /* + * Assume that M_PKTHDR is set and just work with what + * is left rather than check.. Should not make any + * real difference, anyway. + */ + if ((MHLEN > up) && (len > up)) + up = MIN(len, MHLEN); +# else +# ifdef MLEN + if ((MLEN > up) && (len > up)) + up = MIN(len, MLEN); +# endif /* MLEN */ +# endif /* MHLEN */ + fin->fin_ip = ip; + ip = fr_pullup(m, fin, up); + if (ip == NULL) + goto finished; +# endif /* __sgi */ + } +#else + /*EMPTY*/ #endif /* _KERNEL */ - - changed = 0; - fin->fin_ifp = ifp; - fin->fin_v = v; - fin->fin_out = out; - fin->fin_mp = mp; - fr_makefrip(hlen, ip, fin); + } + + fin->fin_error = fr_unreach; + if (fr_makefrip(hlen, ip, fin) == -1) + goto finished; + ip = fin->fin_ip; -#ifdef _KERNEL -# ifdef USE_INET6 if (v == 6) { - ATOMIC_INCL(frstats[0].fr_ipv6[out]); - if (((ip6_t *)ip)->ip6_hlim < fr_minttl) { - ATOMIC_INCL(frstats[0].fr_badttl); - if (fr_minttllog & 1) - logit = -3; - if (fr_minttllog & 2) - drop = 1; - } - } else -# endif + ATOMIC_INCL(frstats[out].fr_ipv6); + } + + /* + * For at least IPv6 packets, if a m_pullup() fails then this pointer + * becomes NULL and so we have no packet to free. + */ + if (*fin->fin_mp == NULL) + goto finished; + if (!out) { - if (fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { - ATOMIC_INCL(frstats[0].fr_badsrc); - if (fr_chksrc & 1) - drop = 1; - if (fr_chksrc & 2) - logit = -2; - } else if (ip->ip_ttl < fr_minttl) { - ATOMIC_INCL(frstats[0].fr_badttl); - if (fr_minttllog & 1) - logit = -3; - if (fr_minttllog & 2) - drop = 1; - } - } - if (drop) { -# ifdef IPFILTER_LOG - if (logit) { - fin->fin_group = logit; - pass = FR_INQUE|FR_NOMATCH|FR_LOGB; - (void) IPLLOG(pass, ip, fin, m); - } -# endif -# if !SOLARIS - m_freem(m); -# endif - return error; - } + if (v == 4) { +#ifdef _KERNEL + if (fr_chksrc && !fr_verifysrc(fin)) { + ATOMIC_INCL(frstats[0].fr_badsrc); + fin->fin_flx |= FI_BADSRC; + } #endif - pass = fr_pass; - if (fin->fin_fl & FI_SHORT) { + if (ip->ip_ttl < fr_minttl) { + ATOMIC_INCL(frstats[0].fr_badttl); + fin->fin_flx |= FI_LOWTTL; + } + } +#ifdef USE_INET6 + else if (v == 6) { + if (((ip6_t *)ip)->ip6_hlim < fr_minttl) { + ATOMIC_INCL(frstats[0].fr_badttl); + fin->fin_flx |= FI_LOWTTL; + } + } +#endif + } + + if (fin->fin_flx & FI_SHORT) { ATOMIC_INCL(frstats[out].fr_short); } + pass = fr_pass; + READ_ENTER(&ipf_mutex); /* @@ -989,206 +2319,65 @@ int out; * after it has no auth. table matchup. This also stops NAT from * occuring until after the packet has been auth'd. */ - apass = fr_checkauth(ip, fin); + fr = fr_checkauth(fin, &pass); + if (!out) + (void) fr_checknatin(fin, &pass); + if (!out) + (void) fr_acctpkt(fin, NULL); - if (!out) { -#ifdef USE_INET6 - if (v == 6) - list = ipacct6[0][fr_active]; - else -#endif - list = ipacct[0][fr_active]; - changed = ip_natin(ip, fin); - if (!apass && (fin->fin_fr = list) && - (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INCL(frstats[0].fr_acct); - } - } + if (fr == NULL) + if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) + fr = fr_knownfrag(fin, &pass); + if (fr == NULL) + fr = fr_checkstate(fin, &pass); - if (!apass) { - if ((fin->fin_fl & FI_FRAG) == FI_FRAG) - fr = ipfr_knownfrag(ip, fin); - if (!fr && !(fin->fin_fl & FI_SHORT)) - fr = fr_checkstate(ip, fin); - if (fr != NULL) - pass = fr->fr_flags; - if (fr && (pass & FR_LOGFIRST)) - pass &= ~(FR_LOGFIRST|FR_LOG); - } + if ((pass & FR_NOMATCH) || (fr == NULL)) + fr = fr_firewall(fin, &pass); - if (apass || !fr) { - /* - * If a packet is found in the auth table, then skip checking - * the access lists for permission but we do need to consider - * the result as if it were from the ACL's. - */ - if (!apass) { - fc = frcache + out; - if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { - /* - * copy cached data so we can unlock the mutex - * earlier. - */ - bcopy((char *)fc, (char *)fin, FI_COPYSIZE); - ATOMIC_INCL(frstats[out].fr_chit); - if ((fr = fin->fin_fr)) { - ATOMIC_INCL(fr->fr_hits); - pass = fr->fr_flags; - } - } else { -#ifdef USE_INET6 - if (v == 6) - list = ipfilter6[out][fr_active]; - else -#endif - list = ipfilter[out][fr_active]; - if ((fin->fin_fr = list)) - pass = fr_scanlist(fr_pass, ip, fin, m); - if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE))) - bcopy((char *)fin, (char *)fc, - FI_COPYSIZE); - if (pass & FR_NOMATCH) { - ATOMIC_INCL(frstats[out].fr_nom); - fin->fin_fr = NULL; - } - } - } else - pass = apass; - fr = fin->fin_fr; - - /* - * If we fail to add a packet to the authorization queue, - * then we drop the packet later. However, if it was added - * then pretend we've dropped it already. - */ - if ((pass & FR_AUTH)) { - if (fr_newauth((mb_t *)m, fin, ip) != 0) { - m = *mp = NULL; - error = 0; - } else - error = ENOSPC; - } - - if (pass & FR_PREAUTH) { - READ_ENTER(&ipf_auth); - if ((fin->fin_fr = ipauth) && - (pass = fr_scanlist(0, ip, fin, m))) { - ATOMIC_INCL(fr_authstats.fas_hits); - } else { - ATOMIC_INCL(fr_authstats.fas_miss); - } - RWLOCK_EXIT(&ipf_auth); - } - - fin->fin_fr = fr; - if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { - if (fin->fin_fl & FI_FRAG) { - if (ipfr_newfrag(ip, fin) == -1) { - ATOMIC_INCL(frstats[out].fr_bnfr); - } else { - ATOMIC_INCL(frstats[out].fr_nfr); - } - } else { - ATOMIC_INCL(frstats[out].fr_cfr); - } - } - if (pass & FR_KEEPSTATE) { - if (fr_addstate(ip, fin, NULL, 0) == NULL) { - ATOMIC_INCL(frstats[out].fr_bads); - } else { - ATOMIC_INCL(frstats[out].fr_ads); - } - } - } else if (fr != NULL) { - pass = fr->fr_flags; - if (pass & FR_LOGFIRST) - pass &= ~(FR_LOGFIRST|FR_LOG); - } - -#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL)) - if (securelevel <= 0) -#endif - if (fr && fr->fr_func && !(pass & FR_CALLNOW)) - pass = (*fr->fr_func)(pass, ip, fin); + fin->fin_fr = fr; /* * Only count/translate packets which will be passed on, out the * interface. */ - if (out && (pass & FR_PASS)) { -#ifdef USE_INET6 - if (v == 6) - list = ipacct6[1][fr_active]; - else -#endif - list = ipacct[1][fr_active]; - if (list != NULL) { - u_32_t sg, sr; + if (out && FR_ISPASS(pass)) { + (void) fr_acctpkt(fin, NULL); - fin->fin_fr = list; - sg = fin->fin_group; - sr = fin->fin_rule; - if (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT) { - ATOMIC_INCL(frstats[1].fr_acct); - } - fin->fin_group = sg; - fin->fin_rule = sr; - fin->fin_fr = fr; - } - changed = ip_natout(ip, fin); - } else - fin->fin_fr = fr; - RWLOCK_EXIT(&ipf_mutex); - -#ifdef IPFILTER_LOG - if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { - if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { - pass |= FF_LOGNOMATCH; - ATOMIC_INCL(frstats[out].fr_npkl); - goto logit; - } else if (((pass & FR_LOGMASK) == FR_LOGP) || - ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) { - if ((pass & FR_LOGMASK) != FR_LOGP) - pass |= FF_LOGPASS; - ATOMIC_INCL(frstats[out].fr_ppkl); - goto logit; - } else if (((pass & FR_LOGMASK) == FR_LOGB) || - ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) { - if ((pass & FR_LOGMASK) != FR_LOGB) - pass |= FF_LOGBLOCK; - ATOMIC_INCL(frstats[out].fr_bpkl); -logit: - if (!IPLLOG(pass, ip, fin, m)) { - ATOMIC_INCL(frstats[out].fr_skip); - if ((pass & (FR_PASS|FR_LOGORBLOCK)) == - (FR_PASS|FR_LOGORBLOCK)) - pass ^= FR_PASS|FR_BLOCK; + if (fr_checknatout(fin, &pass) == -1) { + pass &= ~FR_CMDMASK; + pass |= FR_BLOCK; + } else if ((fr_update_ipid != 0) && (v == 4)) { + if (fr_updateipid(fin) == -1) { + ATOMIC_INCL(frstats[1].fr_ipud); + pass &= ~FR_CMDMASK; + pass |= FR_BLOCK; + } else { + ATOMIC_INCL(frstats[0].fr_ipud); } } } -#endif /* IPFILTER_LOG */ -#ifdef _KERNEL +#ifdef IPFILTER_LOG + if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) + (void) fr_dolog(fin, &pass); +#endif + + if (fin->fin_state != NULL) + fr_statederef(fin, (ipstate_t **)&fin->fin_state); + + if (fin->fin_nat != NULL) + fr_natderef((nat_t **)&fin->fin_nat); + /* * Only allow FR_DUP to work if a rule matched - it makes no sense to * set FR_DUP as a "default" as there are no instructions about where * to send the packet. */ - if (fr && (pass & FR_DUP)) -# if SOLARIS - mc = dupmsg(m); -# else -# if defined(__OpenBSD__) && (OpenBSD >= 199905) - mc = m_copym2(m, 0, M_COPYALL, M_DONTWAIT); -# else - mc = m_copy(m, 0, M_COPYALL); -# endif -# endif -#endif - if (pass & FR_PASS) { - ATOMIC_INCL(frstats[out].fr_pass); - } else if (pass & FR_BLOCK) { - ATOMIC_INCL(frstats[out].fr_block); + if ((fr != NULL) && (pass & FR_DUP)) { + mc = M_DUPLICATE(m); + } + + if (pass & (FR_RETRST|FR_RETICMP)) { /* * Should we return an ICMP packet to indicate error * status passing through the packet filter ? @@ -1198,33 +2387,24 @@ logit: * some operating systems. */ if (!out) { - if (changed == -1) - /* - * If a packet results in a NAT error, do not - * send a reset or ICMP error as it may disrupt - * an existing flow. This is the proxy saying - * the content is bad so just drop the packet - * silently. - */ - ; - else if (pass & FR_RETICMP) { + if (pass & FR_RETICMP) { int dst; if ((pass & FR_RETMASK) == FR_FAKEICMP) dst = 1; else dst = 0; - send_icmp_err(ip, ICMP_UNREACH, fin, dst); + (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst); ATOMIC_INCL(frstats[0].fr_ret); } else if (((pass & FR_RETMASK) == FR_RETRST) && - !(fin->fin_fl & FI_SHORT)) { - if (send_reset(ip, fin) == 0) { + !(fin->fin_flx & FI_SHORT)) { + if (fr_send_reset(fin) == 0) { ATOMIC_INCL(frstats[1].fr_ret); } } } else { if (pass & FR_RETRST) - error = ECONNRESET; + fin->fin_error = ECONNRESET; } } @@ -1235,76 +2415,175 @@ logit: * Once we're finished return to our caller, freeing the packet if * we are dropping it (* BSD ONLY *). */ - if ((changed == -1) && (pass & FR_PASS)) { - pass &= ~FR_PASS; - pass |= FR_BLOCK; +#if defined(USE_INET6) || (defined(__sgi) && defined(_KERNEL)) +filtered: +#endif + if (FR_ISPASS(pass)) { + ATOMIC_INCL(frstats[out].fr_pass); + } else if (FR_ISBLOCK(pass)) { + ATOMIC_INCL(frstats[out].fr_block); } -#if defined(_KERNEL) -# if !SOLARIS -# if !defined(linux) - if (fr) { - frdest_t *fdp = &fr->fr_tif; - if (((pass & FR_FASTROUTE) && !out) || - (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - (void) ipfr_fastroute(m, mp, fin, fdp); - m = *mp; + if (fr != NULL) { + frdest_t *fdp; + + fdp = &fr->fr_tifs[fin->fin_rev]; + + if (!out && (pass & FR_FASTROUTE)) { + /* + * For fastroute rule, no destioation interface defined + * so pass NULL as the frdest_t parameter + */ + (void) fr_fastroute(m, mp, fin, NULL); + m = *mp = NULL; + } else if ((fdp->fd_ifp != NULL) && + (fdp->fd_ifp != (struct ifnet *)-1)) { + /* this is for to rules: */ + (void) fr_fastroute(m, mp, fin, fdp); + m = *mp = NULL; } + /* + * Generate a duplicated packet. + */ if (mc != NULL) - (void) ipfr_fastroute(mc, &mc, fin, &fr->fr_dif); + (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif); } - if (!(pass & FR_PASS) && m) { - m_freem(m); - m = *mp = NULL; - } -# ifdef __sgi - else if (changed && up && m) - m_copyback(m, 0, up, hbuf); -# endif -# endif /* !linux */ -# else /* !SOLARIS */ - if (fr) { - frdest_t *fdp = &fr->fr_tif; + /* + * This late because the likes of fr_fastroute() use fin_fr. + */ + RWLOCK_EXIT(&ipf_mutex); - if (((pass & FR_FASTROUTE) && !out) || - (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) - (void) ipfr_fastroute(ip, m, mp, fin, fdp); - - if (mc != NULL) - (void) ipfr_fastroute(ip, mc, &mc, fin, &fr->fr_dif); + if (!FR_ISPASS(pass)) { + if (m != NULL) { + FREE_MB_T(m); + m = *mp = NULL; + } } -# endif /* !SOLARIS */ - return (pass & FR_PASS) ? 0 : error; +#if defined(_KERNEL) && defined(__sgi) + else { + if ((fin->fin_flx & FI_NATED) && up && (m != NULL)) { + COPYBACK(m, 0, up, hbuf); + } + } +#endif +finished: + RWLOCK_EXIT(&ipf_global); +#ifdef _KERNEL +# if OpenBSD >= 200311 + if (FR_ISPASS(pass)) { + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + } +# endif + return (FR_ISPASS(pass)) ? 0 : fin->fin_error; #else /* _KERNEL */ - if (pass & FR_NOMATCH) + FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); + if ((pass & FR_NOMATCH) != 0) return 1; - if (pass & FR_PASS) + + if ((pass & FR_RETMASK) != 0) + switch (pass & FR_RETMASK) + { + case FR_RETRST : + return 3; + case FR_RETICMP : + return 4; + case FR_FAKEICMP : + return 5; + } + + switch (pass & FR_CMDMASK) + { + case FR_PASS : return 0; - if (pass & FR_AUTH) + case FR_BLOCK : + return -1; + case FR_AUTH : return -2; - if ((pass & FR_RETMASK) == FR_RETRST) + case FR_ACCOUNT : return -3; - if ((pass & FR_RETMASK) == FR_RETICMP) + case FR_PREAUTH : return -4; - if ((pass & FR_RETMASK) == FR_FAKEICMP) - return -5; - return -1; + } + return 2; #endif /* _KERNEL */ } -/* - * ipf_cksum - * addr should be 16bit aligned and len is in bytes. - * length is in bytes - */ -u_short ipf_cksum(addr, len) -register u_short *addr; -register int len; +#ifdef IPFILTER_LOG +/* ------------------------------------------------------------------------ */ +/* Function: fr_dolog */ +/* Returns: frentry_t* - returns contents of fin_fr (no change made) */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Checks flags set to see how a packet should be logged, if it is to be */ +/* logged. Adjust statistics based on its success or not. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_dolog(fin, passp) +fr_info_t *fin; +u_32_t *passp; { - register u_32_t sum = 0; + u_32_t pass; + int out; + + out = fin->fin_out; + pass = *passp; + + if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { + pass |= FF_LOGNOMATCH; + ATOMIC_INCL(frstats[out].fr_npkl); + goto logit; + } else if (((pass & FR_LOGMASK) == FR_LOGP) || + (FR_ISPASS(pass) && (fr_flags & FF_LOGPASS))) { + if ((pass & FR_LOGMASK) != FR_LOGP) + pass |= FF_LOGPASS; + ATOMIC_INCL(frstats[out].fr_ppkl); + goto logit; + } else if (((pass & FR_LOGMASK) == FR_LOGB) || + (FR_ISBLOCK(pass) && (fr_flags & FF_LOGBLOCK))) { + if ((pass & FR_LOGMASK) != FR_LOGB) + pass |= FF_LOGBLOCK; + ATOMIC_INCL(frstats[out].fr_bpkl); +logit: + if (ipflog(fin, pass) == -1) { + ATOMIC_INCL(frstats[out].fr_skip); + + /* + * If the "or-block" option has been used then + * block the packet if we failed to log it. + */ + if ((pass & FR_LOGORBLOCK) && + FR_ISPASS(pass)) { + pass &= ~FR_CMDMASK; + pass |= FR_BLOCK; + } + } + *passp = pass; + } + + return fin->fin_fr; +} +#endif /* IPFILTER_LOG */ + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_cksum */ +/* Returns: u_short - IP header checksum */ +/* Parameters: addr(I) - pointer to start of buffer to checksum */ +/* len(I) - length of buffer in bytes */ +/* */ +/* Calculate the two's complement 16 bit checksum of the buffer passed. */ +/* */ +/* N.B.: addr should be 16bit aligned. */ +/* ------------------------------------------------------------------------ */ +u_short ipf_cksum(addr, len) +u_short *addr; +int len; +{ + u_32_t sum = 0; for (sum = 0; len > 1; len -= 2) sum += *addr++; @@ -1322,42 +2601,124 @@ register int len; } -/* - * NB: This function assumes we've pullup'd enough for all of the IP header - * and the TCP header. We also assume that data blocks aren't allocated in - * odd sizes. - */ -u_short fr_tcpsum(m, ip, tcp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_cksum */ +/* Returns: u_short - layer 4 checksum */ +/* Parameters: m(I ) - pointer to buffer holding packet */ +/* ip(I) - pointer to IP header */ +/* l4proto(I) - protocol to caclulate checksum for */ +/* l4hdr(I) - pointer to layer 4 header */ +/* */ +/* Calculates the TCP checksum for the packet held in "m", using the data */ +/* in the IP header "ip" to seed it. */ +/* */ +/* NB: This function assumes we've pullup'd enough for all of the IP header */ +/* and the TCP header. We also assume that data blocks aren't allocated in */ +/* odd sizes. */ +/* ------------------------------------------------------------------------ */ +u_short fr_cksum(m, ip, l4proto, l4hdr) mb_t *m; ip_t *ip; -tcphdr_t *tcp; +int l4proto; +void *l4hdr; { - u_short *sp, slen, ts; + u_short *sp, slen, sumsave, l4hlen, *csump; u_int sum, sum2; int hlen; +#ifdef USE_INET6 + ip6_t *ip6; +#endif + + csump = NULL; + sumsave = 0; + l4hlen = 0; + sp = NULL; + slen = 0; + hlen = 0; + sum = 0; /* * Add up IP Header portion */ - hlen = ip->ip_hl << 2; - slen = ip->ip_len - hlen; - sum = htons((u_short)ip->ip_p); - sum += htons(slen); - sp = (u_short *)&ip->ip_src; - sum += *sp++; /* ip_src */ - sum += *sp++; - sum += *sp++; /* ip_dst */ - sum += *sp++; - ts = tcp->th_sum; - tcp->th_sum = 0; -#ifdef KERNEL -# if SOLARIS +#ifdef USE_INET6 + if (IP_V(ip) == 4) { +#endif + hlen = IP_HL(ip) << 2; + slen = ip->ip_len - hlen; + sum = htons((u_short)l4proto); + sum += htons(slen); + sp = (u_short *)&ip->ip_src; + sum += *sp++; /* ip_src */ + sum += *sp++; + sum += *sp++; /* ip_dst */ + sum += *sp++; +#ifdef USE_INET6 + } else if (IP_V(ip) == 6) { + ip6 = (ip6_t *)ip; + hlen = sizeof(*ip6); + slen = ntohs(ip6->ip6_plen); + sum = htons((u_short)ip6->ip6_nxt); + sum += htons(slen); + sp = (u_short *)&ip6->ip6_src; + sum += *sp++; /* ip6_src */ + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; /* ip6_dst */ + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + sum += *sp++; + } +#endif + + switch (l4proto) + { + case IPPROTO_UDP : + csump = &((udphdr_t *)l4hdr)->uh_sum; + l4hlen = sizeof(udphdr_t); + break; + + case IPPROTO_TCP : + csump = &((tcphdr_t *)l4hdr)->th_sum; + l4hlen = sizeof(tcphdr_t); + break; + case IPPROTO_ICMP : + csump = &((icmphdr_t *)l4hdr)->icmp_cksum; + l4hlen = 4; + sum = 0; + break; + default : + break; + } + + if (csump != NULL) { + sumsave = *csump; + *csump = 0; + } + + l4hlen = l4hlen; /* LINT */ + +#ifdef _KERNEL +# ifdef MENTAT + { + void *rp = m->b_rptr; + + if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr) + m->b_rptr = (u_char *)ip; sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - sum2 = ~sum2 & 0xffff; -# else /* SOLARIS */ + m->b_rptr = rp; + sum2 = (u_short)(~sum2 & 0xffff); + } +# else /* MENTAT */ # if defined(BSD) || defined(sun) -# if BSD >= 199306 +# if BSD >= 199103 m->m_data += hlen; # else m->m_off += hlen; @@ -1365,7 +2726,7 @@ tcphdr_t *tcp; m->m_len -= hlen; sum2 = in_cksum(m, slen); m->m_len += hlen; -# if BSD >= 199306 +# if BSD >= 199103 m->m_data -= hlen; # else m->m_off -= hlen; @@ -1373,10 +2734,10 @@ tcphdr_t *tcp; /* * Both sum and sum2 are partial sums, so combine them together. */ - sum = (sum & 0xffff) + (sum >> 16); - sum = ~sum & 0xffff; - sum2 += sum; - sum2 = (sum2 & 0xffff) + (sum2 >> 16); + sum += ~sum2 & 0xffff; + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum2 = ~sum & 0xffff; # else /* defined(BSD) || defined(sun) */ { union { @@ -1384,35 +2745,44 @@ tcphdr_t *tcp; u_short s; } bytes; u_short len = ip->ip_len; -# if defined(__sgi) +# if defined(__sgi) int add; -# endif +# endif /* * Add up IP Header portion */ - sp = (u_short *)&ip->ip_src; - len -= (ip->ip_hl << 2); - sum = ntohs(IPPROTO_TCP); - sum += htons(len); - sum += *sp++; /* ip_src */ - sum += *sp++; - sum += *sp++; /* ip_dst */ - sum += *sp++; - if (sp != (u_short *)tcp) - sp = (u_short *)tcp; - sum += *sp++; /* sport */ - sum += *sp++; /* dport */ - sum += *sp++; /* seq */ - sum += *sp++; - sum += *sp++; /* ack */ - sum += *sp++; - sum += *sp++; /* off */ - sum += *sp++; /* win */ - sum += *sp++; /* Skip over checksum */ - sum += *sp++; /* urp */ + if (sp != (u_short *)l4hdr) + sp = (u_short *)l4hdr; -# ifdef __sgi + switch (l4proto) + { + case IPPROTO_UDP : + sum += *sp++; /* sport */ + sum += *sp++; /* dport */ + sum += *sp++; /* udp length */ + sum += *sp++; /* checksum */ + break; + + case IPPROTO_TCP : + sum += *sp++; /* sport */ + sum += *sp++; /* dport */ + sum += *sp++; /* seq */ + sum += *sp++; + sum += *sp++; /* ack */ + sum += *sp++; + sum += *sp++; /* off */ + sum += *sp++; /* win */ + sum += *sp++; /* checksum */ + sum += *sp++; /* urp */ + break; + case IPPROTO_ICMP : + sum = *sp++; /* type/code */ + sum += *sp++; /* checksum */ + break; + } + +# ifdef __sgi /* * In case we had to copy the IP & TCP header out of mbufs, * skip over the mbuf bits which are the header @@ -1430,24 +2800,26 @@ tcphdr_t *tcp; break; sp = mtod(m, u_short *); } - PANIC((!m),("fr_tcpsum(1): not enough data")); + PANIC((!m),("fr_cksum(1): not enough data")); } } } -# endif +# endif - if (!(len -= sizeof(*tcp))) + len -= (l4hlen + hlen); + if (len <= 0) goto nodata; + while (len > 1) { if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { m = m->m_next; - PANIC((!m),("fr_tcpsum(2): not enough data")); + PANIC((!m),("fr_cksum(2): not enough data")); sp = mtod(m, u_short *); } if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { bytes.c[0] = *(u_char *)sp; m = m->m_next; - PANIC((!m),("fr_tcpsum(3): not enough data")); + PANIC((!m),("fr_cksum(3): not enough data")); sp = mtod(m, u_short *); bytes.c[1] = *(u_char *)sp; sum += bytes.s; @@ -1460,7 +2832,8 @@ tcphdr_t *tcp; sum += *sp++; len -= 2; } - if (len) + + if (len != 0) sum += ntohs(*(u_char *)sp << 8); nodata: while (sum > 0xffff) @@ -1468,22 +2841,24 @@ nodata: sum2 = (u_short)(~sum & 0xffff); } # endif /* defined(BSD) || defined(sun) */ -# endif /* SOLARIS */ -#else /* KERNEL */ +# endif /* MENTAT */ +#else /* _KERNEL */ for (; slen > 1; slen -= 2) - sum += *sp++; + sum += *sp++; if (slen) sum += ntohs(*(u_char *)sp << 8); while (sum > 0xffff) sum = (sum & 0xffff) + (sum >> 16); sum2 = (u_short)(~sum & 0xffff); -#endif /* KERNEL */ - tcp->th_sum = ts; +#endif /* _KERNEL */ + if (csump != NULL) + *csump = sumsave; return sum2; } -#if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) ) +#if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \ + defined(__sgi) ) && !defined(linux) /* * Copyright (c) 1982, 1986, 1988, 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -1513,7 +2888,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * Id: fil.c,v 2.35.2.63 2002/08/28 12:40:08 darrenr Exp + * Id: fil.c,v 2.243.2.7 2004/03/23 12:06:56 darrenr Exp */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1521,12 +2896,12 @@ nodata: */ void m_copydata(m, off, len, cp) - register mb_t *m; - register int off; - register int len; + mb_t *m; + int off; + int len; caddr_t cp; { - register unsigned count; + unsigned count; if (off < 0 || len < 0) panic("m_copydata"); @@ -1551,7 +2926,6 @@ m_copydata(m, off, len, cp) } -# ifndef linux /* * Copy data from a buffer back into the indicated mbuf chain, * starting "off" bytes from the beginning, extending the mbuf @@ -1560,12 +2934,12 @@ m_copydata(m, off, len, cp) void m_copyback(m0, off, len, cp) struct mbuf *m0; - register int off; - register int len; + int off; + int len; caddr_t cp; { - register int mlen; - register struct mbuf *m = m0, *n; + int mlen; + struct mbuf *m = m0, *n; int totlen = 0; if (m0 == 0) @@ -1608,117 +2982,257 @@ out: #endif return; } -# endif /* linux */ -#endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */ +#endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */ -frgroup_t *fr_findgroup(num, flags, which, set, fgpp) -u_32_t num, flags; -minor_t which; +/* ------------------------------------------------------------------------ */ +/* Function: fr_findgroup */ +/* Returns: frgroup_t * - NULL = group not found, else pointer to group */ +/* Parameters: group(I) - group name to search for */ +/* unit(I) - device to which this group belongs */ +/* set(I) - which set of rules (inactive/inactive) this is */ +/* fgpp(O) - pointer to place to store pointer to the pointer */ +/* to where to add the next (last) group or where */ +/* to delete group from. */ +/* */ +/* Search amongst the defined groups for a particular group number. */ +/* ------------------------------------------------------------------------ */ +frgroup_t *fr_findgroup(group, unit, set, fgpp) +char *group; +minor_t unit; int set; frgroup_t ***fgpp; { frgroup_t *fg, **fgp; - if (which == IPL_LOGAUTH) - fgp = &ipfgroups[2][set]; - else if (flags & FR_ACCOUNT) - fgp = &ipfgroups[1][set]; - else if (flags & (FR_OUTQUE|FR_INQUE)) - fgp = &ipfgroups[0][set]; - else - return NULL; + /* + * Which list of groups to search in is dependant on which list of + * rules are being operated on. + */ + fgp = &ipfgroups[unit][set]; - while ((fg = *fgp)) - if (fg->fg_num == num) + while ((fg = *fgp) != NULL) { + if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) break; else fgp = &fg->fg_next; - if (fgpp) + } + if (fgpp != NULL) *fgpp = fgp; return fg; } -frgroup_t *fr_addgroup(num, fp, which, set) -u_32_t num; -frentry_t *fp; -minor_t which; +/* ------------------------------------------------------------------------ */ +/* Function: fr_addgroup */ +/* Returns: frgroup_t * - NULL == did not create group, */ +/* != NULL == pointer to the group */ +/* Parameters: num(I) - group number to add */ +/* head(I) - rule pointer that is using this as the head */ +/* flags(I) - rule flags which describe the type of rule it is */ +/* unit(I) - device to which this group will belong to */ +/* set(I) - which set of rules (inactive/inactive) this is */ +/* Write Locks: ipf_mutex */ +/* */ +/* Add a new group head, or if it already exists, increase the reference */ +/* count to it. */ +/* ------------------------------------------------------------------------ */ +frgroup_t *fr_addgroup(group, head, flags, unit, set) +char *group; +void *head; +u_32_t flags; +minor_t unit; int set; { frgroup_t *fg, **fgp; + u_32_t gflags; - if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp))) + if (group == NULL) + return NULL; + + if (unit == IPL_LOGIPF && *group == '\0') + return NULL; + + fgp = NULL; + gflags = flags & FR_INOUT; + + fg = fr_findgroup(group, unit, set, &fgp); + if (fg != NULL) { + if (fg->fg_flags == 0) + fg->fg_flags = gflags; + else if (gflags != fg->fg_flags) + return NULL; + fg->fg_ref++; return fg; - + } KMALLOC(fg, frgroup_t *); - if (fg) { - fg->fg_num = num; + if (fg != NULL) { + fg->fg_head = head; + fg->fg_start = NULL; fg->fg_next = *fgp; - fg->fg_head = fp; - fg->fg_start = &fp->fr_grp; + bcopy(group, fg->fg_name, FR_GROUPLEN); + fg->fg_flags = gflags; + fg->fg_ref = 1; *fgp = fg; } return fg; } -void fr_delgroup(num, flags, which, set) -u_32_t num, flags; -minor_t which; +/* ------------------------------------------------------------------------ */ +/* Function: fr_delgroup */ +/* Returns: Nil */ +/* Parameters: group(I) - group name to delete */ +/* unit(I) - device to which this group belongs */ +/* set(I) - which set of rules (inactive/inactive) this is */ +/* Write Locks: ipf_mutex */ +/* */ +/* Attempt to delete a group head. */ +/* Only do this when its reference count reaches 0. */ +/* ------------------------------------------------------------------------ */ +void fr_delgroup(group, unit, set) +char *group; +minor_t unit; int set; { frgroup_t *fg, **fgp; - - if (!(fg = fr_findgroup(num, flags, which, set, &fgp))) + + fg = fr_findgroup(group, unit, set, &fgp); + if (fg == NULL) return; - - *fgp = fg->fg_next; - KFREE(fg); + + fg->fg_ref--; + if (fg->fg_ref == 0) { + *fgp = fg->fg_next; + KFREE(fg); + } } +/* ------------------------------------------------------------------------ */ +/* Function: fr_getrulen */ +/* Returns: frentry_t * - NULL == not found, else pointer to rule n */ +/* Parameters: unit(I) - device for which to count the rule's number */ +/* flags(I) - which set of rules to find the rule in */ +/* group(I) - group name */ +/* n(I) - rule number to find */ +/* */ +/* Find rule # n in group # g and return a pointer to it. Return NULl if */ +/* group # g doesn't exist or there are less than n rules in the group. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_getrulen(unit, group, n) +int unit; +char *group; +u_32_t n; +{ + frentry_t *fr; + frgroup_t *fg; -/* - * recursively flush rules from the list, descending groups as they are - * encountered. if a rule is the head of a group and it has lost all its - * group members, then also delete the group reference. - */ + fg = fr_findgroup(group, unit, fr_active, NULL); + if (fg == NULL) + return NULL; + for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--) + ; + if (n != 0) + return NULL; + return fr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_rulen */ +/* Returns: int - >= 0 - rule number, -1 == search failed */ +/* Parameters: unit(I) - device for which to count the rule's number */ +/* fr(I) - pointer to rule to match */ +/* */ +/* Return the number for a rule on a specific filtering device. */ +/* ------------------------------------------------------------------------ */ +int fr_rulen(unit, fr) +int unit; +frentry_t *fr; +{ + frentry_t *fh; + frgroup_t *fg; + u_32_t n = 0; + + if (fr == NULL) + return -1; + fg = fr_findgroup(fr->fr_group, unit, fr_active, NULL); + if (fg == NULL) + return -1; + for (fh = fg->fg_head; fh; n++, fh = fh->fr_next) + if (fh == fr) + break; + if (fh == NULL) + return -1; + return n; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frflushlist */ +/* Returns: int - >= 0 - number of flushed rules */ +/* Parameters: set(I) - which set of rules (inactive/inactive) this is */ +/* unit(I) - device for which to flush rules */ +/* flags(I) - which set of rules to flush */ +/* nfreedp(O) - pointer to int where flush count is stored */ +/* listp(I) - pointer to list to flush pointer */ +/* Write Locks: ipf_mutex */ +/* */ +/* Recursively flush rules from the list, descending groups as they are */ +/* encountered. if a rule is the head of a group and it has lost all its */ +/* group members, then also delete the group reference. nfreedp is needed */ +/* to store the accumulating count of rules removed, whereas the returned */ +/* value is just the number removed from the current list. The latter is */ +/* needed to correctly adjust reference counts on rules that define groups. */ +/* */ +/* NOTE: Rules not loaded from user space cannot be flushed. */ +/* ------------------------------------------------------------------------ */ static int frflushlist(set, unit, nfreedp, listp) int set; minor_t unit; int *nfreedp; frentry_t **listp; { - register int freed = 0, i; - register frentry_t *fp; + int freed = 0, i; + frentry_t *fp; - while ((fp = *listp)) { + while ((fp = *listp) != NULL) { + if ((fp->fr_type & FR_T_BUILTIN) || + !(fp->fr_flags & FR_COPIED)) { + listp = &fp->fr_next; + continue; + } *listp = fp->fr_next; - if (fp->fr_grp) { - i = frflushlist(set, unit, nfreedp, &fp->fr_grp); - MUTEX_ENTER(&ipf_rw); + if (fp->fr_grp != NULL) { + i = frflushlist(set, unit, nfreedp, fp->fr_grp); fp->fr_ref -= i; - MUTEX_EXIT(&ipf_rw); } - ATOMIC_DEC32(fp->fr_ref); - if (fp->fr_grhead) { - fr_delgroup(fp->fr_grhead, fp->fr_flags, - unit, set); - fp->fr_grhead = 0; + if (fp->fr_grhead != NULL) { + fr_delgroup(fp->fr_grhead, unit, set); + *fp->fr_grhead = '\0'; } - if (fp->fr_ref == 0) { - KFREE(fp); + + ASSERT(fp->fr_ref > 0); + fp->fr_next = NULL; + if (fr_derefrule(&fp) == 0) freed++; - } else - fp->fr_next = NULL; } *nfreedp += freed; return freed; } +/* ------------------------------------------------------------------------ */ +/* Function: frflush */ +/* Returns: int - >= 0 - number of flushed rules */ +/* Parameters: unit(I) - device for which to flush rules */ +/* flags(I) - which set of rules to flush */ +/* */ +/* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ +/* and IPv6) as defined by the value of flags. */ +/* ------------------------------------------------------------------------ */ int frflush(unit, flags) minor_t unit; int flags; @@ -1727,26 +3241,23 @@ int flags; if (unit != IPL_LOGIPF) return 0; + WRITE_ENTER(&ipf_mutex); - bzero((char *)frcache, sizeof(frcache[0]) * 2); + bzero((char *)frcache, sizeof(frcache)); set = fr_active; - if (flags & FR_INACTIVE) + if ((flags & FR_INACTIVE) == FR_INACTIVE) set = 1 - set; if (flags & FR_OUTQUE) { -#ifdef USE_INET6 (void) frflushlist(set, unit, &flushed, &ipfilter6[1][set]); (void) frflushlist(set, unit, &flushed, &ipacct6[1][set]); -#endif (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]); (void) frflushlist(set, unit, &flushed, &ipacct[1][set]); } if (flags & FR_INQUE) { -#ifdef USE_INET6 (void) frflushlist(set, unit, &flushed, &ipfilter6[0][set]); (void) frflushlist(set, unit, &flushed, &ipacct6[0][set]); -#endif (void) frflushlist(set, unit, &flushed, &ipfilter[0][set]); (void) frflushlist(set, unit, &flushed, &ipacct[0][set]); } @@ -1755,6 +3266,17 @@ int flags; } +/* ------------------------------------------------------------------------ */ +/* Function: memstr */ +/* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ +/* Parameters: src(I) - pointer to byte sequence to match */ +/* dst(I) - pointer to byte sequence to search */ +/* slen(I) - match length */ +/* dlen(I) - length available to search in */ +/* */ +/* Search dst for a sequence of bytes matching those at src and extend for */ +/* slen bytes. */ +/* ------------------------------------------------------------------------ */ char *memstr(src, dst, slen, dlen) char *src, *dst; int slen, dlen; @@ -1771,34 +3293,50 @@ int slen, dlen; } return s; } - - -void fixskip(listp, rp, addremove) +/* ------------------------------------------------------------------------ */ +/* Function: fr_fixskip */ +/* Returns: Nil */ +/* Parameters: listp(IO) - pointer to start of list with skip rule */ +/* rp(I) - rule added/removed with skip in it. */ +/* addremove(I) - adjustment (-1/+1) to make to skip count, */ +/* depending on whether a rule was just added */ +/* or removed. */ +/* */ +/* Adjust all the rules in a list which would have skip'd past the position */ +/* where we are inserting to skip to the right place given the change. */ +/* ------------------------------------------------------------------------ */ +void fr_fixskip(listp, rp, addremove) frentry_t **listp, *rp; int addremove; { + int rules, rn; frentry_t *fp; - int rules = 0, rn = 0; - for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++) - ; + rules = 0; + for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) + rules++; if (!fp) return; - for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) - if (fp->fr_skip && (rn + fp->fr_skip >= rules)) - fp->fr_skip += addremove; + for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) + if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) + fp->fr_arg += addremove; } #ifdef _KERNEL -/* - * count consecutive 1's in bit mask. If the mask generated by counting - * consecutive 1's is different to that passed, return -1, else return # - * of bits. - */ -int countbits(ip) +/* ------------------------------------------------------------------------ */ +/* Function: count4bits */ +/* Returns: int - >= 0 - number of consecutive bits in input */ +/* Parameters: ip(I) - 32bit IP address */ +/* */ +/* IPv4 ONLY */ +/* count consecutive 1's in bit mask. If the mask generated by counting */ +/* consecutive 1's is different to that passed, return -1, else return # */ +/* of bits. */ +/* ------------------------------------------------------------------------ */ +int count4bits(ip) u_32_t ip; { u_32_t ipn; @@ -1822,158 +3360,187 @@ u_32_t ip; } -/* - * return the first IP Address associated with an interface - */ -int fr_ifpaddr(v, ifptr, inp) -int v; -void *ifptr; -struct in_addr *inp; +# if 0 +/* ------------------------------------------------------------------------ */ +/* Function: count6bits */ +/* Returns: int - >= 0 - number of consecutive bits in input */ +/* Parameters: msk(I) - pointer to start of IPv6 bitmask */ +/* */ +/* IPv6 ONLY */ +/* count consecutive 1's in bit mask. */ +/* ------------------------------------------------------------------------ */ +int count6bits(msk) +u_32_t *msk; { -# ifdef USE_INET6 - struct in6_addr *inp6 = NULL; -# endif -# if SOLARIS - ill_t *ill = ifptr; -# else - struct ifnet *ifp = ifptr; -# endif - struct in_addr in; + int i = 0, k; + u_32_t j; -# if SOLARIS -# ifdef USE_INET6 - if (v == 6) { - struct in6_addr in6; + for (k = 3; k >= 0; k--) + if (msk[k] == 0xffffffff) + i += 32; + else { + for (j = msk[k]; j; j <<= 1) + if (j & 0x80000000) + i++; + } + return i; +} +# endif +#endif /* _KERNEL */ + + +/* ------------------------------------------------------------------------ */ +/* Function: frsynclist */ +/* Returns: void */ +/* Parameters: Nil */ +/* Write Locks: ipf_mutex */ +/* */ +/* Walk through a list of filter rules and resolve any interface names into */ +/* pointers. Where dynamic addresses are used, also update the IP address */ +/* used in the rule. One might wonder why terminating fr_ifnames[] with a */ +/* \0 byte is done here. The reason is that this is the only place where */ +/* the names are resolved into pointers for filter rules and there are */ +/* multiple ways for rules to get into the kernel. */ +/* ------------------------------------------------------------------------ */ +static void frsynclist(fr) +frentry_t *fr; +{ + frdest_t *fdp; + int v, i; + + for (; fr; fr = fr->fr_next) { + v = fr->fr_v; /* - * First is always link local. + * Lookup all the interface names that are part of the rule. */ - if (ill->ill_ipif->ipif_next) - in6 = ill->ill_ipif->ipif_next->ipif_v6lcl_addr; - else - bzero((char *)&in6, sizeof(in6)); - bcopy((char *)&in6, (char *)inp, sizeof(in6)); - } else -# endif - { - in.s_addr = ill->ill_ipif->ipif_local_addr; - *inp = in; - } -# else /* SOLARIS */ -# if linux - ; -# else /* linux */ - struct sockaddr_in *sin; - struct ifaddr *ifa; - -# if (__FreeBSD_version >= 300000) - ifa = TAILQ_FIRST(&ifp->if_addrhead); -# else -# if defined(__NetBSD__) || defined(__OpenBSD__) - ifa = TAILQ_FIRST(&ifp->if_addrlist); -# else -# if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ - ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa; -# else - ifa = ifp->if_addrlist; -# endif -# endif /* __NetBSD__ || __OpenBSD__ */ -# endif /* __FreeBSD_version >= 300000 */ -# if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK)) - sin = (struct sockaddr_in *)&ifa->ifa_addr; -# else - sin = (struct sockaddr_in *)ifa->ifa_addr; - while (sin && ifa) { - if ((v == 4) && (sin->sin_family == AF_INET)) - break; -# ifdef USE_INET6 - if ((v == 6) && (sin->sin_family == AF_INET6)) { - inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; - if (!IN6_IS_ADDR_LINKLOCAL(inp6) && - !IN6_IS_ADDR_LOOPBACK(inp6)) - break; + for (i = 0; i < 4; i++) { + if ((fr->fr_ifnames[i][1] == '\0') && + ((fr->fr_ifnames[i][0] == '-') || + (fr->fr_ifnames[i][0] == '*'))) { + fr->fr_ifas[i] = NULL; + } else if (fr->fr_ifnames[i][0] != '\0') { + fr->fr_ifnames[i][LIFNAMSIZ - 1] = '\0'; + fr->fr_ifas[i] = GETIFP(fr->fr_ifnames[i], v); + if (fr->fr_ifas[i] == (void *)NULL) + fr->fr_ifas[i] = (void *)-1; + } } -# endif -# if (__FreeBSD_version >= 300000) - ifa = TAILQ_NEXT(ifa, ifa_link); -# else -# if defined(__NetBSD__) || defined(__OpenBSD__) - ifa = ifa->ifa_list.tqe_next; -# else - ifa = ifa->ifa_next; -# endif -# endif /* __FreeBSD_version >= 300000 */ - if (ifa) - sin = (struct sockaddr_in *)ifa->ifa_addr; - } - if (ifa == NULL) - sin = NULL; - if (sin == NULL) - return -1; -# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ -# ifdef USE_INET6 - if (v == 6) - bcopy((char *)inp6, (char *)inp, sizeof(*inp6)); - else -# endif - { - in = sin->sin_addr; - *inp = in; - } -# endif /* linux */ -# endif /* SOLARIS */ - return 0; -} - -static void frsynclist(fr) -register frentry_t *fr; -{ - for (; fr; fr = fr->fr_next) { - if (fr->fr_ifa != NULL) { - fr->fr_ifa = GETUNIT(fr->fr_ifname, fr->fr_ip.fi_v); - if (fr->fr_ifa == NULL) - fr->fr_ifa = (void *)-1; + if (fr->fr_type == FR_T_IPF) { + if (fr->fr_satype != FRI_NORMAL && + fr->fr_satype != FRI_LOOKUP) { + (void)fr_ifpaddr(v, fr->fr_satype, + fr->fr_ifas[fr->fr_sifpidx], + &fr->fr_src, &fr->fr_smsk); + } + if (fr->fr_datype != FRI_NORMAL && + fr->fr_datype != FRI_LOOKUP) { + (void)fr_ifpaddr(v, fr->fr_datype, + fr->fr_ifas[fr->fr_difpidx], + &fr->fr_dst, &fr->fr_dmsk); + } } - if (fr->fr_grp) - frsynclist(fr->fr_grp); + + fdp = &fr->fr_tifs[0]; + if (fdp->fd_ifname[0] != '\0') { + fdp->fd_ifp = GETIFP(fdp->fd_ifname, v); + if (fdp->fd_ifp == NULL) + fdp->fd_ifp = (void *)-1; + } + + fdp = &fr->fr_tifs[1]; + if (fdp->fd_ifname[0] != '\0') { + fdp->fd_ifp = GETIFP(fdp->fd_ifname, v); + if (fdp->fd_ifp == NULL) + fdp->fd_ifp = (void *)-1; + } + + fdp = &fr->fr_dif; + if (fdp->fd_ifname[0] != '\0') { + fr->fr_flags &= ~FR_DUP; + fdp->fd_ifp = GETIFP(fdp->fd_ifname, v); + if (fdp->fd_ifp == NULL) + fdp->fd_ifp = (void *)-1; + else + fr->fr_flags |= FR_DUP; + } + +#ifdef IPFILTER_LOOKUP + if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP && + fr->fr_srcptr == NULL) { + fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype, + fr->fr_srcnum, + &fr->fr_srcfunc); + } + if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP && + fr->fr_dstptr == NULL) { + fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype, + fr->fr_dstnum, + &fr->fr_dstfunc); + } +#endif } } +#ifdef _KERNEL +/* ------------------------------------------------------------------------ */ +/* Function: frsync */ +/* Returns: void */ +/* Parameters: Nil */ +/* */ +/* frsync() is called when we suspect that the interface list or */ +/* information about interfaces (like IP#) has changed. Go through all */ +/* filter rules, NAT entries and the state table and check if anything */ +/* needs to be changed/updated. */ +/* ------------------------------------------------------------------------ */ void frsync() { -# if !SOLARIS - register struct ifnet *ifp; + int i; +# if !defined(MENTAT) && !defined(linux) + struct ifnet *ifp; # if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \ (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) # if (NetBSD >= 199905) || defined(__OpenBSD__) - for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) +# elif defined(__FreeBSD_version) && (__FreeBSD_version >= 500043) + IFNET_RLOCK(); + TAILQ_FOREACH(ifp, &ifnet, if_link); # else - for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_link)) + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) # endif # else for (ifp = ifnet; ifp; ifp = ifp->if_next) # endif { - ip_natsync(ifp); - ip_statesync(ifp); + fr_natsync(ifp); + fr_statesync(ifp); } - ip_natsync((struct ifnet *)-1); -# endif /* !SOLARIS */ +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 500043) + IFNET_RUNLOCK(); +# endif +# endif WRITE_ENTER(&ipf_mutex); frsynclist(ipacct[0][fr_active]); frsynclist(ipacct[1][fr_active]); frsynclist(ipfilter[0][fr_active]); frsynclist(ipfilter[1][fr_active]); -#ifdef USE_INET6 frsynclist(ipacct6[0][fr_active]); frsynclist(ipacct6[1][fr_active]); frsynclist(ipfilter6[0][fr_active]); frsynclist(ipfilter6[1][fr_active]); -#endif + + for (i = 0; i < IPL_LOGSIZE; i++) { + frgroup_t *g; + + for (g = ipfgroups[i][0]; g != NULL; g = g->fg_next) + frsynclist(g->fg_start); + for (g = ipfgroups[i][1]; g != NULL; g = g->fg_next) + frsynclist(g->fg_start); + } RWLOCK_EXIT(&ipf_mutex); } @@ -1983,96 +3550,130 @@ void frsync() * copied _from_ in this instance is a pointer to a char buf (which could * end up being unaligned) and on the kernel's local stack. */ -int ircopyptr(a, b, c) -void *a, *b; -size_t c; +/* ------------------------------------------------------------------------ */ +/* Function: copyinptr */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: src(I) - pointer to the source address */ +/* dst(I) - destination address */ +/* size(I) - number of bytes to copy */ +/* */ +/* Copy a block of data in from user space, given a pointer to the pointer */ +/* to start copying from (src) and a pointer to where to store it (dst). */ +/* NB: src - pointer to user space pointer, dst - kernel space pointer */ +/* ------------------------------------------------------------------------ */ +int copyinptr(src, dst, size) +void *src, *dst; +size_t size; { caddr_t ca; int err; #if SOLARIS - if (copyin(a, (char *)&ca, sizeof(ca))) - return EFAULT; + err = COPYIN(src, (caddr_t)&ca, sizeof(ca)); + if (err != 0) + return err; #else - bcopy(a, &ca, sizeof(ca)); + bcopy(src, (caddr_t)&ca, sizeof(ca)); #endif - err = copyin(ca, b, c); - if (err) - err = EFAULT; + err = COPYIN(ca, dst, size); return err; } -int iwcopyptr(a, b, c) -void *a, *b; -size_t c; +/* ------------------------------------------------------------------------ */ +/* Function: copyoutptr */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: src(I) - pointer to the source address */ +/* dst(I) - destination address */ +/* size(I) - number of bytes to copy */ +/* */ +/* Copy a block of data out to user space, given a pointer to the pointer */ +/* to start copying from (src) and a pointer to where to store it (dst). */ +/* NB: src - kernel space pointer, dst - pointer to user space pointer. */ +/* ------------------------------------------------------------------------ */ +int copyoutptr(src, dst, size) +void *src, *dst; +size_t size; { caddr_t ca; int err; #if SOLARIS - if (copyin(b, (char *)&ca, sizeof(ca))) - return EFAULT; + err = COPYIN(dst, (caddr_t)&ca, sizeof(ca)); + if (err != 0) + return err; #else - bcopy(b, &ca, sizeof(ca)); + bcopy(dst, (caddr_t)&ca, sizeof(ca)); #endif - err = copyout(a, ca, c); - if (err) - err = EFAULT; + err = COPYOUT(src, ca, size); return err; } #else /* _KERNEL */ +/* + * See above for description, except that all addressing is in user space. + */ +int copyoutptr(src, dst, size) +void *src, *dst; +size_t size; +{ + caddr_t ca; + + bcopy(dst, (char *)&ca, sizeof(ca)); + bcopy(src, ca, size); + return 0; +} + + +/* + * See above for description, except that all addressing is in user space. + */ +int copyinptr(src, dst, size) +void *src, *dst; +size_t size; +{ + caddr_t ca; + + bcopy(src, (char *)&ca, sizeof(ca)); + bcopy(ca, dst, size); + return 0; +} + + /* * return the first IP Address associated with an interface */ -int fr_ifpaddr(v, ifptr, inp) -int v; +int fr_ifpaddr(v, flags, ifptr, inp, inpmask) +int v, flags; void *ifptr; -struct in_addr *inp; +struct in_addr *inp, *inpmask; { return 0; } - -int ircopyptr(a, b, c) -void *a, *b; -size_t c; -{ - caddr_t ca; - - bcopy(a, &ca, sizeof(ca)); - bcopy(ca, b, c); - return 0; -} - - -int iwcopyptr(a, b, c) -void *a, *b; -size_t c; -{ - caddr_t ca; - - bcopy(b, &ca, sizeof(ca)); - bcopy(a, ca, c); - return 0; -} - - #endif +/* ------------------------------------------------------------------------ */ +/* Function: fr_lock */ +/* Returns: int - 0 == success, else error */ +/* Parameters: data(I) - pointer to lock value to set */ +/* lockp(O) - pointer to location to store old lock value */ +/* */ +/* Get the new value for the lock integer, set it and return the old value */ +/* in *lockp. */ +/* ------------------------------------------------------------------------ */ int fr_lock(data, lockp) caddr_t data; int *lockp; { int arg, error; - error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + error = COPYIN(data, (caddr_t)&arg, sizeof(arg)); if (!error) { - error = IWCOPY((caddr_t)lockp, data, sizeof(*lockp)); + error = COPYOUT((caddr_t)lockp, data, sizeof(*lockp)); if (!error) *lockp = arg; } @@ -2080,59 +3681,52 @@ int *lockp; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_getstat */ +/* Returns: Nil */ +/* Parameters: fiop(I) - pointer to ipfilter stats structure */ +/* */ +/* Stores a copy of current pointers, counters, etc, in the friostat */ +/* structure. */ +/* ------------------------------------------------------------------------ */ void fr_getstat(fiop) friostat_t *fiop; { + int i, j; + bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2); - fiop->f_locks[0] = fr_state_lock; - fiop->f_locks[1] = fr_nat_lock; - fiop->f_locks[2] = fr_frag_lock; - fiop->f_locks[3] = fr_auth_lock; - fiop->f_fin[0] = ipfilter[0][0]; - fiop->f_fin[1] = ipfilter[0][1]; - fiop->f_fout[0] = ipfilter[1][0]; - fiop->f_fout[1] = ipfilter[1][1]; - fiop->f_acctin[0] = ipacct[0][0]; - fiop->f_acctin[1] = ipacct[0][1]; - fiop->f_acctout[0] = ipacct[1][0]; - fiop->f_acctout[1] = ipacct[1][1]; -#ifdef USE_INET6 - fiop->f_fin6[0] = ipfilter6[0][0]; - fiop->f_fin6[1] = ipfilter6[0][1]; - fiop->f_fout6[0] = ipfilter6[1][0]; - fiop->f_fout6[1] = ipfilter6[1][1]; - fiop->f_acctin6[0] = ipacct6[0][0]; - fiop->f_acctin6[1] = ipacct6[0][1]; - fiop->f_acctout6[0] = ipacct6[1][0]; - fiop->f_acctout6[1] = ipacct6[1][1]; -#else - fiop->f_fin6[0] = NULL; - fiop->f_fin6[1] = NULL; - fiop->f_fout6[0] = NULL; - fiop->f_fout6[1] = NULL; - fiop->f_acctin6[0] = NULL; - fiop->f_acctin6[1] = NULL; - fiop->f_acctout6[0] = NULL; - fiop->f_acctout6[1] = NULL; -#endif + fiop->f_locks[IPL_LOGSTATE] = fr_state_lock; + fiop->f_locks[IPL_LOGNAT] = fr_nat_lock; + fiop->f_locks[IPL_LOGIPF] = fr_frag_lock; + fiop->f_locks[IPL_LOGAUTH] = fr_auth_lock; + + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) { + fiop->f_ipf[i][j] = ipfilter[i][j]; + fiop->f_acct[i][j] = ipacct[i][j]; + fiop->f_ipf6[i][j] = ipfilter6[i][j]; + fiop->f_acct6[i][j] = ipacct6[i][j]; + } + + fiop->f_ticks = fr_ticks; fiop->f_active = fr_active; - fiop->f_froute[0] = ipl_frouteok[0]; - fiop->f_froute[1] = ipl_frouteok[1]; + fiop->f_froute[0] = fr_frouteok[0]; + fiop->f_froute[1] = fr_frouteok[1]; fiop->f_running = fr_running; - fiop->f_groups[0][0] = ipfgroups[0][0]; - fiop->f_groups[0][1] = ipfgroups[0][1]; - fiop->f_groups[1][0] = ipfgroups[1][0]; - fiop->f_groups[1][1] = ipfgroups[1][1]; - fiop->f_groups[2][0] = ipfgroups[2][0]; - fiop->f_groups[2][1] = ipfgroups[2][1]; + for (i = 0; i < IPL_LOGSIZE; i++) { + fiop->f_groups[i][0] = ipfgroups[i][0]; + fiop->f_groups[i][1] = ipfgroups[i][1]; + } #ifdef IPFILTER_LOG fiop->f_logging = 1; #else fiop->f_logging = 0; #endif fiop->f_defpass = fr_pass; - strncpy(fiop->f_version, ipfilter_version, sizeof(fiop->f_version)); + fiop->f_features = fr_features; + (void) strncpy(fiop->f_version, ipfilter_version, + sizeof(fiop->f_version)); } @@ -2176,16 +3770,2080 @@ int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { -1, /* 12: ICMP_UNREACH_TOSHOST */ ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ }; +int icmpreplytype6[ICMP6_MAXTYPE + 1]; #endif +int icmpreplytype4[ICMP_MAXTYPE + 1]; -#ifndef _KERNEL -int mbuflen(buf) -mb_t *buf; + +/* ------------------------------------------------------------------------ */ +/* Function: fr_matchicmpqueryreply */ +/* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ +/* Parameters: v(I) - IP protocol version (4 or 6) */ +/* ic(I) - ICMP information */ +/* icmp(I) - ICMP packet header */ +/* rev(I) - direction (0 = forward/1 = reverse) of packet */ +/* */ +/* Check if the ICMP packet defined by the header pointed to by icmp is a */ +/* reply to one as described by what's in ic. If it is a match, return 1, */ +/* else return 0 for no match. */ +/* ------------------------------------------------------------------------ */ +int fr_matchicmpqueryreply(v, ic, icmp, rev) +int v; +icmpinfo_t *ic; +icmphdr_t *icmp; +int rev; { - ip_t *ip; + int ictype; - ip = (ip_t *)buf; - return ip->ip_len; + ictype = ic->ici_type; + + if (v == 4) { + /* + * If we matched its type on the way in, then when going out + * it will still be the same type. + */ + if ((!rev && (icmp->icmp_type == ictype)) || + (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { + if (icmp->icmp_type != ICMP_ECHOREPLY) + return 1; + if (icmp->icmp_id == ic->ici_id) + return 1; + } + } +#ifdef USE_INET6 + else if (v == 6) { + if ((!rev && (icmp->icmp_type == ictype)) || + (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { + if (icmp->icmp_type != ICMP6_ECHO_REPLY) + return 1; + if (icmp->icmp_id == ic->ici_id) + return 1; + } + } +#endif + return 0; +} + + +#ifdef IPFILTER_LOOKUP +/* ------------------------------------------------------------------------ */ +/* Function: fr_resolvelookup */ +/* Returns: void * - NULL = failure, else success. */ +/* Parameters: type(I) - type of lookup these parameters are for. */ +/* number(I) - table number to use when searching */ +/* funcptr(IO) - pointer to pointer for storing IP address */ +/* searching function. */ +/* */ +/* Search for the "table" number passed in amongst those configured for */ +/* that particular type. If the type is recognised then the function to */ +/* call to do the IP address search will be change, regardless of whether */ +/* or not the "table" number exists. */ +/* ------------------------------------------------------------------------ */ +static void *fr_resolvelookup(type, number, funcptr) +u_int type, number; +lookupfunc_t *funcptr; +{ + char name[FR_GROUPLEN]; + iphtable_t *iph; + ip_pool_t *ipo; + void *ptr; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%u", number); +#else + (void) sprintf(name, "%u", number); +#endif + + READ_ENTER(&ip_poolrw); + + switch (type) + { + case IPLT_POOL : +# if (defined(__osf__) && defined(_KERNEL)) + ptr = NULL; + *funcptr = NULL; +# else + ipo = ip_pool_find(IPL_LOGIPF, name); + ptr = ipo; + if (ipo != NULL) { + ATOMIC_INC32(ipo->ipo_ref); + } + *funcptr = ip_pool_search; +# endif + break; + case IPLT_HASH : + iph = fr_findhtable(IPL_LOGIPF, name); + ptr = iph; + if (iph != NULL) { + ATOMIC_INC32(iph->iph_ref); + } + *funcptr = fr_iphmfindip; + break; + default: + ptr = NULL; + *funcptr = NULL; + break; + } + RWLOCK_EXIT(&ip_poolrw); + + return ptr; } #endif + + +/* ------------------------------------------------------------------------ */ +/* Function: frrequest */ +/* Returns: int - 0 == success, > 0 == errno value */ +/* Parameters: unit(I) - device for which this is for */ +/* req(I) - ioctl command (SIOC*) */ +/* data(I) - pointr to ioctl data */ +/* set(I) - 1 or 0 (filter set) */ +/* makecopy(I) - flag indicating whether data points to a rule */ +/* in kernel space & hence doesn't need copying. */ +/* */ +/* This function handles all the requests which operate on the list of */ +/* filter rules. This includes adding, deleting, insertion. It is also */ +/* responsible for creating groups when a "head" rule is loaded. Interface */ +/* names are resolved here and other sanity checks are made on the content */ +/* of the rule structure being loaded. If a rule has user defined timeouts */ +/* then make sure they are created and initialised before exiting. */ +/* ------------------------------------------------------------------------ */ +int frrequest(unit, req, data, set, makecopy) +int unit; +ioctlcmd_t req; +int set, makecopy; +caddr_t data; +{ + frentry_t frd, *fp, *f, **fprev, **ftail; + int error = 0, in, v; + u_int *p, *pp; + frgroup_t *fg; + char *group; + void *ptr; + + fg = NULL; + fp = &frd; + if (makecopy != 0) { + error = fr_inobj(data, fp, IPFOBJ_FRENTRY); + if (error) + return EFAULT; + if ((fp->fr_flags & FR_T_BUILTIN) != 0) + return EINVAL; + fp->fr_ref = 0; + fp->fr_flags |= FR_COPIED; + } else { + fp = (frentry_t *)data; + if ((fp->fr_type & FR_T_BUILTIN) == 0) + return EINVAL; + fp->fr_flags &= ~FR_COPIED; + } + + if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || + ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) + return EINVAL; + + v = fp->fr_v; + + /* + * Only filter rules for IPv4 or IPv6 are accepted. + */ + if (v == 4) + /*EMPTY*/; +#ifdef USE_INET6 + else if (v == 6) + /*EMPTY*/; +#endif + else { + return EINVAL; + } + + /* + * If the rule is being loaded from user space, i.e. we had to copy it + * into kernel space, then do not trust the function pointer in the + * rule. + */ + if ((makecopy == 1) && (fp->fr_func != NULL)) { + if (fr_findfunc(fp->fr_func) == NULL) + return ESRCH; + error = fr_funcinit(fp); + if (error != 0) + return error; + } + + ptr = NULL; + /* + * Check that the group number does exist and that its use (in/out) + * matches what the rule is. + */ + group = fp->fr_group; + if (!strcmp(group, "0")) + *group = '\0'; + if ((req != (int)SIOCZRLST) && (*group != '\0')) { + fg = fr_findgroup(group, unit, set, NULL); + if (fg == NULL) + return ESRCH; + if (fg->fg_flags == 0) + fg->fg_flags = fp->fr_flags & FR_INOUT; + else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) + return ESRCH; + } + + in = (fp->fr_flags & FR_INQUE) ? 0 : 1; + + /* + * Work out which rule list this change is being applied to. + */ + ftail = NULL; + fprev = NULL; + if (unit == IPL_LOGAUTH) + fprev = &ipauth; + else if (v == 4) { + if (FR_ISACCOUNT(fp->fr_flags)) + fprev = &ipacct[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) + fprev = &ipfilter[in][set]; + } else if (v == 6) { + if (FR_ISACCOUNT(fp->fr_flags)) + fprev = &ipacct6[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) + fprev = &ipfilter6[in][set]; + } + if (fprev == NULL) + return ESRCH; + + if (*group != '\0') { + if (!fg && !(fg = fr_findgroup(group, unit, set, NULL))) + return ESRCH; + fprev = &fg->fg_start; + } + + for (f = *fprev; f != NULL; fprev = &f->fr_next) + if (fp->fr_collect <= f->fr_collect) + break; + ftail = fprev; + + /* + * Copy in extra data for the rule. + */ + if (fp->fr_dsize != 0) { + if (makecopy != 0) { + KMALLOCS(ptr, void *, fp->fr_dsize); + if (!ptr) + return ENOMEM; + error = COPYIN(fp->fr_data, ptr, fp->fr_dsize); + } else { + ptr = fp->fr_data; + error = 0; + } + if (error != 0) { + KFREES(ptr, fp->fr_dsize); + return ENOMEM; + } + fp->fr_data = ptr; + } else + fp->fr_data = NULL; + + /* + * Perform per-rule type sanity checks of their members. + */ + switch (fp->fr_type & ~FR_T_BUILTIN) + { +#if defined(IPFILTER_BPF) + case FR_T_BPFOPC : + if (fp->fr_dsize == 0) + return EINVAL; + if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + break; +#endif + case FR_T_IPF : + if (fp->fr_dsize == 0) + return EINVAL; + switch (fp->fr_satype) + { + case FRI_BROADCAST : + case FRI_DYNAMIC : + case FRI_NETWORK : + case FRI_NETMASKED : + case FRI_PEERADDR : + if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) { + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + break; +#ifdef IPFILTER_LOOKUP + case FRI_LOOKUP : + fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype, + fp->fr_srcnum, + &fp->fr_srcfunc); + break; +#endif + default : + break; + } + + switch (fp->fr_datype) + { + case FRI_BROADCAST : + case FRI_DYNAMIC : + case FRI_NETWORK : + case FRI_NETMASKED : + case FRI_PEERADDR : + if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) { + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + break; +#ifdef IPFILTER_LOOKUP + case FRI_LOOKUP : + fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype, + fp->fr_dstnum, + &fp->fr_dstfunc); + break; +#endif + default : + + break; + } + break; + case FR_T_NONE : + break; + case FR_T_CALLFUNC : + break; + case FR_T_COMPIPF : + break; + default : + if (makecopy && fp->fr_data != NULL) { + KFREES(fp->fr_data, fp->fr_dsize); + } + return EINVAL; + } + + /* + * Lookup all the interface names that are part of the rule. + */ + frsynclist(fp); + fp->fr_statecnt = 0; + + /* + * Look for an existing matching filter rule, but don't include the + * next or interface pointer in the comparison (fr_next, fr_ifa). + * This elminates rules which are indentical being loaded. Checksum + * the constant part of the filter rule to make comparisons quicker + * (this meaning no pointers are included). + */ + for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; + p < pp; p++) + fp->fr_cksum += *p; + pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); + for (p = (u_int *)fp->fr_data; p < pp; p++) + fp->fr_cksum += *p; + + WRITE_ENTER(&ipf_mutex); + bzero((char *)frcache, sizeof(frcache)); + + for (; (f = *ftail) != NULL; ftail = &f->fr_next) + if ((fp->fr_cksum == f->fr_cksum) && + (f->fr_dsize == fp->fr_dsize) && + !bcmp((char *)&f->fr_dsize, + (char *)&fp->fr_dsize, FR_CMPSIZ) && + (!ptr || !f->fr_data || + !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize))) + break; + + /* + * If zero'ing statistics, copy current to caller and zero. + */ + if (req == (ioctlcmd_t)SIOCZRLST) { + if (f == NULL) + error = ESRCH; + else { + error = fr_outobj(data, f, IPFOBJ_FRENTRY); + if (error == 0) { + if (f->fr_dsize != 0 && f->fr_data != NULL) + error = COPYOUT(f->fr_data, ptr, + f->fr_dsize); + if (error == 0) { + f->fr_hits = 0; + f->fr_bytes = 0; + } + } + } + + if (ptr != NULL && makecopy != 0) { + KFREES(ptr, fp->fr_dsize); + } + RWLOCK_EXIT(&ipf_mutex); + return error; + } + + if (!f) { + if (req == (ioctlcmd_t)SIOCINAFR || + req == (ioctlcmd_t)SIOCINIFR) { + ftail = fprev; + if (fp->fr_hits != 0) { + while (--fp->fr_hits && (f = *ftail)) + ftail = &f->fr_next; + } + f = NULL; + ptr = NULL; + error = 0; + } + } + + /* + * Request to remove a rule. + */ + if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) { + if (!f) + error = ESRCH; + else { + /* + * Do not allow activity from user space to interfere + * with rules not loaded that way. + */ + if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { + error = EPERM; + goto done; + } + + /* + * Return EBUSY if the rule is being reference by + * something else (eg state information. + */ + if (f->fr_ref > 1) { + error = EBUSY; + goto done; + } +#ifdef IPFILTER_SCAN + if (f->fr_isctag[0] != '\0' && + (f->fr_isc != (struct ipscan *)-1)) + ipsc_detachfr(f); +#endif + if ((fg != NULL) && (fg->fg_head != NULL)) + fg->fg_head->fr_ref--; + if (unit == IPL_LOGAUTH) { + error = fr_preauthcmd(req, f, ftail); + goto done; + } + if (*f->fr_grhead != '\0') + fr_delgroup(f->fr_grhead, unit, set); + fr_fixskip(fprev, f, -1); + *ftail = f->fr_next; + f->fr_next = NULL; + (void)fr_derefrule(&f); + } + } else { + /* + * Not removing, so we must be adding/inserting a rule. + */ + if (f) + error = EEXIST; + else { + if (unit == IPL_LOGAUTH) { + error = fr_preauthcmd(req, fp, ftail); + goto done; + } + if (makecopy) { + KMALLOC(f, frentry_t *); + } else + f = fp; + if (f != NULL) { + if (fg != NULL && fg->fg_head!= NULL ) + fg->fg_head->fr_ref++; + if (fp != f) + bcopy((char *)fp, (char *)f, + sizeof(*f)); + MUTEX_NUKE(&f->fr_lock); + MUTEX_INIT(&f->fr_lock, "filter rule lock"); +#ifdef IPFILTER_SCAN + if (f->fr_isctag[0] != '\0' && + ipsc_attachfr(f)) + f->fr_isc = (struct ipscan *)-1; +#endif + f->fr_hits = 0; + if (makecopy != 0) + f->fr_ref = 1; + f->fr_next = *ftail; + *ftail = f; + if (req == (ioctlcmd_t)SIOCINIFR || + req == (ioctlcmd_t)SIOCINAFR) + fr_fixskip(fprev, f, 1); + f->fr_grp = NULL; + group = f->fr_grhead; + if (*group != '\0') { + fg = fr_addgroup(group, f, f->fr_flags, + unit, set); + if (fg != NULL) + f->fr_grp = &fg->fg_start; + } + } else + error = ENOMEM; + } + } +done: + RWLOCK_EXIT(&ipf_mutex); + if ((ptr != NULL) && (error != 0) && (makecopy != 0)) { + KFREES(ptr, fp->fr_dsize); + } + return (error); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_funcinit */ +/* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ +/* Parameters: fr(I) - pointer to filter rule */ +/* */ +/* If a rule is a call rule, then check if the function it points to needs */ +/* an init function to be called now the rule has been loaded. */ +/* ------------------------------------------------------------------------ */ +static int fr_funcinit(fr) +frentry_t *fr; +{ + ipfunc_resolve_t *ft; + int err; + + err = ESRCH; + + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (ft->ipfu_addr == fr->fr_func) { + err = 0; + if (ft->ipfu_init != NULL) + err = (*ft->ipfu_init)(fr); + break; + } + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_findfunc */ +/* Returns: ipfunc_t - pointer to function if found, else NULL */ +/* Parameters: funcptr(I) - function pointer to lookup */ +/* */ +/* Look for a function in the table of known functions. */ +/* ------------------------------------------------------------------------ */ +static ipfunc_t fr_findfunc(funcptr) +ipfunc_t funcptr; +{ + ipfunc_resolve_t *ft; + + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (ft->ipfu_addr == funcptr) + return funcptr; + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_resolvefunc */ +/* Returns: int - 0 == success, else error */ +/* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ +/* */ +/* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ +/* This will either be the function name (if the pointer is set) or the */ +/* function pointer if the name is set. When found, fill in the details so */ +/* it can be copied back to user space. */ +/* ------------------------------------------------------------------------ */ +int fr_resolvefunc(data) +void *data; +{ + ipfunc_resolve_t res, *ft; + + if (COPYIN(data, &res, sizeof(res)) != 0) + return EFAULT; + + if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (strncmp(res.ipfu_name, ft->ipfu_name, + sizeof(res.ipfu_name)) == 0) { + res.ipfu_addr = ft->ipfu_addr; + res.ipfu_init = ft->ipfu_init; + if (COPYOUT(&res, data, sizeof(res)) != 0) + return EFAULT; + return 0; + } + } + if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { + for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) + if (ft->ipfu_addr == res.ipfu_addr) { + (void) strncpy(res.ipfu_name, ft->ipfu_name, + sizeof(res.ipfu_name)); + res.ipfu_init = ft->ipfu_init; + if (COPYOUT(&res, data, sizeof(res)) != 0) + return EFAULT; + return 0; + } + } + return ESRCH; +} + + +#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \ + (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \ + (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \ + (defined(__OpenBSD__) && (OpenBSD < 200006)) +/* + * From: NetBSD + * ppsratecheck(): packets (or events) per second limitation. + */ +int +ppsratecheck(lasttime, curpps, maxpps) + struct timeval *lasttime; + int *curpps; + int maxpps; /* maximum pps allowed */ +{ + struct timeval tv, delta; + int rv; + + GETKTIME(&tv); + + delta.tv_sec = tv.tv_sec - lasttime->tv_sec; + delta.tv_usec = tv.tv_usec - lasttime->tv_usec; + if (delta.tv_usec < 0) { + delta.tv_sec--; + delta.tv_usec += 1000000; + } + + /* + * check for 0,0 is so that the message will be seen at least once. + * if more than one second have passed since the last update of + * lasttime, reset the counter. + * + * we do increment *curpps even in *curpps < maxpps case, as some may + * try to use *curpps for stat purposes as well. + */ + if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || + delta.tv_sec >= 1) { + *lasttime = tv; + *curpps = 0; + rv = 1; + } else if (maxpps < 0) + rv = 1; + else if (*curpps < maxpps) + rv = 1; + else + rv = 0; + *curpps = *curpps + 1; + + return (rv); +} +#endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_derefrule */ +/* Returns: int - 0 == rule freed up, else rule not freed */ +/* Parameters: fr(I) - pointer to filter rule */ +/* */ +/* Decrement the reference counter to a rule by one. If it reaches zero, */ +/* free it and any associated storage space being used by it. */ +/* ------------------------------------------------------------------------ */ +int fr_derefrule(frp) +frentry_t **frp; +{ + frentry_t *fr; + + fr = *frp; + + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref--; + if (fr->fr_ref == 0) { + MUTEX_EXIT(&fr->fr_lock); + MUTEX_DESTROY(&fr->fr_lock); + +#ifdef IPFILTER_LOOKUP + if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP) + ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr); + if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP) + ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr); +#endif + + if (fr->fr_dsize) { + KFREES(fr->fr_data, fr->fr_dsize); + } + if ((fr->fr_flags & FR_COPIED) != 0) { + KFREE(fr); + return 0; + } + return 1; + } else { + MUTEX_EXIT(&fr->fr_lock); + } + *frp = NULL; + return -1; +} + + +#ifdef IPFILTER_LOOKUP +/* ------------------------------------------------------------------------ */ +/* Function: fr_grpmapinit */ +/* Returns: int - 0 == success, else ESRCH because table entry not found*/ +/* Parameters: fr(I) - pointer to rule to find hash table for */ +/* */ +/* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ +/* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */ +/* ------------------------------------------------------------------------ */ +static int fr_grpmapinit(fr) +frentry_t *fr; +{ + char name[FR_GROUPLEN]; + iphtable_t *iph; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(name, sizeof(name), "%d", fr->fr_arg); +#else + (void) sprintf(name, "%d", fr->fr_arg); +#endif + iph = fr_findhtable(IPL_LOGIPF, name); + if (iph == NULL) + return ESRCH; + if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) + return ESRCH; + fr->fr_ptr = iph; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_srcgrpmap */ +/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Look for a rule group head in a hash table, using the source address as */ +/* the key, and descend into that group and continue matching rules against */ +/* the packet. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_srcgrpmap(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + frgroup_t *fg; + void *rval; + + rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_src); + if (rval == NULL) + return NULL; + + fg = rval; + fin->fin_fr = fg->fg_start; + (void) fr_scanlist(fin, *passp); + return fin->fin_fr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_dstgrpmap */ +/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(IO) - pointer to current/new filter decision (unused) */ +/* */ +/* Look for a rule group head in a hash table, using the destination */ +/* address as the key, and descend into that group and continue matching */ +/* rules against the packet. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_dstgrpmap(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + frgroup_t *fg; + void *rval; + + rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_dst); + if (rval == NULL) + return NULL; + + fg = rval; + fin->fin_fr = fg->fg_start; + (void) fr_scanlist(fin, *passp); + return fin->fin_fr; +} +#endif /* IPFILTER_LOOKUP */ + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_addtimeoutqueue */ +/* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ +/* timeout queue with given interval. */ +/* Parameters: parent(I) - pointer to pointer to parent node of this list */ +/* of interface queues. */ +/* seconds(I) - timeout value in seconds for this queue. */ +/* */ +/* This routine first looks for a timeout queue that matches the interval */ +/* being requested. If it finds one, increments the reference counter and */ +/* returns a pointer to it. If none are found, it allocates a new one and */ +/* inserts it at the top of the list. */ +/* ------------------------------------------------------------------------ */ +ipftq_t *fr_addtimeoutqueue(parent, seconds) +ipftq_t **parent; +u_int seconds; +{ + u_int period; + ipftq_t *ifq; + + period = seconds * IPF_HZ_DIVIDE; + MUTEX_ENTER(&ipf_timeoutlock); + for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) + if (ifq->ifq_ttl == period) + break; + + if (ifq != NULL) { + MUTEX_ENTER(&ifq->ifq_lock); + ifq->ifq_ref++; + MUTEX_EXIT(&ifq->ifq_lock); + MUTEX_EXIT(&ipf_timeoutlock); + return ifq; + } + + KMALLOC(ifq, ipftq_t *); + if (ifq != NULL) { + ifq->ifq_ttl = period; + ifq->ifq_head = NULL; + ifq->ifq_tail = &ifq->ifq_head; + ifq->ifq_next = *parent; + ifq->ifq_pnext = parent; + ifq->ifq_ref = 1; + ifq->ifq_flags = IFQF_USER; + *parent = ifq; + fr_userifqs++; + MUTEX_NUKE(&ifq->ifq_lock); + MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex"); + } + MUTEX_EXIT(&ipf_timeoutlock); + return ifq; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_deletetimeoutqueue */ +/* Returns: Nil */ +/* Parameters: difp(I) - timeout queue which is losing a reference. */ +/* */ +/* This routine must be called when we're discarding a pointer to a timeout */ +/* queue object. It takes care of the reference counter and free's it when */ +/* it reaches 0. */ +/* ------------------------------------------------------------------------ */ +void fr_deletetimeoutqueue(ifq) +ipftq_t *ifq; +{ + MUTEX_ENTER(&ipf_timeoutlock); + MUTEX_ENTER(&ifq->ifq_lock); + + ifq->ifq_ref--; + + if ((ifq->ifq_ref == 0) && (ifq->ifq_head == NULL)) { + /* + * Remove from its position in the list. + */ + *ifq->ifq_pnext = ifq->ifq_next; + if (ifq->ifq_next != NULL) + ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; + + MUTEX_EXIT(&ifq->ifq_lock); /* Tru64 */ + MUTEX_DESTROY(&ifq->ifq_lock); + KFREE(ifq); + fr_userifqs--; + } else { + MUTEX_EXIT(&ifq->ifq_lock); + } + MUTEX_EXIT(&ipf_timeoutlock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_queuefront */ +/* Returns: Nil */ +/* Parameters: tqe(I) - pointer to timeout queue entry */ +/* */ +/* Move a queue entry to the front of the queue, if it isn't already there. */ +/* ------------------------------------------------------------------------ */ +void fr_queuefront(tqe) +ipftqent_t *tqe; +{ + ipftq_t *ifq; + + ifq = tqe->tqe_ifq; + + if (ifq->ifq_head != tqe) { + MUTEX_ENTER(&ifq->ifq_lock); + *tqe->tqe_pnext = tqe->tqe_next; + if (tqe->tqe_next) + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + else + ifq->ifq_tail = tqe->tqe_pnext; + + tqe->tqe_next = ifq->ifq_head; + ifq->ifq_head->tqe_pnext = &tqe->tqe_next; + ifq->ifq_head = tqe; + tqe->tqe_pnext = &ifq->ifq_head; + MUTEX_EXIT(&ifq->ifq_lock); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_queueback */ +/* Returns: Nil */ +/* Parameters: tqe(I) - pointer to timeout queue entry */ +/* */ +/* Move a queue entry to the back of the queue, if it isn't already there. */ +/* ------------------------------------------------------------------------ */ +void fr_queueback(tqe) +ipftqent_t *tqe; +{ + ipftq_t *ifq; + + ifq = tqe->tqe_ifq; + + if (ifq->ifq_tail != NULL && *ifq->ifq_tail != tqe) { + MUTEX_ENTER(&ifq->ifq_lock); + *tqe->tqe_pnext = tqe->tqe_next; + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + + tqe->tqe_next = NULL; + tqe->tqe_die = fr_ticks + ifq->ifq_ttl; + tqe->tqe_pnext = ifq->ifq_tail; + *ifq->ifq_tail = tqe; + ifq->ifq_tail = &tqe->tqe_next; + tqe->tqe_die = fr_ticks + ifq->ifq_ttl; + MUTEX_EXIT(&ifq->ifq_lock); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_queueappend */ +/* Returns: Nil */ +/* Parameters: tqe(I) - pointer to timeout queue entry */ +/* ifq(I) - pointer to timeout queue */ +/* parent(I) - owing object pointer */ +/* */ +/* Move a queue entry to the back of the queue, if it isn't already there. */ +/* ------------------------------------------------------------------------ */ +void fr_queueappend(tqe, ifq, parent) +ipftqent_t *tqe; +ipftq_t *ifq; +void *parent; +{ + + MUTEX_ENTER(&ifq->ifq_lock); + tqe->tqe_parent = parent; + tqe->tqe_pnext = ifq->ifq_tail; + *ifq->ifq_tail = tqe; + ifq->ifq_tail = &tqe->tqe_next; + tqe->tqe_next = NULL; + tqe->tqe_ifq = ifq; + tqe->tqe_die = fr_ticks + ifq->ifq_ttl; + MUTEX_EXIT(&ifq->ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_movequeue */ +/* Returns: Nil */ +/* Parameters: tq(I) - pointer to timeout queue information */ +/* oifp(I) - old timeout queue entry was on */ +/* nifp(I) - new timeout queue to put entry on */ +/* */ +/* Move a queue entry from one timeout queue to another timeout queue. */ +/* If it notices that the current entry is already last and does not need */ +/* to move queue, the return. */ +/* ------------------------------------------------------------------------ */ +void fr_movequeue(tqe, oifq, nifq) +ipftqent_t *tqe; +ipftq_t *oifq, *nifq; +{ + /* + * Is the operation here going to be a no-op ? + */ + if (oifq == nifq && *oifq->ifq_tail == tqe) + return; + + /* + * Remove from the old queue + */ + MUTEX_ENTER(&oifq->ifq_lock); + *tqe->tqe_pnext = tqe->tqe_next; + if (tqe->tqe_next) + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + else + oifq->ifq_tail = tqe->tqe_pnext; + tqe->tqe_next = NULL; + + /* + * If we're moving from one queue to another, release the lock on the + * old queue and get a lock on the new queue. For user defined queues, + * if we're moving off it, call delete in case it can now be freed. + */ + if (oifq != nifq) { + tqe->tqe_ifq = NULL; + MUTEX_EXIT(&oifq->ifq_lock); + if ((oifq->ifq_flags & IFQF_USER) != 0) + fr_deletetimeoutqueue(oifq); + + MUTEX_ENTER(&nifq->ifq_lock); + tqe->tqe_ifq = nifq; + nifq->ifq_ref++; + } + + /* + * Add to the bottom of the new queue + */ + tqe->tqe_die = fr_ticks + nifq->ifq_ttl; + tqe->tqe_pnext = nifq->ifq_tail; + *nifq->ifq_tail = tqe; + nifq->ifq_tail = &tqe->tqe_next; + MUTEX_EXIT(&nifq->ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_updateipid */ +/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* When we are doing NAT, change the IP of every packet to represent a */ +/* single sequence of packets coming from the host, hiding any host */ +/* specific sequencing that might otherwise be revealed. If the packet is */ +/* a fragment, then store the 'new' IPid in the fragment cache and look up */ +/* the fragment cache for non-leading fragments. If a non-leading fragment */ +/* has no match in the cache, return an error. */ +/* ------------------------------------------------------------------------ */ +static INLINE int fr_updateipid(fin) +fr_info_t *fin; +{ + u_short id, ido, sums; + u_32_t sumd, sum; + ip_t *ip; + + if (fin->fin_off != 0) { + sum = fr_ipid_knownfrag(fin); + if (sum == 0xffffffff) + return -1; + sum &= 0xffff; + id = (u_short)sum; + } else { + id = fr_nextipid(fin); + if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) + (void) fr_ipid_newfrag(fin, (u_32_t)id); + } + + ip = fin->fin_ip; + ido = ntohs(ip->ip_id); + if (id == ido) + return 0; + ip->ip_id = htons(id); + CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ + sum = (~ntohs(ip->ip_sum)) & 0xffff; + sum += sumd; + sum = (sum >> 16) + (sum & 0xffff); + sum = (sum >> 16) + (sum & 0xffff); + sums = ~(u_short)sum; + ip->ip_sum = htons(sums); + return 0; +} + + +#ifdef NEED_FRGETIFNAME +/* ------------------------------------------------------------------------ */ +/* Function: fr_getifname */ +/* Returns: char * - pointer to interface name */ +/* Parameters: ifp(I) - pointer to network interface */ +/* buffer(O) - pointer to where to store interface name */ +/* */ +/* Constructs an interface name in the buffer passed. The buffer passed is */ +/* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ +/* as a NULL pointer then return a pointer to a static array. */ +/* ------------------------------------------------------------------------ */ +char *fr_getifname(ifp, buffer) +struct ifnet *ifp; +char *buffer; +{ + static char namebuf[LIFNAMSIZ]; +# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ + defined(__sgi) || defined(linux) || \ + (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) + int unit, space; + char temp[20]; + char *s; +# endif + + if (buffer == NULL) + buffer = namebuf; + (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); + buffer[LIFNAMSIZ - 1] = '\0'; +# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ + defined(__sgi) || \ + (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) + for (s = buffer; *s; s++) + ; + unit = ifp->if_unit; + space = LIFNAMSIZ - (s - buffer); + if (space > 0) { +# if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(temp, sizeof(temp), "%d", unit); +# else + (void) sprintf(temp, "%d", unit); +# endif + (void) strncpy(s, temp, space); + } +# endif + return buffer; +} +#endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ioctlswitch */ +/* Returns: int - -1 continue processing, else ioctl return value */ +/* Parameters: unit(I) - device unit opened */ +/* data(I) - pointer to ioctl data */ +/* cmd(I) - ioctl command */ +/* mode(I) - mode value */ +/* */ +/* Based on the value of unit, call the appropriate ioctl handler or return */ +/* EIO if ipfilter is not running. Also checks if write perms are req'd */ +/* for the device in order to execute the ioctl. */ +/* ------------------------------------------------------------------------ */ +int fr_ioctlswitch(unit, data, cmd, mode) +int unit, mode; +ioctlcmd_t cmd; +void *data; +{ + int error = 0; + + switch (unit) + { + case IPL_LOGIPF : + error = -1; + break; + case IPL_LOGNAT : + if (fr_running > 0) + error = fr_nat_ioctl(data, cmd, mode); + else + error = EIO; + break; + case IPL_LOGSTATE : + if (fr_running > 0) + error = fr_state_ioctl(data, cmd, mode); + else + error = EIO; + break; + case IPL_LOGAUTH : + if (fr_running > 0) { + if ((cmd == (ioctlcmd_t)SIOCADAFR) || + (cmd == (ioctlcmd_t)SIOCRMAFR)) { + if (!(mode & FWRITE)) { + error = EPERM; + } else { + error = frrequest(unit, cmd, data, + fr_active, 1); + } + } else { + error = fr_auth_ioctl(data, cmd, mode); + } + } else + error = EIO; + break; + case IPL_LOGSYNC : +#ifdef IPFILTER_SYNC + if (fr_running > 0) + error = fr_sync_ioctl(data, cmd, mode); + else +#endif + error = EIO; + break; + case IPL_LOGSCAN : +#ifdef IPFILTER_SCAN + if (fr_running > 0) + error = fr_scan_ioctl(data, cmd, mode); + else +#endif + error = EIO; + break; + case IPL_LOGLOOKUP : +#ifdef IPFILTER_LOOKUP + if (fr_running > 0) + error = ip_lookup_ioctl(data, cmd, mode); + else +#endif + error = EIO; + break; + default : + error = EIO; + break; + } + + return error; +} + + +/* + * This array defines the expected size of objects coming into the kernel + * for the various recognised object types. + */ +static int fr_objbytes[] = { + 0, /* frentry */ + sizeof(struct friostat), + sizeof(struct fr_info), + sizeof(struct fr_authstat), + sizeof(struct ipfrstat), + sizeof(struct ipnat), + sizeof(struct natstat), + sizeof(struct ipstate_save), + sizeof(struct nat_save), + sizeof(struct natlookup), + 0, /* ipstate */ + sizeof(struct ips_stat), + sizeof(struct frauth), + sizeof(struct ipftune) +}; + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_inobj */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* ptr(I) - pointer to store real data in */ +/* type(I) - type of structure being moved */ +/* */ +/* Copy in the contents of what the ipfobj_t points to. In future, we */ +/* add things to check for version numbers, sizes, etc, to make it backward */ +/* compatible at the ABI for user land. */ +/* ------------------------------------------------------------------------ */ +int fr_inobj(data, ptr, type) +void *data; +void *ptr; +int type; +{ + ipfobj_t obj; + int error = 0; + + if ((type < 0) || + (type > ((sizeof(fr_objbytes)/sizeof(fr_objbytes[0])) - 1))) + return EINVAL; + + BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); + + if (obj.ipfo_type != type) + return EINVAL; + +#ifndef IPFILTER_COMPAT + if ((fr_objbytes[type] != 0) && (obj.ipfo_size != fr_objbytes[type])) + return EINVAL; +#else + if (obj.ipfo_rev != IPFILTER_VERSION) + /* XXX compatibility hook here */ + ; + if ((fr_objbytes[type] != 0) && (obj.ipfo_size != fr_objbytes[type])) + /* XXX compatibility hook here */ + return EINVAL; +#endif + + error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, obj.ipfo_size); + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_outobj */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* ptr(I) - pointer to store real data in */ +/* type(I) - type of structure being moved */ +/* */ +/* Copy out the contents of what ptr is to where ipfobj points to. In */ +/* future, we add things to check for version numbers, sizes, etc, to make */ +/* it backward compatible at the ABI for user land. */ +/* ------------------------------------------------------------------------ */ +int fr_outobj(data, ptr, type) +void *data; +void *ptr; +int type; +{ + ipfobj_t obj; + int error; + + BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); + + if (obj.ipfo_type != type) + return EINVAL; + +#ifndef IPFILTER_COMPAT + if ((fr_objbytes[type] != 0) && (obj.ipfo_size != fr_objbytes[type])) + return EINVAL; +#else + if (obj.ipfo_rev != IPFILTER_VERSION) + /* XXX compatibility hook here */ + ; + if ((fr_objbytes[type] != 0) && (obj.ipfo_size != fr_objbytes[type])) + /* XXX compatibility hook here */ + return EINVAL; +#endif + + error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size); + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkl4sum */ +/* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* If possible, calculate the layer 4 checksum for the packet. If this is */ +/* not possible, return without indicating a failure or success but in a */ +/* way that is ditinguishable. */ +/* ------------------------------------------------------------------------ */ +int fr_checkl4sum(fin) +fr_info_t *fin; +{ + u_short sum, hdrsum, *csump; + udphdr_t *udp; + int dosum; + + if ((fin->fin_flx & FI_NOCKSUM) != 0) + return 0; + + /* + * If the TCP packet isn't a fragment, isn't too short and otherwise + * isn't already considered "bad", then validate the checksum. If + * this check fails then considered the packet to be "bad". + */ + if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) + return 1; + + csump = NULL; + hdrsum = 0; + dosum = 0; + sum = 0; + +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) + if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) { + hdrsum = 0; + sum = 0; + } else { +#endif + switch (fin->fin_p) + { + case IPPROTO_TCP : + csump = &((tcphdr_t *)fin->fin_dp)->th_sum; + dosum = 1; + break; + + case IPPROTO_UDP : + udp = fin->fin_dp; + if (udp->uh_sum != 0) { + csump = &udp->uh_sum; + dosum = 1; + } + break; + + case IPPROTO_ICMP : + csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; + dosum = 1; + break; + + default : + return 1; + /*NOTREACHED*/ + } + + if (csump != NULL) + hdrsum = *csump; + + if (dosum) + sum = fr_cksum(fin->fin_m, fin->fin_ip, + fin->fin_p, fin->fin_dp); +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) + } +#endif +#if !defined(_KERNEL) + FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); +#endif + if (hdrsum == sum) + return 0; + return -1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ifpfillv4addr */ +/* Returns: int - 0 = address update, -1 = address not updated */ +/* Parameters: atype(I) - type of network address update to perform */ +/* sin(I) - pointer to source of address information */ +/* mask(I) - pointer to source of netmask information */ +/* inp(I) - pointer to destination address store */ +/* inpmask(I) - pointer to destination netmask store */ +/* */ +/* Given a type of network address update (atype) to perform, copy */ +/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ +/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ +/* which case the operation fails. For all values of atype other than */ +/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ +/* value. */ +/* ------------------------------------------------------------------------ */ +int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask) +int atype; +struct sockaddr_in *sin, *mask; +struct in_addr *inp, *inpmask; +{ + if (inpmask != NULL && atype != FRI_NETMASKED) + inpmask->s_addr = 0xffffffff; + + if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { + if (atype == FRI_NETMASKED) { + if (inpmask == NULL) + return -1; + inpmask->s_addr = mask->sin_addr.s_addr; + } + inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; + } else { + inp->s_addr = sin->sin_addr.s_addr; + } + return 0; +} + + +#ifdef USE_INET6 +/* ------------------------------------------------------------------------ */ +/* Function: fr_ifpfillv6addr */ +/* Returns: int - 0 = address update, -1 = address not updated */ +/* Parameters: atype(I) - type of network address update to perform */ +/* sin(I) - pointer to source of address information */ +/* mask(I) - pointer to source of netmask information */ +/* inp(I) - pointer to destination address store */ +/* inpmask(I) - pointer to destination netmask store */ +/* */ +/* Given a type of network address update (atype) to perform, copy */ +/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ +/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ +/* which case the operation fails. For all values of atype other than */ +/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ +/* value. */ +/* ------------------------------------------------------------------------ */ +int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask) +int atype; +struct sockaddr_in6 *sin, *mask; +struct in_addr *inp, *inpmask; +{ + i6addr_t *src, *dst, *and, *dmask; + + src = (i6addr_t *)&sin->sin6_addr; + and = (i6addr_t *)&mask->sin6_addr; + dst = (i6addr_t *)inp; + dmask = (i6addr_t *)inpmask; + + if (inpmask != NULL && atype != FRI_NETMASKED) { + dmask->i6[0] = 0xffffffff; + dmask->i6[1] = 0xffffffff; + dmask->i6[2] = 0xffffffff; + dmask->i6[3] = 0xffffffff; + } + + if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { + if (atype == FRI_NETMASKED) { + if (inpmask == NULL) + return -1; + dmask->i6[0] = and->i6[0]; + dmask->i6[1] = and->i6[1]; + dmask->i6[2] = and->i6[2]; + dmask->i6[3] = and->i6[3]; + } + + dst->i6[0] = src->i6[0] & and->i6[0]; + dst->i6[1] = src->i6[1] & and->i6[1]; + dst->i6[2] = src->i6[2] & and->i6[2]; + dst->i6[3] = src->i6[3] & and->i6[3]; + } else { + dst->i6[0] = src->i6[0]; + dst->i6[1] = src->i6[1]; + dst->i6[2] = src->i6[2]; + dst->i6[3] = src->i6[3]; + } + return 0; +} +#endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_coalesce */ +/* Returns: 1 == success, -1 == failure */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Attempt to get all of the packet data into a single, contiguous buffer. */ +/* If this call returns a failure then the buffers have also been freed. */ +/* ------------------------------------------------------------------------ */ +int fr_coalesce(fin) +fr_info_t *fin; +{ +#if !defined(__sgi) && defined(_KERNEL) + if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { +# ifdef MENTAT + FREE_MB_T(*fin->fin_mp); +# endif + fin->fin_m = NULL; + *fin->fin_mp = NULL; + return -1; + } +#endif + return 1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_matchtag */ +/* Returns: 0 == mismatch, 1 == match. */ +/* Parameters: tag1(I) - pointer to first tag to compare */ +/* tag2(I) - pointer to second tag to compare */ +/* */ +/* Returns true (non-zero) or false(0) if the two tag structures can be */ +/* considered to be a match or not match, respectively. The tag is 16 */ +/* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ +/* compare the ints instead, for speed. tag1 is the master of the */ +/* comparison. This function should only be called with both tag1 and tag2 */ +/* as non-NULL pointers. */ +/* ------------------------------------------------------------------------ */ +int fr_matchtag(tag1, tag2) +ipftag_t *tag1, *tag2; +{ + if (tag1 == tag2) + return 1; + + if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) + return 1; + + if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && + (tag1->ipt_num[1] == tag2->ipt_num[1]) && + (tag1->ipt_num[2] == tag2->ipt_num[2]) && + (tag1->ipt_num[3] == tag2->ipt_num[3])) + return 1; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_pullup */ +/* Returns: NULL == pullup failed, else pointer to protocol header */ +/* Parameters: m(I) - pointer to buffer where data packet starts */ +/* fin(I) - pointer to packet information */ +/* len(I) - number of bytes to pullup */ +/* */ +/* Attempt to move at least len bytes (from the start of the buffer) into a */ +/* single buffer for ease of access. Operating system native functions are */ +/* used to manage buffers - if necessary. If the entire packet ends up in */ +/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ +/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ +/* and ONLY if the pullup succeeds. */ +/* ------------------------------------------------------------------------ */ +#if defined(_KERNEL) && !defined(__sgi) +void *fr_pullup(min, fin, len) +mb_t *min; +fr_info_t *fin; +int len; +{ +# ifdef MENTAT + qpktinfo_t *qpi = fin->fin_qpi; +# endif + int out = fin->fin_out, dpoff, ipoff; + mb_t *m = min; + char *ip; + + if (m == NULL) + return NULL; + + if ((fin->fin_flx & FI_COALESCE) != 0) + return MTOD(m, void *); + + ipoff = (char *)fin->fin_ip - MTOD(m, char *); + if (fin->fin_dp != NULL) + dpoff = (char *)fin->fin_dp - (char *)fin->fin_ip; + else + dpoff = 0; + + if (M_LEN(m) < len) { +# ifdef MENTAT + int inc = 0; + + if (ipoff > 0) { + if ((ipoff & 3) != 0) { + inc = 4 - (ipoff & 3); + if (m->b_rptr - inc >= m->b_datap->db_base) + m->b_rptr -= inc; + else + inc = 0; + } + } + if (!pullupmsg(m, len + ipoff + inc)) { + ATOMIC_INCL(frstats[out].fr_pull[1]); + return NULL; + } + m->b_rptr += inc; + ATOMIC_INCL(frstats[out].fr_pull[0]); + qpi->qpi_data = MTOD(m, char *) + ipoff; +# else + m = m_pullup(m, len); + *fin->fin_mp = m; + if (m == NULL) { + ATOMIC_INCL(frstats[out].fr_pull[1]); + return NULL; + } + ATOMIC_INCL(frstats[out].fr_pull[0]); +# endif /* MENTAT */ + } + ip = MTOD(m, char *) + ipoff; + fin->fin_ip = (ip_t *)ip; + if (fin->fin_dp != NULL) + fin->fin_dp = (char *)fin->fin_ip + dpoff; + + if (len == fin->fin_plen) + fin->fin_flx |= FI_COALESCE; + return ip; +} +#endif /* _KERNEL && !__sgi */ + + +/* + * The following table lists all of the tunable variables that can be + * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row + * in the table below is as follows: + * + * pointer to value, name of value, minimum, maximum, size of the value's + * container, value attribute flags + * + * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED + * means the value can only be written to when IPFilter is loaded but disabled. + * The obvious implication is if neither of these are set then the value can be + * changed at any time without harm. + */ +ipftuneable_t ipf_tuneables[] = { + /* filtering */ + { { &fr_flags }, "fr_flags", 0, 0xffffffff, + sizeof(fr_flags), 0 }, + { { &fr_active }, "fr_active", 0, 0, + sizeof(fr_active), IPFT_RDONLY }, + { { &fr_control_forwarding }, "fr_control_forwarding", 0, 1, + sizeof(fr_control_forwarding), 0 }, + { { &fr_update_ipid }, "fr_update_ipid", 0, 1, + sizeof(fr_update_ipid), 0 }, + { { &fr_chksrc }, "fr_chksrc", 0, 1, + sizeof(fr_chksrc), 0 }, + { { &fr_pass }, "fr_pass", 0, 0xffffffff, + sizeof(fr_pass), 0 }, + { { &fr_unreach }, "fr_unreach", 0, 0xff, + sizeof(fr_unreach), 0 }, + /* state */ + { { &fr_tcpidletimeout }, "fr_tcpidletimeout", 1, 0x7fffffff, + sizeof(fr_tcpidletimeout), IPFT_WRDISABLED }, + { { &fr_tcpclosewait }, "fr_tcpclosewait", 1, 0x7fffffff, + sizeof(fr_tcpclosewait), IPFT_WRDISABLED }, + { { &fr_tcplastack }, "fr_tcplastack", 1, 0x7fffffff, + sizeof(fr_tcplastack), IPFT_WRDISABLED }, + { { &fr_tcptimeout }, "fr_tcptimeout", 1, 0x7fffffff, + sizeof(fr_tcptimeout), IPFT_WRDISABLED }, + { { &fr_tcpclosed }, "fr_tcpclosed", 1, 0x7fffffff, + sizeof(fr_tcpclosed), IPFT_WRDISABLED }, + { { &fr_tcphalfclosed }, "fr_tcphalfclosed", 1, 0x7fffffff, + sizeof(fr_tcphalfclosed), IPFT_WRDISABLED }, + { { &fr_udptimeout }, "fr_udptimeout", 1, 0x7fffffff, + sizeof(fr_udptimeout), IPFT_WRDISABLED }, + { { &fr_udpacktimeout }, "fr_udpacktimeout", 1, 0x7fffffff, + sizeof(fr_udpacktimeout), IPFT_WRDISABLED }, + { { &fr_icmptimeout }, "fr_icmptimeout", 1, 0x7fffffff, + sizeof(fr_icmptimeout), IPFT_WRDISABLED }, + { { &fr_icmpacktimeout }, "fr_icmpacktimeout", 1, 0x7fffffff, + sizeof(fr_icmpacktimeout), IPFT_WRDISABLED }, + { { &fr_statemax }, "fr_statemax", 1, 0x7fffffff, + sizeof(fr_statemax), 0 }, + { { &fr_statesize }, "fr_statesize", 1, 0x7fffffff, + sizeof(fr_statesize), IPFT_WRDISABLED }, + { { &fr_state_lock }, "fr_state_lock", 0, 1, + sizeof(fr_state_lock), IPFT_RDONLY }, + { { &fr_state_maxbucket }, "fr_state_maxbucket", 1, 0x7fffffff, + sizeof(fr_state_maxbucket), IPFT_WRDISABLED }, + { { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset", 0, 1, + sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED }, + { { &ipstate_logging }, "ipstate_logging", 0, 1, + sizeof(ipstate_logging), 0 }, + /* nat */ + { { &fr_nat_lock }, "fr_nat_lock", 0, 1, + sizeof(fr_nat_lock), IPFT_RDONLY }, + { { &ipf_nattable_sz }, "ipf_nattable_sz", 1, 0x7fffffff, + sizeof(ipf_nattable_sz), IPFT_WRDISABLED }, + { { &ipf_nattable_max }, "ipf_nattable_max", 1, 0x7fffffff, + sizeof(ipf_nattable_max), 0 }, + { { &ipf_natrules_sz }, "ipf_natrules_sz", 1, 0x7fffffff, + sizeof(ipf_natrules_sz), IPFT_WRDISABLED }, + { { &ipf_rdrrules_sz }, "ipf_rdrrules_sz", 1, 0x7fffffff, + sizeof(ipf_rdrrules_sz), IPFT_WRDISABLED }, + { { &ipf_hostmap_sz }, "ipf_hostmap_sz", 1, 0x7fffffff, + sizeof(ipf_hostmap_sz), IPFT_WRDISABLED }, + { { &fr_nat_maxbucket }, "fr_nat_maxbucket", 1, 0x7fffffff, + sizeof(fr_nat_maxbucket), IPFT_WRDISABLED }, + { { &fr_nat_maxbucket_reset }, "fr_nat_maxbucket_reset", 0, 1, + sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED }, + { { &nat_logging }, "nat_logging", 0, 1, + sizeof(nat_logging), 0 }, + { { &fr_defnatage }, "fr_defnatage", 1, 0x7fffffff, + sizeof(fr_defnatage), IPFT_WRDISABLED }, + { { &fr_defnaticmpage }, "fr_defnaticmpage", 1, 0x7fffffff, + sizeof(fr_defnaticmpage), IPFT_WRDISABLED }, + /* frag */ + { { &ipfr_size }, "ipfr_size", 1, 0x7fffffff, + sizeof(ipfr_size), IPFT_WRDISABLED }, + { { &fr_ipfrttl }, "fr_ipfrttl", 1, 0x7fffffff, + sizeof(fr_ipfrttl), IPFT_WRDISABLED }, +#ifdef IPFILTER_LOG + /* log */ + { { &ipl_suppress }, "ipl_suppress", 0, 1, + sizeof(ipl_suppress), 0 }, + { { &ipl_buffer_sz }, "ipl_buffer_sz", 0, 0, + sizeof(ipl_buffer_sz), IPFT_RDONLY }, + { { &ipl_logmax }, "ipl_logmax", 0, 0x7fffffff, + sizeof(ipl_logmax), IPFT_WRDISABLED }, + { { &ipl_logall }, "ipl_logall", 0, 1, + sizeof(ipl_logall), 0 }, +#endif + { { NULL }, NULL, 0, 0 } +}; + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipftune */ +/* Returns: int - 0 == success, else failure */ +/* Parameters: cmd(I) - ioctl command number */ +/* data(I) - pointer to ioctl data structure */ +/* */ +/* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ +/* three ioctls provide the means to access and control global variables */ +/* within IPFilter, allowing (for example) timeouts and table sizes to be */ +/* changed without rebooting, reloading or recompiling. The initialisation */ +/* and 'destruction' routines of the various components of ipfilter are all */ +/* each responsible for handling their own values being too big. */ +/* ------------------------------------------------------------------------ */ +int fr_ipftune(cmd, data) +ioctlcmd_t cmd; +void *data; +{ + ipftuneable_t *ta; + ipftune_t tu; + void *cookie; + int error; + + error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE); + if (error != 0) + return error; + + tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; + ta = ipf_tuneables; + cookie = tu.ipft_cookie; + + switch (cmd) + { + case SIOCIPFGETNEXT : + /* + * If cookie is non-NULL, assume it to be a pointer to the last + * entry we looked at, so find it (if possible) and return a + * pointer to the next one after it. The last entry in the + * the table is a NULL entry, so when we get to it, set cookie + * to NULL and return that, indicating end of list, erstwhile + * if we come in with cookie set to NULL, we are starting anew + * at the front of the list. + */ + if (cookie != NULL) { + for (; ta->ipft_name != NULL; ta++) + if (ta == cookie) { + ta++; + break; + } + if (ta->ipft_name == NULL) + ta = NULL; + } + cookie = ta; + tu.ipft_cookie = cookie; + if (ta != NULL) { + /* + * Entry found, but does the data pointed to by that + * row fit in what we can return? + */ + if (ta->ipft_sz > sizeof(tu.ipft_un)) + return EINVAL; + + tu.ipft_vlong = 0; + if (ta->ipft_sz == sizeof(u_long)) + tu.ipft_vlong = *ta->ipft_plong; + else if (ta->ipft_sz == sizeof(u_int)) + tu.ipft_vint = *ta->ipft_pint; + else if (ta->ipft_sz == sizeof(u_short)) + tu.ipft_vshort = *ta->ipft_pshort; + else if (ta->ipft_sz == sizeof(u_char)) + tu.ipft_vchar = *ta->ipft_pchar; + + tu.ipft_sz = ta->ipft_sz; + tu.ipft_min = ta->ipft_min; + tu.ipft_max = ta->ipft_max; + tu.ipft_flags = ta->ipft_flags; + bcopy(ta->ipft_name, tu.ipft_name, + MIN(sizeof(tu.ipft_name), + strlen(ta->ipft_name) + 1)); + } + error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); + break; + + case SIOCIPFGET : + case SIOCIPFSET : + /* + * Search by name or by cookie value for a particular entry + * in the tuning paramter table. + */ + error = ESRCH; + if (cookie != NULL) { + for (; ta->ipft_name != NULL; ta++) + if (ta == cookie) { + error = 0; + break; + } + } else if (tu.ipft_name[0] != '\0') { + for (; ta->ipft_name != NULL; ta++) + if (!strncmp(ta->ipft_name, tu.ipft_name, + MIN(sizeof(tu.ipft_name), + strlen(ta->ipft_name) + 1))) + break; + if (ta->ipft_name == NULL) + ta = NULL; + else + error = 0; + } + if (error != 0) + break; + + if (cmd == (ioctlcmd_t)SIOCIPFGET) { + /* + * Fetch the tuning parameters for a particular value + */ + tu.ipft_cookie = ta; + tu.ipft_vlong = 0; + if (ta->ipft_sz == sizeof(u_long)) + tu.ipft_vlong = *ta->ipft_plong; + else if (ta->ipft_sz == sizeof(u_int)) + tu.ipft_vint = *ta->ipft_pint; + else if (ta->ipft_sz == sizeof(u_short)) + tu.ipft_vshort = *ta->ipft_pshort; + else if (ta->ipft_sz == sizeof(u_char)) + tu.ipft_vchar = *ta->ipft_pchar; + tu.ipft_sz = ta->ipft_sz; + tu.ipft_min = ta->ipft_min; + tu.ipft_max = ta->ipft_max; + tu.ipft_flags = ta->ipft_flags; + error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); + + } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { + /* + * Set an internal parameter. The hard part here is + * getting the new value safely and correctly out of + * the kernel (given we only know its size, not type.) + */ + u_long in; + + if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && + (fr_running > 0)) { + error = EBUSY; + break; + } + + in = tu.ipft_vlong; + if (in < ta->ipft_min || in > ta->ipft_max) { + error = EINVAL; + break; + } + + if (ta->ipft_sz == sizeof(u_long)) { + tu.ipft_vlong = *ta->ipft_plong; + *ta->ipft_plong = in; + } else if (ta->ipft_sz == sizeof(u_int)) { + tu.ipft_vint = *ta->ipft_pint; + *ta->ipft_pint = (u_int)(in & 0xffffffff); + } else if (ta->ipft_sz == sizeof(u_short)) { + tu.ipft_vshort = *ta->ipft_pshort; + *ta->ipft_pshort = (u_short)(in & 0xffff); + } else if (ta->ipft_sz == sizeof(u_char)) { + tu.ipft_vchar = *ta->ipft_pchar; + *ta->ipft_pchar = (u_char)(in & 0xff); + } + error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); + } + break; + + default : + error = EINVAL; + break; + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_initialise */ +/* Returns: int - 0 == success, < 0 == failure */ +/* Parameters: None. */ +/* */ +/* Call of the initialise functions for all the various subsystems inside */ +/* of IPFilter. If any of them should fail, return immeadiately a failure */ +/* BUT do not try to recover from the error here. */ +/* ------------------------------------------------------------------------ */ +int fr_initialise() +{ + int i; + +#ifdef IPFILTER_LOG + i = fr_loginit(); + if (i < 0) + return -10 + i; +#endif + i = fr_natinit(); + if (i < 0) + return -20 + i; + + i = fr_stateinit(); + if (i < 0) + return -30 + i; + + i = fr_authinit(); + if (i < 0) + return -40 + i; + + i = fr_fraginit(); + if (i < 0) + return -50 + i; + + i = appr_init(); + if (i < 0) + return -60 + i; + +#ifdef IPFILTER_SYNC + i = ipfsync_init(); + if (i < 0) + return -70 + i; +#endif +#ifdef IPFILTER_SCAN + i = ipsc_init(); + if (i < 0) + return -80 + i; +#endif +#ifdef IPFILTER_LOOKUP + i = ip_lookup_init(); + if (i < 0) + return -90 + i; +#endif +#ifdef IPFILTER_COMPILED + ipfrule_add(); +#endif + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_deinitialise */ +/* Returns: None. */ +/* Parameters: None. */ +/* */ +/* Call all the various subsystem cleanup routines to deallocate memory or */ +/* destroy locks or whatever they've done that they need to now undo. */ +/* The order here IS important as there are some cross references of */ +/* internal data structures. */ +/* ------------------------------------------------------------------------ */ +void fr_deinitialise() +{ + fr_fragunload(); + fr_authunload(); + fr_stateunload(); +#ifdef IPFILTER_SCAN + fr_scanunload(); +#endif + fr_natunload(); + appr_unload(); + +#ifdef IPFILTER_COMPILED + ipfrule_remove(); +#endif + + (void) frflush(IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); + (void) frflush(IPL_LOGIPF, FR_INQUE|FR_OUTQUE); + +#ifdef IPFILTER_LOOKUP + ip_lookup_unload(); +#endif + +#ifdef IPFILTER_LOG + fr_logunload(); +#endif +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_zerostats */ +/* Returns: int - 0 = success, else failure */ +/* Parameters: data(O) - pointer to pointer for copying data back to */ +/* */ +/* Copies the current statistics out to userspace and then zero's the */ +/* current ones in the kernel. The lock is only held across the bzero() as */ +/* the copyout may result in paging (ie network activity.) */ +/* ------------------------------------------------------------------------ */ +int fr_zerostats(data) +caddr_t data; +{ + friostat_t fio; + int error; + + fr_getstat(&fio); + error = copyoutptr(&fio, data, sizeof(fio)); + if (error) + return EFAULT; + + WRITE_ENTER(&ipf_mutex); + bzero((char *)frstats, sizeof(*frstats) * 2); + RWLOCK_EXIT(&ipf_mutex); + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_resolvdest */ +/* Returns: Nil */ +/* Parameters: fdp(IO) - pointer to destination information to resolve */ +/* v(I) - IP protocol version to match */ +/* */ +/* Looks up an interface name in the frdest structure pointed to by fdp and */ +/* if a matching name can be found for the particular IP protocol version */ +/* then store the interface pointer in the frdest struct. If no match is */ +/* found, then set the interface pointer to be -1 as NULL is considered to */ +/* indicate there is no information at all in the structure. */ +/* ------------------------------------------------------------------------ */ +void fr_resolvdest(fdp, v) +frdest_t *fdp; +int v; +{ + void *ifp; + + ifp = NULL; + + if (*fdp->fd_ifname != '\0') { + ifp = GETIFP(fdp->fd_ifname, v); + if (ifp == NULL) + ifp = (void *)-1; + } + fdp->fd_ifp = ifp; +} diff --git a/sys/netinet/ip_auth.c b/sys/netinet/ip_auth.c index 9fedba2b91f9..f488119d7547 100644 --- a/sys/netinet/ip_auth.c +++ b/sys/netinet/ip_auth.c @@ -1,41 +1,49 @@ -/* $NetBSD: ip_auth.c,v 1.32 2003/08/22 21:53:03 itojun Exp $ */ +/* $NetBSD: ip_auth.c,v 1.33 2004/03/28 09:00:56 martti Exp $ */ /* - * Copyright (C) 1998-2001 by Darren Reed & Guido van Rooij. + * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. * * See the IPFILTER.LICENCE file for details on licencing. */ -#ifdef __sgi -# include +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include #include #include #include #include -#if !defined(_KERNEL) && !defined(KERNEL) +#if !defined(_KERNEL) # include # include # include +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include # include #else # include #endif -#ifndef linux +#if !defined(linux) # include #endif #include -#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +#if defined(_KERNEL) # include -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) # include # endif -#else +#endif +#if defined(__SVR4) || defined(__svr4__) # include # include # ifdef _KERNEL @@ -50,6 +58,9 @@ #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) # include #endif +#if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) +# include +#endif #include #ifdef sun # include @@ -58,28 +69,29 @@ #include #include #include -#ifndef KERNEL +#if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) # define KERNEL +# define _KERNEL # define NOT_KERNEL #endif -#ifndef linux +#if !defined(linux) # include #endif #ifdef NOT_KERNEL +# undef _KERNEL # undef KERNEL #endif -#ifdef __sgi -# ifdef IFF_DRVRLOCK /* IRIX6 */ -# include -# endif -#endif #include -#if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */ +#if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ extern struct ifqueue ipintrq; /* ip packet input queue */ #else -# ifndef linux +# if !defined(__hpux) && !defined(linux) # if __FreeBSD_version >= 300000 # include +# if __FreeBSD_version >= 500042 +# define IF_QFULL _IF_QFULL +# define IF_DROP _IF_DROP +# endif /* __FreeBSD_version >= 500042 */ # endif # include # include @@ -91,7 +103,7 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ #include #include "netinet/ip_fil.h" #include "netinet/ip_auth.h" -#if !SOLARIS && !defined(linux) +#if !defined(MENTAT) && !defined(linux) # include # ifdef __FreeBSD__ # include @@ -99,63 +111,94 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ #endif #if (__FreeBSD_version >= 300000) # include -# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# if defined(_KERNEL) && !defined(IPFILTER_LKM) # include # include # endif #endif +/* END OF INCLUDES */ #if !defined(lint) #if defined(__NetBSD__) #include -__KERNEL_RCSID(0, "$NetBSD: ip_auth.c,v 1.32 2003/08/22 21:53:03 itojun Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_auth.c,v 1.33 2004/03/28 09:00:56 martti Exp $"); #else -static const char rcsid[] = "@(#)Id: ip_auth.c,v 2.11.2.20 2002/06/04 14:40:42 darrenr Exp"; +static const char rcsid[] = "@(#)Id: ip_auth.c,v 2.73 2004/02/11 14:18:14 darrenr Exp"; #endif #endif -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_auth, ipf_mutex; -extern kmutex_t ipf_authmx; -# if SOLARIS +#if SOLARIS extern kcondvar_t ipfauthwait; -# endif -#endif -#ifdef linux -static struct wait_queue *ipfauthwait = NULL; +#endif /* SOLARIS */ +#if defined(linux) && defined(_KERNEL) +wait_queue_head_t fr_authnext_linux; #endif int fr_authsize = FR_NUMAUTH; int fr_authused = 0; int fr_defaultauthage = 600; int fr_auth_lock = 0; +int fr_auth_init = 0; fr_authstat_t fr_authstats; -static frauth_t fr_auth[FR_NUMAUTH]; -mb_t *fr_authpkts[FR_NUMAUTH]; -static int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; -static frauthent_t *fae_list = NULL; +static frauth_t *fr_auth = NULL; +mb_t **fr_authpkts = NULL; +int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; +frauthent_t *fae_list = NULL; frentry_t *ipauth = NULL, *fr_authlist = NULL; +int fr_authinit() +{ + KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); + if (fr_auth != NULL) + bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); + else + return -1; + + KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); + if (fr_authpkts != NULL) + bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); + else + return -1; + + MUTEX_INIT(&ipf_authmx, "ipf auth log mutex"); + RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock"); +#if SOLARIS && defined(_KERNEL) + cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL); +#endif +#if defined(linux) && defined(_KERNEL) + init_waitqueue_head(&fr_authnext_linux); +#endif + + fr_auth_init = 1; + + return 0; +} + + /* * Check if a packet has authorization. If the packet is found to match an * authorization result and that would result in a feedback loop (i.e. it * will end up returning FR_AUTH) then return FR_BLOCK instead. */ -u_32_t fr_checkauth(ip, fin) -ip_t *ip; +frentry_t *fr_checkauth(fin, passp) fr_info_t *fin; +u_32_t *passp; { - u_short id = ip->ip_id; frentry_t *fr; frauth_t *fra; u_32_t pass; + u_short id; + ip_t *ip; int i; if (fr_auth_lock || !fr_authused) - return 0; + return NULL; + + ip = fin->fin_ip; + id = ip->ip_id; READ_ENTER(&ipf_auth); for (i = fr_authstart; i != fr_authend; ) { @@ -170,7 +213,7 @@ fr_info_t *fin; /* * Avoid feedback loop. */ - if (!(pass = fra->fra_pass) || (pass & FR_AUTH)) + if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) pass = FR_BLOCK; /* * Create a dummy rule for the stateful checking to @@ -178,26 +221,26 @@ fr_info_t *fin; * trust from userland! */ if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && - (fin->fin_fi.fi_fl & FI_FRAG))) { + (fin->fin_flx & FI_FRAG))) { KMALLOC(fr, frentry_t *); if (fr) { bcopy((char *)fra->fra_info.fin_fr, - fr, sizeof(*fr)); + (char *)fr, sizeof(*fr)); fr->fr_grp = NULL; fr->fr_ifa = fin->fin_ifp; fr->fr_func = NULL; fr->fr_ref = 1; fr->fr_flags = pass; -#if BSD >= 199306 - fr->fr_oifa = NULL; -#endif + fr->fr_ifas[1] = NULL; + fr->fr_ifas[2] = NULL; + fr->fr_ifas[3] = NULL; } } else fr = fra->fra_info.fin_fr; fin->fin_fr = fr; RWLOCK_EXIT(&ipf_auth); WRITE_ENTER(&ipf_auth); - if (fr && fr != fra->fra_info.fin_fr) { + if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { fr->fr_next = fr_authlist; fr_authlist = fr; } @@ -208,7 +251,7 @@ fr_info_t *fin; while (fra->fra_index == -1) { i++; fra++; - if (i == FR_NUMAUTH) { + if (i == fr_authsize) { i = 0; fra = fr_auth; } @@ -222,15 +265,19 @@ fr_info_t *fin; } } RWLOCK_EXIT(&ipf_auth); - return pass; + if (passp != NULL) + *passp = pass; + ATOMIC_INCL(fr_authstats.fas_hits); + return fr; } i++; - if (i == FR_NUMAUTH) + if (i == fr_authsize) i = 0; } fr_authstats.fas_miss++; RWLOCK_EXIT(&ipf_auth); - return 0; + ATOMIC_INCL(fr_authstats.fas_miss); + return NULL; } @@ -239,15 +286,17 @@ fr_info_t *fin; * If we do, store it and wake up any user programs which are waiting to * hear about these events. */ -int fr_newauth(m, fin, ip) +int fr_newauth(m, fin) mb_t *m; fr_info_t *fin; -ip_t *ip; { -#if defined(_KERNEL) && SOLARIS - qif_t *qif = fin->fin_qif; +#if defined(_KERNEL) && defined(MENTAT) + qpktinfo_t *qpi = fin->fin_qpi; #endif frauth_t *fra; +#if !defined(sparc) && !defined(m68k) + ip_t *ip; +#endif int i; if (fr_auth_lock) @@ -259,7 +308,7 @@ ip_t *ip; RWLOCK_EXIT(&ipf_auth); return 0; } else { - if (fr_authused == FR_NUMAUTH) { + if (fr_authused == fr_authsize) { fr_authstats.fas_nospace++; RWLOCK_EXIT(&ipf_auth); return 0; @@ -269,21 +318,24 @@ ip_t *ip; fr_authstats.fas_added++; fr_authused++; i = fr_authend++; - if (fr_authend == FR_NUMAUTH) + if (fr_authend == fr_authsize) fr_authend = 0; RWLOCK_EXIT(&ipf_auth); + fra = fr_auth + i; fra->fra_index = i; fra->fra_pass = 0; fra->fra_age = fr_defaultauthage; bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); -#if SOLARIS && defined(_KERNEL) -# if !defined(sparc) +#if !defined(sparc) && !defined(m68k) /* * No need to copyback here as we want to undo the changes, not keep * them. */ - if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4)) + ip = fin->fin_ip; +# if defined(MENTAT) && defined(_KERNEL) + if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) +# endif { register u_short bo; @@ -292,159 +344,163 @@ ip_t *ip; bo = ip->ip_off; ip->ip_off = htons(bo); } -# endif - m->b_rptr -= qif->qf_off; +#endif +#if SOLARIS && defined(_KERNEL) + m->b_rptr -= qpi->qpi_off; fr_authpkts[i] = *(mblk_t **)fin->fin_mp; - fra->fra_q = qif->qf_q; + fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ cv_signal(&ipfauthwait); #else # if defined(BSD) && !defined(sparc) && (BSD >= 199306) if (!fin->fin_out) { - HTONS(ip->ip_len); - HTONS(ip->ip_off); + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); } # endif fr_authpkts[i] = m; - WAKEUP(&fr_authnext); + WAKEUP(&fr_authnext,0); #endif return 1; } -int fr_auth_ioctl(data, mode, cmd, fr, frptr) +int fr_auth_ioctl(data, cmd, mode) caddr_t data; +ioctlcmd_t cmd; int mode; -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -u_long cmd; -#else -int cmd; -#endif -frentry_t *fr, **frptr; { mb_t *m; -#if defined(_KERNEL) && !SOLARIS +#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ + (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) struct ifqueue *ifq; +# ifdef USE_SPL int s; +# endif /* USE_SPL */ #endif frauth_t auth, *au = &auth, *fra; - frauthent_t *fae, **faep; - int i, error = 0; + int i, error = 0, len; + char *t; switch (cmd) { case SIOCSTLCK : - error = fr_lock(data, &fr_auth_lock); - break; - case SIOCINIFR : - case SIOCRMIFR : - case SIOCADIFR : - error = EINVAL; - break; - case SIOCINAFR : - error = EINVAL; - break; - case SIOCRMAFR : - case SIOCADAFR : - for (faep = &fae_list; (fae = *faep); ) - if (&fae->fae_fr == fr) - break; - else - faep = &fae->fae_next; - if (cmd == SIOCRMAFR) { - if (!fr || !frptr) - error = EINVAL; - else if (!fae) - error = ESRCH; - else { - WRITE_ENTER(&ipf_auth); - SPL_NET(s); - *faep = fae->fae_next; - *frptr = fr->fr_next; - SPL_X(s); - RWLOCK_EXIT(&ipf_auth); - KFREE(fae); - } - } else if (fr && frptr) { - KMALLOC(fae, frauthent_t *); - if (fae != NULL) { - bcopy((char *)fr, (char *)&fae->fae_fr, - sizeof(*fr)); - WRITE_ENTER(&ipf_auth); - SPL_NET(s); - fae->fae_age = fr_defaultauthage; - fae->fae_fr.fr_hits = 0; - fae->fae_fr.fr_next = *frptr; - *frptr = &fae->fae_fr; - fae->fae_next = *faep; - *faep = fae; - ipauth = &fae_list->fae_fr; - SPL_X(s); - RWLOCK_EXIT(&ipf_auth); - } else - error = ENOMEM; - } else - error = EINVAL; - break; - case SIOCATHST: - fr_authstats.fas_faelist = fae_list; - error = IWCOPYPTR((char *)&fr_authstats, data, - sizeof(fr_authstats)); - break; - case SIOCAUTHW: if (!(mode & FWRITE)) { error = EPERM; break; } + error = fr_lock(data, &fr_auth_lock); + break; + + case SIOCATHST: + fr_authstats.fas_faelist = fae_list; + error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); + break; + + case SIOCIPFFL: + SPL_NET(s); + WRITE_ENTER(&ipf_auth); + i = fr_authflush(); + RWLOCK_EXIT(&ipf_auth); + SPL_X(s); + error = copyoutptr((char *)&i, data, sizeof(i)); + break; + + case SIOCAUTHW: fr_authioctlloop: + error = fr_inobj(data, au, IPFOBJ_FRAUTH); READ_ENTER(&ipf_auth); if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { - error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data, - sizeof(frauth_t)); + error = fr_outobj(data, &fr_auth[fr_authnext], + IPFOBJ_FRAUTH); + if (auth.fra_len != 0 && auth.fra_buf != NULL) { + /* + * Copy packet contents out to user space if + * requested. Bail on an error. + */ + m = fr_authpkts[fr_authnext]; + len = MSGDSIZE(m); + if (len > auth.fra_len) + len = auth.fra_len; + auth.fra_len = len; + for (t = auth.fra_buf; m && (len > 0); ) { + i = MIN(M_LEN(m), len); + error = copyoutptr(MTOD(m, char *), + t, i); + len -= i; + t += i; + if (error != 0) + break; + } + } RWLOCK_EXIT(&ipf_auth); - if (error) + if (error != 0) break; - WRITE_ENTER(&ipf_auth); SPL_NET(s); + WRITE_ENTER(&ipf_auth); fr_authnext++; - if (fr_authnext == FR_NUMAUTH) + if (fr_authnext == fr_authsize) fr_authnext = 0; - SPL_X(s); RWLOCK_EXIT(&ipf_auth); + SPL_X(s); return 0; } RWLOCK_EXIT(&ipf_auth); + /* + * We exit ipf_global here because a program that enters in + * here will have a lock on it and goto sleep having this lock. + * If someone were to do an 'ipf -D' the system would then + * deadlock. The catch with releasing it here is that the + * caller of this function expects it to be held when we + * return so we have to reacquire it in here. + */ + RWLOCK_EXIT(&ipf_global); + + MUTEX_ENTER(&ipf_authmx); #ifdef _KERNEL # if SOLARIS - mutex_enter(&ipf_authmx); - if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) { - mutex_exit(&ipf_authmx); - return EINTR; + error = 0; + if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) + error = EINTR; +# else /* SOLARIS */ +# ifdef __hpux + { + lock_t *l; + + l = get_sleep_lock(&fr_authnext); + error = sleep(&fr_authnext, PZERO+1); + spinunlock(l); } - mutex_exit(&ipf_authmx); -# else +# else +# ifdef __osf__ + error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, + &ipf_authmx, MS_LOCK_SIMPLE); +# else error = SLEEP(&fr_authnext, "fr_authnext"); -# endif +# endif /* __osf__ */ +# endif /* __hpux */ +# endif /* SOLARIS */ #endif - if (!error) + MUTEX_EXIT(&ipf_authmx); + READ_ENTER(&ipf_global); + if (error == 0) { + READ_ENTER(&ipf_auth); goto fr_authioctlloop; - break; - case SIOCAUTHR: - if (!(mode & FWRITE)) { - error = EPERM; - break; } - error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth)); - if (error) + break; + + case SIOCAUTHR: + error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); + if (error != 0) return error; - WRITE_ENTER(&ipf_auth); SPL_NET(s); + WRITE_ENTER(&ipf_auth); i = au->fra_index; fra = fr_auth + i; - if ((i < 0) || (i > FR_NUMAUTH) || + if ((i < 0) || (i >= fr_authsize) || (fra->fra_info.fin_id != au->fra_info.fin_id)) { - SPL_X(s); RWLOCK_EXIT(&ipf_auth); - return EINVAL; + SPL_X(s); + return ESRCH; } m = fr_authpkts[i]; fra->fra_index = -2; @@ -452,59 +508,67 @@ fr_authioctlloop: fr_authpkts[i] = NULL; RWLOCK_EXIT(&ipf_auth); #ifdef _KERNEL - if (m && au->fra_info.fin_out) { -# if SOLARIS - error = (fr_qout(fra->fra_q, m) == 0) ? EINVAL : 0; -# else /* SOLARIS */ - struct route ro; - - bzero((char *)&ro, sizeof(ro)); -# if ((_BSDI_VERSION >= 199802) && (_BSDI_VERSION < 200005)) || \ - defined(__OpenBSD__) || (defined(IRIX) && (IRIX >= 605)) - error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL, - NULL); + if ((m != NULL) && (au->fra_info.fin_out != 0)) { +# ifdef MENTAT + error = !putq(fra->fra_q, m); +# else /* MENTAT */ +# ifdef linux # else - error = ip_output(m, NULL, &ro, IP_FORWARDING, - (struct ip_moptions *)NULL, (struct socket *)NULL); -# endif - if (ro.ro_rt) { - RTFREE(ro.ro_rt); - } -# endif /* SOLARIS */ - if (error) +# if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ + (defined(__sgi) && (IRIX >= 60500) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, + NULL); +# else + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); +# endif +# endif /* Linux */ +# endif /* MENTAT */ + if (error != 0) fr_authstats.fas_sendfail++; else fr_authstats.fas_sendok++; } else if (m) { -# if SOLARIS - error = (fr_qin(fra->fra_q, m) == 0) ? EINVAL : 0; -# else /* SOLARIS */ +# ifdef MENTAT + error = !putq(fra->fra_q, m); +# else /* MENTAT */ +# ifdef linux +# else +# if __FreeBSD_version >= 501000 + netisr_dispatch(NETISR_IP, m); +# else +# if IRIX >= 60516 + ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; +# else ifq = &ipintrq; +# endif if (IF_QFULL(ifq)) { IF_DROP(ifq); - m_freem(m); + FREE_MB_T(m); error = ENOBUFS; } else { IF_ENQUEUE(ifq, m); -# if IRIX < 605 +# if IRIX < 60500 schednetisr(NETISR_IP); -# endif +# endif } -# endif /* SOLARIS */ - if (error) +# endif +# endif /* Linux */ +# endif /* MENTAT */ + if (error != 0) fr_authstats.fas_quefail++; else fr_authstats.fas_queok++; } else error = EINVAL; -# if SOLARIS - if (error) +# ifdef MENTAT + if (error != 0) error = EINVAL; -# else +# else /* MENTAT */ /* * If we experience an error which will result in the packet * not being processed, make sure we advance to the next one. - */ + */ if (error == ENOBUFS) { fr_authused--; fra->fra_index = -1; @@ -512,7 +576,7 @@ fr_authioctlloop: if (i == fr_authstart) { while (fra->fra_index == -1) { i++; - if (i == FR_NUMAUTH) + if (i == fr_authsize) i = 0; fr_authstart = i; if (i == fr_authend) @@ -524,10 +588,11 @@ fr_authioctlloop: } } } -# endif +# endif /* MENTAT */ #endif /* _KERNEL */ SPL_X(s); break; + default : error = EINVAL; break; @@ -546,41 +611,48 @@ void fr_authunload() frentry_t *fr, **frp; mb_t *m; - WRITE_ENTER(&ipf_auth); - for (i = 0; i < FR_NUMAUTH; i++) { - if ((m = fr_authpkts[i])) { - FREE_MB_T(m); - fr_authpkts[i] = NULL; - fr_auth[i].fra_index = -1; - } + if (fr_auth != NULL) { + KFREES(fr_auth, fr_authsize * sizeof(*fr_auth)); + fr_auth = NULL; } + if (fr_authpkts != NULL) { + for (i = 0; i < fr_authsize; i++) { + m = fr_authpkts[i]; + if (m != NULL) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + } + } + KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); + fr_authpkts = NULL; + } - for (faep = &fae_list; (fae = *faep); ) { + faep = &fae_list; + while ((fae = *faep) != NULL) { *faep = fae->fae_next; KFREE(fae); } ipauth = NULL; - RWLOCK_EXIT(&ipf_auth); - if (fr_authlist) { - /* - * We *MuST* reget ipf_auth because otherwise we won't get the - * locks in the right order and risk deadlock. - * We need ipf_mutex here to prevent a rule from using it - * inside fr_check(). - */ - WRITE_ENTER(&ipf_mutex); - WRITE_ENTER(&ipf_auth); - for (frp = &fr_authlist; (fr = *frp); ) { + if (fr_authlist != NULL) { + for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { if (fr->fr_ref == 1) { *frp = fr->fr_next; KFREE(fr); } else frp = &fr->fr_next; } - RWLOCK_EXIT(&ipf_auth); - RWLOCK_EXIT(&ipf_mutex); + } + + if (fr_auth_init == 1) { +# if SOLARIS && defined(_KERNEL) + cv_destroy(&ipfauthwait); +# endif + MUTEX_DESTROY(&ipf_authmx); + RW_DESTROY(&ipf_auth); + + fr_auth_init = 0; } } @@ -596,17 +668,18 @@ void fr_authexpire() register frauthent_t *fae, **faep; register frentry_t *fr, **frp; mb_t *m; -#if !SOLARIS && defined(_KERNEL) +# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL) int s; -#endif +# endif if (fr_auth_lock) return; SPL_NET(s); WRITE_ENTER(&ipf_auth); - for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { - if ((!--fra->fra_age) && (m = fr_authpkts[i])) { + for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) { + fra->fra_age--; + if ((fra->fra_age == 0) && (m = fr_authpkts[i])) { FREE_MB_T(m); fr_authpkts[i] = NULL; fr_auth[i].fra_index = -1; @@ -615,8 +688,9 @@ void fr_authexpire() } } - for (faep = &fae_list; (fae = *faep); ) { - if (!--fae->fae_age) { + for (faep = &fae_list; ((fae = *faep) != NULL); ) { + fae->fae_age--; + if (fae->fae_age == 0) { *faep = fae->fae_next; KFREE(fae); fr_authstats.fas_expire++; @@ -628,7 +702,7 @@ void fr_authexpire() else ipauth = NULL; - for (frp = &fr_authlist; (fr = *frp); ) { + for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { if (fr->fr_ref == 1) { *frp = fr->fr_next; KFREE(fr); @@ -638,3 +712,98 @@ void fr_authexpire() RWLOCK_EXIT(&ipf_auth); SPL_X(s); } + +int fr_preauthcmd(cmd, fr, frptr) +ioctlcmd_t cmd; +frentry_t *fr, **frptr; +{ + frauthent_t *fae, **faep; + int error = 0; +# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL) + int s; +#endif + + if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) + return EIO; + + for (faep = &fae_list; ((fae = *faep) != NULL); ) { + if (&fae->fae_fr == fr) + break; + else + faep = &fae->fae_next; + } + + if (cmd == (ioctlcmd_t)SIOCRMAFR) { + if (fr == NULL || frptr == NULL) + error = EINVAL; + else if (fae == NULL) + error = ESRCH; + else { + SPL_NET(s); + WRITE_ENTER(&ipf_auth); + *faep = fae->fae_next; + if (ipauth == &fae->fae_fr) + ipauth = fae_list ? &fae_list->fae_fr : NULL; + RWLOCK_EXIT(&ipf_auth); + SPL_X(s); + + KFREE(fae); + } + } else if (fr != NULL && frptr != NULL) { + KMALLOC(fae, frauthent_t *); + if (fae != NULL) { + bcopy((char *)fr, (char *)&fae->fae_fr, + sizeof(*fr)); + SPL_NET(s); + WRITE_ENTER(&ipf_auth); + fae->fae_age = fr_defaultauthage; + fae->fae_fr.fr_hits = 0; + fae->fae_fr.fr_next = *frptr; + *frptr = &fae->fae_fr; + fae->fae_next = *faep; + *faep = fae; + ipauth = &fae_list->fae_fr; + RWLOCK_EXIT(&ipf_auth); + SPL_X(s); + } else + error = ENOMEM; + } else + error = EINVAL; + return error; +} + + +/* + * Flush held packets. + * Must already be properly SPL'ed and Locked on &ipf_auth. + * + */ +int fr_authflush() +{ + register int i, num_flushed; + mb_t *m; + + if (fr_auth_lock) + return -1; + + num_flushed = 0; + + for (i = 0 ; i < fr_authsize; i++) { + m = fr_authpkts[i]; + if (m != NULL) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + fr_auth[i].fra_index = -1; + /* perhaps add & use a flush counter inst.*/ + fr_authstats.fas_expire++; + fr_authused--; + num_flushed++; + } + } + + fr_authstart = 0; + fr_authend = 0; + fr_authnext = 0; + + return num_flushed; +} diff --git a/sys/netinet/ip_auth.h b/sys/netinet/ip_auth.h index 837f51fe3a09..bee3e47f9ce0 100644 --- a/sys/netinet/ip_auth.h +++ b/sys/netinet/ip_auth.h @@ -1,11 +1,11 @@ -/* $NetBSD: ip_auth.h,v 1.10 2002/01/24 08:23:41 martti Exp $ */ +/* $NetBSD: ip_auth.h,v 1.11 2004/03/28 09:00:56 martti Exp $ */ /* * Copyright (C) 1997-2001 by Darren Reed & Guido Van Rooij. * * See the IPFILTER.LICENCE file for details on licencing. * - * Id: ip_auth.h,v 2.3.2.5 2001/11/04 13:15:51 darrenr Exp + * Id: ip_auth.h,v 2.16 2003/07/25 12:29:56 darrenr Exp * */ #ifndef _NETINET_IP_AUTH_H_ @@ -15,10 +15,12 @@ typedef struct frauth { int fra_age; + int fra_len; int fra_index; u_32_t fra_pass; fr_info_t fra_info; -#if SOLARIS + char *fra_buf; +#ifdef MENTAT queue_t *fra_q; #endif } frauth_t; @@ -46,18 +48,19 @@ typedef struct fr_authstat { extern frentry_t *ipauth; extern struct fr_authstat fr_authstats; extern int fr_defaultauthage; +extern int fr_authstart; +extern int fr_authend; extern int fr_authsize; extern int fr_authused; extern int fr_auth_lock; -extern u_32_t fr_checkauth __P((ip_t *, fr_info_t *)); +extern frentry_t *fr_checkauth __P((fr_info_t *, u_32_t *)); extern void fr_authexpire __P((void)); +extern int fr_authinit __P((void)); extern void fr_authunload __P((void)); -extern mb_t *fr_authpkts[]; -extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); -#if defined(__NetBSD__) || defined(__OpenBSD__) || \ - (__FreeBSD_version >= 300003) -extern int fr_auth_ioctl __P((caddr_t, int, u_long, frentry_t *, frentry_t **)); -#else -extern int fr_auth_ioctl __P((caddr_t, int, int, frentry_t *, frentry_t **)); -#endif -#endif /* _NETINET_IP_AUTH_H_ */ +extern int fr_authflush __P((void)); +extern mb_t **fr_authpkts; +extern int fr_newauth __P((mb_t *, fr_info_t *)); +extern int fr_preauthcmd __P((ioctlcmd_t, frentry_t *, frentry_t **)); +extern int fr_auth_ioctl __P((caddr_t, ioctlcmd_t, int)); + +#endif /* __IP_AUTH_H__ */ diff --git a/sys/netinet/ip_compat.h b/sys/netinet/ip_compat.h index 8d951fc57324..108f94e9f3d9 100644 --- a/sys/netinet/ip_compat.h +++ b/sys/netinet/ip_compat.h @@ -1,12 +1,12 @@ -/* $NetBSD: ip_compat.h,v 1.34 2003/06/26 00:43:32 itojun Exp $ */ +/* $NetBSD: ip_compat.h,v 1.35 2004/03/28 09:00:56 martti Exp $ */ /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_compat.h 1.8 1/14/96 - * Id: ip_compat.h,v 2.26.2.46 2002/06/27 14:39:40 darrenr Exp + * Id: ip_compat.h,v 2.142.2.2 2004/03/23 12:03:42 darrenr Exp */ #ifndef _NETINET_IP_COMPAT_H_ @@ -24,25 +24,6 @@ # define const #endif -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif -#if SOLARIS -# if !defined(SOLARIS2) -# define SOLARIS2 3 /* Pick an old version */ -# endif -# if SOLARIS2 >= 8 -# ifndef USE_INET6 -# define USE_INET6 -# endif -# else -# undef USE_INET6 -# endif -#endif -#if defined(sun) && !(defined(__svr4__) || defined(__SVR4)) -# undef USE_INET6 -#endif - #if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL__) # undef KERNEL # undef _KERNEL @@ -52,27 +33,51 @@ # define __KERNEL__ #endif +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif +#if SOLARIS2 >= 8 +# ifndef USE_INET6 +# define USE_INET6 +# endif +#endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ + !defined(_KERNEL) +# define USE_INET6 +#endif +#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000) && \ + !defined(_KERNEL) +# define USE_INET6 +#endif +#if defined(OpenBSD) && (OpenBSD >= 200206) && !defined(_KERNEL) +# define USE_INET6 +#endif +#if defined(__osf__) +# define USE_INET6 +#endif +#if defined(linux) && defined(CONFIG_IPV6) +# define USE_INET6 +#endif +#if defined(HPUXREV) && (HPUXREV >= 1111) +# define USE_INET6 +#endif + +#if defined(BSD) && (BSD < 199103) && defined(__osf__) +# undef BSD +# define BSD 199103 +#endif + #if defined(__SVR4) || defined(__svr4__) || defined(__sgi) -#define index strchr -# if !defined(KERNEL) +# define index strchr +# if !defined(_KERNEL) # define bzero(a,b) memset(a,0,b) # define bcmp memcmp # define bcopy(a,b,c) memmove(b,a,c) # endif #endif -#ifndef offsetof -#define offsetof(t,m) (int)((&((t *)0L)->m)) -#endif - -#if defined(__sgi) || defined(bsdi) -struct ether_addr { - u_char ether_addr_octet[6]; -}; -#endif - -#ifndef LIFNAMSIZ -# ifdef IF_NAMESIZE +#ifndef LIFNAMSIZ +# ifdef IF_NAMESIZE # define LIFNAMSIZ IF_NAMESIZE # else # ifdef IFNAMSIZ @@ -83,6 +88,12 @@ struct ether_addr { # endif #endif +#if defined(__sgi) || defined(bsdi) || defined(__hpux) || defined(hpux) +struct ether_addr { + u_char ether_addr_octet[6]; +}; +#endif + #if defined(__sgi) && !defined(IPFILTER_LKM) # ifdef __STDC__ # define IPL_EXTERN(ep) ipfilter##ep @@ -97,114 +108,1201 @@ struct ether_addr { # endif #endif -#ifdef __sgi -# include -#endif - -#ifdef linux -# include -#endif - /* * This is a workaround for troubles on FreeBSD and OpenBSD. */ -#ifndef _KERNEL -# define ADD_KERNEL -# define _KERNEL -# define KERNEL -#endif -#ifdef __OpenBSD__ +#ifndef linux +# ifndef _KERNEL +# define ADD_KERNEL +# define _KERNEL +# define KERNEL +# endif +# ifdef __OpenBSD__ struct file; -#endif -#include -#ifdef ADD_KERNEL -# undef _KERNEL -# undef KERNEL +# endif +# include +# ifdef ADD_KERNEL +# undef _KERNEL +# undef KERNEL +# endif #endif -#if SOLARIS -# define MTYPE(m) ((m)->b_datap->db_type) -# if SOLARIS2 >= 4 -# include -# endif + +/* ----------------------------------------------------------------------- */ +/* S O L A R I S */ +/* ----------------------------------------------------------------------- */ +#if SOLARIS +# define MENTAT 1 +# include +# include +# include # include # include # include +# if SOLARIS2 >= 10 +# include +# include +# include +# include +# endif /* * because Solaris 2 defines these in two places :-/ */ +# ifndef KERNEL +# define _KERNEL +# undef RES_INIT +# endif /* _KERNEL */ + +# if SOLARIS2 >= 8 +# include +# include +# endif + +# include +/* These 5 are defined in and */ # undef IPOPT_EOL # undef IPOPT_NOP # undef IPOPT_LSRR # undef IPOPT_RR # undef IPOPT_SSRR +# ifdef i386 +# define _SYS_PROMIF_H +# endif +# include +# undef COPYOUT +# include # ifndef KERNEL -# define _KERNEL -# undef RES_INIT -# if SOLARIS2 >= 8 -# include -# endif -# include -# include -# include # undef _KERNEL -# else /* _KERNEL */ -# if SOLARIS2 >= 8 -# include -# endif -# include -# include -# include -# endif /* _KERNEL */ +# endif # if SOLARIS2 >= 8 +# define SNPRINTF snprintf + # include -# include # define ipif_local_addr ipif_lcl_addr /* Only defined in private include file */ # ifndef V4_PART_OF_V6 # define V4_PART_OF_V6(v6) v6.s6_addr32[3] # endif +struct ip6_ext { + u_char ip6e_nxt; + u_char ip6e_len; +}; +# endif /* SOLARIS2 >= 8 */ + +# if SOLARIS2 >= 6 +# include +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; +# endif +# define U_32_T 1 + +# ifdef _KERNEL +# define KRWLOCK_T krwlock_t +# define KMUTEX_T kmutex_t +# include "qif.h" +# include "pfil.h" +# if SOLARIS2 >= 6 +# if SOLARIS2 == 6 +# define ATOMIC_INCL(x) atomic_add_long((uint32_t*)&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long((uint32_t*)&(x), -1) +# else +# define ATOMIC_INCL(x) atomic_add_long(&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long(&(x), -1) +# endif /* SOLARIS2 == 6 */ +# define ATOMIC_INC64(x) atomic_add_64((uint64_t*)&(x), 1) +# define ATOMIC_INC32(x) atomic_add_32((uint32_t*)&(x), 1) +# define ATOMIC_INC16(x) atomic_add_16((uint16_t*)&(x), 1) +# define ATOMIC_DEC64(x) atomic_add_64((uint64_t*)&(x), -1) +# define ATOMIC_DEC32(x) atomic_add_32((uint32_t*)&(x), -1) +# define ATOMIC_DEC16(x) atomic_add_16((uint16_t*)&(x), -1) +# else +# define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ + mutex_exit(&ipf_rw); } +# define ATOMIC_DEC(x) { mutex_enter(&ipf_rw); (x)--; \ + mutex_exit(&ipf_rw); } +# endif /* SOLARIS2 >= 6 */ +# define USE_MUTEXES +# define MUTEX_ENTER(x) mutex_enter(&(x)->ipf_lk) +# define READ_ENTER(x) rw_enter(&(x)->ipf_lk, RW_READER) +# define WRITE_ENTER(x) rw_enter(&(x)->ipf_lk, RW_WRITER) +# define MUTEX_DOWNGRADE(x) rw_downgrade(&(x)->ipf_lk) +# define RWLOCK_INIT(x, y) rw_init(&(x)->ipf_lk, (y), \ + RW_DRIVER, NULL) +# define RWLOCK_EXIT(x) rw_exit(&(x)->ipf_lk) +# define RW_DESTROY(x) rw_destroy(&(x)->ipf_lk) +# define MUTEX_INIT(x, y) mutex_init(&(x)->ipf_lk, (y), \ + MUTEX_DRIVER, NULL) +# define MUTEX_DESTROY(x) mutex_destroy(&(x)->ipf_lk) +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) +# define MUTEX_EXIT(x) mutex_exit(&(x)->ipf_lk) +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) (void) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) (void) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +# ifdef sparc +# define ntohs(x) (x) +# define ntohl(x) (x) +# define htons(x) (x) +# define htonl(x) (x) +# endif /* sparc */ +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define GET_MINOR(x) getminor(x) +extern void *get_unit __P((char *, int)); +# define GETIFP(n, v) get_unit(n, v) +# define IFNAME(x) ((qif_t *)x)->qf_name +# define COPYIFNAME(x, b) \ + (void) strncpy(b, ((qif_t *)x)->qf_name, \ + LIFNAMSIZ) +# define GETKTIME(x) uniqtime((struct timeval *)x) +# define MSGDSIZE(x) msgdsize(x) +# define M_LEN(x) ((x)->b_wptr - (x)->b_rptr) +# define M_DUPLICATE(x) dupmsg((x)) +# define MTOD(m,t) ((t)((m)->b_rptr)) +# define MTYPE(m) ((m)->b_datap->db_type) +# define FREE_MB_T(m) freemsg(m) +# define m_next b_cont +# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7) +# define IPF_PANIC(x,y) if (x) { printf y; cmn_err(CE_PANIC, "ipf_panic"); } +typedef mblk_t mb_t; +# endif /* _KERNEL */ + +# if (SOLARIS2 >= 7) +# ifdef lint +# define ALIGN32(ptr) (ptr ? 0L : 0L) +# define ALIGN16(ptr) (ptr ? 0L : 0L) +# else +# define ALIGN32(ptr) (ptr) +# define ALIGN16(ptr) (ptr) +# endif # endif -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; - struct qinit *qf_wqinfo; - struct qinit *qf_rqinfo; - struct qinit qf_wqinit; - struct qinit qf_rqinit; - mblk_t *qf_m; /* These three fields are for passing data up from */ - queue_t *qf_q; /* fr_qin and fr_qout to the packet processing. */ - size_t qf_off; - size_t qf_len; /* this field is used for in ipfr_fastroute */ - char qf_name[LIFNAMSIZ]; - /* - * in case the ILL has disappeared... - */ - size_t qf_hl; /* header length */ - int qf_sap; -# if SOLARIS2 >= 8 - int qf_tunoff; /* tunnel offset */ -#endif - size_t qf_incnt; - size_t qf_outcnt; -} qif_t; -#else /* SOLARIS */ -# if !defined(__sgi) -typedef int minor_t; +# if SOLARIS2 < 6 +typedef struct uio uio_t; # endif +typedef int ioctlcmd_t; + +# define OS_RECOGNISED 1 + #endif /* SOLARIS */ -#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) + +/* ----------------------------------------------------------------------- */ +/* H P U X */ +/* ----------------------------------------------------------------------- */ +#ifdef __hpux +# define MENTAT 1 +# include +# include +# include +# include +# ifdef USE_INET6 +# include +# include +# include +typedef struct ip6_hdr ip6_t; +# endif + +# ifdef _KERNEL +# define SNPRINTF sprintf +# if (HPUXREV >= 1111) +# define IPL_SELECT +# ifdef IPL_SELECT +# include +# include +# define READ_COLLISION 0x01 + +typedef struct iplog_select_s { + kthread_t *read_waiter; + int state; +} iplog_select_t; +# endif +# endif + +# define GETKTIME(x) uniqtime((struct timeval *)x) + +# if HPUXREV == 1111 +# include "kern_svcs.h" +# else +# include +# endif +# undef ti_flags +# undef TCP_NODELAY +# undef TCP_MAXSEG +# include +# include "../netinet/ip_info.h" +/* + * According to /usr/include/sys/spinlock.h on HP-UX 11.00, these functions + * are available. Attempting to use them actually results in unresolved + * symbols when it comes time to load the module. + * This has been fixed! Yipee! + */ +# if 1 +# ifdef __LP64__ +# define ATOMIC_INCL(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_DECL(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1) +# else +# define ATOMIC_INCL(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_DECL(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1) +# endif +# define ATOMIC_INC64(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_INC32(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_INC16(x) lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), 1) +# define ATOMIC_DEC64(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1) +# define ATOMIC_DEC32(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1) +# define ATOMIC_DEC16(x) lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), -1) +# else /* 0 */ +# define ATOMIC_INC64(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC64(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INC32(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC32(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INCL(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DECL(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# endif +# define ip_cksum ip_csuma +# define memcpy(a,b,c) bcopy((caddr_t)b, (caddr_t)a, c) +# define USE_MUTEXES +# define MUTEX_INIT(x, y) initlock(&(x)->ipf_lk, 0, 0, (y)) +# define MUTEX_ENTER(x) spinlock(&(x)->ipf_lk) +# define MUTEX_EXIT(x) spinunlock(&(x)->ipf_lk); +# define MUTEX_DESTROY(x) +# define MUTEX_NUKE(x) bzero((char *)(x), sizeof(*(x))) +# define KMUTEX_T lock_t +# define kmutex_t lock_t /* for pfil.h */ +# define krwlock_t lock_t /* for pfil.h */ +/* + * The read-write lock implementation in HP-UX 11.0 is crippled - it can + * only be used by threads working in a user context! + * This has been fixed! Yipee! (Or at least it does in 11.00, not 11.11..) + */ +# if HPUXREV < 1111 +# define MUTEX_DOWNGRADE(x) lock_write_to_read(x) +# define KRWLOCK_T struct rw_lock +# define READ_ENTER(x) lock_read(&(x)->ipf_lk) +# define WRITE_ENTER(x) lock_write(&(x)->ipf_lk) +# if HPUXREV >= 1111 +# define RWLOCK_INIT(x, y) rwlock_init4(&(x)->ipf_lk, 0, RWLCK_CANSLEEP, 0, y) +# else +# define RWLOCK_INIT(x, y) lock_init3(&(x)->ipf_lk, 0, 1, 0, 0, y) +# endif +# define RWLOCK_EXIT(x) lock_done(&(x)->ipf_lk) +# else +# define KRWLOCK_T lock_t +# define KMUTEX_T lock_t +# define READ_ENTER(x) MUTEX_ENTER(x) +# define WRITE_ENTER(x) MUTEX_ENTER(x) +# define MUTEX_DOWNGRADE(x) +# define RWLOCK_INIT(x, y) initlock(&(x)->ipf_lk, 0, 0, y) +# define RWLOCK_EXIT(x) MUTEX_EXIT(x) +# endif +# define RW_DESTROY(x) +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# if HPUXREV >= 1111 +# define BCOPYIN(a,b,c) 0; bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) 0; bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# else +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# endif +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +extern void *get_unit __P((char *, int)); +# define GETIFP(n, v) get_unit(n, v) +# define IFNAME(x, b) ((ill_t *)x)->ill_name +# define COPYIFNAME(x, b) \ + (void) strncpy(b, ((qif_t *)x)->qf_name, \ + LIFNAMSIZ) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define SLEEP(id, n) { lock_t *_l = get_sleep_lock((caddr_t)id); \ + sleep(id, PZERO+1); \ + spinunlock(_l); \ + } +# define WAKEUP(id,x) { lock_t *_l = get_sleep_lock((caddr_t)id); \ + wakeup(id + x); \ + spinunlock(_l); \ + } +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_IOSYS, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_IOSYS, M_NOWAIT) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define MSGDSIZE(x) msgdsize(x) +# define M_LEN(x) ((x)->b_wptr - (x)->b_rptr) +# define M_DUPLICATE(x) dupmsg((x)) +# define MTOD(m,t) ((t)((m)->b_rptr)) +# define MTYPE(m) ((m)->b_datap->db_type) +# define FREE_MB_T(m) freemsg(m) +# define m_next b_cont +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef mblk_t mb_t; + +# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7) + +# include "qif.h" +# include "pfil.h" + +# else /* _KERNEL */ + +typedef unsigned char uchar_t; + +# ifndef _SYS_STREAM_INCLUDED +typedef char * mblk_t; +typedef void * queue_t; +typedef u_long ulong; +# endif +# include + +# endif /* _KERNEL */ + +# ifdef lint +# define ALIGN32(ptr) (ptr ? 0L : 0L) +# define ALIGN16(ptr) (ptr ? 0L : 0L) +# else +# define ALIGN32(ptr) (ptr) +# define ALIGN16(ptr) (ptr) +# endif + +typedef struct uio uio_t; +typedef int ioctlcmd_t; +typedef int minor_t; +typedef unsigned int u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 + +#endif /* __hpux */ + +/* ----------------------------------------------------------------------- */ +/* I R I X */ +/* ----------------------------------------------------------------------- */ +#ifdef __sgi +# undef MENTAT +# if IRIX < 60500 +typedef struct uio uio_t; +# endif +typedef int ioctlcmd_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# ifdef INET6 +# define USE_INET6 +# endif + +# define hz HZ +# include +# define IPF_LOCK_PL plhi +# include +# undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; + +# ifdef MUTEX_INIT +# define KMUTEX_T mutex_t +# else +# define KMUTEX_T kmutex_t +# define KRWLOCK_T kmutex_t +# endif + +# ifdef _KERNEL +# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)++; MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)--; MUTEX_EXIT(&ipf_rw); } +# define USE_MUTEXES +# ifdef MUTEX_INIT +# include +# define ATOMIC_INCL(x) atomicAddUlong(&(x), 1) +# define ATOMIC_INC64(x) atomicAddUint64(&(x), 1) +# define ATOMIC_INC32(x) atomicAddUint(&(x), 1) +# define ATOMIC_INC16 ATOMIC_INC +# define ATOMIC_DECL(x) atomicAddUlong(&(x), -1) +# define ATOMIC_DEC64(x) atomicAddUint64(&(x), -1) +# define ATOMIC_DEC32(x) atomicAddUint(&(x), -1) +# define ATOMIC_DEC16 ATOMIC_DEC +# undef MUTEX_INIT +# define MUTEX_INIT(x, y) mutex_init(&(x)->ipf_lk, \ + MUTEX_DEFAULT, y) +# undef MUTEX_ENTER +# define MUTEX_ENTER(x) mutex_lock(&(x)->ipf_lk, 0) +# undef MUTEX_EXIT +# define MUTEX_EXIT(x) mutex_unlock(&(x)->ipf_lk) +# undef MUTEX_DESTROY +# define MUTEX_DESTROY(x) mutex_destroy(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) mrdemote(&(x)->ipf_lk) +# define KRWLOCK_T mrlock_t +# define RWLOCK_INIT(x, y) mrinit(&(x)->ipf_lk, y) +# undef RW_DESTROY +# define RW_DESTROY(x) mrfree(&(x)->ipf_lk) +# define READ_ENTER(x) RW_RDLOCK(&(x)->ipf_lk) +# define WRITE_ENTER(x) RW_WRLOCK(&(x)->ipf_lk) +# define RWLOCK_EXIT(x) RW_UNLOCK(&(x)->ipf_lk) +# else +# define READ_ENTER(x) MUTEX_ENTER(&(x)->ipf_lk) +# define WRITE_ENTER(x) MUTEX_ENTER(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_EXIT(x) MUTEX_EXIT(&(x)->ipf_lk) +# define MUTEX_EXIT(x) UNLOCK((x)->ipf_lk.l, (x)->ipf_lk.pl); +# define MUTEX_INIT(x,y) (x)->ipf_lk.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->ipf_lk.l) +# define MUTEX_ENTER(x) (x)->ipf_lk.pl = LOCK((x)->ipf_lk.l, \ + IPF_LOCK_PL); +# endif +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) +# define FREE_MB_T(m) m_freem(m) +# define MTOD(m,t) mtod(m,t) +# define COPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define COPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define SLEEP(id, n) sleep((id), PZERO+1) +# define WAKEUP(id,x) wakeup(id+x) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define GETIFP(n,v) ifunit(n) +# include +# include +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define GET_MINOR(x) getminor(x) +# define USE_SPL 1 +# define SPL_IMP(x) (x) = splimp() +# define SPL_NET(x) (x) = splnet() +# define SPL_X(x) (void) splx(x) +extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); +extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define GETKTIME(x) microtime((struct timeval *)x) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# else +# undef RW_DESTROY +# undef MUTEX_INIT +# undef MUTEX_DESTROY +# endif /* _KERNEL */ + +# define OS_RECOGNISED 1 + +#endif /* __sgi */ + +/* ----------------------------------------------------------------------- */ +/* T R U 6 4 */ +/* ----------------------------------------------------------------------- */ +#ifdef __osf__ +# undef MENTAT + +# include +# include + +# ifdef _KERNEL +# define KMUTEX_T simple_lock_data_t +# define KRWLOCK_T lock_data_t +# include +# define USE_MUTEXES +# define READ_ENTER(x) lock_read(&(x)->ipf_lk) +# define WRITE_ENTER(x) lock_write(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) lock_write_to_read(&(x)->ipf_lk) +# define RWLOCK_INIT(x, y) lock_init(&(x)->ipf_lk, TRUE) +# define RWLOCK_EXIT(x) lock_done(&(x)->ipf_lk) +# define RW_DESTROY(x) lock_terminate(&(x)->ipf_lk) +# define MUTEX_ENTER(x) simple_lock(&(x)->ipf_lk) +# define MUTEX_INIT(x, y) simple_lock_init(&(x)->ipf_lk) +# define MUTEX_DESTROY(x) simple_lock_terminate(&(x)->ipf_lk) +# define MUTEX_EXIT(x) simple_unlock(&(x)->ipf_lk) +# define MUTEX_NUKE(x) bzero(x, sizeof(*(x))) +# define ATOMIC_INC64(x) atomic_incq((uint64_t*)&(x)) +# define ATOMIC_DEC64(x) atomic_decq((uint64_t*)&(x)) +# define ATOMIC_INC32(x) atomic_incl((uint32_t*)&(x)) +# define ATOMIC_DEC32(x) atomic_decl((uint32_t*)&(x)) +# define ATOMIC_INC16(x) { simple_lock(&ipf_rw); (x)++; \ + simple_unlock(&ipf_rw); } +# define ATOMIC_DEC16(x) { simple_lock(&ipf_rw); (x)--; \ + simple_unlock(&ipf_rw); } +# define ATOMIC_INCL(x) atomic_incl((uint32_t*)&(x)) +# define ATOMIC_DECL(x) atomic_decl((uint32_t*)&(x)) +# define ATOMIC_INC(x) { simple_lock(&ipf_rw); (x)++; \ + simple_unlock(&ipf_rw); } +# define ATOMIC_DEC(x) { simple_lock(&ipf_rw); (x)--; \ + simple_unlock(&ipf_rw); } +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a, b, d) +# define FREE_MB_T(m) m_freem(m) +# define MTOD(m,t) mtod(m,t) +# define GETIFP(n, v) ifunit(n) +# define GET_MINOR getminor +# define WAKEUP(id,x) wakeup(id + x) +# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFILT, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFILT, M_NOWAIT) +# define KFREE(x) FREE((x), M_PFILT) +# define KFREES(x,s) FREE((x), M_PFILT) +# define MSGDSIZE(x) (x)->m_pkthdr.len +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define GETKTIME(x) microtime((struct timeval *)x) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# endif /* _KERNEL */ + +# if (defined(_KERNEL) || defined(_NO_BITFIELDS) || (__STDC__ == 1)) +# define IP_V(x) ((x)->ip_vhl >> 4) +# define IP_HL(x) ((x)->ip_vhl & 0xf) +# define IP_V_A(x,y) (x)->ip_vhl |= (((y) << 4) & 0xf0) +# define IP_HL_A(x,y) (x)->ip_vhl |= ((y) & 0xf) +# define TCP_OFF(x) ((x)->th_xoff >> 4) +# define TCP_OFF_A(x,y) (x)->th_xoff = ((y) << 4) +# endif + +/* + * These are from's Solaris' #defines for little endian. + */ +#define IP6F_MORE_FRAG 0x0100 +#define IP6F_RESERVED_MASK 0x0600 +#define IP6F_OFF_MASK 0xf8ff + +struct ip6_ext { + u_char ip6e_nxt; + u_char ip6e_len; +}; + +typedef int ioctlcmd_t; +/* + * Really, any arch where sizeof(long) != sizeof(int). + */ +typedef unsigned int u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* __osf__ */ + +/* ----------------------------------------------------------------------- */ +/* N E T B S D */ +/* ----------------------------------------------------------------------- */ +#ifdef __NetBSD__ +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "bpfilter.h" +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000) +# include "opt_inet.h" +# endif +# ifdef INET6 +# define USE_INET6 +# endif +# endif + +# ifdef _KERNEL +# define MSGDSIZE(x) (x)->m_pkthdr.len +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define GETKTIME(x) microtime((struct timeval *)x) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# endif /* _KERNEL */ +# if (NetBSD <= 1991011) && (NetBSD >= 199606) +# define IFNAME(x) ((struct ifnet *)x)->if_xname +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) +# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index)&7) +# else +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# endif + +typedef struct uio uio_t; +typedef u_long ioctlcmd_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + + +# define OS_RECOGNISED 1 +#endif /* __NetBSD__ */ + + +/* ----------------------------------------------------------------------- */ +/* F R E E B S D */ +/* ----------------------------------------------------------------------- */ +#ifdef __FreeBSD__ +# if defined(_KERNEL) && !defined(IPFILTER_LKM) && !defined(KLD_MODULE) +# include "bpf.h" +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) +# include "opt_inet6.h" +# endif +# ifdef INET6 +# define USE_INET6 +# endif +# endif + +# if defined(_KERNEL) +# if !defined(IPFILTER_LKM) && (__FreeBSD_version >= 300000) +# include "bpf.h" +# include "opt_ipfilter.h" +# endif +# if (__FreeBSD_version >= 500043) +# define NETBSD_PF +# endif +# endif /* _KERNEL */ + +# if (__FreeBSD_version >= 500043) +# include +# define KMUTEX_T struct mtx +# define KRWLOCK_T struct mtx +# endif + +# if (__FreeBSD_version >= 501113) +# include +# define IFNAME(x) ((struct ifnet *)x)->if_xname +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) +# endif +# if (__FreeBSD_version >= 500043) +# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index) & 7) +# else +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# endif + +# ifdef _KERNEL +# define GETKTIME(x) microtime((struct timeval *)x) + +# if (__FreeBSD_version >= 500002) +# include +# include +# include +# endif + +# if (__FreeBSD_version >= 500043) +# define USE_MUTEXES +# define MUTEX_ENTER(x) mtx_lock(&(x)->ipf_lk) +# define READ_ENTER(x) mtx_lock(&(x)->ipf_lk) +# define WRITE_ENTER(x) mtx_lock(&(x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_INIT(x, y) mtx_init(&(x)->ipf_lk, (y), NULL, \ + MTX_DEF) +# define RW_DESTROY(x) mtx_destroy(&(x)->ipf_lk) +# define RWLOCK_EXIT(x) mtx_unlock(&(x)->ipf_lk) +# define MUTEX_EXIT(x) mtx_unlock(&(x)->ipf_lk) +# define MUTEX_INIT(x,y) mtx_init(&(x)->ipf_lk, (y), NULL,\ + MTX_DEF) +# define MUTEX_DESTROY(x) mtx_destroy(&(x)->ipf_lk) +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) +# include +# define ATOMIC_INC(x) { mtx_lock(&ipf_rw.ipf_lk); (x)++; \ + mtx_unlock(&ipf_rw.ipf_lk); } +# define ATOMIC_DEC(x) { mtx_lock(&ipf_rw.ipf_lk); (x)--; \ + mtx_unlock(&ipf_rw.ipf_lk); } +# if 0 +# define ATOMIC_INCL(x) atomic_add_long(x, 1) +# define ATOMIC_INC64(x) atomic_add_(x, 1) +# define ATOMIC_INC32(x) atomic_add_(x, 1) +# define ATOMIC_INC16(x) atomic_add_short(x, 1) +# define ATOMIC_DECL(x) atomic_subtrct_long(x, -1) +# define ATOMIC_DEC64(x) atomic_subtrct_(x, -1) +# define ATOMIC_DEC32(x) atomic_subtrct_(x, -1) +# define ATOMIC_DEC16(x) atomic_subtrct_short(x, -1) +# endif +# define SPL_X(x) ; +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +extern int in_cksum __P((struct mbuf *, int)); +# endif /* __FreeBSD_version >= 500043 */ +# define MSGDSIZE(x) (x)->m_pkthdr.len +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# endif /* _KERNEL */ + +# if __FreeBSD__ < 3 +# include +# else +# if __FreeBSD__ == 3 +# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) +# define ACTUALLY_LKM_NOT_KERNEL +# endif +# endif +# endif + +# if (__FreeBSD_version >= 300000) +typedef u_long ioctlcmd_t; +# else +typedef int ioctlcmd_t; +# endif +typedef struct uio uio_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* __FreeBSD__ */ + + +/* ----------------------------------------------------------------------- */ +/* O P E N B S D */ +/* ----------------------------------------------------------------------- */ +#ifdef __OpenBSD__ +# ifdef INET6 +# define USE_INET6 +# endif + +# ifdef _KERNEL +# if !defined(IPFILTER_LKM) +# include "bpfilter.h" +# endif +# if (OpenBSD >= 200311) +# define SNPRINTF snprintf +# if defined(USE_INET6) +# include "netinet6/in6_var.h" +# include "netinet6/nd6.h" +# endif +# endif +# define GETKTIME(x) microtime((struct timeval *)x) +# define MSGDSIZE(x) (x)->m_pkthdr.len +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } +typedef struct mbuf mb_t; +# endif /* _KERNEL */ +# if (OpenBSD >= 199603) +# define IFNAME(x, b) ((struct ifnet *)x)->if_xname +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) +# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index)&7) +# else +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# endif + +typedef struct uio uio_t; +typedef u_long ioctlcmd_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* __OpenBSD__ */ + + +/* ----------------------------------------------------------------------- */ +/* B S D O S */ +/* ----------------------------------------------------------------------- */ +#ifdef _BSDI_VERSION +# ifdef INET6 +# define USE_INET6 +# endif + +# ifdef _KERNEL +# define GETKTIME(x) microtime((struct timeval *)x) +# define MSGDSIZE(x) (x)->m_pkthdr.len +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +typedef struct mbuf mb_t; +# endif /* _KERNEL */ + +# if (_BSDI_VERSION >= 199701) +typedef u_long ioctlcmd_t; +# else +typedef int ioctlcmd_t; +# endif +typedef u_int32_t u_32_t; +# define U_32_T 1 + +#endif /* _BSDI_VERSION */ + + +/* ----------------------------------------------------------------------- */ +/* S U N O S 4 */ +/* ----------------------------------------------------------------------- */ +#if defined(sun) && !defined(OS_RECOGNISED) /* SunOS4 */ +# ifdef _KERNEL +# include +# define GETKTIME(x) uniqtime((struct timeval *)x) +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# define GETIFP(n, v) ifunit(n, IFNAMSIZ) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# define SLEEP(id, n) sleep((id), PZERO+1) +# define WAKEUP(id,x) wakeup(id + x) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } + +extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); +extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); + +typedef struct mbuf mb_t; +# endif + +typedef struct uio uio_t; +typedef int ioctlcmd_t; +typedef int minor_t; +typedef unsigned int u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 + +#endif /* SunOS 4 */ + +/* ----------------------------------------------------------------------- */ +/* L I N U X */ +/* ----------------------------------------------------------------------- */ +#if defined(linux) && !defined(OS_RECOGNISED) +# ifdef _KERNEL +# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) +# define COPYIN(a,b,c) copy_from_user((caddr_t)(b), (caddr_t)(a), (c)) +# define COPYOUT(a,b,c) copy_to_user((caddr_t)(b), (caddr_t)(a), (c)) +# define FREE_MB_T(m) kfree_skb(m) +# define GETKTIME(x) do_gettimeofday((struct timeval *)x) +# define SLEEP(x,s) 0, interruptible_sleep_on(x##_linux) +# define WAKEUP(x,y) wake_up(x##_linux + y) +# define UIOMOVE(a,b,c,d) uiomove(a,b,c,d) +# define USE_MUTEXES +# define KRWLOCK_T rwlock_t +# define KMUTEX_T spinlock_t +# define MUTEX_INIT(x,y) spin_lock_init(&(x)->ipf_lk) +# define MUTEX_ENTER(x) spin_lock(&(x)->ipf_lk) +# define MUTEX_EXIT(x) spin_unlock(&(x)->ipf_lk) +# define MUTEX_DESTROY(x) do { } while (0) +# define MUTEX_NUKE(x) bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk)) +# define READ_ENTER(x) ipf_read_enter(x) +# define WRITE_ENTER(x) ipf_write_enter(x) +# define RWLOCK_INIT(x,y) rwlock_init(&(x)->ipf_lk) +# define RW_DESTROY(x) do { } while (0) +# define RWLOCK_EXIT(x) ipf_rw_exit(x) +# define MUTEX_DOWNGRADE(x) ipf_rw_downgrade(x) +# define ATOMIC_INCL(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DECL(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_INC64(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_INC32(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_INC16(x) MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DEC64(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DEC32(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define ATOMIC_DEC16(x) MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw) +# define SPL_IMP(x) do { } while (0) +# define SPL_NET(x) do { } while (0) +# define SPL_X(x) do { } while (0) +# define IFNAME(x) ((struct net_device*)x)->name +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct net_device *)fin->fin_ifp)->ifindex) & 7) +typedef struct sk_buff mb_t; +extern void m_copydata __P((mb_t *, int, int, caddr_t)); +# define mbuf sk_buff + +# define mtod(m, t) ((t)(m)->data) +# define m_len len +# define m_next next +# define m_pullup(m,l) (m) +# define M_DUPLICATE(m) skb_clone((m), GFP_KERNEL) +# define MSGDSIZE(m) (m)->len +# define M_LEN(m) (m)->len + +# define splnet(x) ; +# define printf printk +# define bcopy(s,d,z) memmove(d, s, z) +# define bzero(s,z) memset(s, 0, z) +# define bcmp(a,b,z) memcmp(a, b, z) + +# define ifnet net_device +# define if_xname name +# define if_unit ifindex + +# define KMALLOC(x,t) (x) = (t)kmalloc(sizeof(*(x)), GFP_KERNEL) +# define KFREE(x) kfree(x) +# define KMALLOCS(x,t,s) (x) = (t)kmalloc((s), GFP_KERNEL) +# define KFREES(x,s) kfree(x) + +# define GETIFP(n,v) dev_get_by_name(n) + +# else +# include + +struct mbuf { +}; + +# ifndef _NET_ROUTE_H +struct rtentry { +}; +# endif + +struct ifnet { + char if_xname[IFNAMSIZ]; + int if_unit; + int (* if_output) __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); +}; +# define IFNAME(x) ((struct ifnet *)x)->if_xname + +# endif /* _KERNEL */ + +# define COPYIFNAME(x, b) \ + (void) strncpy(b, \ + ((struct ifnet *)x)->if_xname, \ + LIFNAMSIZ) + +# include +# define FWRITE FMODE_WRITE +# define FREAD FMODE_READ + +# define __USE_MISC 1 +# define __FAVOR_BSD 1 + +typedef struct uio { + struct iovec *uio_iov; + void *uio_file; + char *uio_buf; + int uio_iovcnt; + int uio_offset; + size_t uio_resid; + int uio_rw; +} uio_t; + +extern int uiomove __P((caddr_t, size_t, int, struct uio *)); + +# define UIO_READ 1 +# define UIO_WRITE 2 + +typedef u_long ioctlcmd_t; +typedef int minor_t; +typedef u_int32_t u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 + +#endif + + +#ifndef OS_RECOGNISED +#error ip_compat.h does not recognise this platform/OS. +#endif + + +/* ----------------------------------------------------------------------- */ +/* G E N E R I C */ +/* ----------------------------------------------------------------------- */ +#ifndef OS_RECOGNISED +#endif + +/* + * For BSD kernels, if bpf is in the kernel, enable ipfilter to use bpf in + * filter rules. + */ +#if !defined(IPFILTER_BPF) && ((NBPF > 0) || (NBPFILTER > 0)) +# define IPFILTER_BPF +#endif + +/* + * Userland locking primitives + */ +typedef struct { + char *eMm_owner; + char *eMm_heldin; + u_int eMm_magic; + int eMm_held; + int eMm_heldat; +#ifdef __hpux + char eMm_fill[8]; +#endif +} eMmutex_t; + +typedef struct { + char *eMrw_owner; + char *eMrw_heldin; + u_int eMrw_magic; + short eMrw_read; + short eMrw_write; + int eMrw_heldat; +#ifdef __hpux + char eMm_fill[24]; +#endif +} eMrwlock_t; + +typedef union { +#ifdef KMUTEX_T + struct { + KMUTEX_T ipf_slk; + char *ipf_lname; + } ipf_lkun_s; +#endif + eMmutex_t ipf_emu; +} ipfmutex_t; + +typedef union { +#ifdef KRWLOCK_T + struct { + KRWLOCK_T ipf_slk; + char *ipf_lname; + int ipf_sr; + int ipf_sw; + u_int ipf_magic; + } ipf_lkun_s; +#endif + eMrwlock_t ipf_emu; +} ipfrwlock_t; + +#define ipf_lk ipf_lkun_s.ipf_slk +#define ipf_lname ipf_lkun_s.ipf_lname +#define ipf_isr ipf_lkun_s.ipf_sr +#define ipf_isw ipf_lkun_s.ipf_sw +#define ipf_magic ipf_lkun_s.ipf_magic + +#ifdef __GNUC__ +# define INLINE __inline__ +#else +# ifndef INLINE +# define INLINE +# endif +#endif + +#if defined(linux) && defined(_KERNEL) +extern INLINE void ipf_read_enter __P((ipfrwlock_t *)); +extern INLINE void ipf_write_enter __P((ipfrwlock_t *)); +extern INLINE void ipf_rw_exit __P((ipfrwlock_t *)); +extern INLINE void ipf_rw_downgrade __P((ipfrwlock_t *)); +#endif + +/* + * In a non-kernel environment, there are a lot of macros that need to be + * filled in to be null-ops or to point to some compatibility function, + * somewhere in userland. + */ +#ifndef _KERNEL +typedef struct mb_s { + struct mb_s *mb_next; + int mb_len; + u_long mb_buf[2048]; +} mb_t; +# undef m_next +# define m_next mb_next +# define MSGDSIZE(x) (x)->mb_len /* XXX - from ipt.c */ +# define M_LEN(x) (x)->mb_len +# define M_DUPLICATE(x) (x) +# define GETKTIME(x) gettimeofday((struct timeval *)(x), NULL) +# define MTOD(m, t) ((t)(m)->mb_buf) +# define FREE_MB_T(x) +# define SLEEP(x,y) 1; +# define WAKEUP(x,y) ; +# define IPF_PANIC(x,y) ; +# define PANIC(x,y) ; +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# define SPL_X(x) ; +# define KMALLOC(a,b) (a) = (b)malloc(sizeof(*a)) +# define KMALLOCS(a,b,c) (a) = (b)malloc(c) +# define KFREE(x) free(x) +# define KFREES(x,s) free(x) +# define GETIFP(x, v) get_unit(x,v) +# define COPYIN(a,b,c) (bcopy((a), (b), (c)), 0) +# define COPYOUT(a,b,c) (bcopy((a), (b), (c)), 0) +# define BCOPYIN(a,b,c) (bcopy((a), (b), (c)), 0) +# define BCOPYOUT(a,b,c) (bcopy((a), (b), (c)), 0) +# define COPYDATA(m, o, l, b) bcopy(MTOD((mb_t *)m, char *) + (o), \ + (b), (l)) +# define COPYBACK(m, o, l, b) bcopy((b), \ + MTOD((mb_t *)m, char *) + (o), \ + (l)) +# define UIOMOVE(a,b,c,d) ipfuiomove(a,b,c,d) +extern void m_copydata __P((mb_t *, int, int, caddr_t)); +extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); +# ifndef CACHE_HASH +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# endif + +# define MUTEX_DESTROY(x) eMmutex_destroy(&(x)->ipf_emu) +# define MUTEX_ENTER(x) eMmutex_enter(&(x)->ipf_emu, \ + __FILE__, __LINE__) +# define MUTEX_EXIT(x) eMmutex_exit(&(x)->ipf_emu) +# define MUTEX_INIT(x,y) eMmutex_init(&(x)->ipf_emu, y) +# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) + +# define MUTEX_DOWNGRADE(x) eMrwlock_downgrade(&(x)->ipf_emu, \ + __FILE__, __LINE__) +# define READ_ENTER(x) eMrwlock_read_enter(&(x)->ipf_emu, \ + __FILE__, __LINE__) +# define RWLOCK_INIT(x, y) eMrwlock_init(&(x)->ipf_emu, y) +# define RWLOCK_EXIT(x) eMrwlock_exit(&(x)->ipf_emu) +# define RW_DESTROY(x) eMrwlock_destroy(&(x)->ipf_emu) +# define WRITE_ENTER(x) eMrwlock_write_enter(&(x)->ipf_emu, \ + __FILE__, \ + __LINE__) + +# define USE_MUTEXES 1 + +extern void eMmutex_destroy __P((eMmutex_t *)); +extern void eMmutex_enter __P((eMmutex_t *, char *, int)); +extern void eMmutex_exit __P((eMmutex_t *)); +extern void eMmutex_init __P((eMmutex_t *, char *)); +extern void eMrwlock_destroy __P((eMrwlock_t *)); +extern void eMrwlock_exit __P((eMrwlock_t *)); +extern void eMrwlock_init __P((eMrwlock_t *, char *)); +extern void eMrwlock_read_enter __P((eMrwlock_t *, char *, int)); +extern void eMrwlock_write_enter __P((eMrwlock_t *, char *, int)); +extern void eMrwlock_downgrade __P((eMrwlock_t *, char *, int)); + +#endif + +#define MAX_IPV4HDR ((0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8) #ifndef IP_OFFMASK -#define IP_OFFMASK 0x1fff +# define IP_OFFMASK 0x1fff #endif + +/* + * On BSD's use quad_t as a guarantee for getting at least a 64bit sized + * object. + */ #if BSD > 199306 # define USE_QUAD_T # define U_QUAD_T u_quad_t @@ -215,111 +1313,233 @@ typedef int minor_t; #endif /* BSD > 199306 */ -#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) -# include -# ifndef __FreeBSD_version -# ifdef IPFILTER_LKM -# include -# else -# include -# endif -# endif -# ifdef IPFILTER_LKM -# define ACTUALLY_LKM_NOT_KERNEL -# endif -# if defined(__FreeBSD_version) && (__FreeBSD_version < 300000) -# include -# else -# if (__FreeBSD_version >= 300000) && (__FreeBSD_version < 400000) -# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) -# define ACTUALLY_LKM_NOT_KERNEL -# endif -# endif -# endif -#endif /* __FreeBSD__ && KERNEL */ - -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 500000) && \ - defined(_KERNEL) -# include -#endif - -/* - * These operating systems already take care of the problem for us. - */ -#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ - defined(__sgi) -typedef u_int32_t u_32_t; -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000) -# include "opt_inet.h" -# endif -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ - !defined(KLD_MODULE) -# include "opt_inet6.h" -# endif -# ifdef INET6 -# define USE_INET6 -# endif -# endif -# if !defined(_KERNEL) && !defined(IPFILTER_LKM) && !defined(USE_INET6) -# if (defined(__FreeBSD_version) && (__FreeBSD_version >= 400000)) || \ - (defined(OpenBSD) && (OpenBSD >= 200111)) || \ - (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000)) -# define USE_INET6 -# endif -# endif -#else -/* - * Really, any arch where sizeof(long) != sizeof(int). - */ -# if defined(__alpha__) || defined(__alpha) || defined(_LP64) -typedef unsigned int u_32_t; -# else -# if SOLARIS2 >= 6 -typedef uint32_t u_32_t; -# else -typedef unsigned int u_32_t; -# endif -# endif -#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */ - #ifdef USE_INET6 -# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ + defined(__osf__) || defined(linux) # include -# ifdef _KERNEL -# include +# ifndef linux +# include +# if defined(_KERNEL) && !defined(__osf__) +# include +# endif # endif typedef struct ip6_hdr ip6_t; # endif -# include -union i6addr { - u_32_t i6[4]; - struct in_addr in4; - struct in6_addr in6; -}; -#else -union i6addr { - u_32_t i6[4]; - struct in_addr in4; -}; #endif -#define IP6CMP(a,b) bcmp((char *)&(a), (char *)&(b), sizeof(a)) -#define IP6EQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) == 0) -#define IP6NEQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) != 0) -#define IP6_ISZERO(a) ((((union i6addr *)(a))->i6[0] | \ - ((union i6addr *)(a))->i6[1] | \ - ((union i6addr *)(a))->i6[2] | \ - ((union i6addr *)(a))->i6[3]) == 0) -#define IP6_NOTZERO(a) ((((union i6addr *)(a))->i6[0] | \ - ((union i6addr *)(a))->i6[1] | \ - ((union i6addr *)(a))->i6[2] | \ - ((union i6addr *)(a))->i6[3]) != 0) - #ifndef MAX -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +# define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif +#if defined(_KERNEL) +# ifdef MENTAT +# define COPYDATA mb_copydata +# define COPYBACK mb_copyback +# else +# define COPYDATA m_copydata +# define COPYBACK m_copyback +# endif +# if (BSD >= 199306) || defined(__FreeBSD__) +# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105180000)) || \ + defined(__FreeBSD__) || (defined(OpenBSD) && (OpenBSD < 200206)) || \ + defined(_BSDI_VERSION) +# include +# endif +# if !defined(__FreeBSD__) || (defined (__FreeBSD_version) && \ + (__FreeBSD_version >= 300000)) +# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105180000)) || \ + (defined(OpenBSD) && (OpenBSD >= 200111)) +/* # include */ +# else +# include +extern vm_map_t kmem_map; +# endif +# include +# else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ +# include +# endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ + +# ifdef IPFILTER_M_IPFILTER +# include +MALLOC_DECLARE(M_IPFILTER); +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_IPFILTER, \ + M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_IPFILTER, \ + M_NOWAIT) +# define KFREE(x) FREE((x), M_IPFILTER) +# define KFREES(x,s) FREE((x), M_IPFILTER) +# else /* IPFILTER_M_IPFILTER */ +# ifdef M_PFIL +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFIL, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) +# define KFREE(x) FREE((x), M_PFIL) +# define KFREES(x,s) FREE((x), M_PFIL) +# else /* M_PFIL */ +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT) +# define KFREE(x) FREE((x), M_TEMP) +# define KFREES(x,s) FREE((x), M_TEMP) +# endif /* M_PFIL */ +# endif /* IPFILTER_M_IPFILTER */ +# define UIOMOVE(a,b,c,d) uiomove(a,b,d) +# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0) +# define WAKEUP(id,x) wakeup(id+x) +# define GETIFP(n, v) ifunit(n) +# endif /* (Free)BSD */ + +# if !defined(USE_MUTEXES) && !defined(SPL_NET) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \ + (defined(OpenBSD) && (OpenBSD >= 200006)) +# define SPL_NET(x) x = splsoftnet() +# else +# define SPL_IMP(x) x = splimp() +# define SPL_NET(x) x = splnet() +# endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */ +# define SPL_X(x) (void) splx(x) +# endif /* !USE_MUTEXES */ + +# ifndef FREE_MB_T +# define FREE_MB_T(m) m_freem(m) +# endif + +# ifndef MTOD +# define MTOD(m,t) mtod(m,t) +# endif + +# ifndef COPYIN +# define COPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define COPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# endif + +# ifndef KMALLOC +# define KMALLOC(a,b) (a) = (b)new_kmem_alloc(sizeof(*(a)), \ + KMEM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) +# endif + +# ifndef GET_MINOR +# define GET_MINOR(x) minor(x) +# endif +# define PANIC(x,y) if (x) panic y +#endif /* _KERNEL */ + +#ifndef IFNAME +# define IFNAME(x) ((struct ifnet *)x)->if_name +#endif +#ifndef COPYIFNAME +# define NEED_FRGETIFNAME +extern char *fr_getifname __P((struct ifnet *, char *)); +# define COPYIFNAME(x, b) \ + fr_getifname((struct ifnet *)x, b) +#endif + +#ifndef ASSERT +# define ASSERT(x) +#endif + +/* + * If mutexes aren't being used, turn all the mutex functions into null-ops. + */ +#if !defined(USE_MUTEXES) +# define USE_SPL 1 +# undef RW_DESTROY +# undef MUTEX_INIT +# undef MUTEX_NUKE +# undef MUTEX_DESTROY +# define MUTEX_ENTER(x) ; +# define READ_ENTER(x) ; +# define WRITE_ENTER(x) ; +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_INIT(x, y) ; +# define RWLOCK_EXIT(x) ; +# define RW_DESTROY(x) ; +# define MUTEX_EXIT(x) ; +# define MUTEX_INIT(x,y) ; +# define MUTEX_DESTROY(x) ; +# define MUTEX_NUKE(x) ; +#endif /* !USE_MUTEXES */ +#ifndef ATOMIC_INC +# define ATOMIC_INC(x) (x)++ +# define ATOMIC_DEC(x) (x)-- +#endif + +/* + * If there are no atomic operations for bit sizes defined, define them to all + * use a generic one that works for all sizes. + */ +#ifndef ATOMIC_INCL +# define ATOMIC_INCL ATOMIC_INC +# define ATOMIC_INC64 ATOMIC_INC +# define ATOMIC_INC32 ATOMIC_INC +# define ATOMIC_INC16 ATOMIC_INC +# define ATOMIC_DECL ATOMIC_DEC +# define ATOMIC_DEC64 ATOMIC_DEC +# define ATOMIC_DEC32 ATOMIC_DEC +# define ATOMIC_DEC16 ATOMIC_DEC +#endif + +typedef struct tcphdr tcphdr_t; +typedef struct udphdr udphdr_t; +typedef struct icmp icmphdr_t; +typedef struct ip ip_t; +typedef struct ether_header ether_header_t; +typedef struct tcpiphdr tcpiphdr_t; + +#ifndef FR_GROUPLEN +# define FR_GROUPLEN 16 +#endif + +#ifdef offsetof +# undef offsetof +#endif +#ifndef offsetof +# define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif + +/* + * This set of macros has been brought about because on Tru64 it is not + * possible to easily assign or examine values in a structure that are + * bit fields. + */ +#ifndef IP_V +# define IP_V(x) (x)->ip_v +#endif +#ifndef IP_V_A +# define IP_V_A(x,y) (x)->ip_v = (y) +#endif +#ifndef IP_HL +# define IP_HL(x) (x)->ip_hl +#endif +#ifndef IP_HL_A +# define IP_HL_A(x,y) (x)->ip_hl = (y) +#endif +#ifndef TCP_OFF +# define TCP_OFF(x) (x)->th_off +#endif +#ifndef TCP_OFF_A +# define TCP_OFF_A(x,y) (x)->th_off = (y) +#endif +#define IPMINLEN(i, h) ((i)->ip_len >= (IP_HL(i) * 4 + sizeof(struct h))) + + +/* + * XXX - This is one of those *awful* hacks which nobody likes + */ +#ifdef ultrix +#define A_A +#else +#define A_A & +#endif + +#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|\ + TH_ECN|TH_CWR) + +#if (BSD >= 199306) && !defined(m_act) +# define m_act m_nextpkt +#endif + /* * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108. * @@ -354,317 +1574,87 @@ union i6addr { /* * IP option #defines */ -/*#define IPOPT_RR 7 */ +#undef IPOPT_RR +#define IPOPT_RR 7 +#undef IPOPT_ZSU #define IPOPT_ZSU 10 /* ZSU */ +#undef IPOPT_MTUP #define IPOPT_MTUP 11 /* MTUP */ +#undef IPOPT_MTUR #define IPOPT_MTUR 12 /* MTUR */ +#undef IPOPT_ENCODE #define IPOPT_ENCODE 15 /* ENCODE */ -/*#define IPOPT_TS 68 */ +#undef IPOPT_TS +#define IPOPT_TS 68 +#undef IPOPT_TR #define IPOPT_TR 82 /* TR */ -/*#define IPOPT_SECURITY 130 */ -/*#define IPOPT_LSRR 131 */ +#undef IPOPT_SECURITY +#define IPOPT_SECURITY 130 +#undef IPOPT_LSRR +#define IPOPT_LSRR 131 +#undef IPOPT_E_SEC #define IPOPT_E_SEC 133 /* E-SEC */ +#undef IPOPT_CIPSO #define IPOPT_CIPSO 134 /* CIPSO */ -/*#define IPOPT_SATID 136 */ +#undef IPOPT_SATID +#define IPOPT_SATID 136 #ifndef IPOPT_SID # define IPOPT_SID IPOPT_SATID #endif -/*#define IPOPT_SSRR 137 */ +#undef IPOPT_SSRR +#define IPOPT_SSRR 137 +#undef IPOPT_ADDEXT #define IPOPT_ADDEXT 147 /* ADDEXT */ +#undef IPOPT_VISA #define IPOPT_VISA 142 /* VISA */ +#undef IPOPT_IMITD #define IPOPT_IMITD 144 /* IMITD */ +#undef IPOPT_EIP #define IPOPT_EIP 145 /* EIP */ +#undef IPOPT_RTRALRT +#define IPOPT_RTRALRT 148 /* RTRALRT */ +#undef IPOPT_SDB +#define IPOPT_SDB 149 +#undef IPOPT_NSAPA +#define IPOPT_NSAPA 150 +#undef IPOPT_DPS +#define IPOPT_DPS 151 +#undef IPOPT_UMP +#define IPOPT_UMP 152 +#undef IPOPT_FINN #define IPOPT_FINN 205 /* FINN */ -#ifndef TCPOPT_WSCALE -# define TCPOPT_WSCALE 3 +#ifndef TCPOPT_EOL +# define TCPOPT_EOL 0 +#endif +#ifndef TCPOPT_NOP +# define TCPOPT_NOP 1 +#endif +#ifndef TCPOPT_MAXSEG +# define TCPOPT_MAXSEG 2 +#endif +#ifndef TCPOLEN_MAXSEG +# define TCPOLEN_MAXSEG 4 +#endif +#ifndef TCPOPT_WINDOW +# define TCPOPT_WINDOW 3 +#endif +#ifndef TCPOLEN_WINDOW +# define TCPOLEN_WINDOW 3 +#endif +#ifndef TCPOPT_SACK_PERMITTED +# define TCPOPT_SACK_PERMITTED 4 +#endif +#ifndef TCPOLEN_SACK_PERMITTED +# define TCPOLEN_SACK_PERMITTED 2 +#endif +#ifndef TCPOPT_SACK +# define TCPOPT_SACK 5 +#endif +#ifndef TCPOPT_TIMESTAMP +# define TCPOPT_TIMESTAMP 8 #endif -/* - * Build some macros and #defines to enable the same code to compile anywhere - * Well, that's the idea, anyway :-) - */ -#if SOLARIS -typedef mblk_t mb_t; -# if SOLARIS2 >= 7 -# ifdef lint -# define ALIGN32(ptr) (ptr ? 0L : 0L) -# define ALIGN16(ptr) (ptr ? 0L : 0L) -# else -# define ALIGN32(ptr) (ptr) -# define ALIGN16(ptr) (ptr) -# endif -# endif -#else -typedef struct mbuf mb_t; -#endif /* SOLARIS */ - -#if !SOLARIS || (SOLARIS2 < 6) || !defined(KERNEL) -# define ATOMIC_INCL ATOMIC_INC -# define ATOMIC_INC64 ATOMIC_INC -# define ATOMIC_INC32 ATOMIC_INC -# define ATOMIC_INC16 ATOMIC_INC -# define ATOMIC_DECL ATOMIC_DEC -# define ATOMIC_DEC64 ATOMIC_DEC -# define ATOMIC_DEC32 ATOMIC_DEC -# define ATOMIC_DEC16 ATOMIC_DEC -#endif -#ifdef __sgi -# define hz HZ -# include -# define IPF_LOCK_PL plhi -# include -#undef kmutex_t -typedef struct { - lock_t *l; - int pl; -} kmutex_t; -# undef MUTEX_INIT -# undef MUTEX_DESTROY -#endif -#ifdef KERNEL -# if SOLARIS -# if SOLARIS2 >= 6 -# include -# if SOLARIS2 == 6 -# define ATOMIC_INCL(x) atomic_add_long((uint32_t*)&(x), 1) -# define ATOMIC_DECL(x) atomic_add_long((uint32_t*)&(x), -1) -# else -# define ATOMIC_INCL(x) atomic_add_long(&(x), 1) -# define ATOMIC_DECL(x) atomic_add_long(&(x), -1) -# endif -# define ATOMIC_INC64(x) atomic_add_64((uint64_t*)&(x), 1) -# define ATOMIC_INC32(x) atomic_add_32((uint32_t*)&(x), 1) -# define ATOMIC_INC16(x) atomic_add_16((uint16_t*)&(x), 1) -# define ATOMIC_DEC64(x) atomic_add_64((uint64_t*)&(x), -1) -# define ATOMIC_DEC32(x) atomic_add_32((uint32_t*)&(x), -1) -# define ATOMIC_DEC16(x) atomic_add_16((uint16_t*)&(x), -1) -# else -# define IRE_CACHE IRE_ROUTE -# define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ - mutex_exit(&ipf_rw); } -# define ATOMIC_DEC(x) { mutex_enter(&ipf_rw); (x)--; \ - mutex_exit(&ipf_rw); } -# endif -# define MUTEX_ENTER(x) mutex_enter(x) -# if 1 -# define KRWLOCK_T krwlock_t -# define READ_ENTER(x) rw_enter(x, RW_READER) -# define WRITE_ENTER(x) rw_enter(x, RW_WRITER) -# define RW_UPGRADE(x) { if (rw_tryupgrade(x) == 0) { \ - rw_exit(x); \ - rw_enter(x, RW_WRITER); } \ - } -# define MUTEX_DOWNGRADE(x) rw_downgrade(x) -# define RWLOCK_INIT(x, y, z) rw_init((x), (y), RW_DRIVER, (z)) -# define RWLOCK_EXIT(x) rw_exit(x) -# define RW_DESTROY(x) rw_destroy(x) -# else -# define KRWLOCK_T kmutex_t -# define READ_ENTER(x) mutex_enter(x) -# define WRITE_ENTER(x) mutex_enter(x) -# define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) -# define RWLOCK_EXIT(x) mutex_exit(x) -# define RW_DESTROY(x) mutex_destroy(x) -# endif -# define MUTEX_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) -# define MUTEX_DESTROY(x) mutex_destroy(x) -# define MUTEX_EXIT(x) mutex_exit(x) -# define MTOD(m,t) (t)((m)->b_rptr) -# define IRCOPY(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) -# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define IRCOPYPTR ircopyptr -# define IWCOPYPTR iwcopyptr -# define FREE_MB_T(m) freemsg(m) -# define SPL_NET(x) ; -# define SPL_IMP(x) ; -# undef SPL_X -# define SPL_X(x) ; -# ifdef sparc -# define ntohs(x) (x) -# define ntohl(x) (x) -# define htons(x) (x) -# define htonl(x) (x) -# endif /* sparc */ -# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) -# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) -# define GET_MINOR(x) getminor(x) -extern ill_t *get_unit __P((char *, int)); -# define GETUNIT(n, v) get_unit(n, v) -# define IFNAME(x) ((ill_t *)x)->ill_name -# else /* SOLARIS */ -# if defined(__sgi) -# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ - (x)++; MUTEX_EXIT(&ipf_rw); } -# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ - (x)--; MUTEX_EXIT(&ipf_rw); } -# define MUTEX_ENTER(x) (x)->pl = LOCK((x)->l, IPF_LOCK_PL); -# define KRWLOCK_T kmutex_t -# define READ_ENTER(x) MUTEX_ENTER(x) -# define WRITE_ENTER(x) MUTEX_ENTER(x) -# define RW_UPGRADE(x) ; -# define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_EXIT(x) MUTEX_EXIT(x) -# define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); -# define MUTEX_INIT(x,y,z) (x)->l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) -# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->l) -# else /* __sgi */ -# define ATOMIC_INC(x) (x)++ -# define ATOMIC_DEC(x) (x)-- -# define MUTEX_ENTER(x) ; -# define READ_ENTER(x) ; -# define WRITE_ENTER(x) ; -# define RW_UPGRADE(x) ; -# define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_EXIT(x) ; -# define MUTEX_EXIT(x) ; -# define MUTEX_INIT(x,y,z) ; -# define MUTEX_DESTROY(x) ; -# endif /* __sgi */ -# ifndef linux -# define FREE_MB_T(m) m_freem(m) -# define MTOD(m,t) mtod(m,t) -# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) -# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) -# define IRCOPYPTR ircopyptr -# define IWCOPYPTR iwcopyptr -# endif /* !linux */ -# endif /* SOLARIS */ - -# ifdef sun -# if !SOLARIS -# include -# define GETUNIT(n, v) ifunit(n, IFNAMSIZ) -# define IFNAME(x) ((struct ifnet *)x)->if_name -# endif -# else -# ifndef linux -# define GETUNIT(n, v) ifunit(n) -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) -# define IFNAME(x) ((struct ifnet *)x)->if_xname -# else -# define USE_GETIFNAME 1 -# define IFNAME(x) get_ifname((struct ifnet *)x) -extern char *get_ifname __P((struct ifnet *)); -# endif -# endif -# endif /* sun */ - -# if defined(sun) && !defined(linux) || defined(__sgi) -# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) -# define SLEEP(id, n) sleep((id), PZERO+1) -# define WAKEUP(id) wakeup(id) -# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) -# define KFREES(x,s) kmem_free((char *)(x), (s)) -# if !SOLARIS -extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); -extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); -# endif -# ifdef __sgi -# include -# include -# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) -# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) -# define GET_MINOR(x) getminor(x) -# else -# if !SOLARIS -# define KMALLOC(a,b) (a) = (b)new_kmem_alloc(sizeof(*(a)), \ - KMEM_NOSLEEP) -# define KMALLOCS(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) -# endif /* SOLARIS */ -# endif /* __sgi */ -# endif /* sun && !linux */ -# ifndef GET_MINOR -# define GET_MINOR(x) minor(x) -# endif -# if (BSD >= 199306) || defined(__FreeBSD__) -# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105180000)) || \ - defined(__FreeBSD__) || (defined(OpenBSD) && (OpenBSD < 200206)) || \ - defined(_BSDI_VERSION) -# include -# endif -# if !defined(__FreeBSD__) || (defined (__FreeBSD_version) && \ - (__FreeBSD_version >= 300000)) -# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105180000)) || \ - (defined(OpenBSD) && (OpenBSD >= 200111)) -/* # include */ -# else -# include -extern vm_map_t kmem_map; -# endif -# include -# else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ -# include -# endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ -# ifdef M_PFIL -# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFIL, M_NOWAIT) -# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) -# define KFREE(x) FREE((x), M_PFIL) -# define KFREES(x,s) FREE((x), M_PFIL) -# else -# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT) -# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT) -# define KFREE(x) FREE((x), M_TEMP) -# define KFREES(x,s) FREE((x), M_TEMP) -# endif /* M_PFIL */ -# define UIOMOVE(a,b,c,d) uiomove(a,b,d) -# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0) -# define WAKEUP(id) wakeup(id) -# endif /* BSD */ -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \ - (defined(OpenBSD) && (OpenBSD >= 200006)) -# define SPL_NET(x) x = splsoftnet() -# define SPL_X(x) (void) splx(x) -# else -# if !SOLARIS && !defined(linux) -# define SPL_IMP(x) x = splimp() -# define SPL_NET(x) x = splnet() -# define SPL_X(x) (void) splx(x) -# endif -# endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */ -# define PANIC(x,y) if (x) panic y -#else /* KERNEL */ -# define SLEEP(x,y) 1 -# define WAKEUP(x) ; -# define PANIC(x,y) ; -# define ATOMIC_INC(x) (x)++ -# define ATOMIC_DEC(x) (x)-- -# define MUTEX_ENTER(x) ; -# define READ_ENTER(x) ; -# define MUTEX_INIT(x,y,z) ; -# define MUTEX_DESTROY(x) ; -# define WRITE_ENTER(x) ; -# define RW_UPGRADE(x) ; -# define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_EXIT(x) ; -# define MUTEX_EXIT(x) ; -# define SPL_NET(x) ; -# define SPL_IMP(x) ; -# undef SPL_X -# define SPL_X(x) ; -# define KMALLOC(a,b) (a) = (b)malloc(sizeof(*a)) -# define KMALLOCS(a,b,c) (a) = (b)malloc(c) -# define KFREE(x) free(x) -# define KFREES(x,s) free(x) -# define FREE_MB_T(x) ; -# define GETUNIT(x, v) get_unit(x,v) -# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) -# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) -# define IRCOPYPTR ircopyptr -# define IWCOPYPTR iwcopyptr -# define IFNAME(x) get_ifname((struct ifnet *)x) -# define UIOMOVE(a,b,c,d) ipfuiomove(a,b,c,d) -extern void m_copydata __P((mb_t *, int, int, caddr_t)); -extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); -#endif /* KERNEL */ - -/* - * These #ifdef's are here mainly for linux, but who knows, they may - * not be in other places or maybe one day linux will grow up and some - * of these will turn up there too. - */ #ifndef ICMP_MINLEN # define ICMP_MINLEN 8 #endif @@ -716,6 +1706,9 @@ extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); #ifndef ICMP_UNREACH_ADMIN_PROHIBIT # define ICMP_UNREACH_ADMIN_PROHIBIT 13 #endif +#ifndef ICMP_UNREACH_FILTER +# define ICMP_UNREACH_FILTER 13 +#endif #ifndef ICMP_UNREACH_HOST_PRECEDENCE # define ICMP_UNREACH_HOST_PRECEDENCE 14 #endif @@ -854,6 +1847,9 @@ extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); #ifndef TH_URG # define TH_URG 0x20 #endif +#undef TH_ACKMASK +#define TH_ACKMASK (TH_FIN|TH_SYN|TH_RST|TH_ACK) + #ifndef IPOPT_EOL # define IPOPT_EOL 0 #endif @@ -902,313 +1898,48 @@ extern int ipfuiomove __P((caddr_t, int, int, struct uio *)); #ifndef IPOPT_OLEN # define IPOPT_OLEN 1 #endif +#ifndef IPPROTO_HOPOPTS +# define IPPROTO_HOPOPTS 0 +#endif +#ifndef IPPROTO_ENCAP +# define IPPROTO_ENCAP 4 +#endif +#ifndef IPPROTO_IPV6 +# define IPPROTO_IPV6 41 +#endif +#ifndef IPPROTO_ROUTING +# define IPPROTO_ROUTING 43 +#endif +#ifndef IPPROTO_FRAGMENT +# define IPPROTO_FRAGMENT 44 +#endif #ifndef IPPROTO_GRE # define IPPROTO_GRE 47 /* GRE encaps RFC 1701 */ #endif #ifndef IPPROTO_ESP # define IPPROTO_ESP 50 #endif +#ifndef IPPROTO_AH +# define IPPROTO_AH 51 +#endif #ifndef IPPROTO_ICMPV6 # define IPPROTO_ICMPV6 58 #endif - -#ifdef linux -#include -/* - * TCP States - */ -#define TCPS_CLOSED 0 /* closed */ -#define TCPS_LISTEN 1 /* listening for connection */ -#define TCPS_SYN_SENT 2 /* active, have sent syn */ -#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ -/* states < TCPS_ESTABLISHED are those where connections not established */ -#define TCPS_ESTABLISHED 4 /* established */ -#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ -/* states > TCPS_CLOSE_WAIT are those where user has closed */ -#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ -#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ -/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ -#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ - -/* - * file flags. - */ -#ifdef WRITE -#define FWRITE WRITE -#define FREAD READ -#else -#define FWRITE _IOC_WRITE -#define FREAD _IOC_READ +#ifndef IPPROTO_NONE +# define IPPROTO_NONE 59 #endif -/* - * mbuf related problems. - */ -#define mtod(m,t) (t)((m)->data) -#define m_len len -#define m_next next - -#ifdef IP_DF -#undef IP_DF +#ifndef IPPROTO_DSTOPTS +# define IPPROTO_DSTOPTS 60 #endif -#define IP_DF 0x4000 - -typedef struct { - __u16 th_sport; - __u16 th_dport; - __u32 th_seq; - __u32 th_ack; -# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ - defined(__vax__) - __u8 th_res:4; - __u8 th_off:4; -#else - __u8 th_off:4; - __u8 th_res:4; +#ifndef IPPROTO_FRAGMENT +# define IPPROTO_FRAGMENT 44 #endif - __u8 th_flags; - __u16 th_win; - __u16 th_sum; - __u16 th_urp; -} tcphdr_t; - -typedef struct { - __u16 uh_sport; - __u16 uh_dport; - __u16 uh_ulen; - __u16 uh_sum; -} udphdr_t; - -typedef struct { -# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ - defined(__vax__) - __u8 ip_hl:4; - __u8 ip_v:4; -# else - __u8 ip_v:4; - __u8 ip_hl:4; -# endif - __u8 ip_tos; - __u16 ip_len; - __u16 ip_id; - __u16 ip_off; - __u8 ip_ttl; - __u8 ip_p; - __u16 ip_sum; - struct in_addr ip_src; - struct in_addr ip_dst; -} ip_t; - -/* - * Structure of an icmp header. - */ -typedef struct icmp { - __u8 icmp_type; /* type of message, see below */ - __u8 icmp_code; /* type sub code */ - __u16 icmp_cksum; /* ones complement cksum of struct */ - union { - __u8 ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - __u16 icd_id; - __u16 icd_seq; - } ih_idseq; - int ih_void; - } icmp_hun; -# define icmp_pptr icmp_hun.ih_pptr -# define icmp_gwaddr icmp_hun.ih_gwaddr -# define icmp_id icmp_hun.ih_idseq.icd_id -# define icmp_seq icmp_hun.ih_idseq.icd_seq -# define icmp_void icmp_hun.ih_void - union { - struct id_ts { - n_time its_otime; - n_time its_rtime; - n_time its_ttime; - } id_ts; - struct id_ip { - ip_t idi_ip; - /* options and then 64 bits of data */ - } id_ip; - u_long id_mask; - char id_data[1]; - } icmp_dun; -# define icmp_otime icmp_dun.id_ts.its_otime -# define icmp_rtime icmp_dun.id_ts.its_rtime -# define icmp_ttime icmp_dun.id_ts.its_ttime -# define icmp_ip icmp_dun.id_ip.idi_ip -# define icmp_mask icmp_dun.id_mask -# define icmp_data icmp_dun.id_data -} icmphdr_t; - -# ifndef LINUX_IPOVLY -# define LINUX_IPOVLY -struct ipovly { - caddr_t ih_next, ih_prev; /* for protocol sequence q's */ - u_char ih_x1; /* (unused) */ - u_char ih_pr; /* protocol */ - short ih_len; /* protocol length */ - struct in_addr ih_src; /* source internet address */ - struct in_addr ih_dst; /* destination internet address */ -}; -# endif - -typedef struct { - __u8 ether_dhost[6]; - __u8 ether_shost[6]; - __u16 ether_type; -} ether_header_t; - -typedef struct uio { - int uio_resid; - int uio_rw; - caddr_t uio_buf; -} uio_t; - -# define UIO_READ 0 -# define UIO_WRITE 1 -# define UIOMOVE(a, b, c, d) uiomove(a,b,c,d) - -/* - * For masking struct ifnet onto struct device - */ -# define if_name name - -# ifdef KERNEL -# define GETUNIT(x, v) dev_get(x) -# define FREE_MB_T(m) kfree_skb(m, FREE_WRITE) -# define uniqtime do_gettimeofday -# undef INT_MAX -# undef UINT_MAX -# undef LONG_MAX -# undef ULONG_MAX -# include -# define SPL_X(x) -# define SPL_NET(x) -# define SPL_IMP(x) - -# define bcmp(a,b,c) memcmp(a,b,c) -# define bcopy(a,b,c) memcpy(b,a,c) -# define bzero(a,c) memset(a,0,c) - -# define UNITNAME(n) dev_get((n)) - -# define KMALLOC(a,b) (a) = (b)kmalloc(sizeof(*(a)), GFP_ATOMIC) -# define KMALLOCS(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC) -# define KFREE(x) kfree_s((x), sizeof(*(x))) -# define KFREES(x,s) kfree_s((x), (s)) -#define IRCOPY(const void *a, void *b, size_t c) { \ - int error; \ - - error = verify_area(VERIFY_READ, a ,c); \ - if (!error) \ - memcpy_fromfs(b, a, c); \ - return error; \ -} -static inline int IWCOPY(const void *a, void *b, size_t c) -{ - int error; - - error = verify_area(VERIFY_WRITE, b, c); - if (!error) - memcpy_tofs(b, a, c); - return error; -} -static inline int IRCOPYPTR(const void *a, void *b, size_t c) { - caddr_t ca; - int error; - - error = verify_area(VERIFY_READ, a ,sizeof(ca)); - if (!error) { - memcpy_fromfs(ca, a, sizeof(ca)); - error = verify_area(VERIFY_READ, ca , c); - if (!error) - memcpy_fromfs(b, ca, c); - } - return error; -} -static inline int IWCOPYPTR(const void *a, void *b, size_t c) { - caddr_t ca; - int error; - - - error = verify_area(VERIFY_READ, b ,sizeof(ca)); - if (!error) { - memcpy_fromfs(ca, b, sizeof(ca)); - error = verify_area(VERIFY_WRITE, ca, c); - if (!error) - memcpy_tofs(ca, a, c); - } - return error; -} -# else -# define __KERNEL__ -# undef INT_MAX -# undef UINT_MAX -# undef LONG_MAX -# undef ULONG_MAX -# define s8 __s8 -# define u8 __u8 -# define s16 __s16 -# define u16 __u16 -# define s32 __s32 -# define u32 __u32 -# include -# undef __KERNEL__ -# endif -# define ifnet device -#else -typedef struct tcphdr tcphdr_t; -typedef struct udphdr udphdr_t; -typedef struct icmp icmphdr_t; -typedef struct ip ip_t; -typedef struct ether_header ether_header_t; -#endif /* linux */ -typedef struct tcpiphdr tcpiphdr_t; - -#if defined(hpux) || defined(linux) -struct ether_addr { - char ether_addr_octet[6]; -}; -#endif - -/* - * XXX - This is one of those *awful* hacks which nobody likes - */ -#ifdef ultrix -#define A_A -#else -#define A_A & -#endif - -#if (BSD >= 199306) && !defined(m_act) -# define m_act m_nextpkt -#endif - #ifndef ICMP_ROUTERADVERT # define ICMP_ROUTERADVERT 9 #endif #ifndef ICMP_ROUTERSOLICIT # define ICMP_ROUTERSOLICIT 10 #endif -#undef ICMP_MAX_UNREACH -#define ICMP_MAX_UNREACH 14 -#undef ICMP_MAXTYPE -#define ICMP_MAXTYPE 18 -/* - * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data, - * another IP header and then 64 bits of data, totalling 56. Of course, - * the last 64 bits is dependant on that being available. - */ -#define ICMPERR_ICMPHLEN 8 -#define ICMPERR_IPICMPHLEN (20 + 8) -#define ICMPERR_MINPKTLEN (20 + 8 + 20) -#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) -#define ICMP6_MINLEN 8 -#define ICMP6ERR_MINPKTLEN (40 + 8) -#define ICMP6ERR_IPICMPHLEN (40 + 8 + 40) - #ifndef ICMP6_DST_UNREACH # define ICMP6_DST_UNREACH 1 #endif @@ -1380,6 +2111,79 @@ struct ether_addr { #endif #define TH_ECNALL (TH_ECN|TH_CWR) -#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|TH_ECN|TH_CWR) +/* + * TCP States + */ +#define IPF_TCPS_CLOSED 0 /* closed */ +#define IPF_TCPS_LISTEN 1 /* listening for connection */ +#define IPF_TCPS_SYN_SENT 2 /* active, have sent syn */ +#define IPF_TCPS_SYN_RECEIVED 3 /* have send and received syn */ +#define IPF_TCPS_HALF_ESTAB 4 /* for connections not fully "up" */ +/* states < IPF_TCPS_ESTABLISHED are those where connections not established */ +#define IPF_TCPS_ESTABLISHED 5 /* established */ +#define IPF_TCPS_CLOSE_WAIT 6 /* rcvd fin, waiting for close */ +/* states > IPF_TCPS_CLOSE_WAIT are those where user has closed */ +#define IPF_TCPS_FIN_WAIT_1 7 /* have closed, sent fin */ +#define IPF_TCPS_CLOSING 8 /* closed xchd FIN; await FIN ACK */ +#define IPF_TCPS_LAST_ACK 9 /* had fin and close; await FIN ACK */ +/* states > IPF_TCPS_CLOSE_WAIT && < IPF_TCPS_FIN_WAIT_2 await ACK of FIN */ +#define IPF_TCPS_FIN_WAIT_2 10 /* have closed, fin is acked */ +#define IPF_TCPS_TIME_WAIT 11 /* in 2*msl quiet wait after close */ +#define IPF_TCP_NSTATES 12 + +#define TCP_MSL 120 + +#undef ICMP_MAX_UNREACH +#define ICMP_MAX_UNREACH 14 +#undef ICMP_MAXTYPE +#define ICMP_MAXTYPE 18 + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +#ifndef LOG_FTP +# define LOG_FTP (11<<3) +#endif +#ifndef LOG_AUTHPRIV +# define LOG_AUTHPRIV (10<<3) +#endif +#ifndef LOG_AUDIT +# define LOG_AUDIT (13<<3) +#endif +#ifndef LOG_NTP +# define LOG_NTP (12<<3) +#endif +#ifndef LOG_SECURITY +# define LOG_SECURITY (13<<3) +#endif +#ifndef LOG_LFMT +# define LOG_LFMT (14<<3) +#endif +#ifndef LOG_CONSOLE +# define LOG_CONSOLE (14<<3) +#endif + +/* + * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data, + * another IP header and then 64 bits of data, totalling 56. Of course, + * the last 64 bits is dependant on that being available. + */ +#define ICMPERR_ICMPHLEN 8 +#define ICMPERR_IPICMPHLEN (20 + 8) +#define ICMPERR_MINPKTLEN (20 + 8 + 20) +#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) +#define ICMP6ERR_MINPKTLEN (40 + 8) +#define ICMP6ERR_IPICMPHLEN (40 + 8 + 40) + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifdef IPF_DEBUG +# define DPRINT(x) printf x +#else +# define DPRINT(x) +#endif #endif /* _NETINET_IP_COMPAT_H_ */ diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c deleted file mode 100644 index 8aaddc02857e..000000000000 --- a/sys/netinet/ip_fil.c +++ /dev/null @@ -1,2232 +0,0 @@ -/* $NetBSD: ip_fil.c,v 1.95 2003/08/22 22:11:44 itojun Exp $ */ - -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif - -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif -#if defined(_KERNEL) && defined(__FreeBSD_version) && \ - (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) -#include "opt_inet6.h" -#include "opt_ipsec.h" -#endif -#include -#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ - defined(_KERNEL) && !defined(_LKM) -# include "opt_ipfilter_log.h" -# include "opt_pfil_hooks.h" -# include "opt_ipsec.h" -#endif -#if defined(__FreeBSD__) && !defined(__FreeBSD_version) -# if !defined(_KERNEL) || defined(IPFILTER_LKM) -# include -# endif -#endif -#ifdef __sgi -# define _KMEMUSER -# include -#endif -#ifndef _KERNEL -# include -# include -# include -# include -# include -#endif -#include -#include -#include -#if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include -# include -#else -# include -#endif -#include -#ifdef _KERNEL -# include -#endif -#if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) -# include -# else -# include -# endif -# include -#else -# include -#endif -#include -#include - -#include -#ifdef sun -# include -#endif -#if __FreeBSD_version >= 300000 -# include -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include "opt_ipfilter.h" -# endif -#endif -#ifdef __sgi -#include -# ifdef IFF_DRVRLOCK /* IRIX6 */ -#include -# endif -#endif -#include -#include -#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#ifndef _KERNEL -# include -# include -#endif -#include "netinet/ip_compat.h" -#ifdef USE_INET6 -# include -# if !SOLARIS -# include -# include -# endif -#endif -#include "netinet/ip_fil.h" -#include "netinet/ip_nat.h" -#include "netinet/ip_frag.h" -#include "netinet/ip_state.h" -#include "netinet/ip_proxy.h" -#include "netinet/ip_auth.h" -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) -# include -#endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif -#if !SOLARIS && defined(_KERNEL) && !defined(__sgi) -# include -extern int ip_optcopy __P((struct ip *, struct ip *)); -#endif - -#if !defined(lint) -#if defined(__NetBSD__) -#include -__KERNEL_RCSID(0, "$NetBSD: ip_fil.c,v 1.95 2003/08/22 22:11:44 itojun Exp $"); -#else -static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)Id: ip_fil.c,v 2.42.2.60 2002/08/28 12:40:39 darrenr Exp"; -#endif -#endif - - -extern struct protosw inetsw[]; - -#ifndef _KERNEL -# include "ipt.h" -static struct ifnet **ifneta = NULL; -static int nifs = 0; -#else -# if (BSD < 199306) || defined(__sgi) -extern int tcp_ttl; -# endif -#endif - -#ifdef ICMP_UNREACH_FILTER_PROHIB -int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB; -#else -int ipl_unreach = ICMP_UNREACH_FILTER; -#endif -u_long ipl_frouteok[2] = {0, 0}; - -static int frzerostats __P((caddr_t)); -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -static int frrequest __P((int, u_long, caddr_t, int)); -#else -static int frrequest __P((int, int, caddr_t, int)); -#endif -#ifdef _KERNEL -static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); -static int send_ip __P((ip_t *, fr_info_t *, struct mbuf **)); -# ifdef USE_INET6 -static int ipfr_fastroute6 __P((struct mbuf *, struct mbuf **, - fr_info_t *, frdest_t *)); -# endif -# ifdef __sgi -extern int tcp_mtudisc; -extern kmutex_t ipf_rw; -extern KRWLOCK_T ipf_mutex; -# endif -#else -void init_ifp __P((void)); -# if defined(__sgi) && (IRIX < 605) -static int no_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *)); -static int write_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *)); -# else -static int no_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); -static int write_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); -# endif -#endif -int fr_running = 0; - -#if (__FreeBSD_version >= 300000) && defined(_KERNEL) -struct callout_handle ipfr_slowtimer_ch; -#endif -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) -# include -struct callout ipfr_slowtimer_ch; -#endif -#if defined(__OpenBSD__) -# include -struct timeout ipfr_slowtimer_ch; -#endif -#if defined(__sgi) && defined(_KERNEL) -toid_t ipfr_slowtimer_ch; -#endif - -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) && \ - defined(_KERNEL) -#include -#include - -const struct cdevsw ipl_cdevsw = { - iplopen, iplclose, iplread, nowrite, iplioctl, - nostop, notty, nopoll, nommap, nokqfilter, -}; -#endif - -#if (_BSDI_VERSION >= 199510) && defined(_KERNEL) -# include -# include - -struct cfdriver iplcd = { - NULL, "ipl", NULL, NULL, DV_DULL, 0 -}; - -struct devsw iplsw = { - &iplcd, - iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap, - nostrat, nodump, nopsize, 0, - nostop -}; -#endif /* _BSDI_VERSION >= 199510 && _KERNEL */ - -#if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701) -# include -# if defined(NETBSD_PF) -# include -/* - * We provide the fr_checkp name just to minimize changes later. - */ -int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); -# endif /* NETBSD_PF */ -#endif /* __NetBSD__ */ - - -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) && \ - defined(_KERNEL) -# include - -static int fr_check_wrapper(void *, struct mbuf **, struct ifnet *, int ); - -static int fr_check_wrapper(arg, mp, ifp, dir) -void *arg; -struct mbuf **mp; -struct ifnet *ifp; -int dir; -{ - struct ip *ip = mtod(*mp, struct ip *); - int rv, hlen = ip->ip_hl << 2; - -#if defined(M_CSUM_TCPv4) - /* - * If the packet is out-bound, we can't delay checksums - * here. For in-bound, the checksum has already been - * validated. - */ - if (dir == PFIL_OUT) { - if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) { - in_delayed_cksum(*mp); - (*mp)->m_pkthdr.csum_flags &= - ~(M_CSUM_TCPv4|M_CSUM_UDPv4); - } - } -#endif /* M_CSUM_TCPv4 */ - - /* - * We get the packet with all fields in network byte - * order. We expect ip_len and ip_off to be in host - * order. We frob them, call the filter, then frob - * them back. - * - * Note, we don't need to update the checksum, because - * it has already been verified. - */ - NTOHS(ip->ip_len); - NTOHS(ip->ip_off); - - rv = fr_check(ip, hlen, ifp, (dir == PFIL_OUT), mp); - - if (rv == 0 && *mp != NULL) { - ip = mtod(*mp, struct ip *); - HTONS(ip->ip_len); - HTONS(ip->ip_off); - } - - return (rv); -} - -# ifdef USE_INET6 -# include - -static int fr_check_wrapper6(void *, struct mbuf **, struct ifnet *, int ); - -static int fr_check_wrapper6(arg, mp, ifp, dir) -void *arg; -struct mbuf **mp; -struct ifnet *ifp; -int dir; -{ - - return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr), - ifp, (dir == PFIL_OUT), mp)); -} -# endif -#endif /* __NetBSD_Version >= 105110000 && _KERNEL */ -#ifdef _KERNEL -# if defined(IPFILTER_LKM) && !defined(__sgi) -int iplidentify(s) -char *s; -{ - if (strcmp(s, "ipl") == 0) - return 1; - return 0; -} -# endif /* IPFILTER_LKM */ - - -/* - * Try to detect the case when compiling for NetBSD with pseudo-device - */ -# if defined(__NetBSD__) && defined(PFIL_HOOKS) -void -ipfilterattach(count) -int count; -{ - - /* - * Do nothing here, really. The filter will be enabled - * by the SIOCFRENB ioctl. - */ -} -# endif - - -# if defined(__NetBSD__) -int ipl_enable() -# else -int iplattach() -# endif -{ - char *defpass; - int s; -# if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)) - int error = 0; -# endif -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) - struct pfil_head *ph_inet; -# ifdef USE_INET6 - struct pfil_head *ph_inet6; -# endif -#endif - - SPL_NET(s); - if (fr_running || (fr_checkp == fr_check)) { - printf("IP Filter: already initialized\n"); - SPL_X(s); - return EBUSY; - } - -# ifdef IPFILTER_LOG - ipflog_init(); -# endif - if (nat_init() == -1) { - SPL_X(s); - return EIO; - } - if (fr_stateinit() == -1) { - SPL_X(s); - return EIO; - } - if (appr_init() == -1) { - SPL_X(s); - return EIO; - } - -# ifdef NETBSD_PF -# if (__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) -# if __NetBSD_Version__ >= 105110000 - ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); -# ifdef USE_INET6 - ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); -# endif - if (ph_inet == NULL -# ifdef USE_INET6 - && ph_inet6 == NULL -# endif - ) - return ENODEV; - - if (ph_inet != NULL) - error = pfil_add_hook((void *)fr_check_wrapper, NULL, - PFIL_IN|PFIL_OUT, ph_inet); - else - error = 0; -# else - error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif - if (error) { -# ifdef USE_INET6 - goto pfil_error; -# else - SPL_X(s); - appr_unload(); - ip_natunload(); - fr_stateunload(); - return error; -# endif - } -# else - pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); -# endif -# ifdef USE_INET6 -# if __NetBSD_Version__ >= 105110000 - if (ph_inet6 != NULL) - error = pfil_add_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); - else - error = 0; - if (error) { - pfil_remove_hook((void *)fr_check, NULL, - PFIL_IN|PFIL_OUT, ph_inet); -# else - error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); - if (error) { - pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif -pfil_error: - SPL_X(s); - appr_unload(); - ip_natunload(); - fr_stateunload(); - return error; - } -# endif -# endif - -# ifdef __sgi - error = ipfilter_sgi_attach(); - if (error) { - SPL_X(s); - appr_unload(); - ip_natunload(); - fr_stateunload(); - return error; - } -# endif - - bzero((char *)frcache, sizeof(frcache)); - fr_savep = fr_checkp; - fr_checkp = fr_check; - fr_running = 1; - - SPL_X(s); - if (fr_pass & FR_PASS) - defpass = "pass"; - else if (fr_pass & FR_BLOCK) - defpass = "block"; - else - defpass = "no-match -> block"; - - printf("%s initialized. Default = %s all, Logging = %s\n", - ipfilter_version, defpass, -# ifdef IPFILTER_LOG - "enabled"); -# else - "disabled"); -# endif -#ifdef _KERNEL -# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) - callout_init(&ipfr_slowtimer_ch); - callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); -# else -# if defined(__OpenBSD__) - timeout_set(&ipfr_slowtimer_ch, ipfr_slowtimer, NULL); - timeout_add(&ipfr_slowtimer_ch, hz/2); -# else -# if (__FreeBSD_version >= 300000) || defined(__sgi) - ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); -# else - timeout(ipfr_slowtimer, NULL, hz/2); -# endif -# endif -# endif -#endif - return 0; -} - - -/* - * Disable the filter by removing the hooks from the IP input/output - * stream. - */ -# if defined(__NetBSD__) -int ipl_disable() -# else -int ipldetach() -# endif -{ - int s, i; -#if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000) - int error = 0; -# if __NetBSD_Version__ >= 105150000 - struct pfil_head *ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); -# ifdef USE_INET6 - struct pfil_head *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); -# endif -# endif -#endif - -#ifdef _KERNEL -# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) - callout_stop(&ipfr_slowtimer_ch); -# else -# if (__FreeBSD_version >= 300000) - untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); -# else -# ifdef __sgi - untimeout(ipfr_slowtimer_ch); -# else -# if defined(__OpenBSD__) - timeout_del(&ipfr_slowtimer_ch); -# else - untimeout(ipfr_slowtimer, NULL); -# endif /* OpenBSD */ -# endif /* __sgi */ -# endif /* FreeBSD */ -# endif /* NetBSD */ -#endif - SPL_NET(s); - if (!fr_running) - { - printf("IP Filter: not initialized\n"); - SPL_X(s); - return 0; - } - - printf("%s unloaded\n", ipfilter_version); - - fr_checkp = fr_savep; - i = frflush(IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); - i += frflush(IPL_LOGIPF, FR_INQUE|FR_OUTQUE); - fr_running = 0; - -# ifdef NETBSD_PF -# if ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011)) -# if __NetBSD_Version__ >= 105110000 - if (ph_inet != NULL) - error = pfil_remove_hook((void *)fr_check_wrapper, NULL, - PFIL_IN|PFIL_OUT, ph_inet); - else - error = 0; -# else - error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif - if (error) { - SPL_X(s); - return error; - } -# else - pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); -# endif -# ifdef USE_INET6 -# if __NetBSD_Version__ >= 105110000 - if (ph_inet6 != NULL) - error = pfil_remove_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); - else - error = 0; -# else - error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); -# endif - if (error) { - SPL_X(s); - return error; - } -# endif -# endif - -# ifdef __sgi - ipfilter_sgi_detach(); -# endif - - appr_unload(); - ipfr_unload(); - ip_natunload(); - fr_stateunload(); - fr_authunload(); - - SPL_X(s); - return 0; -} -#endif /* _KERNEL */ - - -static int frzerostats(data) -caddr_t data; -{ - friostat_t fio; - int error; - - fr_getstat(&fio); - error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); - if (error) - return EFAULT; - - bzero((char *)frstats, sizeof(*frstats) * 2); - - return 0; -} - - -/* - * Filter ioctl interface. - */ -#ifdef __sgi -int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode -# ifdef _KERNEL - , cred_t *cp, int *rp -# endif -) -#else -int IPL_EXTERN(ioctl)(dev, cmd, data, mode -# if (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \ - (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \ - defined(__OpenBSD__))) -, p) -struct proc *p; -# else -) -# endif -dev_t dev; -# if defined(__NetBSD__) || defined(__OpenBSD__) || \ - (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) -u_long cmd; -# else -int cmd; -# endif -caddr_t data; -int mode; -#endif /* __sgi */ -{ -#if defined(_KERNEL) && !SOLARIS - int s; -#endif - int error = 0, unit = 0, tmp; - -#if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel >= 2) && (mode & FWRITE)) - return EPERM; -#endif -#ifdef _KERNEL - unit = GET_MINOR(dev); - if ((IPL_LOGMAX < unit) || (unit < 0)) - return ENXIO; -#else - unit = dev; -#endif - - if (fr_running == 0 && (cmd != SIOCFRENB || unit != IPL_LOGIPF)) - return ENODEV; - - SPL_NET(s); - - if (unit == IPL_LOGNAT) { - /* - * If we're doing a NAT operation, implicitly enable - * IP Filter if not already enabled. We do this - * because filtering and NAT are really separate - * operations, and it's not entirely obvious from - * a user's point of view that you need to enable - * the filter in order to enable NAT. - * - * Since the default rule is to pass all packets, - * this shouldn't cause any noticeable side-effects. - */ - if (fr_running == 0) { -#if defined(_KERNEL) - error = ipl_enable(); -#else - error = EIO; -#endif - } - if (error == 0) - error = nat_ioctl(data, cmd, mode); - SPL_X(s); - return error; - } - if (unit == IPL_LOGSTATE) { - if (fr_running) - error = fr_state_ioctl(data, cmd, mode); - else - error = EIO; - SPL_X(s); - return error; - } - if (unit == IPL_LOGAUTH) { - if (!fr_running) - error = EIO; - else - error = fr_auth_ioctl(data, mode, cmd, NULL, NULL); - SPL_X(s); - return error; - } - - switch (cmd) { - case FIONREAD : -#ifdef IPFILTER_LOG - error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, - sizeof(iplused[IPL_LOGIPF])); -#endif - break; -#if (!defined(IPFILTER_LKM) || defined(__NetBSD__)) && defined(_KERNEL) - case SIOCFRENB : - { - u_int enable; - - if (!(mode & FWRITE)) - error = EPERM; - else { - error = IRCOPY(data, (caddr_t)&enable, sizeof(enable)); - if (error) - break; - if (enable) -# if defined(__NetBSD__) - error = ipl_enable(); -# else - error = iplattach(); -# endif - else -# if defined(__NetBSD__) - error = ipl_disable(); -# else - error = ipldetach(); -# endif - } - break; - } -#endif - case SIOCSETFF : - if (!(mode & FWRITE)) - error = EPERM; - else - error = IRCOPY(data, (caddr_t)&fr_flags, - sizeof(fr_flags)); - break; - case SIOCGETFF : - error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); - break; - case SIOCINAFR : - case SIOCRMAFR : - case SIOCADAFR : - case SIOCZRLST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(unit, cmd, data, fr_active); - break; - case SIOCINIFR : - case SIOCRMIFR : - case SIOCADIFR : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(unit, cmd, data, 1 - fr_active); - break; - case SIOCSWAPA : - if (!(mode & FWRITE)) - error = EPERM; - else { - bzero((char *)frcache, sizeof(frcache[0]) * 2); - *(u_int *)data = fr_active; - fr_active = 1 - fr_active; - } - break; - case SIOCGETFS : - { - friostat_t fio; - - fr_getstat(&fio); - error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); - if (error) - error = EFAULT; - break; - } - case SIOCFRZST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frzerostats(data); - break; - case SIOCIPFFL : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - if (!error) { - tmp = frflush(unit, tmp); - error = IWCOPY((caddr_t)&tmp, data, - sizeof(tmp)); - } - } - break; - case SIOCSTLCK : - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - if (!error) { - fr_state_lock = tmp; - fr_nat_lock = tmp; - fr_frag_lock = tmp; - fr_auth_lock = tmp; - } else - error = EFAULT; - break; -#ifdef IPFILTER_LOG - case SIOCIPFFB : - if (!(mode & FWRITE)) - error = EPERM; - else - *(int *)data = ipflog_clear(unit); - break; -#endif /* IPFILTER_LOG */ - case SIOCGFRST : - error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, - sizeof(ipfrstat_t)); - if (error) - error = EFAULT; - break; - case SIOCAUTHW : - case SIOCAUTHR : - if (!(mode & FWRITE)) { - error = EPERM; - break; - } - case SIOCFRSYN : - if (!(mode & FWRITE)) - error = EPERM; - else { -#if defined(_KERNEL) && defined(__sgi) - ipfsync(); -#endif - frsync(); - } - break; - default : - error = EINVAL; - break; - } - SPL_X(s); - return error; -} - - -void fr_forgetifp(ifp) -void *ifp; -{ - register frentry_t *f; - - WRITE_ENTER(&ipf_mutex); - for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; - for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; - for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; - for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; -#ifdef USE_INET6 - for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; - for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; - for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; - for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) - if (f->fr_ifa == ifp) - f->fr_ifa = (void *)-1; -#endif - RWLOCK_EXIT(&ipf_mutex); - ip_natsync(ifp); -} - - -static int frrequest(unit, req, data, set) -int unit; -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -u_long req; -#else -int req; -#endif -int set; -caddr_t data; -{ - register frentry_t *fp, *f, **fprev; - register frentry_t **ftail; - frgroup_t *fg = NULL; - int error = 0, in, i; - u_int *p, *pp; - frentry_t frd; - frdest_t *fdp; - u_int group; - - fp = &frd; - error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); - if (error) - return EFAULT; - fp->fr_ref = 0; -#if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel > 0) && (fp->fr_func != NULL)) - return EPERM; -#endif - - /* - * Check that the group number does exist and that if a head group - * has been specified, doesn't exist. - */ - if ((req != SIOCZRLST) && ((req == SIOCINAFR) || (req == SIOCINIFR) || - (req == SIOCADAFR) || (req == SIOCADIFR)) && fp->fr_grhead && - fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL)) - return EEXIST; - if ((req != SIOCZRLST) && fp->fr_group && - !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL)) - return ESRCH; - - in = (fp->fr_flags & FR_INQUE) ? 0 : 1; - - if (unit == IPL_LOGAUTH) - ftail = fprev = &ipauth; - else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4)) - ftail = fprev = &ipacct[in][set]; - else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4)) - ftail = fprev = &ipfilter[in][set]; -#ifdef USE_INET6 - else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6)) - ftail = fprev = &ipacct6[in][set]; - else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6)) - ftail = fprev = &ipfilter6[in][set]; -#endif - else - return ESRCH; - - if ((group = fp->fr_group)) { - if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL))) - return ESRCH; - ftail = fprev = fg->fg_start; - } - - bzero((char *)frcache, sizeof(frcache[0]) * 2); - - for (i = 0; i < 4; i++) { - if ((fp->fr_ifnames[i][1] == '\0') && - ((fp->fr_ifnames[i][0] == '-') || - (fp->fr_ifnames[i][0] == '*'))) { - fp->fr_ifas[i] = NULL; - } else if (*fp->fr_ifnames[i]) { - fp->fr_ifas[i] = GETUNIT(fp->fr_ifnames[i], fp->fr_v); - if (!fp->fr_ifas[i]) - fp->fr_ifas[i] = (void *)-1; - } - } - - fdp = &fp->fr_dif; - fp->fr_flags &= ~FR_DUP; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; - else - fp->fr_flags |= FR_DUP; - } - - fdp = &fp->fr_tif; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; - } - - /* - * Look for a matching filter rule, but don't include the next or - * interface pointer in the comparison (fr_next, fr_ifa). - */ - for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum; - p < pp; p++) - fp->fr_cksum += *p; - - for (; (f = *ftail); ftail = &f->fr_next) - if ((fp->fr_cksum == f->fr_cksum) && - !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ)) - break; - - /* - * If zero'ing statistics, copy current to caller and zero. - */ - if (req == SIOCZRLST) { - if (!f) - return ESRCH; - error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); - if (error) - return EFAULT; - f->fr_hits = 0; - f->fr_bytes = 0; - return 0; - } - - if (!f) { - if (req != SIOCINAFR && req != SIOCINIFR) - while ((f = *ftail)) - ftail = &f->fr_next; - else { - if (fp->fr_hits) { - ftail = fprev; - while (--fp->fr_hits && (f = *ftail)) - ftail = &f->fr_next; - } - f = NULL; - } - } - - if (req == SIOCRMAFR || req == SIOCRMIFR) { - if (!f) - error = ESRCH; - else { - /* - * Only return EBUSY if there is a group list, else - * it's probably just state information referencing - * the rule. - */ - if ((f->fr_ref > 1) && f->fr_grp) - return EBUSY; - if (fg && fg->fg_head) - fg->fg_head->fr_ref--; - if (f->fr_grhead) - fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, - unit, set); - fixskip(fprev, f, -1); - *ftail = f->fr_next; - f->fr_next = NULL; - f->fr_ref--; - if (f->fr_ref == 0) - KFREE(f); - } - } else { - if (f) - error = EEXIST; - else { - KMALLOC(f, frentry_t *); - if (f != NULL) { - if (fg && fg->fg_head) - fg->fg_head->fr_ref++; - bcopy((char *)fp, (char *)f, sizeof(*f)); - f->fr_ref = 1; - f->fr_hits = 0; - f->fr_next = *ftail; - *ftail = f; - if (req == SIOCINIFR || req == SIOCINAFR) - fixskip(fprev, f, 1); - f->fr_grp = NULL; - if ((group = f->fr_grhead)) - fg = fr_addgroup(group, f, unit, set); - } else - error = ENOMEM; - } - } - return (error); -} - - -#ifdef _KERNEL -/* - * routines below for saving IP headers to buffer - */ -# ifdef __sgi -# ifdef _KERNEL -int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp) -# else -int IPL_EXTERN(open)(dev_t dev, int flags) -# endif -# else -int IPL_EXTERN(open)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) -, devtype, p) -int devtype; -struct proc *p; -# else -) -# endif -dev_t dev; -int flags; -# endif /* __sgi */ -{ -# if defined(__sgi) && defined(_KERNEL) - u_int min = geteminor(*pdev); -# else - u_int min = GET_MINOR(dev); -# endif - - if (IPL_LOGMAX < min) - min = ENXIO; - else - min = 0; - return min; -} - - -# ifdef __sgi -int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp) -#else -int IPL_EXTERN(close)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) -, devtype, p) -int devtype; -struct proc *p; -# else -) -# endif -dev_t dev; -int flags; -# endif /* __sgi */ -{ - u_int min = GET_MINOR(dev); - - if (IPL_LOGMAX < min) - min = ENXIO; - else - min = 0; - return min; -} - -/* - * iplread/ipllog - * both of these must operate with at least splnet() lest they be - * called during packet processing and cause an inconsistancy to appear in - * the filter lists. - */ -# ifdef __sgi -int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp) -# else -# if BSD >= 199306 -int IPL_EXTERN(read)(dev, uio, ioflag) -int ioflag; -# else -int IPL_EXTERN(read)(dev, uio) -# endif -dev_t dev; -register struct uio *uio; -# endif /* __sgi */ -{ -# ifdef IPFILTER_LOG - return ipflog_read(GET_MINOR(dev), uio); -# else - return ENXIO; -# endif -} - - -/* - * send_reset - this could conceivably be a call to tcp_respond(), but that - * requires a large amount of setting up and isn't any more efficient. - */ -int send_reset(oip, fin) -struct ip *oip; -fr_info_t *fin; -{ - struct tcphdr *tcp, *tcp2; - int tlen = 0, hlen; - struct mbuf *m; -#ifdef USE_INET6 - ip6_t *ip6, *oip6 = (ip6_t *)oip; -#endif - ip_t *ip; - - tcp = (struct tcphdr *)fin->fin_dp; - if (tcp->th_flags & TH_RST) - return -1; /* feedback loop */ -# if (BSD < 199306) || defined(__sgi) - m = m_get(M_DONTWAIT, MT_HEADER); -# else - m = m_gethdr(M_DONTWAIT, MT_HEADER); -# endif - if (m == NULL) - return ENOBUFS; - if (m == NULL) - return -1; - - tlen = fin->fin_dlen - (tcp->th_off << 2) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - -#ifdef USE_INET6 - hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); -#else - hlen = sizeof(ip_t); -#endif - m->m_len = sizeof(*tcp2) + hlen; -# if BSD >= 199306 - m->m_data += max_linkhdr; - m->m_pkthdr.len = m->m_len; - m->m_pkthdr.rcvif = (struct ifnet *)0; -# endif - ip = mtod(m, struct ip *); -# ifdef USE_INET6 - ip6 = (ip6_t *)ip; -# endif - bzero((char *)ip, sizeof(*tcp2) + hlen); - tcp2 = (struct tcphdr *)((char *)ip + hlen); - - tcp2->th_sport = tcp->th_dport; - tcp2->th_dport = tcp->th_sport; - if (tcp->th_flags & TH_ACK) { - tcp2->th_seq = tcp->th_ack; - tcp2->th_flags = TH_RST; - } else { - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); - tcp2->th_flags = TH_RST|TH_ACK; - } - tcp2->th_off = sizeof(*tcp2) >> 2; -# ifdef USE_INET6 - if (fin->fin_v == 6) { - ip6->ip6_plen = htons(sizeof(struct tcphdr)); - ip6->ip6_nxt = IPPROTO_TCP; - ip6->ip6_src = oip6->ip6_dst; - ip6->ip6_dst = oip6->ip6_src; - tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, - sizeof(*ip6), sizeof(*tcp2)); - return send_ip(oip, fin, &m); - } -# endif - ip->ip_p = IPPROTO_TCP; - ip->ip_len = htons(sizeof(struct tcphdr)); - ip->ip_src.s_addr = oip->ip_dst.s_addr; - ip->ip_dst.s_addr = oip->ip_src.s_addr; - tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); - ip->ip_len = hlen + sizeof(*tcp2); - return send_ip(oip, fin, &m); -} - - -/* - * Send an IP(v4/v6) datagram out into the network - */ -static int send_ip(oip, fin, mp) -ip_t *oip; -fr_info_t *fin; -struct mbuf **mp; -{ - struct mbuf *m = *mp; - int error, hlen; - fr_info_t frn; - ip_t *ip; - - bzero((char *)&frn, sizeof(frn)); - frn.fin_ifp = fin->fin_ifp; - frn.fin_v = fin->fin_v; - frn.fin_out = fin->fin_out; - frn.fin_mp = fin->fin_mp; - - ip = mtod(m, ip_t *); - hlen = sizeof(*ip); - - ip->ip_v = fin->fin_v; - if (ip->ip_v == 4) { - ip->ip_hl = (sizeof(*oip) >> 2); - ip->ip_v = IPVERSION; - ip->ip_tos = oip->ip_tos; - ip->ip_id = oip->ip_id; - -# if defined(__NetBSD__) || defined(__OpenBSD__) - if (ip_mtudisc != 0) - ip->ip_off = IP_DF; -# else -# if defined(__sgi) - if (ip->ip_p == IPPROTO_TCP && tcp_mtudisc != 0) - ip->ip_off = IP_DF; -# endif -# endif - -# if (BSD < 199306) || defined(__sgi) - ip->ip_ttl = tcp_ttl; -# else - ip->ip_ttl = ip_defttl; -# endif - ip->ip_sum = 0; - frn.fin_dp = (char *)(ip + 1); - } -# ifdef USE_INET6 - else if (ip->ip_v == 6) { - ip6_t *ip6 = (ip6_t *)ip; - - hlen = sizeof(*ip6); - ip6->ip6_hlim = 127; - frn.fin_dp = (char *)(ip6 + 1); - } -# endif -# ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -# endif - - fr_makefrip(hlen, ip, &frn); - - error = ipfr_fastroute(m, mp, &frn, NULL); - return error; -} - - -int send_icmp_err(oip, type, fin, dst) -ip_t *oip; -int type; -fr_info_t *fin; -int dst; -{ - int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code; - u_short shlen, slen = 0, soff = 0; - struct in_addr dst4; - struct icmp *icmp; - struct mbuf *m; - void *ifp; -#ifdef USE_INET6 - ip6_t *ip6, *oip6 = (ip6_t *)oip; - struct in6_addr dst6; -#endif - ip_t *ip; - - if ((type < 0) || (type > ICMP_MAXTYPE)) - return -1; - - code = fin->fin_icode; -#ifdef USE_INET6 - if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) - return -1; -#endif - - avail = 0; - m = NULL; - ifp = fin->fin_ifp; - if (fin->fin_v == 4) { - if ((oip->ip_p == IPPROTO_ICMP) && - !(fin->fin_fi.fi_fl & FI_SHORT)) - switch (ntohs(fin->fin_data[0]) >> 8) - { - case ICMP_ECHO : - case ICMP_TSTAMP : - case ICMP_IREQ : - case ICMP_MASKREQ : - break; - default : - return 0; - } - -# if (BSD < 199306) || defined(__sgi) - avail = MLEN; - m = m_get(M_DONTWAIT, MT_HEADER); -# else - avail = MHLEN; - m = m_gethdr(M_DONTWAIT, MT_HEADER); -# endif - if (m == NULL) - return ENOBUFS; - - if (dst == 0) { - if (fr_ifpaddr(4, ifp, &dst4) == -1) - return -1; - } else - dst4.s_addr = oip->ip_dst.s_addr; - - hlen = sizeof(ip_t); - ohlen = oip->ip_hl << 2; - xtra = 8; - } - -#ifdef USE_INET6 - else if (fin->fin_v == 6) { - hlen = sizeof(ip6_t); - ohlen = sizeof(ip6_t); - type = icmptoicmp6types[type]; - if (type == ICMP6_DST_UNREACH) - code = icmptoicmp6unreach[code]; - - MGETHDR(m, M_DONTWAIT, MT_HEADER); - if (!m) - return ENOBUFS; - - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - return ENOBUFS; - } -# ifdef M_TRAILINGSPACE - m->m_len = 0; - avail = M_TRAILINGSPACE(m); -# else - avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; -# endif - xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), - avail - hlen - sizeof(*icmp) - max_linkhdr); - if (dst == 0) { - if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1) - return -1; - } else - dst6 = oip6->ip6_dst; - } -#endif - - iclen = hlen + sizeof(*icmp); -# if BSD >= 199306 - avail -= (max_linkhdr + iclen); - m->m_data += max_linkhdr; - m->m_pkthdr.rcvif = (struct ifnet *)0; - if (xtra > avail) - xtra = avail; - iclen += xtra; - m->m_pkthdr.len = iclen; -#else - avail -= (m->m_off + iclen); - if (xtra > avail) - xtra = avail; - iclen += xtra; -#endif - m->m_len = iclen; - ip = mtod(m, ip_t *); - icmp = (struct icmp *)((char *)ip + hlen); - bzero((char *)ip, iclen); - - icmp->icmp_type = type; - icmp->icmp_code = fin->fin_icode; - icmp->icmp_cksum = 0; -#ifdef icmp_nextmtu - if (type == ICMP_UNREACH && - fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) - icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu); -#endif - - if (avail) { - bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); - avail -= MIN(ohlen, avail); - } - -#ifdef USE_INET6 - ip6 = (ip6_t *)ip; - if (fin->fin_v == 6) { - ip6->ip6_flow = 0; - ip6->ip6_plen = htons(iclen - hlen); - ip6->ip6_nxt = IPPROTO_ICMPV6; - ip6->ip6_hlim = 0; - ip6->ip6_src = dst6; - ip6->ip6_dst = oip6->ip6_src; - if (avail) - bcopy((char *)oip + ohlen, - (char *)&icmp->icmp_ip + ohlen, avail); - icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, - sizeof(*ip6), iclen - hlen); - } else -#endif - { - slen = oip->ip_len; - oip->ip_len = htons(oip->ip_len); - soff = oip->ip_off; - oip->ip_off = htons(ip->ip_off); - - ip->ip_src.s_addr = dst4.s_addr; - ip->ip_dst.s_addr = oip->ip_src.s_addr; - - if (avail > 8) - avail = 8; - if (avail) - bcopy((char *)oip + ohlen, - (char *)&icmp->icmp_ip + ohlen, avail); - icmp->icmp_cksum = ipf_cksum((u_short *)icmp, - sizeof(*icmp) + 8); - ip->ip_len = iclen; - ip->ip_p = IPPROTO_ICMP; - } - - shlen = fin->fin_hlen; - fin->fin_hlen = hlen; - err = send_ip(oip, fin, &m); - fin->fin_hlen = shlen; -#ifdef USE_INET6 - if (fin->fin_v == 4) -#endif - { - oip->ip_len = slen; - oip->ip_off = soff; - } - return err; -} - - -# if !defined(IPFILTER_LKM) && !defined(__sgi) && \ - (!defined(__FreeBSD_version) || (__FreeBSD_version < 300000)) -# if (BSD < 199306) -int iplinit __P((void)); - -int -# else -void iplinit __P((void)); - -void -# endif -iplinit() -{ - -# if defined(__NetBSD__) - if (ipl_enable() != 0) -# else - if (iplattach() != 0) -# endif - { - printf("IP Filter failed to attach\n"); - } - ip_init(); -} -# endif /* ! __NetBSD__ */ - - -/* - * Return the length of the entire mbuf. - */ -size_t mbufchainlen(m0) -register struct mbuf *m0; -{ -#if BSD >= 199306 - return m0->m_pkthdr.len; -#else - register size_t len = 0; - - for (; m0; m0 = m0->m_next) - len += m0->m_len; - return len; -#endif -} - - -int ipfr_fastroute(m0, mpp, fin, fdp) -struct mbuf *m0, **mpp; -fr_info_t *fin; -frdest_t *fdp; -{ - register struct ip *ip, *mhip; - register struct mbuf *m = m0; - register struct route *ro; - int len, off, error = 0, hlen, code; - struct ifnet *ifp, *sifp; - struct sockaddr_in *dst; - struct route iproute; - frentry_t *fr; - - ip = NULL; - ro = NULL; - ifp = NULL; - ro = &iproute; - ro->ro_rt = NULL; - -#ifdef USE_INET6 - if (fin->fin_v == 6) { - error = ipfr_fastroute6(m0, mpp, fin, fdp); - if (error != 0) - goto bad; - goto done; - } -#else - if (fin->fin_v == 6) - goto bad; -#endif - -#ifdef M_WRITABLE - /* - * HOT FIX/KLUDGE: - * - * If the mbuf we're about to send is not writable (because of - * a cluster reference, for example) we'll need to make a copy - * of it since this routine modifies the contents. - * - * If you have non-crappy network hardware that can transmit data - * from the mbuf, rather than making a copy, this is gonna be a - * problem. - */ - if (M_WRITABLE(m) == 0) { - if ((m0 = m_dup(m, M_DONTWAIT)) != NULL) { - m_freem(*mpp); - *mpp = m0; - m = m0; - } else { - error = ENOBUFS; - m_freem(*mpp); - goto done; - } - } -#endif - - hlen = fin->fin_hlen; - ip = mtod(m0, struct ip *); - -#if defined(__NetBSD__) && defined(M_CSUM_IPv4) - /* - * Clear any in-bound checksum flags for this packet. - */ -# if (__NetBSD_Version__ > 105009999) - m0->m_pkthdr.csum_flags = 0; -# else - m0->m_pkthdr.csuminfo = 0; -# endif -#endif /* __NetBSD__ && M_CSUM_IPv4 */ - - /* - * Route packet. - */ -#ifdef __sgi - ROUTE_RDLOCK(); -#endif - bzero((caddr_t)ro, sizeof (*ro)); - dst = (struct sockaddr_in *)&ro->ro_dst; - dst->sin_family = AF_INET; - dst->sin_addr = ip->ip_dst; - - fr = fin->fin_fr; - if (fdp != NULL) - ifp = fdp->fd_ifp; - else - ifp = fin->fin_ifp; - - /* - * In case we're here due to "to " being used with "keep state", - * check that we're going in the correct direction. - */ - if ((fr != NULL) && (fin->fin_rev != 0)) { - if ((ifp != NULL) && (fdp == &fr->fr_tif)) - return 0; - } else if (fdp != NULL) { - if (fdp->fd_ip.s_addr != 0) - dst->sin_addr = fdp->fd_ip; - } - -# if BSD >= 199306 - dst->sin_len = sizeof(*dst); -# endif -# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ - !defined(__OpenBSD__) -# ifdef RTF_CLONING - rtalloc_ign(ro, RTF_CLONING); -# else - rtalloc_ign(ro, RTF_PRCLONING); -# endif -# else - rtalloc(ro); -# endif - -#ifdef __sgi - ROUTE_UNLOCK(); -#endif - - if (!ifp) { - if (!fr || !(fr->fr_flags & FR_FASTROUTE)) { - error = -2; - goto bad; - } - } - - if ((ifp == NULL) && (ro->ro_rt != NULL)) - ifp = ro->ro_rt->rt_ifp; - - if ((ro->ro_rt == NULL) || (ifp == NULL)) { - if (in_localaddr(ip->ip_dst)) - error = EHOSTUNREACH; - else - error = ENETUNREACH; - goto bad; - } - - if (ro->ro_rt->rt_flags & RTF_GATEWAY) { -#if BSD >= 199306 - dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; -#else - dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; -#endif - } - ro->ro_rt->rt_use++; - - /* - * For input packets which are being "fastrouted", they won't - * go back through output filtering and miss their chance to get - * NAT'd and counted. - */ - if (fin->fin_out == 0) { - sifp = fin->fin_ifp; - fin->fin_ifp = ifp; - fin->fin_out = 1; - if ((fin->fin_fr = ipacct[1][fr_active]) && - (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INCL(frstats[1].fr_acct); - } - fin->fin_fr = NULL; - if (!fr || !(fr->fr_flags & FR_RETMASK)) - (void) fr_checkstate(ip, fin); - (void) ip_natout(ip, fin); - fin->fin_ifp = sifp; - } - ip->ip_sum = 0; - /* - * If small enough for interface, can just send directly. - */ - if (ip->ip_len <= ifp->if_mtu) { -# ifndef sparc -# if (!defined(__FreeBSD__) && !(_BSDI_VERSION >= 199510)) && \ - !(__NetBSD_Version__ >= 105110000) - ip->ip_id = htons(ip->ip_id); -# endif - ip->ip_len = htons(ip->ip_len); - ip->ip_off = htons(ip->ip_off); -# endif -# if defined(__NetBSD__) && defined(M_CSUM_IPv4) -# if (__NetBSD_Version__ > 105009999) - if (ifp->if_csum_flags_tx & IFCAP_CSUM_IPv4) - m->m_pkthdr.csum_flags |= M_CSUM_IPv4; - else if (ip->ip_sum == 0) - ip->ip_sum = in_cksum(m, hlen); -# else - if (ifp->if_capabilities & IFCAP_CSUM_IPv4) - m->m_pkthdr.csuminfo |= M_CSUM_IPv4; - else if (ip->ip_sum == 0) - ip->ip_sum = in_cksum(m, hlen); -# endif -# else - if (!ip->ip_sum) - ip->ip_sum = in_cksum(m, hlen); -# endif /* __NetBSD__ && M_CSUM_IPv4 */ -# if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, - ro->ro_rt); -# else - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); -# endif - goto done; - } - - /* - * Too large for interface; fragment if possible. - * Must be able to put at least 8 bytes per fragment. - */ - if (ip->ip_off & IP_DF) { - error = EMSGSIZE; - goto bad; - } - len = (ifp->if_mtu - hlen) &~ 7; - if (len < 8) { - error = EMSGSIZE; - goto bad; - } - - { - int mhlen, firstlen = len; - struct mbuf **mnext = &m->m_act; - - /* - * Loop through length of segment after first fragment, - * make new header and copy data of each part and link onto chain. - */ - m0 = m; - mhlen = sizeof (struct ip); - for (off = hlen + len; off < ip->ip_len; off += len) { -# ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); -# else - MGET(m, M_DONTWAIT, MT_HEADER); -# endif - if (m == 0) { - error = ENOBUFS; - goto bad; - } -# if BSD >= 199306 - m->m_data += max_linkhdr; -# else - m->m_off = MMAXOFF - hlen; -# endif - mhip = mtod(m, struct ip *); - bcopy((char *)ip, (char *)mhip, sizeof(*ip)); - if (hlen > sizeof (struct ip)) { - mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); - mhip->ip_hl = mhlen >> 2; - } - m->m_len = mhlen; - mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); - if (ip->ip_off & IP_MF) - mhip->ip_off |= IP_MF; - if (off + len >= ip->ip_len) - len = ip->ip_len - off; - else - mhip->ip_off |= IP_MF; - mhip->ip_len = htons((u_short)(len + mhlen)); - m->m_next = m_copy(m0, off, len); - if (m->m_next == 0) { - error = ENOBUFS; /* ??? */ - goto sendorfree; - } -# if BSD >= 199306 - m->m_pkthdr.len = mhlen + len; - m->m_pkthdr.rcvif = NULL; -# endif - mhip->ip_off = htons((u_short)mhip->ip_off); - mhip->ip_sum = 0; - mhip->ip_sum = in_cksum(m, mhlen); - *mnext = m; - mnext = &m->m_act; - } - /* - * Update first fragment by trimming what's been copied out - * and updating header, then send each fragment (in order). - */ - m_adj(m0, hlen + firstlen - ip->ip_len); - ip->ip_len = htons((u_short)(hlen + firstlen)); - ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m0, hlen); -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_act; - m->m_act = 0; - if (error == 0) -# if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst, ro->ro_rt); -# else - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst); -# endif - else - m_freem(m); - } - } -done: - if (!error) - ipl_frouteok[0]++; - else - ipl_frouteok[1]++; - - if (ro->ro_rt != NULL) { - RTFREE(ro->ro_rt); - } - *mpp = NULL; - return error; -bad: - if ((error == EMSGSIZE) && (fin->fin_v == 4)) { - sifp = fin->fin_ifp; - code = fin->fin_icode; - fin->fin_icode = ICMP_UNREACH_NEEDFRAG; - fin->fin_ifp = ifp; - (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1); - fin->fin_ifp = sifp; - fin->fin_icode = code; - } - m_freem(m); - goto done; -} - - -/* - * Return true or false depending on whether the route to the - * given IP address uses the same interface as the one passed. - */ -int fr_verifysrc(ipa, ifp) -struct in_addr ipa; -void *ifp; -{ - struct sockaddr_in *dst; - struct route iproute; - - bzero((char *)&iproute, sizeof(iproute)); - dst = (struct sockaddr_in *)&iproute.ro_dst; -# if (BSD >= 199306) - dst->sin_len = sizeof(*dst); -# endif - dst->sin_family = AF_INET; - dst->sin_addr = ipa; -# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ - !defined(__OpenBSD__) -# ifdef RTF_CLONING - rtalloc_ign(&iproute, RTF_CLONING); -# else - rtalloc_ign(&iproute, RTF_PRCLONING); -# endif -# else - rtalloc(&iproute); -# endif - if (iproute.ro_rt == NULL) - return 0; - return (ifp == iproute.ro_rt->rt_ifp); -} - - -# ifdef USE_GETIFNAME -char * -get_ifname(ifp) -struct ifnet *ifp; -{ - static char workbuf[64]; - - sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); - return workbuf; -} -# endif - - -# if defined(USE_INET6) -/* - * This is the IPv6 specific fastroute code. It doesn't clean up the mbuf's - * or ensure that it is an IPv6 packet that is being forwarded, those are - * expected to be done by the called (ipfr_fastroute). - */ -static int ipfr_fastroute6(m0, mpp, fin, fdp) -struct mbuf *m0, **mpp; -fr_info_t *fin; -frdest_t *fdp; -{ - struct route_in6 ip6route; - struct sockaddr_in6 *dst6; - struct route_in6 *ro; - struct ifnet *ifp; - frentry_t *fr; - int error; - - ro = &ip6route; - fr = fin->fin_fr; - bzero((caddr_t)ro, sizeof(*ro)); - dst6 = (struct sockaddr_in6 *)&ro->ro_dst; - dst6->sin6_family = AF_INET6; - dst6->sin6_len = sizeof(struct sockaddr_in6); - dst6->sin6_addr = fin->fin_fi.fi_dst.in6; - - if (fdp != NULL) - ifp = fdp->fd_ifp; - else - ifp = fin->fin_ifp; - - if ((fr != NULL) && (fin->fin_rev != 0)) { - if ((ifp != NULL) && (fdp == &fr->fr_tif)) - return 0; - } else if (fdp != NULL) { - if (IP6_NOTZERO(&fdp->fd_ip6)) - dst6->sin6_addr = fdp->fd_ip6.in6; - } - if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) - return -2; - - rtalloc((struct route *)ro); - - if ((ifp == NULL) && (ro->ro_rt != NULL)) - ifp = ro->ro_rt->rt_ifp; - - if ((ro->ro_rt == NULL) || (ifp == NULL) || - (ifp != ro->ro_rt->rt_ifp)) { - error = EHOSTUNREACH; - } else { - if (ro->ro_rt->rt_flags & RTF_GATEWAY) - dst6 = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway; - ro->ro_rt->rt_use++; - - if (m0->m_pkthdr.len <= IN6_LINKMTU(ifp)) - error = nd6_output(ifp, fin->fin_ifp, m0, dst6, - ro->ro_rt); - else - error = EMSGSIZE; - } - - if (ro->ro_rt != NULL) { - RTFREE(ro->ro_rt); - } - return error; -} -# endif -#else /* #ifdef _KERNEL */ - - -# if defined(__sgi) && (IRIX < 605) -static int no_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s)) -# else -static int no_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s, struct rtentry *rt)) -# endif -{ - return 0; -} - - -# ifdef __STDC__ -# if defined(__sgi) && (IRIX < 605) -static int write_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s)) -# else -static int write_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s, struct rtentry *rt)) -# endif -{ - ip_t *ip = (ip_t *)m; -# else -static int write_output(ifp, ip) -struct ifnet *ifp; -ip_t *ip; -{ -# endif - char fname[32]; - int fd; - -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - sprintf(fname, "%s", ifp->if_xname); -# else - sprintf(fname, "%s%d", ifp->if_name, ifp->if_unit); -# endif - fd = open(fname, O_WRONLY|O_APPEND); - if (fd == -1) { - perror("open"); - return -1; - } - write(fd, (char *)ip, ntohs(ip->ip_len)); - close(fd); - return 0; -} - - -char *get_ifname(ifp) -struct ifnet *ifp; -{ -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - return ifp->if_xname; -# else - static char fullifname[LIFNAMSIZ]; - - sprintf(fullifname, "%s%d", ifp->if_name, ifp->if_unit); - return fullifname; -# endif -} - - -struct ifnet *get_unit(ifname, v) -char *ifname; -int v; -{ - struct ifnet *ifp, **ifa, **old_ifneta; - - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - if (!strncmp(ifname, ifp->if_xname, sizeof(ifp->if_xname))) -# else - char fullname[LIFNAMSIZ]; - - sprintf(fullname, "%s%d", ifp->if_name, ifp->if_unit); - if (!strcmp(ifname, fullname)) -# endif - return ifp; - } - - if (!ifneta) { - ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); - if (!ifneta) - return NULL; - ifneta[1] = NULL; - ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp)); - if (!ifneta[0]) { - free(ifneta); - return NULL; - } - nifs = 1; - } else { - old_ifneta = ifneta; - nifs++; - ifneta = (struct ifnet **)realloc(ifneta, - (nifs + 1) * sizeof(*ifa)); - if (!ifneta) { - free(old_ifneta); - nifs = 0; - return NULL; - } - ifneta[nifs] = NULL; - ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp)); - if (!ifneta[nifs - 1]) { - nifs--; - return NULL; - } - } - ifp = ifneta[nifs - 1]; - -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - strncpy(ifp->if_xname, ifname, sizeof(ifp->if_xname)); -# else - ifp->if_name = strdup(ifname); - - ifname = ifp->if_name; - while (*ifname && !isdigit(*ifname)) - ifname++; - if (*ifname && isdigit(*ifname)) { - ifp->if_unit = atoi(ifname); - *ifname = '\0'; - } else - ifp->if_unit = -1; -# endif - ifp->if_output = no_output; - return ifp; -} - - - -void init_ifp() -{ - struct ifnet *ifp, **ifa; - char fname[32]; - int fd; - -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { - ifp->if_output = write_output; - sprintf(fname, "/tmp/%s", ifp->if_xname); - fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); - if (fd == -1) - perror("open"); - else - close(fd); - } -# else - - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { - ifp->if_output = write_output; - sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); - fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); - if (fd == -1) - perror("open"); - else - close(fd); - } -# endif -} - - -int send_reset(ip, fin) -ip_t *ip; -fr_info_t *fin; -{ - verbose("- TCP RST sent\n"); - return 0; -} - - -int send_icmp_err(ip, code, fin, dst) -ip_t *ip; -int code; -fr_info_t *fin; -int dst; -{ - verbose("- ICMP UNREACHABLE sent\n"); - return 0; -} - - -void frsync() -{ - return; -} - -void m_copydata(m, off, len, cp) -mb_t *m; -int off, len; -caddr_t cp; -{ - bcopy((char *)m + off, cp, len); -} - - -int ipfuiomove(buf, len, rwflag, uio) -caddr_t buf; -int len, rwflag; -struct uio *uio; -{ - int left, ioc, num, offset; - struct iovec *io; - char *start; - - if (rwflag == UIO_READ) { - left = len; - ioc = 0; - - offset = uio->uio_offset; - - while ((left > 0) && (ioc < uio->uio_iovcnt)) { - io = uio->uio_iov + ioc; - num = io->iov_len; - if (num > left) - num = left; - start = (char *)io->iov_base + offset; - if (start > (char *)io->iov_base + io->iov_len) { - offset -= io->iov_len; - ioc++; - continue; - } - bcopy(buf, start, num); - uio->uio_resid -= num; - uio->uio_offset += num; - left -= num; - if (left > 0) - ioc++; - } - if (left > 0) - return EFAULT; - } - return 0; -} -#endif /* _KERNEL */ diff --git a/sys/netinet/ip_fil.h b/sys/netinet/ip_fil.h index 2edf937d7398..58a8b68715b3 100644 --- a/sys/netinet/ip_fil.h +++ b/sys/netinet/ip_fil.h @@ -1,33 +1,21 @@ -/* $NetBSD: ip_fil.h,v 1.53 2004/02/24 15:12:52 wiz Exp $ */ +/* $NetBSD: ip_fil.h,v 1.54 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1993-2002 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_fil.h 1.35 6/5/96 - * Id: ip_fil.h,v 2.29.2.33 2002/06/04 14:46:28 darrenr Exp + * Id: ip_fil.h,v 2.170 2004/02/10 12:23:08 darrenr Exp */ #ifndef _NETINET_IP_FIL_H_ #define _NETINET_IP_FIL_H_ -/* - * Pathnames for various IP Filter control devices. Used by LKM - * and userland, so defined here. - */ -#define IPNAT_NAME "/dev/ipnat" -#define IPSTATE_NAME "/dev/ipstate" -#define IPAUTH_NAME "/dev/ipauth" - #ifndef SOLARIS # define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif - #ifndef __P # ifdef __STDC__ # define __P(x) x @@ -36,135 +24,313 @@ # endif #endif -#ifndef offsetof -# define offsetof(t,m) (int)((&((t *)0L)->m)) -#endif - #if defined(__STDC__) || defined(__GNUC__) -# define SIOCADAFR _IOW('r', 60, struct frentry *) -# define SIOCRMAFR _IOW('r', 61, struct frentry *) +# define SIOCADAFR _IOW('r', 60, struct ipfobj) +# define SIOCRMAFR _IOW('r', 61, struct ipfobj) # define SIOCSETFF _IOW('r', 62, u_int) # define SIOCGETFF _IOR('r', 63, u_int) -# define SIOCGETFS _IOWR('r', 64, struct friostat *) +# define SIOCGETFS _IOWR('r', 64, struct ipfobj) # define SIOCIPFFL _IOWR('r', 65, int) # define SIOCIPFFB _IOR('r', 66, int) -# define SIOCADIFR _IOW('r', 67, struct frentry *) -# define SIOCRMIFR _IOW('r', 68, struct frentry *) +# define SIOCADIFR _IOW('r', 67, struct ipfobj) +# define SIOCRMIFR _IOW('r', 68, struct ipfobj) # define SIOCSWAPA _IOR('r', 69, u_int) -# define SIOCINAFR _IOW('r', 70, struct frentry *) -# define SIOCINIFR _IOW('r', 71, struct frentry *) +# define SIOCINAFR _IOW('r', 70, struct ipfobj) +# define SIOCINIFR _IOW('r', 71, struct ipfobj) # define SIOCFRENB _IOW('r', 72, u_int) # define SIOCFRSYN _IOW('r', 73, u_int) -# define SIOCFRZST _IOWR('r', 74, struct friostat *) -# define SIOCZRLST _IOWR('r', 75, struct frentry *) -# define SIOCAUTHW _IOWR('r', 76, struct frauth *) -# define SIOCAUTHR _IOWR('r', 77, struct frauth *) -# define SIOCATHST _IOWR('r', 78, struct fr_authstat *) +# define SIOCFRZST _IOWR('r', 74, struct ipfobj) +# define SIOCZRLST _IOWR('r', 75, struct ipfobj) +# define SIOCAUTHW _IOWR('r', 76, struct ipfobj) +# define SIOCAUTHR _IOWR('r', 77, struct ipfobj) +# define SIOCATHST _IOWR('r', 78, struct ipfobj) # define SIOCSTLCK _IOWR('r', 79, u_int) -# define SIOCSTPUT _IOWR('r', 80, struct ipstate_save *) -# define SIOCSTGET _IOWR('r', 81, struct ipstate_save *) -# define SIOCSTGSZ _IOWR('r', 82, struct natget) -# define SIOCGFRST _IOWR('r', 83, struct ipfrstat *) +# define SIOCSTPUT _IOWR('r', 80, struct ipfobj) +# define SIOCSTGET _IOWR('r', 81, struct ipfobj) +# define SIOCSTGSZ _IOWR('r', 82, struct ipfobj) +# define SIOCGFRST _IOWR('r', 83, struct ipfobj) +# define SIOCSETLG _IOWR('r', 84, int) +# define SIOCGETLG _IOWR('r', 85, int) +# define SIOCFUNCL _IOWR('r', 86, struct ipfunc_resolve) +# define SIOCIPFGETNEXT _IOWR('r', 87, struct ipfobj) +# define SIOCIPFGET _IOWR('r', 88, struct ipfobj) +# define SIOCIPFSET _IOWR('r', 89, struct ipfobj) #else -# define SIOCADAFR _IOW(r, 60, struct frentry *) -# define SIOCRMAFR _IOW(r, 61, struct frentry *) +# define SIOCADAFR _IOW(r, 60, struct ipfobj) +# define SIOCRMAFR _IOW(r, 61, struct ipfobj) # define SIOCSETFF _IOW(r, 62, u_int) # define SIOCGETFF _IOR(r, 63, u_int) -# define SIOCGETFS _IOWR(r, 64, struct friostat *) +# define SIOCGETFS _IOWR(r, 64, struct ipfobj) # define SIOCIPFFL _IOWR(r, 65, int) # define SIOCIPFFB _IOR(r, 66, int) -# define SIOCADIFR _IOW(r, 67, struct frentry *) -# define SIOCRMIFR _IOW(r, 68, struct frentry *) +# define SIOCADIFR _IOW(r, 67, struct ipfobj) +# define SIOCRMIFR _IOW(r, 68, struct ipfobj) # define SIOCSWAPA _IOR(r, 69, u_int) -# define SIOCINAFR _IOW(r, 70, struct frentry *) -# define SIOCINIFR _IOW(r, 71, struct frentry *) +# define SIOCINAFR _IOW(r, 70, struct ipfobj) +# define SIOCINIFR _IOW(r, 71, struct ipfobj) # define SIOCFRENB _IOW(r, 72, u_int) # define SIOCFRSYN _IOW(r, 73, u_int) -# define SIOCFRZST _IOWR(r, 74, struct friostat *) -# define SIOCZRLST _IOWR(r, 75, struct frentry *) -# define SIOCAUTHW _IOWR(r, 76, struct frauth *) -# define SIOCAUTHR _IOWR(r, 77, struct frauth *) -# define SIOCATHST _IOWR(r, 78, struct fr_authstat *) +# define SIOCFRZST _IOWR(r, 74, struct ipfobj) +# define SIOCZRLST _IOWR(r, 75, struct ipfobj) +# define SIOCAUTHW _IOWR(r, 76, struct ipfobj) +# define SIOCAUTHR _IOWR(r, 77, struct ipfobj) +# define SIOCATHST _IOWR(r, 78, struct ipfobj) # define SIOCSTLCK _IOWR(r, 79, u_int) -# define SIOCSTPUT _IOWR(r, 80, struct ipstate_save *) -# define SIOCSTGET _IOWR(r, 81, struct ipstate_save *) -# define SIOCSTGSZ _IOWR(r, 82, struct natget) -# define SIOCGFRST _IOWR(r, 83, struct ipfrstat *) +# define SIOCSTPUT _IOWR(r, 80, struct ipfobj) +# define SIOCSTGET _IOWR(r, 81, struct ipfobj) +# define SIOCSTGSZ _IOWR(r, 82, struct ipfobj) +# define SIOCGFRST _IOWR(r, 83, struct ipfobj) +# define SIOCSETLG _IOWR(r, 84, int) +# define SIOCGETLG _IOWR(r, 85, int) +# define SIOCFUNCL _IOWR(r, 86, struct ipfunc_resolve) +# define SIOCIPFGETNEXT _IOWR(r, 87, struct ipfobj) +# define SIOCIPFGET _IOWR(r, 88, struct ipfobj) +# define SIOCIPFSET _IOWR(r, 89, struct ipfobj) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR #define SIOCINSFR SIOCINAFR +struct ipscan; +struct ifnet; + + +typedef int (* lookupfunc_t) __P((void *, int, void *)); + +/* + * i6addr is used as a container for both IPv4 and IPv6 addresses, as well + * as other types of objects, depending on its qualifier. + */ +#ifdef USE_INET6 +typedef union i6addr { + u_32_t i6[4]; + struct in_addr in4; + struct in6_addr in6; + void *vptr[2]; + lookupfunc_t lptr[2]; +} i6addr_t; +#else +typedef union i6addr { + u_32_t i6[4]; + struct in_addr in4; + void *vptr[2]; + lookupfunc_t lptr[2]; +} i6addr_t; +#endif +#define in4_addr in4.s_addr +#define iplookupnum i6[0] +#define iplookuptype i6[1] +/* + * NOTE: These DO overlap the above on 64bit systems and this IS recognised. + */ +#define iplookupptr vptr[0] +#define iplookupfunc lptr[1] + +#define I60(x) (((i6addr_t *)(x))->i6[0]) +#define I61(x) (((i6addr_t *)(x))->i6[1]) +#define I62(x) (((i6addr_t *)(x))->i6[2]) +#define I63(x) (((i6addr_t *)(x))->i6[3]) +#define HI60(x) ntohl(((i6addr_t *)(x))->i6[0]) +#define HI61(x) ntohl(((i6addr_t *)(x))->i6[1]) +#define HI62(x) ntohl(((i6addr_t *)(x))->i6[2]) +#define HI63(x) ntohl(((i6addr_t *)(x))->i6[3]) + +#define IP6_EQ(a,b) ((I63(a) == I63(b)) && (I62(a) == I62(b)) && \ + (I61(a) == I61(b)) && (I60(a) == I60(b))) +#define IP6_NEQ(a,b) ((I63(a) != I63(b)) || (I62(a) != I62(b)) || \ + (I61(a) != I61(b)) || (I60(a) != I60(b))) +#define IP6_ISZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) == 0) +#define IP6_NOTZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) != 0) +#define IP6_GT(a,b) (HI60(a) > HI60(b) || (HI60(a) == HI60(b) && \ + (HI61(a) > HI61(b) || (HI61(a) == HI61(b) && \ + (HI62(a) > HI62(b) || (HI62(a) == HI62(b) && \ + HI63(a) > HI63(b))))))) +#define IP6_LT(a,b) (HI60(a) < HI60(b) || (HI60(a) == HI60(b) && \ + (HI61(a) < HI61(b) || (HI61(a) == HI61(b) && \ + (HI62(a) < HI62(b) || (HI62(a) == HI62(b) && \ + HI63(a) < HI63(b))))))) +#define NLADD(n,x) htonl(ntohl(n) + (x)) +#define IP6_INC(a) \ + { i6addr_t *_i6 = (i6addr_t *)(a); \ + _i6->i6[0] = NLADD(_i6->i6[0], 1); \ + if (_i6->i6[0] == 0) { \ + _i6->i6[0] = NLADD(_i6->i6[1], 1); \ + if (_i6->i6[1] == 0) { \ + _i6->i6[0] = NLADD(_i6->i6[2], 1); \ + if (_i6->i6[2] == 0) { \ + _i6->i6[0] = NLADD(_i6->i6[3], 1); \ + } \ + } \ + } \ + } +#define IP6_ADD(a,x,d) \ + { i6addr_t *_s = (i6addr_t *)(a); \ + i6addr_t *_d = (i6addr_t *)(d); \ + _d->i6[0] = NLADD(_s->i6[0], x); \ + if (ntohl(_d->i6[0]) < ntohl(_s->i6[0])) { \ + _d->i6[1] = NLADD(_d->i6[1], 1); \ + if (ntohl(_d->i6[1]) < ntohl(_s->i6[1])) { \ + _d->i6[2] = NLADD(_d->i6[2], 1); \ + if (ntohl(_d->i6[2]) < ntohl(_s->i6[2])) { \ + _d->i6[3] = NLADD(_d->i6[3], 1); \ + } \ + } \ + } \ + } +#define IP6_AND(a,b,d) { i6addr_t *_s1 = (i6addr_t *)(a); \ + i6addr_t *_s2 = (i6addr_t *)(d); \ + i6addr_t *_d = (i6addr_t *)(d); \ + _d->i6[0] = _s1->i6[0] & _s2->i6[0]; \ + _d->i6[1] = _s1->i6[1] & _s2->i6[1]; \ + _d->i6[2] = _s1->i6[2] & _s2->i6[2]; \ + _d->i6[3] = _s1->i6[3] & _s2->i6[3]; \ + } +#define IP6_MERGE(a,b,c) \ + { i6addr_t *_d, *_s1, *_s2; \ + _d = (i6addr_t *)(a); \ + _s1 = (i6addr_t *)(b); \ + _s2 = (i6addr_t *)(c); \ + _d->i6[0] |= _s1->i6[0] & ~_s2->i6[0]; \ + _d->i6[1] |= _s1->i6[1] & ~_s2->i6[1]; \ + _d->i6[2] |= _s1->i6[2] & ~_s2->i6[2]; \ + _d->i6[2] |= _s1->i6[3] & ~_s2->i6[3]; \ + } + + typedef struct fr_ip { u_32_t fi_v:4; /* IP version */ - u_32_t fi_fl:4; /* packet flags */ + u_32_t fi_xx:4; /* spare */ u_32_t fi_tos:8; /* IP packet TOS */ u_32_t fi_ttl:8; /* IP packet TTL */ u_32_t fi_p:8; /* IP packet protocol */ - union i6addr fi_src; /* source address from packet */ - union i6addr fi_dst; /* destination address from packet */ u_32_t fi_optmsk; /* bitmask composed from IP options */ + i6addr_t fi_src; /* source address from packet */ + i6addr_t fi_dst; /* destination address from packet */ u_short fi_secmsk; /* bitmask composed from IP security options */ u_short fi_auth; /* authentication code from IP sec. options */ + u_32_t fi_flx; /* packet flags */ + u_32_t fi_tcpmsk; /* TCP options set/reset */ + u_32_t fi_res1; /* RESERVED */ } fr_ip_t; -#define FI_OPTIONS (FF_OPTIONS >> 24) -#define FI_TCPUDP (FF_TCPUDP >> 24) /* TCP/UCP implied comparison*/ -#define FI_FRAG (FF_FRAG >> 24) -#define FI_SHORT (FF_SHORT >> 24) -#define FI_CMP (FI_OPTIONS|FI_TCPUDP|FI_SHORT) +/* + * For use in fi_flx + */ +#define FI_TCPUDP 0x0001 /* TCP/UCP implied comparison*/ +#define FI_OPTIONS 0x0002 +#define FI_FRAG 0x0004 +#define FI_SHORT 0x0008 +#define FI_NATED 0x0010 +#define FI_MULTICAST 0x0020 +#define FI_BROADCAST 0x0040 +#define FI_MBCAST 0x0080 +#define FI_STATE 0x0100 +#define FI_BADNAT 0x0200 +#define FI_BAD 0x0400 +#define FI_OOW 0x0800 /* Out of state window, else match */ +#define FI_ICMPERR 0x1000 +#define FI_FRAGTAIL 0x2000 +#define FI_BADSRC 0x4000 +#define FI_LOWTTL 0x8000 +#define FI_CMP 0xcff3 /* Not FI_FRAG,FI_FRAGTAIL */ +#define FI_WITH 0xeffe /* Not FI_TCPUDP */ +#define FI_V6EXTHDR 0x10000 +#define FI_COALESCE 0x20000 +#define FI_NOCKSUM 0x20000000 /* don't do a L4 checksum validation */ +#define FI_DONTCACHE 0x40000000 /* don't cache the result */ +#define FI_IGNORE 0x80000000 #define fi_saddr fi_src.in4.s_addr #define fi_daddr fi_dst.in4.s_addr +#define fi_srcnum fi_src.iplookupnum +#define fi_dstnum fi_dst.iplookupnum +#define fi_srctype fi_src.iplookuptype +#define fi_dsttype fi_dst.iplookuptype +#define fi_srcptr fi_src.iplookupptr +#define fi_dstptr fi_dst.iplookupptr +#define fi_srcfunc fi_src.iplookupfunc +#define fi_dstfunc fi_dst.iplookupfunc /* * These are both used by the state and NAT code to indicate that one port or * the other should be treated as a wildcard. + * NOTE: When updating, check bit masks in ip_state.h and update there too. */ -#define FI_W_SPORT 0x00000100 -#define FI_W_DPORT 0x00000200 -#define FI_WILDP (FI_W_SPORT|FI_W_DPORT) -#define FI_W_SADDR 0x00000400 -#define FI_W_DADDR 0x00000800 -#define FI_WILDA (FI_W_SADDR|FI_W_DADDR) -#define FI_NEWFR 0x00001000 /* Create a filter rule */ -#define FI_IGNOREPKT 0x00002000 /* Do not treat as a real packet */ -#define FI_NORULE 0x00004000 /* Not direct a result of a rule */ +#define SI_W_SPORT 0x00000100 +#define SI_W_DPORT 0x00000200 +#define SI_WILDP (SI_W_SPORT|SI_W_DPORT) +#define SI_W_SADDR 0x00000400 +#define SI_W_DADDR 0x00000800 +#define SI_WILDA (SI_W_SADDR|SI_W_DADDR) +#define SI_NEWFR 0x00001000 +#define SI_CLONE 0x00002000 +#define SI_CLONED 0x00004000 + typedef struct fr_info { void *fin_ifp; /* interface packet is `on' */ - struct fr_ip fin_fi; /* IP Packet summary */ - u_short fin_data[2]; /* TCP/UDP ports, ICMP code/type */ - u_int fin_out; /* in or out ? 1 == out, 0 == in */ + fr_ip_t fin_fi; /* IP Packet summary */ + union { + u_short fid_16[2]; /* TCP/UDP ports, ICMP code/type */ + u_32_t fid_32; + } fin_dat; + int fin_out; /* in or out ? 1 == out, 0 == in */ + int fin_rev; /* state only: 1 = reverse */ u_short fin_hlen; /* length of IP header in bytes */ - u_char fin_rev; /* state only: 1 = reverse */ u_char fin_tcpf; /* TCP header flags (SYN, ACK, etc) */ - u_int fin_icode; /* ICMP error to return */ + u_char fin_icode; /* ICMP error to return */ u_32_t fin_rule; /* rule # last matched */ - u_32_t fin_group; /* group number, -1 for none */ + char fin_group[FR_GROUPLEN]; /* group number, -1 for none */ struct frentry *fin_fr; /* last matching rule */ - char *fin_dp; /* start of data past IP header */ - u_short fin_plen; - u_short fin_off; - u_short fin_dlen; /* length of data portion of packet */ + void *fin_dp; /* start of data past IP header */ + int fin_dlen; /* length of data portion of packet */ + int fin_plen; u_short fin_id; /* IP packet id field */ - u_int fin_misc; - void *fin_mp; /* pointer to pointer to mbuf */ -#if SOLARIS - void *fin_qfm; /* pointer to mblk where pkt starts */ - void *fin_qif; + u_short fin_off; + int fin_depth; /* Group nesting depth */ + int fin_error; /* Error code to return */ + void *fin_nat; + void *fin_state; + void *fin_nattag; + ip_t *fin_ip; + mb_t **fin_mp; /* pointer to pointer to mbuf */ + mb_t *fin_m; /* pointer to mbuf */ +#ifdef MENTAT + mb_t *fin_qfm; /* pointer to mblk where pkt starts */ + void *fin_qpi; #endif } fr_info_t; #define fin_v fin_fi.fi_v #define fin_p fin_fi.fi_p -#define fin_saddr fin_fi.fi_saddr +#define fin_flx fin_fi.fi_flx +#define fin_optmsk fin_fi.fi_optmsk +#define fin_secmsk fin_fi.fi_secmsk +#define fin_auth fin_fi.fi_auth #define fin_src fin_fi.fi_src.in4 -#define fin_daddr fin_fi.fi_daddr +#define fin_src6 fin_fi.fi_src.in6 +#define fin_saddr fin_fi.fi_saddr #define fin_dst fin_fi.fi_dst.in4 -#define fin_fl fin_fi.fi_fl +#define fin_dst6 fin_fi.fi_dst.in6 +#define fin_daddr fin_fi.fi_daddr +#define fin_data fin_dat.fid_16 +#define fin_sport fin_dat.fid_16[0] +#define fin_dport fin_dat.fid_16[1] +#define fin_ports fin_dat.fid_32 + +#define IPF_IN 0 +#define IPF_OUT 1 + +typedef struct frentry *(*ipfunc_t) __P((fr_info_t *, u_32_t *)); +typedef int (*ipfuncinit_t) __P((struct frentry *)); + +typedef struct ipfunc_resolve { + char ipfu_name[32]; + ipfunc_t ipfu_addr; + ipfuncinit_t ipfu_init; +} ipfunc_resolve_t; /* * Size for compares on fr_info structures @@ -172,37 +338,67 @@ typedef struct fr_info { #define FI_CSIZE offsetof(fr_info_t, fin_icode) #define FI_LCSIZE offsetof(fr_info_t, fin_dp) -/* - * For fin_misc - */ -#define FM_BADSTATE 0x00000001 - /* * Size for copying cache fr_info structure */ #define FI_COPYSIZE offsetof(fr_info_t, fin_dp) +/* + * Structure for holding IPFilter's tag information + */ +#define IPFTAG_LEN 16 +typedef struct { + union { + u_32_t iptu_num[4]; + char iptu_tag[IPFTAG_LEN]; + } ipt_un; + int ipt_not; +} ipftag_t; + +#define ipt_tag ipt_un.iptu_tag +#define ipt_num ipt_un.iptu_num + + +/* + * This structure is used to hold information about the next hop for where + * to forward a packet. + */ typedef struct frdest { void *fd_ifp; - union i6addr fd_ip6; + i6addr_t fd_ip6; char fd_ifname[LIFNAMSIZ]; -#if SOLARIS - mb_t *fd_mp; /* cache resolver for to/dup-to */ -#endif } frdest_t; #define fd_ip fd_ip6.in4 +/* + * This structure holds information about a port comparison. + */ typedef struct frpcmp { int frp_cmp; /* data for port comparisons */ u_short frp_port; /* top port for <> and >< */ u_short frp_top; /* top port for <> and >< */ } frpcmp_t; +#define FR_NONE 0 +#define FR_EQUAL 1 +#define FR_NEQUAL 2 +#define FR_LESST 3 +#define FR_GREATERT 4 +#define FR_LESSTE 5 +#define FR_GREATERTE 6 +#define FR_OUTRANGE 7 +#define FR_INRANGE 8 +#define FR_INCRANGE 9 + +/* + * Structure containing all the relevant TCP things that can be checked in + * a filter rule. + */ typedef struct frtuc { - u_char ftu_tcpfm; /* tcp flags mask */ - u_char ftu_tcpf; /* tcp flags */ + u_char ftu_tcpfm; /* tcp flags mask */ + u_char ftu_tcpf; /* tcp flags */ frpcmp_t ftu_src; frpcmp_t ftu_dst; } frtuc_t; @@ -214,47 +410,123 @@ typedef struct frtuc { #define ftu_stop ftu_src.frp_top #define ftu_dtop ftu_dst.frp_top +#define FR_TCPFMAX 0x3f + +/* + * This structure makes up what is considered to be the IPFilter specific + * matching components of a filter rule, as opposed to the data structures + * used to define the result which are in frentry_t and not here. + */ +typedef struct fripf { + fr_ip_t fri_ip; + fr_ip_t fri_mip; /* mask structure */ + + u_short fri_icmpm; /* data for ICMP packets (mask) */ + u_short fri_icmp; + + frtuc_t fri_tuc; + int fri_satype; /* addres type */ + int fri_datype; /* addres type */ + int fri_sifpidx; /* doing dynamic addressing */ + int fri_difpidx; /* index into fr_ifps[] to use when */ +} fripf_t; + +#define fri_dstnum fri_ip.fi_dstnum +#define fri_srcnum fri_mip.fi_srcnum +#define fri_dstptr fri_ip.fi_dstptr +#define fri_srcptr fri_mip.fi_srcptr + +#define FRI_NORMAL 0 /* Normal address */ +#define FRI_DYNAMIC 1 /* dynamic address */ +#define FRI_LOOKUP 2 /* address is a pool # */ +#define FRI_RANGE 3 /* address/mask is a range */ +#define FRI_NETWORK 4 /* network address from if */ +#define FRI_BROADCAST 5 /* broadcast address from if */ +#define FRI_PEERADDR 6 /* Peer address for P-to-P */ +#define FRI_NETMASKED 7 /* network address with netmask from if */ + + +typedef struct frentry * (* frentfunc_t) __P((fr_info_t *)); + typedef struct frentry { + ipfmutex_t fr_lock; struct frentry *fr_next; - struct frentry *fr_grp; - int fr_ref; /* reference count - for grouping */ + struct frentry **fr_grp; + struct ipscan *fr_isc; void *fr_ifas[4]; + void *fr_ptr; /* for use with fr_arg */ + char *fr_comment; /* text comment for rule */ + int fr_ref; /* reference count - for grouping */ + int fr_statecnt; /* state count - for limit rules */ /* * These are only incremented when a packet matches this rule and * it is the last match */ U_QUAD_T fr_hits; U_QUAD_T fr_bytes; + + /* + * For PPS rate limiting + */ + struct timeval fr_lastpkt; + int fr_curpps; + + union { + void *fru_data; + caddr_t fru_caddr; + fripf_t *fru_ipf; + frentfunc_t fru_func; + } fr_dun; + /* * Fields after this may not change whilst in the kernel. */ - struct fr_ip fr_ip; - struct fr_ip fr_mip; /* mask structure */ - - - u_short fr_icmpm; /* data for ICMP packets (mask) */ - u_short fr_icmp; - - u_int fr_age[2]; /* aging for state */ - frtuc_t fr_tuc; - u_32_t fr_group; /* group to which this rule belongs */ - u_32_t fr_grhead; /* group # which this rule starts */ + ipfunc_t fr_func; /* call this function */ + int fr_dsize; + int fr_pps; + int fr_statemax; /* max reference count */ + int fr_flineno; /* line number from conf file */ + u_32_t fr_type; u_32_t fr_flags; /* per-rule flags && options (see below) */ - u_int fr_skip; /* # of rules to skip */ + u_32_t fr_logtag; /* user defined log tag # */ + u_32_t fr_collect; /* collection number */ + u_int fr_arg; /* misc. numeric arg for rule */ u_int fr_loglevel; /* syslog log facility + priority */ - int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ - int fr_sap; /* For solaris only */ + u_int fr_age[2]; /* non-TCP timeouts */ + u_char fr_v; u_char fr_icode; /* return ICMP code */ + char fr_group[FR_GROUPLEN]; /* group to which this rule belongs */ + char fr_grhead[FR_GROUPLEN]; /* group # which this rule starts */ + ipftag_t fr_nattag; char fr_ifnames[4][LIFNAMSIZ]; - struct frdest fr_tif; /* "to" interface */ - struct frdest fr_dif; /* duplicate packet interfaces */ + char fr_isctag[16]; + frdest_t fr_tifs[2]; /* "to"/"reply-to" interface */ + frdest_t fr_dif; /* duplicate packet interface */ + /* + * This must be last and will change after loaded into the kernel. + */ u_int fr_cksum; /* checksum on filter rules for performance */ } frentry_t; -#define fr_v fr_ip.fi_v +#define fr_caddr fr_dun.fru_caddr +#define fr_data fr_dun.fru_data +#define fr_dfunc fr_dun.fru_func +#define fr_ipf fr_dun.fru_ipf +#define fr_ip fr_ipf->fri_ip +#define fr_mip fr_ipf->fri_mip +#define fr_icmpm fr_ipf->fri_icmpm +#define fr_icmp fr_ipf->fri_icmp +#define fr_tuc fr_ipf->fri_tuc +#define fr_satype fr_ipf->fri_satype +#define fr_datype fr_ipf->fri_datype +#define fr_sifpidx fr_ipf->fri_sifpidx +#define fr_difpidx fr_ipf->fri_difpidx #define fr_proto fr_ip.fi_p +#define fr_mproto fr_mip.fi_p #define fr_ttl fr_ip.fi_ttl +#define fr_mttl fr_mip.fi_ttl #define fr_tos fr_ip.fi_tos +#define fr_mtos fr_mip.fi_tos #define fr_tcpfm fr_tuc.ftu_tcpfm #define fr_tcpf fr_tuc.ftu_tcpf #define fr_scmp fr_tuc.ftu_scmp @@ -264,57 +536,108 @@ typedef struct frentry { #define fr_stop fr_tuc.ftu_stop #define fr_dtop fr_tuc.ftu_dtop #define fr_dst fr_ip.fi_dst.in4 +#define fr_daddr fr_ip.fi_dst.in4.s_addr #define fr_src fr_ip.fi_src.in4 +#define fr_saddr fr_ip.fi_src.in4.s_addr #define fr_dmsk fr_mip.fi_dst.in4 +#define fr_dmask fr_mip.fi_dst.in4.s_addr #define fr_smsk fr_mip.fi_src.in4 +#define fr_smask fr_mip.fi_src.in4.s_addr +#define fr_dstnum fr_ip.fi_dstnum +#define fr_srcnum fr_ip.fi_srcnum +#define fr_dsttype fr_ip.fi_dsttype +#define fr_srctype fr_ip.fi_srctype +#define fr_dstptr fr_mip.fi_dstptr +#define fr_srcptr fr_mip.fi_srcptr +#define fr_dstfunc fr_mip.fi_dstfunc +#define fr_srcfunc fr_mip.fi_srcfunc +#define fr_optbits fr_ip.fi_optmsk +#define fr_optmask fr_mip.fi_optmsk +#define fr_secbits fr_ip.fi_secmsk +#define fr_secmask fr_mip.fi_secmsk +#define fr_authbits fr_ip.fi_auth +#define fr_authmask fr_mip.fi_auth +#define fr_flx fr_ip.fi_flx +#define fr_mflx fr_mip.fi_flx #define fr_ifname fr_ifnames[0] #define fr_oifname fr_ifnames[2] #define fr_ifa fr_ifas[0] #define fr_oifa fr_ifas[2] +#define fr_tif fr_tifs[0] +#define fr_rif fr_tifs[1] -#define FR_CMPSIZ (sizeof(struct frentry) - offsetof(frentry_t, fr_ip)) +#define FR_NOLOGTAG 0 + +#ifndef offsetof +#define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif +#define FR_CMPSIZ (sizeof(struct frentry) - \ + offsetof(struct frentry, fr_dsize)) + +/* + * fr_type + */ +#define FR_T_NONE 0 +#define FR_T_IPF 1 /* IPF structures */ +#define FR_T_BPFOPC 2 /* BPF opcode */ +#define FR_T_CALLFUNC 3 /* callout to function in fr_func only */ +#define FR_T_COMPIPF 4 /* compiled C code */ +#define FR_T_BUILTIN 0x80000000 /* rule is in kernel space */ /* * fr_flags */ +#define FR_CALL 0x00000 /* call rule */ #define FR_BLOCK 0x00001 /* do not allow packet to pass */ #define FR_PASS 0x00002 /* allow packet to pass */ -#define FR_OUTQUE 0x00004 /* outgoing packets */ -#define FR_INQUE 0x00008 /* ingoing packets */ +#define FR_AUTH 0x00003 /* use authentication */ +#define FR_PREAUTH 0x00004 /* require preauthentication */ +#define FR_ACCOUNT 0x00005 /* Accounting rule */ +#define FR_SKIP 0x00006 /* skip rule */ +#define FR_DIVERT 0x00007 /* divert rule */ +#define FR_CMDMASK 0x0000f #define FR_LOG 0x00010 /* Log */ #define FR_LOGB 0x00011 /* Log-fail */ #define FR_LOGP 0x00012 /* Log-pass */ -#define FR_NOTSRCIP 0x00020 /* not the src IP# */ -#define FR_NOTDSTIP 0x00040 /* not the dst IP# */ -#define FR_RETRST 0x00080 /* Return TCP RST packet - reset connection */ -#define FR_RETICMP 0x00100 /* Return ICMP unreachable packet */ -#define FR_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */ -#define FR_NOMATCH 0x00200 /* no match occurred */ -#define FR_ACCOUNT 0x00400 /* count packet bytes */ -#define FR_KEEPFRAG 0x00800 /* keep fragment information */ -#define FR_KEEPSTATE 0x01000 /* keep `connection' state information */ -#define FR_INACTIVE 0x02000 -#define FR_QUICK 0x04000 /* match & stop processing list */ -#define FR_FASTROUTE 0x08000 /* bypass normal routing */ -#define FR_CALLNOW 0x10000 /* call another function (fr_func) if matches */ -#define FR_DUP 0x20000 /* duplicate packet */ +#define FR_LOGMASK (FR_LOG|FR_CMDMASK) +#define FR_CALLNOW 0x00020 /* call another function (fr_func) if matches */ +#define FR_NOTSRCIP 0x00040 +#define FR_NOTDSTIP 0x00080 +#define FR_QUICK 0x00100 /* match & stop processing list */ +#define FR_KEEPFRAG 0x00200 /* keep fragment information */ +#define FR_KEEPSTATE 0x00400 /* keep `connection' state information */ +#define FR_FASTROUTE 0x00800 /* bypass normal routing */ +#define FR_RETRST 0x01000 /* Return TCP RST packet - reset connection */ +#define FR_RETICMP 0x02000 /* Return ICMP unreachable packet */ +#define FR_FAKEICMP 0x03000 /* Return ICMP unreachable with fake source */ +#define FR_OUTQUE 0x04000 /* outgoing packets */ +#define FR_INQUE 0x08000 /* ingoing packets */ +#define FR_LOGBODY 0x10000 /* Log the body */ +#define FR_LOGFIRST 0x20000 /* Log the first byte if state held */ #define FR_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */ -#define FR_LOGBODY 0x80000 /* Log the body */ -#define FR_LOGFIRST 0x100000 /* Log the first byte if state held */ -#define FR_AUTH 0x200000 /* use authentication */ -#define FR_PREAUTH 0x400000 /* require preauthentication */ -#define FR_DONTCACHE 0x800000 /* don't cache the result */ +#define FR_DUP 0x80000 /* duplicate packet */ +#define FR_FRSTRICT 0x100000 /* strict frag. cache */ +#define FR_STSTRICT 0x200000 /* strict keep state */ +#define FR_NEWISN 0x400000 /* new ISN for outgoing TCP */ +#define FR_NOICMPERR 0x800000 /* do not match ICMP errors in state */ +#define FR_NOMATCH 0x8000000 /* no match occured */ + /* 0x10000000 FF_LOGPASS */ + /* 0x20000000 FF_LOGBLOCK */ + /* 0x40000000 FF_LOGNOMATCH */ + /* 0x80000000 FF_BLOCKNONIP */ +#define FR_COPIED 0x40000000 /* copied from user space */ +#define FR_INACTIVE 0x80000000 /* only used when flush'ing rules */ -#define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB) #define FR_RETMASK (FR_RETICMP|FR_RETRST|FR_FAKEICMP) +#define FR_ISBLOCK(x) (((x) & FR_CMDMASK) == FR_BLOCK) +#define FR_ISPASS(x) (((x) & FR_CMDMASK) == FR_PASS) +#define FR_ISAUTH(x) (((x) & FR_CMDMASK) == FR_AUTH) +#define FR_ISPREAUTH(x) (((x) & FR_CMDMASK) == FR_PREAUTH) +#define FR_ISACCOUNT(x) (((x) & FR_CMDMASK) == FR_ACCOUNT) +#define FR_ISSKIP(x) (((x) & FR_CMDMASK) == FR_SKIP) +#define FR_ISNOMATCH(x) ((x) & FR_NOMATCH) +#define FR_INOUT (FR_INQUE|FR_OUTQUE) -/* - * These correspond to #define's for FI_* and are stored in fr_flags - */ -#define FF_OPTIONS 0x01000000 -#define FF_TCPUDP 0x02000000 -#define FF_FRAG 0x04000000 -#define FF_SHORT 0x08000000 /* * recognized flags for SIOCGETFF and SIOCSETFF, and get put in fr_flags */ @@ -324,16 +647,40 @@ typedef struct frentry { #define FF_LOGGING (FF_LOGPASS|FF_LOGBLOCK|FF_LOGNOMATCH) #define FF_BLOCKNONIP 0x80000000 /* Solaris2 Only */ -#define FR_NONE 0 -#define FR_EQUAL 1 -#define FR_NEQUAL 2 -#define FR_LESST 3 -#define FR_GREATERT 4 -#define FR_LESSTE 5 -#define FR_GREATERTE 6 -#define FR_OUTRANGE 7 -#define FR_INRANGE 8 +/* + * Structure that passes information on what/how to flush to the kernel. + */ +typedef struct ipfflush { + int ipflu_how; + int ipflu_arg; +} ipfflush_t; + + +/* + * + */ +typedef struct ipfgetctl { + u_int ipfg_min; /* min value */ + u_int ipfg_current; /* current value */ + u_int ipfg_max; /* max value */ + u_int ipfg_default; /* default value */ + u_int ipfg_steps; /* value increments */ + char ipfg_name[40]; /* tag name for this control */ +} ipfgetctl_t; + +typedef struct ipfsetctl { + int ipfs_which; /* 0 = min 1 = current 2 = max 3 = default */ + u_int ipfs_value; /* min value */ + char ipfs_name[40]; /* tag name for this control */ +} ipfsetctl_t; + + +/* + * Some of the statistics below are in their own counters, but most are kept + * in this single structure so that they can all easily be collected and + * copied back as required. + */ typedef struct filterstats { u_long fr_pass; /* packets allowed */ u_long fr_block; /* packets denied */ @@ -356,97 +703,53 @@ typedef struct filterstats { u_long fr_pull[2]; /* good and bad pullup attempts */ u_long fr_badsrc; /* source received doesn't match route */ u_long fr_badttl; /* TTL in packet doesn't reach minimum */ -#if SOLARIS - u_long fr_notdata; /* PROTO/PCPROTO that have no data */ - u_long fr_nodata; /* mblks that have no data */ u_long fr_bad; /* bad IP packets to the filter */ - u_long fr_notip; /* packets passed through no on ip queue */ - u_long fr_drop; /* packets dropped - no info for them! */ - u_long fr_copy; /* messages copied due to db_ref > 1 */ -#endif - u_long fr_ipv6[2]; /* IPv6 packets in/out */ + u_long fr_ipv6; /* IPv6 packets in/out */ + u_long fr_ppshit; /* dropped because of pps ceiling */ + u_long fr_ipud; /* IP id update failures */ } filterstats_t; -/* - * For SIOCGETFS - */ -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]; - struct frentry *f_fin6[2]; - struct frentry *f_fout6[2]; - struct frentry *f_acctin6[2]; - struct frentry *f_acctout6[2]; - struct frentry *f_auth; - struct frgroup *f_groups[3][2]; - u_long f_froute[2]; - int f_defpass; /* default pass - from fr_pass */ - char f_active; /* 1 or 0 - active rule set */ - char f_running; /* 1 if running, else 0 */ - char f_logging; /* 1 if enabled, else 0 */ - char f_version[32]; /* version string */ - int f_locks[4]; -} friostat_t; - -typedef struct optlist { - u_short ol_val; - int ol_bit; -} optlist_t; - - -/* - * Group list structure. - */ -typedef struct frgroup { - u_32_t fg_num; - struct frgroup *fg_next; - struct frentry *fg_head; - struct frentry **fg_start; -} frgroup_t; - - /* * Log structure. Each packet header logged is prepended by one of these. * Following this in the log records read from the device will be an ipflog * structure which is then followed by any packet data. */ typedef struct iplog { - u_32_t ipl_magic; - u_int ipl_count; - struct timeval ipl_time; - size_t ipl_dsize; + u_32_t ipl_magic; + u_int ipl_count; + struct timeval ipl_time; + size_t ipl_dsize; struct iplog *ipl_next; } iplog_t; -#define IPL_MAGIC 0x49504c4d /* 'IPLM' */ +#define ipl_sec ipl_time.tv_sec +#define ipl_usec ipl_time.tv_usec + +#define IPL_MAGIC 0x49504c4d /* 'IPLM' */ +#define IPL_MAGIC_NAT 0x49504c4e /* 'IPLN' */ +#define IPL_MAGIC_STATE 0x49504c53 /* 'IPLS' */ #define IPLOG_SIZE sizeof(iplog_t) typedef struct ipflog { #if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - char fl_ifname[LIFNAMSIZ]; + (defined(OpenBSD) && (OpenBSD >= 199603)) #else u_int fl_unit; - char fl_ifname[LIFNAMSIZ]; #endif - u_char fl_plen; /* extra data after hlen */ - u_char fl_hlen; /* length of IP headers saved */ - u_short fl_loglevel; /* syslog log level */ u_32_t fl_rule; - u_32_t fl_group; u_32_t fl_flags; + u_32_t fl_lflags; + u_32_t fl_logtag; + ipftag_t fl_nattag; + u_short fl_plen; /* extra data after hlen */ + u_short fl_loglevel; /* syslog log level */ + char fl_group[FR_GROUPLEN]; + u_char fl_hlen; /* length of IP headers saved */ u_char fl_dir; - u_char fl_pad[3]; + u_char fl_xxx[2]; /* pad */ + char fl_ifname[LIFNAMSIZ]; } ipflog_t; - -#ifndef ICMP_UNREACH_FILTER -# define ICMP_UNREACH_FILTER 13 -#endif - #ifndef IPF_LOGGING # define IPF_LOGGING 0 #endif @@ -454,8 +757,14 @@ typedef struct ipflog { # define IPF_DEFAULT_PASS FR_PASS #endif -#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) -#define IPLLOGSIZE 8192 +#define DEFAULT_IPFLOGSIZE 8192 +#ifndef IPFILTER_LOGSIZE +# define IPFILTER_LOGSIZE DEFAULT_IPFLOGSIZE +#else +# if IPF_LOGSIZE < DEFAULT_IPFLOGSIZE +# error IPFILTER_LOGSISZE too small. Must be >= DEFAULT_IPFLOGSIZE +# endif +#endif #define IPF_OPTCOPY 0x07ff00 /* bit mask of copied options */ @@ -470,15 +779,300 @@ typedef struct ipflog { # define IPL_NAME "/dev/ipl" # endif #endif -#define IPL_NAT IPNAT_NAME -#define IPL_STATE IPSTATE_NAME -#define IPL_AUTH IPAUTH_NAME +/* + * Pathnames for various IP Filter control devices. Used by LKM + * and userland, so defined here. + */ +#define IPNAT_NAME "/dev/ipnat" +#define IPSTATE_NAME "/dev/ipstate" +#define IPAUTH_NAME "/dev/ipauth" +#define IPSYNC_NAME "/dev/ipsync" +#define IPSCAN_NAME "/dev/ipscan" +#define IPLOOKUP_NAME "/dev/iplookup" #define IPL_LOGIPF 0 /* Minor device #'s for accessing logs */ #define IPL_LOGNAT 1 #define IPL_LOGSTATE 2 #define IPL_LOGAUTH 3 -#define IPL_LOGMAX 3 +#define IPL_LOGSYNC 4 +#define IPL_LOGSCAN 5 +#define IPL_LOGLOOKUP 6 +#define IPL_LOGCOUNT 7 +#define IPL_LOGMAX 7 +#define IPL_LOGSIZE IPL_LOGMAX + 1 +#define IPL_LOGALL -1 +#define IPL_LOGNONE -2 + +/* + * For SIOCGETFS + */ +typedef struct friostat { + struct filterstats f_st[2]; + struct frentry *f_ipf[2][2]; + struct frentry *f_acct[2][2]; + struct frentry *f_ipf6[2][2]; + struct frentry *f_acct6[2][2]; + struct frentry *f_auth; + struct frgroup *f_groups[IPL_LOGSIZE][2]; + u_long f_froute[2]; + u_long f_ticks; + int f_locks[IPL_LOGMAX]; + size_t f_kmutex_sz; + size_t f_krwlock_sz; + int f_defpass; /* default pass - from fr_pass */ + int f_active; /* 1 or 0 - active rule set */ + int f_running; /* 1 if running, else 0 */ + int f_logging; /* 1 if enabled, else 0 */ + int f_features; + char f_version[32]; /* version string */ +} friostat_t; + +#define f_fin f_ipf[0] +#define f_fin6 f_ipf6[0] +#define f_fout f_ipf[1] +#define f_fout6 f_ipf6[1] +#define f_acctin f_acct[0] +#define f_acctin6 f_acct6[0] +#define f_acctout f_acct[1] +#define f_acctout6 f_acct6[1] + +#define IPF_FEAT_LKM 0x001 +#define IPF_FEAT_LOG 0x002 +#define IPF_FEAT_LOOKUP 0x004 +#define IPF_FEAT_BPF 0x008 +#define IPF_FEAT_COMPILED 0x010 +#define IPF_FEAT_CKSUM 0x020 +#define IPF_FEAT_SYNC 0x040 +#define IPF_FEAT_SCAN 0x080 +#define IPF_FEAT_IPV6 0x100 + +typedef struct optlist { + u_short ol_val; + int ol_bit; +} optlist_t; + + +/* + * Group list structure. + */ +typedef struct frgroup { + struct frgroup *fg_next; + struct frentry *fg_head; + struct frentry *fg_start; + u_32_t fg_flags; + int fg_ref; + char fg_name[FR_GROUPLEN]; +} frgroup_t; + +#define FG_NAME(g) (*(g)->fg_name == '\0' ? "" : (g)->fg_name) + + +/* + * Used by state and NAT tables + */ +typedef struct icmpinfo { + u_short ici_id; + u_short ici_seq; + u_char ici_type; +} icmpinfo_t; + +typedef struct udpinfo { + u_short us_sport; + u_short us_dport; +} udpinfo_t; + + +typedef struct tcpdata { + u_32_t td_end; + u_32_t td_maxend; + u_32_t td_maxwin; + u_32_t td_winscale; + u_32_t td_maxseg; + int td_winflags; +} tcpdata_t; + +#define TCP_WSCALE_MAX 14 + +#define TCP_WSCALE_SEEN 0x00000001 +#define TCP_WSCALE_FIRST 0x00000002 + + +typedef struct tcpinfo { + u_short ts_sport; + u_short ts_dport; + tcpdata_t ts_data[2]; +} tcpinfo_t; + +typedef struct greinfo { + u_short gs_flags; + u_short gs_ptype; + u_short gs_call; +} greinfo_t; + +typedef struct grehdr { + union { + struct grebits { + u_32_t grub_C:1; + u_32_t grub_R:1; + u_32_t grub_K:1; + u_32_t grub_S:1; + u_32_t grub_s:1; + u_32_t grub_recur:1; + u_32_t grub_A:1; + u_32_t grub_flags:3; + u_32_t grub_ver:3; + u_short grub_ptype; + } gru_bits; + u_short gru_flags; + } gr_un; + u_short gr_len; + u_short gr_call; +} grehdr_t; + +#define gr_flags gr_un.gru_flags +#define gr_bits gr_un.gru_bits +#define gr_ptype gr_bits.grub_ptype +#define gr_C gr_bits.grub_C +#define gr_R gr_bits.grub_R +#define gr_K gr_bits.grub_K +#define gr_S gr_bits.grub_S +#define gr_s gr_bits.grub_s +#define gr_recur gr_bits.grub_recur +#define gr_A gr_bits.grub_A +#define gr_ver gr_bits.grub_ver + + +/* + * Timeout tail queue list member + */ +typedef struct ipftqent { + struct ipftqent **tqe_pnext; + struct ipftqent *tqe_next; + struct ipftq *tqe_ifq; + void *tqe_parent; /* pointer back to NAT/state struct */ + u_long tqe_die; /* when this entriy is to die */ + u_long tqe_touched; + int tqe_flags; + int tqe_state[2]; /* current state of this entry */ +} ipftqent_t; + +#define TQE_RULEBASED 0x00000001 + + +/* + * Timeout tail queue head for IPFilter + */ +typedef struct ipftq { + ipfmutex_t ifq_lock; + u_int ifq_ttl; + ipftqent_t *ifq_head; + ipftqent_t **ifq_tail; + struct ipftq *ifq_next; + struct ipftq **ifq_pnext; + int ifq_ref; + u_int ifq_flags; +} ipftq_t; + +#define IFQF_USER 0x01 /* User defined aging */ + +#define IPF_HZ_MULT 1 +#define IPF_HZ_DIVIDE 2 /* How many times a second ipfilter */ + /* checks its timeout queues. */ +#define IPF_TTLVAL(x) (((x) / IPF_HZ_MULT) * IPF_HZ_DIVIDE) + +/* + * Structure to define address for pool lookups. + */ +typedef struct { + u_char adf_len; + i6addr_t adf_addr; +} addrfamily_t; + + +/* + * Object structure description. For passing through in ioctls. + */ +typedef struct ipfobj { + u_32_t ipfo_rev; /* IPFilter version number */ + u_32_t ipfo_size; /* size of object at ipfo_ptr */ + void *ipfo_ptr; /* pointer to object */ + int ipfo_type; /* type of object being pointed to */ + int ipfo_offset; /* bytes from ipfo_ptr where to start */ + u_char ipfo_xxxpad[32]; /* reserved for future use */ +} ipfobj_t; + +#define IPFOBJ_FRENTRY 0 /* struct frentry */ +#define IPFOBJ_IPFSTAT 1 /* struct friostat */ +#define IPFOBJ_IPFINFO 2 /* struct fr_info */ +#define IPFOBJ_AUTHSTAT 3 /* struct fr_authstat */ +#define IPFOBJ_FRAGSTAT 4 /* struct ipfrstat */ +#define IPFOBJ_IPNAT 5 /* struct ipnat */ +#define IPFOBJ_NATSTAT 6 /* struct natstat */ +#define IPFOBJ_STATESAVE 7 /* struct ipstate_save */ +#define IPFOBJ_NATSAVE 8 /* struct nat_save */ +#define IPFOBJ_NATLOOKUP 9 /* struct natlookup */ +#define IPFOBJ_IPSTATE 10 /* struct ipstate */ +#define IPFOBJ_STATESTAT 11 /* struct ips_stat */ +#define IPFOBJ_FRAUTH 12 /* struct frauth */ +#define IPFOBJ_TUNEABLE 13 /* struct ipftune */ + + +typedef union ipftunevalptr { + void *ipftp_void; + u_long *ipftp_long; + u_int *ipftp_int; + u_short *ipftp_short; + u_char *ipftp_char; +} ipftunevalptr_t; + +typedef struct ipftuneable { + ipftunevalptr_t ipft_una; + char *ipft_name; + u_long ipft_min; + u_long ipft_max; + int ipft_sz; + int ipft_flags; +} ipftuneable_t; + +#define ipft_addr ipft_una.ipftp_void +#define ipft_plong ipft_una.ipftp_long +#define ipft_pint ipft_una.ipftp_int +#define ipft_pshort ipft_una.ipftp_short +#define ipft_pchar ipft_una.ipftp_char + +#define IPFT_RDONLY 1 /* read-only */ +#define IPFT_WRDISABLED 2 /* write when disabled only */ + +typedef union ipftuneval { + u_long ipftu_long; + u_int ipftu_int; + u_short ipftu_short; + u_char ipftu_char; +} ipftuneval_t; + +typedef struct ipftune { + void *ipft_cookie; + ipftuneval_t ipft_un; + u_long ipft_min; + u_long ipft_max; + int ipft_sz; + int ipft_flags; + char ipft_name[80]; +} ipftune_t; + +#define ipft_vlong ipft_un.ipftu_long +#define ipft_vint ipft_un.ipftu_int +#define ipft_vshort ipft_un.ipftu_short +#define ipft_vchar ipft_un.ipftu_char + + +/* +** HPUX Port +*/ +#ifdef __hpux +/* HP-UX locking sequence deadlock detection module lock MAJOR ID */ +# define IPF_SMAJ 0 /* temp assignment XXX, not critical */ +#endif #if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \ (__FreeBSD_version >= 220000) @@ -491,7 +1085,8 @@ typedef struct ipflog { * with this! */ #if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \ - (defined(NetBSD1_2) && NetBSD1_2 > 1) + (defined(NetBSD1_2) && NetBSD1_2 > 1) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 500043)) # if (NetBSD >= 199905) # define PFIL_HOOKS # endif @@ -500,63 +1095,60 @@ typedef struct ipflog { # endif #endif - #ifndef _KERNEL -extern char *get_ifname __P((struct ifnet *)); -extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +extern int fr_check __P((struct ip *, int, void *, int, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); -extern int send_reset __P((ip_t *, fr_info_t *)); -extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); extern int ipf_log __P((void)); extern struct ifnet *get_unit __P((char *, int)); -extern int mbuflen __P((mb_t *)); +extern char *get_ifname __P((struct ifnet *)); # if defined(__NetBSD__) || defined(__OpenBSD__) || \ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) -extern int iplioctl __P((dev_t, u_long, caddr_t, int)); +extern int iplioctl __P((int, ioctlcmd_t, caddr_t, int)); # else -extern int iplioctl __P((dev_t, int, caddr_t, int)); +extern int iplioctl __P((int, ioctlcmd_t, caddr_t, int)); # endif extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); +extern void m_freem __P((mb_t *)); #else /* #ifndef _KERNEL */ +extern void *fr_pullup __P((mb_t *, fr_info_t *, int)); # if defined(__NetBSD__) && defined(PFIL_HOOKS) extern void ipfilterattach __P((int)); # endif -extern int iplattach __P((void)); extern int ipl_enable __P((void)); extern int ipl_disable __P((void)); -extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); -extern int send_reset __P((ip_t *, fr_info_t *)); -# if SOLARIS -extern int fr_check __P((ip_t *, int, void *, int, qif_t *, mb_t **)); -extern int (*fr_checkp) __P((ip_t *, int, void *, - int, qif_t *, mb_t **)); -# if SOLARIS2 >= 7 +# ifdef MENTAT +extern int fr_check __P((struct ip *, int, void *, int, void *, + mblk_t **)); +# if SOLARIS +# if SOLARIS2 >= 7 extern int iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *)); -# else +# else extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *)); -# endif +# endif extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); +extern int iplread __P((dev_t, uio_t *, cred_t *)); +# endif +# ifdef __hpux +extern int iplopen __P((dev_t, int, intptr_t, int)); +extern int iplclose __P((dev_t, int, int)); +extern int iplioctl __P((dev_t, int, caddr_t, int)); +extern int iplread __P((dev_t, uio_t *)); +extern int iplselect __P((dev_t, int)); +# endif extern int ipfsync __P((void)); -extern int ipfr_fastroute __P((ip_t *, mblk_t *, mblk_t **, - fr_info_t *, frdest_t *)); -extern void copyin_mblk __P((mblk_t *, size_t, size_t, char *)); -extern void copyout_mblk __P((mblk_t *, size_t, size_t, char *)); -extern int fr_qin __P((queue_t *, mblk_t *)); extern int fr_qout __P((queue_t *, mblk_t *)); -extern int iplread __P((dev_t, struct uio *, cred_t *)); -# else /* SOLARIS */ -extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +# else /* MENTAT */ +extern int fr_check __P((struct ip *, int, void *, int, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); -extern int ipfr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi # include extern int iplioctl __P((dev_t, int, caddr_t, int, cred_t *, int *)); extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); -extern int iplread __P((dev_t, struct uio *, cred_t *)); +extern int iplread __P((dev_t, uio_t *, cred_t *)); extern int ipfsync __P((void)); extern int ipfilter_sgi_attach __P((void)); extern void ipfilter_sgi_detach __P((void)); @@ -569,78 +1161,149 @@ extern int iplidentify __P((char *)); (NetBSD >= 199511) || defined(__OpenBSD__) # if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || \ defined(__OpenBSD__) || (__FreeBSD_version >= 300000) +# if (__FreeBSD_version >= 500024) +extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct thread *)); +# else extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +# endif /* __FreeBSD_version >= 500024 */ # else extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); # endif +# if (__FreeBSD_version >= 500024) +extern int iplopen __P((dev_t, int, int, struct thread *)); +extern int iplclose __P((dev_t, int, int, struct thread *)); +# else extern int iplopen __P((dev_t, int, int, struct proc *)); extern int iplclose __P((dev_t, int, int, struct proc *)); +# endif /* __FreeBSD_version >= 500024 */ # else -# ifndef linux +# ifdef linux +extern int iplioctl __P((struct inode *, struct file *, u_int, u_long)); +# else extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); extern int iplioctl __P((dev_t, int, caddr_t, int)); -# else -extern int iplioctl(struct inode *, struct file *, u_int, u_long); -extern int iplopen __P((struct inode *, struct file *)); -extern void iplclose __P((struct inode *, struct file *)); -# endif /* !linux */ +# endif # endif /* (_BSDI_VERSION >= 199510) */ # if BSD >= 199306 extern int iplread __P((dev_t, struct uio *, int)); +extern int iplwrite __P((dev_t, struct uio *, int)); # else # ifndef linux extern int iplread __P((dev_t, struct uio *)); -# else -extern int iplread(struct inode *, struct file *, char *, int); -# endif /* !linux */ +extern int iplwrite __P((dev_t, struct uio *)); +# endif # endif /* BSD >= 199306 */ # endif /* __ sgi */ -# endif /* SOLARIS */ +# endif /* MENTAT */ + #endif /* #ifndef _KERNEL */ +extern ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_hostmap; +extern ipfmutex_t ipf_timeoutlock, ipf_stinsert, ipf_natio, ipf_nat_new; +extern ipfrwlock_t ipf_mutex, ipf_global, ip_poolrw, ipf_ipidfrag; +extern ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; + extern char *memstr __P((char *, char *, int, int)); -extern void fixskip __P((frentry_t **, frentry_t *, int)); -extern int countbits __P((u_32_t)); +extern int count4bits __P((u_32_t)); +extern int frrequest __P((int, ioctlcmd_t, caddr_t, int, int)); +extern char *getifname __P((struct ifnet *)); +extern int iplattach __P((void)); extern int ipldetach __P((void)); extern u_short ipf_cksum __P((u_short *, int)); -extern int ircopyptr __P((void *, void *, size_t)); -extern int iwcopyptr __P((void *, void *, size_t)); - -extern void ipflog_init __P((void)); -extern int ipflog_clear __P((minor_t)); -extern int ipflog __P((u_int, ip_t *, fr_info_t *, mb_t *)); -extern int ipllog __P((int, fr_info_t *, void **, size_t *, int *, int)); -extern int ipflog_read __P((minor_t, struct uio *)); +extern int copyinptr __P((void *, void *, size_t)); +extern int copyoutptr __P((void *, void *, size_t)); +extern int fr_inobj __P((void *, void *, int)); +extern int fr_ioctlswitch __P((int, void *, ioctlcmd_t, int)); +extern int fr_ipftune __P((ioctlcmd_t, void *)); +extern int fr_outobj __P((void *, void *, int)); +extern int fr_send_reset __P((fr_info_t *)); +extern int fr_send_icmp_err __P((int, fr_info_t *, int)); +extern void fr_resolvdest __P((struct frdest *, int)); +extern int fr_resolvefunc __P((void *)); +extern int fr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *)); +#if (__FreeBSD_version < 490000) || !defined(_KERNEL) +extern int ppsratecheck __P((struct timeval *, int *, int)); +#endif +extern ipftq_t *fr_addtimeoutqueue __P((ipftq_t **, u_int)); +extern void fr_deletetimeoutqueue __P((ipftq_t *)); +extern void fr_movequeue __P((ipftqent_t *, ipftq_t *, ipftq_t *)); +extern void fr_queueappend __P((ipftqent_t *, ipftq_t *, void *)); +extern void fr_queueback __P((ipftqent_t *)); +extern void fr_queuefront __P((ipftqent_t *)); +extern void fr_checkv4sum __P((fr_info_t *)); +extern int fr_checkl4sum __P((fr_info_t *)); +extern int fr_ifpfillv4addr __P((int, struct sockaddr_in *, + struct sockaddr_in *, struct in_addr *, + struct in_addr *)); +extern int fr_coalesce __P((fr_info_t *)); +#ifdef USE_INET6 +extern void fr_checkv6sum __P((fr_info_t *)); +extern int fr_ifpfillv6addr __P((int, struct sockaddr_in6 *, + struct sockaddr_in6 *, struct in_addr *, + struct in_addr *)); +#endif extern int frflush __P((minor_t, int)); extern void frsync __P((void)); -extern frgroup_t *fr_addgroup __P((u_32_t, frentry_t *, minor_t, int)); -extern void fr_delgroup __P((u_32_t, u_32_t, minor_t, int)); -extern frgroup_t *fr_findgroup __P((u_32_t, u_32_t, minor_t, int, - frgroup_t ***)); +extern frgroup_t *fr_addgroup __P((char *, void *, u_32_t, minor_t, int)); +extern int fr_derefrule __P((frentry_t **)); +extern void fr_delgroup __P((char *, minor_t, int)); +extern frgroup_t *fr_findgroup __P((char *, minor_t, int, frgroup_t ***)); -extern int fr_copytolog __P((int, char *, int)); -extern void fr_forgetifp __P((void *)); -extern void fr_getstat __P((struct friostat *)); -extern int fr_ifpaddr __P((int, void *, struct in_addr *)); -extern int fr_lock __P((caddr_t, int *)); -extern void fr_makefrip __P((int, ip_t *, fr_info_t *)); -extern u_short fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *)); -extern int fr_scanlist __P((u_32_t, ip_t *, fr_info_t *, void *)); -extern int fr_tcpudpchk __P((frtuc_t *, fr_info_t *)); -extern int fr_verifysrc __P((struct in_addr, void *)); +extern int fr_loginit __P((void)); +extern int ipflog_clear __P((minor_t)); +extern int ipflog_read __P((minor_t, uio_t *)); +extern int ipflog __P((fr_info_t *, u_int)); +extern int ipllog __P((int, fr_info_t *, void **, size_t *, int *, int)); +extern void fr_logunload __P((void)); -extern int ipl_unreach; +extern frentry_t *fr_acctpkt __P((fr_info_t *, u_32_t *)); +extern int fr_copytolog __P((int, char *, int)); +extern u_short fr_cksum __P((mb_t *, ip_t *, int, void *)); +extern void fr_deinitialise __P((void)); +extern frentry_t *fr_dolog __P((fr_info_t *, u_32_t *)); +extern frentry_t *fr_dstgrpmap __P((fr_info_t *, u_32_t *)); +extern void fr_fixskip __P((frentry_t **, frentry_t *, int)); +extern void fr_forgetifp __P((void *)); +extern frentry_t *fr_getrulen __P((int, char *, u_32_t)); +extern void fr_getstat __P((struct friostat *)); +extern int fr_ifpaddr __P((int, int, void *, + struct in_addr *, struct in_addr *)); +extern int fr_initialise __P((void)); +extern int fr_lock __P((caddr_t, int *)); +extern int fr_makefrip __P((int, ip_t *, fr_info_t *)); +extern int fr_matchtag __P((ipftag_t *, ipftag_t *)); +extern int fr_matchicmpqueryreply __P((int, icmpinfo_t *, + struct icmp *, int)); +extern u_32_t fr_newisn __P((fr_info_t *)); +extern u_short fr_nextipid __P((fr_info_t *)); +extern int fr_rulen __P((int, frentry_t *)); +extern int fr_scanlist __P((fr_info_t *, u_32_t)); +extern frentry_t *fr_srcgrpmap __P((fr_info_t *, u_32_t *)); +extern int fr_tcpudpchk __P((fr_info_t *, frtuc_t *)); +extern int fr_verifysrc __P((fr_info_t *fin)); +extern int fr_zerostats __P((char *)); + +extern int fr_unreach; extern int fr_running; -extern u_long ipl_frouteok[2]; +extern u_long fr_frouteok[2]; extern int fr_pass; extern int fr_flags; extern int fr_active; extern int fr_chksrc; extern int fr_minttl; -extern int fr_minttllog; -extern fr_info_t frcache[2]; +extern int fr_refcnt; +extern int fr_control_forwarding; +extern int fr_update_ipid; +extern int nat_logging; +extern int ipstate_logging; +extern int ipl_suppress; +extern int ipl_buffer_sz; +extern int ipl_logmax; +extern int ipl_logall; +extern u_long fr_ticks; +extern fr_info_t frcache[2][8]; extern char ipfilter_version[]; extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; extern int iplused[IPL_LOGMAX + 1]; @@ -649,8 +1312,13 @@ extern struct frentry *ipfilter[2][2], *ipacct[2][2]; extern struct frentry *ipfilter6[2][2], *ipacct6[2][2]; extern int icmptoicmp6types[ICMP_MAXTYPE+1]; extern int icmptoicmp6unreach[ICMP_MAX_UNREACH]; +extern int icmpreplytype6[ICMP6_MAXTYPE + 1]; #endif -extern struct frgroup *ipfgroups[3][2]; +extern int icmpreplytype4[ICMP_MAXTYPE + 1]; +extern struct frgroup *ipfgroups[IPL_LOGSIZE][2]; extern struct filterstats frstats[]; +extern frentry_t *ipfrule_match __P((fr_info_t *)); +extern u_char ipf_iss_secret[32]; +extern ipftuneable_t ipf_tuneables[]; #endif /* _NETINET_IP_FIL_H_ */ diff --git a/sys/netinet/ip_fil_netbsd.c b/sys/netinet/ip_fil_netbsd.c index 7ed4bf5e66fd..e33326d22daf 100644 --- a/sys/netinet/ip_fil_netbsd.c +++ b/sys/netinet/ip_fil_netbsd.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_fil_netbsd.c,v 1.1.1.1 2004/03/28 08:56:39 martti Exp $ */ +/* $NetBSD: ip_fil_netbsd.c,v 1.2 2004/03/28 09:00:57 martti Exp $ */ /* * Copyright (C) 1993-2003 by Darren Reed. @@ -19,6 +19,8 @@ static const char rcsid[] = "@(#)Id: ip_fil_netbsd.c,v 2.55.2.2 2004/03/22 12:18 #include #if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) # include "opt_ipfilter_log.h" +# include "opt_pfil_hooks.h" +# include "opt_ipsec.h" #endif #include #include @@ -77,6 +79,7 @@ MALLOC_DEFINE(M_IPFILTER, "IP Filter", "IP Filter packet filter data structures" #if __NetBSD_Version__ >= 105009999 # define csuminfo csum_flags #endif +#endif extern struct protosw inetsw[]; diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c index 1d42a4d2a409..679b8e93929d 100644 --- a/sys/netinet/ip_frag.c +++ b/sys/netinet/ip_frag.c @@ -1,47 +1,55 @@ -/* $NetBSD: ip_frag.c,v 1.34 2002/09/19 08:12:49 martti Exp $ */ +/* $NetBSD: ip_frag.c,v 1.35 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1993-2001 by Darren Reed. + * Copyright (C) 1993-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif - -#ifdef __sgi -# include +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include #include #include #include #include -#if !defined(_KERNEL) && !defined(KERNEL) +#ifdef __hpux +# include +#endif +#if !defined(_KERNEL) # include # include # include +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include # include #else # include #endif -#ifndef linux +#if !defined(linux) # include #endif #include -#if defined(_KERNEL) && !defined(linux) +#if defined(_KERNEL) # include +# if !defined(__SVR4) && !defined(__svr4__) +# include +# endif #endif #if !defined(__SVR4) && !defined(__svr4__) # if defined(_KERNEL) && !defined(__sgi) # include # endif -# ifndef linux -# include -# endif #else # include # ifdef _KERNEL @@ -58,7 +66,7 @@ #include #include #include -#ifndef linux +#if !defined(linux) # include #endif #include @@ -71,68 +79,134 @@ #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_auth.h" +#include "netinet/ip_proxy.h" #if (__FreeBSD_version >= 300000) # include -# if (defined(KERNEL) || defined(_KERNEL)) +# if defined(_KERNEL) # ifndef IPFILTER_LKM # include # include # endif -extern struct callout_handle ipfr_slowtimer_ch; +extern struct callout_handle fr_slowtimer_ch; # endif #endif #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) # include -extern struct callout ipfr_slowtimer_ch; +extern struct callout fr_slowtimer_ch; #endif #if defined(__OpenBSD__) # include -extern struct timeout ipfr_slowtimer_ch; +extern struct timeout fr_slowtimer_ch; #endif +/* END OF INCLUDES */ #if !defined(lint) #if defined(__NetBSD__) #include -__KERNEL_RCSID(0, "$NetBSD: ip_frag.c,v 1.34 2002/09/19 08:12:49 martti Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_frag.c,v 1.35 2004/03/28 09:00:57 martti Exp $"); #else static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.10.2.24 2002/08/28 12:41:04 darrenr Exp"; +static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77 2004/01/27 00:24:54 darrenr Exp"; #endif #endif -static ipfr_t *ipfr_heads[IPFT_SIZE]; -static ipfr_t *ipfr_nattab[IPFT_SIZE]; +static ipfr_t *ipfr_list = NULL; +static ipfr_t **ipfr_tail = &ipfr_list; +static ipfr_t **ipfr_heads; + +static ipfr_t *ipfr_natlist = NULL; +static ipfr_t **ipfr_nattail = &ipfr_natlist; +static ipfr_t **ipfr_nattab; + +static ipfr_t *ipfr_ipidlist = NULL; +static ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; +static ipfr_t **ipfr_ipidtab; + static ipfrstat_t ipfr_stats; static int ipfr_inuse = 0; +int ipfr_size = IPFT_SIZE; int fr_ipfrttl = 120; /* 60 seconds */ int fr_frag_lock = 0; - -#ifdef _KERNEL -# if SOLARIS2 >= 7 -extern timeout_id_t ipfr_timer_id; -# else -extern int ipfr_timer_id; -# endif -#endif -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat, ipf_mutex; -# if SOLARIS -extern KRWLOCK_T ipf_solaris; -# else -KRWLOCK_T ipf_solaris; -# endif -extern kmutex_t ipf_rw; -#endif +int fr_frag_init = 0; +u_long fr_ticks = 0; -static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, ipfr_t **)); -static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **)); -static void ipfr_delete __P((ipfr_t *)); +static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); +static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); +static void fr_fragdelete __P((ipfr_t *, ipfr_t ***)); -ipfrstat_t *ipfr_fragstats() +/* ------------------------------------------------------------------------ */ +/* Function: fr_fraginit */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: Nil */ +/* */ +/* Initialise the hash tables for the fragment cache lookups. */ +/* ------------------------------------------------------------------------ */ +int fr_fraginit() +{ + KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); + if (ipfr_heads == NULL) + return -1; + bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *)); + + KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); + if (ipfr_nattab == NULL) + return -1; + bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); + + KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); + if (ipfr_ipidtab == NULL) + return -1; + bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); + + RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock"); + fr_frag_init = 1; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Free all memory allocated whilst running and from initialisation. */ +/* ------------------------------------------------------------------------ */ +void fr_fragunload() +{ + if (fr_frag_init == 1) { + fr_fragclear(); + + RW_DESTROY(&ipf_frag); + fr_frag_init = 0; + } + + if (ipfr_heads != NULL) + KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *)); + ipfr_heads = NULL; + + if (ipfr_nattab != NULL) + KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); + ipfr_nattab = NULL; + + if (ipfr_ipidtab != NULL) + KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); + ipfr_ipidtab = NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragstats */ +/* Returns: ipfrstat_t* - pointer to struct with current frag stats */ +/* Parameters: Nil */ +/* */ +/* Updates ipfr_stats with current information and returns a pointer to it */ +/* ------------------------------------------------------------------------ */ +ipfrstat_t *fr_fragstats() { ipfr_stats.ifs_table = ipfr_heads; ipfr_stats.ifs_nattab = ipfr_nattab; @@ -141,24 +215,36 @@ ipfrstat_t *ipfr_fragstats() } -/* - * add a new entry to the fragment cache, registering it as having come - * through this box, with the result of the filter operation. - */ -static ipfr_t *ipfr_new(ip, fin, table) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: ipfr_newfrag */ +/* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* table(I) - pointer to frag table to add to */ +/* */ +/* Add a new entry to the fragment cache, registering it as having come */ +/* through this box, with the result of the filter operation. */ +/* ------------------------------------------------------------------------ */ +static ipfr_t *ipfr_newfrag(fin, pass, table) fr_info_t *fin; +u_32_t pass; ipfr_t *table[]; { - ipfr_t **fp, *fra, frag; + ipfr_t *fra, frag; u_int idx, off; + ip_t *ip; if (ipfr_inuse >= IPFT_SIZE) return NULL; - if (!(fin->fin_fl & FI_FRAG)) + if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) return NULL; + ip = fin->fin_ip; + + if (pass & FR_FRSTRICT) + if ((ip->ip_off & IP_OFFMASK) != 0) + return NULL; + frag.ipfr_p = ip->ip_p; idx = ip->ip_p; frag.ipfr_id = ip->ip_id; @@ -179,10 +265,10 @@ ipfr_t *table[]; /* * first, make sure it isn't already there... */ - for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next) - if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, + for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) + if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ)) { - ATOMIC_INCL(ipfr_stats.ifs_exists); + ipfr_stats.ifs_exists++; return NULL; } @@ -192,105 +278,165 @@ ipfr_t *table[]; */ KMALLOC(fra, ipfr_t *); if (fra == NULL) { - ATOMIC_INCL(ipfr_stats.ifs_nomem); + ipfr_stats.ifs_nomem++; return NULL; } - if ((fra->ipfr_rule = fin->fin_fr) != NULL) { - ATOMIC_INC32(fin->fin_fr->fr_ref); - } - + if ((fra->ipfr_rule = fin->fin_fr) != NULL) + fin->fin_fr->fr_ref++; /* - * Instert the fragment into the fragment table, copy the struct used + * Insert the fragment into the fragment table, copy the struct used * in the search using bcopy rather than reassign each field. * Set the ttl to the default. */ - if ((fra->ipfr_next = table[idx])) - table[idx]->ipfr_prev = fra; - fra->ipfr_prev = NULL; + if ((fra->ipfr_hnext = table[idx]) != NULL) + table[idx]->ipfr_hprev = &fra->ipfr_hnext; + fra->ipfr_hprev = table + idx; fra->ipfr_data = NULL; table[idx] = fra; - bcopy((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ); - fra->ipfr_ttl = fr_ipfrttl; + bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); + fra->ipfr_ttl = fr_ticks + fr_ipfrttl; + /* * Compute the offset of the expected start of the next packet. */ off = ip->ip_off & IP_OFFMASK; - if (!off) + if (off == 0) fra->ipfr_seen0 = 1; fra->ipfr_off = off + (fin->fin_dlen >> 3); - ATOMIC_INCL(ipfr_stats.ifs_new); - ATOMIC_INC32(ipfr_inuse); + fra->ipfr_pass = pass; + ipfr_stats.ifs_new++; + ipfr_inuse++; return fra; } -int ipfr_newfrag(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_newfrag */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Add a new entry to the fragment cache table based on the current packet */ +/* ------------------------------------------------------------------------ */ +int fr_newfrag(fin, pass) +u_32_t pass; fr_info_t *fin; { - ipfr_t *ipf; + ipfr_t *fra; - if ((ip->ip_v != 4) || (fr_frag_lock)) + if ((fin->fin_v != 4) || (fr_frag_lock != 0)) return -1; + WRITE_ENTER(&ipf_frag); - ipf = ipfr_new(ip, fin, ipfr_heads); - RWLOCK_EXIT(&ipf_frag); - if (ipf == NULL) { - ATOMIC_INCL(frstats[fin->fin_out].fr_bnfr); - return -1; + fra = ipfr_newfrag(fin, pass, ipfr_heads); + if (fra != NULL) { + *ipfr_tail = fra; + fra->ipfr_prev = ipfr_tail; + ipfr_tail = &fra->ipfr_next; + if (ipfr_list == NULL) + ipfr_list = fra; + fra->ipfr_next = NULL; } - ATOMIC_INCL(frstats[fin->fin_out].fr_nfr); - return 0; + RWLOCK_EXIT(&ipf_frag); + return fra ? 0 : -1; } -int ipfr_nat_newfrag(ip, fin, nat) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_nat_newfrag */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* */ +/* Create a new NAT fragment cache entry based on the current packet and */ +/* the NAT structure for this "session". */ +/* ------------------------------------------------------------------------ */ +int fr_nat_newfrag(fin, pass, nat) fr_info_t *fin; +u_32_t pass; nat_t *nat; { - ipfr_t *ipf; - int off; + ipfr_t *fra; - if ((ip->ip_v != 4) || (fr_frag_lock)) - return -1; - - off = fin->fin_off; - off <<= 3; - if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) - return -1; + if ((fin->fin_v != 4) || (fr_frag_lock != 0)) + return 0; WRITE_ENTER(&ipf_natfrag); - ipf = ipfr_new(ip, fin, ipfr_nattab); - if (ipf != NULL) { - ipf->ipfr_data = nat; - nat->nat_data = ipf; + fra = ipfr_newfrag(fin, pass, ipfr_nattab); + if (fra != NULL) { + fra->ipfr_data = nat; + nat->nat_data = fra; + *ipfr_nattail = fra; + fra->ipfr_prev = ipfr_nattail; + ipfr_nattail = &fra->ipfr_next; + fra->ipfr_next = NULL; } RWLOCK_EXIT(&ipf_natfrag); - return ipf ? 0 : -1; + return fra ? 0 : -1; } -/* - * check the fragment cache to see if there is already a record of this packet - * with its filter result known. - */ -static ipfr_t *ipfr_lookup(ip, fin, table) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipid_newfrag */ +/* Returns: int - 0 == success, -1 == error */ +/* Parameters: fin(I) - pointer to packet information */ +/* ipid(I) - new IP ID for this fragmented packet */ +/* */ +/* Create a new fragment cache entry for this packet and store, as a data */ +/* pointer, the new IP ID value. */ +/* ------------------------------------------------------------------------ */ +int fr_ipid_newfrag(fin, ipid) +fr_info_t *fin; +u_32_t ipid; +{ + ipfr_t *fra; + + if ((fin->fin_v != 4) || (fr_frag_lock)) + return 0; + + WRITE_ENTER(&ipf_ipidfrag); + fra = ipfr_newfrag(fin, 0, ipfr_ipidtab); + if (fra != NULL) { + fra->ipfr_data = (void *)ipid; + *ipfr_ipidtail = fra; + fra->ipfr_prev = ipfr_ipidtail; + ipfr_ipidtail = &fra->ipfr_next; + fra->ipfr_next = NULL; + } + RWLOCK_EXIT(&ipf_ipidfrag); + return fra ? 0 : -1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fraglookup */ +/* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ +/* matching entry in the frag table, else NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* table(I) - pointer to fragment cache table to search */ +/* */ +/* Check the fragment cache to see if there is already a record of this */ +/* packet with its filter result known. */ +/* ------------------------------------------------------------------------ */ +static ipfr_t *fr_fraglookup(fin, table) fr_info_t *fin; ipfr_t *table[]; { - ipfr_t *f, frag; + ipfr_t *f, frag; u_int idx; - + ip_t *ip; + + if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) + return NULL; + /* * For fragments, we record protocol, packet id, TOS and both IP#'s * (these should all be the same for all fragments of a packet). * * build up a hash value to index the table with. */ + ip = fin->fin_ip; frag.ipfr_p = ip->ip_p; idx = ip->ip_p; frag.ipfr_id = ip->ip_id; @@ -311,48 +457,71 @@ ipfr_t *table[]; /* * check the table, careful to only compare the right amount of data */ - for (f = table[idx]; f; f = f->ipfr_next) - if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src, + for (f = table[idx]; f; f = f->ipfr_hnext) + if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, IPFR_CMPSZ)) { - u_short atoff, off; + u_short off; - off = fin->fin_off; + /* + * We don't want to let short packets match because + * they could be compromising the security of other + * rules that want to match on layer 4 fields (and + * can't because they have been fragmented off.) + * Why do this check here? The counter acts as an + * indicator of this kind of attack, whereas if it was + * elsewhere, it wouldn't know if other matching + * packets had been seen. + */ + if (fin->fin_flx & FI_SHORT) { + ATOMIC_INCL(ipfr_stats.ifs_short); + continue; + } /* * XXX - We really need to be guarding against the * retransmission of (src,dst,id,offset-range) here * because a fragmented packet is never resent with - * the same IP ID#. + * the same IP ID# (or shouldn't). */ + off = ip->ip_off & IP_OFFMASK; if (f->ipfr_seen0) { - if (!off || (fin->fin_fl & FI_SHORT)) + if (off == 0) { + ATOMIC_INCL(ipfr_stats.ifs_retrans0); continue; - } else if (!off) + } + } else if (off == 0) f->ipfr_seen0 = 1; if (f != table[idx]) { + ipfr_t **fp; + /* - * move fragment info. to the top of the list - * to speed up searches. + * Move fragment info. to the top of the list + * to speed up searches. First, delink... */ - if ((f->ipfr_prev->ipfr_next = f->ipfr_next)) - f->ipfr_next->ipfr_prev = f->ipfr_prev; - f->ipfr_next = table[idx]; - table[idx]->ipfr_prev = f; - f->ipfr_prev = NULL; + fp = f->ipfr_hprev; + (*fp) = f->ipfr_hnext; + if (f->ipfr_hnext != NULL) + f->ipfr_hnext->ipfr_hprev = fp; + /* + * Then put back at the top of the chain. + */ + f->ipfr_hnext = table[idx]; + table[idx]->ipfr_hprev = &f->ipfr_hnext; + f->ipfr_hprev = table + idx; table[idx] = f; } - atoff = off + (fin->fin_dlen >> 3); + /* * If we've follwed the fragments, and this is the * last (in order), shrink expiration time. */ if (off == f->ipfr_off) { if (!(ip->ip_off & IP_MF)) - f->ipfr_ttl = 1; - else - f->ipfr_off = atoff; - } + f->ipfr_ttl = fr_ticks + 1; + f->ipfr_off = (fin->fin_dlen >> 3) + off; + } else if (f->ipfr_pass & FR_FRSTRICT) + continue; ATOMIC_INCL(ipfr_stats.ifs_hits); return f; } @@ -360,33 +529,30 @@ ipfr_t *table[]; } -/* - * functional interface for NAT lookups of the NAT fragment cache - */ -nat_t *ipfr_nat_knownfrag(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_nat_knownfrag */ +/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ +/* match found, else NULL */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Functional interface for NAT lookups of the NAT fragment cache */ +/* ------------------------------------------------------------------------ */ +nat_t *fr_nat_knownfrag(fin) fr_info_t *fin; { - ipfr_t *ipf; - nat_t *nat; - int off; + nat_t *nat; + ipfr_t *ipf; - if ((fin->fin_v != 4) || (fr_frag_lock)) + if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist) return NULL; - - off = fin->fin_off; - off <<= 3; - if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) - return NULL; - READ_ENTER(&ipf_natfrag); - ipf = ipfr_lookup(ip, fin, ipfr_nattab); + ipf = fr_fraglookup(fin, ipfr_nattab); if (ipf != NULL) { nat = ipf->ipfr_data; /* * This is the last fragment for this packet. */ - if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) { nat->nat_data = NULL; ipf->ipfr_data = NULL; } @@ -397,117 +563,196 @@ fr_info_t *fin; } -/* - * functional interface for normal lookups of the fragment cache - */ -frentry_t *ipfr_knownfrag(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipid_knownfrag */ +/* Returns: u_32_t - IPv4 ID for this packet if match found, else */ +/* return 0xfffffff to indicate no match. */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Functional interface for IP ID lookups of the IP ID fragment cache */ +/* ------------------------------------------------------------------------ */ +u_32_t fr_ipid_knownfrag(fin) fr_info_t *fin; { - frentry_t *fr; - ipfr_t *fra; - int off; + ipfr_t *ipf; + u_32_t id; - if ((fin->fin_v != 4) || (fr_frag_lock)) - return NULL; + if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist) + return 0xffffffff; - off = fin->fin_off; - off <<= 3; - if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) + READ_ENTER(&ipf_ipidfrag); + ipf = fr_fraglookup(fin, ipfr_ipidtab); + if (ipf != NULL) + id = (u_32_t)ipf->ipfr_data; + else + id = 0xffffffff; + RWLOCK_EXIT(&ipf_ipidfrag); + return id; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_knownfrag */ +/* Returns: frentry_t* - pointer to filter rule if a match is found in */ +/* the frag cache table, else NULL. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(O) - pointer to where to store rule flags resturned */ +/* */ +/* Functional interface for normal lookups of the fragment cache. If a */ +/* match is found, return the rule pointer and flags from the rule, except */ +/* that if FR_LOGFIRST is set, reset FR_LOG. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_knownfrag(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + frentry_t *fr = NULL; + ipfr_t *fra; + u_32_t pass; + + if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL)) return NULL; READ_ENTER(&ipf_frag); - fra = ipfr_lookup(ip, fin, ipfr_heads); - if (fra != NULL) + fra = fr_fraglookup(fin, ipfr_heads); + if (fra != NULL) { fr = fra->ipfr_rule; - else - fr = NULL; + fin->fin_fr = fr; + if (fr != NULL) { + pass = fr->fr_flags; + if ((pass & FR_LOGFIRST) != 0) + pass &= ~(FR_LOGFIRST|FR_LOG); + *passp = pass; + } + } RWLOCK_EXIT(&ipf_frag); return fr; } -/* - * forget any references to this external object. - */ -void ipfr_forget(nat) -void *nat; +/* ------------------------------------------------------------------------ */ +/* Function: fr_forget */ +/* Returns: Nil */ +/* Parameters: ptr(I) - pointer to data structure */ +/* */ +/* Search through all of the fragment cache entries and wherever a pointer */ +/* is found to match ptr, reset it to NULL. */ +/* ------------------------------------------------------------------------ */ +void fr_forget(ptr) +void *ptr; +{ + ipfr_t *fr; + + WRITE_ENTER(&ipf_frag); + for (fr = ipfr_list; fr; fr = fr->ipfr_next) + if (fr->ipfr_data == ptr) + fr->ipfr_data = NULL; + RWLOCK_EXIT(&ipf_frag); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_forgetnat */ +/* Returns: Nil */ +/* Parameters: ptr(I) - pointer to data structure */ +/* */ +/* Search through all of the fragment cache entries for NAT and wherever a */ +/* pointer is found to match ptr, reset it to NULL. */ +/* ------------------------------------------------------------------------ */ +void fr_forgetnat(ptr) +void *ptr; { ipfr_t *fr; - int idx; WRITE_ENTER(&ipf_natfrag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next) - if (fr->ipfr_data == nat) - fr->ipfr_data = NULL; - + for (fr = ipfr_natlist; fr; fr = fr->ipfr_next) + if (fr->ipfr_data == ptr) + fr->ipfr_data = NULL; RWLOCK_EXIT(&ipf_natfrag); } -static void ipfr_delete(fra) -ipfr_t *fra; +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragdelete */ +/* Returns: Nil */ +/* Parameters: fra(I) - pointer to fragment structure to delete */ +/* tail(IO) - pointer to the pointer to the tail of the frag */ +/* list */ +/* */ +/* Remove a fragment cache table entry from the table & list. Also free */ +/* the filter rule it is associated with it if it is no longer used as a */ +/* result of decreasing the reference count. */ +/* ------------------------------------------------------------------------ */ +static void fr_fragdelete(fra, tail) +ipfr_t *fra, ***tail; { frentry_t *fr; fr = fra->ipfr_rule; - if (fr != NULL) { - ATOMIC_DEC32(fr->fr_ref); - if (fr->fr_ref == 0) - KFREE(fr); - } - if (fra->ipfr_prev) - fra->ipfr_prev->ipfr_next = fra->ipfr_next; + if (fr != NULL) + (void)fr_derefrule(&fr); + if (fra->ipfr_next) fra->ipfr_next->ipfr_prev = fra->ipfr_prev; + *fra->ipfr_prev = fra->ipfr_next; + if (*tail == &fra->ipfr_next) + *tail = fra->ipfr_prev; + + if (fra->ipfr_hnext) + fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; + *fra->ipfr_hprev = fra->ipfr_hnext; KFREE(fra); } -/* - * Free memory in use by fragment state info. kept. - */ -void ipfr_unload() +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragclear */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Free memory in use by fragment state information kept. Do the normal */ +/* fragment state stuff first and then the NAT-fragment table. */ +/* ------------------------------------------------------------------------ */ +void fr_fragclear() { - ipfr_t **fp, *fra; + ipfr_t *fra; nat_t *nat; - int idx; WRITE_ENTER(&ipf_frag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fra = *fp); ) { - *fp = fra->ipfr_next; - ipfr_delete(fra); - } + while ((fra = ipfr_list) != NULL) + fr_fragdelete(fra, &ipfr_tail); + ipfr_tail = &ipfr_list; RWLOCK_EXIT(&ipf_frag); WRITE_ENTER(&ipf_nat); WRITE_ENTER(&ipf_natfrag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { - *fp = fra->ipfr_next; - nat = fra->ipfr_data; - if (nat != NULL) { - if (nat->nat_data == fra) - nat->nat_data = NULL; - } - ipfr_delete(fra); + while ((fra = ipfr_natlist) != NULL) { + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; } + fr_fragdelete(fra, &ipfr_nattail); + } + ipfr_nattail = &ipfr_natlist; RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); } -void ipfr_fragexpire() +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragexpire */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Expire entries in the fragment cache table that have been there too long */ +/* ------------------------------------------------------------------------ */ +void fr_fragexpire() { ipfr_t **fp, *fra; nat_t *nat; - int idx; -#if defined(_KERNEL) -# if !SOLARIS +#if defined(USE_SPL) && defined(_KERNEL) int s; -# endif #endif if (fr_frag_lock) @@ -515,25 +760,29 @@ void ipfr_fragexpire() SPL_NET(s); WRITE_ENTER(&ipf_frag); - /* * Go through the entire table, looking for entries to expire, - * decreasing the ttl by one for each entry. If it reaches 0, - * remove it from the chain and free it. + * which is indicated by the ttl being less than or equal to fr_ticks. */ - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fra = *fp); ) { - --fra->ipfr_ttl; - if (fra->ipfr_ttl == 0) { - *fp = fra->ipfr_next; - ipfr_delete(fra); - ATOMIC_INCL(ipfr_stats.ifs_expire); - ATOMIC_DEC32(ipfr_inuse); - } else - fp = &fra->ipfr_next; - } + for (fp = &ipfr_list; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + fr_fragdelete(fra, &ipfr_tail); + ipfr_stats.ifs_expire++; + ipfr_inuse--; + } RWLOCK_EXIT(&ipf_frag); + WRITE_ENTER(&ipf_ipidfrag); + for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + fr_fragdelete(fra, &ipfr_ipidtail); + ipfr_stats.ifs_expire++; + ipfr_inuse--; + } + RWLOCK_EXIT(&ipf_ipidfrag); + /* * Same again for the NAT table, except that if the structure also * still points to a NAT structure, and the NAT structure points back @@ -543,83 +792,72 @@ void ipfr_fragexpire() */ WRITE_ENTER(&ipf_nat); WRITE_ENTER(&ipf_natfrag); - for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { - --fra->ipfr_ttl; - if (fra->ipfr_ttl == 0) { - ATOMIC_INCL(ipfr_stats.ifs_expire); - ATOMIC_DEC32(ipfr_inuse); - nat = fra->ipfr_data; - if (nat != NULL) { - if (nat->nat_data == fra) - nat->nat_data = NULL; - } - *fp = fra->ipfr_next; - ipfr_delete(fra); - } else - fp = &fra->ipfr_next; + for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; } + fr_fragdelete(fra, &ipfr_nattail); + ipfr_stats.ifs_expire++; + ipfr_inuse--; + } RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); SPL_X(s); } -/* - * Slowly expire held state for fragments. Timeouts are set * in expectation - * of this being called twice per second. - */ -#ifdef _KERNEL -# if (BSD >= 199306) || SOLARIS || defined(__sgi) -# if defined(SOLARIS2) && (SOLARIS2 < 7) -void ipfr_slowtimer() -# else -void ipfr_slowtimer __P((void *ptr)) -# endif +/* ------------------------------------------------------------------------ */ +/* Function: fr_slowtimer */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Slowly expire held state for fragments. Timeouts are set * in */ +/* expectation of this being called twice per second. */ +/* ------------------------------------------------------------------------ */ +#if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ + !defined(__osf__)) +# if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) +void fr_slowtimer __P((void *ptr)) # else -int ipfr_slowtimer() +int fr_slowtimer() # endif -#else -void ipfr_slowtimer() -#endif { -#if defined(_KERNEL) && SOLARIS - extern int fr_running; + READ_ENTER(&ipf_global); - if (fr_running <= 0) - return; - READ_ENTER(&ipf_solaris); -#endif - -#if defined(__sgi) && defined(_KERNEL) - ipfilter_sgi_intfsync(); -#endif - - ipfr_fragexpire(); + fr_fragexpire(); fr_timeoutstate(); - ip_natexpire(); + fr_natexpire(); fr_authexpire(); -#if defined(_KERNEL) -# if SOLARIS - ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); - RWLOCK_EXIT(&ipf_solaris); -# else + fr_ticks++; + if (fr_running <= 0) + goto done; +# ifdef _KERNEL # if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) - callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); + callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); # else -# if (__FreeBSD_version >= 300000) - ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# if defined(__OpenBSD__) + timeout_add(&fr_slowtimer_ch, hz/2); # else -# if defined(__OpenBSD__) - timeout_add(&ipfr_slowtimer_ch, hz/2); +# if (__FreeBSD_version >= 300000) + fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); # else - timeout(ipfr_slowtimer, NULL, hz/2); -# endif -# endif -# if (BSD < 199306) && !defined(__sgi) - return 0; -# endif /* FreeBSD */ +# ifdef linux + ; +# else + timeout(fr_slowtimer, NULL, hz/2); +# endif +# endif /* FreeBSD */ +# endif /* OpenBSD */ # endif /* NetBSD */ -# endif /* SOLARIS */ -#endif /* defined(_KERNEL) */ +# endif +done: + RWLOCK_EXIT(&ipf_global); +# if (BSD < 199103) || !defined(_KERNEL) + return 0; +# endif } +#endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ diff --git a/sys/netinet/ip_frag.h b/sys/netinet/ip_frag.h index bfb042713a10..b0286ad4ced0 100644 --- a/sys/netinet/ip_frag.h +++ b/sys/netinet/ip_frag.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip_frag.h,v 1.18 2002/09/19 08:09:15 martti Exp $ */ +/* $NetBSD: ip_frag.h,v 1.19 2004/03/28 09:00:57 martti Exp $ */ /* * Copyright (C) 1993-2001 by Darren Reed. @@ -6,7 +6,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_frag.h 1.5 3/24/96 - * Id: ip_frag.h,v 2.4.2.7 2002/07/06 14:17:51 darrenr Exp + * Id: ip_frag.h,v 2.23 2004/01/08 13:34:28 darrenr Exp */ #ifndef _NETINET_IP_FRAG_H_ @@ -15,17 +15,19 @@ #define IPFT_SIZE 257 typedef struct ipfr { - struct ipfr *ipfr_next, *ipfr_prev; + struct ipfr *ipfr_hnext, **ipfr_hprev; + struct ipfr *ipfr_next, **ipfr_prev; void *ipfr_data; + void *ipfr_ifp; struct in_addr ipfr_src; struct in_addr ipfr_dst; - void *ipfr_ifp; u_32_t ipfr_optmsk; u_short ipfr_secmsk; u_short ipfr_auth; u_short ipfr_id; u_char ipfr_p; u_char ipfr_tos; + u_32_t ipfr_pass; u_short ipfr_off; u_char ipfr_ttl; u_char ipfr_seen0; @@ -40,36 +42,45 @@ typedef struct ipfrstat { u_long ifs_hits; u_long ifs_expire; u_long ifs_inuse; + u_long ifs_retrans0; + u_long ifs_short; struct ipfr **ifs_table; struct ipfr **ifs_nattab; } ipfrstat_t; -#define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_off) - \ - offsetof(ipfr_t, ipfr_src)) +#define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_pass) - \ + offsetof(ipfr_t, ipfr_ifp)) +extern int ipfr_size; extern int fr_ipfrttl; extern int fr_frag_lock; -extern ipfrstat_t *ipfr_fragstats __P((void)); -extern int ipfr_newfrag __P((ip_t *, fr_info_t *)); -extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, struct nat *)); -extern nat_t *ipfr_nat_knownfrag __P((ip_t *, fr_info_t *)); -extern frentry_t *ipfr_knownfrag __P((ip_t *, fr_info_t *)); -extern void ipfr_forget __P((void *)); -extern void ipfr_unload __P((void)); -extern void ipfr_fragexpire __P((void)); +extern int fr_fraginit __P((void)); +extern void fr_fragunload __P((void)); +extern ipfrstat_t *fr_fragstats __P((void)); -#ifdef _KERNEL -# if (BSD >= 199306) || SOLARIS || defined(__sgi) -# if defined(SOLARIS2) && (SOLARIS2 < 7) -extern void ipfr_slowtimer __P((void)); -# else -extern void ipfr_slowtimer __P((void *)); -# endif +extern int fr_newfrag __P((fr_info_t *, u_32_t)); +extern frentry_t *fr_knownfrag __P((fr_info_t *, u_32_t *)); + +extern int fr_nat_newfrag __P((fr_info_t *, u_32_t, struct nat *)); +extern nat_t *fr_nat_knownfrag __P((fr_info_t *)); + +extern int fr_ipid_newfrag __P((fr_info_t *, u_32_t)); +extern u_32_t fr_ipid_knownfrag __P((fr_info_t *)); + +extern void fr_forget __P((void *)); +extern void fr_forgetnat __P((void *)); +extern void fr_fragclear __P((void)); +extern void fr_fragexpire __P((void)); + +#if defined(_KERNEL) && ((BSD >= 199306) || SOLARIS || defined(__sgi) \ + || defined(__osf__) || (defined(__sgi) && (IRIX >= 60500))) +# if defined(SOLARIS2) && (SOLARIS2 < 7) +extern void fr_slowtimer __P((void)); # else -extern int ipfr_slowtimer __P((void)); -# endif /* (BSD >= 199306) || SOLARIS */ +extern void fr_slowtimer __P((void *)); +# endif #else -extern void ipfr_slowtimer __P((void)); -#endif /* _KERNEL */ +extern int fr_slowtimer __P((void)); +#endif #endif /* _NETINET_IP_FRAG_H_ */ diff --git a/sys/netinet/ip_ftp_pxy.c b/sys/netinet/ip_ftp_pxy.c index d9e9440ea62a..ca1bf6577d43 100644 --- a/sys/netinet/ip_ftp_pxy.c +++ b/sys/netinet/ip_ftp_pxy.c @@ -1,30 +1,28 @@ -/* $NetBSD: ip_ftp_pxy.c,v 1.26 2002/09/19 08:12:50 martti Exp $ */ +/* $NetBSD: ip_ftp_pxy.c,v 1.27 2004/03/28 09:00:57 martti Exp $ */ #include -__KERNEL_RCSID(1, "$NetBSD: ip_ftp_pxy.c,v 1.26 2002/09/19 08:12:50 martti Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ip_ftp_pxy.c,v 1.27 2004/03/28 09:00:57 martti Exp $"); /* + * Copyright (C) 1997-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * Id: ip_ftp_pxy.c,v 2.7.2.38 2002/08/28 12:45:47 darrenr Exp + * Id: ip_ftp_pxy.c,v 2.88 2004/02/02 18:23:38 darrenr Exp */ -#if SOLARIS && defined(_KERNEL) -extern kmutex_t ipf_rw; -#endif - -#define isdigit(x) ((x) >= '0' && (x) <= '9') -#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z')) -#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) -#define isalpha(x) (isupper(x) || islower(x)) -#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') +#undef IPF_FTP_DEBUG #define IPF_FTP_PROXY #define IPF_MINPORTLEN 18 #define IPF_MAXPORTLEN 30 #define IPF_MIN227LEN 39 #define IPF_MAX227LEN 51 +#define IPF_MIN229LEN 47 +#define IPF_MAX229LEN 51 #define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ #define FTPXY_GO 0 @@ -44,24 +42,37 @@ extern kmutex_t ipf_rw; #define FTPXY_PASS_2 14 #define FTPXY_PAOK_2 15 +/* + * Values for FTP commands. Numerics cover 0-999 + */ +#define FTPXY_C_PASV 1000 + int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); int ippr_ftp_complete __P((char *, size_t)); -int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *)); int ippr_ftp_init __P((void)); -int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); +void ippr_ftp_fini __P((void)); +int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_epsv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); -int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_process __P((fr_info_t *, nat_t *, ftpinfo_t *, int)); int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); -int ippr_ftp_valid __P((int, char *, size_t)); -int ippr_ftp_server_valid __P((char *, size_t)); -int ippr_ftp_client_valid __P((char *, size_t)); +int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t)); +int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t)); +int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t)); u_short ippr_ftp_atoi __P((char **)); +int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, + u_int, char *, char *, u_int)); static frentry_t ftppxyfr; + +int ftp_proxy_init = 0; int ippr_ftp_pasvonly = 0; -int ippr_ftp_insecure = 0; +int ippr_ftp_insecure = 0; /* Do not require logins before transfers */ +int ippr_ftp_pasvrdr = 0; +int ippr_ftp_forcepasv = 0; /* PASV must be last command prior to 227 */ /* @@ -72,13 +83,24 @@ int ippr_ftp_init() bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); ftppxyfr.fr_ref = 1; ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex"); + ftp_proxy_init = 1; + return 0; } -int ippr_ftp_new(fin, ip, aps, nat) +void ippr_ftp_fini() +{ + if (ftp_proxy_init == 1) { + MUTEX_DESTROY(&ftppxyfr.fr_lock); + ftp_proxy_init = 0; + } +} + + +int ippr_ftp_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { @@ -88,6 +110,10 @@ nat_t *nat; KMALLOC(ftp, ftpinfo_t *); if (ftp == NULL) return -1; + + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_data = ftp; aps->aps_psiz = sizeof(ftpinfo_t); @@ -99,6 +125,7 @@ nat_t *nat; f->ftps_rptr = f->ftps_buf; f->ftps_wptr = f->ftps_buf; ftp->ftp_passok = FTPXY_INIT; + ftp->ftp_incok = 0; return 0; } @@ -112,25 +139,28 @@ int dlen; { tcphdr_t *tcp, tcph, *tcp2 = &tcph; char newbuf[IPF_FTPBUFSZ], *s; + struct in_addr swip, swip2; + int inc, off = 0, flags; u_int a1, a2, a3, a4; - struct in_addr swip; u_short a5, a6, sp; size_t nlen, olen; fr_info_t fi; - int inc, off; - nat_t *ipn; + nat_t *nat2; mb_t *m; -#if SOLARIS - mb_t *m1; -#endif + m = fin->fin_m; tcp = (tcphdr_t *)fin->fin_dp; + off = (char *)tcp - MTOD(m, char *) + (TCP_OFF(tcp) << 2); + /* * Check for client sending out PORT message. */ - if (dlen < IPF_MINPORTLEN) + if (dlen < IPF_MINPORTLEN) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", dlen); +#endif return 0; - off = fin->fin_hlen + (tcp->th_off << 2); + } /* * Skip the PORT command + space */ @@ -139,23 +169,42 @@ int dlen; * Pick out the address components, two at a time. */ a1 = ippr_ftp_atoi(&s); - if (!s) + if (s == NULL) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:ippr_ftp_atoi(1) failed\n"); +#endif return 0; + } a2 = ippr_ftp_atoi(&s); - if (!s) + if (s == NULL) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:ippr_ftp_atoi(2) failed\n"); +#endif return 0; + } /* - * check that IP address in the PORT/PASV reply is the same as the + * Check that IP address in the PORT/PASV reply is the same as the * sender of the command - prevents using PORT for port scanning. */ a1 <<= 16; a1 |= a2; - if (a1 != ntohl(nat->nat_inip.s_addr)) - return 0; + if (((nat->nat_dir == NAT_OUTBOUND) && + (a1 != ntohl(nat->nat_inip.s_addr))) || + ((nat->nat_dir == NAT_INBOUND) && + (a1 != ntohl(nat->nat_oip.s_addr)))) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:a1 != nat->nat_inip\n"); +#endif + return APR_ERR(1); + } a5 = ippr_ftp_atoi(&s); - if (!s) + if (s == NULL) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:ippr_ftp_atoi(3) failed\n"); +#endif return 0; + } if (*s == ')') s++; @@ -167,110 +216,99 @@ int dlen; if ((*s == '\r') && (*(s + 1) == '\n')) { s += 2; a6 = a5 & 0xff; - } else + } else { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:missing cr-lf\n"); +#endif return 0; + } a5 >>= 8; a5 &= 0xff; /* * Calculate new address parts for PORT command */ - a1 = ntohl(ip->ip_src.s_addr); + if (nat->nat_dir == NAT_INBOUND) + a1 = ntohl(nat->nat_oip.s_addr); + else + a1 = ntohl(ip->ip_src.s_addr); a2 = (a1 >> 16) & 0xff; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; olen = s - f->ftps_rptr; /* DO NOT change this to snprintf! */ +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", + "PORT", a1, a2, a3, a4, a5, a6); +#else (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "PORT", a1, a2, a3, a4, a5, a6); +#endif nlen = strlen(newbuf); inc = nlen - olen; - if ((inc + ip->ip_len) > 65535) + if ((inc + ip->ip_len) > 65535) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", inc); +#endif return 0; + } #if !defined(_KERNEL) - m = *((mb_t **)fin->fin_mp); - bcopy(newbuf, (char *)m + off, nlen); + bcopy(newbuf, MTOD(m, char *) + off, nlen); #else -# if SOLARIS - m = fin->fin_qfm; - for (m1 = m; m1->b_cont; m1 = m1->b_cont) - ; - if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { - mblk_t *nm; - - /* alloc enough to keep same trailer space for lower driver */ - nm = allocb(nlen, BPRI_MED); - PANIC((!nm),("ippr_ftp_out: allocb failed")); - - nm->b_band = m1->b_band; - nm->b_wptr += nlen; - - m1->b_wptr -= olen; - PANIC((m1->b_wptr < m1->b_rptr), - ("ippr_ftp_out: cannot handle fragmented data block")); - - linkb(m1, nm); - } else { - if (m1->b_datap->db_struiolim == m1->b_wptr) - m1->b_datap->db_struiolim += inc; - m1->b_datap->db_struioflag &= ~STRUIO_IP; - m1->b_wptr += inc; - } - copyin_mblk(m, off, nlen, newbuf); +# if defined(MENTAT) + if (inc < 0) + (void)adjmsg(m, inc); # else - m = *((mb_t **)fin->fin_mp); if (inc < 0) m_adj(m, inc); - /* the mbuf chain will be extended if necessary by m_copyback() */ - m_copyback(m, off, nlen, newbuf); # ifdef M_PKTHDR if (!(m->m_flags & M_PKTHDR)) m->m_pkthdr.len += inc; # endif # endif #endif + /* the mbuf chain will be extended if necessary by m_copyback() */ + COPYBACK(m, off, nlen, newbuf); + if (inc != 0) { -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) - register u_32_t sum1, sum2; - - sum1 = ip->ip_len; - sum2 = ip->ip_len + inc; - - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sum2 -= sum1; - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - fix_outcksum(fin, &ip->ip_sum, sum2); -#endif ip->ip_len += inc; + fin->fin_dlen += inc; + fin->fin_plen += inc; } /* * Add skeleton NAT entry for connection which will come back the * other way. */ - sp = (a5 << 8 | a6); + sp = a5 << 8 | a6; /* * Don't allow the PORT command to specify a port < 1024 due to * security crap. */ - if (sp < 1024) + if (sp < 1024) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_port:sp(%d) < 1024\n", sp); +#endif return 0; + } /* * The server may not make the connection back from port 20, but * it is the most likely so use it here to check for a conflicting * mapping. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_flx |= FI_IGNORE; fi.fin_data[0] = sp; fi.fin_data[1] = fin->fin_data[1] - 1; - ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, 0); - if (ipn == NULL) { + if (nat->nat_dir == NAT_OUTBOUND) + nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + else + nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + if (nat2 == NULL) { int slen; slen = ip->ip_len; @@ -278,28 +316,59 @@ int dlen; bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = htons(sp); - tcp2->th_off = 5; + TCP_OFF_A(tcp2, 5); tcp2->th_flags = TH_SYN; tcp2->th_dport = 0; /* XXX - don't specify remote port */ fi.fin_data[1] = 0; fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); fi.fin_dp = (char *)tcp2; fi.fin_fr = &ftppxyfr; - fi.fin_out = 1; + fi.fin_out = nat->nat_dir; + fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; swip = ip->ip_src; - fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; - ip->ip_src = nat->nat_inip; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_W_DPORT|FI_IGNOREPKT); + swip2 = ip->ip_dst; + if (nat->nat_dir == NAT_OUTBOUND) { + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; + ip->ip_src = nat->nat_inip; + } else if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; + ip->ip_src = nat->nat_oip; + } + + flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; + if (nat->nat_dir == NAT_INBOUND) + flags |= NAT_NOTRULEPORT; + nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir); + + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_TCP); + nat_update(&fi, nat2, nat->nat_ptr); + fi.fin_ifp = NULL; + if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; + ip->ip_dst = nat->nat_inip; + } + (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); } ip->ip_len = slen; ip->ip_src = swip; + ip->ip_dst = swip2; + } else { + ipstate_t *is; + + nat_update(&fi, nat2, nat->nat_ptr); + READ_ENTER(&ipf_state); + is = nat2->nat_state; + if (is != NULL) { + MUTEX_ENTER(&is->is_lock); + (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, + is->is_flags); + MUTEX_EXIT(&is->is_lock); + } + RWLOCK_EXIT(&ipf_state); } - return inc; + return APR_INC(inc); } @@ -374,35 +443,49 @@ int dlen; } -int ippr_ftp_pasv(fin, ip, nat, f, dlen) +int ippr_ftp_pasv(fin, ip, nat, ftp, dlen) fr_info_t *fin; ip_t *ip; nat_t *nat; -ftpside_t *f; +ftpinfo_t *ftp; int dlen; { - tcphdr_t *tcp, tcph, *tcp2 = &tcph; - struct in_addr swip, swip2; - u_int a1, a2, a3, a4; - u_short a5, a6, dp; - fr_info_t fi; - nat_t *ipn; - int inc; + u_int a1, a2, a3, a4, data_ip; + char newbuf[IPF_FTPBUFSZ]; + u_short a5, a6; + ftpside_t *f; char *s; + if (ippr_ftp_forcepasv != 0 && + ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n", + ftp->ftp_side[0].ftps_cmds); +#endif + return 0; + } + + f = &ftp->ftp_side[1]; + #define PASV_REPLEN 24 /* * Check for PASV reply message. */ - if (dlen < IPF_MIN227LEN) + if (dlen < IPF_MIN227LEN) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", dlen); +#endif return 0; - else if (strncmp(f->ftps_rptr, "227 Entering Passive Mod", PASV_REPLEN)) + } else if (strncmp(f->ftps_rptr, + "227 Entering Passive Mod", PASV_REPLEN)) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:227 reply wrong\n"); +#endif return 0; - - tcp = (tcphdr_t *)fin->fin_dp; + } /* - * Skip the PORT command + space + * Skip the PASV reply + space */ s = f->ftps_rptr + PASV_REPLEN; while (*s && !isdigit(*s)) @@ -411,24 +494,44 @@ int dlen; * Pick out the address components, two at a time. */ a1 = ippr_ftp_atoi(&s); - if (!s) + if (s == NULL) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:ippr_ftp_atoi(1) failed\n"); +#endif return 0; + } a2 = ippr_ftp_atoi(&s); - if (!s) + if (s == NULL) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:ippr_ftp_atoi(2) failed\n"); +#endif return 0; + } /* - * check that IP address in the PORT/PASV reply is the same as the - * sender of the command - prevents using PORT for port scanning. + * check that IP address in the PASV reply is the same as the + * sender of the command - prevents using PASV for port scanning. */ a1 <<= 16; a1 |= a2; - if (a1 != ntohl(nat->nat_oip.s_addr)) + + if (((nat->nat_dir == NAT_INBOUND) && + (a1 != ntohl(nat->nat_inip.s_addr))) || + ((nat->nat_dir == NAT_OUTBOUND) && + (a1 != ntohl(nat->nat_oip.s_addr)))) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:a1 != nat->nat_oip\n"); +#endif return 0; + } a5 = ippr_ftp_atoi(&s); - if (!s) + if (s == NULL) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:ippr_ftp_atoi(3) failed\n"); +#endif return 0; + } if (*s == ')') s++; @@ -441,93 +544,116 @@ int dlen; */ if ((*s == '\r') && (*(s + 1) == '\n')) { s += 2; - a6 = a5 & 0xff; - } else + } else { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:missing cr-lf\n"); +#endif return 0; + } + + a6 = a5 & 0xff; a5 >>= 8; /* * Calculate new address parts for 227 reply */ - a1 = ntohl(ip->ip_src.s_addr); + if (nat->nat_dir == NAT_INBOUND) { + data_ip = nat->nat_outip.s_addr; + a1 = ntohl(data_ip); + } else + data_ip = htonl(a1); + a2 = (a1 >> 16) & 0xff; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; - inc = 0; -#if 0 - olen = s - f->ftps_rptr; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", + "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); +#else (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); - nlen = strlen(newbuf); +#endif + return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6), + newbuf, s, data_ip); +} + +int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpside_t *f; +u_int port; +char *newmsg; +char *s; +u_int data_ip; +{ + int inc, off, nflags, sflags; + tcphdr_t *tcp, tcph, *tcp2; + struct in_addr swip, swip2; + struct in_addr data_addr; + size_t nlen, olen; + fr_info_t fi; + nat_t *nat2; + mb_t *m; + + m = fin->fin_m; + tcp = (tcphdr_t *)fin->fin_dp; + off = (char *)tcp - MTOD(m, char *) + (TCP_OFF(tcp) << 2); + + data_addr.s_addr = data_ip; + tcp2 = &tcph; + inc = 0; + + + olen = s - f->ftps_rptr; + nlen = strlen(newmsg); inc = nlen - olen; - if ((inc + ip->ip_len) > 65535) + if ((inc + ip->ip_len) > 65535) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n", inc); +#endif return 0; + } #if !defined(_KERNEL) - m = *((mb_t **)fin->fin_mp); - m_copyback(m, off, nlen, newbuf); + bcopy(newmsg, (char *)m + off, nlen); #else -# if SOLARIS - m = fin->fin_qfm; - for (m1 = m; m1->b_cont; m1 = m1->b_cont) - ; - if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { - mblk_t *nm; - - /* alloc enough to keep same trailer space for lower driver */ - nm = allocb(nlen, BPRI_MED); - PANIC((!nm),("ippr_ftp_out: allocb failed")); - - nm->b_band = m1->b_band; - nm->b_wptr += nlen; - - m1->b_wptr -= olen; - PANIC((m1->b_wptr < m1->b_rptr), - ("ippr_ftp_out: cannot handle fragmented data block")); - - linkb(m1, nm); - } else { - m1->b_wptr += inc; - } - /*copyin_mblk(m, off, nlen, newbuf);*/ -# else /* SOLARIS */ - m = *((mb_t **)fin->fin_mp); +# if defined(MENTAT) + if (inc < 0) + (void)adjmsg(m, inc); +# else /* defined(MENTAT) */ if (inc < 0) m_adj(m, inc); /* the mbuf chain will be extended if necessary by m_copyback() */ - /*m_copyback(m, off, nlen, newbuf);*/ -# endif /* SOLARIS */ -#endif /* _KERNEL */ +# endif /* defined(MENTAT) */ +#endif /* !defined(_KERNEL) */ + COPYBACK(m, off, nlen, newmsg); + if (inc != 0) { -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) - register u_32_t sum1, sum2; - - sum1 = ip->ip_len; - sum2 = ip->ip_len + inc; - - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sum2 -= sum1; - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - fix_outcksum(fin, &ip->ip_sum, sum2); -#endif /* SOLARIS || defined(__sgi) */ ip->ip_len += inc; + fin->fin_dlen += inc; + fin->fin_plen += inc; } -#endif /* 0 */ /* * Add skeleton NAT entry for connection which will come back the * other way. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_flx |= FI_IGNORE; fi.fin_data[0] = 0; - dp = htons(fin->fin_data[1] - 1); - fi.fin_data[1] = ntohs(dp); - ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, 0); - if (ipn == NULL) { + fi.fin_data[1] = port; + nflags = IPN_TCP|SI_W_SPORT; + if (ippr_ftp_pasvrdr && f->ftps_ifp) + nflags |= SI_W_DPORT; + if (nat->nat_dir == NAT_OUTBOUND) + nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH, + nat->nat_p, nat->nat_inip, nat->nat_oip); + else + nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH, + nat->nat_p, nat->nat_inip, nat->nat_oip); + if (nat2 == NULL) { int slen; slen = ip->ip_len; @@ -535,31 +661,63 @@ int dlen; bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = 0; /* XXX - fake it for nat_new */ - tcp2->th_off = 5; + TCP_OFF_A(tcp2, 5); tcp2->th_flags = TH_SYN; - fi.fin_data[1] = a5 << 8 | a6; + fi.fin_data[1] = port; fi.fin_dlen = sizeof(*tcp2); - tcp2->th_dport = htons(fi.fin_data[1]); + tcp2->th_dport = htons(port); fi.fin_data[0] = 0; fi.fin_dp = (char *)tcp2; + fi.fin_plen = fi.fin_hlen + sizeof(*tcp); fi.fin_fr = &ftppxyfr; - fi.fin_out = 1; + fi.fin_out = nat->nat_dir; + fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; swip = ip->ip_src; swip2 = ip->ip_dst; - fi.fin_fi.fi_daddr = ip->ip_src.s_addr; - fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; - ip->ip_dst = ip->ip_src; - ip->ip_src = nat->nat_inip; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_W_SPORT|FI_IGNOREPKT); + if (nat->nat_dir == NAT_OUTBOUND) { + fi.fin_fi.fi_daddr = data_addr.s_addr; + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; + ip->ip_dst = data_addr; + ip->ip_src = nat->nat_inip; + } else if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; + fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; + ip->ip_src = nat->nat_oip; + ip->ip_dst = nat->nat_outip; } + + sflags = nflags; + nflags |= NAT_SLAVE; + if (nat->nat_dir == NAT_INBOUND) + nflags |= NAT_NOTRULEPORT; + nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_TCP); + nat_update(&fi, nat2, nat->nat_ptr); + fi.fin_ifp = NULL; + if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; + ip->ip_dst = nat->nat_inip; + } + (void) fr_addstate(&fi, &nat2->nat_state, sflags); + } + ip->ip_len = slen; ip->ip_src = swip; ip->ip_dst = swip2; + } else { + ipstate_t *is; + + nat_update(&fi, nat2, nat->nat_ptr); + READ_ENTER(&ipf_state); + is = nat2->nat_state; + if (is != NULL) { + MUTEX_ENTER(&is->is_lock); + (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, + is->is_flags); + MUTEX_EXIT(&is->is_lock); + } + RWLOCK_EXIT(&ipf_state); } return inc; } @@ -585,9 +743,13 @@ int dlen; return 0; if (ftp->ftp_passok == FTPXY_GO) { if (!strncmp(rptr, "227 ", 4)) - inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen); + else if (!strncmp(rptr, "229 ", 4)) + inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { - inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen); + } else if (ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) { + inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); } else if (*rptr == '5' || *rptr == '4') ftp->ftp_passok = FTPXY_INIT; else if (ftp->ftp_incok) { @@ -613,6 +775,7 @@ int dlen; } } ftp->ftp_incok = 0; + while ((*rptr++ != '\n') && (rptr < wptr)) ; f->ftps_rptr = rptr; @@ -624,111 +787,162 @@ int dlen; * Look to see if the buffer starts with something which we recognise as * being the correct syntax for the FTP protocol. */ -int ippr_ftp_client_valid(buf, len) +int ippr_ftp_client_valid(ftps, buf, len) +ftpside_t *ftps; char *buf; size_t len; { register char *s, c; register size_t i = len; + char cmd[5]; - if (i < 5) + if (i < 5) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i); +#endif return 2; + } s = buf; c = *s++; i--; if (isalpha(c)) { + cmd[0] = toupper(c); c = *s++; i--; if (isalpha(c)) { + cmd[1] = toupper(c); c = *s++; i--; if (isalpha(c)) { + cmd[2] = toupper(c); c = *s++; i--; if (isalpha(c)) { + cmd[3] = toupper(c); c = *s++; i--; if ((c != ' ') && (c != '\r')) - return 1; + goto bad_client_command; } else if ((c != ' ') && (c != '\r')) - return 1; + goto bad_client_command; } else - return 1; + goto bad_client_command; } else - return 1; - } else + goto bad_client_command; + } else { +bad_client_command: +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_client_valid:bad cmd:len %d i %d c 0x%x\n", + (int)i, (int)len, c); +#endif return 1; + } + for (; i; i--) { c = *s++; - if (c == '\n') + if (c == '\n') { + cmd[4] = '\0'; + if (!strcmp(cmd, "PASV")) + ftps->ftps_cmds = FTPXY_C_PASV; + else + ftps->ftps_cmds = 0; return 0; + } } +#if !defined(_KERNEL) + printf("ippr_ftp_client_valid:junk after cmd[%s]\n", buf); +#endif return 2; } -int ippr_ftp_server_valid(buf, len) +int ippr_ftp_server_valid(ftps, buf, len) +ftpside_t *ftps; char *buf; size_t len; { register char *s, c; register size_t i = len; + int cmd; if (i < 5) return 2; s = buf; c = *s++; + cmd = 0; i--; if (isdigit(c)) { + cmd = (c - '0') * 100; c = *s++; i--; if (isdigit(c)) { + cmd += (c - '0') * 10; c = *s++; i--; if (isdigit(c)) { + cmd += (c - '0'); c = *s++; i--; if ((c != '-') && (c != ' ')) - return 1; + goto bad_server_command; } else - return 1; + goto bad_server_command; } else - return 1; - } else + goto bad_server_command; + } else { +bad_server_command: +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_server_valid:bad cmd:len %d i %d c 0x%x\n", + (int)i, (int)len, c); +#endif return 1; + } + for (; i; i--) { c = *s++; - if (c == '\n') + if (c == '\n') { + ftps->ftps_cmds = cmd; return 0; + } } +#if !defined(_KERNEL) + printf("ippr_ftp_server_valid:junk after cmd[%s]\n", buf); +#endif return 2; } -int ippr_ftp_valid(side, buf, len) +int ippr_ftp_valid(ftp, side, buf, len) +ftpinfo_t *ftp; int side; char *buf; size_t len; { + ftpside_t *ftps; int ret; + ftps = &ftp->ftp_side[side]; + if (side == 0) - ret = ippr_ftp_client_valid(buf, len); + ret = ippr_ftp_client_valid(ftps, buf, len); else - ret = ippr_ftp_server_valid(buf, len); + ret = ippr_ftp_server_valid(ftps, buf, len); return ret; } /* + * For map rules, the following applies: * rv == 0 for outbound processing, * rv == 1 for inbound processing. + * For rdr rules, the following applies: + * rv == 0 for inbound processing, + * rv == 1 for outbound processing. */ -int ippr_ftp_process(fin, ip, nat, ftp, rv) +int ippr_ftp_process(fin, nat, ftp, rv) fr_info_t *fin; -ip_t *ip; nat_t *nat; ftpinfo_t *ftp; int rv; @@ -739,33 +953,29 @@ int rv; ap_session_t *aps; ftpside_t *f, *t; tcphdr_t *tcp; + ip_t *ip; mb_t *m; + m = fin->fin_m; + ip = fin->fin_ip; tcp = (tcphdr_t *)fin->fin_dp; - off = fin->fin_hlen + (tcp->th_off << 2); -#if SOLARIS && defined(_KERNEL) - m = fin->fin_qfm; -#else - m = *((mb_t **)fin->fin_mp); -#endif + off = (char *)tcp - MTOD(m, char *) + (TCP_OFF(tcp) << 2); -#ifndef _KERNEL - mlen = mbuflen(m); -#else -# if SOLARIS - mlen = msgdsize(m); -# else - mlen = mbufchainlen(m); -# endif -#endif - mlen -= off; - - aps = nat->nat_aps; - t = &ftp->ftp_side[1 - rv]; f = &ftp->ftp_side[rv]; + t = &ftp->ftp_side[1 - rv]; thseq = ntohl(tcp->th_seq); thack = ntohl(tcp->th_ack); + mlen = MSGDSIZE(m) - off; + if (mlen <= 0) { + if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { + f->ftps_seq[0] = thseq + 1; + t->ftps_seq[0] = thack; + } + return 0; + } + aps = nat->nat_aps; + sel = aps->aps_sel[1 - rv]; sel2 = aps->aps_sel[rv]; if (rv == 0) { @@ -819,9 +1029,10 @@ int rv; #endif ok = 0; - if (t->ftps_seq[0] == 0) - t->ftps_seq[0] = thack, ok = 1; - else { + if (t->ftps_seq[0] == 0) { + t->ftps_seq[0] = thack; + ok = 1; + } else { if (ackoff == 0) { if (t->ftps_seq[0] == thack) ok = 1; @@ -846,24 +1057,28 @@ int rv; #if PROXY_DEBUG if (!ok) - printf("not ok\n"); + printf("not ok\n"); #endif if (!mlen) { - if (t->ftps_seq[0] + ackoff != thack) + if (t->ftps_seq[0] + ackoff != thack) { +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf( + "ippr_ftp_process:seq[0](%x) + ackoff(%x) != thack(%x)\n", + t->ftps_seq[0], ackoff, thack); +#endif return APR_ERR(1); + } #if PROXY_DEBUG printf("f:seq[0] %x seq[1] %x\n", f->ftps_seq[0], f->ftps_seq[1]); #endif if (tcp->th_flags & TH_FIN) { - if (thseq + seqoff == f->ftps_seq[0] + 1 || - f->ftps_seq[0] + seqoff + 1 == thseq || - thseq + seqoff == f->ftps_seq[0] || - thseq == f->ftps_seq[0] + seqoff) - ; - else { -#if PROXY_DEBUG + if (thseq == f->ftps_seq[1]) { + f->ftps_seq[0] = f->ftps_seq[1] - seqoff; + f->ftps_seq[1] = thseq + 1 - seqoff; + } else { +#if PROXY_DEBUG || !defined(_KERNEL) || defined(IPF_FTP_DEBUG) printf("FIN: thseq %x seqoff %d ftps_seq %x\n", thseq, seqoff, f->ftps_seq[0]); #endif @@ -875,17 +1090,19 @@ int rv; } ok = 0; - if (thseq == f->ftps_seq[0] || thseq == f->ftps_seq[1]) + if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { ok = 1; /* * Retransmitted data packet. */ - else if (thseq + mlen == f->ftps_seq[0] || - thseq + mlen == f->ftps_seq[1]) + } else if ((thseq + mlen == f->ftps_seq[0]) || + (thseq + mlen == f->ftps_seq[1])) { ok = 1; + } + if (ok == 0) { inc = thseq - f->ftps_seq[0]; -#if PROXY_DEBUG +#if PROXY_DEBUG || !defined(_KERNEL) printf("inc %d sel %d rv %d\n", inc, sel, rv); printf("th_seq %x ftps_seq %x/%x\n", thseq, f->ftps_seq[0], f->ftps_seq[1]); @@ -907,25 +1124,18 @@ int rv; while (mlen > 0) { len = MIN(mlen, FTP_BUFSZ / 2); - -#if !defined(_KERNEL) - bcopy((char *)m + off, wptr, len); -#else -# if SOLARIS - copyout_mblk(m, off, len, wptr); -# else - m_copydata(m, off, len, wptr); -# endif -#endif + COPYDATA(m, off, len, wptr); mlen -= len; off += len; wptr += len; f->ftps_wptr = wptr; if (f->ftps_junk == 2) - f->ftps_junk = ippr_ftp_valid(rv, rptr, wptr - rptr); + f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, + wptr - rptr); while ((f->ftps_junk == 0) && (wptr > rptr)) { - f->ftps_junk = ippr_ftp_valid(rv, rptr, wptr - rptr); + f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, + wptr - rptr); if (f->ftps_junk == 0) { f->ftps_cmds++; len = wptr - rptr; @@ -947,6 +1157,9 @@ int rv; */ if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) { /* f->ftps_seq[1] += inc; */ +#if !defined(_KERNEL) || defined(IPF_FTP_DEBUG) + printf("ippr_ftp_process:cmds == 0 junk == 1\n"); +#endif return APR_ERR(2); } @@ -990,18 +1203,9 @@ int rv; /* f->ftps_seq[1] += inc; */ if (tcp->th_flags & TH_FIN) f->ftps_seq[1]++; -#ifndef _KERNEL - mlen = mbuflen(m); -#else -# if SOLARIS - mlen = msgdsize(m); -# else - mlen = mbufchainlen(m); -# endif -#endif - off = fin->fin_hlen + (tcp->th_off << 2); - mlen -= off; #if PROXY_DEBUG + mlen = MSGDSIZE(m); + mlen -= off; printf("ftps_seq[1] = %x inc %d len %d\n", f->ftps_seq[1], inc, mlen); #endif @@ -1011,33 +1215,43 @@ int rv; } -int ippr_ftp_out(fin, ip, aps, nat) +int ippr_ftp_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { ftpinfo_t *ftp; + int rev; ftp = aps->aps_data; if (ftp == NULL) return 0; - return ippr_ftp_process(fin, ip, nat, ftp, 0); + + rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; + if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) + ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; + + return ippr_ftp_process(fin, nat, ftp, rev); } -int ippr_ftp_in(fin, ip, aps, nat) +int ippr_ftp_in(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { ftpinfo_t *ftp; + int rev; ftp = aps->aps_data; if (ftp == NULL) return 0; - return ippr_ftp_process(fin, ip, nat, ftp, 1); + + rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; + if (ftp->ftp_side[rev].ftps_ifp == NULL) + ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; + + return ippr_ftp_process(fin, nat, ftp, 1 - rev); } @@ -1053,7 +1267,7 @@ char **ptr; register char *s = *ptr, c; register u_char i = 0, j = 0; - while ((c = *s++) && isdigit(c)) { + while (((c = *s++) != '\0') && isdigit(c)) { i *= 10; i += c - '0'; } @@ -1061,7 +1275,7 @@ char **ptr; *ptr = NULL; return 0; } - while ((c = *s++) && isdigit(c)) { + while (((c = *s++) != '\0') && isdigit(c)) { j *= 10; j += c - '0'; } @@ -1070,3 +1284,103 @@ char **ptr; j &= 0xff; return (i << 8) | j; } + + +int ippr_ftp_epsv(fin, ip, nat, f, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpside_t *f; +int dlen; +{ + char newbuf[IPF_FTPBUFSZ]; + char *s; + u_short ap = 0; + +#define EPSV_REPLEN 33 + /* + * Check for EPSV reply message. + */ + if (dlen < IPF_MIN229LEN) + return (0); + else if (strncmp(f->ftps_rptr, + "229 Entering Extended Passive Mode", EPSV_REPLEN)) + return (0); + + /* + * Skip the EPSV command + space + */ + s = f->ftps_rptr + 33; + while (*s && !isdigit(*s)) + s++; + + /* + * As per RFC 2428, there are no addres components in the EPSV + * response. So we'll go straight to getting the port. + */ + while (*s && isdigit(*s)) { + ap *= 10; + ap += *s++ - '0'; + } + + if (!s) + return 0; + + if (*s == '|') + s++; + if (*s == ')') + s++; + if (*s == '\n') + s--; + /* + * check for CR-LF at the end. + */ + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; + } else + return 0; + +#if defined(SNPRINTF) && defined(_KERNEL) + SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", + "229 Entering Extended Passive Mode", ap); +#else + (void) sprintf(newbuf, "%s (|||%u|)\r\n", + "229 Entering Extended Passive Mode", ap); +#endif + + return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s, + ip->ip_src.s_addr); +} + + +#if 0 +ippr_ftp_parse(str, len) +{ + char *s, c; + + if (len < 5) + return -1; + s = str; + if (*s++ != '|') + return -1; + c = *s++; + if (c != '|') { + if (*s++ != '|') + return -1; + } else + c = '1'; + + if (c == '1') { + /* + * IPv4 dotted quad. + */ + return 0; + } else if (c == '2') { + /* + * IPv6 hex string + */ + return 0; + } + return -1; +} +#endif diff --git a/sys/netinet/ip_h323_pxy.c b/sys/netinet/ip_h323_pxy.c index 88e4c8fc9c5f..680725aaaca0 100644 --- a/sys/netinet/ip_h323_pxy.c +++ b/sys/netinet/ip_h323_pxy.c @@ -1,8 +1,8 @@ -/* $NetBSD: ip_h323_pxy.c,v 1.8 2003/06/23 15:20:57 martin Exp $ */ +/* $NetBSD: ip_h323_pxy.c,v 1.9 2004/03/28 09:00:57 martti Exp $ */ /* * Copyright 2001, QNX Software Systems Ltd. All Rights Reserved - * + * * This source code has been published by QNX Software Systems Ltd. (QSSL). * However, any use, reproduction, modification, distribution or transfer of * this software, or any software which includes or is based upon any of this @@ -16,7 +16,7 @@ /* * Simple H.323 proxy - * + * * by xtang@canada.com * ported to ipfilter 3.4.20 by Michael Grant mg-ipf@grant.org */ @@ -32,32 +32,31 @@ #include "opt_ipfilter_log.h" #endif -__KERNEL_RCSID(1, "$NetBSD: ip_h323_pxy.c,v 1.8 2003/06/23 15:20:57 martin Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ip_h323_pxy.c,v 1.9 2004/03/28 09:00:57 martti Exp $"); #define IPF_H323_PROXY int ippr_h323_init __P((void)); -int ippr_h323_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_h323_fini __P((void)); +int ippr_h323_new __P((fr_info_t *, ap_session_t *, nat_t *)); void ippr_h323_del __P((ap_session_t *)); -int ippr_h323_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_h323_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_h323_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_h323_in __P((fr_info_t *, ap_session_t *, nat_t *)); -int ippr_h245_init __P((void)); -int ippr_h245_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_h245_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_h245_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_h245_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_h245_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_h245_in __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t h323_fr; -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_nat; -#endif -static int find_port __P((int, u_char *, int datlen, int *, u_short *)); +int h323_proxy_init = 0; + +static int find_port __P((int, caddr_t, int datlen, int *, u_short *)); static int find_port(ipaddr, data, datlen, off, port) int ipaddr; -unsigned char *data; +caddr_t data; int datlen, *off; unsigned short *port; { @@ -93,17 +92,30 @@ int ippr_h323_init() bzero((char *)&h323_fr, sizeof(h323_fr)); h323_fr.fr_ref = 1; h323_fr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&h323_fr.fr_lock, "H323 proxy rule lock"); + h323_proxy_init = 1; return 0; } -int ippr_h323_new(fin, ip, aps, nat) +void ippr_h323_fini() +{ + if (h323_proxy_init == 1) { + MUTEX_DESTROY(&h323_fr.fr_lock); + h323_proxy_init = 0; + } +} + + +int ippr_h323_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_data = NULL; aps->aps_psiz = 0; @@ -119,17 +131,18 @@ ap_session_t *aps; if (aps->aps_data) { for (i = 0, ipn = aps->aps_data; - i < (aps->aps_psiz / sizeof(ipnat_t)); + i < (aps->aps_psiz / sizeof(ipnat_t)); i++, ipn = (ipnat_t *)((char *)ipn + sizeof(*ipn))) { - /* + /* * Check the comment in ippr_h323_in() function, - * just above nat_ioctl() call. + * just above fr_nat_ioctl() call. * We are lucky here because this function is not * called with ipf_nat locked. */ - if (nat_ioctl((caddr_t)ipn, SIOCRMNAT, NAT_SYSSPACE| - NAT_LOCKHELD|FWRITE) == -1) { + if (fr_nat_ioctl((caddr_t)ipn, SIOCRMNAT, NAT_SYSSPACE| + NAT_LOCKHELD|FWRITE) == -1) { + /*EMPTY*/; /* log the error */ } } @@ -142,32 +155,23 @@ ap_session_t *aps; } -int ippr_h323_out(fin, ip, aps, nat) +int ippr_h323_in(fin, aps, nat) fr_info_t *fin; -ip_t *ip; -ap_session_t *aps; -nat_t *nat; -{ - return 0; -} - - -int ippr_h323_in(fin, ip, aps, nat) -fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { int ipaddr, off, datlen; unsigned short port; - unsigned char *data; + caddr_t data; tcphdr_t *tcp; - + ip_t *ip; + + ip = fin->fin_ip; tcp = (tcphdr_t *)fin->fin_dp; ipaddr = ip->ip_src.s_addr; - data = (unsigned char *)tcp + (tcp->th_off << 2); - datlen = fin->fin_dlen - (tcp->th_off << 2); + data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); + datlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); if (find_port(ipaddr, data, datlen, &off, &port) == 0) { ipnat_t *ipn; char *newarray; @@ -181,27 +185,27 @@ nat_t *nat; return -1; } ipn = (ipnat_t *)&newarray[aps->aps_psiz]; - bcopy(nat->nat_ptr, ipn, sizeof(ipnat_t)); - strncpy(ipn->in_plabel, "h245", APR_LABELLEN); + bcopy((caddr_t)nat->nat_ptr, (caddr_t)ipn, sizeof(ipnat_t)); + (void) strncpy(ipn->in_plabel, "h245", APR_LABELLEN); ipn->in_inip = nat->nat_inip.s_addr; ipn->in_inmsk = 0xffffffff; ipn->in_dport = htons(port); - /* - * we got a problem here. we need to call nat_ioctl() to add + /* + * we got a problem here. we need to call fr_nat_ioctl() to add * the h245 proxy rule, but since we already hold (READ locked) - * the nat table rwlock (ipf_nat), if we go into nat_ioctl(), + * the nat table rwlock (ipf_nat), if we go into fr_nat_ioctl(), * it will try to WRITE lock it. This will causing dead lock * on RTP. - * + * * The quick & dirty solution here is release the read lock, - * call nat_ioctl() and re-lock it. + * call fr_nat_ioctl() and re-lock it. * A (maybe better) solution is do a UPGRADE(), and instead - * of calling nat_ioctl(), we add the nat rule ourself. + * of calling fr_nat_ioctl(), we add the nat rule ourself. */ RWLOCK_EXIT(&ipf_nat); - if (nat_ioctl((caddr_t)ipn, SIOCADNAT, - NAT_SYSSPACE|FWRITE) == -1) { + if (fr_nat_ioctl((caddr_t)ipn, SIOCADNAT, + NAT_SYSSPACE|FWRITE) == -1) { READ_ENTER(&ipf_nat); return -1; } @@ -217,87 +221,80 @@ nat_t *nat; } -int ippr_h245_init() -{ - return 0; -} - - -int ippr_h245_new(fin, ip, aps, nat) +int ippr_h245_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_data = NULL; aps->aps_psiz = 0; return 0; } -int ippr_h245_out(fin, ip, aps, nat) +int ippr_h245_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { int ipaddr, off, datlen; - u_short port; - unsigned char *data; tcphdr_t *tcp; - + caddr_t data; + u_short port; + ip_t *ip; + + aps = aps; /* LINT */ + + ip = fin->fin_ip; tcp = (tcphdr_t *)fin->fin_dp; ipaddr = nat->nat_inip.s_addr; - data = (unsigned char *)tcp + (tcp->th_off << 2); - datlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2); + data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); + datlen = ip->ip_len - fin->fin_hlen - (TCP_OFF(tcp) << 2); if (find_port(ipaddr, data, datlen, &off, &port) == 0) { fr_info_t fi; - nat_t *ipn; + nat_t *nat2; /* port = htons(port); */ - ipn = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP, - ip->ip_src, ip->ip_dst, 1); - if (ipn == NULL) { + nat2 = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP, + ip->ip_src, ip->ip_dst); + if (nat2 == NULL) { struct ip newip; struct udphdr udp; - bcopy(ip, &newip, sizeof(newip)); + bcopy((caddr_t)ip, (caddr_t)&newip, sizeof(newip)); newip.ip_len = fin->fin_hlen + sizeof(udp); newip.ip_p = IPPROTO_UDP; newip.ip_src = nat->nat_inip; - bzero(&udp, sizeof(udp)); + bzero((char *)&udp, sizeof(udp)); udp.uh_sport = port; - bcopy(fin, &fi, sizeof(fi)); + bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi)); fi.fin_fi.fi_p = IPPROTO_UDP; fi.fin_data[0] = port; fi.fin_data[1] = 0; fi.fin_dp = (char *)&udp; - - ipn = nat_new(&fi, &newip, nat->nat_ptr, NULL, - IPN_UDP|FI_W_DPORT, NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_ptr->in_hits++; + + nat2 = nat_new(&fi, nat->nat_ptr, NULL, + NAT_SLAVE|IPN_UDP|SI_W_DPORT, + NAT_OUTBOUND); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_UDP); + nat_update(&fi, nat2, nat2->nat_ptr); + + nat2->nat_ptr->in_hits++; #ifdef IPFILTER_LOG - nat_log(ipn, (u_int)(nat->nat_ptr->in_redir)); + nat_log(nat2, (u_int)(nat->nat_ptr->in_redir)); #endif - bcopy((u_char*)&ip->ip_src.s_addr, + bcopy((caddr_t)&ip->ip_src.s_addr, data + off, 4); - bcopy((u_char*)&ipn->nat_outport, + bcopy((caddr_t)&nat2->nat_outport, data + off + 4, 2); } } } return 0; } - - -int ippr_h245_in(fin, ip, aps, nat) -fr_info_t *fin; -ip_t *ip; -ap_session_t *aps; -nat_t *nat; -{ - return 0; -} diff --git a/sys/netinet/ip_ipsec_pxy.c b/sys/netinet/ip_ipsec_pxy.c index 92d651ebc072..33388f5d6ac8 100644 --- a/sys/netinet/ip_ipsec_pxy.c +++ b/sys/netinet/ip_ipsec_pxy.c @@ -1,47 +1,83 @@ -/* $NetBSD: ip_ipsec_pxy.c,v 1.2 2002/04/01 16:47:46 jdolecek Exp $ */ +/* $NetBSD: ip_ipsec_pxy.c,v 1.3 2004/03/28 09:00:57 martti Exp $ */ /* + * Copyright (C) 2001-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * * Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT * code. * - * Id: ip_ipsec_pxy.c,v 1.1.2.10 2002/01/13 04:58:29 darrenr Exp + * Id: ip_ipsec_pxy.c,v 2.20.2.1 2004/03/14 13:10:48 darrenr Exp * */ -__KERNEL_RCSID(1, "$NetBSD: ip_ipsec_pxy.c,v 1.2 2002/04/01 16:47:46 jdolecek Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ip_ipsec_pxy.c,v 1.3 2004/03/28 09:00:57 martti Exp $"); #define IPF_IPSEC_PROXY int ippr_ipsec_init __P((void)); -int ippr_ipsec_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_ipsec_fini __P((void)); +int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *)); void ippr_ipsec_del __P((ap_session_t *)); -int ippr_ipsec_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *)); int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t ipsecfr; - - +static ipftq_t *ipsecnattqe; +static ipftq_t *ipsecstatetqe; static char ipsec_buffer[1500]; +int ipsec_proxy_init = 0; + /* - * RCMD application proxy initialization. + * IPSec application proxy initialization. */ int ippr_ipsec_init() { bzero((char *)&ipsecfr, sizeof(ipsecfr)); ipsecfr.fr_ref = 1; ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock"); + ipsec_proxy_init = 1; + + ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, 60); + if (ipsecnattqe == NULL) + return -1; + ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, 60); + if (ipsecstatetqe == NULL) { + fr_deletetimeoutqueue(ipsecnattqe); + ipsecnattqe = NULL; + return -1; + } + ipsecfr.fr_age[0] = 60; + ipsecfr.fr_age[1] = 60; return 0; } +void ippr_ipsec_fini() +{ + if (ipsecnattqe != NULL) + fr_deletetimeoutqueue(ipsecnattqe); + ipsecnattqe = NULL; + if (ipsecstatetqe != NULL) + fr_deletetimeoutqueue(ipsecstatetqe); + ipsecstatetqe = NULL; + + if (ipsec_proxy_init == 1) { + MUTEX_DESTROY(&ipsecfr.fr_lock); + ipsec_proxy_init = 0; + } +} + + /* * Setup for a new IPSEC proxy. */ -int ippr_ipsec_new(fin, ip, aps, nat) +int ippr_ipsec_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { @@ -51,38 +87,20 @@ nat_t *nat; char *ptr; int p, off, dlen; mb_t *m; + ip_t *ip; bzero(ipsec_buffer, sizeof(ipsec_buffer)); off = fin->fin_hlen + sizeof(udphdr_t); -#ifdef _KERNEL -# if SOLARIS - m = fin->fin_qfm; + ip = fin->fin_ip; + m = fin->fin_m; - dlen = msgdsize(m) - off; + dlen = M_LEN(m) - off; if (dlen < 16) return -1; - copyout_mblk(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); -# else - m = *(mb_t **)fin->fin_mp; - dlen = mbufchainlen(m) - off; - if (dlen < 16) - return -1; - m_copydata(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); -# endif -#else - m = *(mb_t **)fin->fin_mp; - dlen = ip->ip_len - off; - ptr = (char *)m; - ptr += off; - bcopy(ptr, ipsec_buffer, MIN(sizeof(ipsec_buffer), dlen)); -#endif + COPYDATA(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); - /* - * Because _new() gets called from nat_new(), ipf_nat is held with a - * write lock so pass rw=1 to nat_outlookup(). - */ if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip, - ip->ip_dst, 1) != NULL) + ip->ip_dst) != NULL) return -1; aps->aps_psiz = sizeof(*ipsec); @@ -99,20 +117,23 @@ nat_t *nat; * describe ESP but UDP instead. */ ipn = &ipsec->ipsc_rule; - ipn->in_ifp = fin->fin_ifp; + ipn->in_tqehead[0] = ipsecnattqe; + ipn->in_tqehead[1] = ipsecnattqe; + ipn->in_ifps[0] = fin->fin_ifp; ipn->in_apr = NULL; ipn->in_use = 1; ipn->in_hits = 1; - ipn->in_nip = ntohl(nat->nat_outip.s_addr); + ipn->in_nip = nat->nat_outip.s_addr; ipn->in_ippip = 1; ipn->in_inip = nat->nat_inip.s_addr; ipn->in_inmsk = 0xffffffff; - ipn->in_outip = nat->nat_outip.s_addr; - ipn->in_outmsk = 0xffffffff; + ipn->in_outip = fin->fin_saddr; + ipn->in_outmsk = nat->nat_outip.s_addr; ipn->in_srcip = fin->fin_saddr; ipn->in_srcmsk = 0xffffffff; ipn->in_redir = NAT_MAP; - bcopy(nat->nat_ptr->in_ifname, ipn->in_ifname, sizeof(ipn->in_ifname)); + bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0], + sizeof(ipn->in_ifnames[0])); ipn->in_p = IPPROTO_ESP; bcopy((char *)fin, (char *)&fi, sizeof(fi)); @@ -122,12 +143,13 @@ nat_t *nat; fi.fin_data[1] = 0; p = ip->ip_p; ip->ip_p = IPPROTO_ESP; - fi.fin_fl &= ~FI_TCPUDP; + fi.fin_flx &= ~FI_TCPUDP; + fi.fin_flx |= FI_IGNORE; ptr = ipsec_buffer; - bcopy(ptr, ipsec->ipsc_icookie, sizeof(ipsec_cookie_t)); + bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t)); ptr += sizeof(ipsec_cookie_t); - bcopy(ptr, ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t)); + bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t)); /* * The responder cookie should only be non-zero if the initiator * cookie is non-zero. Therefore, it is safe to assume(!) that the @@ -135,76 +157,95 @@ nat_t *nat; */ if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0) ipsec->ipsc_rckset = 1; - else - nat->nat_age = 60; /* 30 seconds */ - ipsec->ipsc_nat = nat_new(&fi, ip, ipn, &ipsec->ipsc_nat, FI_IGNOREPKT, - NAT_OUTBOUND); + ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat, + NAT_SLAVE|SI_WILDP, NAT_OUTBOUND); if (ipsec->ipsc_nat != NULL) { + (void) nat_proto(&fi, ipsec->ipsc_nat, 0); + nat_update(&fi, ipsec->ipsc_nat, ipn); + fi.fin_data[0] = 0; fi.fin_data[1] = 0; - ipsec->ipsc_state = fr_addstate(ip, &fi, &ipsec->ipsc_state, - FI_IGNOREPKT|FI_NORULE); + ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state, + SI_WILDP); } - ip->ip_p = p; + ip->ip_p = p & 0xff; return 0; } /* - * For outgoing IKE packets. refresh timeouts for NAT & stat entries, if + * For outgoing IKE packets. refresh timeouts for NAT & state entries, if * we can. If they have disappeared, recreate them. */ -int ippr_ipsec_out(fin, ip, aps, nat) +int ippr_ipsec_inout(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { ipsec_pxy_t *ipsec; fr_info_t fi; + ip_t *ip; int p; - bcopy((char *)fin, (char *)&fi, sizeof(fi)); - fi.fin_fi.fi_p = IPPROTO_ESP; - fi.fin_fr = &ipsecfr; - fi.fin_data[0] = 0; - fi.fin_data[1] = 0; - p = ip->ip_p; - ip->ip_p = IPPROTO_ESP; - fi.fin_fl &= ~FI_TCPUDP; + if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) + return 0; + + if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) + return 0; ipsec = aps->aps_data; + if (ipsec != NULL) { + ip = fin->fin_ip; + p = ip->ip_p; + + if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) { + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_fi.fi_p = IPPROTO_ESP; + fi.fin_fr = &ipsecfr; + fi.fin_data[0] = 0; + fi.fin_data[1] = 0; + ip->ip_p = IPPROTO_ESP; + fi.fin_flx &= ~FI_TCPUDP; + fi.fin_flx |= FI_IGNORE; + } + /* * Update NAT timeout/create NAT if missing. */ - if (ipsec->ipsc_rckset == 0) - nat->nat_age = 60; /* 30 seconds */ if (ipsec->ipsc_nat != NULL) - ipsec->ipsc_nat->nat_age = nat->nat_age; - else - ipsec->ipsc_nat = nat_new(&fi, ip, &ipsec->ipsc_rule, + fr_queueback(&ipsec->ipsc_nat->nat_tqe); + else { + ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule, &ipsec->ipsc_nat, - FI_IGNOREPKT, NAT_OUTBOUND); + NAT_SLAVE|SI_WILDP, + nat->nat_dir); + if (ipsec->ipsc_nat != NULL) { + (void) nat_proto(&fi, ipsec->ipsc_nat, 0); + nat_update(&fi, ipsec->ipsc_nat, + &ipsec->ipsc_rule); + } + } /* * Update state timeout/create state if missing. */ READ_ENTER(&ipf_state); if (ipsec->ipsc_state != NULL) { - ipsec->ipsc_state->is_age = nat->nat_age; + fr_queueback(&ipsec->ipsc_state->is_sti); + ipsec->ipsc_state->is_die = nat->nat_age; RWLOCK_EXIT(&ipf_state); } else { RWLOCK_EXIT(&ipf_state); fi.fin_data[0] = 0; fi.fin_data[1] = 0; - ipsec->ipsc_state = fr_addstate(ip, &fi, + ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state, - FI_IGNOREPKT|FI_NORULE); + SI_WILDP); } + ip->ip_p = p; } - ip->ip_p = p; return 0; } @@ -225,24 +266,15 @@ nat_t *nat; mb_t *m; int off; - if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_fl & FI_FRAG)) + nat = nat; /* LINT */ + + if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG)) return -1; ipsec = aps->aps_data; off = fin->fin_hlen + sizeof(udphdr_t); -#ifdef _KERNEL -# if SOLARIS - m = fin->fin_qfm; - - copyout_mblk(m, off, sizeof(cookies), (char *)cookies); -# else - m = *(mb_t **)fin->fin_mp; - m_copydata(m, off, sizeof(cookies), (char *)cookies); -# endif -#else - m = *(mb_t **)fin->fin_mp; - bcopy((char *)m + off, cookies, sizeof(cookies)); -#endif + m = fin->fin_m; + COPYDATA(m, off, sizeof(cookies), (char *)cookies); if ((cookies[0] != ipsec->ipsc_icookie[0]) || (cookies[1] != ipsec->ipsc_icookie[1])) @@ -250,7 +282,6 @@ nat_t *nat; if (ipsec->ipsc_rckset == 0) { if ((cookies[2]|cookies[3]) == 0) { - nat->nat_age = 60; /* 30 seconds */ return 0; } ipsec->ipsc_rckset = 1; @@ -282,13 +313,18 @@ ap_session_t *aps; * deleted ASAP. */ if (ipsec->ipsc_nat != NULL) { - ipsec->ipsc_nat->nat_age = 1; + ipsec->ipsc_nat->nat_age = fr_ticks + 1; ipsec->ipsc_nat->nat_ptr = NULL; + ipsec->ipsc_nat->nat_me = NULL; + fr_queuefront(&ipsec->ipsc_nat->nat_tqe); } READ_ENTER(&ipf_state); - if (ipsec->ipsc_state != NULL) - ipsec->ipsc_state->is_age = 1; + if (ipsec->ipsc_state != NULL) { + ipsec->ipsc_state->is_die = fr_ticks + 1; + ipsec->ipsc_state->is_me = NULL; + fr_queuefront(&ipsec->ipsc_state->is_sti); + } RWLOCK_EXIT(&ipf_state); ipsec->ipsc_state = NULL; diff --git a/sys/netinet/ip_log.c b/sys/netinet/ip_log.c index 945f239492f2..33a7de96344b 100644 --- a/sys/netinet/ip_log.c +++ b/sys/netinet/ip_log.c @@ -1,147 +1,180 @@ -/* $NetBSD: ip_log.c,v 1.23 2002/09/25 06:43:21 martti Exp $ */ +/* $NetBSD: ip_log.c,v 1.24 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1997-2001 by Darren Reed. + * Copyright (C) 1997-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * Id: ip_log.c,v 2.5.2.19 2002/04/25 16:32:48 darrenr Exp + * Id: ip_log.c,v 2.75.2.3 2004/03/23 12:03:45 darrenr Exp */ #include -__KERNEL_RCSID(0, "$NetBSD: ip_log.c,v 1.23 2002/09/25 06:43:21 martti Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_log.c,v 1.24 2004/03/28 09:00:57 martti Exp $"); #include -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ defined(_KERNEL) # include "opt_ipfilter_log.h" #endif -#ifdef __FreeBSD__ -# if defined(_KERNEL) && !defined(IPFILTER_LKM) +#if defined(__FreeBSD__) && !defined(IPFILTER_LKM) +# if defined(_KERNEL) # if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) # include "opt_ipfilter.h" # endif # else -# ifdef KLD_MODULE -# ifndef __FreeBSD_cc_version -# include -# else -# if __FreeBSD_cc_version < 430000 -# include -# endif -# endif -# endif +# include # endif #endif -#ifdef IPFILTER_LOG -# ifndef SOLARIS -# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#ifndef SOLARIS +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif +#include +#include +#include +#ifndef _KERNEL +# include +# include +# include +# include +# define _KERNEL +# define KERNEL +# ifdef __OpenBSD__ +struct file; # endif -# ifndef _KERNEL -# include -# include -# include -# include +# include +# undef _KERNEL +# undef KERNEL +#endif +#if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include +# include +#else +# include +#endif +#include +#if defined(_KERNEL) +# include +# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) +# include # endif -# include -# include -# include -# if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include -# include +#endif /* _KERNEL */ +#if !SOLARIS && !defined(__hpux) && !defined(linux) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) +# include # else -# include +# include # endif -# include -# if defined(_KERNEL) -# include -# endif -# if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) -# include -# else -# include -# endif -# include -# else +# include +#else +# if !defined(__hpux) && defined(_KERNEL) # include # include -# include -# ifdef _KERNEL -# include -# include -# include -# include -# include -# endif -# endif -# include -# include - -# include -# ifdef sun -# include -# endif -# if __FreeBSD_version >= 300000 -# include -# endif -# include -# include -# ifdef __sgi -# define _KMEMUSER # include -# ifdef IFF_DRVRLOCK /* IRIX6 */ -# include -# endif +# include +# include +# include +# include +# include +# include +# endif /* !__hpux */ +#endif /* !SOLARIS && !__hpux */ +#if !defined(linux) +# include +#endif +#include + +#include +#ifdef sun +# include +#endif +#if __FreeBSD_version >= 300000 +# include +#endif +#include +#include +#ifdef __sgi +# include +# ifdef IFF_DRVRLOCK /* IRIX6 */ +# include # endif -# if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ -# include -# endif -# include -# include -# include -# include -# include +#endif +#if !defined(__hpux) && !defined(linux) && \ + !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ +# include +#endif +#include +#include +#include +#include +#include +#ifdef USE_INET6 +# include +#endif +#if !defined(linux) # include -# ifndef _KERNEL -# include -# endif -# include "netinet/ip_compat.h" -# include -# include "netinet/ip_fil.h" -# if (__FreeBSD_version >= 300000) -# include -# endif +#endif +#ifndef _KERNEL +# include +#endif +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_auth.h" +#if (__FreeBSD_version >= 300000) || defined(__NetBSD__) +# include +#endif +/* END OF INCLUDES */ -# ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -# endif -# ifdef IPFILTER_LOGSIZE -# undef IPLLOGSIZE -# define IPLLOGSIZE IPFILTER_LOGSIZE -# endif +#ifdef IPFILTER_LOG +# if defined(IPL_SELECT) +# include +# include +# define READ_COLLISION 0x001 -# if SOLARIS || defined(__sgi) -extern kmutex_t ipl_mutex; -# if SOLARIS +iplog_select_t iplog_ss[IPL_LOGMAX+1]; + +extern int selwait; +# endif /* IPL_SELECT */ + +# if defined(linux) && defined(_KERNEL) +wait_queue_head_t iplh_linux[IPL_LOGSIZE]; +# endif +# if SOLARIS extern kcondvar_t iplwait; -# endif # endif -iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; -int iplused[IPL_LOGMAX+1]; -static fr_info_t iplcrc[IPL_LOGMAX+1]; +iplog_t **iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE]; +int iplused[IPL_LOGSIZE]; +static fr_info_t iplcrc[IPL_LOGSIZE]; +int ipl_suppress = 1; +int ipl_buffer_sz; +int ipl_logmax = IPL_LOGMAX; +int ipl_logall = 0; +int ipl_log_init = 0; +int ipl_magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE, + IPL_MAGIC, IPL_MAGIC, IPL_MAGIC, + IPL_MAGIC, IPL_MAGIC }; -/* - * Initialise log buffers & pointers. Also iniialised the CRC to a local - * secret for use in calculating the "last log checksum". - */ -void ipflog_init() +/* ------------------------------------------------------------------------ */ +/* Function: fr_loginit */ +/* Returns: int - 0 == success (always returned) */ +/* Parameters: Nil */ +/* */ +/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ +/* secret for use in calculating the "last log checksum". */ +/* ------------------------------------------------------------------------ */ +int fr_loginit() { int i; @@ -151,40 +184,88 @@ void ipflog_init() iplh[i] = &iplt[i]; iplused[i] = 0; bzero((char *)&iplcrc[i], sizeof(iplcrc[i])); +# ifdef IPL_SELECT + iplog_ss[i].read_waiter = 0; + iplog_ss[i].state = 0; +# endif +# if defined(linux) && defined(_KERNEL) + init_waitqueue_head(iplh_linux + i); +# endif } + +# if SOLARIS && defined(_KERNEL) + cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL); +# endif + MUTEX_INIT(&ipl_mutex, "ipf log mutex"); + + ipl_log_init = 1; + + return 0; } -/* - * ipflog - * Create a log record for a packet given that it has been triggered by a - * rule (or the default setting). Calculate the transport protocol header - * size using predetermined size of a couple of popular protocols and thus - * how much data to copy into the log, including part of the data body if - * requested. - */ -int ipflog(flags, ip, fin, m) -u_int flags; -ip_t *ip; -fr_info_t *fin; -mb_t *m; +/* ------------------------------------------------------------------------ */ +/* Function: fr_logunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Clean up any log data that has accumulated without being read. */ +/* ------------------------------------------------------------------------ */ +void fr_logunload() { - ipflog_t ipfl; - register size_t mlen, hlen; + int i; + + if (ipl_log_init == 0) + return; + + for (i = IPL_LOGMAX; i >= 0; i--) + (void) ipflog_clear(i); + +# if SOLARIS && defined(_KERNEL) + cv_destroy(&iplwait); +# endif + MUTEX_DESTROY(&ipl_mutex); + + ipl_log_init = 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipflog */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: fin(I) - pointer to packet information */ +/* flags(I) - flags from filter rules */ +/* */ +/* Create a log record for a packet given that it has been triggered by a */ +/* rule (or the default setting). Calculate the transport protocol header */ +/* size using predetermined size of a couple of popular protocols and thus */ +/* how much data to copy into the log, including part of the data body if */ +/* requested. */ +/* ------------------------------------------------------------------------ */ +int ipflog(fin, flags) +fr_info_t *fin; +u_int flags; +{ + register size_t hlen; + int types[2], mlen; size_t sizes[2]; void *ptrs[2]; - int types[2]; + ipflog_t ipfl; u_char p; -# if SOLARIS && defined(_KERNEL) - ill_t *ifp = fin->fin_ifp; + mb_t *m; +# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) + qif_t *ifp; # else - struct ifnet *ifp = fin->fin_ifp; -# endif + struct ifnet *ifp; +# endif /* SOLARIS || __hpux */ + ipfl.fl_nattag.ipt_num[0] = 0; + m = fin->fin_m; + ifp = fin->fin_ifp; + hlen = fin->fin_hlen; /* * calculate header size. */ - hlen = fin->fin_hlen; if (fin->fin_off == 0) { p = fin->fin_fi.fi_p; if (p == IPPROTO_TCP) @@ -195,7 +276,7 @@ mb_t *m; struct icmp *icmp; icmp = (struct icmp *)fin->fin_dp; - + /* * For ICMP, if the packet is an error packet, also * include the information about the packet which @@ -217,51 +298,90 @@ mb_t *m; break; } } +# ifdef USE_INET6 + else if (p == IPPROTO_ICMPV6) { + struct icmp6_hdr *icmp; + + icmp = (struct icmp6_hdr *)fin->fin_dp; + + /* + * For ICMPV6, if the packet is an error packet, also + * include the information about the packet which + * caused the error. + */ + if (icmp->icmp6_type < 128) { + hlen += MIN(sizeof(struct icmp6_hdr) + 8, + fin->fin_dlen); + } else { + hlen += MIN(sizeof(struct icmp6_hdr), + fin->fin_dlen); + } + } +# endif } /* * Get the interface number and name to which this packet is * currently associated. */ - bzero((char *)ipfl.fl_ifname, sizeof(ipfl.fl_ifname)); -# if SOLARIS && defined(_KERNEL) - ipfl.fl_unit = (u_char)ifp->ill_ppa; - bcopy(ifp->ill_name, ipfl.fl_ifname, - MIN(ifp->ill_name_length, sizeof(ipfl.fl_ifname))); - mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0; +# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) + ipfl.fl_unit = (u_char)ifp->qf_ppa; + COPYIFNAME(ifp, ipfl.fl_ifname); # else # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ); + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + COPYIFNAME(ifp, ipfl.fl_ifname); # else ipfl.fl_unit = (u_char)ifp->if_unit; - strncpy(ipfl.fl_ifname, ifp->if_name, MIN(sizeof(ipfl.fl_ifname), - sizeof(ifp->if_name))); +# if defined(_KERNEL) + if ((ipfl.fl_ifname[0] = ifp->if_name[0])) + if ((ipfl.fl_ifname[1] = ifp->if_name[1])) + if ((ipfl.fl_ifname[2] = ifp->if_name[2])) + ipfl.fl_ifname[3] = ifp->if_name[3]; +# else + (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); + ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; +# endif # endif - mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0; -# endif +# endif /* __hpux || SOLARIS */ + mlen = fin->fin_plen - hlen; + if (!ipl_logall) { + mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; + } else if ((flags & FR_LOGBODY) == 0) { + mlen = 0; + } + if (mlen < 0) + mlen = 0; ipfl.fl_plen = (u_char)mlen; ipfl.fl_hlen = (u_char)hlen; ipfl.fl_rule = fin->fin_rule; - ipfl.fl_group = fin->fin_group; - if (fin->fin_fr != NULL) + (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); + if (fin->fin_fr != NULL) { ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; - else + ipfl.fl_logtag = fin->fin_fr->fr_logtag; + } else { ipfl.fl_loglevel = 0xffff; + ipfl.fl_logtag = FR_NOLOGTAG; + } + if (fin->fin_nattag != NULL) + bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, + sizeof(ipfl.fl_nattag)); ipfl.fl_flags = flags; ipfl.fl_dir = fin->fin_out; + ipfl.fl_lflags = fin->fin_flx; ptrs[0] = (void *)&ipfl; sizes[0] = sizeof(ipfl); types[0] = 0; -# if SOLARIS && defined(_KERNEL) +# if defined(MENTAT) && defined(_KERNEL) /* * Are we copied from the mblk or an aligned array ? */ - if (ip == (ip_t *)m->b_rptr) { + if (fin->fin_ip == (ip_t *)m->b_rptr) { ptrs[1] = m; sizes[1] = hlen + mlen; types[1] = 1; } else { - ptrs[1] = ip; + ptrs[1] = fin->fin_ip; sizes[1] = hlen + mlen; types[1] = 0; } @@ -269,14 +389,25 @@ mb_t *m; ptrs[1] = m; sizes[1] = hlen + mlen; types[1] = 1; -# endif +# endif /* MENTAT */ return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); } -/* - * ipllog - */ +/* ------------------------------------------------------------------------ */ +/* Function: ipllog */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: dev(I) - device that owns this log record */ +/* fin(I) - pointer to packet information */ +/* items(I) - array of pointers to log data */ +/* itemsz(I) - array of size of valid memory pointed to */ +/* types(I) - type of data pointed to by items pointers */ +/* cnt(I) - number of elements in arrays items/itemsz/types */ +/* */ +/* Takes an array of parameters and constructs one record to include the */ +/* miscellaneous packet information, as well as packet data, for reading */ +/* from the log device. */ +/* ------------------------------------------------------------------------ */ int ipllog(dev, fin, items, itemsz, types, cnt) int dev; fr_info_t *fin; @@ -288,29 +419,32 @@ int *types, cnt; iplog_t *ipl; size_t len; int i; - + /* * Check to see if this log record has a CRC which matches the last * record logged. If it does, just up the count on the previous one * rather than create a new one. */ - MUTEX_ENTER(&ipl_mutex); - if (fin != NULL) { - if ((ipll[dev] != NULL) && - bcmp((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE) == 0) { - ipll[dev]->ipl_count++; - MUTEX_EXIT(&ipl_mutex); - return 1; - } - bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE); - } else - bzero((char *)&iplcrc[dev], FI_LCSIZE); - MUTEX_EXIT(&ipl_mutex); + if (ipl_suppress) { + MUTEX_ENTER(&ipl_mutex); + if ((fin != NULL) && (fin->fin_off == 0)) { + if ((ipll[dev] != NULL) && + bcmp((char *)fin, (char *)&iplcrc[dev], + FI_LCSIZE) == 0) { + ipll[dev]->ipl_count++; + MUTEX_EXIT(&ipl_mutex); + return 0; + } + bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE); + } else + bzero((char *)&iplcrc[dev], FI_CSIZE); + MUTEX_EXIT(&ipl_mutex); + } /* * Get the total amount of data to be logged. */ - for (i = 0, len = IPLOG_SIZE; i < cnt; i++) + for (i = 0, len = sizeof(iplog_t); i < cnt; i++) len += itemsz[i]; /* @@ -318,13 +452,13 @@ int *types, cnt; * allocate that much. */ KMALLOCS(buf, caddr_t, len); - if (!buf) - return 0; + if (buf == NULL) + return -1; MUTEX_ENTER(&ipl_mutex); - if ((iplused[dev] + len) > IPLLOGSIZE) { + if ((iplused[dev] + len) > IPFILTER_LOGSIZE) { MUTEX_EXIT(&ipl_mutex); KFREES(buf, len); - return 0; + return -1; } iplused[dev] += len; MUTEX_EXIT(&ipl_mutex); @@ -334,36 +468,26 @@ int *types, cnt; * amount of space we're going to use. */ ipl = (iplog_t *)buf; - ipl->ipl_magic = IPL_MAGIC; + ipl->ipl_magic = ipl_magic[dev]; ipl->ipl_count = 1; ipl->ipl_next = NULL; ipl->ipl_dsize = len; -# ifdef _KERNEL -# if SOLARIS || defined(sun) - uniqtime(&ipl->ipl_time); -# else -# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) - microtime(&ipl->ipl_time); -# endif -# endif -# else - ipl->ipl_time.tv_sec = 0; - ipl->ipl_time.tv_usec = 0; -# endif +#ifdef _KERNEL + GETKTIME(&ipl->ipl_sec); +#else + ipl->ipl_sec = 0; + ipl->ipl_usec = 0; +#endif /* * Loop through all the items to be logged, copying each one to the * buffer. Use bcopy for normal data or the mb_t copyout routine. */ - for (i = 0, s = buf + IPLOG_SIZE; i < cnt; i++) { - if (types[i] == 0) + for (i = 0, s = buf + sizeof(*ipl); i < cnt; i++) { + if (types[i] == 0) { bcopy(items[i], s, itemsz[i]); - else if (types[i] == 1) { -# if SOLARIS && defined(_KERNEL) - copyout_mblk(items[i], 0, itemsz[i], s); -# else - m_copydata(items[i], 0, itemsz[i], s); -# endif + } else if (types[i] == 1) { + COPYDATA(items[i], 0, itemsz[i], s); } s += itemsz[i]; } @@ -371,17 +495,37 @@ int *types, cnt; ipll[dev] = ipl; *iplh[dev] = ipl; iplh[dev] = &ipl->ipl_next; + + /* + * Now that the log record has been completed and added to the queue, + * wake up any listeners who may want to read it. + */ # if SOLARIS && defined(_KERNEL) cv_signal(&iplwait); - mutex_exit(&ipl_mutex); + MUTEX_EXIT(&ipl_mutex); # else MUTEX_EXIT(&ipl_mutex); - WAKEUP(&iplh[dev]); + WAKEUP(iplh,dev); # endif - return 1; +# ifdef IPL_SELECT + iplog_input_ready(dev); +# endif + return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: ipflog_read */ +/* Returns: int - 0 == success, else error value. */ +/* Parameters: unit(I) - device we are reading from */ +/* uio(O) - pointer to information about where to store data */ +/* */ +/* Called to handle a read on an IPFilter device. Returns only complete */ +/* log messages - will not partially copy a log record out to userland. */ +/* */ +/* NOTE: This function will block and wait for a signal to return data if */ +/* there is none present. Asynchronous I/O is not implemented. */ +/* ------------------------------------------------------------------------ */ int ipflog_read(unit, uio) minor_t unit; struct uio *uio; @@ -389,7 +533,7 @@ struct uio *uio; size_t dlen, copied; int error = 0; iplog_t *ipl; -# if defined(_KERNEL) && !SOLARIS +# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) int s; # endif @@ -399,11 +543,12 @@ struct uio *uio; */ if (IPL_LOGMAX < unit) return ENXIO; - if (!uio->uio_resid) + if (uio->uio_resid == 0) return 0; - if (uio->uio_resid < IPLOG_SIZE) + if ((uio->uio_resid < sizeof(iplog_t)) || + (uio->uio_resid > IPFILTER_LOGSIZE)) return EINVAL; - + /* * Lock the log so we can snapshot the variables. Wait for a signal * if the log is empty. @@ -411,28 +556,50 @@ struct uio *uio; SPL_NET(s); MUTEX_ENTER(&ipl_mutex); - while (!iplused[unit] || !iplt[unit]) { + while (iplt[unit] == NULL) { # if SOLARIS && defined(_KERNEL) - if (!cv_wait_sig(&iplwait, &ipl_mutex)) { + if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) { MUTEX_EXIT(&ipl_mutex); return EINTR; } # else - MUTEX_EXIT(&ipl_mutex); - error = SLEEP(&iplh[unit], "ipl sleep"); - if (error) { - SPL_X(s); - return error; +# if defined(__hpux) && defined(_KERNEL) + lock_t *l; + +# ifdef IPL_SELECT + if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { + /* this is no blocking system call */ + MUTEX_EXIT(&ipl_mutex); + return 0; } +# endif + + MUTEX_EXIT(&ipl_mutex); + l = get_sleep_lock(&iplh[unit]); + error = sleep(&iplh[unit], PZERO+1); + spinunlock(l); +# else +# if defined(__osf__) && defined(_KERNEL) + error = mpsleep(&iplh[unit], PSUSP|PCATCH, "iplread", 0, + &ipl_mutex, MS_LOCK_SIMPLE); +# else + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); + error = SLEEP(unit + iplh, "ipl sleep"); +# endif /* __osf__ */ +# endif /* __hpux */ + if (error) + return error; + SPL_NET(s); MUTEX_ENTER(&ipl_mutex); # endif /* SOLARIS */ } -# if BSD >= 199306 || defined(__FreeBSD__) +# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__) uio->uio_rw = UIO_READ; # endif - for (copied = 0; (ipl = iplt[unit]); copied += dlen) { + for (copied = 0; (ipl = iplt[unit]) != NULL; copied += dlen) { dlen = ipl->ipl_dsize; if (dlen > uio->uio_resid) break; @@ -442,15 +609,19 @@ struct uio *uio; iplt[unit] = ipl->ipl_next; iplused[unit] -= dlen; MUTEX_EXIT(&ipl_mutex); + SPL_X(s); error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); - MUTEX_ENTER(&ipl_mutex); if (error) { + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); ipl->ipl_next = iplt[unit]; iplt[unit] = ipl; iplused[unit] += dlen; break; } + MUTEX_ENTER(&ipl_mutex); KFREES((caddr_t)ipl, dlen); + SPL_NET(s); } if (!iplt[unit]) { iplused[unit] = 0; @@ -464,6 +635,13 @@ struct uio *uio; } +/* ------------------------------------------------------------------------ */ +/* Function: ipflog_clear */ +/* Returns: int - number of log bytes cleared. */ +/* Parameters: unit(I) - device we are reading from */ +/* */ +/* Deletes all queued up log records for a given output device. */ +/* ------------------------------------------------------------------------ */ int ipflog_clear(unit) minor_t unit; { @@ -471,7 +649,7 @@ minor_t unit; int used; MUTEX_ENTER(&ipl_mutex); - while ((ipl = iplt[unit])) { + while ((ipl = iplt[unit]) != NULL) { iplt[unit] = ipl->ipl_next; KFREES((caddr_t)ipl, ipl->ipl_dsize); } @@ -479,7 +657,7 @@ minor_t unit; ipll[unit] = NULL; used = iplused[unit]; iplused[unit] = 0; - bzero((char *)&iplcrc[unit], FI_LCSIZE); + bzero((char *)&iplcrc[unit], FI_CSIZE); MUTEX_EXIT(&ipl_mutex); return used; } diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c index 37e442c79d46..dfbc7a841b8d 100644 --- a/sys/netinet/ip_nat.c +++ b/sys/netinet/ip_nat.c @@ -1,18 +1,15 @@ -/* $NetBSD: ip_nat.c,v 1.55 2003/12/04 15:32:01 christos Exp $ */ +/* $NetBSD: ip_nat.c,v 1.56 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1995-2001 by Darren Reed. + * Copyright (C) 1995-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. - * - * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com) */ -#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) -#define _KERNEL -#endif - -#ifdef __sgi -# include +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include #include @@ -23,30 +20,35 @@ defined(_KERNEL) # include "opt_ipfilter_log.h" #endif -#if !defined(_KERNEL) && !defined(KERNEL) +#if !defined(_KERNEL) # include # include # include +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include # include #else # include #endif #include -#ifndef linux +#if !defined(linux) # include #endif #include -#if defined(_KERNEL) && !defined(linux) +#if defined(_KERNEL) # include -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# if !defined(__SVR4) && !defined(__svr4__) # include # endif -#else +#endif +#if defined(__SVR4) || defined(__svr4__) # include # include # ifdef _KERNEL @@ -73,22 +75,14 @@ #include #include -#ifdef __sgi -# ifdef IFF_DRVRLOCK /* IRIX6 */ -#include -#include -# endif -#endif - #ifdef RFC1825 # include # include extern struct ifnet vpnif; #endif -#ifndef linux +#if !defined(linux) # include -# include #endif #include #include @@ -100,66 +94,120 @@ extern struct ifnet vpnif; #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" +#ifdef IPFILTER_SYNC +#include "netinet/ip_sync.h" +#endif #if (__FreeBSD_version >= 300000) # include #endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif +/* END OF INCLUDES */ + #undef SOCKADDR_IN #define SOCKADDR_IN struct sockaddr_in #if !defined(lint) -#if defined(__NetBSD__) -#include -__KERNEL_RCSID(0, "$NetBSD: ip_nat.c,v 1.55 2003/12/04 15:32:01 christos Exp $"); -#else static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)Id: ip_nat.c,v 2.37.2.70 2002/08/28 12:45:48 darrenr Exp"; -#endif +static const char rcsid[] = "@(#)Id: ip_nat.c,v 2.195.2.6 2004/03/23 15:57:32 darrenr Exp"; #endif + +/* ======================================================================== */ +/* How the NAT is organised and works. */ +/* */ +/* Inside (interface y) NAT Outside (interface x) */ +/* -------------------- -+- ------------------------------------- */ +/* Packet going | out, processsed by fr_checknatout() for x */ +/* ------------> | ------------> */ +/* src=10.1.1.1 | src=192.1.1.1 */ +/* | */ +/* | in, processed by fr_checknatin() for x */ +/* <------------ | <------------ */ +/* dst=10.1.1.1 | dst=192.1.1.1 */ +/* -------------------- -+- ------------------------------------- */ +/* fr_checknatout() - changes ip_src and if required, sport */ +/* - creates a new mapping, if required. */ +/* fr_checknatin() - changes ip_dst and if required, dport */ +/* */ +/* In the NAT table, internal source is recorded as "in" and externally */ +/* seen as "out". */ +/* ======================================================================== */ + + nat_t **nat_table[2] = { NULL, NULL }, *nat_instances = NULL; ipnat_t *nat_list = NULL; +u_int ipf_nattable_max = NAT_TABLE_MAX; u_int ipf_nattable_sz = NAT_TABLE_SZ; u_int ipf_natrules_sz = NAT_SIZE; u_int ipf_rdrrules_sz = RDR_SIZE; u_int ipf_hostmap_sz = HOSTMAP_SIZE; +u_int fr_nat_maxbucket = 0, + fr_nat_maxbucket_reset = 1; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; ipnat_t **nat_rules = NULL; ipnat_t **rdr_rules = NULL; hostmap_t **maptable = NULL; +ipftq_t nat_tqb[IPF_TCP_NSTATES]; +ipftq_t nat_udptq; +ipftq_t nat_icmptq; +ipftq_t nat_iptq; +ipftq_t *nat_utqe = NULL; +#ifdef IPFILTER_LOG +int nat_logging = 1; +#else +int nat_logging = 0; +#endif u_long fr_defnatage = DEF_NAT_AGE, fr_defnaticmpage = 6; /* 3 seconds */ natstat_t nat_stats; int fr_nat_lock = 0; -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_t ipf_rw; -extern KRWLOCK_T ipf_nat; +int fr_nat_init = 0; +#if SOLARIS +extern int pfil_delayed_copy; #endif static int nat_flushtable __P((void)); +static int nat_clearlist __P((void)); static void nat_addnat __P((struct ipnat *)); static void nat_addrdr __P((struct ipnat *)); -static void nat_delete __P((struct nat *)); +static void nat_delete __P((struct nat *, int)); static void nat_delrdr __P((struct ipnat *)); static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t)); -static void nat_tabmove __P((fr_info_t *, nat_t *)); -static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); +static void nat_tabmove __P((nat_t *)); +static int nat_match __P((fr_info_t *, ipnat_t *)); +static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); +static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, - struct in_addr)); + struct in_addr, struct in_addr, u_32_t)); static void nat_hostmapdel __P((struct hostmap *)); -static void tcp_mss_clamp __P((tcphdr_t *, uint32_t, fr_info_t *, u_short *)); +static INLINE int nat_icmpquerytype4 __P((int)); +static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int)); +static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int)); +static INLINE int nat_icmperrortype4 __P((int)); +static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, + tcphdr_t *, nat_t **, int)); +static INLINE void nat_resolverule __P((ipnat_t *)); +static nat_t *fr_natclone __P((fr_info_t *, nat_t *)); +static void nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *, u_short *)); +static INLINE int nat_wildok __P((nat_t *, int, int, int, int)); -int nat_init() +/* ------------------------------------------------------------------------ */ +/* Function: fr_natinit */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: Nil */ +/* */ +/* Initialise all of the NAT locks, tables and other structures. */ +/* ------------------------------------------------------------------------ */ +int fr_natinit() { + int i; + KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); if (nat_table[0] != NULL) bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *)); @@ -170,29 +218,106 @@ int nat_init() if (nat_table[1] != NULL) bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *)); else - return -1; + return -2; KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz); if (nat_rules != NULL) bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *)); else - return -1; + return -3; KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz); if (rdr_rules != NULL) bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *)); else - return -1; + return -4; KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz); if (maptable != NULL) bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); else - return -1; + return -5; + + KMALLOCS(nat_stats.ns_bucketlen[0], u_long *, + ipf_nattable_sz * sizeof(u_long)); + if (nat_stats.ns_bucketlen[0] == NULL) + return -6; + bzero((char *)nat_stats.ns_bucketlen[0], + ipf_nattable_sz * sizeof(u_long)); + + KMALLOCS(nat_stats.ns_bucketlen[1], u_long *, + ipf_nattable_sz * sizeof(u_long)); + if (nat_stats.ns_bucketlen[1] == NULL) + return -7; + + bzero((char *)nat_stats.ns_bucketlen[1], + ipf_nattable_sz * sizeof(u_long)); + + if (fr_nat_maxbucket == 0) { + for (i = ipf_nattable_sz; i > 0; i >>= 1) + fr_nat_maxbucket++; + fr_nat_maxbucket *= 2; + } + + fr_sttab_init(nat_tqb); + /* + * Increase this because we may have "keep state" following this too + * and packet storms can occur if this is removed too quickly. + */ + nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = fr_tcplastack; + nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &nat_udptq; + nat_udptq.ifq_ttl = fr_defnatage; + nat_udptq.ifq_head = NULL; + nat_udptq.ifq_tail = &nat_udptq.ifq_head; + MUTEX_INIT(&nat_udptq.ifq_lock, "nat ipftq udp tab"); + nat_udptq.ifq_next = &nat_icmptq; + nat_icmptq.ifq_ttl = fr_defnaticmpage; + nat_icmptq.ifq_head = NULL; + nat_icmptq.ifq_tail = &nat_icmptq.ifq_head; + MUTEX_INIT(&nat_icmptq.ifq_lock, "nat icmp ipftq tab"); + nat_icmptq.ifq_next = &nat_iptq; + nat_iptq.ifq_ttl = fr_defnaticmpage; + nat_iptq.ifq_head = NULL; + nat_iptq.ifq_tail = &nat_iptq.ifq_head; + MUTEX_INIT(&nat_iptq.ifq_lock, "nat ip ipftq tab"); + nat_iptq.ifq_next = NULL; + + for (i = 0; i < IPF_TCP_NSTATES; i++) { + if (nat_tqb[i].ifq_ttl < fr_defnaticmpage) + nat_tqb[i].ifq_ttl = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat_tqb[i].ifq_ttl > fr_defnatage) + nat_tqb[i].ifq_ttl = fr_defnatage; +#endif + } + + /* + * Increase this because we may have "keep state" following + * this too and packet storms can occur if this is removed + * too quickly. + */ + nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl; + + RWLOCK_INIT(&ipf_nat, "ipf IP NAT rwlock"); + RWLOCK_INIT(&ipf_natfrag, "ipf IP NAT-Frag rwlock"); + MUTEX_INIT(&ipf_nat_new, "ipf nat new mutex"); + MUTEX_INIT(&ipf_natio, "ipf nat io mutex"); + + fr_nat_init = 1; + return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_addrdr */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to add */ +/* */ +/* Adds a redirect rule to the hash table of redirect rules and the list of */ +/* loaded NAT rules. Updates the bitmask indicating which netmasks are in */ +/* use by redirect rules. */ +/* ------------------------------------------------------------------------ */ static void nat_addrdr(n) ipnat_t *n; { @@ -201,7 +326,7 @@ ipnat_t *n; u_int hv; int k; - k = countbits(n->in_outmsk); + k = count4bits(n->in_outmsk); if ((k >= 0) && (k != 32)) rdr_masks |= 1 << k; j = (n->in_outip & n->in_outmsk); @@ -211,10 +336,20 @@ ipnat_t *n; np = &(*np)->in_rnext; n->in_rnext = NULL; n->in_prnext = np; + n->in_hv = hv; *np = n; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_addnat */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to add */ +/* */ +/* Adds a NAT map rule to the hash table of rules and the list of loaded */ +/* NAT rules. Updates the bitmask indicating which netmasks are in use by */ +/* redirect rules. */ +/* ------------------------------------------------------------------------ */ static void nat_addnat(n) ipnat_t *n; { @@ -223,7 +358,7 @@ ipnat_t *n; u_int hv; int k; - k = countbits(n->in_inmsk); + k = count4bits(n->in_inmsk); if ((k >= 0) && (k != 32)) nat_masks |= 1 << k; j = (n->in_inip & n->in_inmsk); @@ -233,10 +368,18 @@ ipnat_t *n; np = &(*np)->in_mnext; n->in_mnext = NULL; n->in_pmnext = np; + n->in_hv = hv; *np = n; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_delrdr */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to delete */ +/* */ +/* Removes a redirect rule from the hash table of redirect rules. */ +/* ------------------------------------------------------------------------ */ static void nat_delrdr(n) ipnat_t *n; { @@ -246,60 +389,93 @@ ipnat_t *n; } +/* ------------------------------------------------------------------------ */ +/* Function: nat_delnat */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule to delete */ +/* */ +/* Removes a NAT map rule from the hash table of NAT map rules. */ +/* ------------------------------------------------------------------------ */ static void nat_delnat(n) ipnat_t *n; { - if (n->in_mnext) + if (n->in_mnext != NULL) n->in_mnext->in_pmnext = n->in_pmnext; *n->in_pmnext = n->in_mnext; } -/* - * check if an ip address has already been allocated for a given mapping that - * is not doing port based translation. - * - * Must be called with ipf_nat held as a write lock. - */ -static struct hostmap *nat_hostmap(np, real, map) +/* ------------------------------------------------------------------------ */ +/* Function: nat_hostmap */ +/* Returns: struct hostmap* - NULL if no hostmap could be created, */ +/* else a pointer to the hostmapping to use */ +/* Parameters: np(I) - pointer to NAT rule */ +/* real(I) - real IP address */ +/* map(I) - mapped IP address */ +/* port(I) - destination port number */ +/* Write Locks: ipf_nat */ +/* */ +/* Check if an ip address has already been allocated for a given mapping */ +/* that is not doing port based translation. If is not yet allocated, then */ +/* create a new entry. */ +/* ------------------------------------------------------------------------ */ +static struct hostmap *nat_hostmap(np, src, dst, map, port) ipnat_t *np; -struct in_addr real; +struct in_addr src; +struct in_addr dst; struct in_addr map; +u_32_t port; { hostmap_t *hm; u_int hv; - hv = real.s_addr % HOSTMAP_SIZE; + hv = (src.s_addr ^ dst.s_addr); + hv += src.s_addr; + hv += dst.s_addr; + hv %= HOSTMAP_SIZE; for (hm = maptable[hv]; hm; hm = hm->hm_next) - if ((hm->hm_realip.s_addr == real.s_addr) && - (np == hm->hm_ipnat)) { + if ((hm->hm_srcip.s_addr == src.s_addr) && + (hm->hm_dstip.s_addr == dst.s_addr) && + ((np == NULL) || (np == hm->hm_ipnat)) && + ((port == 0) || (port == hm->hm_port))) { hm->hm_ref++; return hm; } + if (np == NULL) + return NULL; + KMALLOC(hm, hostmap_t *); if (hm) { hm->hm_next = maptable[hv]; hm->hm_pnext = maptable + hv; - if (maptable[hv]) + if (maptable[hv] != NULL) maptable[hv]->hm_pnext = &hm->hm_next; maptable[hv] = hm; hm->hm_ipnat = np; - hm->hm_realip = real; + hm->hm_srcip = src; + hm->hm_dstip = dst; hm->hm_mapip = map; hm->hm_ref = 1; + hm->hm_port = port; } return hm; } -/* - * Must be called with ipf_nat held as a write lock. - */ +/* ------------------------------------------------------------------------ */ +/* Function: nat_hostmapdel */ +/* Returns: Nil */ +/* Parameters: hm(I) - pointer to hostmap structure */ +/* Write Locks: ipf_nat */ +/* */ +/* Decrement the references to this hostmap structure by one. If this */ +/* reaches zero then remove it and free it. */ +/* ------------------------------------------------------------------------ */ static void nat_hostmapdel(hm) struct hostmap *hm; { - ATOMIC_DEC32(hm->hm_ref); + hm->hm_ref--; if (hm->hm_ref == 0) { if (hm->hm_next) hm->hm_next->hm_pnext = hm->hm_pnext; @@ -309,17 +485,27 @@ struct hostmap *hm; } +/* ------------------------------------------------------------------------ */ +/* Function: fix_outcksum */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* sp(I) - location of 16bit checksum to update */ +/* n((I) - amount to adjust checksum by */ +/* */ +/* Adjusts the 16bit checksum by "n" for packets going out. */ +/* ------------------------------------------------------------------------ */ void fix_outcksum(fin, sp, n) fr_info_t *fin; u_short *sp; u_32_t n; { - register u_short sumshort; - register u_32_t sum1; + u_short sumshort; + u_32_t sum1; - if (!n) + if (n == 0) return; - else if (n & NAT_HW_CKSUM) { + + if (n & NAT_HW_CKSUM) { n &= 0xffff; n += fin->fin_dlen; n = (n & 0xffff) + (n >> 16); @@ -336,28 +522,34 @@ u_32_t n; } +/* ------------------------------------------------------------------------ */ +/* Function: fix_incksum */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* sp(I) - location of 16bit checksum to update */ +/* n((I) - amount to adjust checksum by */ +/* */ +/* Adjusts the 16bit checksum by "n" for packets going in. */ +/* ------------------------------------------------------------------------ */ void fix_incksum(fin, sp, n) fr_info_t *fin; u_short *sp; u_32_t n; { - register u_short sumshort; - register u_32_t sum1; + u_short sumshort; + u_32_t sum1; - if (!n) + if (n == 0) return; - else if (n & NAT_HW_CKSUM) { + + if (n & NAT_HW_CKSUM) { n &= 0xffff; n += fin->fin_dlen; n = (n & 0xffff) + (n >> 16); *sp = n & 0xffff; return; } -#ifdef sparc - sum1 = (~(*sp)) & 0xffff; -#else sum1 = (~ntohs(*sp)) & 0xffff; -#endif sum1 += ~(n) & 0xffff; sum1 = (sum1 >> 16) + (sum1 & 0xffff); /* Again */ @@ -367,27 +559,32 @@ u_32_t n; } -/* - * fix_datacksum is used *only* for the adjustments of checksums in the data - * section of an IP packet. - * - * The only situation in which you need to do this is when NAT'ing an - * ICMP error message. Such a message, contains in its body the IP header - * of the original IP packet, that causes the error. - * - * You can't use fix_incksum or fix_outcksum in that case, because for the - * kernel the data section of the ICMP error is just data, and no special - * processing like hardware cksum or ntohs processing have been done by the - * kernel on the data section. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fix_datacksum */ +/* Returns: Nil */ +/* Parameters: sp(I) - location of 16bit checksum to update */ +/* n((I) - amount to adjust checksum by */ +/* */ +/* Fix_datacksum is used *only* for the adjustments of checksums in the */ +/* data section of an IP packet. */ +/* */ +/* The only situation in which you need to do this is when NAT'ing an */ +/* ICMP error message. Such a message, contains in its body the IP header */ +/* of the original IP packet, that causes the error. */ +/* */ +/* You can't use fix_incksum or fix_outcksum in that case, because for the */ +/* kernel the data section of the ICMP error is just data, and no special */ +/* processing like hardware cksum or ntohs processing have been done by the */ +/* kernel on the data section. */ +/* ------------------------------------------------------------------------ */ void fix_datacksum(sp, n) u_short *sp; u_32_t n; { - register u_short sumshort; - register u_32_t sum1; + u_short sumshort; + u_32_t sum1; - if (!n) + if (n == 0) return; sum1 = (~ntohs(*sp)) & 0xffff; @@ -399,74 +596,62 @@ u_32_t n; *(sp) = htons(sumshort); } -/* - * 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, mode) -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -u_long cmd; -#else -int cmd; -#endif +/* ------------------------------------------------------------------------ */ +/* Function: fr_nat_ioctl */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* cmd(I) - ioctl command integer */ +/* mode(I) - file mode bits used with open */ +/* */ +/* Processes an ioctl call made to operate on the IP Filter NAT device. */ +/* ------------------------------------------------------------------------ */ +int fr_nat_ioctl(data, cmd, mode) +ioctlcmd_t cmd; caddr_t data; int mode; { - register ipnat_t *nat, *nt, *n = NULL, **np = NULL; + ipnat_t *nat, *nt, *n = NULL, **np = NULL; int error = 0, ret, arg, getlock; ipnat_t natd; - u_32_t i, j; #if (BSD >= 199306) && defined(_KERNEL) if ((securelevel >= 2) && (mode & FWRITE)) return EPERM; #endif - nat = NULL; /* XXX gcc -Wuninitialized */ - KMALLOC(nt, ipnat_t *); +#if defined(__osf__) && defined(_KERNEL) + getlock = 0; +#else getlock = (mode & NAT_LOCKHELD) ? 0 : 1; - if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { +#endif + + nat = NULL; /* XXX gcc -Wuninitialized */ + if (cmd == (ioctlcmd_t)SIOCADNAT) { + KMALLOC(nt, ipnat_t *); + } else { + nt = NULL; + } + + if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { if (mode & NAT_SYSSPACE) { bcopy(data, (char *)&natd, sizeof(natd)); error = 0; } else { - error = IRCOPYPTR(data, (char *)&natd, sizeof(natd)); + error = fr_inobj(data, &natd, IPFOBJ_IPNAT); } - } else if (cmd == SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ - error = IRCOPY(data, (char *)&arg, sizeof(arg)); - if (error) - error = EFAULT; + + } else if (cmd == (ioctlcmd_t)SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ + BCOPYIN(data, &arg, sizeof(arg)); } - if (error) + if (error != 0) goto done; /* * For add/delete, look to see if the NAT entry is already present */ - if (getlock == 1) - WRITE_ENTER(&ipf_nat); - if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { + if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { nat = &natd; nat->in_flags &= IPN_USERFLAGS; if ((nat->in_redir & NAT_MAPBLK) == 0) { @@ -475,14 +660,11 @@ int mode; if ((nat->in_flags & IPN_IPRANGE) == 0) nat->in_outip &= nat->in_outmsk; } - for (np = &nat_list; (n = *np); np = &n->in_next) + MUTEX_ENTER(&ipf_natio); + for (np = &nat_list; ((n = *np) != NULL); np = &n->in_next) if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, - IPN_CMPSIZ)) { - if (n->in_redir == NAT_REDIRECT && - n->in_pnext != nat->in_pnext) - continue; + IPN_CMPSIZ)) break; - } } switch (cmd) @@ -496,182 +678,94 @@ int mode; error = EPERM; else { tmp = ipflog_clear(IPL_LOGNAT); - IWCOPY((char *)&tmp, (char *)data, sizeof(tmp)); + BCOPYOUT((char *)&tmp, (char *)data, sizeof(tmp)); } break; } + case SIOCSETLG : + if (!(mode & FWRITE)) + error = EPERM; + else { + BCOPYIN((char *)data, (char *)&nat_logging, + sizeof(nat_logging)); + } + break; + case SIOCGETLG : + BCOPYOUT((char *)&nat_logging, (char *)data, + sizeof(nat_logging)); + break; + case FIONREAD : + arg = iplused[IPL_LOGNAT]; + BCOPYOUT(&arg, data, sizeof(arg)); + break; #endif case SIOCADNAT : if (!(mode & FWRITE)) { error = EPERM; - break; - } - if (n) { + } else if (n != NULL) { error = EEXIST; - break; - } - if (nt == NULL) { + } else if (nt == NULL) { error = ENOMEM; + } + if (error != 0) { + MUTEX_EXIT(&ipf_natio); break; } - n = nt; - nt = NULL; - bcopy((char *)nat, (char *)n, sizeof(*n)); - n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); - if (!n->in_ifp) - n->in_ifp = (void *)-1; - if (n->in_plabel[0] != '\0') { - n->in_apr = appr_lookup(n->in_p, n->in_plabel); - if (!n->in_apr) { - error = ENOENT; - break; - } - } - n->in_next = NULL; - *np = n; - - if (n->in_redir & NAT_REDIRECT) { - n->in_flags &= ~IPN_NOTDST; - nat_addrdr(n); - } - if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { - n->in_flags &= ~IPN_NOTSRC; - nat_addnat(n); - } - - n->in_use = 0; - if (n->in_redir & NAT_MAPBLK) - n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); - else if (n->in_flags & IPN_AUTOPORTMAP) - n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); - else if (n->in_flags & IPN_IPRANGE) - n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); - else if (n->in_flags & IPN_SPLIT) - n->in_space = 2; - else - n->in_space = ~ntohl(n->in_outmsk); - /* - * Calculate the number of valid IP addresses in the output - * mapping range. In all cases, the range is inclusive of - * the start and ending IP addresses. - * If to a CIDR address, lose 2: broadcast + network address - * (so subtract 1) - * If to a range, add one. - * If to a single IP address, set to 1. - */ - if (n->in_space) { - if ((n->in_flags & IPN_IPRANGE) != 0) - n->in_space += 1; - else - n->in_space -= 1; - } else - n->in_space = 1; - if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && - ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) - n->in_nip = ntohl(n->in_outip) + 1; - else if ((n->in_flags & IPN_SPLIT) && - (n->in_redir & NAT_REDIRECT)) - n->in_nip = ntohl(n->in_inip); - else - n->in_nip = ntohl(n->in_outip); - if (n->in_redir & NAT_MAP) { - n->in_pnext = ntohs(n->in_pmin); - /* - * Multiply by the number of ports made available. - */ - if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { - n->in_space *= (ntohs(n->in_pmax) - - ntohs(n->in_pmin) + 1); - /* - * Because two different sources can map to - * different destinations but use the same - * local IP#/port #. - * If the result is smaller than in_space, then - * we may have wrapped around 32bits. - */ - i = n->in_inmsk; - if ((i != 0) && (i != 0xffffffff)) { - j = n->in_space * (~ntohl(i) + 1); - if (j >= n->in_space) - n->in_space = j; - else - n->in_space = 0xffffffff; - } - } - /* - * If no protocol is specified, multiple by 256. - */ - if ((n->in_flags & IPN_TCPUDP) == 0) { - j = n->in_space * 256; - if (j >= n->in_space) - n->in_space = j; - else - n->in_space = 0xffffffff; - } - } - /* Otherwise, these fields are preset */ - n = NULL; - nat_stats.ns_rules++; + bcopy((char *)nat, (char *)nt, sizeof(*n)); + error = nat_siocaddnat(nt, np, getlock); + MUTEX_EXIT(&ipf_natio); + if (error == 0) + nt = NULL; break; case SIOCRMNAT : if (!(mode & FWRITE)) { error = EPERM; n = NULL; - break; - } - if (!n) { + } else if (n == NULL) { error = ESRCH; + } + + if (error != 0) { + MUTEX_EXIT(&ipf_natio); break; } - if (n->in_redir & NAT_REDIRECT) - nat_delrdr(n); - if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) - nat_delnat(n); - if (nat_list == NULL) { - nat_masks = 0; - rdr_masks = 0; - } - *np = n->in_next; - if (!n->in_use) { - if (n->in_apr) - appr_free(n->in_apr); - KFREE(n); - nat_stats.ns_rules--; - } else { - n->in_flags |= IPN_DELETE; - n->in_next = NULL; - } + nat_siocdelnat(n, np, getlock); + + MUTEX_EXIT(&ipf_natio); n = NULL; break; case SIOCGNATS : - MUTEX_DOWNGRADE(&ipf_nat); nat_stats.ns_table[0] = nat_table[0]; nat_stats.ns_table[1] = nat_table[1]; nat_stats.ns_list = nat_list; nat_stats.ns_maptable = maptable; nat_stats.ns_nattab_sz = ipf_nattable_sz; + nat_stats.ns_nattab_max = ipf_nattable_max; nat_stats.ns_rultab_sz = ipf_natrules_sz; nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; nat_stats.ns_hostmap_sz = ipf_hostmap_sz; nat_stats.ns_instances = nat_instances; nat_stats.ns_apslist = ap_sess_list; - error = IWCOPYPTR((char *)&nat_stats, (char *)data, - sizeof(nat_stats)); + error = fr_outobj(data, &nat_stats, IPFOBJ_NATSTAT); break; case SIOCGNATL : { natlookup_t nl; - MUTEX_DOWNGRADE(&ipf_nat); - error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl)); + if (getlock) { + READ_ENTER(&ipf_nat); + } + error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP); if (error) break; if (nat_lookupredir(&nl)) { - error = IWCOPYPTR((char *)&nl, (char *)data, - sizeof(nl)); + error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP); } else error = ESRCH; + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } break; } case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ @@ -679,6 +773,9 @@ int mode; error = EPERM; break; } + if (getlock) { + WRITE_ENTER(&ipf_nat); + } error = 0; if (arg == 0) ret = nat_flushtable(); @@ -686,56 +783,62 @@ int mode; ret = nat_clearlist(); else error = EINVAL; - MUTEX_DOWNGRADE(&ipf_nat); - if (!error) { - error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); - if (error) - error = EFAULT; + if (getlock) { + MUTEX_DOWNGRADE(&ipf_nat); + } + if (error == 0) { + BCOPYOUT(&ret, data, sizeof(ret)); + } + if (getlock) { + RWLOCK_EXIT(&ipf_nat); } break; + case SIOCPROXY : + error = appr_ioctl(data, cmd, mode); + break; case SIOCSTLCK : - error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); - if (!error) { - error = IWCOPY((caddr_t)&fr_nat_lock, data, - sizeof(fr_nat_lock)); - if (!error) - fr_nat_lock = arg; - } else - error = EFAULT; + error = fr_lock(data, &fr_nat_lock); break; case SIOCSTPUT : - if (fr_nat_lock) + if (fr_nat_lock) { + if (getlock) { + WRITE_ENTER(&ipf_nat); + } error = fr_natputent(data); - else + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + } else error = EACCES; break; case SIOCSTGSZ : - if (fr_nat_lock) + if (fr_nat_lock) { + if (getlock) { + READ_ENTER(&ipf_nat); + } error = fr_natgetsz(data); - else + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + } else error = EACCES; break; case SIOCSTGET : - if (fr_nat_lock) + if (fr_nat_lock) { + if (getlock) { + READ_ENTER(&ipf_nat); + } error = fr_natgetent(data); - else + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + } else error = EACCES; break; - case FIONREAD : -#ifdef IPFILTER_LOG - arg = (int)iplused[IPL_LOGNAT]; - MUTEX_DOWNGRADE(&ipf_nat); - error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); - if (error) - error = EFAULT; -#endif - break; default : error = EINVAL; break; } - if (getlock == 1) - RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ done: if (nt) KFREE(nt); @@ -743,76 +846,270 @@ done: } +/* ------------------------------------------------------------------------ */ +/* Function: nat_siocaddnat */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: n(I) - pointer to new NAT rule */ +/* np(I) - pointer to where to insert new NAT rule */ +/* getlock(I) - flag indicating if lock on ipf_nat is held */ +/* Mutex Locks: ipf_natio */ +/* */ +/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ +/* from information passed to the kernel, then add it to the appropriate */ +/* NAT rule table(s). */ +/* ------------------------------------------------------------------------ */ +static int nat_siocaddnat(n, np, getlock) +ipnat_t *n, **np; +int getlock; +{ + int error = 0, i, j; + + nat_resolverule(n); + if (n->in_plabel[0] != '\0') { + if (n->in_apr == NULL) + return ENOENT; + } + + n->in_use = 0; + if (n->in_redir & NAT_MAPBLK) + n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); + else if (n->in_flags & IPN_AUTOPORTMAP) + n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); + else if (n->in_flags & IPN_IPRANGE) + n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); + else if (n->in_flags & IPN_SPLIT) + n->in_space = 2; + else if (n->in_outmsk != 0) + n->in_space = ~ntohl(n->in_outmsk); + else + n->in_space = 1; + + /* + * Calculate the number of valid IP addresses in the output + * mapping range. In all cases, the range is inclusive of + * the start and ending IP addresses. + * If to a CIDR address, lose 2: broadcast + network address + * (so subtract 1) + * If to a range, add one. + * If to a single IP address, set to 1. + */ + if (n->in_space) { + if ((n->in_flags & IPN_IPRANGE) != 0) + n->in_space += 1; + else + n->in_space -= 1; + } else + n->in_space = 1; + + if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && + ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0)) + n->in_nip = ntohl(n->in_outip) + 1; + else if ((n->in_flags & IPN_SPLIT) && + (n->in_redir & NAT_REDIRECT)) + n->in_nip = ntohl(n->in_inip); + else + n->in_nip = ntohl(n->in_outip); + if (n->in_redir & NAT_MAP) { + n->in_pnext = ntohs(n->in_pmin); + /* + * Multiply by the number of ports made available. + */ + if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { + n->in_space *= (ntohs(n->in_pmax) - + ntohs(n->in_pmin) + 1); + /* + * Because two different sources can map to + * different destinations but use the same + * local IP#/port #. + * If the result is smaller than in_space, then + * we may have wrapped around 32bits. + */ + i = n->in_inmsk; + if ((i != 0) && (i != 0xffffffff)) { + j = n->in_space * (~ntohl(i) + 1); + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } + } + /* + * If no protocol is specified, multiple by 256 to allow for + * at least one IP:IP mapping per protocol. + */ + if ((n->in_flags & IPN_TCPUDPICMP) == 0) { + j = n->in_space * 256; + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } + } + + /* Otherwise, these fields are preset */ + + if (getlock) { + WRITE_ENTER(&ipf_nat); + } + n->in_next = NULL; + *np = n; + + if (n->in_age[0] != 0) + n->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, n->in_age[0]); + + if (n->in_age[1] != 0) + n->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, n->in_age[1]); + + if (n->in_redir & NAT_REDIRECT) { + n->in_flags &= ~IPN_NOTDST; + nat_addrdr(n); + } + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { + n->in_flags &= ~IPN_NOTSRC; + nat_addnat(n); + } + n = NULL; + nat_stats.ns_rules++; +#if SOLARIS + pfil_delayed_copy = 0; +#endif + if (getlock) { + RWLOCK_EXIT(&ipf_nat); /* WRITE */ + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_resolvrule */ +/* Returns: Nil */ +/* Parameters: n(I) - pointer to NAT rule */ +/* */ +/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ +/* from information passed to the kernel, then add it to the appropriate */ +/* NAT rule table(s). */ +/* ------------------------------------------------------------------------ */ +static INLINE void nat_resolverule(n) +ipnat_t *n; +{ + n->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; + if (!strncmp(n->in_ifnames[0], "*", LIFNAMSIZ)) { + n->in_ifps[0] = NULL; + } else if (!strncmp(n->in_ifnames[0], "-", LIFNAMSIZ)) { + n->in_ifps[0] = (void *)-1; + } else { + n->in_ifps[0] = (void *)GETIFP(n->in_ifnames[0], 4); + if (n->in_ifps[0] == NULL) + n->in_ifps[0] = (void *)-1; + } + + n->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; + if (n->in_ifnames[1][0] == '\0') { + (void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ); + n->in_ifps[1] = n->in_ifps[0]; + } else { + if (!strncmp(n->in_ifnames[1], "*", LIFNAMSIZ)) { + n->in_ifps[1] = NULL; + } else if (!strncmp(n->in_ifnames[1], "-", LIFNAMSIZ)) { + n->in_ifps[1] = (void *)-1; + } else { + n->in_ifps[1] = (void *)GETIFP(n->in_ifnames[1], 4); + if (n->in_ifps[1] == NULL) + n->in_ifps[1] = (void *)-1; + } + } + + if (n->in_plabel[0] != '\0') { + n->in_apr = appr_lookup(n->in_p, n->in_plabel); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_siocdelnat */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: n(I) - pointer to new NAT rule */ +/* np(I) - pointer to where to insert new NAT rule */ +/* getlock(I) - flag indicating if lock on ipf_nat is held */ +/* Mutex Locks: ipf_natio */ +/* */ +/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */ +/* from information passed to the kernel, then add it to the appropriate */ +/* NAT rule table(s). */ +/* ------------------------------------------------------------------------ */ +static void nat_siocdelnat(n, np, getlock) +ipnat_t *n, **np; +int getlock; +{ + if (getlock) { + WRITE_ENTER(&ipf_nat); + } + if (n->in_redir & NAT_REDIRECT) + nat_delrdr(n); + if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) + nat_delnat(n); + if (nat_list == NULL) { + nat_masks = 0; + rdr_masks = 0; + } + + if (n->in_tqehead[0] != NULL) + fr_deletetimeoutqueue(n->in_tqehead[0]); + + if (n->in_tqehead[1] != NULL) + fr_deletetimeoutqueue(n->in_tqehead[1]); + + *np = n->in_next; + + if (n->in_use == 0) { + if (n->in_apr) + appr_free(n->in_apr); + KFREE(n); + nat_stats.ns_rules--; +#if SOLARIS + if (nat_stats.ns_rules == 0) + pfil_delayed_copy = 1; +#endif + } else { + n->in_flags |= IPN_DELETE; + n->in_next = NULL; + } + if (getlock) { + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natgetsz */ +/* Returns: int - 0 == success, != 0 is the error value. */ +/* Parameters: data(I) - pointer to natget structure with kernel pointer */ +/* get the size of. */ +/* */ +/* Handle SIOCSTGSZ. */ +/* Return the size of the nat list entry to be copied back to user space. */ +/* The size of the entry is stored in the ng_sz field and the enture natget */ +/* structure is copied back to the user. */ +/* ------------------------------------------------------------------------ */ static int fr_natgetsz(data) caddr_t data; { ap_session_t *aps; nat_t *nat, *n; - int error = 0; natget_t ng; - error = IRCOPY(data, (caddr_t)&ng, sizeof(ng)); - if (error) - return EFAULT; + BCOPYIN(data, &ng, sizeof(ng)); nat = ng.ng_ptr; if (!nat) { nat = nat_instances; ng.ng_sz = 0; - if (nat == NULL) { - error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); - if (error) - error = EFAULT; - return error; - } - } else { /* - * Make sure the pointer we're copying from exists in the - * current list of entries. Security precaution to prevent - * copying of random kernel data. + * Empty list so the size returned is 0. Simple. */ - for (n = nat_instances; n; n = n->nat_next) - if (n == nat) - break; - if (!n) - return ESRCH; - } - - ng.ng_sz = sizeof(nat_save_t); - aps = nat->nat_aps; - if ((aps != NULL) && (aps->aps_data != 0)) { - ng.ng_sz += sizeof(ap_session_t); - ng.ng_sz += aps->aps_psiz; - } - - error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); - if (error) - error = EFAULT; - return error; -} - - -static int fr_natgetent(data) -caddr_t data; -{ - nat_save_t ipn, *ipnp, *ipnn = NULL; - register nat_t *n, *nat; - ap_session_t *aps; - int error; - - error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); - if (error) - return EFAULT; - error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); - if (error) - return EFAULT; - - nat = ipn.ipn_next; - if (!nat) { - nat = nat_instances; if (nat == NULL) { - if (nat_instances == NULL) - return ENOENT; + BCOPYOUT(&ng, data, sizeof(ng)); return 0; } } else { @@ -828,75 +1125,171 @@ caddr_t data; return ESRCH; } - ipn.ipn_next = nat->nat_next; - ipn.ipn_dsize = 0; - bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat)); - ipn.ipn_nat.nat_data = NULL; - - if (nat->nat_ptr) { - bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat, - sizeof(ipn.ipn_ipnat)); + /* + * Incluse any space required for proxy data structures. + */ + ng.ng_sz = sizeof(nat_save_t); + aps = nat->nat_aps; + if ((aps != NULL) && (aps->aps_data != 0)) { + ng.ng_sz += sizeof(ap_session_t); + ng.ng_sz += aps->aps_psiz; + if (ng.ng_sz > 4) + ng.ng_sz -= 4; /* XXX - sizeof(ipn_data) */ } - if (nat->nat_fr) - bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule, - sizeof(ipn.ipn_rule)); + BCOPYOUT(&ng, data, sizeof(ng)); + return 0; +} - if ((aps = nat->nat_aps)) { + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natgetent */ +/* Returns: int - 0 == success, != 0 is the error value. */ +/* Parameters: data(I) - pointer to natget structure with kernel pointer */ +/* to NAT structure to copy out. */ +/* */ +/* Handle SIOCSTGET. */ +/* Copies out NAT entry to user space. Any additional data held for a */ +/* proxy is also copied, as to is the NAT rule which was responsible for it */ +/* ------------------------------------------------------------------------ */ +static int fr_natgetent(data) +caddr_t data; +{ + ap_session_t *aps; + nat_save_t ipn; + nat_t *n, *nat; + int error; + + error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); + if (error != 0) + return error; + + nat = ipn.ipn_next; + if (nat == NULL) { + nat = nat_instances; + if (nat == NULL) { + if (nat_instances == NULL) + return ENOENT; + return 0; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (n = nat_instances; n; n = n->nat_next) + if (n == nat) + break; + if (n == NULL) + return ESRCH; + } + + /* + * Copy out the NAT structure. + */ + error = copyoutptr((char *)nat, + (char *)data + offsetof(struct nat_save, ipn_nat), + sizeof(struct nat)); + if (error != 0) + return error; + + /* + * If we have a pointer to the NAT rule it belongs to, save that too. + */ + if (nat->nat_ptr != NULL) { + error = copyoutptr((char *)nat->nat_ptr, + (char *)data + + offsetof(struct nat_save, ipn_ipnat), + sizeof(struct ipnat)); + if (error != 0) + return error; + } + + /* + * If we also know the NAT entry has an associated filter rule, + * save that too. + */ + if (nat->nat_fr != NULL) { + error = copyoutptr((char *)nat->nat_fr, + (char *)data + + offsetof(struct nat_save, ipn_rule), + sizeof(struct frentry)); + if (error != 0) + return error; + } + + /* + * Last but not least, if there is an application proxy session set + * up for this NAT entry, then copy that out too, including any + * private data saved along side it by the proxy. + */ + aps = nat->nat_aps; + if (aps != NULL) { ipn.ipn_dsize = sizeof(*aps); if (aps->aps_data) ipn.ipn_dsize += aps->aps_psiz; - KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); - if (ipnn == NULL) - return ENOMEM; - bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + error = copyoutptr((char *)&ipn.ipn_dsize, + (char *)data + + offsetof(struct nat_save, ipn_dsize), + sizeof(ipn.ipn_dsize)); + if (error != 0) + return error; - bcopy((char *)aps, (char *)ipnn->ipn_data, sizeof(*aps)); - if (aps->aps_data) { - bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps), - aps->aps_psiz); - ipnn->ipn_dsize += aps->aps_psiz; + error = copyoutptr((char *)aps, (char *)data + + offsetof(struct nat_save, ipn_data), + sizeof(*aps)); + if (error != 0) + return error; + + if (aps->aps_psiz > 0) { + error = copyoutptr((char *)aps->aps_data, + (char *)data + sizeof(*aps) + + offsetof(struct nat_save, ipn_data), + aps->aps_psiz); + if (error != 0) + return error; } - error = IWCOPY((caddr_t)ipnn, ipnp, - sizeof(ipn) + ipn.ipn_dsize); - if (error) - error = EFAULT; - KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize); - } else { - error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); - if (error) - error = EFAULT; } return error; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_natputent */ +/* Returns: int - 0 == success, != 0 is the error value. */ +/* Parameters: data(I) - pointer to natget structure with NAT structure */ +/* information to load into the kernel. */ +/* */ +/* Handle SIOCSTPUT. */ +/* Loads a NAT table entry from user space, including a NAT rule, proxy and */ +/* firewall rule data structures, if pointers to them indicate so. */ +/* ------------------------------------------------------------------------ */ static int fr_natputent(data) caddr_t data; { - nat_save_t ipn, *ipnp, *ipnn = NULL; - register nat_t *n, *nat; + nat_save_t ipn, *ipnn; ap_session_t *aps; + nat_t *n, *nat; frentry_t *fr; ipnat_t *in; - int error; - error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); - if (error) - return EFAULT; - error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); - if (error) - return EFAULT; + error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); + if (error != 0) + return error; + nat = NULL; - if (ipn.ipn_dsize) { - KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize); + if (ipn.ipn_dsize != 0) { + KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize - + sizeof(ipn.ipn_data)); if (ipnn == NULL) return ENOMEM; - bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); - error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data, - ipn.ipn_dsize); - if (error) { + + /* XXX should use fr_inobj */ + error = copyinptr(data, ipnn, sizeof(ipn) + ipn.ipn_dsize - + sizeof(ipn.ipn_data)); + if (error != 0) { error = EFAULT; goto junkput; } @@ -905,7 +1298,7 @@ caddr_t data; KMALLOC(nat, nat_t *); if (nat == NULL) { - error = EFAULT; + error = ENOMEM; goto junkput; } @@ -913,6 +1306,7 @@ caddr_t data; /* * Initialize all these so that nat_delete() doesn't cause a crash. */ + MUTEX_NUKE(&nat->nat_lock); nat->nat_phnext[0] = NULL; nat->nat_phnext[1] = NULL; fr = nat->nat_fr; @@ -923,12 +1317,11 @@ caddr_t data; nat->nat_ptr = NULL; nat->nat_hm = NULL; nat->nat_data = NULL; - nat->nat_ifp = GETUNIT(nat->nat_ifname, 4); /* * Restore the rule associated with this nat session */ - if (in) { + if (in != NULL) { KMALLOC(in, ipnat_t *); if (in == NULL) { error = ENOMEM; @@ -943,17 +1336,15 @@ caddr_t data; in->in_prnext = NULL; in->in_mnext = NULL; in->in_pmnext = NULL; - in->in_ifp = GETUNIT(in->in_ifname, 4); - if (in->in_plabel[0] != '\0') { - in->in_apr = appr_lookup(in->in_p, in->in_plabel); - } + + nat_resolverule(in); } /* * Restore ap_session_t structure. Include the private data allocated * if it was there. */ - if (aps) { + if (aps != NULL) { KMALLOC(aps, ap_session_t *); if (aps == NULL) { error = ENOMEM; @@ -965,7 +1356,7 @@ caddr_t data; bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); if (in) aps->aps_apr = in->in_apr; - if (aps->aps_psiz) { + if (aps->aps_psiz != 0) { KMALLOCS(aps->aps_data, void *, aps->aps_psiz); if (aps->aps_data == NULL) { error = ENOMEM; @@ -984,7 +1375,7 @@ caddr_t data; * build up a new one. */ if (fr != NULL) { - if (nat->nat_flags & FI_NEWFR) { + if (nat->nat_flags & SI_NEWFR) { KMALLOC(fr, frentry_t *); nat->nat_fr = fr; if (fr == NULL) { @@ -992,12 +1383,10 @@ caddr_t data; goto junkput; } bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr)); + MUTEX_NUKE(&fr->fr_lock); + MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); ipn.ipn_nat.nat_fr = fr; - error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); - if (error) { - error = EFAULT; - goto junkput; - } + (void) fr_outobj(&ipn, data, IPFOBJ_NATSAVE); } else { for (n = nat_instances; n; n = n->nat_next) if (n->nat_fr == fr) @@ -1009,82 +1398,170 @@ caddr_t data; } } - if (ipnn) + if (ipnn != NULL) { KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); - nat_insert(nat); + } + if (nat_insert(nat, 0) == -1) { + KFREE(nat); + error = ENOMEM; + goto junkput; + } return 0; junkput: - if (ipnn) + if (ipnn != NULL) { KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); - if (nat) - nat_delete(nat); + } + if (nat != NULL) + nat_delete(nat, 0); return error; } -/* - * Delete a nat entry from the various lists and table. - */ -static void nat_delete(natd) -struct nat *natd; +/* ------------------------------------------------------------------------ */ +/* Function: nat_delete */ +/* Returns: Nil */ +/* Parameters: natd(I) - pointer to NAT structure to delete */ +/* logtype(I) - type of LOG record to create before deleting */ +/* Write Lock: ipf_nat */ +/* */ +/* Delete a nat entry from the various lists and table. If NAT logging is */ +/* enabled then generate a NAT log record for this event. */ +/* ------------------------------------------------------------------------ */ +static void nat_delete(nat, logtype) +struct nat *nat; +int logtype; { + ipftqent_t *tqe; struct ipnat *ipn; + ipftq_t *ifq; - if (natd->nat_flags & FI_WILDP) - nat_stats.ns_wilds--; - if (natd->nat_hnext[0]) - natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; - *natd->nat_phnext[0] = natd->nat_hnext[0]; - if (natd->nat_hnext[1]) - natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; - *natd->nat_phnext[1] = natd->nat_hnext[1]; - if (natd->nat_me != NULL) - *natd->nat_me = NULL; + if (logtype != 0 && nat_logging != 0) + nat_log(nat, logtype); - if (natd->nat_fr != NULL) { - ATOMIC_DEC32(natd->nat_fr->fr_ref); + MUTEX_ENTER(&ipf_nat_new); + + /* + * Take it as a general indication that all the pointers are set if + * nat_pnext is set. + */ + if (nat->nat_pnext != NULL) { + nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; + nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; + + *nat->nat_pnext = nat->nat_next; + if (nat->nat_next != NULL) { + nat->nat_next->nat_pnext = nat->nat_pnext; + nat->nat_next = NULL; + } + nat->nat_pnext = NULL; + + *nat->nat_phnext[0] = nat->nat_hnext[0]; + if (nat->nat_hnext[0] != NULL) { + nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; + nat->nat_hnext[0] = NULL; + } + nat->nat_phnext[0] = NULL; + + *nat->nat_phnext[1] = nat->nat_hnext[1]; + if (nat->nat_hnext[1] != NULL) { + nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; + nat->nat_hnext[1] = NULL; + } + nat->nat_phnext[1] = NULL; + + if ((nat->nat_flags & SI_WILDP) != 0) + nat_stats.ns_wilds--; } - if (natd->nat_hm != NULL) - nat_hostmapdel(natd->nat_hm); + if (nat->nat_me != NULL) { + *nat->nat_me = NULL; + nat->nat_me = NULL; + } + + tqe = &nat->nat_tqe; + ifq = tqe->tqe_ifq; + if (ifq != NULL) { + *tqe->tqe_pnext = tqe->tqe_next; + if (tqe->tqe_next) + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + else + ifq->ifq_tail = tqe->tqe_pnext; + tqe->tqe_ifq = NULL; + } + + if ((ifq->ifq_flags & IFQF_USER) != 0) + fr_deletetimeoutqueue(ifq); + + nat->nat_ref--; + if (nat->nat_ref > 0) { + MUTEX_EXIT(&ipf_nat_new); + return; + } + +#ifdef IPFILTER_SYNC + if (nat->nat_sync) + ipfsync_del(nat->nat_sync); +#endif + + if (nat->nat_fr != NULL) + (void)fr_derefrule(&nat->nat_fr); + + if (nat->nat_hm != NULL) + nat_hostmapdel(nat->nat_hm); /* * If there is an active reference from the nat entry to its parent * rule, decrement the rule's reference count and free it too if no * longer being used. */ - ipn = natd->nat_ptr; + ipn = nat->nat_ptr; if (ipn != NULL) { ipn->in_space++; ipn->in_use--; - if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) { + if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) { if (ipn->in_apr) appr_free(ipn->in_apr); KFREE(ipn); nat_stats.ns_rules--; +#if SOLARIS + if (nat_stats.ns_rules == 0) + pfil_delayed_copy = 1; +#endif } } - MUTEX_DESTROY(&natd->nat_lock); + MUTEX_DESTROY(&nat->nat_lock); + + aps_free(nat->nat_aps); + nat_stats.ns_inuse--; + MUTEX_EXIT(&ipf_nat_new); + /* * If there's a fragment table entry too for this nat entry, then - * dereference that as well. + * dereference that as well. This is after nat_lock is released + * because of Tru64. */ - ipfr_forget((void *)natd); - aps_free(natd->nat_aps); - nat_stats.ns_inuse--; - KFREE(natd); + fr_forgetnat((void *)nat); + + KFREE(nat); } +/* ------------------------------------------------------------------------ */ +/* Function: nat_flushtable */ +/* Returns: int - number of NAT rules deleted */ +/* Parameters: Nil */ +/* */ +/* Deletes all currently active NAT sessions. In deleting each NAT entry a */ +/* log record should be emitted in nat_delete() if NAT logging is enabled. */ +/* ------------------------------------------------------------------------ */ /* * nat_flushtable - clear the NAT table of all mapping entries. - * (this is for the dynamic mappings) */ static int nat_flushtable() { - register nat_t *nat, **natp; - register int j = 0; + nat_t *nat; + int j = 0; /* * ALL NAT mappings deleted, so lets just make the deletions @@ -1097,26 +1574,28 @@ static int nat_flushtable() bzero((char *)nat_table[1], sizeof(nat_table[1]) * ipf_nattable_sz); - for (natp = &nat_instances; (nat = *natp); ) { - *natp = nat->nat_next; -#ifdef IPFILTER_LOG - nat_log(nat, NL_FLUSH); -#endif - nat_delete(nat); + while ((nat = nat_instances) != NULL) { + nat_delete(nat, NL_FLUSH); j++; } + nat_stats.ns_inuse = 0; return j; } -/* - * nat_clearlist - delete all rules in the active NAT mapping list. - * (this is for NAT/RDR rules) - */ -int nat_clearlist() +/* ------------------------------------------------------------------------ */ +/* Function: nat_clearlist */ +/* Returns: int - number of NAT/RDR rules deleted */ +/* Parameters: Nil */ +/* */ +/* Delete all rules in the current list of rules. There is nothing elegant */ +/* about this cleanup: simply free all entries on the list of rules and */ +/* clear out the tables used for hashed NAT rule lookups. */ +/* ------------------------------------------------------------------------ */ +static int nat_clearlist() { - register ipnat_t *n, **np = &nat_list; + ipnat_t *n, **np = &nat_list; int i = 0; if (nat_rules != NULL) @@ -1124,10 +1603,10 @@ int nat_clearlist() if (rdr_rules != NULL) bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz); - while ((n = *np)) { + while ((n = *np) != NULL) { *np = n->in_next; - if (!n->in_use) { - if (n->in_apr) + if (n->in_use == 0) { + if (n->in_apr != NULL) appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; @@ -1137,455 +1616,716 @@ int nat_clearlist() } i++; } +#if SOLARIS + pfil_delayed_copy = 1; +#endif nat_masks = 0; rdr_masks = 0; return i; } -/* - * Check for MSS option and clamp it if necessary. - */ -static __inline void -tcp_mss_clamp(tcp, maxmss, fin, csump) - tcphdr_t *tcp; - uint32_t maxmss; - fr_info_t *fin; - u_short *csump; + +/* ------------------------------------------------------------------------ */ +/* Function: nat_newmap */ +/* Returns: int - -1 == error, 0 == success */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT entry */ +/* ni(I) - pointer to structure with misc. information needed */ +/* to create new NAT entry. */ +/* */ +/* Given an empty NAT structure, populate it with new information about a */ +/* new NAT session, as defined by the matching NAT rule. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_newmap(fin, nat, ni) +fr_info_t *fin; +nat_t *nat; +natinfo_t *ni; { - uint8_t *cp, *ep; - uint8_t opt; - uint16_t v; - uint32_t mss, sumd; - int hlen; - int advance; + u_short st_port, dport, sport, port, sp, dp; + struct in_addr in, inb; + hostmap_t *hm; + u_32_t flags; + u_32_t st_ip; + ipnat_t *np; + nat_t *natl; + int l; - hlen = tcp->th_off << 2; - if (hlen > sizeof(*tcp)) { - cp = (uint8_t *)tcp + sizeof(*tcp); - ep = (uint8_t *)tcp + hlen; + /* + * If it's an outbound packet which doesn't match any existing + * record, then create a new port + */ + l = 0; + hm = NULL; + np = ni->nai_np; + st_ip = np->in_nip; + st_port = np->in_pnext; + flags = ni->nai_flags; + sport = ni->nai_sport; + dport = ni->nai_dport; - while (cp < ep) { - opt = cp[0]; - if (opt == TCPOPT_EOL) - break; - else if (opt == TCPOPT_NOP) { - cp++; - continue; - } - - if (&cp[1] >= ep) - break; - advance = cp[1]; - if (&cp[advance] > ep) - break; - switch (opt) { - case TCPOPT_MAXSEG: - if (advance != 4) - break; - memcpy(&v, &cp[2], sizeof(v)); - mss = ntohs(v); - if (mss > maxmss) { - v = htons(maxmss); - memcpy(&cp[2], &v, sizeof(v)); - CALC_SUMD(mss, maxmss, sumd); - fix_outcksum(fin, csump, sumd); - } - break; - default: - /* ignore unknown options */ - break; - } - - cp += advance; + /* + * Do a loop until we either run out of entries to try or we find + * a NAT mapping that isn't currently being used. This is done + * because the change to the source is not (usually) being fixed. + */ + do { + port = 0; + in.s_addr = htonl(np->in_nip); + if (l == 0) { + /* + * Check to see if there is an existing NAT + * setup for this IP address pair. + */ + hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, + in, 0); + if (hm != NULL) + in.s_addr = hm->hm_mapip.s_addr; + } else if ((l == 1) && (hm != NULL)) { + nat_hostmapdel(hm); + hm = NULL; } + in.s_addr = ntohl(in.s_addr); + + nat->nat_hm = hm; + + if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { + if (l > 0) + return -1; + } + + if (np->in_redir == NAT_BIMAP && + np->in_inmsk == np->in_outmsk) { + /* + * map the address block in a 1:1 fashion + */ + in.s_addr = np->in_outip; + in.s_addr |= fin->fin_saddr & ~np->in_inmsk; + in.s_addr = ntohl(in.s_addr); + + } else if (np->in_redir & NAT_MAPBLK) { + if ((l >= np->in_ppip) || ((l > 0) && + !(flags & IPN_TCPUDP))) + return -1; + /* + * map-block - Calculate destination address. + */ + in.s_addr = ntohl(fin->fin_saddr); + in.s_addr &= ntohl(~np->in_inmsk); + inb.s_addr = in.s_addr; + in.s_addr /= np->in_ippip; + in.s_addr &= ntohl(~np->in_outmsk); + in.s_addr += ntohl(np->in_outip); + /* + * Calculate destination port. + */ + if ((flags & IPN_TCPUDP) && + (np->in_ppip != 0)) { + port = ntohs(sport) + l; + port %= np->in_ppip; + port += np->in_ppip * + (inb.s_addr % np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + + } else if ((np->in_outip == 0) && + (np->in_outmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if ((l > 0) || + fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, + &in, NULL) == -1) + return -1; + in.s_addr = ntohl(in.s_addr); + + } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) { + /* + * 0/0 - use the original source address/port. + */ + if (l > 0) + return -1; + in.s_addr = ntohl(fin->fin_saddr); + + } else if ((np->in_outmsk != 0xffffffff) && + (np->in_pnext == 0) && ((l > 0) || (hm == NULL))) + np->in_nip++; + + natl = NULL; + + if ((flags & IPN_TCPUDP) && + ((np->in_redir & NAT_MAPBLK) == 0) && + (np->in_flags & IPN_AUTOPORTMAP)) { + /* + * "ports auto" (without map-block) + */ + if ((l > 0) && (l % np->in_ppip == 0)) { + if (l > np->in_space) { + return -1; + } else if ((l > np->in_ppip) && + np->in_outmsk != 0xffffffff) + np->in_nip++; + } + if (np->in_ppip != 0) { + port = ntohs(sport); + port += (l % np->in_ppip); + port %= np->in_ppip; + port += np->in_ppip * + (ntohl(fin->fin_saddr) % + np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + + } else if (((np->in_redir & NAT_MAPBLK) == 0) && + (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { + /* + * Standard port translation. Select next port. + */ + port = htons(np->in_pnext++); + + if (np->in_pnext > ntohs(np->in_pmax)) { + np->in_pnext = ntohs(np->in_pmin); + if (np->in_outmsk != 0xffffffff) + np->in_nip++; + } + } + + if (np->in_flags & IPN_IPRANGE) { + if (np->in_nip > ntohl(np->in_outmsk)) + np->in_nip = ntohl(np->in_outip); + } else { + if ((np->in_outmsk != 0xffffffff) && + ((np->in_nip + 1) & ntohl(np->in_outmsk)) > + ntohl(np->in_outip)) + np->in_nip = ntohl(np->in_outip) + 1; + } + + if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY))) + port = sport; + + /* + * Here we do a lookup of the connection as seen from + * the outside. If an IP# pair already exists, try + * again. So if you have A->B becomes C->B, you can + * also have D->E become C->E but not D->B causing + * another C->B. Also take protocol and ports into + * account when determining whether a pre-existing + * NAT setup will cause an external conflict where + * this is appropriate. + */ + inb.s_addr = htonl(in.s_addr); + sp = fin->fin_data[0]; + dp = fin->fin_data[1]; + fin->fin_data[0] = fin->fin_data[1]; + fin->fin_data[1] = htons(port); + natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), + (u_int)fin->fin_p, fin->fin_dst, inb); + fin->fin_data[0] = sp; + fin->fin_data[1] = dp; + + /* + * Has the search wrapped around and come back to the + * start ? + */ + if ((natl != NULL) && + (np->in_pnext != 0) && (st_port == np->in_pnext) && + (np->in_nip != 0) && (st_ip == np->in_nip)) + return -1; + l++; + } while (natl != NULL); + + if (np->in_space > 0) + np->in_space--; + + /* Setup the NAT table */ + nat->nat_inip = fin->fin_src; + nat->nat_outip.s_addr = htonl(in.s_addr); + nat->nat_oip = fin->fin_dst; + if (nat->nat_hm == NULL) + nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, + nat->nat_outip, 0); + + /* + * The ICMP checksum does not have a pseudo header containing + * the IP addresses + */ + ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); + ni->nai_sum2 = LONG_SUM(in.s_addr); + if ((flags & IPN_TCPUDP)) { + ni->nai_sum1 += ntohs(sport); + ni->nai_sum2 += ntohs(port); } + + if (flags & IPN_TCPUDPICMP) { + nat->nat_inport = sport; + nat->nat_outport = port; /* sport */ + nat->nat_oport = dport; + ((tcphdr_t *)fin->fin_dp)->th_sport = port; + } if (flags & IPN_ICMPQUERY) { + ((icmphdr_t *)fin->fin_dp)->icmp_id = port; + nat->nat_inport = port; + nat->nat_outport = port; + } + ni->nai_ip.s_addr = htonl(in.s_addr); + ni->nai_port = port; + ni->nai_nport = dport; + return 0; } -/* - * Create a new NAT table entry. - * NOTE: Assumes write lock on ipf_nat has been obtained already. - * If you intend on changing this, beware: appr_new() may call nat_new() - * recursively! - */ -nat_t *nat_new(fin, ip, np, natsave, flags, direction) + +/* ------------------------------------------------------------------------ */ +/* Function: nat_newrdr */ +/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */ +/* allow rule to be moved if IPN_ROUNDR is set. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT entry */ +/* ni(I) - pointer to structure with misc. information needed */ +/* to create new NAT entry. */ +/* */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_newrdr(fin, nat, ni) +fr_info_t *fin; +nat_t *nat; +natinfo_t *ni; +{ + u_short nport, dport, sport; + struct in_addr in; + hostmap_t *hm; + u_32_t flags; + ipnat_t *np; + int move; + + move = 1; + hm = NULL; + in = ni->nai_ip; + np = ni->nai_np; + flags = ni->nai_flags; + sport = ni->nai_sport; + dport = ni->nai_dport; + + /* + * If the matching rule has IPN_STICKY set, then we want to have the + * same rule kick in as before. Why would this happen? If you have + * a collection of rdr rules with "round-robin sticky", the current + * packet might match a different one to the previous connection but + * we want the same destination to be used. + */ + if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == + (IPN_ROUNDR|IPN_STICKY)) { + hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, + (u_32_t)dport); + if (hm != NULL) { + ni->nai_ip.s_addr = hm->hm_mapip.s_addr; + np = hm->hm_ipnat; + ni->nai_np = np; + move = 0; + } + } + + /* + * Otherwise, it's an inbound packet. Most likely, we don't + * want to rewrite source ports and source addresses. Instead, + * we want to rewrite to a fixed internal address and fixed + * internal port. + */ + if (np->in_flags & IPN_SPLIT) { + in.s_addr = np->in_nip; + + if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { + hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, + in, (u_32_t)dport); + if (hm != NULL) { + in.s_addr = hm->hm_mapip.s_addr; + move = 0; + } + } + + if (hm == NULL || hm->hm_ref == 1) { + if (np->in_inip == htonl(in.s_addr)) { + np->in_nip = ntohl(np->in_inmsk); + move = 0; + } else { + np->in_nip = ntohl(np->in_inip); + } + } + + } else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL) == -1) + return -1; + in.s_addr = ntohl(in.s_addr); + + } else if ((np->in_inip == 0) && (np->in_inmsk== 0)) { + /* + * 0/0 - use the original destination address/port. + */ + in.s_addr = ntohl(fin->fin_daddr); + + } else if (np->in_redir == NAT_BIMAP && + np->in_inmsk == np->in_outmsk) { + /* + * map the address block in a 1:1 fashion + */ + in.s_addr |= ntohl(fin->fin_daddr & ~np->in_inmsk); + + } else { + in.s_addr = ntohl(np->in_inip); + } + + if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0)) + nport = dport; + else { + /* + * Whilst not optimized for the case where + * pmin == pmax, the gain is not significant. + */ + if (np->in_pmin != np->in_pmax) { + nport = ntohs(dport) - ntohs(np->in_pmin) + + ntohs(np->in_pnext); + nport = htons(nport); + } else + nport = np->in_pnext; + } + + /* + * When the redirect-to address is set to 0.0.0.0, just + * assume a blank `forwarding' of the packet. We don't + * setup any translation for this either. + */ + if (in.s_addr == 0) { + if (nport == dport) + return -1; + in.s_addr = ntohl(fin->fin_daddr); + } + + nat->nat_inip.s_addr = htonl(in.s_addr); + nat->nat_outip = fin->fin_dst; + nat->nat_oip = fin->fin_src; + + ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport); + ni->nai_sum2 = LONG_SUM(in.s_addr) + ntohs(nport); + + ni->nai_ip.s_addr = in.s_addr; + ni->nai_nport = nport; + ni->nai_port = sport; + + if (flags & IPN_TCPUDP) { + nat->nat_inport = nport; + nat->nat_outport = dport; + nat->nat_oport = sport; + ((tcphdr_t *)fin->fin_dp)->th_dport = nport; + } else if (flags & IPN_ICMPQUERY) { + ((icmphdr_t *)fin->fin_dp)->icmp_id = nport; + nat->nat_inport = nport; + nat->nat_outport = nport; + } + + return move; +} + +/* ------------------------------------------------------------------------ */ +/* Function: nat_new */ +/* Returns: nat_t* - NULL == failure to create new NAT structure, */ +/* else pointer to new NAT structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* np(I) - pointer to NAT rule */ +/* natsave(I) - pointer to where to store NAT struct pointer */ +/* flags(I) - flags describing the current packet */ +/* direction(I) - direction of packet (in/out) */ +/* Write Lock: ipf_nat */ +/* */ +/* Attempts to create a new NAT entry. Does not actually change the packet */ +/* in any way. */ +/* */ +/* This fucntion is in three main parts: (1) deal with creating a new NAT */ +/* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */ +/* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */ +/* and (3) building that structure and putting it into the NAT table(s). */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_new(fin, np, natsave, flags, direction) fr_info_t *fin; -ip_t *ip; ipnat_t *np; nat_t **natsave; u_int flags; int direction; { - register u_32_t sum1, sum2, sumd, l; u_short port = 0, sport = 0, dport = 0, nport = 0; - struct in_addr in, inb; - u_short nflags, sp, dp; tcphdr_t *tcp = NULL; hostmap_t *hm = NULL; + struct in_addr in; nat_t *nat, *natl; -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - qif_t *qf = fin->fin_qif; + u_int nflags; + natinfo_t ni; + u_32_t sumd; + int move; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) + qpktinfo_t *qpi = fin->fin_qpi; #endif - nflags = flags & np->in_flags; - if (flags & IPN_TCPUDP) { - tcp = (tcphdr_t *)fin->fin_dp; - sport = htons(fin->fin_data[0]); - dport = htons(fin->fin_data[1]); + if (nat_stats.ns_inuse >= ipf_nattable_max) { + nat_stats.ns_memfail++; + return NULL; } + move = 1; + nflags = np->in_flags & flags; + nflags &= NAT_FROMRULE; + + ni.nai_np = np; + ni.nai_nflags = nflags; + ni.nai_flags = flags; + /* Give me a new nat */ KMALLOC(nat, nat_t *); if (nat == NULL) { nat_stats.ns_memfail++; + /* + * Try to automatically tune the max # of entries in the + * table allowed to be less than what will cause kmem_alloc() + * to fail and try to eliminate panics due to out of memory + * conditions arising. + */ + if (ipf_nattable_max > ipf_nattable_sz) { + ipf_nattable_max = nat_stats.ns_inuse - 100; + printf("ipf_nattable_max reduced to %d\n", + ipf_nattable_max); + } return NULL; } + if (flags & IPN_TCPUDP) { + tcp = fin->fin_dp; + ni.nai_sport = htons(fin->fin_sport); + ni.nai_dport = htons(fin->fin_dport); + } else if (flags & IPN_ICMPQUERY) { + /* + * In the ICMP query NAT code, we translate the ICMP id fields + * to make them unique. This is indepedent of the ICMP type + * (e.g. in the unlikely event that a host sends an echo and + * an tstamp request with the same id, both packets will have + * their ip address/id field changed in the same way). + */ + /* The icmp_id field is used by the sender to identify the + * process making the icmp request. (the receiver justs + * copies it back in its response). So, it closely matches + * the concept of source port. We overlay sport, so we can + * maximally reuse the existing code. + */ + ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id; + ni.nai_dport = ni.nai_sport; + } + bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; - if (flags & FI_WILDP) - nat_stats.ns_wilds++; + + MUTEX_ENTER(&ipf_nat_new); + /* * Search the current table for a match. */ if (direction == NAT_OUTBOUND) { /* - * Values at which the search for a free resouce starts. + * We can now arrange to call this for the same connection + * because ipf_nat_new doesn't protect the code path into + * this function. */ - u_32_t st_ip; - u_short st_port; - - /* - * If it's an outbound packet which doesn't match any existing - * record, then create a new port - */ - l = 0; - st_ip = np->in_nip; - st_port = np->in_pnext; - - do { - port = 0; - in.s_addr = htonl(np->in_nip); - if (l == 0) { - /* - * Check to see if there is an existing NAT - * setup for this IP address pair. - */ - hm = nat_hostmap(np, fin->fin_src, in); - if (hm != NULL) - in.s_addr = hm->hm_mapip.s_addr; - } else if ((l == 1) && (hm != NULL)) { - nat_hostmapdel(hm); - hm = NULL; - } - in.s_addr = ntohl(in.s_addr); - - nat->nat_hm = hm; - - if ((np->in_outmsk == 0xffffffff) && - (np->in_pnext == 0)) { - if (l > 0) - goto badnat; - } - - if (np->in_redir & NAT_MAPBLK) { - if ((l >= np->in_ppip) || ((l > 0) && - !(flags & IPN_TCPUDP))) - goto badnat; - /* - * map-block - Calculate destination address. - */ - in.s_addr = ntohl(fin->fin_saddr); - in.s_addr &= ntohl(~np->in_inmsk); - inb.s_addr = in.s_addr; - in.s_addr /= np->in_ippip; - in.s_addr &= ntohl(~np->in_outmsk); - in.s_addr += ntohl(np->in_outip); - /* - * Calculate destination port. - */ - if ((flags & IPN_TCPUDP) && - (np->in_ppip != 0)) { - port = ntohs(sport) + l; - port %= np->in_ppip; - port += np->in_ppip * - (inb.s_addr % np->in_ippip); - port += MAPBLK_MINPORT; - port = htons(port); - } - } else if (!np->in_outip && - (np->in_outmsk == 0xffffffff)) { - /* - * 0/32 - use the interface's IP address. - */ - if ((l > 0) || - fr_ifpaddr(4, fin->fin_ifp, &in) == -1) - goto badnat; - in.s_addr = ntohl(in.s_addr); - } else if (!np->in_outip && !np->in_outmsk) { - /* - * 0/0 - use the original source address/port. - */ - if (l > 0) - goto badnat; - in.s_addr = ntohl(fin->fin_saddr); - } else if ((np->in_outmsk != 0xffffffff) && - (np->in_pnext == 0) && - ((l > 0) || (hm == NULL))) - np->in_nip++; - natl = NULL; - - if ((nflags & IPN_TCPUDP) && - ((np->in_redir & NAT_MAPBLK) == 0) && - (np->in_flags & IPN_AUTOPORTMAP)) { - if ((l > 0) && (l % np->in_ppip == 0)) { - if (l > np->in_space) { - goto badnat; - } else if ((l > np->in_ppip) && - np->in_outmsk != 0xffffffff) - np->in_nip++; - } - if (np->in_ppip != 0) { - port = ntohs(sport); - port += (l % np->in_ppip); - port %= np->in_ppip; - port += np->in_ppip * - (ntohl(fin->fin_saddr) % - np->in_ippip); - port += MAPBLK_MINPORT; - port = htons(port); - } - } else if (((np->in_redir & NAT_MAPBLK) == 0) && - (nflags & IPN_TCPUDP) && - (np->in_pnext != 0)) { - port = htons(np->in_pnext++); - if (np->in_pnext > ntohs(np->in_pmax)) { - np->in_pnext = ntohs(np->in_pmin); - if (np->in_outmsk != 0xffffffff) - np->in_nip++; - } - } - - if (np->in_flags & IPN_IPRANGE) { - if (np->in_nip > ntohl(np->in_outmsk)) - np->in_nip = ntohl(np->in_outip); - } else { - if ((np->in_outmsk != 0xffffffff) && - ((np->in_nip + 1) & ntohl(np->in_outmsk)) > - ntohl(np->in_outip)) - np->in_nip = ntohl(np->in_outip) + 1; - } - - if (!port && (flags & IPN_TCPUDP)) - port = sport; - - /* - * Here we do a lookup of the connection as seen from - * the outside. If an IP# pair already exists, try - * again. So if you have A->B becomes C->B, you can - * also have D->E become C->E but not D->B causing - * another C->B. Also take protocol and ports into - * account when determining whether a pre-existing - * NAT setup will cause an external conflict where - * this is appropriate. - */ - inb.s_addr = htonl(in.s_addr); - sp = fin->fin_data[0]; - dp = fin->fin_data[1]; - fin->fin_data[0] = fin->fin_data[1]; - fin->fin_data[1] = htons(port); - natl = nat_inlookup(fin, flags & ~FI_WILDP, - (u_int)fin->fin_p, fin->fin_dst, - inb, 1); - fin->fin_data[0] = sp; - fin->fin_data[1] = dp; - - /* - * Has the search wrapped around and come back to the - * start ? - */ - if ((natl != NULL) && - (np->in_pnext != 0) && (st_port == np->in_pnext) && - (np->in_nip != 0) && (st_ip == np->in_nip)) - goto badnat; - l++; - } while (natl != NULL); - - if (np->in_space > 0) - np->in_space--; - - /* Setup the NAT table */ - nat->nat_inip = fin->fin_src; - nat->nat_outip.s_addr = htonl(in.s_addr); - nat->nat_oip = fin->fin_dst; - if (nat->nat_hm == NULL) - nat->nat_hm = nat_hostmap(np, fin->fin_src, - nat->nat_outip); - - sum1 = LONG_SUM(ntohl(fin->fin_saddr)) + ntohs(sport); - sum2 = LONG_SUM(in.s_addr) + ntohs(port); - - if (flags & IPN_TCPUDP) { - nat->nat_inport = sport; - nat->nat_outport = port; /* sport */ - nat->nat_oport = dport; + natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p, + fin->fin_src, fin->fin_dst); + if (natl != NULL) { + MUTEX_EXIT(&ipf_nat_new); + return natl; } + + move = nat_newmap(fin, nat, &ni); + if (move == -1) + goto badnat; + + np = ni.nai_np; + in = ni.nai_ip; } else { /* - * Otherwise, it's an inbound packet. Most likely, we don't - * want to rewrite source ports and source addresses. Instead, - * we want to rewrite to a fixed internal address and fixed - * internal port. + * NAT_INBOUND is used only for redirects rules */ - if (np->in_flags & IPN_SPLIT) { - in.s_addr = np->in_nip; - if (np->in_inip == htonl(in.s_addr)) - np->in_nip = ntohl(np->in_inmsk); - else { - np->in_nip = ntohl(np->in_inip); - if (np->in_flags & IPN_ROUNDR) { - nat_delrdr(np); - nat_addrdr(np); - } - } - } else { - in.s_addr = ntohl(np->in_inip); - if (np->in_flags & IPN_ROUNDR) { - nat_delrdr(np); - nat_addrdr(np); - } - } - if (!np->in_pnext) - nport = dport; - else { - /* - * Whilst not optimized for the case where - * pmin == pmax, the gain is not significant. - */ - if (np->in_pmin != np->in_pmax) { - nport = ntohs(dport) - ntohs(np->in_pmin) + - ntohs(np->in_pnext); - nport = ntohs(nport); - } else - nport = np->in_pnext; + natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p, + fin->fin_src, fin->fin_dst); + if (natl != NULL) { + MUTEX_EXIT(&ipf_nat_new); + return natl; } - /* - * When the redirect-to address is set to 0.0.0.0, just - * assume a blank `forwarding' of the packet. - */ - if (in.s_addr == 0) - in.s_addr = ntohl(fin->fin_daddr); + move = nat_newrdr(fin, nat, &ni); + if (move == -1) + goto badnat; - nat->nat_inip.s_addr = htonl(in.s_addr); - nat->nat_outip = fin->fin_dst; - nat->nat_oip = fin->fin_src; + np = ni.nai_np; + in = ni.nai_ip; + } + port = ni.nai_port; + nport = ni.nai_nport; - sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport); - sum2 = LONG_SUM(in.s_addr) + ntohs(nport); - - if (flags & IPN_TCPUDP) { - nat->nat_inport = nport; - nat->nat_outport = dport; - nat->nat_oport = sport; + if ((move == 1) && (np->in_flags & IPN_ROUNDR)) { + if (np->in_redir == NAT_REDIRECT) { + nat_delrdr(np); + nat_addrdr(np); + } else if (np->in_redir == NAT_MAP) { + nat_delnat(np); + nat_addnat(np); } } - CALC_SUMD(sum1, sum2, sumd); + if (flags & IPN_TCPUDP) { + sport = ni.nai_sport; + dport = ni.nai_dport; + } else if (flags & IPN_ICMPQUERY) { + sport = ni.nai_sport; + dport = 0; + } + + CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - if ((flags & IPN_TCPUDP) && dohwcksum && - (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) + if ((flags & IPN_TCP) && dohwcksum && + (((ill_t *)qpi->qpi_ill)->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { if (direction == NAT_OUTBOUND) - sum1 = LONG_SUM(ntohl(in.s_addr)); + ni.nai_sum1 = LONG_SUM(ntohl(in.s_addr)); else - sum1 = LONG_SUM(ntohl(fin->fin_saddr)); - sum1 += LONG_SUM(ntohl(fin->fin_daddr)); - sum1 += IPPROTO_TCP; - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff); + ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); + ni.nai_sum1 += LONG_SUM(ntohl(fin->fin_daddr)); + ni.nai_sum1 += 30; + ni.nai_sum1 = (ni.nai_sum1 & 0xffff) + (ni.nai_sum1 >> 16); + nat->nat_sumd[1] = NAT_HW_CKSUM|(ni.nai_sum1 & 0xffff); } else #endif nat->nat_sumd[1] = nat->nat_sumd[0]; - if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) { + if ((flags & IPN_TCPUDPICMP) && ((sport != port) || (dport != nport))) { if (direction == NAT_OUTBOUND) - sum1 = LONG_SUM(ntohl(fin->fin_saddr)); + ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); else - sum1 = LONG_SUM(ntohl(fin->fin_daddr)); + ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)); - sum2 = LONG_SUM(in.s_addr); + ni.nai_sum2 = LONG_SUM(in.s_addr); - CALC_SUMD(sum1, sum2, sumd); + CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); - } else - nat->nat_ipsumd = nat->nat_sumd[0]; - - in.s_addr = htonl(in.s_addr); - - strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ); - - nat->nat_me = natsave; - nat->nat_dir = direction; - nat->nat_ifp = fin->fin_ifp; - nat->nat_ptr = np; - nat->nat_mssclamp = np->in_mssclamp; - nat->nat_p = fin->fin_p; - nat->nat_bytes = 0; - nat->nat_pkts = 0; - nat->nat_fr = fin->fin_fr; - if (nat->nat_fr != NULL) { - ATOMIC_INC32(nat->nat_fr->fr_ref); - } - if (direction == NAT_OUTBOUND) { - if (flags & IPN_TCPUDP) - tcp->th_sport = port; } else { - if (flags & IPN_TCPUDP) - tcp->th_dport = nport; + nat->nat_ipsumd = nat->nat_sumd[0]; + if (!(flags & IPN_TCPUDPICMP)) { + nat->nat_sumd[0] = 0; + nat->nat_sumd[1] = 0; + } } - nat_insert(nat); - - if ((np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && dport == np->in_dport))) - (void) appr_new(fin, ip, nat); - - np->in_use++; -#ifdef IPFILTER_LOG - nat_log(nat, (u_int)np->in_redir); -#endif + if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) { + if ((hm = nat->nat_hm) != NULL) + nat_hostmapdel(hm); + MUTEX_EXIT(&ipf_nat_new); + KFREE(nat); + return NULL; + } + if (flags & SI_WILDP) + nat_stats.ns_wilds++; + MUTEX_EXIT(&ipf_nat_new); return nat; badnat: nat_stats.ns_badnat++; if ((hm = nat->nat_hm) != NULL) nat_hostmapdel(hm); + MUTEX_EXIT(&ipf_nat_new); KFREE(nat); return NULL; } -/* - * Insert a NAT entry into the hash tables for searching and add it to the - * list of active NAT entries. Adjust global counters when complete. - */ -void nat_insert(nat) +/* ------------------------------------------------------------------------ */ +/* Function: nat_finalise */ +/* Returns: int - 0 == sucess, -1 == failure */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT entry */ +/* ni(I) - pointer to structure with misc. information needed */ +/* to create new NAT entry. */ +/* Write Lock: ipf_nat */ +/* */ +/* This is the tail end of constructing a new NAT entry and is the same */ +/* for both IPv4 and IPv6. */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction) +fr_info_t *fin; +nat_t *nat; +natinfo_t *ni; +tcphdr_t *tcp; +nat_t **natsave; +int direction; +{ + frentry_t *fr; + ipnat_t *np; + + np = ni->nai_np; + + COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0]); +#ifdef IPFILTER_SYNC + if ((nat->nat_flags & SI_CLONE) == 0) + nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); +#endif + + nat->nat_me = natsave; + nat->nat_dir = direction; + nat->nat_ifps[0] = fin->fin_ifp; + nat->nat_ptr = np; + nat->nat_p = fin->fin_p; + nat->nat_mssclamp = np->in_mssclamp; + fr = fin->fin_fr; + nat->nat_fr = fr; + + if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) + if (appr_new(fin, nat) == -1) + return -1; + + if (nat_insert(nat, fin->fin_rev) == 0) { + if (nat_logging) + nat_log(nat, (u_int)np->in_redir); + np->in_use++; + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + MUTEX_EXIT(&fr->fr_lock); + } + return 0; + } + + /* + * nat_insert failed, so cleanup time... + */ + return -1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_insert */ +/* Returns: int - 0 == sucess, -1 == failure */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* rev(I) - flag indicating forward/reverse direction of packet */ +/* Write Lock: ipf_nat */ +/* */ +/* Insert a NAT entry into the hash tables for searching and add it to the */ +/* list of active NAT entries. Adjust global counters when complete. */ +/* ------------------------------------------------------------------------ */ +int nat_insert(nat, rev) nat_t *nat; +int rev; { u_int hv1, hv2; nat_t **natp; - MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL); - - nat->nat_age = fr_defnatage; - nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0'; - if (nat->nat_ifname[0] !='\0') { - nat->nat_ifp = GETUNIT(nat->nat_ifname, 4); - } - - nat->nat_next = nat_instances; - nat_instances = nat; - - if (!(nat->nat_flags & (FI_W_SPORT|FI_W_DPORT))) { + /* + * Try and return an error as early as possible, so calculate the hash + * entry numbers first and then proceed. + */ + if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) { hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, @@ -1593,20 +2333,54 @@ nat_t *nat; hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, - ipf_nattable_sz); + ipf_nattable_sz); } else { - hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, nat->nat_inip.s_addr, - ipf_nattable_sz); - hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, nat->nat_outip.s_addr, - ipf_nattable_sz); + hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); + hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz); + hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); + hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz); } + if (nat_stats.ns_bucketlen[0][hv1] >= fr_nat_maxbucket || + nat_stats.ns_bucketlen[1][hv2] >= fr_nat_maxbucket) { + return -1; + } + + nat->nat_hv[0] = hv1; + nat->nat_hv[1] = hv2; + + MUTEX_INIT(&nat->nat_lock, "nat entry lock"); + + nat->nat_ref = 1; + nat->nat_bytes[0] = 0; + nat->nat_pkts[0] = 0; + nat->nat_bytes[1] = 0; + nat->nat_pkts[1] = 0; + + nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; + if (nat->nat_ifnames[0][0] !='\0') { + nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4); + } + nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0'; + if (nat->nat_ifnames[1][0] !='\0') { + nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], 4); + } else { + nat->nat_ifps[1] = nat->nat_ifps[0]; + } + + nat->nat_next = nat_instances; + nat->nat_pnext = &nat_instances; + if (nat_instances) + nat_instances->nat_pnext = &nat->nat_next; + nat_instances = nat; + natp = &nat_table[0][hv1]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + nat_stats.ns_bucketlen[0][hv1]++; natp = &nat_table[1][hv2]; if (*natp) @@ -1614,44 +2388,63 @@ nat_t *nat; nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; + nat_stats.ns_bucketlen[1][hv2]++; + + fr_setnatqueue(nat, rev); nat_stats.ns_added++; nat_stats.ns_inuse++; + return 0; } -nat_t *nat_icmplookup(ip, fin, dir) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: nat_icmperrorlookup */ +/* Returns: nat_t* - point to matching NAT structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* dir(I) - direction of packet (in/out) */ +/* */ +/* Check if the ICMP error message is related to an existing TCP, UDP or */ +/* ICMP query nat entry. */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_icmperrorlookup(fin, dir) fr_info_t *fin; int dir; { - icmphdr_t *icmp; - tcphdr_t *tcp = NULL; - ip_t *oip; int flags = 0, type, minlen; + icmphdr_t *icmp, *orgicmp; + tcphdr_t *tcp = NULL; + u_short data[2]; + nat_t *nat; + ip_t *oip; + u_int p; - icmp = (icmphdr_t *)fin->fin_dp; + icmp = fin->fin_dp; /* * Does it at least have the return (basic) IP header ? * Only a basic IP header (no options) should be with an ICMP error * header. */ - if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN)) + if (fin->fin_hlen != sizeof(ip_t) || + (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; + type = icmp->icmp_type; + /* * If it's not an error type, then return. */ - if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && - (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && - (type != ICMP_PARAMPROB)) + if (!nat_icmperrortype4(type)) return NULL; + /* + * Check packet size + */ oip = (ip_t *)((char *)fin->fin_dp + 8); - minlen = (oip->ip_hl << 2); + minlen = IP_HL(oip) << 2; if (minlen < sizeof(ip_t)) return NULL; - if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) + if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) return NULL; /* * Is the buffer big enough for all of it ? It's the size of the IP @@ -1666,104 +2459,134 @@ int dir; { mb_t *m; -# if SOLARIS - m = fin->fin_qfm; + m = fin->fin_m; +# if defined(MENTAT) if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) return NULL; # else - m = *(mb_t **)fin->fin_mp; if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > - (char *)ip + m->m_len) + (char *)fin->fin_ip + M_LEN(m)) return NULL; # endif } #endif - if (oip->ip_p == IPPROTO_TCP) + p = oip->ip_p; + if (p == IPPROTO_TCP) flags = IPN_TCP; - else if (oip->ip_p == IPPROTO_UDP) + else if (p == IPPROTO_UDP) flags = IPN_UDP; - if (flags & IPN_TCPUDP) { - u_short data[2]; - nat_t *nat; + else if (p == IPPROTO_ICMP) { + orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); + /* see if this is related to an ICMP query */ + if (nat_icmpquerytype4(orgicmp->icmp_type)) { + data[0] = fin->fin_data[0]; + data[1] = fin->fin_data[1]; + fin->fin_data[0] = 0; + fin->fin_data[1] = orgicmp->icmp_id; + + flags = IPN_ICMPERR|IPN_ICMPQUERY; + /* + * NOTE : dir refers to the direction of the original + * ip packet. By definition the icmp error + * message flows in the opposite direction. + */ + if (dir == NAT_INBOUND) + nat = nat_inlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); + else + nat = nat_outlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); + fin->fin_data[0] = data[0]; + fin->fin_data[1] = data[1]; + return nat; + } + } + + if (flags & IPN_TCPUDP) { minlen += 8; /* + 64bits of data to get ports */ - if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) + if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) return NULL; data[0] = fin->fin_data[0]; data[1] = fin->fin_data[1]; - tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); + tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); fin->fin_data[0] = ntohs(tcp->th_dport); fin->fin_data[1] = ntohs(tcp->th_sport); if (dir == NAT_INBOUND) { - nat = nat_inlookup(fin, flags, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + nat = nat_inlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); } else { - nat = nat_outlookup(fin, flags, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + nat = nat_outlookup(fin, flags, p, oip->ip_dst, + oip->ip_src); } fin->fin_data[0] = data[0]; fin->fin_data[1] = data[1]; return nat; } if (dir == NAT_INBOUND) - return nat_inlookup(fin, 0, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); else - return nat_outlookup(fin, 0, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); } -/* - * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP - * packet gets correctly recognised. - */ -nat_t *nat_icmp(ip, fin, nflags, dir) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: nat_icmperror */ +/* Returns: nat_t* - point to matching NAT structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* nflags(I) - NAT flags for this packet */ +/* dir(I) - direction of packet (in/out) */ +/* */ +/* Fix up an ICMP packet which is an error message for an existing NAT */ +/* session. This will correct both packet header data and checksums. */ +/* */ +/* This should *ONLY* be used for incoming ICMP error packets to make sure */ +/* a NAT'd ICMP packet gets correctly recognised. */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_icmperror(fin, nflags, dir) fr_info_t *fin; u_int *nflags; int dir; { - u_32_t sum1, sum2, sumd, sumd2 = 0; + u_32_t sum1, sum2, sumd, sumd2; struct in_addr in; - int flags, dlen; icmphdr_t *icmp; + int flags, dlen; udphdr_t *udp; tcphdr_t *tcp; nat_t *nat; ip_t *oip; - if ((fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) + if ((fin->fin_flx & (FI_SHORT|FI_FRAGTAIL))) return NULL; /* - * nat_icmplookup() will return NULL for `defective' packets. + * nat_icmperrorlookup() will return NULL for `defective' packets. */ - if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) + if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir))) return NULL; flags = 0; + sumd2 = 0; *nflags = IPN_ICMPERR; - icmp = (icmphdr_t *)fin->fin_dp; + icmp = fin->fin_dp; oip = (ip_t *)&icmp->icmp_ip; if (oip->ip_p == IPPROTO_TCP) flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) flags = IPN_UDP; - udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); - dlen = ip->ip_len - ((char *)udp - (char *)ip); - /* - * XXX - what if this is bogus hl and we go off the end ? - * In this case, nat_icmplookup() will have returned NULL. - */ + else if (oip->ip_p == IPPROTO_ICMP) + flags = IPN_ICMPQUERY; + udp = (udphdr_t *)((((char *)oip) + (IP_HL(oip) << 2))); tcp = (tcphdr_t *)udp; + dlen = fin->fin_plen - ((char *)udp - (char *)fin->fin_ip); /* * Need to adjust ICMP header to include the real IP#'s and * port #'s. Only apply a checksum change relative to the - * IP address change as it will be modified again in ip_natout + * IP address change as it will be modified again in fr_checknatout * for both address and port. Two checksum changes are * necessary for the two header address changes. Be careful * to only modify the checksum once for the port # and twice @@ -1781,7 +2604,6 @@ int dir; * checksum. So, we must compensate that as well. Even worse, the * change in the UDP and TCP checksums require yet another * adjustment of the ICMP checksum of the ICMP error message. - * */ if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { @@ -1803,28 +2625,30 @@ int dir; * Fix IP checksum of the offending IP packet to adjust for * the change in the IP address. * - * Normally, you would expect that the ICMP checksum of the + * Normally, you would expect that the ICMP checksum of the * ICMP error message needs to be adjusted as well for the * IP address change in oip. - * However, this is a NOP, because the ICMP checksum is + * However, this is a NOP, because the ICMP checksum is * calculated over the complete ICMP packet, which includes the - * changed oip IP addresses and oip->ip_sum. However, these + * changed oip IP addresses and oip->ip_sum. However, these * two changes cancel each other out (if the delta for - * the IP address is x, then the delta for ip_sum is minus x), + * the IP address is x, then the delta for ip_sum is minus x), * so no change in the icmp_cksum is necessary. * * Be careful that nat_dir refers to the direction of the * offending IP packet (oip), not to its ICMP response (icmp) */ fix_datacksum(&oip->ip_sum, sumd); + /* Fix icmp cksum : IP Addr + Cksum */ + sumd2 = (sumd << 1); /* * Fix UDP pseudo header checksum to compensate for the * IP address change. */ - if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + if ((oip->ip_p == IPPROTO_UDP) && (udp->uh_sum != 0)) { /* - * The UDP checksum is optional, only adjust it + * The UDP checksum is optional, only adjust it * if it has been set. */ sum1 = ntohs(udp->uh_sum); @@ -1832,55 +2656,56 @@ int dir; sum2 = ntohs(udp->uh_sum); /* - * Fix ICMP checksum to compensate the UDP + * Fix ICMP checksum to compensate the UDP * checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); - sumd2 = sumd; + sumd2 += sumd; } /* - * Fix TCP pseudo header checksum to compensate for the + * Fix TCP pseudo header checksum to compensate for the * IP address change. Before we can do the change, we * must make sure that oip is sufficient large to hold * the TCP checksum (normally it does not!). */ if (oip->ip_p == IPPROTO_TCP && dlen >= 18) { - + sum1 = ntohs(tcp->th_sum); fix_datacksum(&tcp->th_sum, sumd); sum2 = ntohs(tcp->th_sum); /* - * Fix ICMP checksum to compensate the TCP - * checksum adjustment. + * Fix ICMP checksum to compensate the TCP checksum + * adjustment. */ CALC_SUMD(sum1, sum2, sumd); - sumd2 = sumd; + sumd2 += sumd; } } else { - /* * Fix IP checksum of the offending IP packet to adjust for * the change in the IP address. * - * Normally, you would expect that the ICMP checksum of the + * Normally, you would expect that the ICMP checksum of the * ICMP error message needs to be adjusted as well for the * IP address change in oip. - * However, this is a NOP, because the ICMP checksum is + * However, this is a NOP, because the ICMP checksum is * calculated over the complete ICMP packet, which includes the - * changed oip IP addresses and oip->ip_sum. However, these + * changed oip IP addresses and oip->ip_sum. However, these * two changes cancel each other out (if the delta for - * the IP address is x, then the delta for ip_sum is minus x), + * the IP address is x, then the delta for ip_sum is minus x), * so no change in the icmp_cksum is necessary. * * Be careful that nat_dir refers to the direction of the * offending IP packet (oip), not to its ICMP response (icmp) */ fix_datacksum(&oip->ip_sum, sumd); + /* Fix icmp cksum : IP Addr + Cksum */ + sumd2 = (sumd << 1); /* XXX FV : without having looked at Solaris source code, it seems unlikely - * that SOLARIS would compensate this in the kernel (a body of an IP packet + * that SOLARIS would compensate this in the kernel (a body of an IP packet * in the data section of an ICMP packet). I have the feeling that this should * be unconditional, but I'm not in a position to check. */ @@ -1889,41 +2714,41 @@ int dir; * Fix UDP pseudo header checksum to compensate for the * IP address change. */ - if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + if ((oip->ip_p == IPPROTO_UDP) && (udp->uh_sum != 0)) { /* - * The UDP checksum is optional, only adjust it - * if it has been set + * The UDP checksum is optional, only adjust it + * if it has been set */ sum1 = ntohs(udp->uh_sum); fix_datacksum(&udp->uh_sum, sumd); sum2 = ntohs(udp->uh_sum); /* - * Fix ICMP checksum to compensate the UDP + * Fix ICMP checksum to compensate the UDP * checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); - sumd2 = sumd; + sumd2 += sumd; } - /* - * Fix TCP pseudo header checksum to compensate for the + /* + * Fix TCP pseudo header checksum to compensate for the * IP address change. Before we can do the change, we * must make sure that oip is sufficient large to hold * the TCP checksum (normally it does not!). */ if (oip->ip_p == IPPROTO_TCP && dlen >= 18) { - + sum1 = ntohs(tcp->th_sum); fix_datacksum(&tcp->th_sum, sumd); sum2 = ntohs(tcp->th_sum); /* - * Fix ICMP checksum to compensate the TCP - * checksum adjustment. + * Fix ICMP checksum to compensate the TCP checksum + * adjustment. */ CALC_SUMD(sum1, sum2, sumd); - sumd2 = sumd; + sumd2 += sumd; } #endif } @@ -1970,23 +2795,23 @@ int dir; * The UDP checksum is optional, only adjust * it if it has been set. */ - if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + if ((oip->ip_p == IPPROTO_UDP) && + (udp->uh_sum != 0)) { sum1 = ntohs(udp->uh_sum); fix_datacksum(&udp->uh_sum, sumd); sum2 = ntohs(udp->uh_sum); /* - * Fix ICMP checksum to - * compensate UDP checksum - * adjustment. + * Fix ICMP checksum to compenstate + * UDP checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); sumd2 += sumd; } /* - * Fix tcp checksum (if present) to compensate + * Fix TCP checksum (if present) to compensate * port adjustment. NOTE : the offending IP * packet flows the other direction compared to * the ICMP message. @@ -1998,9 +2823,8 @@ int dir; sum2 = ntohs(tcp->th_sum); /* - * Fix ICMP checksum to - * compensate TCP checksum - * adjustment. + * Fix ICMP checksum to compensate + * TCP checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); sumd2 += sumd; @@ -2008,6 +2832,8 @@ int dir; } } else { if (tcp->th_dport != nat->nat_outport) { + udphdr_t *udp = (udphdr_t *)tcp; + /* * Fix ICMP checksum to compensate port * adjustment. @@ -2019,7 +2845,7 @@ int dir; tcp->th_dport = nat->nat_outport; /* - * Fix udp checksum to compensate port + * Fix UDP checksum to compensate port * adjustment. NOTE : the offending IP * packet flows the other direction compared * to the ICMP message. @@ -2027,7 +2853,8 @@ int dir; * The UDP checksum is optional, only adjust * it if it has been set. */ - if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + if ((oip->ip_p == IPPROTO_UDP) && + (udp->uh_sum != 0)) { sum1 = ntohs(udp->uh_sum); fix_datacksum(&udp->uh_sum, sumd); @@ -2042,7 +2869,7 @@ int dir; } /* - * Fix tcp checksum (if present) to compensate + * Fix TCP checksum (if present) to compensate * port adjustment. NOTE : the offending IP * packet flows the other direction compared to * the ICMP message. @@ -2055,50 +2882,97 @@ int dir; /* * Fix ICMP checksum to compensate - * UDP checksum adjustment. + * TCP checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); sumd2 += sumd; } } } - if (sumd2) { + if (sumd2 != 0) { sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); - if (nat->nat_dir == NAT_OUTBOUND) { + if (nat->nat_dir == NAT_INBOUND) { fix_outcksum(fin, &icmp->icmp_cksum, sumd2); } else { fix_incksum(fin, &icmp->icmp_cksum, sumd2); } } + } else if ((flags & IPN_ICMPQUERY) != 0) { + icmphdr_t *orgicmp; + + /* + * XXX - what if this is bogus hl and we go off the end ? + * In this case, nat_icmperrorlookup() will have returned NULL. + */ + orgicmp = (icmphdr_t *)udp; + + if (nat->nat_dir == NAT_OUTBOUND) { + if (orgicmp->icmp_id != nat->nat_inport) { + + /* + * Fix ICMP checksum (of the offening ICMP + * query packet) to compensate the change + * in the ICMP id of the offending ICMP + * packet. + * + * Since you modify orgicmp->icmp_id with + * a delta (say x) and you compensate that + * in origicmp->icmp_cksum with a delta + * minus x, you don't have to adjust the + * overall icmp->icmp_cksum + */ + sum1 = ntohs(orgicmp->icmp_id); + sum2 = ntohs(nat->nat_inport); + CALC_SUMD(sum1, sum2, sumd); + orgicmp->icmp_id = nat->nat_inport; + fix_datacksum(&orgicmp->icmp_cksum, sumd); + } + } /* nat_dir == NAT_INBOUND is impossible for icmp queries */ } - if (oip->ip_p == IPPROTO_ICMP) - nat->nat_age = fr_defnaticmpage; return nat; } /* - * NB: these lookups don't lock access to the list, it assume it has already - * been done! + * NB: these lookups don't lock access to the list, it assumed that it has + * already been done! */ -/* - * Lookup a nat entry based on the mapped destination ip address/port and - * real source address/port. We use this lookup when receiving a packet, - * we're looking for a table entry, based on the destination address. - * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. - */ -nat_t *nat_inlookup(fin, flags, p, src, mapdst, rw) + +/* ------------------------------------------------------------------------ */ +/* Function: nat_inlookup */ +/* Returns: nat_t* - NULL == no match, */ +/* else pointer to matching NAT entry */ +/* Parameters: fin(I) - pointer to packet information */ +/* flags(I) - NAT flags for this packet */ +/* p(I) - protocol for this packet */ +/* src(I) - source IP address */ +/* mapdst(I) - destination IP address */ +/* */ +/* Lookup a nat entry based on the mapped destination ip address/port and */ +/* real source address/port. We use this lookup when receiving a packet, */ +/* we're looking for a table entry, based on the destination address. */ +/* */ +/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ +/* */ +/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ +/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ +/* */ +/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ +/* the packet is of said protocol */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_inlookup(fin, flags, p, src, mapdst) fr_info_t *fin; -register u_int flags, p; +u_int flags, p; struct in_addr src , mapdst; -int rw; { - register u_short sport, dport; - register nat_t *nat; - register int nflags; - register u_32_t dst; + u_short sport, dport; + grehdr_t *gre; ipnat_t *ipn; + u_int sflags; + nat_t *nat; + int nflags; + u_32_t dst; void *ifp; u_int hv; @@ -2106,26 +2980,74 @@ int rw; ifp = fin->fin_ifp; else ifp = NULL; + sport = 0; + dport = 0; + gre = NULL; dst = mapdst.s_addr; - if (flags & IPN_TCPUDP) { + sflags = flags & NAT_TCPUDPICMP; + + switch (p) + { + case IPPROTO_TCP : + case IPPROTO_UDP : sport = htons(fin->fin_data[0]); dport = htons(fin->fin_data[1]); - } else { - sport = 0; - dport = 0; + break; + case IPPROTO_ICMP : + if (flags & IPN_ICMPERR) + sport = fin->fin_data[1]; + else + dport = fin->fin_data[1]; + break; + case IPPROTO_GRE : + gre = fin->fin_dp; + break; + default : + break; } + + if ((flags & SI_WILDP) != 0) + goto find_in_wild_ports; + hv = NAT_HASH_FN(dst, dport, 0xffffffff); hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz); nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; - if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_oip.s_addr == src.s_addr && + + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[0]) + continue; + } else { + if (ifp != nat->nat_ifps[1]) + continue; + } + } + + if (nat->nat_oip.s_addr == src.s_addr && nat->nat_outip.s_addr == dst && - ((p == 0) || (p == nat->nat_p))) { + (((p == 0) && + (sflags == (nat->nat_flags & IPN_TCPUDPICMP))) + || (p == nat->nat_p))) { switch (p) { +#if 0 + case IPPROTO_GRE : + if (gre->gr_call != nat->nat_gre.gs_call) + continue; + break; +#endif + case IPPROTO_ICMP : + if ((flags & IPN_ICMPERR) != 0) { + if (nat->nat_outport != sport) + continue; + } else { + if (nat->nat_outport != dport) + continue; + } + break; case IPPROTO_TCP : case IPPROTO_UDP : if (nat->nat_oport != sport) @@ -2144,56 +3066,94 @@ int rw; return nat; } } - if (!nat_stats.ns_wilds || !(flags & FI_WILDP)) + + /* + * So if we didn't find it but there are wildcard members in the hash + * table, go back and look for them. We do this search and update here + * because it is modifying the NAT table and we want to do this only + * for the first packet that matches. The exception, of course, is + * for "dummy" (FI_IGNORE) lookups. + */ +find_in_wild_ports: + if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) return NULL; - if (!rw) { - RWLOCK_EXIT(&ipf_nat); - } + if (nat_stats.ns_wilds == 0) + return NULL; + + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(dst, 0, 0xffffffff); - hv = NAT_HASH_FN(src.s_addr, dst, ipf_nattable_sz); - if (!rw) { - WRITE_ENTER(&ipf_nat); - } + hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz); + + WRITE_ENTER(&ipf_nat); + nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { - nflags = nat->nat_flags; - if (ifp && ifp != nat->nat_ifp) - continue; - if (!(nflags & FI_WILDP)) + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[0]) + continue; + } else { + if (ifp != nat->nat_ifps[1]) + continue; + } + } + + if (nat->nat_p != fin->fin_p) continue; if (nat->nat_oip.s_addr != src.s_addr || nat->nat_outip.s_addr != dst) continue; - if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && - ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { - nat_tabmove(fin, nat); + + nflags = nat->nat_flags; + if (!(nflags & (NAT_TCPUDP|SI_WILDP))) + continue; + + if (nat_wildok(nat, (int)sport, (int)dport, nflags, + NAT_INBOUND) == 1) { + if ((fin->fin_flx & FI_IGNORE) != 0) + break; + if ((nflags & SI_CLONE) != 0) { + nat = fr_natclone(fin, nat); + if (nat == NULL) + break; + } else { + MUTEX_ENTER(&ipf_nat_new); + nat_stats.ns_wilds--; + MUTEX_EXIT(&ipf_nat_new); + } + nat->nat_oport = sport; + nat->nat_outport = dport; + nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); + nat_tabmove(nat); break; } } - if (!rw) { - MUTEX_DOWNGRADE(&ipf_nat); - } + + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } -/* - * This function is only called for TCP/UDP NAT table entries where the - * original was placed in the table without hashing on the ports and we now - * want to include hashing on port numbers. - */ -static void nat_tabmove(fin, nat) -fr_info_t *fin; +/* ------------------------------------------------------------------------ */ +/* Function: nat_tabmove */ +/* Returns: Nil */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* Write Lock: ipf_nat */ +/* */ +/* This function is only called for TCP/UDP NAT table entries where the */ +/* original was placed in the table without hashing on the ports and we now */ +/* want to include hashing on port numbers. */ +/* ------------------------------------------------------------------------ */ +static void nat_tabmove(nat) nat_t *nat; { - register u_short sport, dport; - u_int hv, nflags; nat_t **natp; + u_int hv; - nflags = nat->nat_flags; - - sport = ntohs(fin->fin_data[0]); - dport = ntohs(fin->fin_data[1]); + if (nat->nat_flags & SI_CLONE) + return; /* * Remove the NAT entry from the old location @@ -2201,76 +3161,133 @@ nat_t *nat; if (nat->nat_hnext[0]) nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; *nat->nat_phnext[0] = nat->nat_hnext[0]; + nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--; if (nat->nat_hnext[1]) nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; *nat->nat_phnext[1] = nat->nat_hnext[1]; + nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; /* * Add into the NAT table in the new position */ - hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, 0xffffffff); - hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff); + hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, + ipf_nattable_sz); + nat->nat_hv[0] = hv; natp = &nat_table[0][hv]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + nat_stats.ns_bucketlen[0][hv]++; - hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, 0xffffffff); - hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff); + hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport, + ipf_nattable_sz); + nat->nat_hv[1] = hv; natp = &nat_table[1][hv]; if (*natp) (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; + nat_stats.ns_bucketlen[1][hv]++; } -/* - * Lookup a nat entry based on the source 'real' ip address/port and - * destination address/port. We use this lookup when sending a packet out, - * we're looking for a table entry, based on the source address. - * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. - */ -nat_t *nat_outlookup(fin, flags, p, src, dst, rw) +/* ------------------------------------------------------------------------ */ +/* Function: nat_outlookup */ +/* Returns: nat_t* - NULL == no match, */ +/* else pointer to matching NAT entry */ +/* Parameters: fin(I) - pointer to packet information */ +/* flags(I) - NAT flags for this packet */ +/* p(I) - protocol for this packet */ +/* src(I) - source IP address */ +/* dst(I) - destination IP address */ +/* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */ +/* */ +/* Lookup a nat entry based on the source 'real' ip address/port and */ +/* destination address/port. We use this lookup when sending a packet out, */ +/* we're looking for a table entry, based on the source address. */ +/* */ +/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ +/* */ +/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */ +/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */ +/* */ +/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */ +/* the packet is of said protocol */ +/* ------------------------------------------------------------------------ */ +nat_t *nat_outlookup(fin, flags, p, src, dst) fr_info_t *fin; -register u_int flags, p; +u_int flags, p; struct in_addr src , dst; -int rw; { - register u_short sport, dport; - register nat_t *nat; - register int nflags; + u_short sport, dport; + u_int sflags; ipnat_t *ipn; u_32_t srcip; + nat_t *nat; + int nflags; void *ifp; u_int hv; ifp = fin->fin_ifp; srcip = src.s_addr; - if (flags & IPN_TCPUDP) { - sport = ntohs(fin->fin_data[0]); - dport = ntohs(fin->fin_data[1]); - } else { - sport = 0; - dport = 0; + sflags = flags & IPN_TCPUDPICMP; + sport = 0; + dport = 0; + + switch (p) + { + case IPPROTO_TCP : + case IPPROTO_UDP : + sport = htons(fin->fin_data[0]); + dport = htons(fin->fin_data[1]); + break; + case IPPROTO_ICMP : + if (flags & IPN_ICMPERR) + sport = fin->fin_data[1]; + else + dport = fin->fin_data[1]; + break; + default : + break; } + if ((flags & SI_WILDP) != 0) + goto find_out_wild_ports; + hv = NAT_HASH_FN(srcip, sport, 0xffffffff); hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz); nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; - if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_inip.s_addr == srcip && + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[1]) + continue; + } else { + if (ifp != nat->nat_ifps[0]) + continue; + } + } + + if (nat->nat_inip.s_addr == srcip && nat->nat_oip.s_addr == dst.s_addr && - ((p == 0) || (p == nat->nat_p))) { + (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP))) + || (p == nat->nat_p))) { switch (p) { +#if 0 + case IPPROTO_GRE : + if (gre->gr_call != nat->nat_gre.gs_call) + continue; + break; +#endif case IPPROTO_TCP : case IPPROTO_UDP : if (nat->nat_oport != dport) @@ -2289,47 +3306,92 @@ int rw; return nat; } } - if (!nat_stats.ns_wilds || !(flags & FI_WILDP)) - return NULL; - if (!rw) { - RWLOCK_EXIT(&ipf_nat); - } - hv = NAT_HASH_FN(dst.s_addr, srcip, ipf_nattable_sz); - if (!rw) { - WRITE_ENTER(&ipf_nat); - } + /* + * So if we didn't find it but there are wildcard members in the hash + * table, go back and look for them. We do this search and update here + * because it is modifying the NAT table and we want to do this only + * for the first packet that matches. The exception, of course, is + * for "dummy" (FI_IGNORE) lookups. + */ +find_out_wild_ports: + if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) + return NULL; + if (nat_stats.ns_wilds == 0) + return NULL; + + RWLOCK_EXIT(&ipf_nat); + + hv = NAT_HASH_FN(srcip, 0, 0xffffffff); + hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz); + + WRITE_ENTER(&ipf_nat); + nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { - nflags = nat->nat_flags; - if (ifp && ifp != nat->nat_ifp) - continue; - if (!(nflags & FI_WILDP)) + if (ifp != NULL) { + if (nat->nat_dir == NAT_REDIRECT) { + if (ifp != nat->nat_ifps[1]) + continue; + } else { + if (ifp != nat->nat_ifps[0]) + continue; + } + } + + if (nat->nat_p != fin->fin_p) continue; if ((nat->nat_inip.s_addr != srcip) || (nat->nat_oip.s_addr != dst.s_addr)) continue; - if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) && - ((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) { - nat_tabmove(fin, nat); + + nflags = nat->nat_flags; + if (!(nflags & (NAT_TCPUDP|SI_WILDP))) + continue; + + if (nat_wildok(nat, (int)sport, (int)dport, nflags, + NAT_OUTBOUND) == 1) { + if ((fin->fin_flx & FI_IGNORE) != 0) + break; + if ((nflags & SI_CLONE) != 0) { + nat = fr_natclone(fin, nat); + if (nat == NULL) + break; + } else { + MUTEX_ENTER(&ipf_nat_new); + nat_stats.ns_wilds--; + MUTEX_EXIT(&ipf_nat_new); + } + nat->nat_inport = sport; + nat->nat_oport = dport; + if (nat->nat_outport == 0) + nat->nat_outport = sport; + nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); + nat_tabmove(nat); break; } } - if (!rw) { - MUTEX_DOWNGRADE(&ipf_nat); - } + + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } -/* - * Lookup the NAT tables to search for a matching redirect - */ +/* ------------------------------------------------------------------------ */ +/* Function: nat_lookupredir */ +/* Returns: nat_t* - NULL == no match, */ +/* else pointer to matching NAT entry */ +/* Parameters: np(I) - pointer to description of packet to find NAT table */ +/* entry for. */ +/* */ +/* Lookup the NAT tables to search for a matching redirect */ +/* ------------------------------------------------------------------------ */ nat_t *nat_lookupredir(np) -register natlookup_t *np; +natlookup_t *np; { - nat_t *nat; fr_info_t fi; + nat_t *nat; bzero((char *)&fi, sizeof(fi)); fi.fin_data[0] = ntohs(np->nl_inport); @@ -2340,7 +3402,7 @@ register natlookup_t *np; * ip address. Else, we use the fake. */ if ((nat = nat_outlookup(&fi, np->nl_flags, 0, np->nl_inip, - np->nl_outip, 0))) { + np->nl_outip))) { np->nl_realip = nat->nat_outip; np->nl_realport = nat->nat_outport; } @@ -2348,18 +3410,27 @@ register natlookup_t *np; } -static int nat_match(fin, np, ip) +/* ------------------------------------------------------------------------ */ +/* Function: nat_match */ +/* Returns: int - 0 == no match, 1 == match */ +/* Parameters: fin(I) - pointer to packet information */ +/* np(I) - pointer to NAT rule */ +/* */ +/* Pull the matching of a packet against a NAT rule out of that complex */ +/* loop inside fr_checknatin() and lay it out properly in its own function. */ +/* ------------------------------------------------------------------------ */ +static int nat_match(fin, np) fr_info_t *fin; ipnat_t *np; -ip_t *ip; { frtuc_t *ft; - if (ip->ip_v != 4) + if (fin->fin_v != 4) return 0; if (np->in_p && fin->fin_p != np->in_p) return 0; + if (fin->fin_out) { if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) return 0; @@ -2381,321 +3452,427 @@ ip_t *ip; } ft = &np->in_tuc; - if (!(fin->fin_fl & FI_TCPUDP) || - (fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) { + if (!(fin->fin_flx & FI_TCPUDP) || + (fin->fin_flx & (FI_SHORT|FI_FRAGTAIL))) { if (ft->ftu_scmp || ft->ftu_dcmp) return 0; return 1; } - return fr_tcpudpchk(ft, fin); + return fr_tcpudpchk(fin, ft); } -/* - * Packets going out on the external interface go through this. - * Here, the source address requires alteration, if anything. - */ -int ip_natout(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: nat_update */ +/* Returns: Nil */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* np(I) - pointer to NAT rule */ +/* */ +/* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */ +/* called with fin_rev updated - i.e. after calling nat_proto(). */ +/* ------------------------------------------------------------------------ */ +void nat_update(fin, nat, np) fr_info_t *fin; +nat_t *nat; +ipnat_t *np; { - register ipnat_t *np = NULL; - register u_32_t ipa; - tcphdr_t *tcp = NULL; - u_short sport = 0, dport = 0, *csump = NULL; - int natadd = 1, i, icmpset = 1; - u_int nflags = 0, hv, msk; - struct ifnet *ifp; - frentry_t *fr; - void *sifp; - u_32_t iph; - nat_t *nat; + ipftq_t *ifq, *ifq2; + ipftqent_t *tqe; - if (nat_list == NULL || (fr_nat_lock)) + MUTEX_ENTER(&nat->nat_lock); + tqe = &nat->nat_tqe; + ifq = tqe->tqe_ifq; + + /* + * We allow over-riding of NAT timeouts from NAT rules, even for + * TCP, however, if it is TCP and there is no rule timeout set, + * then do not update the timeout here. + */ + if (np != NULL) + ifq2 = np->in_tqehead[fin->fin_rev]; + else + ifq2 = NULL; + + if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) { + (void) fr_tcp_age(&nat->nat_tqe, fin, nat_tqb, 0); + } else { + if (ifq2 == NULL) { + if (nat->nat_p == IPPROTO_UDP) + ifq2 = &nat_udptq; + else if (nat->nat_p == IPPROTO_ICMP) + ifq2 = &nat_icmptq; + else + ifq2 = &nat_iptq; + } + + fr_movequeue(tqe, ifq, ifq2); + } + MUTEX_EXIT(&nat->nat_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checknatout */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 0 == no packet translation occurred, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(I) - pointer to filtering result flags */ +/* */ +/* Check to see if an outcoming packet should be changed. ICMP packets are */ +/* first checked to see if they match an existing entry (if an error), */ +/* otherwise a search of the current NAT table is made. If neither results */ +/* in a match then a search for a matching NAT rule is made. Create a new */ +/* NAT entry if a we matched a NAT rule. Lastly, actually change the */ +/* packet header(s) as required. */ +/* ------------------------------------------------------------------------ */ +int fr_checknatout(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + icmphdr_t *icmp = NULL; + tcphdr_t *tcp = NULL; + ipnat_t *np = NULL; + struct ifnet *ifp; + u_int nflags = 0; + u_32_t ipa, iph; + int natadd = 1; + frentry_t *fr; + nat_t *nat; + int rval; + + if (nat_list == NULL || fr_nat_lock != 0) return 0; - if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && - fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) { - sifp = fin->fin_ifp; - fin->fin_ifp = fr->fr_tif.fd_ifp; - } else - sifp = fin->fin_ifp; - ifp = fin->fin_ifp; + fr = fin->fin_fr; + if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && + fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) + ifp = fr->fr_tif.fd_ifp; + else + ifp = fin->fin_ifp; - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { - if (fin->fin_p == IPPROTO_TCP) + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + switch (fin->fin_p) + { + case IPPROTO_TCP : nflags = IPN_TCP; - else if (fin->fin_p == IPPROTO_UDP) + break; + case IPPROTO_UDP : nflags = IPN_UDP; - if ((nflags & IPN_TCPUDP)) { - tcp = (tcphdr_t *)fin->fin_dp; - sport = tcp->th_sport; - dport = tcp->th_dport; + break; + case IPPROTO_ICMP : + icmp = fin->fin_dp; + + /* + * This is an incoming packet, so the destination is + * the icmp_id and the source port equals 0 + */ + if (nat_icmpquerytype4(icmp->icmp_type)) + nflags = IPN_ICMPQUERY; + break; + default : + break; } + + if ((nflags & IPN_TCPUDP)) + tcp = fin->fin_dp; } ipa = fin->fin_saddr; READ_ENTER(&ipf_nat); - if ((fin->fin_p == IPPROTO_ICMP) && - (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) - icmpset = 1; - else if ((fin->fin_fl & FI_FRAG) && - (nat = ipfr_nat_knownfrag(ip, fin))) + if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && + (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) + /*EMPTY*/; + else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) natadd = 0; - else if ((nat = nat_outlookup(fin, nflags|FI_WILDP|FI_WILDA, - (u_int)fin->fin_p, fin->fin_src, - fin->fin_dst, 0))) { + else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, + fin->fin_src, fin->fin_dst))) { nflags = nat->nat_flags; - if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { - if ((nflags & FI_W_SPORT) && - (nat->nat_inport != sport)) - nat->nat_inport = sport; - if ((nflags & FI_W_DPORT) && - (nat->nat_oport != dport)) - nat->nat_oport = dport; - - if (nat->nat_outport == 0) - nat->nat_outport = sport; - nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); - nflags = nat->nat_flags; - nat_stats.ns_wilds--; - } } else { - RWLOCK_EXIT(&ipf_nat); + u_32_t hv, msk, nmsk; - msk = 0xffffffff; - i = 32; - - WRITE_ENTER(&ipf_nat); /* * If there is no current entry in the nat table for this IP#, * create one for it (if there is a matching rule). */ + RWLOCK_EXIT(&ipf_nat); + msk = 0xffffffff; + nmsk = nat_masks; + WRITE_ENTER(&ipf_nat); maskloop: iph = ipa & htonl(msk); hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); for (np = nat_rules[hv]; np; np = np->in_mnext) { - if (np->in_ifp && (np->in_ifp != ifp)) + if ((np->in_ifps[0] && (np->in_ifps[0] != ifp))) continue; - if ((np->in_flags & IPN_RF) && - !(np->in_flags & nflags)) + if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) continue; if (np->in_flags & IPN_FILTER) { - if (!nat_match(fin, np, ip)) + if (!nat_match(fin, np)) continue; } else if ((ipa & np->in_inmsk) != np->in_inip) continue; - if (*np->in_plabel && !appr_ok(ip, tcp, np)) + + if ((fr != NULL) && + !fr_matchtag(&np->in_tag, &fr->fr_nattag)) continue; - nat = nat_new(fin, ip, np, NULL, - (u_int)nflags, NAT_OUTBOUND); - if (nat != NULL) { + + if (*np->in_plabel != '\0') { + if (((np->in_flags & IPN_FILTER) == 0) && + (np->in_dport != tcp->th_dport)) + continue; + if (appr_ok(fin, tcp, np) == 0) + continue; + } + + if ((nat = nat_new(fin, np, NULL, nflags, + NAT_OUTBOUND))) { np->in_hits++; break; } } - if ((np == NULL) && (i > 0)) { - do { - i--; + if ((np == NULL) && (nmsk != 0)) { + while (nmsk) { msk <<= 1; - } while ((i >= 0) && ((nat_masks & (1 << i)) == 0)); - if (i >= 0) + if (nmsk & 0x80000000) + break; + nmsk <<= 1; + } + if (nmsk != 0) { + nmsk <<= 1; goto maskloop; + } } MUTEX_DOWNGRADE(&ipf_nat); } - /* - * NOTE: ipf_nat must now only be held as a read lock - */ - if (nat) { - np = nat->nat_ptr; - if (natadd && (fin->fin_fl & FI_FRAG) && np) - ipfr_nat_newfrag(ip, fin, nat); - MUTEX_ENTER(&nat->nat_lock); - if (fin->fin_p != IPPROTO_TCP) { - if (np && np->in_age[1]) - nat->nat_age = np->in_age[1]; - else if (!icmpset && (fin->fin_p == IPPROTO_ICMP)) - nat->nat_age = fr_defnaticmpage; - else - nat->nat_age = fr_defnatage; + if (nat != NULL) { + rval = fr_natout(fin, nat, natadd, nflags); + if (rval == 1) { + MUTEX_ENTER(&nat->nat_lock); + nat->nat_ref++; + MUTEX_EXIT(&nat->nat_lock); + fin->fin_nat = nat; } - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&nat->nat_lock); + } else + rval = 0; + RWLOCK_EXIT(&ipf_nat); - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ - if (nflags == IPN_ICMPERR) { - u_32_t s1, s2, sumd; - - s1 = LONG_SUM(ntohl(fin->fin_saddr)); - s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); - CALC_SUMD(s1, s2, sumd); - - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(fin, &ip->ip_sum, sumd); - else - fix_incksum(fin, &ip->ip_sum, sumd); - } -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) - else { - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); - else - fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); - } -#endif - /* - * Only change the packet contents, not what is filtered upon. - */ - ip->ip_src = nat->nat_outip; - - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { - - if ((nat->nat_outport != 0) && (tcp != NULL)) { - tcp->th_sport = nat->nat_outport; - fin->fin_data[0] = ntohs(tcp->th_sport); - } - - if (fin->fin_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - MUTEX_ENTER(&nat->nat_lock); - fr_tcp_age(&nat->nat_age, - nat->nat_tcpstate, fin, 1, 0); - if (nat->nat_age < fr_defnaticmpage) - nat->nat_age = fr_defnaticmpage; -#ifdef LARGE_NAT - else if (nat->nat_age > fr_defnatage) - nat->nat_age = fr_defnatage; -#endif - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - - /* - * Do a MSS CLAMPING on a SYN packet, - * only deal IPv4 for now. - */ - if (nat->nat_mssclamp && - (tcp->th_flags & TH_SYN) != 0) - tcp_mss_clamp(tcp, nat->nat_mssclamp, fin, csump); - - MUTEX_EXIT(&nat->nat_lock); - } else if (fin->fin_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } - - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(fin, csump, - nat->nat_sumd[1]); - else - fix_incksum(fin, csump, - nat->nat_sumd[1]); - } - } - - if (np && (np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && dport == np->in_dport))) { - i = appr_check(ip, fin, nat); - if (i == 0) - i = 1; - else if (i == -1) - nat->nat_drop[1]++; - } else - i = 1; - ATOMIC_INCL(nat_stats.ns_mapped[1]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - fin->fin_ifp = sifp; - return i; + if (rval == -1) { + if (passp != NULL) + *passp = FR_BLOCK; + fin->fin_flx |= FI_BADNAT; } - RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ - fin->fin_ifp = sifp; - return 0; + return rval; +} + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natout */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* natadd(I) - flag indicating if it is safe to add frag cache */ +/* nflags(I) - NAT flags set for this packet */ +/* */ +/* Translate a packet coming "out" on an interface. */ +/* ------------------------------------------------------------------------ */ +int fr_natout(fin, nat, natadd, nflags) +fr_info_t *fin; +nat_t *nat; +int natadd; +u_32_t nflags; +{ + icmphdr_t *icmp; + u_short *csump; + tcphdr_t *tcp; + ipnat_t *np; + int i; + + tcp = NULL; + icmp = NULL; + csump = NULL; + np = nat->nat_ptr; + + if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL) && + (np->in_flags & IPN_FRAG)) + (void) fr_nat_newfrag(fin, 0, nat); + + MUTEX_ENTER(&nat->nat_lock); + nat->nat_bytes[1] += fin->fin_plen; + nat->nat_pkts[1]++; + MUTEX_EXIT(&nat->nat_lock); + + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + */ + if (nflags == IPN_ICMPERR) { + u_32_t s1, s2, sumd; + + s1 = LONG_SUM(ntohl(fin->fin_saddr)); + s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); + CALC_SUMD(s1, s2, sumd); + + if (fin->fin_v == 4) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd); + else + fix_incksum(fin, &fin->fin_ip->ip_sum, sumd); + } + } +#if !defined(_KERNEL) || (defined(MENTAT) || defined(__sgi)) + else if (fin->fin_v == 4) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(fin, &fin->fin_ip->ip_sum, + nat->nat_ipsumd); + else + fix_incksum(fin, &fin->fin_ip->ip_sum, + nat->nat_ipsumd); + } +#endif + fin->fin_ip->ip_src = nat->nat_outip; + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { + tcp = fin->fin_dp; + + tcp->th_sport = nat->nat_outport; + fin->fin_data[0] = ntohs(nat->nat_outport); + } + + if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { + icmp = fin->fin_dp; + icmp->icmp_id = nat->nat_outport; + } + + csump = nat_proto(fin, nat, nflags); + } + + nat_update(fin, nat, np); + + if (csump != NULL) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(fin, csump, nat->nat_sumd[1]); + else + fix_incksum(fin, csump, nat->nat_sumd[1]); + } +#ifdef IPFILTER_SYNC + ipfsync_update(SMC_NAT, fin, nat->nat_sync); +#endif + /* ------------------------------------------------------------- */ + /* A few quick notes: */ + /* Following are test conditions prior to calling the */ + /* appr_check routine. */ + /* */ + /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ + /* with a redirect rule, we attempt to match the packet's */ + /* source port against in_dport, otherwise we'd compare the */ + /* packet's destination. */ + /* ------------------------------------------------------------- */ + if ((np != NULL) && (np->in_apr != NULL)) { + i = appr_check(fin, nat); + if (i == 0) + i = 1; + } else + i = 1; + ATOMIC_INCL(nat_stats.ns_mapped[1]); + fin->fin_flx |= FI_NATED; + return i; } -/* - * Packets coming in from the external interface go through this. - * Here, the destination address requires alteration, if anything. - */ -int ip_natin(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_checknatin */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 0 == no packet translation occurred, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* passp(I) - pointer to filtering result flags */ +/* */ +/* Check to see if an incoming packet should be changed. ICMP packets are */ +/* first checked to see if they match an existing entry (if an error), */ +/* otherwise a search of the current NAT table is made. If neither results */ +/* in a match then a search for a matching NAT rule is made. Create a new */ +/* NAT entry if a we matched a NAT rule. Lastly, actually change the */ +/* packet header(s) as required. */ +/* ------------------------------------------------------------------------ */ +int fr_checknatin(fin, passp) fr_info_t *fin; +u_32_t *passp; { - register struct in_addr src; - register struct in_addr in; - register ipnat_t *np; - u_short sport = 0, dport = 0, *csump = NULL; - u_int nflags = 0, natadd = 1, hv, msk; - struct ifnet *ifp = fin->fin_ifp; - tcphdr_t *tcp = NULL; - int i, icmpset = 0; + u_int nflags, natadd; + struct ifnet *ifp; + struct in_addr in; + icmphdr_t *icmp; + tcphdr_t *tcp; + u_short dport; + ipnat_t *np; nat_t *nat; u_32_t iph; + int rval; - if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock)) + if (nat_list == NULL || fr_nat_lock != 0) return 0; - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { - if (fin->fin_p == IPPROTO_TCP) + tcp = NULL; + icmp = NULL; + dport = 0; + natadd = 1; + nflags = 0; + ifp = fin->fin_ifp; + + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + switch (fin->fin_p) + { + case IPPROTO_TCP : nflags = IPN_TCP; - else if (fin->fin_p == IPPROTO_UDP) + break; + case IPPROTO_UDP : nflags = IPN_UDP; + break; + case IPPROTO_ICMP : + icmp = fin->fin_dp; + + /* + * This is an incoming packet, so the destination is + * the icmp_id and the source port equals 0 + */ + if (nat_icmpquerytype4(icmp->icmp_type)) { + nflags = IPN_ICMPQUERY; + dport = icmp->icmp_id; + } break; + default : + break; + } + if ((nflags & IPN_TCPUDP)) { - tcp = (tcphdr_t *)fin->fin_dp; - sport = tcp->th_sport; + tcp = fin->fin_dp; dport = tcp->th_dport; } } in = fin->fin_dst; - /* make sure the source address is to be redirected */ - src = fin->fin_src; READ_ENTER(&ipf_nat); - if ((fin->fin_p == IPPROTO_ICMP) && - (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) - icmpset = 1; - else if ((fin->fin_fl & FI_FRAG) && - (nat = ipfr_nat_knownfrag(ip, fin))) + if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && + (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) + /*EMPTY*/; + else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) natadd = 0; - else if ((nat = nat_inlookup(fin, nflags|FI_WILDP|FI_WILDA, - (u_int)fin->fin_p, fin->fin_src, in, 0))) { + else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p, + fin->fin_src, in))) { nflags = nat->nat_flags; - if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { - if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT)) - nat->nat_oport = sport; - if ((nat->nat_outport != dport) && - (nflags & FI_W_SPORT)) - nat->nat_outport = dport; - nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); - nflags = nat->nat_flags; - nat_stats.ns_wilds--; - } } else { + u_32_t hv, msk, rmsk; + RWLOCK_EXIT(&ipf_nat); - + rmsk = rdr_masks; msk = 0xffffffff; - i = 32; - WRITE_ENTER(&ipf_nat); /* * If there is no current entry in the nat table for this IP#, @@ -2705,140 +3882,260 @@ maskloop: iph = in.s_addr & htonl(msk); hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz); for (np = rdr_rules[hv]; np; np = np->in_rnext) { - if ((np->in_ifp && (np->in_ifp != ifp)) || - (np->in_p && (np->in_p != fin->fin_p)) || - (np->in_flags && !(nflags & np->in_flags))) + if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) + continue; + if (np->in_p && (np->in_p != fin->fin_p)) + continue; + if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) continue; if (np->in_flags & IPN_FILTER) { - if (!nat_match(fin, np, ip)) + if (!nat_match(fin, np)) + continue; + } else { + if ((in.s_addr & np->in_outmsk) != np->in_outip) + continue; + if (np->in_pmin && + ((ntohs(np->in_pmax) < ntohs(dport)) || + (ntohs(dport) < ntohs(np->in_pmin)))) + continue; + } + + if (*np->in_plabel != '\0') { + if (!appr_ok(fin, tcp, np)) { continue; - } else if ((in.s_addr & np->in_outmsk) != np->in_outip) - continue; - if ((!np->in_pmin || (np->in_flags & IPN_FILTER) || - ((ntohs(np->in_pmax) >= ntohs(dport)) && - (ntohs(dport) >= ntohs(np->in_pmin))))) - if ((nat = nat_new(fin, ip, np, NULL, nflags, - NAT_INBOUND))) { - np->in_hits++; - break; } + } + + nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); + if (nat != NULL) { + np->in_hits++; + break; + } } - if ((np == NULL) && (i > 0)) { - do { - i--; + if ((np == NULL) && (rmsk != 0)) { + while (rmsk) { msk <<= 1; - } while ((i >= 0) && ((rdr_masks & (1 << i)) == 0)); - if (i >= 0) + if (rmsk & 0x80000000) + break; + rmsk <<= 1; + } + if (rmsk != 0) { + rmsk <<= 1; goto maskloop; + } } MUTEX_DOWNGRADE(&ipf_nat); } - - /* - * NOTE: ipf_nat must now only be held as a read lock - */ - if (nat) { - np = nat->nat_ptr; - fin->fin_fr = nat->nat_fr; - if (natadd && (fin->fin_fl & FI_FRAG) && np) - ipfr_nat_newfrag(ip, fin, nat); - if (np && (np->in_apr != NULL) && (np->in_dport == 0 || - (tcp != NULL && sport == np->in_dport))) { - i = appr_check(ip, fin, nat); - if (i == -1) { - nat->nat_drop[0]++; - RWLOCK_EXIT(&ipf_nat); - return i; - } + if (nat != NULL) { + rval = fr_natin(fin, nat, natadd, nflags); + if (rval == 1) { + MUTEX_ENTER(&nat->nat_lock); + nat->nat_ref++; + MUTEX_EXIT(&nat->nat_lock); + fin->fin_nat = nat; + fin->fin_state = nat->nat_state; } + } else + rval = 0; + RWLOCK_EXIT(&ipf_nat); - MUTEX_ENTER(&nat->nat_lock); - if (fin->fin_p != IPPROTO_TCP) { - if (np && np->in_age[0]) - nat->nat_age = np->in_age[0]; - else if (!icmpset && (fin->fin_p == IPPROTO_ICMP)) - nat->nat_age = fr_defnaticmpage; - else - nat->nat_age = fr_defnatage; - } - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&nat->nat_lock); - ip->ip_dst = nat->nat_inip; - fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; - - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) - if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); - else - fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); -#endif - if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { - - if ((nat->nat_inport != 0) && (tcp != NULL)) { - tcp->th_dport = nat->nat_inport; - fin->fin_data[1] = ntohs(tcp->th_dport); - } - - if (fin->fin_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - MUTEX_ENTER(&nat->nat_lock); - fr_tcp_age(&nat->nat_age, - nat->nat_tcpstate, fin, 0, 0); - if (nat->nat_age < fr_defnaticmpage) - nat->nat_age = fr_defnaticmpage; -#ifdef LARGE_NAT - else if (nat->nat_age > fr_defnatage) - nat->nat_age = fr_defnatage; -#endif - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - MUTEX_EXIT(&nat->nat_lock); - } else if (fin->fin_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } - - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(fin, csump, - nat->nat_sumd[0]); - else - fix_outcksum(fin, csump, - nat->nat_sumd[0]); - } - } - ATOMIC_INCL(nat_stats.ns_mapped[0]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - return 1; + if (rval == -1) { + if (passp != NULL) + *passp = FR_BLOCK; + fin->fin_flx |= FI_BADNAT; } - RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ - return 0; + return rval; } -/* - * Free all memory used by NAT structures allocated at runtime. - */ -void ip_natunload() +/* ------------------------------------------------------------------------ */ +/* Function: fr_natin */ +/* Returns: int - -1 == packet failed NAT checks so block it, */ +/* 1 == packet was successfully translated. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* natadd(I) - flag indicating if it is safe to add frag cache */ +/* nflags(I) - NAT flags set for this packet */ +/* Locks Held: ipf_nat (READ) */ +/* */ +/* Translate a packet coming "in" on an interface. */ +/* ------------------------------------------------------------------------ */ +int fr_natin(fin, nat, natadd, nflags) +fr_info_t *fin; +nat_t *nat; +int natadd; +u_32_t nflags; +{ + icmphdr_t *icmp; + u_short *csump; + tcphdr_t *tcp; + ipnat_t *np; + int i; + + tcp = NULL; + csump = NULL; + np = nat->nat_ptr; + fin->fin_fr = nat->nat_fr; + + if (np != NULL) { + if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && + (np->in_flags & IPN_FRAG)) + (void) fr_nat_newfrag(fin, 0, nat); + + /* ------------------------------------------------------------- */ + /* A few quick notes: */ + /* Following are test conditions prior to calling the */ + /* appr_check routine. */ + /* */ + /* A NULL tcp indicates a non TCP/UDP packet. When dealing */ + /* with a map rule, we attempt to match the packet's */ + /* source port against in_dport, otherwise we'd compare the */ + /* packet's destination. */ + /* ------------------------------------------------------------- */ + if (np->in_apr != NULL) { + i = appr_check(fin, nat); + if (i == -1) { + return -1; + } + } + } + +#ifdef IPFILTER_SYNC + ipfsync_update(SMC_NAT, fin, nat->nat_sync); +#endif + + MUTEX_ENTER(&nat->nat_lock); + nat->nat_bytes[0] += fin->fin_plen; + nat->nat_pkts[0]++; + MUTEX_EXIT(&nat->nat_lock); + + fin->fin_ip->ip_dst = nat->nat_inip; + fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; + if (nflags & IPN_TCPUDP) + tcp = fin->fin_dp; + + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + */ +#if !defined(_KERNEL) || (defined(MENTAT) || defined(__sgi) || defined(__osf__)) + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); + else + fix_outcksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); +#endif + + if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { + if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_dport = nat->nat_inport; + fin->fin_data[1] = ntohs(nat->nat_inport); + } + + + if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { + icmp = fin->fin_dp; + + icmp->icmp_id = nat->nat_inport; + } + + csump = nat_proto(fin, nat, nflags); + } + + nat_update(fin, nat, np); + + if (csump != NULL) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(fin, csump, nat->nat_sumd[0]); + else + fix_outcksum(fin, csump, nat->nat_sumd[0]); + } + ATOMIC_INCL(nat_stats.ns_mapped[0]); + fin->fin_flx |= FI_NATED; + if (np != NULL && np->in_tag.ipt_num[0] != 0) + fin->fin_nattag = &np->in_tag; + return 1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_proto */ +/* Returns: u_short* - pointer to transport header checksum to update, */ +/* NULL if the transport protocol is not recognised */ +/* as needing a checksum update. */ +/* Parameters: fin(I) - pointer to packet information */ +/* nat(I) - pointer to NAT structure */ +/* nflags(I) - NAT flags set for this packet */ +/* */ +/* Return the pointer to the checksum field for each protocol so understood.*/ +/* If support for making other changes to a protocol header is required, */ +/* that is not strictly 'address' translation, such as clamping the MSS in */ +/* TCP down to a specific value, then do it from here. */ +/* ------------------------------------------------------------------------ */ +u_short *nat_proto(fin, nat, nflags) +fr_info_t *fin; +nat_t *nat; +u_int nflags; +{ + icmphdr_t *icmp; + u_short *csump; + tcphdr_t *tcp; + udphdr_t *udp; + + csump = NULL; + if (fin->fin_out == 0) { + fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); + } else { + fin->fin_rev = (nat->nat_dir == NAT_INBOUND); + } + + switch (fin->fin_p) + { + case IPPROTO_TCP : + tcp = fin->fin_dp; + + csump = &tcp->th_sum; + + /* + * Do a MSS CLAMPING on a SYN packet, + * only deal IPv4 for now. + */ + if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) + nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); + + break; + + case IPPROTO_UDP : + udp = fin->fin_dp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + break; + + case IPPROTO_ICMP : + icmp = fin->fin_dp; + + if ((nflags & IPN_ICMPQUERY) != 0) { + if (icmp->icmp_cksum != 0) + csump = &icmp->icmp_cksum; + } + break; + } + return csump; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Free all memory used by NAT structures allocated at runtime. */ +/* ------------------------------------------------------------------------ */ +void fr_natunload() { - WRITE_ENTER(&ipf_nat); (void) nat_clearlist(); (void) nat_flushtable(); - RWLOCK_EXIT(&ipf_nat); if (nat_table[0] != NULL) { KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz); @@ -2860,72 +4157,137 @@ void ip_natunload() KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); maptable = NULL; } + if (nat_stats.ns_bucketlen[0] != NULL) { + KFREES(nat_stats.ns_bucketlen[0], + sizeof(u_long *) * ipf_nattable_sz); + nat_stats.ns_bucketlen[0] = NULL; + } + if (nat_stats.ns_bucketlen[1] != NULL) { + KFREES(nat_stats.ns_bucketlen[1], + sizeof(u_long *) * ipf_nattable_sz); + nat_stats.ns_bucketlen[1] = NULL; + } + + if (fr_nat_maxbucket_reset == 1) + fr_nat_maxbucket = 0; + + if (fr_nat_init == 1) { + fr_nat_init = 0; + fr_sttab_destroy(nat_tqb); + + RW_DESTROY(&ipf_natfrag); + RW_DESTROY(&ipf_nat); + + MUTEX_DESTROY(&ipf_nat_new); + MUTEX_DESTROY(&ipf_natio); + + MUTEX_DESTROY(&nat_udptq.ifq_lock); + MUTEX_DESTROY(&nat_icmptq.ifq_lock); + MUTEX_DESTROY(&nat_iptq.ifq_lock); + } } -/* - * Slowly expire held state for NAT entries. Timeouts are set in - * expectation of this being called twice per second. - */ -void ip_natexpire() +/* ------------------------------------------------------------------------ */ +/* Function: fr_natexpire */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Check all of the timeout queues for entries at the top which need to be */ +/* expired. */ +/* ------------------------------------------------------------------------ */ +void fr_natexpire() { - register struct nat *nat, **natp; -#if defined(_KERNEL) && !SOLARIS + ipftq_t *ifq, *ifqnext; + ipftqent_t *tqe, *tqn; +#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) int s; #endif + int i; SPL_NET(s); WRITE_ENTER(&ipf_nat); - for (natp = &nat_instances; (nat = *natp); ) { - nat->nat_age--; - if (nat->nat_age) { - natp = &nat->nat_next; - continue; + for (ifq = nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) { + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + nat_delete(tqe->tqe_parent, NL_EXPIRE); } - *natp = nat->nat_next; -#ifdef IPFILTER_LOG - nat_log(nat, NL_EXPIRE); -#endif - nat_delete(nat); - nat_stats.ns_expire++; } + + for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + nat_delete(tqe->tqe_parent, NL_EXPIRE); + } + } + RWLOCK_EXIT(&ipf_nat); SPL_X(s); } -/* - */ -void ip_natsync(ifp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_natsync */ +/* Returns: Nil */ +/* Parameters: ifp(I) - pointer to network interface */ +/* */ +/* Walk through all of the currently active NAT sessions, looking for those */ +/* which need to have their translated address updated. */ +/* ------------------------------------------------------------------------ */ +void fr_natsync(ifp) void *ifp; { - register ipnat_t *n; - register nat_t *nat; - register u_32_t sum1, sum2, sumd; + u_32_t sum1, sum2, sumd; struct in_addr in; - ipnat_t *np; + ipnat_t *n; + nat_t *nat; void *ifp2; -#if defined(_KERNEL) && !SOLARIS +#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) int s; #endif + if (fr_running <= 0) + return; + /* * Change IP addresses for NAT sessions for any protocol except TCP - * since it will break the TCP connection anyway. + * since it will break the TCP connection anyway. The only rules + * which will get changed are those which are "map ... -> 0/32", + * where the rule specifies the address is taken from the interface. */ SPL_NET(s); WRITE_ENTER(&ipf_nat); + + if (fr_running <= 0) { + RWLOCK_EXIT(&ipf_nat); + return; + } + for (nat = nat_instances; nat; nat = nat->nat_next) - if (((ifp == NULL) || (ifp == nat->nat_ifp)) && - !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && - (np->in_outmsk == 0xffffffff) && !np->in_nip) { - ifp2 = nat->nat_ifp; + if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || + (ifp == nat->nat_ifps[1]))) { + nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4); + if (nat->nat_ifnames[1][0] != '\0') { + nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], + 4); + } else + nat->nat_ifps[1] = nat->nat_ifps[0]; + ifp2 = nat->nat_ifps[0]; + if (ifp2 == NULL) + continue; + /* * Change the map-to address to be the same as the * new one. */ sum1 = nat->nat_outip.s_addr; - if (fr_ifpaddr(4, ifp2, &in) != -1) + if (fr_ifpaddr(4, FRI_NORMAL, ifp2, &in, NULL) != -1) nat->nat_outip = in; sum2 = nat->nat_outip.s_addr; @@ -2944,59 +4306,149 @@ void *ifp; nat->nat_sumd[1] = nat->nat_sumd[0]; } - for (n = nat_list; (n != NULL); n = n->in_next) - if (n->in_ifp == ifp) { - n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); - if (!n->in_ifp) - n->in_ifp = (void *)-1; + for (n = nat_list; (n != NULL); n = n->in_next) { + if (n->in_ifps[0] == ifp) { + n->in_ifps[0] = (void *)GETIFP(n->in_ifnames[0], 4); + if (n->in_ifps[0] == NULL) + n->in_ifps[0] = (void *)-1; } + if (n->in_ifps[1] == ifp) { + n->in_ifps[1] = (void *)GETIFP(n->in_ifnames[1], 4); + if (n->in_ifps[1] == NULL) + n->in_ifps[1] = (void *)-1; + } + } RWLOCK_EXIT(&ipf_nat); SPL_X(s); } -#ifdef IPFILTER_LOG +/* ------------------------------------------------------------------------ */ +/* Function: nat_icmpquerytype4 */ +/* Returns: int - 1 == success, 0 == failure */ +/* Parameters: icmptype(I) - ICMP type number */ +/* */ +/* Tests to see if the ICMP type number passed is a query/response type or */ +/* not. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_icmpquerytype4(icmptype) +int icmptype; +{ + + /* + * For the ICMP query NAT code, it is essential that both the query + * and the reply match on the NAT rule. Because the NAT structure + * does not keep track of the icmptype, and a single NAT structure + * is used for all icmp types with the same src, dest and id, we + * simply define the replies as queries as well. The funny thing is, + * altough it seems silly to call a reply a query, this is exactly + * as it is defined in the IPv4 specification + */ + + switch (icmptype) + { + + case ICMP_ECHOREPLY: + case ICMP_ECHO: + /* route aedvertisement/solliciation is currently unsupported: */ + /* it would require rewriting the ICMP data section */ + case ICMP_TSTAMP: + case ICMP_TSTAMPREPLY: + case ICMP_IREQ: + case ICMP_IREQREPLY: + case ICMP_MASKREQ: + case ICMP_MASKREPLY: + return 1; + default: + return 0; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_icmperrortype4 */ +/* Returns: int - 1 == success, 0 == failure */ +/* Parameters: icmptype(I) - ICMP type number */ +/* */ +/* Tests to see if the ICMP type number passed is an error type or not. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_icmperrortype4(icmptype) +int icmptype; +{ + + switch (icmptype) + { + case ICMP_SOURCEQUENCH : + case ICMP_PARAMPROB : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_UNREACH : + return 1; + default: + return 0; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_log */ +/* Returns: Nil */ +/* Parameters: nat(I) - pointer to NAT structure */ +/* type(I) - type of log entry to create */ +/* */ +/* Creates a NAT log entry. */ +/* ------------------------------------------------------------------------ */ void nat_log(nat, type) struct nat *nat; u_int type; { +#ifdef IPFILTER_LOG + struct ipnat *np; struct natlog natl; void *items[1]; size_t sizes[1]; - int types[1]; + int rulen, types[1]; natl.nl_inip = nat->nat_inip; natl.nl_outip = nat->nat_outip; natl.nl_origip = nat->nat_oip; - natl.nl_bytes = nat->nat_bytes; - natl.nl_pkts = nat->nat_pkts; + natl.nl_bytes[0] = nat->nat_bytes[0]; + natl.nl_bytes[1] = nat->nat_bytes[1]; + natl.nl_pkts[0] = nat->nat_pkts[0]; + natl.nl_pkts[1] = nat->nat_pkts[1]; natl.nl_origport = nat->nat_oport; natl.nl_inport = nat->nat_inport; natl.nl_outport = nat->nat_outport; natl.nl_p = nat->nat_p; natl.nl_type = type; natl.nl_rule = -1; -#ifndef LARGE_NAT +# ifndef LARGE_NAT if (nat->nat_ptr != NULL) { - struct ipnat *np; - int rulen; for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) if (np == nat->nat_ptr) { natl.nl_rule = rulen; break; } } -#endif +# endif items[0] = &natl; sizes[0] = sizeof(natl); types[0] = 0; (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); -} #endif +} #if defined(__OpenBSD__) +/* ------------------------------------------------------------------------ */ +/* Function: nat_ifdetach */ +/* Returns: Nil */ +/* Parameters: ifp(I) - pointer to network interface */ +/* */ +/* Compatibility interface for OpenBSD to trigger the correct updating of */ +/* interface references within IPFilter. */ +/* ------------------------------------------------------------------------ */ void nat_ifdetach(ifp) void *ifp; { @@ -3004,3 +4456,273 @@ void *ifp; return; } #endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natderef */ +/* Returns: Nil */ +/* Parameters: isp(I) - pointer to pointer to NAT table entry */ +/* */ +/* Decrement the reference counter for this NAT table entry and free it if */ +/* there are no more things using it. */ +/* ------------------------------------------------------------------------ */ +void fr_natderef(natp) +nat_t **natp; +{ + nat_t *nat; + + nat = *natp; + *natp = NULL; + WRITE_ENTER(&ipf_nat); + nat->nat_ref--; + if (nat->nat_ref == 0) + nat_delete(nat, NL_EXPIRE); + RWLOCK_EXIT(&ipf_nat); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natclone */ +/* Returns: ipstate_t* - NULL == cloning failed, */ +/* else pointer to new state structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* Write Lock: ipf_nat */ +/* */ +/* Create a "duplcate" state table entry from the master. */ +/* ------------------------------------------------------------------------ */ +static nat_t *fr_natclone(fin, nat) +fr_info_t *fin; +nat_t *nat; +{ + frentry_t *fr; + nat_t *clone; + ipnat_t *np; + + KMALLOC(clone, nat_t *); + if (clone == NULL) + return NULL; + bcopy((char *)nat, (char *)clone, sizeof(*clone)); + + MUTEX_NUKE(&clone->nat_lock); + + np = clone->nat_ptr; + if (np != NULL) { + np->in_use++; + } + clone->nat_flags &= ~SI_CLONE; + clone->nat_flags |= SI_CLONED; + + fr = clone->nat_fr; + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + MUTEX_EXIT(&fr->fr_lock); + } + + if (nat_insert(clone, fin->fin_rev) == -1) { + KFREE(clone); + return NULL; + } + + /* + * Because the clone is created outside the normal loop of things and + * TCP has special needs in terms of state, initialise the timeout + * state of the new NAT from here. + */ + if (clone->nat_p == IPPROTO_TCP) { + (void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb, \ + clone->nat_flags); + } +#ifdef IPFILTER_SYNC + clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); +#endif + if (nat_logging) + nat_log(clone, NL_CLONE); + return clone; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_wildok */ +/* Returns: int - 1 == packet's ports match wildcards */ +/* 0 == packet's ports don't match wildcards */ +/* Parameters: nat(I) - NAT entry */ +/* sport(I) - source port */ +/* dport(I) - destination port */ +/* flags(I) - wildcard flags */ +/* dir(I) - packet direction */ +/* */ +/* Use NAT entry and packet direction to determine which combination of */ +/* wildcard flags should be used. */ +/* ------------------------------------------------------------------------ */ +static INLINE int nat_wildok(nat, sport, dport, flags, dir) +nat_t *nat; +int sport; +int dport; +int flags; +int dir; +{ + /* + * When called by dir is set to + * nat_inlookup NAT_INBOUND (0) + * nat_outlookup NAT_OUTBOUND (1) + * + * We simply combine the packet's direction in dir with the original + * "intended" direction of that NAT entry in nat->nat_dir to decide + * which combination of wildcard flags to allow. + */ + + switch ((dir << 1) | nat->nat_dir) + { + case 3: /* outbound packet / outbound entry */ + if (((nat->nat_inport == sport) || + (flags & SI_W_SPORT)) && + ((nat->nat_oport == dport) || + (flags & SI_W_DPORT))) + return 1; + break; + case 2: /* outbound packet / inbound entry */ + if (((nat->nat_outport == sport) || + (flags & SI_W_DPORT)) && + ((nat->nat_oport == dport) || + (flags & SI_W_SPORT))) + return 1; + break; + case 1: /* inbound packet / outbound entry */ + if (((nat->nat_oport == sport) || + (flags & SI_W_DPORT)) && + ((nat->nat_outport == dport) || + (flags & SI_W_SPORT))) + return 1; + break; + case 0: /* inbound packet / inbound entry */ + if (((nat->nat_oport == sport) || + (flags & SI_W_SPORT)) && + ((nat->nat_outport == dport) || + (flags & SI_W_DPORT))) + return 1; + break; + default: + break; + } + + return(0); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_mssclamp */ +/* Returns: Nil */ +/* Parameters: tcp(I) - pointer to TCP header */ +/* maxmss(I) - value to clamp the TCP MSS to */ +/* fin(I) - pointer to packet information */ +/* csump(I) - pointer to TCP checksum */ +/* */ +/* Check for MSS option and clamp it if necessary. If found and changed, */ +/* then the TCP header checksum will be updated to reflect the change in */ +/* the MSS. */ +/* ------------------------------------------------------------------------ */ +static void nat_mssclamp(tcp, maxmss, fin, csump) +tcphdr_t *tcp; +u_32_t maxmss; +fr_info_t *fin; +u_short *csump; +{ + u_char *cp, *ep, opt; + int hlen, advance; + u_32_t mss, sumd; + + hlen = TCP_OFF(tcp) << 2; + if (hlen > sizeof(*tcp)) { + cp = (u_char *)tcp + sizeof(*tcp); + ep = (u_char *)tcp + hlen; + + while (cp < ep) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + else if (opt == TCPOPT_NOP) { + cp++; + continue; + } + + if (cp + 1 >= ep) + break; + advance = cp[1]; + if (cp + advance > ep) + break; + switch (opt) + { + case TCPOPT_MAXSEG: + if (advance != 4) + break; + mss = cp[2] * 256 + cp[3]; + if (mss > maxmss) { + cp[2] = maxmss / 256; + cp[3] = maxmss & 0xff; + CALC_SUMD(mss, maxmss, sumd); + fix_outcksum(fin, csump, sumd); + } + break; + default: + /* ignore unknown options */ + break; + } + + cp += advance; + } + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_setnatqueue */ +/* Returns: Nil */ +/* Parameters: nat(I)- pointer to NAT structure */ +/* rev(I) - forward(0) or reverse(1) direction */ +/* Locks: ipf_nat (read or write) */ +/* */ +/* Put the NAT entry on its default queue entry, using rev as a helped in */ +/* determining which queue it should be placed on. */ +/* ------------------------------------------------------------------------ */ +void fr_setnatqueue(nat, rev) +nat_t *nat; +int rev; +{ + ipftq_t *oifq, *nifq; + + if (nat->nat_ptr != NULL) + nifq = nat->nat_ptr->in_tqehead[rev]; + else + nifq = NULL; + + if (nifq == NULL) { + switch (nat->nat_p) + { + case IPPROTO_UDP : + nifq = &nat_udptq; + break; + case IPPROTO_ICMP : + nifq = &nat_icmptq; + break; + case IPPROTO_TCP : + nifq = nat_tqb + nat->nat_tqe.tqe_state[rev]; + break; + default : + nifq = &nat_iptq; + break; + } + } + + oifq = nat->nat_tqe.tqe_ifq; + /* + * If it's currently on a timeout queue, move it from one queue to + * another, else put it on the end of the newly determined queue. + */ + if (oifq != NULL) + fr_movequeue(&nat->nat_tqe, oifq, nifq); + else + fr_queueappend(&nat->nat_tqe, nifq, nat); + return; +} diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h index d2e8eb1413f0..5e613d3ee025 100644 --- a/sys/netinet/ip_nat.h +++ b/sys/netinet/ip_nat.h @@ -1,147 +1,221 @@ -/* $NetBSD: ip_nat.h,v 1.30 2004/01/16 09:01:22 abs Exp $ */ +/* $NetBSD: ip_nat.h,v 1.31 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1995-2001 by Darren Reed. + * Copyright (C) 1995-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_nat.h 1.5 2/4/96 - * Id: ip_nat.h,v 2.17.2.27 2002/08/28 12:45:51 darrenr Exp + * Id: ip_nat.h,v 2.90 2004/02/11 15:10:36 darrenr Exp */ -#ifndef _NETINET_IP_NAT_H_ -#define _NETINET_IP_NAT_H_ +#ifndef __IP_NAT_H__ +#define __IP_NAT_H__ #ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif #if defined(__STDC__) || defined(__GNUC__) -#define SIOCADNAT _IOW('r', 60, struct ipnat *) -#define SIOCRMNAT _IOW('r', 61, struct ipnat *) -#define SIOCGNATS _IOWR('r', 62, struct natstat *) -#define SIOCGNATL _IOWR('r', 63, struct natlookup *) +#define SIOCADNAT _IOW('r', 60, struct ipfobj) +#define SIOCRMNAT _IOW('r', 61, struct ipfobj) +#define SIOCGNATS _IOWR('r', 62, struct ipfobj) +#define SIOCGNATL _IOWR('r', 63, struct ipfobj) +#define SIOCPROXY _IOWR('r', 64, struct ap_control) #else -#define SIOCADNAT _IOW(r, 60, struct ipnat *) -#define SIOCRMNAT _IOW(r, 61, struct ipnat *) -#define SIOCGNATS _IOWR(r, 62, struct natstat *) -#define SIOCGNATL _IOWR(r, 63, struct natlookup *) +#define SIOCADNAT _IOW(r, 60, struct ipfobj) +#define SIOCRMNAT _IOW(r, 61, struct ipfobj) +#define SIOCGNATS _IOWR(r, 62, struct ipfobj) +#define SIOCGNATL _IOWR(r, 63, struct ipfobj) +#define SIOCPROXY _IOWR(r, 64, struct ap_control) #endif -/* #define LARGE_NAT */ /* define this if you're setting up a system to NAT +#undef LARGE_NAT /* define this if you're setting up a system to NAT * LARGE numbers of networks/hosts - i.e. in the * hundreds or thousands. In such a case, you should * also change the RDR_SIZE and NAT_SIZE below to more * appropriate sizes. The figures below were used for * a setup with 1000-2000 networks to NAT. */ -#ifndef NAT_SIZE -# define NAT_SIZE 127 +#ifndef NAT_SIZE +# ifdef LARGE_NAT +# define NAT_SIZE 2047 +# else +# define NAT_SIZE 127 +# endif #endif -#ifndef RDR_SIZE -# define RDR_SIZE 127 +#ifndef RDR_SIZE +# ifdef LARGE_NAT +# define RDR_SIZE 2047 +# else +# define RDR_SIZE 127 +# endif #endif -#ifndef HOSTMAP_SIZE -# define HOSTMAP_SIZE 127 +#ifndef HOSTMAP_SIZE +# ifdef LARGE_NAT +# define HOSTMAP_SIZE 8191 +# else +# define HOSTMAP_SIZE 2047 +# endif #endif -#ifndef NAT_TABLE_SZ -# define NAT_TABLE_SZ 127 +#ifndef NAT_TABLE_MAX +/* + * This is newly introduced and for the sake of "least surprise", the numbers + * present aren't what we'd normally use for creating a proper hash table. + */ +# ifdef LARGE_NAT +# define NAT_TABLE_MAX 180000 +# else +# define NAT_TABLE_MAX 30000 +# endif #endif -#ifdef LARGE_NAT -#undef NAT_SIZE -#undef RDR_SIZE -#undef NAT_TABLE_SZ -#undef HOSTMAP_SIZE -#define NAT_SIZE 2047 -#define RDR_SIZE 2047 -#define NAT_TABLE_SZ 16383 -#define HOSTMAP_SIZE 8191 +#ifndef NAT_TABLE_SZ +# ifdef LARGE_NAT +# define NAT_TABLE_SZ 16383 +# else +# define NAT_TABLE_SZ 2047 +# endif #endif #ifndef APR_LABELLEN #define APR_LABELLEN 16 #endif #define NAT_HW_CKSUM 0x80000000 -#ifndef DEF_NAT_AGE -# define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ -#endif +#define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ +struct ipstate; struct ap_session; typedef struct nat { - u_long nat_age; - int nat_flags; - u_32_t nat_sumd[2]; - u_32_t nat_ipsumd; - void *nat_data; - struct ap_session *nat_aps; /* proxy session */ - struct frentry *nat_fr; /* filter rule ptr if appropriate */ - struct in_addr nat_inip; - struct in_addr nat_outip; - struct in_addr nat_oip; /* other ip */ - u_32_t nat_mssclamp; /* if != zero clamp MSS to this */ - U_QUAD_T nat_pkts; - U_QUAD_T nat_bytes; - u_int nat_drop[2]; - u_short nat_oport; /* other port */ - u_short nat_inport; - u_short nat_outport; - u_short nat_use; - u_char nat_tcpstate[2]; - u_char nat_p; /* protocol for NAT */ - struct ipnat *nat_ptr; /* pointer back to the rule */ - struct hostmap *nat_hm; + ipfmutex_t nat_lock; struct nat *nat_next; + struct nat **nat_pnext; struct nat *nat_hnext[2]; struct nat **nat_phnext[2]; + struct hostmap *nat_hm; + void *nat_data; struct nat **nat_me; - void *nat_ifp; - int nat_dir; - char nat_ifname[IFNAMSIZ]; -#if SOLARIS || defined(__sgi) - kmutex_t nat_lock; -#endif + struct ipstate *nat_state; + struct ap_session *nat_aps; /* proxy session */ + frentry_t *nat_fr; /* filter rule ptr if appropriate */ + struct ipnat *nat_ptr; /* pointer back to the rule */ + void *nat_ifps[2]; + void *nat_sync; + ipftqent_t nat_tqe; + u_32_t nat_flags; + u_32_t nat_sumd[2]; /* ip checksum delta for data segment*/ + u_32_t nat_ipsumd; /* ip checksum delta for ip header */ + u_32_t nat_mssclamp; /* if != zero clamp MSS to this */ + i6addr_t nat_inip6; + i6addr_t nat_outip6; + i6addr_t nat_oip6; /* other ip */ + U_QUAD_T nat_pkts[2]; + U_QUAD_T nat_bytes[2]; + union { + udpinfo_t nat_unu; + tcpinfo_t nat_unt; + icmpinfo_t nat_uni; + greinfo_t nat_ugre; + } nat_un; + u_short nat_oport; /* other port */ + u_short nat_use; + u_char nat_p; /* protocol for NAT */ + int nat_dir; + int nat_ref; /* reference count */ + int nat_hv[2]; + char nat_ifnames[2][LIFNAMSIZ]; } nat_t; +#define nat_inip nat_inip6.in4 +#define nat_outip nat_outip6.in4 +#define nat_oip nat_oip6.in4 +#define nat_age nat_tqe.tqe_die +#define nat_inport nat_un.nat_unt.ts_sport +#define nat_outport nat_un.nat_unt.ts_dport +#define nat_type nat_un.nat_uni.ici_type +#define nat_seq nat_un.nat_uni.ici_seq +#define nat_id nat_un.nat_uni.ici_id +#define nat_tcpstate nat_tqe.tqe_state +#define nat_gre nat_un.nat_ugre + +/* + * Values for nat_dir + */ +#define NAT_INBOUND 0 +#define NAT_OUTBOUND 1 + +/* + * Definitions for nat_flags + */ +#define NAT_TCP 0x0001 /* IPN_TCP */ +#define NAT_UDP 0x0002 /* IPN_UDP */ +#define NAT_ICMPERR 0x0004 /* IPN_ICMPERR */ +#define NAT_ICMPQUERY 0x0008 /* IPN_ICMPQUERY */ +#define NAT_SEARCH 0x0010 +#define NAT_SLAVE 0x0020 /* Slave connection for a proxy */ +#define NAT_NOTRULEPORT 0x0040 + +#define NAT_TCPUDP (NAT_TCP|NAT_UDP) +#define NAT_TCPUDPICMP (NAT_TCP|NAT_UDP|NAT_ICMPERR) +#define NAT_FROMRULE (NAT_TCP|NAT_UDP) + +/* 0x0100 reserved for FI_W_SPORT */ +/* 0x0200 reserved for FI_W_DPORT */ +/* 0x0400 reserved for FI_W_SADDR */ +/* 0x0800 reserved for FI_W_DADDR */ +/* 0x1000 reserved for FI_W_NEWFR */ +/* 0x2000 reserved for SI_CLONE */ +/* 0x4000 reserved for SI_CLONED */ +/* 0x8000 reserved for SI_IGNOREPKT */ + +#define NAT_DEBUG 0x800000 + typedef struct ipnat { - struct ipnat *in_next; - struct ipnat *in_rnext; - struct ipnat **in_prnext; - struct ipnat *in_mnext; - struct ipnat **in_pmnext; - void *in_ifp; - void *in_apr; - u_long in_space; - u_int in_use; - u_int in_hits; - struct in_addr in_nextip; - u_short in_pnext; - u_short in_ippip; /* IP #'s per IP# */ - u_32_t in_mssclamp; /* if != zero clamp MSS to this */ - u_32_t in_flags; /* From here to in_dport must be reflected */ - u_short in_spare; - u_short in_ppip; /* ports per IP */ - u_short in_port[2]; /* correctly in IPN_CMPSIZ */ - struct in_addr in_in[2]; - struct in_addr in_out[2]; - struct in_addr in_src[2]; - struct frtuc in_tuc; - u_int in_age[2]; /* Aging for NAT entries. Not for TCP */ - int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */ - char in_ifname[IFNAMSIZ]; - char in_plabel[APR_LABELLEN]; /* proxy label */ - char in_p; /* protocol */ + struct ipnat *in_next; /* NAT rule list next */ + struct ipnat *in_rnext; /* rdr rule hash next */ + struct ipnat **in_prnext; /* prior rdr next ptr */ + struct ipnat *in_mnext; /* map rule hash next */ + struct ipnat **in_pmnext; /* prior map next ptr */ + struct ipftq *in_tqehead[2]; + void *in_ifps[2]; + void *in_apr; + char *in_comment; + i6addr_t in_next6; + u_long in_space; + u_long in_hits; + u_int in_use; + u_int in_hv; + int in_flineno; /* conf. file line number */ + u_short in_pnext; + u_char in_xxx1[2]; + /* From here to the end is covered by IPN_CMPSIZ */ + u_32_t in_flags; + u_32_t in_mssclamp; /* if != 0 clamp MSS to this */ + u_int in_age[2]; + int in_redir; /* see below for values */ + int in_p; /* protocol. */ + i6addr_t in_in[2]; + i6addr_t in_out[2]; + i6addr_t in_src[2]; + frtuc_t in_tuc; + u_short in_port[2]; + u_short in_ppip; /* ports per IP. */ + u_short in_ippip; /* IP #'s per IP# */ + char in_ifnames[2][LIFNAMSIZ]; + char in_plabel[APR_LABELLEN]; /* proxy label. */ + ipftag_t in_tag; } ipnat_t; #define in_pmin in_port[0] /* Also holds static redir port */ #define in_pmax in_port[1] -#define in_nip in_nextip.s_addr -#define in_inip in_in[0].s_addr -#define in_inmsk in_in[1].s_addr -#define in_outip in_out[0].s_addr -#define in_outmsk in_out[1].s_addr -#define in_srcip in_src[0].s_addr -#define in_srcmsk in_src[1].s_addr +#define in_nextip in_next6.in4 +#define in_nip in_next6.in4.s_addr +#define in_inip in_in[0].in4.s_addr +#define in_inmsk in_in[1].in4.s_addr +#define in_outip in_out[0].in4.s_addr +#define in_outmsk in_out[1].in4.s_addr +#define in_srcip in_src[0].in4.s_addr +#define in_srcmsk in_src[1].in4.s_addr #define in_scmp in_tuc.ftu_scmp #define in_dcmp in_tuc.ftu_dcmp #define in_stop in_tuc.ftu_stop @@ -149,18 +223,40 @@ typedef struct ipnat { #define in_sport in_tuc.ftu_sport #define in_dport in_tuc.ftu_dport -#define NAT_OUTBOUND 0 -#define NAT_INBOUND 1 +/* + * Bit definitions for in_flags + */ +#define IPN_ANY 0x00000 +#define IPN_TCP 0x00001 +#define IPN_UDP 0x00002 +#define IPN_TCPUDP (IPN_TCP|IPN_UDP) +#define IPN_ICMPERR 0x00004 +#define IPN_TCPUDPICMP (IPN_TCP|IPN_UDP|IPN_ICMPERR) +#define IPN_ICMPQUERY 0x00008 +#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) +#define IPN_AUTOPORTMAP 0x00010 +#define IPN_IPRANGE 0x00020 +#define IPN_FILTER 0x00040 +#define IPN_SPLIT 0x00080 +#define IPN_ROUNDR 0x00100 +#define IPN_NOTSRC 0x04000 +#define IPN_NOTDST 0x08000 +#define IPN_DYNSRCIP 0x10000 /* dynamic src IP# */ +#define IPN_DYNDSTIP 0x20000 /* dynamic dst IP# */ +#define IPN_DELETE 0x40000 +#define IPN_STICKY 0x80000 +#define IPN_FRAG 0x100000 +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ + IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|\ + IPN_FRAG|IPN_STICKY) +/* + * Values for in_redir + */ #define NAT_MAP 0x01 #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) #define NAT_MAPBLK 0x04 -/* 0x100 reserved for FI_W_SPORT */ -/* 0x200 reserved for FI_W_DPORT */ -/* 0x400 reserved for FI_W_SADDR */ -/* 0x800 reserved for FI_W_DADDR */ -/* 0x1000 reserved for FI_W_NEWFR */ #define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ #define USABLE_PORTS (65536 - MAPBLK_MINPORT) @@ -195,16 +291,59 @@ typedef struct natget { } natget_t; +typedef struct nattrpnt { + struct in_addr tr_dstip; /* real destination IP# */ + struct in_addr tr_srcip; /* real source IP# */ + struct in_addr tr_locip; /* local source IP# */ + u_int tr_flags; + int tr_expire; + u_short tr_dstport; /* real destination port# */ + u_short tr_srcport; /* real source port# */ + u_short tr_locport; /* local source port# */ + struct nattrpnt *tr_hnext; + struct nattrpnt **tr_phnext; + struct nattrpnt *tr_next; + struct nattrpnt **tr_pnext; /* previous next */ +} nattrpnt_t; + +#define TN_CMPSIZ offsetof(nattrpnt_t, tr_hnext) + + +/* + * This structure gets used to help NAT sessions keep the same NAT rule (and + * thus translation for IP address) when: + * (a) round-robin redirects are in use + * (b) different IP add + */ typedef struct hostmap { struct hostmap *hm_next; struct hostmap **hm_pnext; struct ipnat *hm_ipnat; - struct in_addr hm_realip; + struct in_addr hm_srcip; + struct in_addr hm_dstip; struct in_addr hm_mapip; - int hm_ref; + u_32_t hm_port; + int hm_ref; } hostmap_t; +/* + * Structure used to pass information in to nat_newmap and nat_newrdr. + */ +typedef struct natinfo { + ipnat_t *nai_np; + u_32_t nai_sum1; + u_32_t nai_sum2; + u_32_t nai_nflags; + u_32_t nai_flags; + struct in_addr nai_ip; + u_short nai_port; + u_short nai_nport; + u_short nai_sport; + u_short nai_dport; +} natinfo_t; + + typedef struct natstat { u_long ns_mapped[2]; u_long ns_rules; @@ -215,37 +354,23 @@ typedef struct natstat { u_long ns_logfail; u_long ns_memfail; u_long ns_badnat; + u_long ns_addtrpnt; nat_t **ns_table[2]; hostmap_t **ns_maptable; ipnat_t *ns_list; void *ns_apslist; + u_int ns_wilds; u_int ns_nattab_sz; + u_int ns_nattab_max; u_int ns_rultab_sz; u_int ns_rdrtab_sz; + u_int ns_trpntab_sz; u_int ns_hostmap_sz; nat_t *ns_instances; - u_int ns_wilds; + nattrpnt_t *ns_trpntlist; + u_long *ns_bucketlen[2]; } natstat_t; -#define IPN_ANY 0x000 -#define IPN_TCP 0x001 -#define IPN_UDP 0x002 -#define IPN_TCPUDP (IPN_TCP|IPN_UDP) -#define IPN_DELETE 0x004 -#define IPN_ICMPERR 0x008 -#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) -#define IPN_AUTOPORTMAP 0x010 -#define IPN_IPRANGE 0x020 -#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ - IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|IPN_FRAG) -#define IPN_FILTER 0x040 -#define IPN_SPLIT 0x080 -#define IPN_ROUNDR 0x100 -#define IPN_NOTSRC 0x080000 -#define IPN_NOTDST 0x100000 -#define IPN_FRAG 0x200000 - - typedef struct natlog { struct in_addr nl_origip; struct in_addr nl_outip; @@ -255,8 +380,8 @@ typedef struct natlog { u_short nl_inport; u_short nl_type; int nl_rule; - U_QUAD_T nl_pkts; - U_QUAD_T nl_bytes; + U_QUAD_T nl_pkts[2]; + U_QUAD_T nl_bytes[2]; u_char nl_p; } natlog_t; @@ -265,6 +390,7 @@ typedef struct natlog { #define NL_NEWRDR NAT_REDIRECT #define NL_NEWBIMAP NAT_BIMAP #define NL_NEWBLOCK NAT_MAPBLK +#define NL_CLONE 0xfffd #define NL_FLUSH 0xfffe #define NL_EXPIRE 0xffff @@ -286,46 +412,59 @@ typedef struct natlog { #define NAT_SYSSPACE 0x80000000 #define NAT_LOCKHELD 0x40000000 + extern u_int ipf_nattable_sz; +extern u_int ipf_nattable_max; extern u_int ipf_natrules_sz; extern u_int ipf_rdrrules_sz; +extern u_int ipf_hostmap_sz; +extern u_int fr_nat_maxbucket; +extern u_int fr_nat_maxbucket_reset; extern int fr_nat_lock; -extern void ip_natsync __P((void *)); +extern void fr_natsync __P((void *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; + /* nat_table[0] -> hashed list sorted by inside (ip, port) */ + /* nat_table[1] -> hashed list sorted by outside (ip, port) */ extern nat_t **nat_table[2]; extern nat_t *nat_instances; +extern ipnat_t *nat_list; extern ipnat_t **nat_rules; extern ipnat_t **rdr_rules; -extern ipnat_t *nat_list; +extern ipftq_t *nat_utqe; extern natstat_t nat_stats; + #if defined(__OpenBSD__) extern void nat_ifdetach __P((void *)); #endif -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -extern int nat_ioctl __P((caddr_t, u_long, int)); -#else -extern int nat_ioctl __P((caddr_t, int, int)); -#endif -extern int nat_init __P((void)); -extern nat_t *nat_new __P((fr_info_t *, ip_t *, ipnat_t *, nat_t **, - u_int, int)); +extern int fr_nat_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int fr_natinit __P((void)); +extern nat_t *nat_new __P((fr_info_t *, ipnat_t *, nat_t **, u_int, int)); extern nat_t *nat_outlookup __P((fr_info_t *, u_int, u_int, struct in_addr, - struct in_addr, int)); + struct in_addr)); +extern void fix_datacksum __P((u_short *, u_32_t)); extern nat_t *nat_inlookup __P((fr_info_t *, u_int, u_int, struct in_addr, - struct in_addr, int)); + struct in_addr)); +extern nat_t *nat_tnlookup __P((fr_info_t *, int)); +extern nat_t *nat_maplookup __P((void *, u_int, struct in_addr, + struct in_addr)); extern nat_t *nat_lookupredir __P((natlookup_t *)); -extern nat_t *nat_icmplookup __P((ip_t *, fr_info_t *, int)); -extern nat_t *nat_icmp __P((ip_t *, fr_info_t *, u_int *, int)); -extern int nat_clearlist __P((void)); -extern void nat_insert __P((nat_t *)); +extern nat_t *nat_icmperrorlookup __P((fr_info_t *, int)); +extern nat_t *nat_icmperror __P((fr_info_t *, u_int *, int)); +extern int nat_insert __P((nat_t *, int)); -extern int ip_natout __P((ip_t *, fr_info_t *)); -extern int ip_natin __P((ip_t *, fr_info_t *)); -extern void ip_natunload __P((void)), ip_natexpire __P((void)); +extern int fr_checknatout __P((fr_info_t *, u_32_t *)); +extern int fr_natout __P((fr_info_t *, nat_t *, int, u_32_t)); +extern int fr_checknatin __P((fr_info_t *, u_32_t *)); +extern int fr_natin __P((fr_info_t *, nat_t *, int, u_32_t)); +extern void fr_natunload __P((void)); +extern void fr_natexpire __P((void)); extern void nat_log __P((struct nat *, u_int)); extern void fix_incksum __P((fr_info_t *, u_short *, u_32_t)); extern void fix_outcksum __P((fr_info_t *, u_short *, u_32_t)); -extern void fix_datacksum __P((u_short *, u_32_t)); +extern void fr_natderef __P((nat_t **)); +extern u_short *nat_proto __P((fr_info_t *, nat_t *, u_int)); +extern void nat_update __P((fr_info_t *, nat_t *, ipnat_t *)); +extern void fr_setnatqueue __P((nat_t *, int)); -#endif /* _NETINET_IP_NAT_H_ */ +#endif /* __IP_NAT_H__ */ diff --git a/sys/netinet/ip_netbios_pxy.c b/sys/netinet/ip_netbios_pxy.c index d094556476bd..00ab0ded55a2 100644 --- a/sys/netinet/ip_netbios_pxy.c +++ b/sys/netinet/ip_netbios_pxy.c @@ -1,13 +1,13 @@ -/* $NetBSD: ip_netbios_pxy.c,v 1.4 2002/09/19 08:12:53 martti Exp $ */ +/* $NetBSD: ip_netbios_pxy.c,v 1.5 2004/03/28 09:00:57 martti Exp $ */ /* * Simple netbios-dgm transparent proxy for in-kernel use. * For use with the NAT code. - * Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp + * Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp */ /*- - * Copyright (c) 2002 Paul J. Ledbetter III + * Copyright (c) 2002-2003 Paul J. Ledbetter III * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,18 +31,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp + * Id: ip_netbios_pxy.c,v 2.8 2003/12/01 02:52:16 darrenr Exp */ -__KERNEL_RCSID(1, "$NetBSD: ip_netbios_pxy.c,v 1.4 2002/09/19 08:12:53 martti Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ip_netbios_pxy.c,v 1.5 2004/03/28 09:00:57 martti Exp $"); #define IPF_NETBIOS_PROXY int ippr_netbios_init __P((void)); -int ippr_netbios_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_netbios_fini __P((void)); +int ippr_netbios_out __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t netbiosfr; +int netbios_proxy_init = 0; + /* * Initialize local structures. */ @@ -51,43 +54,55 @@ int ippr_netbios_init() bzero((char *)&netbiosfr, sizeof(netbiosfr)); netbiosfr.fr_ref = 1; netbiosfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&netbiosfr.fr_lock, "NETBIOS proxy rule lock"); + netbios_proxy_init = 1; + return 0; } -int ippr_netbios_out(fin, ip, aps, nat) + +void ippr_netbios_fini() +{ + if (netbios_proxy_init == 1) { + MUTEX_DESTROY(&netbiosfr.fr_lock); + netbios_proxy_init = 0; + } +} + + +int ippr_netbios_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { char dgmbuf[6]; - int off, dlen; udphdr_t *udp; + ip_t *ip; mb_t *m; + aps = aps; /* LINT */ + nat = nat; /* LINT */ + + ip = fin->fin_ip; m = *(mb_t **)fin->fin_mp; off = fin->fin_hlen + sizeof(udphdr_t); -#if SOLARIS - dlen = msgdsize(m); -#else - dlen = mbufchainlen(m); -#endif + dlen = M_LEN(m); dlen -= off; /* * no net bios datagram could possibly be shorter than this */ - if (dlen < 11) + if (dlen < 11) return 0; udp = (udphdr_t *)fin->fin_dp; - /* + /* * move past the * ip header; * udp header; - * 4 bytes into the net bios dgm header. + * 4 bytes into the net bios dgm header. * According to rfc1002, this should be the exact location of * the source address/port */ @@ -103,11 +118,7 @@ nat_t *nat; dgmbuf[5] = (char)((udp->uh_sport >> 8)&0xFF); /* replace data in packet */ -#if SOLARIS - copyin_mblk(m, off, sizeof(dgmbuf), dgmbuf); -#else - m_copyback(m, off, sizeof(dgmbuf), dgmbuf); -#endif + COPYBACK(m, off, sizeof(dgmbuf), dgmbuf); return 0; } diff --git a/sys/netinet/ip_proxy.c b/sys/netinet/ip_proxy.c index 3211ac91c184..565ffe753f26 100644 --- a/sys/netinet/ip_proxy.c +++ b/sys/netinet/ip_proxy.c @@ -1,47 +1,58 @@ -/* $NetBSD: ip_proxy.c,v 1.36 2002/09/19 08:12:54 martti Exp $ */ +/* $NetBSD: ip_proxy.c,v 1.37 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1997-2002 by Darren Reed. + * Copyright (C) 1997-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif - -#ifdef __sgi -# include +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include #include #include #include #include -#if !defined(__FreeBSD_version) -# include -#endif #include -#if !defined(_KERNEL) && !defined(KERNEL) +#if !defined(_KERNEL) && !defined(__KERNEL__) # include # include # include +# include +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include +# undef _KERNEL #endif -#ifndef linux +#if !defined(linux) # include #endif #include #if defined(_KERNEL) -# if !defined(linux) -# include -# else -# include +# if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \ + !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) +# include # endif -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# include +# if !defined(__SVR4) && !defined(__svr4__) # include # endif +#endif +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) +# include +# include +# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #else +# include +#endif +#if defined(__SVR4) || defined(__svr4__) # include # ifdef _KERNEL # include @@ -76,74 +87,88 @@ # include #endif +#include "netinet/ip_ftp_pxy.c" +#include "netinet/ip_rcmd_pxy.c" +#if defined(_KERNEL) +# include "netinet/ip_irc_pxy.c" +# include "netinet/ip_raudio_pxy.c" +# include "netinet/ip_h323_pxy.c" +# include "netinet/ip_pptp_pxy.c" +# ifdef IPFILTER_PRO +# include "netinet/ip_msnrpc_pxy.c" +# endif +# include "netinet/ip_netbios_pxy.c" +#endif +#include "netinet/ip_ipsec_pxy.c" +#include "netinet/ip_rpcb_pxy.c" + +/* END OF INCLUDES */ + #if !defined(lint) -#if defined(__NetBSD__) -#include -__KERNEL_RCSID(0, "$NetBSD: ip_proxy.c,v 1.36 2002/09/19 08:12:54 martti Exp $"); -#else -static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.9.2.24 2002/08/28 12:45:51 darrenr Exp"; -#endif -#endif - -#if defined(_KERNEL) && (SOLARIS || defined(__sgi)) -extern KRWLOCK_T ipf_nat, ipf_state; -#endif - -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.62.2.3 2004/03/19 23:00:34 darrenr Exp"; #endif static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); - -#define PROXY_DEBUG 0 - #define AP_SESS_SIZE 53 -#include "netinet/ip_ftp_pxy.c" -#if defined(_KERNEL) -#include "netinet/ip_rcmd_pxy.c" -#include "netinet/ip_raudio_pxy.c" -#include "netinet/ip_netbios_pxy.c" -#include "netinet/ip_h323_pxy.c" -#endif -#include "netinet/ip_ipsec_pxy.c" - ap_session_t *ap_sess_tab[AP_SESS_SIZE]; ap_session_t *ap_sess_list = NULL; aproxy_t *ap_proxylist = NULL; aproxy_t ap_proxies[] = { #ifdef IPF_FTP_PROXY - { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_fini, ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL }, #endif +#ifdef IPF_IRC_PROXY + { NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini, + ippr_irc_new, NULL, NULL, ippr_irc_out, NULL, NULL }, +#endif #ifdef IPF_RCMD_PROXY - { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, - ippr_rcmd_new, NULL, NULL, ippr_rcmd_out, NULL }, + { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_fini, + ippr_rcmd_new, NULL, ippr_rcmd_in, ippr_rcmd_out, NULL, NULL }, #endif #ifdef IPF_RAUDIO_PROXY - { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL, - ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL }, + { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, ippr_raudio_fini, + ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL, NULL }, #endif -#ifdef IPF_IPSEC_PROXY - { NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, ippr_ipsec_init, NULL, - ippr_ipsec_new, ippr_ipsec_del, NULL, ippr_ipsec_out, - ippr_ipsec_match }, +#ifdef IPF_MSNRPC_PROXY + { NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, ippr_msnrpc_init, ippr_msnrpc_fini, + ippr_msnrpc_new, NULL, ippr_msnrpc_in, ippr_msnrpc_out, NULL, NULL }, #endif #ifdef IPF_NETBIOS_PROXY - { NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, NULL, - NULL, NULL, NULL, ippr_netbios_out, NULL }, + { NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, ippr_netbios_fini, + NULL, NULL, NULL, ippr_netbios_out, NULL, NULL }, +#endif +#ifdef IPF_IPSEC_PROXY + { NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, + ippr_ipsec_init, ippr_ipsec_fini, ippr_ipsec_new, ippr_ipsec_del, + ippr_ipsec_inout, ippr_ipsec_inout, ippr_ipsec_match, NULL }, +#endif +#ifdef IPF_PPTP_PROXY + { NULL, "pptp", (char)IPPROTO_TCP, 0, 0, + ippr_pptp_init, ippr_pptp_fini, ippr_pptp_new, ippr_pptp_del, + ippr_pptp_inout, ippr_pptp_inout, ippr_pptp_match, NULL }, #endif #ifdef IPF_H323_PROXY - { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, NULL, - ippr_h323_new, ippr_h323_del, ippr_h323_in, ippr_h323_out, NULL }, - { NULL, "h245", (char)IPPROTO_TCP, 0, 0, ippr_h245_init, NULL, - ippr_h245_new, NULL, NULL, ippr_h245_out, NULL }, -#endif - { NULL, "", '\0', 0, 0, NULL, NULL, NULL } + { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, ippr_h323_fini, + ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL }, + { NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL, + ippr_h245_new, NULL, NULL, ippr_h245_out, NULL }, +#endif +#ifdef IPF_RPCB_PROXY +# if 0 + { NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, + ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, + ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, +# endif + { NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, + ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, + ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, +#endif + { NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL } }; - /* * Dynamically add a new kernel proxy. Ensure that it is unique in the * collection compiled in and dynamically added. @@ -159,14 +184,38 @@ aproxy_t *ap; sizeof(ap->apr_label))) return -1; - for (a = ap_proxylist; a && a->apr_p; a = a->apr_next) + for (a = ap_proxylist; a->apr_p; a = a->apr_next) if ((a->apr_p == ap->apr_p) && !strncmp(a->apr_label, ap->apr_label, sizeof(ap->apr_label))) return -1; ap->apr_next = ap_proxylist; ap_proxylist = ap; - return (*ap->apr_init)(); + if (ap->apr_init != NULL) + return (*ap->apr_init)(); + return 0; +} + + +/* + * Check to see if the proxy this control request has come through for + * exists, and if it does and it has a control function then invoke that + * control function. + */ +int appr_ctl(ctl) +ap_ctl_t *ctl; +{ + aproxy_t *a; + int error; + + a = appr_lookup(ctl->apc_p, ctl->apc_label); + if (a == NULL) + error = ESRCH; + else if (a->apr_ctl == NULL) + error = ENXIO; + else + error = (*a->apr_ctl)(a, ctl); + return error; } @@ -180,7 +229,7 @@ aproxy_t *ap; { aproxy_t *a, **app; - for (app = &ap_proxylist; (a = *app); app = &a->apr_next) + for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) if (a == ap) { a->apr_flags |= APR_DELETE; *app = a->apr_next; @@ -195,8 +244,8 @@ aproxy_t *ap; /* * Return 1 if the packet is a good match against a proxy, else 0. */ -int appr_ok(ip, tcp, nat) -ip_t *ip; +int appr_ok(fin, tcp, nat) +fr_info_t *fin; tcphdr_t *tcp; ipnat_t *nat; { @@ -204,14 +253,61 @@ ipnat_t *nat; u_short dport = nat->in_dport; if ((apr == NULL) || (apr->apr_flags & APR_DELETE) || - (ip->ip_p != apr->apr_p)) + (fin->fin_p != apr->apr_p)) return 0; - if (((tcp != NULL) && (tcp->th_dport != dport)) || (!tcp && dport)) + if ((tcp == NULL) && dport) return 0; return 1; } +int appr_ioctl(data, cmd, mode) +caddr_t data; +ioctlcmd_t cmd; +int mode; +{ + ap_ctl_t ctl; + caddr_t ptr; + int error; + + mode = mode; /* LINT */ + + switch (cmd) + { + case SIOCPROXY : + BCOPYIN(data, &ctl, sizeof(ctl)); + ptr = NULL; + + if (ctl.apc_dsize > 0) { + KMALLOCS(ptr, caddr_t, ctl.apc_dsize); + if (ptr == NULL) + error = ENOMEM; + else { + error = copyinptr(ctl.apc_data, ptr, + ctl.apc_dsize); + if (error == 0) + ctl.apc_data = ptr; + } + } else { + ctl.apc_data = NULL; + error = 0; + } + + if (error == 0) + error = appr_ctl(&ctl); + + if (ctl.apc_dsize > 0 && ptr != NULL && ctl.apc_data == ptr) { + KFREES(ptr, ctl.apc_dsize); + } + break; + + default : + error = EINVAL; + } + return error; +} + + /* * If a proxy has a match function, call that to do extended packet * matching. @@ -223,6 +319,9 @@ nat_t *nat; aproxy_t *apr; ipnat_t *ipn; + if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) + return -1; + ipn = nat->nat_ptr; if (ipn == NULL) return -1; @@ -242,9 +341,8 @@ nat_t *nat; * relevant details. call the init function once complete, prior to * returning. */ -int appr_new(fin, ip, nat) +int appr_new(fin, nat) fr_info_t *fin; -ip_t *ip; nat_t *nat; { register ap_session_t *aps; @@ -255,19 +353,20 @@ nat_t *nat; apr = nat->nat_ptr->in_apr; - if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) + if (!apr || (apr->apr_flags & APR_DELETE) || + (fin->fin_p != apr->apr_p)) return -1; KMALLOC(aps, ap_session_t *); if (!aps) return -1; bzero((char *)aps, sizeof(*aps)); - aps->aps_p = ip->ip_p; + aps->aps_p = fin->fin_p; aps->aps_data = NULL; aps->aps_apr = apr; aps->aps_psiz = 0; if (apr->apr_new != NULL) - if ((*apr->apr_new)(fin, ip, aps, nat) == -1) { + if ((*apr->apr_new)(fin, aps, nat) == -1) { if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) { KFREES(aps->aps_data, aps->aps_psiz); } @@ -284,78 +383,100 @@ nat_t *nat; /* - * check to see if a packet should be passed through an active proxy routine - * if one has been setup for it. + * Check to see if a packet should be passed through an active proxy routine + * if one has been setup for it. We don't need to check the checksum here if + * IPFILTER_CKSUM is defined because if it is, a failed check causes FI_BAD + * to be set. */ -int appr_check(ip, fin, nat) -ip_t *ip; +int appr_check(fin, nat) fr_info_t *fin; nat_t *nat; { #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - mb_t *m = fin->fin_qfm; +# if defined(ICK_VALID) + mb_t *m; +# endif int dosum = 1; #endif tcphdr_t *tcp = NULL; + udphdr_t *udp = NULL; ap_session_t *aps; aproxy_t *apr; - u_32_t sum; + ip_t *ip; short rv; int err; +#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) + u_32_t s1, s2, sd; +#endif + + if (fin->fin_flx & FI_BAD) + return -1; + +#ifndef IPFILTER_CKSUM + if ((fin->fin_out == 0) && (fr_checkl4sum(fin) == -1)) { +# if PROXY_DEBUG || !defined(_KERNEL) + printf("proxy l4 checksum failure\n"); +# endif + if (fin->fin_p == IPPROTO_TCP) + frstats[fin->fin_out].fr_tcpbad++; + return -1; + } +#endif aps = nat->nat_aps; - if ((aps != NULL) && (aps->aps_p == ip->ip_p)) { - if (ip->ip_p == IPPROTO_TCP) { - tcp = (tcphdr_t *)fin->fin_dp; - /* - * verify that the checksum is correct. If not, then - * don't do anything with this packet. - */ -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - if (dohwcksum && (m->b_ick_flag == ICK_VALID)) { - sum = tcp->th_sum; - dosum = 0; - } - if (dosum) - sum = fr_tcpsum(fin->fin_qfm, ip, tcp); -#else - sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); -#endif - if (sum != tcp->th_sum) { -#if PROXY_DEBUG - printf("proxy tcp checksum failure\n"); -#endif - frstats[fin->fin_out].fr_tcpbad++; + if ((aps != NULL) && (aps->aps_p == fin->fin_p)) { + /* + * If there is data in this packet to be proxied then try and + * get it all into the one buffer, else drop it. + */ + if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE)) + if (fr_coalesce(fin) == -1) return -1; - } + ip = fin->fin_ip; + switch (fin->fin_p) + { + case IPPROTO_TCP : + tcp = (tcphdr_t *)fin->fin_dp; + +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) + m = fin->fin_qfm; + if (dohwcksum && (m->b_ick_flag == ICK_VALID)) + dosum = 0; +#endif /* - * Don't both the proxy with these...or in fact, should - * we free up proxy stuff when seen? + * Don't bother the proxy with these...or in fact, + * should we free up proxy stuff when seen? */ - if ((tcp->th_flags & TH_RST) != 0) - return 0; + if ((fin->fin_tcpf & TH_RST) != 0) + break; + /*FALLTHROUGH*/ + case IPPROTO_UDP : + udp = (udphdr_t *)fin->fin_dp; + break; + default : + break; } apr = aps->aps_apr; err = 0; if (fin->fin_out != 0) { if (apr->apr_outpkt != NULL) - err = (*apr->apr_outpkt)(fin, ip, aps, nat); + err = (*apr->apr_outpkt)(fin, aps, nat); } else { if (apr->apr_inpkt != NULL) - err = (*apr->apr_inpkt)(fin, ip, aps, nat); + err = (*apr->apr_inpkt)(fin, aps, nat); } rv = APR_EXIT(err); if (rv == 1) { -#if PROXY_DEBUG +#if PROXY_DEBUG || !defined(_KERNEL) printf("proxy says bad packet received\n"); #endif return -1; } if (rv == 2) { -#if PROXY_DEBUG +#if PROXY_DEBUG || !defined(_KERNEL) printf("proxy says free app proxy data\n"); #endif appr_free(apr); @@ -363,16 +484,52 @@ nat_t *nat; return -1; } + /* + * If err != 0 then the data size of the packet has changed + * so we need to recalculate the header checksums for the + * packet. + */ +#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) + if (err != 0) { + short adjlen = err & 0xffff; + + s1 = LONG_SUM(ip->ip_len - adjlen); + s2 = LONG_SUM(ip->ip_len); + CALC_SUMD(s1, s2, sd); + fix_outcksum(fin, &ip->ip_sum, sd); + } +#endif + + /* + * For TCP packets, we may need to adjust the sequence and + * acknowledgement numbers to reflect changes in size of the + * data stream. + * + * For both TCP and UDP, recalculate the layer 4 checksum, + * regardless, as we can't tell (here) if data has been + * changed or not. + */ if (tcp != NULL) { err = appr_fixseqack(fin, ip, aps, APR_INC(err)); #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) if (dosum) - tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); + tcp->th_sum = fr_cksum(fin->fin_qfm, ip, + IPPROTO_TCP, tcp); #else - tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); + tcp->th_sum = fr_cksum(fin->fin_m, ip, + IPPROTO_TCP, tcp); +#endif + } else if ((udp != NULL) && (udp->uh_sum != 0)) { +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + if (dosum) + udp->uh_sum = fr_cksum(fin->fin_qfm, ip, + IPPROTO_UDP, udp); +#else + udp->uh_sum = fr_cksum(fin->fin_m, ip, + IPPROTO_UDP, udp); #endif } - aps->aps_bytes += ip->ip_len; + aps->aps_bytes += fin->fin_plen; aps->aps_pkts++; return 1; } @@ -422,7 +579,7 @@ ap_session_t *aps; if (!aps) return; - for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next) + for (ap = &ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next) if (a == aps) { *ap = a->aps_next; break; @@ -431,7 +588,7 @@ ap_session_t *aps; apr = aps->aps_apr; if ((apr != NULL) && (apr->apr_del != NULL)) (*apr->apr_del)(aps); - + if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) KFREES(aps->aps_data, aps->aps_psiz); KFREE(aps); @@ -458,7 +615,7 @@ int inc; * ip_len has already been adjusted by 'inc'. */ nlen = ip->ip_len; - nlen -= (ip->ip_hl << 2) + (tcp->th_off << 2); + nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2); inc2 = inc; inc = (int)inc2; @@ -475,7 +632,7 @@ int inc; sel, !sel, seq1, aps->aps_seqmin[!sel]); #endif sel = aps->aps_sel[out] = !sel; -} + } if (aps->aps_seqoff[sel]) { seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; @@ -510,7 +667,7 @@ int inc; sel, !sel, seq1, aps->aps_ackmin[!sel]); #endif sel = aps->aps_sel[1 - out] = !sel; -} + } if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { seq2 = aps->aps_ackoff[sel]; @@ -529,7 +686,7 @@ int inc; sel, !sel, seq1, aps->aps_ackmin[!sel]); #endif sel = aps->aps_sel[out] = !sel; -} + } if (aps->aps_ackoff[sel]) { seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel]; @@ -564,7 +721,7 @@ int inc; sel, !sel, seq1, aps->aps_seqmin[!sel]); #endif sel = aps->aps_sel[1 - out] = !sel; -} + } if (aps->aps_seqoff[sel] != 0) { #if PROXY_DEBUG @@ -580,7 +737,7 @@ int inc; } } #if PROXY_DEBUG - printf("appr_fixseqack: seq %x ack %x\n", ntohl(tcp->th_seq), + printf("appr_fixseqack: seq %lx ack %lx\n", ntohl(tcp->th_seq), ntohl(tcp->th_ack)); #endif return ch ? 2 : 0; @@ -597,9 +754,11 @@ int appr_init() int err = 0; for (ap = ap_proxies; ap->apr_p; ap++) { - err = (*ap->apr_init)(); - if (err != 0) - break; + if (ap->apr_init != NULL) { + err = (*ap->apr_init)(); + if (err != 0) + break; + } } return err; } @@ -614,9 +773,9 @@ void appr_unload() aproxy_t *ap; for (ap = ap_proxies; ap->apr_p; ap++) - if (ap->apr_fini) + if (ap->apr_fini != NULL) (*ap->apr_fini)(); for (ap = ap_proxylist; ap; ap = ap->apr_next) - if (ap->apr_fini) + if (ap->apr_fini != NULL) (*ap->apr_fini)(); } diff --git a/sys/netinet/ip_proxy.h b/sys/netinet/ip_proxy.h index 1f44ab7f7017..9d02f114a681 100644 --- a/sys/netinet/ip_proxy.h +++ b/sys/netinet/ip_proxy.h @@ -1,11 +1,11 @@ -/* $NetBSD: ip_proxy.h,v 1.18 2002/09/19 08:09:18 martti Exp $ */ +/* $NetBSD: ip_proxy.h,v 1.19 2004/03/28 09:00:57 martti Exp $ */ /* * Copyright (C) 1997-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * - * Id: ip_proxy.h,v 2.8.2.13 2002/07/04 11:07:37 darrenr Exp + * Id: ip_proxy.h,v 2.31 2003/07/25 12:29:59 darrenr Exp */ #ifndef _NETINET_IP_PROXY_H_ @@ -66,6 +66,26 @@ typedef struct ap_session { #define aps_ackmin aps_un.apu_tcp.apt_ackmin +typedef struct ap_control { + char apc_label[APR_LABELLEN]; + u_char apc_p; + /* + * The following fields are upto the proxy's apr_ctl routine to deal + * with. When the proxy gets this in kernel space, apc_data will + * point to a malloc'd region of memory of apc_dsize bytes. If the + * proxy wants to keep that memory, it must set apc_data to NULL + * before it returns. It is expected if this happens that it will + * take care to free it in apr_fini or otherwise as appropriate. + * apc_cmd is provided as a standard place to put simple commands, + * with apc_arg being available to put a simple arg. + */ + u_long apc_cmd; + u_long apc_arg; + void *apc_data; + size_t apc_dsize; +} ap_ctl_t; + + typedef struct aproxy { struct aproxy *apr_next; char apr_label[APR_LABELLEN]; /* Proxy label # */ @@ -74,29 +94,52 @@ typedef struct aproxy { int apr_flags; int (* apr_init) __P((void)); void (* apr_fini) __P((void)); - int (* apr_new) __P((fr_info_t *, ip_t *, - ap_session_t *, struct nat *)); + int (* apr_new) __P((fr_info_t *, ap_session_t *, struct nat *)); void (* apr_del) __P((ap_session_t *)); - int (* apr_inpkt) __P((fr_info_t *, ip_t *, - ap_session_t *, struct nat *)); - int (* apr_outpkt) __P((fr_info_t *, ip_t *, - ap_session_t *, struct nat *)); + int (* apr_inpkt) __P((fr_info_t *, ap_session_t *, struct nat *)); + int (* apr_outpkt) __P((fr_info_t *, ap_session_t *, struct nat *)); int (* apr_match) __P((fr_info_t *, ap_session_t *, struct nat *)); + int (* apr_ctl) __P((struct aproxy *, struct ap_control *)); } aproxy_t; #define APR_DELETE 1 -#define APR_ERR(x) (((x) & 0xffff) << 16) +#define APR_ERR(x) ((x) << 16) #define APR_EXIT(x) (((x) >> 16) & 0xffff) #define APR_INC(x) ((x) & 0xffff) -#define FTP_BUFSZ 160 +/* + * Generic #define's to cover missing things in the kernel + */ +#ifndef isdigit +#define isdigit(x) ((x) >= '0' && (x) <= '9') +#endif +#ifndef isupper +#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z')) +#endif +#ifndef islower +#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) +#endif +#ifndef isalpha +#define isalpha(x) (isupper(x) || islower(x)) +#endif +#ifndef toupper +#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') +#endif +#ifndef isspace +#define isspace(x) (((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \ + ((x) == '\t') || ((x) == '\b')) +#endif + /* * For the ftp proxy. */ +#define FTP_BUFSZ 160 + typedef struct ftpside { char *ftps_rptr; char *ftps_wptr; + void *ftps_ifp; u_32_t ftps_seq[2]; u_32_t ftps_len; int ftps_junk; @@ -110,6 +153,22 @@ typedef struct ftpinfo { ftpside_t ftp_side[2]; } ftpinfo_t; + +/* + * For the irc proxy. + */ +typedef struct ircinfo { + size_t irc_len; + char *irc_snick; + char *irc_dnick; + char *irc_type; + char *irc_arg; + char *irc_addr; + u_32_t irc_ipnum; + u_short irc_port; +} ircinfo_t; + + /* * Real audio proxy structure and #defines */ @@ -141,6 +200,16 @@ typedef struct raudio_s { #define RAP_M_TCP 4 #define RAP_M_UDP_ROBUST (RAP_M_UDP|RAP_M_ROBUST) + +typedef struct msnrpcinfo { + u_int mri_flags; + int mri_cmd[2]; + u_int mri_valid; + struct in_addr mri_raddr; + u_short mri_rport; +} msnrpcinfo_t; + + /* * IPSec proxy */ @@ -155,21 +224,195 @@ typedef struct ipsec_pxy { ipstate_t *ipsc_state; } ipsec_pxy_t; +/* + * Sun RPCBIND proxy + */ +#define RPCB_MAXMSG 888 +#define RPCB_RES_PMAP 0 /* Response contains a v2 port. */ +#define RPCB_RES_STRING 1 /* " " " v3 (GETADDR) string. */ +#define RPCB_RES_LIST 2 /* " " " v4 (GETADDRLIST) list. */ +#define RPCB_MAXREQS 32 /* Arbitrary limit on tracked transactions */ + +#define RPCB_REQMIN 40 +#define RPCB_REQMAX 888 +#define RPCB_REPMIN 20 +#define RPCB_REPMAX 604 /* XXX double check this! */ + +/* + * These macros determine the number of bytes between p and the end of + * r->rs_buf relative to l. + */ +#define RPCB_BUF_END(r) (char *)((r)->rm_msgbuf + (r)->rm_buflen) +#define RPCB_BUF_GEQ(r, p, l) \ + ((RPCB_BUF_END((r)) > (char *)(p)) && \ + ((RPCB_BUF_END((r)) - (char *)(p)) >= (l))) +#define RPCB_BUF_EQ(r, p, l) \ + (RPCB_BUF_END((r)) == ((char *)(p) + (l))) + +/* + * The following correspond to RPC(B) detailed in RFC183[13]. + */ +#define RPCB_CALL 0 +#define RPCB_REPLY 1 +#define RPCB_MSG_VERSION 2 +#define RPCB_PROG 100000 +#define RPCB_GETPORT 3 +#define RPCB_GETADDR 3 +#define RPCB_GETADDRLIST 11 +#define RPCB_MSG_ACCEPTED 0 +#define RPCB_MSG_DENIED 1 + +/* BEGIN (Generic XDR structures) */ +typedef struct xdr_string { + u_32_t *xs_len; + char *xs_str; +} xdr_string_t; + +typedef struct xdr_auth { + /* u_32_t xa_flavor; */ + xdr_string_t xa_string; +} xdr_auth_t; + +typedef struct xdr_uaddr { + u_32_t xu_ip; + u_short xu_port; + xdr_string_t xu_str; +} xdr_uaddr_t; + +typedef struct xdr_proto { + u_int xp_proto; + xdr_string_t xp_str; +} xdr_proto_t; + +#define xu_xslen xu_str.xs_len +#define xu_xsstr xu_str.xs_str +#define xp_xslen xp_str.xs_len +#define xp_xsstr xp_str.xs_str +/* END (Generic XDR structures) */ + +/* BEGIN (RPC call structures) */ +typedef struct pmap_args { + /* u_32_t pa_prog; */ + /* u_32_t pa_vers; */ + u_32_t *pa_prot; + /* u_32_t pa_port; */ +} pmap_args_t; + +typedef struct rpcb_args { + /* u_32_t *ra_prog; */ + /* u_32_t *ra_vers; */ + xdr_proto_t ra_netid; + xdr_uaddr_t ra_maddr; + /* xdr_string_t ra_owner; */ +} rpcb_args_t; + +typedef struct rpc_call { + /* u_32_t rc_rpcvers; */ + /* u_32_t rc_prog; */ + u_32_t *rc_vers; + u_32_t *rc_proc; + xdr_auth_t rc_authcred; + xdr_auth_t rc_authverf; + union { + pmap_args_t ra_pmapargs; + rpcb_args_t ra_rpcbargs; + } rpcb_args; +} rpc_call_t; + +#define rc_pmapargs rpcb_args.ra_pmapargs +#define rc_rpcbargs rpcb_args.ra_rpcbargs +/* END (RPC call structures) */ + +/* BEGIN (RPC reply structures) */ +typedef struct rpcb_entry { + xdr_uaddr_t re_maddr; + xdr_proto_t re_netid; + /* u_32_t re_semantics; */ + xdr_string_t re_family; + xdr_proto_t re_proto; + u_32_t *re_more; /* 1 == another entry follows */ +} rpcb_entry_t; + +typedef struct rpcb_listp { + u_32_t *rl_list; /* 1 == list follows */ + int rl_cnt; + rpcb_entry_t rl_entries[2]; /* TCP / UDP only */ +} rpcb_listp_t; + +typedef struct rpc_resp { + /* u_32_t rr_acceptdeny; */ + /* Omitted 'message denied' fork; we don't care about rejects. */ + xdr_auth_t rr_authverf; + /* u_32_t *rr_astat; */ + union { + u_32_t *resp_pmap; + xdr_uaddr_t resp_getaddr; + rpcb_listp_t resp_getaddrlist; + } rpcb_reply; +} rpc_resp_t; + +#define rr_v2 rpcb_reply.resp_pmap +#define rr_v3 rpcb_reply.resp_getaddr +#define rr_v4 rpcb_reply.resp_getaddrlist +/* END (RPC reply structures) */ + +/* BEGIN (RPC message structure & macros) */ +typedef struct rpc_msg { + char rm_msgbuf[RPCB_MAXMSG]; /* RPCB data buffer */ + u_int rm_buflen; + u_32_t *rm_xid; + /* u_32_t Call vs Reply */ + union { + rpc_call_t rb_call; + rpc_resp_t rb_resp; + } rm_body; +} rpc_msg_t; + +#define rm_call rm_body.rb_call +#define rm_resp rm_body.rb_resp +/* END (RPC message structure & macros) */ + +/* + * These code paths aren't hot enough to warrant per transaction + * mutexes. + */ +typedef struct rpcb_xact { + struct rpcb_xact *rx_next; + struct rpcb_xact **rx_pnext; + u_32_t rx_xid; /* RPC transmission ID */ + u_int rx_type; /* RPCB response type */ + u_int rx_ref; /* reference count */ + u_int rx_proto; /* transport protocol (v2 only) */ +} rpcb_xact_t; + +typedef struct rpcb_session { + ipfmutex_t rs_rxlock; + rpcb_xact_t *rs_rxlist; +} rpcb_session_t; + +/* + * For an explanation, please see the following: + * RFC1832 - Sections 3.11, 4.4, and 4.5. + */ +#define XDRALIGN(x) ((((x) % 4) != 0) ? ((((x) + 3) / 4) * 4) : (x)) + extern ap_session_t *ap_sess_tab[AP_SESS_SIZE]; extern ap_session_t *ap_sess_list; extern aproxy_t ap_proxies[]; extern int ippr_ftp_pasvonly; extern int appr_add __P((aproxy_t *)); +extern int appr_ctl __P((ap_ctl_t *)); extern int appr_del __P((aproxy_t *)); extern int appr_init __P((void)); extern void appr_unload __P((void)); -extern int appr_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); +extern int appr_ok __P((fr_info_t *, tcphdr_t *, struct ipnat *)); extern int appr_match __P((fr_info_t *, struct nat *)); extern void appr_free __P((aproxy_t *)); extern void aps_free __P((ap_session_t *)); -extern int appr_check __P((ip_t *, fr_info_t *, struct nat *)); +extern int appr_check __P((fr_info_t *, struct nat *)); extern aproxy_t *appr_lookup __P((u_int, char *)); -extern int appr_new __P((fr_info_t *, ip_t *, struct nat *)); +extern int appr_new __P((fr_info_t *, struct nat *)); +extern int appr_ioctl __P((caddr_t, ioctlcmd_t, int)); #endif /* _NETINET_IP_PROXY_H_ */ diff --git a/sys/netinet/ip_raudio_pxy.c b/sys/netinet/ip_raudio_pxy.c index e53009402423..c83dfc58570f 100644 --- a/sys/netinet/ip_raudio_pxy.c +++ b/sys/netinet/ip_raudio_pxy.c @@ -1,25 +1,29 @@ -/* $NetBSD: ip_raudio_pxy.c,v 1.8 2002/01/24 08:23:14 martti Exp $ */ +/* $NetBSD: ip_raudio_pxy.c,v 1.9 2004/03/28 09:00:57 martti Exp $ */ #include -__KERNEL_RCSID(1, "$NetBSD: ip_raudio_pxy.c,v 1.8 2002/01/24 08:23:14 martti Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ip_raudio_pxy.c,v 1.9 2004/03/28 09:00:57 martti Exp $"); /* - * Id: ip_raudio_pxy.c,v 1.7.2.8 2002/01/13 04:58:29 darrenr Exp + * Copyright (C) 1998-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ip_raudio_pxy.c,v 1.40 2004/01/27 00:31:38 darrenr Exp */ -#if SOLARIS && defined(_KERNEL) -extern kmutex_t ipf_rw; -#endif #define IPF_RAUDIO_PROXY int ippr_raudio_init __P((void)); -int ippr_raudio_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_raudio_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_raudio_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_raudio_fini __P((void)); +int ippr_raudio_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_raudio_in __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_raudio_out __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t raudiofr; +int raudio_proxy_init = 0; + /* * Real Audio application proxy initialization. @@ -29,26 +33,39 @@ int ippr_raudio_init() bzero((char *)&raudiofr, sizeof(raudiofr)); raudiofr.fr_ref = 1; raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&raudiofr.fr_lock, "Real Audio proxy rule lock"); + raudio_proxy_init = 1; + return 0; } +void ippr_raudio_fini() +{ + if (raudio_proxy_init == 1) { + MUTEX_DESTROY(&raudiofr.fr_lock); + raudio_proxy_init = 0; + } +} + + /* * Setup for a new proxy to handle Real Audio. */ -int ippr_raudio_new(fin, ip, aps, nat) +int ippr_raudio_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { raudio_t *rap; - KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); if (aps->aps_data == NULL) return -1; + fin = fin; /* LINT */ + nat = nat; /* LINT */ + bzero(aps->aps_data, sizeof(raudio_t)); rap = aps->aps_data; aps->aps_psiz = sizeof(raudio_t); @@ -58,22 +75,20 @@ nat_t *nat; -int ippr_raudio_out(fin, ip, aps, nat) +int ippr_raudio_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { raudio_t *rap = aps->aps_data; unsigned char membuf[512 + 1], *s; u_short id = 0; - int off, dlen; tcphdr_t *tcp; + int off, dlen; int len = 0; mb_t *m; -#if SOLARIS - mb_t *m1; -#endif + + nat = nat; /* LINT */ /* * If we've already processed the start messages, then nothing left @@ -82,26 +97,19 @@ nat_t *nat; if (rap->rap_eos == 1) return 0; + m = fin->fin_m; tcp = (tcphdr_t *)fin->fin_dp; - off = fin->fin_hlen + (tcp->th_off << 2); - bzero(membuf, sizeof(membuf)); -#if SOLARIS - m = fin->fin_qfm; + off = (char *)tcp - MTOD(m, char *) + (TCP_OFF(tcp) << 2); + bzero((char *)membuf, sizeof(membuf)); - dlen = msgdsize(m) - off; + dlen = MSGDSIZE(m) - off; if (dlen <= 0) return 0; - dlen = MIN(sizeof(membuf), dlen); - copyout_mblk(m, off, dlen, (char *)membuf); -#else - m = *(mb_t **)fin->fin_mp; - dlen = mbufchainlen(m) - off; - if (dlen <= 0) - return 0; - dlen = MIN(sizeof(membuf), dlen); - m_copydata(m, off, dlen, (char *)membuf); -#endif + if (dlen > sizeof(membuf)) + dlen = sizeof(membuf); + + COPYDATA(m, off, dlen, (char *)membuf); /* * In all the startup parsing, ensure that we don't go outside * the packet buffer boundary. @@ -168,9 +176,8 @@ nat_t *nat; } -int ippr_raudio_in(fin, ip, aps, nat) +int ippr_raudio_in(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { @@ -183,12 +190,10 @@ nat_t *nat; u_short sp, dp; fr_info_t fi; tcp_seq seq; - nat_t *ipn; + nat_t *nat2; u_char swp; + ip_t *ip; mb_t *m; -#if SOLARIS - mb_t *m1; -#endif /* * Wait until we've seen the end of the start messages and even then @@ -198,27 +203,21 @@ nat_t *nat; if (rap->rap_sdone != 0) return 0; + m = fin->fin_m; + ip = fin->fin_ip; tcp = (tcphdr_t *)fin->fin_dp; - off = fin->fin_hlen + (tcp->th_off << 2); - m = *(mb_t **)fin->fin_mp; + off = (char *)tcp - MTOD(m, char *) + (TCP_OFF(tcp) << 2); -#if SOLARIS - m = fin->fin_qfm; - - dlen = msgdsize(m) - off; + dlen = MSGDSIZE(m) - off; if (dlen <= 0) return 0; - bzero(membuf, sizeof(membuf)); + + if (dlen > sizeof(membuf)) + dlen = sizeof(membuf); + + bzero((char *)membuf, sizeof(membuf)); clen = MIN(sizeof(membuf), dlen); - copyout_mblk(m, off, clen, (char *)membuf); -#else - dlen = mbufchainlen(m) - off; - if (dlen <= 0) - return 0; - bzero(membuf, sizeof(membuf)); - clen = MIN(sizeof(membuf), dlen); - m_copydata(m, off, clen, (char *)membuf); -#endif + COPYDATA(m, off, clen, (char *)membuf); seq = ntohl(tcp->th_seq); /* @@ -271,10 +270,12 @@ nat_t *nat; bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); - tcp2->th_off = 5; + TCP_OFF_A(tcp2, 5); + fi.fin_flx |= FI_IGNORE; fi.fin_dp = (char *)tcp2; fi.fin_fr = &raudiofr; fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); tcp2->th_win = htons(8192); slen = ip->ip_len; ip->ip_len = fin->fin_hlen + sizeof(*tcp); @@ -288,13 +289,14 @@ nat_t *nat; fi.fin_data[0] = dp; fi.fin_data[1] = sp; fi.fin_out = 0; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, - IPN_UDP | (sp ? 0 : FI_W_SPORT), NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_IGNOREPKT|FI_NORULE| - (sp ? 0 : FI_W_SPORT)); + nat2 = nat_new(&fi, nat->nat_ptr, NULL, + NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT), + NAT_OUTBOUND); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_UDP); + nat_update(&fi, nat2, nat2->nat_ptr); + + (void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT)); } } @@ -305,12 +307,14 @@ nat_t *nat; fi.fin_data[0] = sp; fi.fin_data[1] = 0; fi.fin_out = 1; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_UDP|FI_W_DPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, NULL, - FI_W_DPORT|FI_IGNOREPKT|FI_NORULE); + nat2 = nat_new(&fi, nat->nat_ptr, NULL, + NAT_SLAVE|IPN_UDP|SI_W_DPORT, + NAT_OUTBOUND); + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_UDP); + nat_update(&fi, nat2, nat2->nat_ptr); + + (void) fr_addstate(&fi, NULL, SI_W_DPORT); } } diff --git a/sys/netinet/ip_rcmd_pxy.c b/sys/netinet/ip_rcmd_pxy.c index 5a10ace48d14..3d32709bd68e 100644 --- a/sys/netinet/ip_rcmd_pxy.c +++ b/sys/netinet/ip_rcmd_pxy.c @@ -1,32 +1,34 @@ -/* $NetBSD: ip_rcmd_pxy.c,v 1.9 2002/01/24 08:23:45 martti Exp $ */ +/* $NetBSD: ip_rcmd_pxy.c,v 1.10 2004/03/28 09:00:57 martti Exp $ */ #include -__KERNEL_RCSID(1, "$NetBSD: ip_rcmd_pxy.c,v 1.9 2002/01/24 08:23:45 martti Exp $"); +__KERNEL_RCSID(1, "$NetBSD: ip_rcmd_pxy.c,v 1.10 2004/03/28 09:00:57 martti Exp $"); /* - * Id: ip_rcmd_pxy.c,v 1.4.2.5 2001/10/30 16:38:14 darrenr Exp - */ -/* + * Copyright (C) 1998-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: ip_rcmd_pxy.c,v 1.41 2004/01/27 00:31:38 darrenr Exp + * * Simple RCMD transparent proxy for in-kernel use. For use with the NAT * code. */ -#if SOLARIS && defined(_KERNEL) -extern kmutex_t ipf_rw; -#endif - -#define isdigit(x) ((x) >= '0' && (x) <= '9') #define IPF_RCMD_PROXY int ippr_rcmd_init __P((void)); -int ippr_rcmd_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_rcmd_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_rcmd_fini __P((void)); +int ippr_rcmd_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_in __P((fr_info_t *, ap_session_t *, nat_t *)); u_short ipf_rcmd_atoi __P((char *)); -int ippr_rcmd_portmsg __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *)); static frentry_t rcmdfr; +int rcmd_proxy_init = 0; + /* * RCMD application proxy initialization. @@ -36,25 +38,43 @@ int ippr_rcmd_init() bzero((char *)&rcmdfr, sizeof(rcmdfr)); rcmdfr.fr_ref = 1; rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock"); + rcmd_proxy_init = 1; + return 0; } +void ippr_rcmd_fini() +{ + if (rcmd_proxy_init == 1) { + MUTEX_DESTROY(&rcmdfr.fr_lock); + rcmd_proxy_init = 0; + } +} + + /* * Setup for a new RCMD proxy. */ -int ippr_rcmd_new(fin, ip, aps, nat) +int ippr_rcmd_new(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + fin = fin; /* LINT */ + nat = nat; /* LINT */ + aps->aps_psiz = sizeof(u_32_t); KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t)); - if (aps->aps_data == NULL) + if (aps->aps_data == NULL) { +#ifdef IP_RCMD_PROXY_DEBUG + printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t)); +#endif return -1; + } *(u_32_t *)aps->aps_data = 0; aps->aps_sport = tcp->th_sport; aps->aps_dport = tcp->th_dport; @@ -71,7 +91,7 @@ char *ptr; register char *s = ptr, c; register u_short i = 0; - while ((c = *s++) && isdigit(c)) { + while (((c = *s++) != '\0') && isdigit(c)) { i *= 10; i += c - '0'; } @@ -79,23 +99,20 @@ char *ptr; } -int ippr_rcmd_portmsg(fin, ip, aps, nat) +int ippr_rcmd_portmsg(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { - char portbuf[8], *s; - struct in_addr swip; - int off, dlen; tcphdr_t *tcp, tcph, *tcp2 = &tcph; + struct in_addr swip, swip2; + int off, dlen, nflags; + char portbuf[8], *s; fr_info_t fi; u_short sp; - nat_t *ipn; + nat_t *nat2; + ip_t *ip; mb_t *m; -#if SOLARIS - mb_t *m1; -#endif tcp = (tcphdr_t *)fin->fin_dp; @@ -108,37 +125,43 @@ nat_t *nat; (tcp->th_seq != *(u_32_t *)aps->aps_data)) return 0; - off = fin->fin_hlen + (tcp->th_off << 2); + m = fin->fin_m; + ip = fin->fin_ip; + off = (char *)tcp - MTOD(m, char *) + (TCP_OFF(tcp) << 2); -#if SOLARIS - m = fin->fin_qfm; + dlen = MSGDSIZE(m) - off; + if (dlen <= 0) + return 0; - dlen = msgdsize(m) - off; bzero(portbuf, sizeof(portbuf)); - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#else - m = *(mb_t **)fin->fin_mp; - dlen = mbufchainlen(m) - off; - bzero(portbuf, sizeof(portbuf)); - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); -#endif + COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf); portbuf[sizeof(portbuf) - 1] = '\0'; s = portbuf; sp = ipf_rcmd_atoi(s); - if (!sp) + if (sp == 0) { +#ifdef IP_RCMD_PROXY_DEBUG + printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n", + dlen, portbuf); +#endif return 0; + } /* * Add skeleton NAT entry for connection which will come back the * other way. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_flx |= FI_IGNORE; fi.fin_data[0] = sp; - fi.fin_data[1] = fin->fin_data[1]; - ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, 0); - if (ipn == NULL) { + fi.fin_data[1] = 0; + if (nat->nat_dir == NAT_OUTBOUND) + nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + else + nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, + nat->nat_inip, nat->nat_oip); + if (nat2 == NULL) { int slen; slen = ip->ip_len; @@ -147,32 +170,64 @@ nat_t *nat; tcp2->th_win = htons(8192); tcp2->th_sport = htons(sp); tcp2->th_dport = 0; /* XXX - don't specify remote port */ - tcp2->th_off = 5; - fi.fin_data[1] = 0; + TCP_OFF_A(tcp2, 5); + tcp2->th_flags = TH_SYN; fi.fin_dp = (char *)tcp2; + fi.fin_fr = &rcmdfr; fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); + fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; + nflags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; + swip = ip->ip_src; - ip->ip_src = nat->nat_inip; - ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT, - NAT_OUTBOUND); - if (ipn != NULL) { - ipn->nat_age = fr_defnatage; - fi.fin_fr = &rcmdfr; - (void) fr_addstate(ip, &fi, NULL, - FI_W_DPORT|FI_IGNOREPKT); + swip2 = ip->ip_dst; + + if (nat->nat_dir == NAT_OUTBOUND) { + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; + ip->ip_src = nat->nat_inip; + } else { + fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; + ip->ip_src = nat->nat_oip; + nflags |= NAT_NOTRULEPORT; + } + + nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); + + if (nat2 != NULL) { + (void) nat_proto(&fi, nat2, IPN_TCP); + nat_update(&fi, nat2, nat2->nat_ptr); + fi.fin_ifp = NULL; + if (nat->nat_dir == NAT_INBOUND) { + fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; + ip->ip_dst = nat->nat_inip; + } + (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); } ip->ip_len = slen; ip->ip_src = swip; + ip->ip_dst = swip2; } return 0; } -int ippr_rcmd_out(fin, ip, aps, nat) +int ippr_rcmd_out(fin, aps, nat) fr_info_t *fin; -ip_t *ip; ap_session_t *aps; nat_t *nat; { - return ippr_rcmd_portmsg(fin, ip, aps, nat); + if (nat->nat_dir == NAT_OUTBOUND) + return ippr_rcmd_portmsg(fin, aps, nat); + return 0; +} + + +int ippr_rcmd_in(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + if (nat->nat_dir == NAT_INBOUND) + return ippr_rcmd_portmsg(fin, aps, nat); + return 0; } diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c index 083cb94f9a7e..a90b34d14c92 100644 --- a/sys/netinet/ip_state.c +++ b/sys/netinet/ip_state.c @@ -1,12 +1,15 @@ -/* $NetBSD: ip_state.c,v 1.43 2004/02/24 15:22:01 wiz Exp $ */ +/* $NetBSD: ip_state.c,v 1.44 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1995-2002 by Darren Reed. + * Copyright (C) 1995-2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ -#ifdef __sgi -# include +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 #endif #include #include @@ -20,17 +23,18 @@ (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) #include "opt_inet6.h" #endif -#if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) +#if !defined(_KERNEL) && !defined(__KERNEL__) # include # include # include -#else -# ifdef linux -# include -# include +# define _KERNEL +# ifdef __OpenBSD__ +struct file; # endif +# include +# undef _KERNEL #endif -#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +#if defined(_KERNEL) && (__FreeBSD_version >= 220000) # include # include # if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) @@ -40,18 +44,17 @@ # include #endif #include -#ifndef linux +#if !defined(linux) # include #endif #include -#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) +#if defined(_KERNEL) # include -#endif -#if !defined(__SVR4) && !defined(__svr4__) -# ifndef linux +# if !defined(__SVR4) && !defined(__svr4__) # include # endif -#else +#endif +#if defined(__SVR4) || defined(__svr4__) # include # include # ifdef _KERNEL @@ -70,8 +73,10 @@ #include #include #include -#ifndef linux +#if !defined(linux) # include +#endif +#if !defined(__hpux) && !defined(linux) # include #endif #include @@ -82,93 +87,132 @@ #include "netinet/ip_nat.h" #include "netinet/ip_frag.h" #include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#ifdef IPFILTER_SYNC +#include "netinet/ip_sync.h" +#endif +#ifdef IPFILTER_SCAN +#include "netinet/ip_scan.h" +#endif #ifdef USE_INET6 #include #endif #if (__FreeBSD_version >= 300000) # include -# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# if defined(_KERNEL) && !defined(IPFILTER_LKM) # include # include # endif #endif +/* END OF INCLUDES */ + #if !defined(lint) #if defined(__NetBSD__) #include -__KERNEL_RCSID(0, "$NetBSD: ip_state.c,v 1.43 2004/02/24 15:22:01 wiz Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_state.c,v 1.44 2004/03/28 09:00:57 martti Exp $"); #else static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)Id: ip_state.c,v 2.30.2.74 2002/07/27 15:58:10 darrenr Exp"; +static const char rcsid[] = "@(#)Id: ip_state.c,v 2.186.2.4 2004/03/22 12:24:12 darrenr Exp"; #endif #endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#define TCP_CLOSE (TH_FIN|TH_RST) - -static ipstate_t **ips_table = NULL; -static int ips_num = 0; -static int ips_wild = 0; -static ips_stat_t ips_stats; -#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_state, ipf_mutex; -extern kmutex_t ipf_rw; -#endif +static ipstate_t **ips_table = NULL; +static u_long *ips_seed = NULL; +static int ips_num = 0; +static u_long ips_last_force_flush = 0; +ips_stat_t ips_stats; #ifdef USE_INET6 -static frentry_t *fr_checkicmp6matchingstate __P((ip6_t *, fr_info_t *)); +static ipstate_t *fr_checkicmp6matchingstate __P((fr_info_t *)); #endif -static int fr_matchsrcdst __P((ipstate_t *, union i6addr, union i6addr, - fr_info_t *, tcphdr_t *)); -static frentry_t *fr_checkicmpmatchingstate __P((ip_t *, fr_info_t *)); -static int fr_matchicmpqueryreply __P((int, ipstate_t *, icmphdr_t *)); +static ipstate_t *fr_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *, + i6addr_t *, tcphdr_t *)); +static ipstate_t *fr_checkicmpmatchingstate __P((fr_info_t *)); static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); -static void fr_delstate __P((ipstate_t *)); +static void fr_delstate __P((ipstate_t *, int)); static int fr_state_remove __P((caddr_t)); -static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int)); -static int fr_tcpoptions __P((tcphdr_t *)); +static void fr_ipsmove __P((ipstate_t *, u_int)); +static int fr_tcpstate __P((fr_info_t *, tcphdr_t *, ipstate_t *)); +static int fr_tcpoptions __P((fr_info_t *, tcphdr_t *, tcpdata_t *)); +static ipstate_t *fr_stclone __P((fr_info_t *, tcphdr_t *, ipstate_t *)); +static void fr_fixinisn __P((fr_info_t *, ipstate_t *)); +static void fr_fixoutisn __P((fr_info_t *, ipstate_t *)); +static void fr_checknewisn __P((fr_info_t *, ipstate_t *)); + int fr_stputent __P((caddr_t)); int fr_stgetent __P((caddr_t)); -void fr_stinsert __P((ipstate_t *)); +#define ONE_DAY IPF_TTLVAL(1 * 86400) /* 1 day */ +#define FIVE_DAYS (5 * ONE_DAY) +#define DOUBLE_HASH(x) (((x) + ips_seed[(x) % fr_statesize]) % fr_statesize) -#define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */ - -#define TCP_MSL 240 /* 2 minutes */ u_long fr_tcpidletimeout = FIVE_DAYS, - fr_tcpclosewait = 2 * TCP_MSL, - fr_tcplastack = 2 * TCP_MSL, - fr_tcptimeout = 2 * TCP_MSL, - fr_tcpclosed = 120, - fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */ - fr_udptimeout = 240, - fr_udpacktimeout = 24, - fr_icmptimeout = 120, - fr_icmpacktimeout = 12; + fr_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL), + fr_tcplastack = IPF_TTLVAL(2 * TCP_MSL), + fr_tcptimeout = IPF_TTLVAL(2 * TCP_MSL), + fr_tcpclosed = IPF_TTLVAL(60), + fr_tcphalfclosed = IPF_TTLVAL(2 * 3600), /* 2 hours */ + fr_udptimeout = IPF_TTLVAL(120), + fr_udpacktimeout = IPF_TTLVAL(12), + fr_icmptimeout = IPF_TTLVAL(60), + fr_icmpacktimeout = IPF_TTLVAL(6); int fr_statemax = IPSTATE_MAX, fr_statesize = IPSTATE_SIZE; int fr_state_doflush = 0, - fr_state_lock = 0; + fr_state_lock = 0, + fr_state_maxbucket = 0, + fr_state_maxbucket_reset = 1, + fr_state_init = 0; +ipftq_t ips_tqtqb[IPF_TCP_NSTATES], + ips_udptq, + ips_udpacktq, + ips_icmptq, + ips_icmpacktq, + *ips_utqe = NULL; +#ifdef IPFILTER_LOG +int ipstate_logging = 1; +#else +int ipstate_logging = 0; +#endif ipstate_t *ips_list = NULL; -static int icmpreplytype4[ICMP_MAXTYPE + 1]; -#ifdef USE_INET6 -static int icmpreplytype6[ICMP6_MAXTYPE + 1]; -#endif +/* ------------------------------------------------------------------------ */ +/* Function: fr_stateinit */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: Nil */ +/* */ +/* Initialise all the global variables used within the state code. */ +/* This action also includes initiailising locks. */ +/* ------------------------------------------------------------------------ */ int fr_stateinit() { int i; KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *)); - if (ips_table != NULL) - bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *)); - else + if (ips_table == NULL) return -1; + bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *)); + + KMALLOCS(ips_seed, u_long *, fr_statesize * sizeof(*ips_seed)); + if (ips_seed == NULL) + return -1; + for (i = 0; i < fr_statesize; i++) { + /* + * XXX - ips_seed[X] should be a random number of sorts. + */ +#if (__FreeBSD_version >= 400000) + ips_seed[i] = arc4random(); +#else + ips_seed[i] = ((u_long)ips_seed + i) * fr_statesize; + ips_seed[i] ^= 0xa5a55a5a; + ips_seed[i] *= (u_long)ips_seed; + ips_seed[i] ^= 0x5a5aa5a5; + ips_seed[i] *= fr_statemax; +#endif + } /* fill icmp reply type table */ for (i = 0; i <= ICMP_MAXTYPE; i++) @@ -188,108 +232,128 @@ int fr_stateinit() icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; #endif + KMALLOCS(ips_stats.iss_bucketlen, u_long *, + fr_statesize * sizeof(u_long)); + if (ips_stats.iss_bucketlen == NULL) + return -1; + bzero((char *)ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long)); + + if (fr_state_maxbucket == 0) { + for (i = fr_statesize; i > 0; i >>= 1) + fr_state_maxbucket++; + fr_state_maxbucket *= 2; + } + + fr_sttab_init(ips_tqtqb); + ips_tqtqb[IPF_TCP_NSTATES - 1].ifq_next = &ips_udptq; + ips_udptq.ifq_ttl = (u_long)fr_udptimeout; + ips_udptq.ifq_head = NULL; + ips_udptq.ifq_tail = &ips_udptq.ifq_head; + MUTEX_INIT(&ips_udptq.ifq_lock, "ipftq udp tab"); + ips_udptq.ifq_next = &ips_udpacktq; + ips_udpacktq.ifq_ttl = (u_long)fr_udpacktimeout; + ips_udpacktq.ifq_head = NULL; + ips_udpacktq.ifq_tail = &ips_udpacktq.ifq_head; + MUTEX_INIT(&ips_udpacktq.ifq_lock, "ipftq udpack tab"); + ips_udpacktq.ifq_next = &ips_icmptq; + ips_icmptq.ifq_ttl = (u_long)fr_icmptimeout; + ips_icmptq.ifq_head = NULL; + ips_icmptq.ifq_tail = &ips_icmptq.ifq_head; + MUTEX_INIT(&ips_icmptq.ifq_lock, "ipftq icmp tab"); + ips_icmptq.ifq_next = &ips_icmpacktq; + ips_icmpacktq.ifq_ttl = (u_long)fr_icmpacktimeout; + ips_icmpacktq.ifq_head = NULL; + ips_icmpacktq.ifq_tail = &ips_icmpacktq.ifq_head; + MUTEX_INIT(&ips_icmpacktq.ifq_lock, "ipftq icmpack tab"); + ips_icmpacktq.ifq_next = NULL; + + RWLOCK_INIT(&ipf_state, "ipf IP state rwlock"); + MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex"); + fr_state_init = 1; + + ips_last_force_flush = fr_ticks; return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_stateunload */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Release and destroy any resources acquired or initialised so that */ +/* IPFilter can be unloaded or re-initialised. */ +/* ------------------------------------------------------------------------ */ +void fr_stateunload() +{ + ipstate_t *is; + + while ((is = ips_list) != NULL) + fr_delstate(is, 0); + ips_stats.iss_inuse = 0; + ips_num = 0; + + if (fr_state_init == 1) { + fr_sttab_destroy(ips_tqtqb); + MUTEX_DESTROY(&ips_udptq.ifq_lock); + MUTEX_DESTROY(&ips_icmptq.ifq_lock); + MUTEX_DESTROY(&ips_udpacktq.ifq_lock); + MUTEX_DESTROY(&ips_icmpacktq.ifq_lock); + } + + if (ips_table != NULL) { + KFREES(ips_table, fr_statesize * sizeof(*ips_table)); + ips_table = NULL; + } + + if (ips_seed != NULL) { + KFREES(ips_seed, fr_statesize * sizeof(*ips_seed)); + ips_seed = NULL; + } + + if (ips_stats.iss_bucketlen != NULL) { + KFREES(ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long)); + ips_stats.iss_bucketlen = NULL; + } + + if (fr_state_maxbucket_reset == 1) + fr_state_maxbucket = 0; + + if (fr_state_init == 1) { + fr_state_init = 0; + RW_DESTROY(&ipf_state); + MUTEX_DESTROY(&ipf_stinsert); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_statetstats */ +/* Returns: ips_state_t* - pointer to state stats structure */ +/* Parameters: Nil */ +/* */ +/* Put all the current numbers and pointers into a single struct and return */ +/* a pointer to it. */ +/* ------------------------------------------------------------------------ */ static ips_stat_t *fr_statetstats() { ips_stats.iss_active = ips_num; + ips_stats.iss_statesize = fr_statesize; + ips_stats.iss_statemax = fr_statemax; ips_stats.iss_table = ips_table; ips_stats.iss_list = ips_list; + ips_stats.iss_ticks = fr_ticks; return &ips_stats; } - -/* - * flush state tables. two actions currently defined: - * which == 0 : flush all state table entries - * which == 1 : flush TCP connections which have started to close but are - * stuck for some reason. - * which == 2 : flush TCP connections which have been idle for a long time, - * starting at > 4 days idle and working back in successive half- - * days to at most 12 hours old. - */ -static int fr_state_flush(which) -int which; -{ - ipstate_t *is, **isp; -#if defined(_KERNEL) && !SOLARIS - int s; -#endif - int delete, removed = 0, try; - - SPL_NET(s); - for (isp = &ips_list; (is = *isp); ) { - delete = 0; - - switch (which) - { - case 0 : - delete = 1; - break; - case 1 : - case 2 : - if (is->is_p != IPPROTO_TCP) - break; - if ((is->is_state[0] != TCPS_ESTABLISHED) || - (is->is_state[1] != TCPS_ESTABLISHED)) - delete = 1; - break; - } - - if (delete) { - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; -#ifdef IPFILTER_LOG - ipstate_log(is, ISL_FLUSH); -#endif - fr_delstate(is); - removed++; - } else - isp = &is->is_next; - } - - /* - * Asked to remove inactive entries, try again if first attempt - * failed. In this case, 86400 is half a day because the counter is - * activated every half second. - */ - if ((which == 2) && (removed == 0)) { - try = 86400; /* half a day */ - for (; (try < FIVE_DAYS) && (removed == 0); try += 86400) { - for (isp = &ips_list; (is = *isp); ) { - delete = 0; - if ((is->is_p == IPPROTO_TCP) && - ((is->is_state[0] == TCPS_ESTABLISHED) || - (is->is_state[1] == TCPS_ESTABLISHED)) && - (is->is_age < try)) { - ips_stats.iss_fin++; - delete = 1; - } else if ((is->is_p != IPPROTO_TCP) && - (is->is_pkts > 1)) { - ips_stats.iss_expire++; - delete = 1; - } - if (delete) { -#ifdef IPFILTER_LOG - ipstate_log(is, ISL_FLUSH); -#endif - fr_delstate(is); - removed++; - } else - isp = &is->is_next; - } - } - } - - SPL_X(s); - return removed; -} - - +/* ------------------------------------------------------------------------ */ +/* Function: fr_state_remove */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to state structure to delete from table */ +/* */ +/* Search for a state structure that matches the one passed, according to */ +/* the IP addresses and other protocol specific information. */ +/* ------------------------------------------------------------------------ */ static int fr_state_remove(data) caddr_t data; { @@ -297,23 +361,20 @@ caddr_t data; int error; sp = &st; - error = IRCOPYPTR(data, (caddr_t)&st, sizeof(st)); + error = fr_inobj(data, &st, IPFOBJ_IPSTATE); if (error) return EFAULT; WRITE_ENTER(&ipf_state); for (sp = ips_list; sp; sp = sp->is_next) if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && - !bcmp((char *)&sp->is_src, (char *)&st.is_src, + !bcmp((caddr_t)&sp->is_src, (caddr_t)&st.is_src, sizeof(st.is_src)) && - !bcmp((char *)&sp->is_dst, (char *)&st.is_dst, + !bcmp((caddr_t)&sp->is_dst, (caddr_t)&st.is_src, sizeof(st.is_dst)) && - !bcmp((char *)&sp->is_ps, (char *)&st.is_ps, + !bcmp((caddr_t)&sp->is_ps, (caddr_t)&st.is_ps, sizeof(st.is_ps))) { -#ifdef IPFILTER_LOG - ipstate_log(sp, ISL_REMOVE); -#endif - fr_delstate(sp); + fr_delstate(sp, ISL_REMOVE); RWLOCK_EXIT(&ipf_state); return 0; } @@ -322,35 +383,47 @@ caddr_t data; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_state_ioctl */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to ioctl data */ +/* cmd(I) - ioctl command integer */ +/* mode(I) - file mode bits used with open */ +/* */ +/* Processes an ioctl call made to operate on the IP Filter state device. */ +/* ------------------------------------------------------------------------ */ int fr_state_ioctl(data, cmd, mode) caddr_t data; -#if defined(__NetBSD__) || defined(__OpenBSD__) -u_long cmd; -#else -int cmd; -#endif +ioctlcmd_t cmd; int mode; { int arg, ret, error = 0; switch (cmd) { + /* + * Delete an entry from the state table. + */ case SIOCDELST : error = fr_state_remove(data); break; + /* + * Flush the state table + */ case SIOCIPFFL : - error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); - if (error) - break; + BCOPYIN(data, (char *)&arg, sizeof(arg)); if (arg == 0 || arg == 1) { WRITE_ENTER(&ipf_state); ret = fr_state_flush(arg); RWLOCK_EXIT(&ipf_state); - error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); + BCOPYOUT((char *)&ret, data, sizeof(ret)); } else error = EINVAL; break; #ifdef IPFILTER_LOG + /* + * Flush the state log. + */ case SIOCIPFFB : if (!(mode & FWRITE)) error = EPERM; @@ -358,23 +431,51 @@ int mode; int tmp; tmp = ipflog_clear(IPL_LOGSTATE); - IWCOPY((char *)&tmp, data, sizeof(tmp)); + BCOPYOUT((char *)&tmp, data, sizeof(tmp)); } break; -#endif - case SIOCGETFS : - error = IWCOPYPTR((caddr_t)fr_statetstats(), data, - sizeof(ips_stat_t)); + /* + * Turn logging of state information on/off. + */ + case SIOCSETLG : + if (!(mode & FWRITE)) + error = EPERM; + else { + BCOPYIN((char *)data, (char *)&ipstate_logging, + sizeof(ipstate_logging)); + } break; + /* + * Return the current state of logging. + */ + case SIOCGETLG : + BCOPYOUT((char *)&ipstate_logging, (char *)data, + sizeof(ipstate_logging)); + break; + /* + * Return the number of bytes currently waiting to be read. + */ case FIONREAD : -#ifdef IPFILTER_LOG - arg = (int)iplused[IPL_LOGSTATE]; - error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); -#endif + arg = iplused[IPL_LOGSTATE]; /* returned in an int */ + BCOPYOUT((char *)&arg, data, sizeof(arg)); break; +#endif + /* + * Get the current state statistics. + */ + case SIOCGETFS : + error = fr_outobj(data, fr_statetstats(), IPFOBJ_STATESTAT); + break; + /* + * Lock/Unlock the state table. (Locking prevents any changes, which + * means no packets match). + */ case SIOCSTLCK : error = fr_lock(data, &fr_state_lock); break; + /* + * Add an entry to the current state table. + */ case SIOCSTPUT : if (!fr_state_lock) { error = EACCES; @@ -382,6 +483,9 @@ int mode; } error = fr_stputent(data); break; + /* + * Get a state table entry. + */ case SIOCSTGET : if (!fr_state_lock) { error = EACCES; @@ -397,22 +501,30 @@ int mode; } -/* - * Copy out state information from the kernel to a user space process. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_stgetent */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to state structure to retrieve from table */ +/* */ +/* Copy out state information from the kernel to a user space process. If */ +/* there is a filter rule associated with the state entry, copy that out */ +/* as well. The entry to copy out is taken from the value of "ips_next" in */ +/* the struct passed in and if not null and not found in the list of current*/ +/* state entries, the retrieval fails. */ +/* ------------------------------------------------------------------------ */ int fr_stgetent(data) caddr_t data; { - register ipstate_t *is, *isn; + ipstate_t *is, *isn; ipstate_save_t ips; int error; - error = IRCOPYPTR(data, (caddr_t)&ips, sizeof(ips)); + error = fr_inobj(data, &ips, IPFOBJ_STATESAVE); if (error) - return error; + return EFAULT; isn = ips.ips_next; - if (!isn) { + if (isn == NULL) { isn = ips_list; if (isn == NULL) { if (ips.ips_next == NULL) @@ -436,102 +548,133 @@ caddr_t data; if (isn->is_rule) bcopy((char *)isn->is_rule, (char *)&ips.ips_fr, sizeof(ips.ips_fr)); - error = IWCOPYPTR((caddr_t)&ips, data, sizeof(ips)); + error = fr_outobj(data, &ips, IPFOBJ_STATESAVE); if (error) - error = EFAULT; - return error; + return EFAULT; + return 0; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_stputent */ +/* Returns: int - 0 == success, != 0 == failure */ +/* Parameters: data(I) - pointer to state information struct */ +/* */ +/* This function implements the SIOCSTPUT ioctl: insert a state entry into */ +/* the state table. If the state info. includes a pointer to a filter rule */ +/* then also add in an orphaned rule (will not show up in any "ipfstat -io" */ +/* output. */ +/* ------------------------------------------------------------------------ */ int fr_stputent(data) caddr_t data; { - register ipstate_t *is, *isn; + ipstate_t *is, *isn; ipstate_save_t ips; int error, out, i; frentry_t *fr; char *name; - error = IRCOPYPTR(data, (caddr_t)&ips, sizeof(ips)); + error = fr_inobj(data, &ips, IPFOBJ_STATESAVE); if (error) - return error; + return EFAULT; KMALLOC(isn, ipstate_t *); if (isn == NULL) return ENOMEM; bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn)); + MUTEX_NUKE(&isn->is_lock); + isn->is_sync = NULL; fr = isn->is_rule; - if (fr != NULL) { - if (isn->is_flags & FI_NEWFR) { - KMALLOC(fr, frentry_t *); - if (fr == NULL) { - KFREE(isn); - return ENOMEM; - } - bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); - out = fr->fr_flags & FR_OUTQUE ? 1 : 0; - isn->is_rule = fr; - ips.ips_is.is_rule = fr; + if (fr == NULL) { + fr_stinsert(isn, 0); + return 0; + } - /* - * Look up all the interface names in the rule. - */ - for (i = 0; i < 4; i++) { - name = fr->fr_ifnames[i]; - if ((name[1] == '\0') && - ((name[0] == '-') || (name[0] == '*'))) { - fr->fr_ifas[i] = NULL; - } else if (*name != '\0') { - fr->fr_ifas[i] = GETUNIT(name, - fr->fr_v); - if (fr->fr_ifas[i] == NULL) - fr->fr_ifas[i] = (void *)-1; - else { - strncpy(isn->is_ifname[i], - IFNAME(fr->fr_ifas[i]), - IFNAMSIZ); - } + if (isn->is_flags & SI_NEWFR) { + KMALLOC(fr, frentry_t *); + if (fr == NULL) { + KFREE(isn); + return ENOMEM; + } + bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); + out = fr->fr_flags & FR_OUTQUE ? 1 : 0; + isn->is_rule = fr; + ips.ips_is.is_rule = fr; + MUTEX_NUKE(&fr->fr_lock); + MUTEX_INIT(&fr->fr_lock, "state filter rule lock"); + + /* + * Look up all the interface names in the rule. + */ + for (i = 0; i < 4; i++) { + name = fr->fr_ifnames[i]; + if ((name[1] == '\0') && + ((name[0] == '-') || (name[0] == '*'))) { + fr->fr_ifas[i] = NULL; + } else if (*name != '\0') { + name[LIFNAMSIZ - 1] = '\0'; + fr->fr_ifas[i] = GETIFP(name, fr->fr_v); + if (fr->fr_ifas[i] == NULL) + fr->fr_ifas[i] = (void *)-1; + else { + COPYIFNAME(fr->fr_ifas[i], + isn->is_ifname[i]); } - isn->is_ifp[out] = fr->fr_ifas[i]; } + isn->is_ifp[out] = fr->fr_ifas[i]; + } - /* - * send a copy back to userland of what we ended up - * to allow for verification. - */ - error = IWCOPYPTR((caddr_t)&ips, data, sizeof(ips)); - if (error) { - KFREE(isn); - KFREE(fr); - return EFAULT; - } - } else { - for (is = ips_list; is; is = is->is_next) - if (is->is_rule == fr) - break; - if (!is) { - KFREE(isn); - return ESRCH; - } + fr->fr_dsize = 0; + fr->fr_data = NULL; + + fr_resolvdest(&fr->fr_tif, fr->fr_v); + fr_resolvdest(&fr->fr_dif, fr->fr_v); + + /* + * send a copy back to userland of what we ended up + * to allow for verification. + */ + error = fr_outobj(data, &ips, IPFOBJ_STATESAVE); + if (error) { + KFREE(isn); + MUTEX_DESTROY(&fr->fr_lock); + KFREE(fr); + return EFAULT; + } + } else { + for (is = ips_list; is; is = is->is_next) + if (is->is_rule == fr) + break; + if (!is) { + KFREE(isn); + return ESRCH; } } - fr_stinsert(isn); + fr_stinsert(isn, 0); return 0; } -/* - * Insert a state table entry manually. - */ -void fr_stinsert(is) -register ipstate_t *is; +/* ------------------------------------------------------------------------ */ +/* Function: fr_stinsert */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure */ +/* rev(I) - flag indicating forward/reverse direction of packet */ +/* */ +/* Inserts a state structure into the hash table (for lookups) and the list */ +/* of state entries (for enumeration). Resolves all of the interface names */ +/* to pointers and adjusts running stats for the hash table as appropriate. */ +/* ------------------------------------------------------------------------ */ +void fr_stinsert(is, rev) +ipstate_t *is; +int rev; { - register u_int hv = is->is_hv; + u_int hv; char *name; int i; - MUTEX_INIT(&is->is_lock, "ipf state entry", NULL); + MUTEX_INIT(&is->is_lock, "ipf state entry"); /* * Look up all the interface names in the state entry. @@ -542,62 +685,109 @@ register ipstate_t *is; ((name[0] == '-') || (name[0] == '*'))) { is->is_ifp[0] = NULL; } else if (*name != '\0') { - is->is_ifp[i] = GETUNIT(name, is->is_v); + is->is_ifp[i] = GETIFP(name, is->is_v); if (is->is_ifp[i] == NULL) is->is_ifp[i] = (void *)-1; } } + /* + * If we could trust is_hv, then the modulous would not be needed, but + * when running with IPFILTER_SYNC, this stops bad values. + */ + hv = is->is_hv % fr_statesize; + is->is_hv = hv; + + MUTEX_ENTER(&ipf_stinsert); /* * add into list table. */ - if (ips_list) + if (ips_list != NULL) ips_list->is_pnext = &is->is_next; is->is_pnext = &ips_list; is->is_next = ips_list; ips_list = is; - if (ips_table[hv]) + + if (ips_table[hv] != NULL) ips_table[hv]->is_phnext = &is->is_hnext; else ips_stats.iss_inuse++; is->is_phnext = ips_table + hv; is->is_hnext = ips_table[hv]; ips_table[hv] = is; + ips_stats.iss_bucketlen[hv]++; ips_num++; + MUTEX_EXIT(&ipf_stinsert); + + fr_setstatequeue(is, rev); } -/* - * Create a new ipstate structure and hang it off the hash table. - */ -ipstate_t *fr_addstate(ip, fin, stsave, flags) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_addstate */ +/* Returns: ipstate_t* - NULL == failure, else pointer to new state */ +/* Parameters: fin(I) - pointer to packet information */ +/* stsave(O) - pointer to place to save pointer to created */ +/* state structure. */ +/* flags(I) - flags to use when creating the structure */ +/* */ +/* Creates a new IP state structure from the packet information collected. */ +/* Inserts it into the state table and appends to the bottom of the active */ +/* list. If the capacity of the table has reached the maximum allowed then */ +/* the call will fail and a flush is scheduled for the next timeout call. */ +/* ------------------------------------------------------------------------ */ +ipstate_t *fr_addstate(fin, stsave, flags) fr_info_t *fin; ipstate_t **stsave; u_int flags; { - register tcphdr_t *tcp = NULL; - register ipstate_t *is; - register u_int hv; + ipstate_t *is, ips; struct icmp *ic; - ipstate_t ips; - int out, ws; - u_int pass; + u_int pass, hv; + frentry_t *fr; + tcphdr_t *tcp; + grehdr_t *gre; void *ifp; + int out; - if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT) || - (fin->fin_misc & FM_BADSTATE)) + if (fr_state_lock || + (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGTAIL|FI_BAD))) return NULL; - if (ips_num == fr_statemax) { - ips_stats.iss_max++; + + if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN)) + return NULL; + + fr = fin->fin_fr; + if ((fr->fr_statemax == 0) && (ips_num == fr_statemax)) { + ATOMIC_INCL(ips_stats.iss_max); fr_state_doflush = 1; return NULL; } + + /* + * If a "keep state" rule has reached the maximum number of references + * to it, then schedule an automatic flush in case we can clear out + * some "dead old wood". + */ + if ((fr != NULL) && (fr->fr_statemax != 0) && + (fr->fr_statecnt >= fr->fr_statemax)) { + MUTEX_EXIT(&fr->fr_lock); + ATOMIC_INCL(ips_stats.iss_maxref); + fr_state_doflush = 1; + return NULL; + } + + pass = (fr == NULL) ? 0 : fr->fr_flags; + + ic = NULL; + tcp = NULL; out = fin->fin_out; is = &ips; bzero((char *)is, sizeof(*is)); - ips.is_age = 1; + is->is_die = 1 + fr_ticks; + is->is_flags = flags & IS_INHERITED; + /* * Copy and calculate... */ @@ -608,12 +798,18 @@ u_int flags; hv += is->is_daddr; #ifdef USE_INET6 if (fin->fin_v == 6) { + /* + * For ICMPv6, we check to see if the destination address is + * a multicast address. If it is, do not include it in the + * calculation of the hash because the correct reply will come + * back from a real address, not a multicast address. + */ if ((is->is_p == IPPROTO_ICMPV6) && IN6_IS_ADDR_MULTICAST(&is->is_dst.in6)) { /* * So you can do keep state with neighbour discovery. */ - flags |= FI_W_DADDR; + flags |= SI_W_DADDR; hv -= is->is_daddr; } else { hv += is->is_dst.i6[1]; @@ -628,36 +824,33 @@ u_int flags; switch (is->is_p) { - int off; - #ifdef USE_INET6 case IPPROTO_ICMPV6 : - ic = (struct icmp *)fin->fin_dp; + ic = fin->fin_dp; + if ((ic->icmp_type & ICMP6_INFOMSG_MASK) == 0) return NULL; switch (ic->icmp_type) { case ICMP6_ECHO_REQUEST : - is->is_icmp.ics_type = ic->icmp_type; - hv += (is->is_icmp.ics_id = ic->icmp_id); - hv += (is->is_icmp.ics_seq = ic->icmp_seq); + is->is_icmp.ici_type = ic->icmp_type; + hv += (is->is_icmp.ici_id = ic->icmp_id); break; case ICMP6_MEMBERSHIP_QUERY : case ND_ROUTER_SOLICIT : case ND_NEIGHBOR_SOLICIT : case ICMP6_NI_QUERY : - is->is_icmp.ics_type = ic->icmp_type; + is->is_icmp.ici_type = ic->icmp_type; break; default : return NULL; } ATOMIC_INCL(ips_stats.iss_icmp); - is->is_age = fr_icmptimeout; break; #endif case IPPROTO_ICMP : - ic = (struct icmp *)fin->fin_dp; + ic = fin->fin_dp; switch (ic->icmp_type) { @@ -665,18 +858,26 @@ u_int flags; case ICMP_TSTAMP : case ICMP_IREQ : case ICMP_MASKREQ : - is->is_icmp.ics_type = ic->icmp_type; - hv += (is->is_icmp.ics_id = ic->icmp_id); - hv += (is->is_icmp.ics_seq = ic->icmp_seq); + is->is_icmp.ici_type = ic->icmp_type; + hv += (is->is_icmp.ici_id = ic->icmp_id); break; default : return NULL; } ATOMIC_INCL(ips_stats.iss_icmp); - is->is_age = fr_icmptimeout; break; + + case IPPROTO_GRE : + gre = fin->fin_dp; + + is->is_gre.gs_flags = gre->gr_flags; + is->is_gre.gs_ptype = gre->gr_ptype; + is->is_gre.gs_call = gre->gr_call; + hv += is->is_gre.gs_call; + break; + case IPPROTO_TCP : - tcp = (tcphdr_t *)fin->fin_dp; + tcp = fin->fin_dp; if (tcp->th_flags & TH_RST) return NULL; @@ -686,32 +887,55 @@ u_int flags; */ is->is_sport = htons(fin->fin_data[0]); is->is_dport = htons(fin->fin_data[1]); - if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { + if ((flags & (SI_W_DPORT|SI_W_SPORT)) == 0) { hv += is->is_sport; hv += is->is_dport; } - if ((flags & FI_IGNOREPKT) == 0) { - is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - - (off = (tcp->th_off << 2)) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - is->is_maxsend = is->is_send; - if ((tcp->th_flags & TH_SYN) && - ((tcp->th_off << 2) >= (sizeof(*tcp) + 4))) { - ws = fr_tcpoptions(tcp); - if (ws >= 0) - is->is_swscale = ws; - } - } + /* + * If this is a real packet then initialise fields in the + * state information structure from the TCP header information. + */ is->is_maxdwin = 1; is->is_maxswin = ntohs(tcp->th_win); if (is->is_maxswin == 0) is->is_maxswin = 1; - if ((tcp->th_flags & TH_OPENING) == TH_SYN) - is->is_fsm = 1; + if ((fin->fin_flx & FI_IGNORE) == 0) { + is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - + (TCP_OFF(tcp) << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + is->is_maxsend = is->is_send; + + /* + * Window scale option is only present in + * SYN/SYN-ACK packet. + */ + if ((tcp->th_flags & ~(TH_FIN|TH_ACK|TH_ECNALL)) == + TH_SYN && + (TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) { + if (fr_tcpoptions(fin, tcp, + &is->is_tcp.ts_data[0])) + is->is_swinflags = TCP_WSCALE_SEEN| + TCP_WSCALE_FIRST; + } + + if ((fin->fin_out != 0) && (pass & FR_NEWISN) != 0) { + fr_checknewisn(fin, is); + fr_fixoutisn(fin, is); + } + + if ((tcp->th_flags & TH_OPENING) == TH_SYN) + is->is_flags |= IS_TCPFSM; + else { + is->is_maxdwin = is->is_maxswin * 2; + is->is_dend = ntohl(tcp->th_ack); + is->is_maxdend = ntohl(tcp->th_ack); + is->is_maxdwin *= 2; + } + } /* * If we're creating state for a starting connection, start the @@ -722,212 +946,452 @@ u_int flags; break; case IPPROTO_UDP : - tcp = (tcphdr_t *)fin->fin_dp; + tcp = fin->fin_dp; is->is_sport = htons(fin->fin_data[0]); is->is_dport = htons(fin->fin_data[1]); - if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { - hv += is->is_sport; - hv += is->is_dport; + if ((flags & (SI_W_DPORT|SI_W_SPORT)) == 0) { + hv += tcp->th_dport; + hv += tcp->th_sport; } ATOMIC_INCL(ips_stats.iss_udp); - is->is_age = fr_udptimeout; break; + default : - is->is_age = fr_udptimeout; break; } + hv = DOUBLE_HASH(hv); + is->is_hv = hv; + is->is_rule = fr; + /* + * Look for identical state. + */ + for (is = ips_table[is->is_hv % fr_statesize]; is != NULL; + is = is->is_hnext) { + if (bcmp(&ips.is_src, &is->is_src, + offsetof(struct ipstate, is_ps) - + offsetof(struct ipstate, is_src)) == 0) + break; + } + if (is != NULL) + return NULL; + + if (ips_stats.iss_bucketlen[hv] >= fr_state_maxbucket) { + ATOMIC_INCL(ips_stats.iss_bucketfull); + return NULL; + } KMALLOC(is, ipstate_t *); if (is == NULL) { ATOMIC_INCL(ips_stats.iss_nomem); return NULL; } bcopy((char *)&ips, (char *)is, sizeof(*is)); - hv %= fr_statesize; - is->is_hv = hv; - is->is_rule = fin->fin_fr; - if (is->is_rule != NULL) { - is->is_group = is->is_rule->fr_group; - ATOMIC_INC32(is->is_rule->fr_ref); - pass = is->is_rule->fr_flags; - is->is_frage[0] = is->is_rule->fr_age[0]; - is->is_frage[1] = is->is_rule->fr_age[1]; - if (is->is_frage[0] != 0) - is->is_age = is->is_frage[0]; + /* + * Do not do the modulous here, it is done in fr_stinsert(). + */ + if (fr != NULL) { + (void) strncpy(is->is_group, fr->fr_group, FR_GROUPLEN); + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + fr->fr_statecnt++; + MUTEX_EXIT(&fr->fr_lock); + if (fr->fr_age[0] != 0) { + is->is_tqehead[0] = fr_addtimeoutqueue(&ips_utqe, + fr->fr_age[0]); + is->is_tqehead[1] = is->is_tqehead[0]; + is->is_sti.tqe_flags |= TQE_RULEBASED; + } + if (fr->fr_age[0] != 0 && fr->fr_age[1] != fr->fr_age[0]) + is->is_tqehead[1] = fr_addtimeoutqueue(&ips_utqe, + fr->fr_age[1]); + is->is_tag = fr->fr_logtag; - is->is_ifp[(out << 1) + 1] = is->is_rule->fr_ifas[1]; - is->is_ifp[(1 - out) << 1] = is->is_rule->fr_ifas[2]; - is->is_ifp[((1 - out) << 1) + 1] = is->is_rule->fr_ifas[3]; + is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1]; + is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2]; + is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3]; - if (((ifp = is->is_rule->fr_ifas[1]) != NULL) && - (ifp != (void *)-1)) - strncpy(is->is_ifname[(out << 1) + 1], - IFNAME(ifp), IFNAMSIZ); - if (((ifp = is->is_rule->fr_ifas[2]) != NULL) && - (ifp != (void *)-1)) - strncpy(is->is_ifname[(1 - out) << 1], - IFNAME(ifp), IFNAMSIZ); - if (((ifp = is->is_rule->fr_ifas[3]) != NULL) && - (ifp != (void *)-1)) - strncpy(is->is_ifname[((1 - out) << 1) + 1], - IFNAME(ifp), IFNAMSIZ); - } else + if (((ifp = fr->fr_ifas[1]) != NULL) && + (ifp != (void *)-1)) { + COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1]); + } + if (((ifp = fr->fr_ifas[2]) != NULL) && + (ifp != (void *)-1)) { + COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1]); + } + if (((ifp = fr->fr_ifas[3]) != NULL) && + (ifp != (void *)-1)) { + COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1]); + } + } else { pass = fr_flags; + is->is_tag = FR_NOLOGTAG; + } is->is_ifp[out << 1] = fin->fin_ifp; - strncpy(is->is_ifname[out << 1], IFNAME(fin->fin_ifp), IFNAMSIZ); - - WRITE_ENTER(&ipf_state); - - is->is_pass = pass; - if ((flags & FI_IGNOREPKT) == 0) { - is->is_pkts = 1; - is->is_bytes = fin->fin_dlen + fin->fin_hlen; + if (fin->fin_ifp != NULL) { + COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]); } + + is->is_ref = 1; + is->is_pass = pass; + is->is_pkts[0] = 0, is->is_bytes[0] = 0; + is->is_pkts[1] = 0, is->is_bytes[1] = 0; + is->is_pkts[2] = 0, is->is_bytes[2] = 0; + is->is_pkts[3] = 0, is->is_bytes[3] = 0; + if ((fin->fin_flx & FI_IGNORE) == 0) { + is->is_pkts[out] = 1; + is->is_bytes[out] = fin->fin_dlen + fin->fin_hlen; + is->is_flx[out][0] = fin->fin_flx & FI_CMP; + } + + if (pass & FR_STSTRICT) + is->is_flags |= IS_STRICT; + /* * We want to check everything that is a property of this packet, * but we don't (automatically) care about it's fragment status as * this may change. */ is->is_v = fin->fin_v; - is->is_rulen = fin->fin_rule; - is->is_opt = fin->fin_fi.fi_optmsk; + is->is_opt = fin->fin_optmsk; is->is_optmsk = 0xffffffff; - is->is_sec = fin->fin_fi.fi_secmsk; + is->is_sec = fin->fin_secmsk; is->is_secmsk = 0xffff; - is->is_auth = fin->fin_fi.fi_auth; + is->is_auth = fin->fin_auth; is->is_authmsk = 0xffff; - is->is_flags = fin->fin_fl & FI_CMP; - is->is_flags |= FI_CMP << 4; - is->is_flags |= flags & (FI_WILDP|FI_WILDA); - if (flags & (FI_WILDP|FI_WILDA)) - ips_wild++; + if (flags & (SI_WILDP|SI_WILDA)) { + ATOMIC_INCL(ips_stats.iss_wild); + } + is->is_rulen = fin->fin_rule; + if (pass & FR_LOGFIRST) is->is_pass &= ~(FR_LOGFIRST|FR_LOG); - fr_stinsert(is); + + READ_ENTER(&ipf_state); is->is_me = stsave; - if (is->is_p == IPPROTO_TCP) { - fr_tcp_age(&is->is_age, is->is_state, fin, - 0, is->is_fsm); /* 0 = packet from the source */ - } -#ifdef IPFILTER_LOG - ipstate_log(is, ISL_NEW); + + fr_stinsert(is, fin->fin_rev); + + if (fin->fin_p == IPPROTO_TCP) { + /* + * If we're creating state for a starting connection, start the + * timer on it as we'll never see an error if it fails to + * connect. + */ + MUTEX_ENTER(&is->is_lock); + (void) fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags); + MUTEX_EXIT(&is->is_lock); +#ifdef IPFILTER_SCAN + if ((is->is_flags & SI_CLONE) == 0) + (void) ipsc_attachis(is); #endif + } +#ifdef IPFILTER_SYNC + if ((is->is_flags & SI_CLONE) == 0) + is->is_sync = ipfsync_new(SMC_STATE, fin, is); +#endif + if (ipstate_logging) + ipstate_log(is, ISL_NEW); + RWLOCK_EXIT(&ipf_state); - fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst); - if ((fin->fin_fl & FI_FRAG) && (pass & FR_KEEPFRAG)) - ipfr_newfrag(ip, fin); + fin->fin_rev = IP6_NEQ(&is->is_dst, &fin->fin_daddr); + fin->fin_flx |= FI_STATE; + if (fin->fin_flx & FI_FRAG) + (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE); + return is; } -static int fr_tcpoptions(tcp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpoptions */ +/* Returns: int - 1 == packet matches state entry, 0 == it does not */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP packet header */ +/* td(I) - pointer to TCP data held as part of the state */ +/* */ +/* Look after the TCP header for any options and deal with those that are */ +/* present. Record details about those that we recogise. */ +/* ------------------------------------------------------------------------ */ +static int fr_tcpoptions(fin, tcp, td) +fr_info_t *fin; tcphdr_t *tcp; +tcpdata_t *td; { - u_char *opt, *last; - int wscale; + int off, mlen, ol, i, len, retval; + char buf[64], *s, opt; + mb_t *m = NULL; - opt = (u_char *) (tcp + 1); - last = ((u_char *)tcp) + (tcp->th_off << 2); + off = fin->fin_hlen + sizeof(*tcp); + len = (TCP_OFF(tcp) << 2) - sizeof(*tcp); + if (fin->fin_plen < off + len) + return 0; - /* If we don't find wscale here, we need to clear it */ - wscale = -2; - - /* Termination condition picked such that opt[0 .. 2] exist */ - while ((opt < last - 2) && (*opt != TCPOPT_EOL)) { - switch (*opt) { - case TCPOPT_NOP: - opt++; - continue; - case TCPOPT_WSCALE: - /* Proper length ? */ - if (opt[1] == 3) { - if (opt[2] > 14) - wscale = 14; - else - wscale = opt[2]; - } - break; - default: - /* Unknown options must be two bytes+ */ - if (opt[1] < 2) - break; - opt += opt[1]; - continue; - } - break; + m = fin->fin_m; + off += (char *)fin->fin_ip - MTOD(m, char *); + mlen = MSGDSIZE(m) - off; + if (len > mlen) { + len = mlen; + retval = 0; + } else { + retval = 1; } - return wscale; + + COPYDATA(m, off, len, buf); + + for (s = buf; len > 0; ) { + opt = *s; + if (opt == TCPOPT_EOL) + break; + else if (opt == TCPOPT_NOP) + ol = 1; + else { + if (len < 2) + break; + ol = (int)*(s + 1); + if (ol < 2 || ol > len) + break; + + /* + * Extract the TCP options we are interested in out of + * the header and store them in the the tcpdata struct. + */ + switch (opt) + { + case TCPOPT_WINDOW : + if (ol == TCPOLEN_WINDOW) { + i = (int)*(s + 2); + if (i > TCP_WSCALE_MAX) + i = TCP_WSCALE_MAX; + else if (i < 0) + i = 0; + td->td_winscale = i; + } + break; + case TCPOPT_MAXSEG : + /* + * So, if we wanted to set the TCP MAXSEG, + * it should be done here... + */ + if (ol == TCPOLEN_MAXSEG) { + i = (int)*(s + 2); + i <<= 8; + i += (int)*(s + 3); + td->td_maxseg = i; + } + break; + } + } + len -= ol; + s += ol; + } + return retval; } - -/* - * check to see if a packet with TCP headers fits within the TCP window. - * change timeout depending on whether new packet is a SYN-ACK returning for a - * SYN or a RST or FIN which indicate time to close up shop. - */ -int fr_tcpstate(is, fin, ip, tcp) -register ipstate_t *is; +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpstate */ +/* Returns: int - 1 == packet matches state entry, 0 == it does not */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP packet header */ +/* is(I) - pointer to master state structure */ +/* */ +/* Check to see if a packet with TCP headers fits within the TCP window. */ +/* Change timeout depending on whether new packet is a SYN-ACK returning */ +/* for a SYN or a RST or FIN which indicate time to close up shop. */ +/* ------------------------------------------------------------------------ */ +static int fr_tcpstate(fin, tcp, is) fr_info_t *fin; -ip_t *ip; tcphdr_t *tcp; +ipstate_t *is; { - register tcp_seq seq, ack, end; - register int ackskew; + int source, ret = 0, flags; tcpdata_t *fdata, *tdata; - u_32_t win, maxwin; - int ret = 0, off; - int source; - int wscale; + + source = !fin->fin_rev; + if (((is->is_flags & IS_TCPFSM) != 0) && (source == 1) && + (ntohs(is->is_sport) != fin->fin_data[0])) + source = 0; + fdata = &is->is_tcp.ts_data[!source]; + tdata = &is->is_tcp.ts_data[source]; + + MUTEX_ENTER(&is->is_lock); + if (fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags)) { +#ifdef IPFILTER_SCAN + if (is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER)) { + ipsc_packet(fin, is); + if (FR_ISBLOCK(is->is_pass)) { + MUTEX_EXIT(&is->is_lock); + return 1; + } + } +#endif + + /* + * Nearing end of connection, start timeout. + */ + ret = fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags); + if (ret == 0) { + MUTEX_EXIT(&is->is_lock); + return 0; + } + + /* + * set s0's as appropriate. Use syn-ack packet as it + * contains both pieces of required information. + */ + /* + * Window scale option is only present in SYN/SYN-ACK packet. + * Compare with ~TH_FIN to mask out T/TCP setups. + */ + flags = tcp->th_flags & ~(TH_FIN|TH_ECNALL); + if (flags == (TH_SYN|TH_ACK)) { + is->is_s0[source] = ntohl(tcp->th_ack); + is->is_s0[!source] = ntohl(tcp->th_seq) + 1; + if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2)) && + tdata->td_winscale) { + if (fr_tcpoptions(fin, tcp, fdata)) { + fdata->td_winflags = TCP_WSCALE_SEEN| + TCP_WSCALE_FIRST; + } + if (!fdata->td_winscale) + tdata->td_winscale = 0; + } + if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) + fr_checknewisn(fin, is); + } else if (flags == TH_SYN) { + is->is_s0[source] = ntohl(tcp->th_seq) + 1; + if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) + if (fr_tcpoptions(fin, tcp, tdata)) { + tdata->td_winflags = TCP_WSCALE_SEEN| + TCP_WSCALE_FIRST; + } + + if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) + fr_checknewisn(fin, is); + + } + ret = 1; + } else + fin->fin_flx |= FI_OOW; + MUTEX_EXIT(&is->is_lock); + return ret; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checknewisn */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* */ +/* Check to see if this TCP connection is expecting and needs a new */ +/* sequence number for a particular direction of the connection. */ +/* */ +/* NOTE: This does not actually change the sequence numbers, only gets new */ +/* one ready. */ +/* ------------------------------------------------------------------------ */ +static void fr_checknewisn(fin, is) +fr_info_t *fin; +ipstate_t *is; +{ + u_32_t sumd, old, new; + tcphdr_t *tcp; + int i; + + i = fin->fin_rev; + tcp = fin->fin_dp; + + if (((i == 0) && !(is->is_flags & IS_ISNSYN)) || + ((i == 1) && !(is->is_flags & IS_ISNACK))) { + old = tcp->th_seq; + new = fr_newisn(fin); + is->is_isninc[i] = new - old; + CALC_SUMD(old, new, sumd); + is->is_sumd[i] = (sumd & 0xffff) + (sumd >> 16); + + is->is_flags |= ((i == 0) ? IS_ISNSYN : IS_ISNACK); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcpinwindow */ +/* Returns: int - 1 == packet inside TCP "window", 0 == not inside. */ +/* Parameters: fin(I) - pointer to packet information */ +/* fdata(I) - pointer to tcp state informatio (reverse) */ +/* tdata(I) - pointer to tcp state informatio (forward) */ +/* tcp(I) - pointer to TCP packet header */ +/* */ +/* Given a packet has matched addresses and ports, check to see if it is */ +/* within the TCP data window. In a show of generosity, allow packets that */ +/* are within the window space behind the current sequence # as well. */ +/* ------------------------------------------------------------------------ */ +int fr_tcpinwindow(fin, fdata, tdata, tcp, flags) +fr_info_t *fin; +tcpdata_t *fdata, *tdata; +tcphdr_t *tcp; +int flags; +{ + tcp_seq seq, ack, end; + int ackskew, tcpflags; + u_32_t win, maxwin; /* * Find difference between last checked packet and this packet. */ - source = IP6EQ(fin->fin_fi.fi_src, is->is_src); - if (source && (ntohs(is->is_sport) != fin->fin_data[0])) - source = 0; - fdata = &is->is_tcp.ts_data[!source]; - tdata = &is->is_tcp.ts_data[source]; - off = tcp->th_off << 2; + tcpflags = tcp->th_flags; seq = ntohl(tcp->th_seq); ack = ntohl(tcp->th_ack); - win = ntohs(tcp->th_win); - end = seq + fin->fin_dlen - off + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - - - if ((tcp->th_flags & TH_SYN) && (off >= sizeof(*tcp) + 4)) - wscale = fr_tcpoptions(tcp); + if (tcpflags & TH_SYN) + win = ntohs(tcp->th_win); else - wscale = -1; + win = ntohs(tcp->th_win) << fdata->td_winscale; + if (win == 0) + win = 1; - MUTEX_ENTER(&is->is_lock); + /* + * if window scaling is present, the scaling is only allowed + * for windows not in the first SYN packet. In that packet the + * window is 65535 to specify the largest window possible + * for receivers not implementing the window scale option. + * Currently, we do not assume TTCP here. That means that + * if we see a second packet from a host (after the initial + * SYN), we can assume that the receiver of the SYN did + * already send back the SYN/ACK (and thus that we know if + * the receiver also does window scaling) + */ + if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) { + if (tdata->td_winflags & TCP_WSCALE_SEEN) { + fdata->td_winflags &= ~TCP_WSCALE_FIRST; + fdata->td_maxwin = win; + } else { + fdata->td_winscale = 0; + fdata->td_winflags = 0; + tdata->td_winscale = 0; + tdata->td_winflags = 0; + } + } - if (wscale >= 0) - fdata->td_wscale = wscale; - else if (wscale == -2) - fdata->td_wscale = tdata->td_wscale = 0; - win <<= fdata->td_wscale; + end = seq + fin->fin_dlen - (TCP_OFF(tcp) << 2) + + ((tcpflags & TH_SYN) ? 1 : 0) + ((tcpflags & TH_FIN) ? 1 : 0); if ((fdata->td_end == 0) && - (!is->is_fsm || ((tcp->th_flags & TH_OPENING) == TH_OPENING))) { + (!(flags & IS_TCPFSM) || + ((tcpflags & TH_OPENING) == TH_OPENING))) { /* * Must be a (outgoing) SYN-ACK in reply to a SYN. */ fdata->td_end = end; fdata->td_maxwin = 1; fdata->td_maxend = end + win; - if (win == 0) - fdata->td_maxend++; } - if (!(tcp->th_flags & TH_ACK)) { /* Pretend an ack was sent */ + if (!(tcpflags & TH_ACK)) { /* Pretend an ack was sent */ ack = tdata->td_end; - } else if (((tcp->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && + } else if (((tcpflags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && (ack == 0)) { /* gross hack to get around certain broken tcp stacks */ ack = tdata->td_end; @@ -939,15 +1403,28 @@ tcphdr_t *tcp; maxwin = tdata->td_maxwin; ackskew = tdata->td_end - ack; + /* + * Strict sequencing only allows in-order delivery. + */ + if ((flags & IS_STRICT) != 0) { + if (seq != fdata->td_end) { + return 0; + } + } + #define SEQ_GE(a,b) ((int)((a) - (b)) >= 0) #define SEQ_GT(a,b) ((int)((a) - (b)) > 0) - if ((SEQ_GE(fdata->td_maxend, end)) && + if ( +#if defined(_KERNEL) + (SEQ_GE(fdata->td_maxend, end)) && (SEQ_GE(seq, fdata->td_end - maxwin)) && +#endif /* XXX what about big packets */ #define MAXACKWINDOW 66000 - (ackskew >= -MAXACKWINDOW) && - (ackskew <= MAXACKWINDOW)) { - /* if ackskew < 0 then this should be due to fragented + (-ackskew <= (MAXACKWINDOW << tdata->td_winscale)) && + ( ackskew <= (MAXACKWINDOW << tdata->td_winscale))) { + + /* if ackskew < 0 then this should be due to fragmented * packets. There is no way to know the length of the * total packet in advance. * We do know the total length from the fragment cache though. @@ -961,54 +1438,132 @@ tcphdr_t *tcp; * Thus, when ackskew is negative but still seems to belong * to this session, we bump up the destinations end value. */ - /* - * Nearing end of connection, start timeout. - */ - /* source ? 0 : 1 -> !source */ - if (fr_tcp_age(&is->is_age, is->is_state, fin, !source, - (int)is->is_fsm) == 0) { - if (ackskew < 0) - tdata->td_end = ack; + if (ackskew < 0) + tdata->td_end = ack; - /* update max window seen */ - if (fdata->td_maxwin < win) - fdata->td_maxwin = win; - if (SEQ_GT(end, fdata->td_end)) - fdata->td_end = end; - if (SEQ_GE(ack + win, tdata->td_maxend)) { - tdata->td_maxend = ack + win; - if (win == 0) - tdata->td_maxend++; - } - - ATOMIC_INCL(ips_stats.iss_hits); - ret = 1; - } + /* update max window seen */ + if (fdata->td_maxwin < win) + fdata->td_maxwin = win; + if (SEQ_GT(end, fdata->td_end)) + fdata->td_end = end; + if (SEQ_GE(ack + win, tdata->td_maxend)) + tdata->td_maxend = ack + win; + return 1; } - MUTEX_EXIT(&is->is_lock); - if ((ret == 0) && ((tcp->th_flags & TH_OPENING) != TH_SYN)) - fin->fin_misc |= FM_BADSTATE; - return ret; + return 0; } -/* - * Match a state table entry against an IP packet. - */ -static int fr_matchsrcdst(is, src, dst, fin, tcp) -ipstate_t *is; -union i6addr src, dst; +/* ------------------------------------------------------------------------ */ +/* Function: fr_stclone */ +/* Returns: ipstate_t* - NULL == cloning failed, */ +/* else pointer to new state structure */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP/UDP header */ +/* is(I) - pointer to master state structure */ +/* */ +/* Create a "duplcate" state table entry from the master. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_stclone(fin, tcp, is) fr_info_t *fin; tcphdr_t *tcp; +ipstate_t *is; { - int ret = 0, rev, out, flags, idx; + ipstate_t *clone; + frentry_t *fr; + u_32_t send; + + if (ips_num == fr_statemax) { + ATOMIC_INCL(ips_stats.iss_max); + fr_state_doflush = 1; + return NULL; + } + KMALLOC(clone, ipstate_t *); + if (clone == NULL) + return NULL; + bcopy((char *)is, (char *)clone, sizeof(*clone)); + + MUTEX_NUKE(&clone->is_lock); + + clone->is_die = ONE_DAY + fr_ticks; + clone->is_state[0] = 0; + clone->is_state[1] = 0; + send = ntohl(tcp->th_seq) + fin->fin_dlen - (TCP_OFF(tcp) << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + + if (fin->fin_rev == 1) { + clone->is_dend = send; + clone->is_maxdend = send; + clone->is_send = 0; + clone->is_maxswin = 1; + clone->is_maxdwin = ntohs(tcp->th_win); + if (clone->is_maxdwin == 0) + clone->is_maxdwin = 1; + } else { + clone->is_send = send; + clone->is_maxsend = send; + clone->is_dend = 0; + clone->is_maxdwin = 1; + clone->is_maxswin = ntohs(tcp->th_win); + if (clone->is_maxswin == 0) + clone->is_maxswin = 1; + } + + fr = clone->is_rule; + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + fr->fr_statecnt++; + MUTEX_EXIT(&fr->fr_lock); + } + clone->is_flags &= ~SI_CLONE; + clone->is_flags |= SI_CLONED; + fr_stinsert(clone, fin->fin_rev); + MUTEX_ENTER(&clone->is_lock); + clone->is_ref = 1; + if (clone->is_p == IPPROTO_TCP) { + (void) fr_tcp_age(&clone->is_sti, fin, ips_tqtqb, + clone->is_flags); + } + MUTEX_EXIT(&clone->is_lock); +#ifdef IPFILTER_SCAN + (void) ipsc_attachis(is); +#endif +#ifdef IPFILTER_SYNC + clone->is_sync = ipfsync_new(SMC_STATE, fin, clone); +#endif + return clone; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_matchsrcdst */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to state structure */ +/* src(I) - pointer to source address */ +/* dst(I) - pointer to destination address */ +/* tcp(I) - pointer to TCP/UDP header */ +/* */ +/* Match a state table entry against an IP packet. The logic below is that */ +/* ret gets set to one if the match succeeds, else remains 0. If it is */ +/* still 0 after the test. no match. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_matchsrcdst(fin, is, src, dst, tcp) +fr_info_t *fin; +ipstate_t *is; +i6addr_t *src, *dst; +tcphdr_t *tcp; +{ + int ret = 0, rev, out, flags, flx = 0, idx; u_short sp, dp; void *ifp; - rev = IP6NEQ(is->is_dst, dst); + rev = IP6_NEQ(&is->is_dst, dst); ifp = fin->fin_ifp; out = fin->fin_out; - flags = is->is_flags & (FI_WILDA|FI_WILDP); + flags = is->is_flags & (SI_WILDA); sp = 0; dp = 0; @@ -1017,77 +1572,111 @@ tcphdr_t *tcp; sp = tcp->th_sport; dp = tcp->th_dport; if (!rev) { - if (!(flags & FI_W_SPORT) && (sp != is->is_sport)) + if (!(flags & SI_W_SPORT) && (sp != is->is_sport)) rev = 1; - else if (!(flags & FI_W_DPORT) && (dp != is->is_dport)) + else if (!(flags & SI_W_DPORT) && (dp != is->is_dport)) rev = 1; } } idx = (out << 1) + rev; - if ((is->is_ifp[idx] == NULL && - (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) || + /* + * If the interface for this 'direction' is set, make sure it matches. + * An interface name that is not set matches any, as does a name of *. + */ + if ((is->is_ifp[idx] == NULL && + (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) || is->is_ifp[idx] == ifp) ret = 1; if (ret == 0) - return 0; + return NULL; ret = 0; + /* + * Match addresses and ports. + */ if (rev == 0) { - if ((IP6EQ(is->is_dst, dst) || (flags & FI_W_DADDR)) && - (IP6EQ(is->is_src, src) || (flags & FI_W_SADDR)) && - (!tcp || ((sp == is->is_sport || flags & FI_W_SPORT) && - (dp == is->is_dport || flags & FI_W_DPORT)))) { + if ((IP6_EQ(&is->is_dst, dst) || (flags & SI_W_DADDR)) && + (IP6_EQ(&is->is_src, src) || (flags & SI_W_SADDR)) && + (!tcp || ((sp == is->is_sport || flags & SI_W_SPORT) && + (dp == is->is_dport || flags & SI_W_DPORT)))) { ret = 1; } } else { - if ((IP6EQ(is->is_dst, src) || (flags & FI_W_DADDR)) && - (IP6EQ(is->is_src, dst) || (flags & FI_W_SADDR)) && - (!tcp || ((sp == is->is_dport || flags & FI_W_DPORT) && - (dp == is->is_sport || flags & FI_W_SPORT)))) { + if ((IP6_EQ(&is->is_dst, src) || (flags & SI_W_DADDR)) && + (IP6_EQ(&is->is_src, dst) || (flags & SI_W_SADDR)) && + (!tcp || ((sp == is->is_dport || flags & SI_W_DPORT) && + (dp == is->is_sport || flags & SI_W_SPORT)))) { ret = 1; } } if (ret == 0) - return 0; + return NULL; /* * Whether or not this should be here, is questionable, but the aim * is to get this out of the main line. */ if (tcp == NULL) - flags = is->is_flags & (FI_CMP|(FI_CMP<<4)); + flags = is->is_flags & ~(SI_WILDP|SI_NEWFR|SI_CLONE|SI_CLONED); - if (((fin->fin_fl & (flags >> 4)) != (flags & FI_CMP)) || - (fin->fin_fi.fi_optmsk != is->is_opt) || - (fin->fin_fi.fi_secmsk != is->is_sec) || - (fin->fin_fi.fi_auth != is->is_auth)) - return 0; - - flags = is->is_flags & (FI_WILDA|FI_WILDP); - if ((flags & (FI_W_SADDR|FI_W_DADDR))) { - if ((flags & FI_W_SADDR) != 0) { + /* + * Only one of the source or destination address can be flaged as a + * wildcard. Fill in the missing address, if set. + */ + if ((flags & (SI_W_SADDR|SI_W_DADDR))) { + if ((flags & SI_W_SADDR) != 0) { if (rev == 0) { is->is_src = fin->fin_fi.fi_src; } else { is->is_src = fin->fin_fi.fi_dst; } - } else if ((flags & FI_W_DADDR) != 0) { + } else if ((flags & SI_W_DADDR) != 0) { if (rev == 0) { is->is_dst = fin->fin_fi.fi_dst; } else { is->is_dst = fin->fin_fi.fi_src; } } - is->is_flags &= ~(FI_W_SADDR|FI_W_DADDR); - if ((is->is_flags & (FI_WILDA|FI_WILDP)) == 0) - ips_wild--; + is->is_flags &= ~(SI_W_SADDR|SI_W_DADDR); + if ((is->is_flags & (SI_WILDA|SI_WILDP)) == 0) { + ATOMIC_DECL(ips_stats.iss_wild); + } } - if ((flags & (FI_W_SPORT|FI_W_DPORT))) { - if ((flags & FI_W_SPORT) != 0) { + flx = fin->fin_flx & FI_CMP; + + /* + * Match up any flags set from IP options. + */ + if ((is->is_flx[out][rev] && (flx != is->is_flx[out][rev])) || + ((fin->fin_optmsk & is->is_optmsk) != is->is_opt) || + ((fin->fin_secmsk & is->is_secmsk) != is->is_sec) || + ((fin->fin_auth & is->is_authmsk) != is->is_auth)) + return NULL; + + /* + * Only one of the source or destination port can be flagged as a + * wildcard. When filling it in, fill in a copy of the matched entry + * if it has the cloning flag set. + */ + if ((fin->fin_flx & FI_IGNORE) != 0) { + fin->fin_rev = rev; + return is; + } + + if ((flags & (SI_W_SPORT|SI_W_DPORT))) { + if ((flags & SI_CLONE) != 0) { + is = fr_stclone(fin, tcp, is); + if (is == NULL) + return NULL; + } else { + ATOMIC_DECL(ips_stats.iss_wild); + } + + if ((flags & SI_W_SPORT) != 0) { if (rev == 0) { is->is_sport = sp; is->is_send = htonl(tcp->th_seq); @@ -1096,7 +1685,7 @@ tcphdr_t *tcp; is->is_send = htonl(tcp->th_ack); } is->is_maxsend = is->is_send + 1; - } else if ((flags & FI_W_DPORT) != 0) { + } else if ((flags & SI_W_DPORT) != 0) { if (rev == 0) { is->is_dport = dp; is->is_dend = htonl(tcp->th_ack); @@ -1106,74 +1695,55 @@ tcphdr_t *tcp; } is->is_maxdend = is->is_dend + 1; } - is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); - ips_wild--; + is->is_flags &= ~(SI_W_SPORT|SI_W_DPORT); + if ((flags & SI_CLONED) && ipstate_logging) + ipstate_log(is, ISL_CLONE); } ret = -1; - if (is->is_ifp[idx] == NULL && - (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) - ret = idx; + if (is->is_flx[out][rev] == 0) + is->is_flx[out][rev] = flx; - if (ret >= 0) { - is->is_ifp[ret] = ifp; - strncpy(is->is_ifname[ret], IFNAME(ifp), - sizeof(is->is_ifname[ret])); + /* + * Check if the interface name for this "direction" is set and if not, + * fill it in. + */ + if (is->is_ifp[idx] == NULL && + (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) { + is->is_ifp[idx] = ifp; + COPYIFNAME(ifp, is->is_ifname[idx]); } fin->fin_rev = rev; - return 1; + return is; } -static int fr_matchicmpqueryreply(v, is, icmp) -int v; -ipstate_t *is; -icmphdr_t *icmp; -{ - if (v == 4) { - /* - * If we matched its type on the way in, then when going out - * it will still be the same type. - */ - if (((icmp->icmp_type == is->is_type) || - (icmpreplytype4[is->is_type] == icmp->icmp_type))) { - if (icmp->icmp_type != ICMP_ECHOREPLY) - return 1; - if ((icmp->icmp_id == is->is_icmp.ics_id) && - (icmp->icmp_seq == is->is_icmp.ics_seq)) - return 1; - } - } -#ifdef USE_INET6 - else if (is->is_v == 6) { - if (((icmp->icmp_type == is->is_type) || - (icmpreplytype6[is->is_type] == icmp->icmp_type))) { - if (icmp->icmp_type != ICMP6_ECHO_REPLY) - return 1; - if ((icmp->icmp_id == is->is_icmp.ics_id) && - (icmp->icmp_seq == is->is_icmp.ics_seq)) - return 1; - } - } -#endif - return 0; -} -static frentry_t *fr_checkicmpmatchingstate(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkicmpmatchingstate */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* If we've got an ICMP error message, using the information stored in the */ +/* ICMP packet, look for a matching state table entry. */ +/* */ +/* If we return NULL then no lock on ipf_state is held. */ +/* If we return non-null then a read-lock on ipf_state is held. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_checkicmpmatchingstate(fin) fr_info_t *fin; { - register ipstate_t *is, **isp; - register u_short sport, dport; - register u_char pr; - u_short savelen, ohlen; - union i6addr dst, src; + ipstate_t *is, **isp; + u_short sport, dport; + u_char pr; + i6addr_t dst, src; struct icmp *ic; + u_short savelen; icmphdr_t *icmp; + int backward, i; fr_info_t ofin; - int type, len; tcphdr_t *tcp; - frentry_t *fr; + int type, len; ip_t *oip; u_int hv; @@ -1182,11 +1752,10 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with * an ICMP error header. */ - if (((ip->ip_v != 4) || (ip->ip_hl != 5)) || + if ((fin->fin_v != 4) || (fin->fin_hlen != sizeof(ip_t)) || (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; - - ic = (struct icmp *)fin->fin_dp; + ic = fin->fin_dp; type = ic->icmp_type; /* * If it's not an error type, then return @@ -1197,15 +1766,18 @@ fr_info_t *fin; return NULL; oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN); - ohlen = oip->ip_hl << 2; - if (fin->fin_plen < ICMPERR_MAXPKTLEN + ohlen - sizeof(*oip)) + /* + * Check if the at least the old IP header (with options) and + * 8 bytes of payload is present. + */ + if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((IP_HL(oip) - 5) << 2)) return NULL; /* - * Sanity checks. + * Sanity Checks. */ len = fin->fin_dlen - ICMPERR_ICMPHLEN; - if ((len <= 0) || (ohlen > len)) + if ((len <= 0) || ((IP_HL(oip) << 2) > len)) return NULL; /* @@ -1214,54 +1786,87 @@ fr_info_t *fin; * may be too big to be in this buffer but not so big that it's * outside the ICMP packet, leading to TCP deref's causing problems. * This is possible because we don't know how big oip_hl is when we - * do the pullup early in fr_check() and thus can't gaurantee it is + * do the pullup early in fr_check() and thus can't guarantee it is * all here now. */ #ifdef _KERNEL { mb_t *m; -# if SOLARIS - m = fin->fin_qfm; + m = fin->fin_m; +# if defined(MENTAT) if ((char *)oip + len > (char *)m->b_wptr) return NULL; # else - m = *(mb_t **)fin->fin_mp; - if ((char *)oip + len > (char *)ip + m->m_len) + if ((char *)oip + len > (char *)fin->fin_ip + m->m_len) return NULL; # endif } #endif + bcopy((char *)fin, (char *)&ofin, sizeof(fin)); /* * in the IPv4 case we must zero the i6addr union otherwise - * the IP6EQ and IP6NEQ macros produce the wrong results because + * the IP6_EQ and IP6_NEQ macros produce the wrong results because * of the 'junk' in the unused part of the union */ bzero((char *)&src, sizeof(src)); bzero((char *)&dst, sizeof(dst)); - bzero((char *)&ofin, sizeof(ofin)); + + /* + * we make an fin entry to be able to feed it to + * matchsrcdst note that not all fields are encessary + * but this is the cleanest way. Note further we fill + * in fin_mp such that if someone uses it we'll get + * a kernel panic. fr_matchsrcdst does not use this. + * + * watch out here, as ip is in host order and oip in network + * order. Any change we make must be undone afterwards, like + * oip->ip_off - it is still in network byte order so fix it. + */ + savelen = oip->ip_len; + oip->ip_len = len; + oip->ip_off = htons(oip->ip_off); + + ofin.fin_flx = FI_NOCKSUM; + ofin.fin_v = 4; + ofin.fin_ip = oip; + ofin.fin_m = NULL; /* if dereferenced, panic XXX */ + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + ofin.fin_plen = fin->fin_dlen - ICMPERR_ICMPHLEN; + (void) fr_makefrip(IP_HL(oip) << 2, oip, &ofin); ofin.fin_ifp = fin->fin_ifp; ofin.fin_out = !fin->fin_out; - ofin.fin_v = 4; - fr = NULL; + /* + * Reset the short and bad flag here because in fr_matchsrcdst() + * the flags for the current packet (fin_flx) are compared against + * those for the existing session. + */ + ofin.fin_flx &= ~(FI_BAD|FI_SHORT); + + /* + * Put old values of ip_len and ip_off back as we don't know + * if we have to forward the packet (or process it again. + */ + oip->ip_len = savelen; + oip->ip_off = htons(oip->ip_off); switch (oip->ip_p) { case IPPROTO_ICMP : - icmp = (icmphdr_t *)((char *)oip + ohlen); + icmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); /* - * a ICMP error can only be generated as a result of an + * an ICMP error can only be generated as a result of an * ICMP query, not as the response on an ICMP error * * XXX theoretically ICMP_ECHOREP and the other reply's are * ICMP query's as well, but adding them here seems strange XXX */ - if ((icmp->icmp_type != ICMP_ECHO) && - (icmp->icmp_type != ICMP_TSTAMP) && - (icmp->icmp_type != ICMP_IREQ) && - (icmp->icmp_type != ICMP_MASKREQ)) + if ((icmp->icmp_type != ICMP_ECHO) && + (icmp->icmp_type != ICMP_TSTAMP) && + (icmp->icmp_type != ICMP_IREQ) && + (icmp->icmp_type != ICMP_MASKREQ)) return NULL; /* @@ -1273,38 +1878,41 @@ fr_info_t *fin; dst.in4 = oip->ip_dst; hv += dst.in4.s_addr; hv += icmp->icmp_id; - hv += icmp->icmp_seq; - hv %= fr_statesize; - - savelen = oip->ip_len; - oip->ip_len = len; - fr_makefrip(ohlen, oip, &ofin); - oip->ip_len = savelen; + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == 4) && - fr_matchsrcdst(is, src, dst, &ofin, NULL) && - fr_matchicmpqueryreply(is->is_v, is, icmp)) { + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != 4)) + continue; + if (is->is_pass & FR_NOICMPERR) + continue; + is = fr_matchsrcdst(&ofin, is, &src, &dst, NULL); + if (is != NULL) { + if ((is->is_pass & FR_NOICMPERR) != 0) { + RWLOCK_EXIT(&ipf_state); + return NULL; + } + backward = IP6_NEQ(&is->is_src, &dst); + i = (backward << 1) + fin->fin_out; + if (is->is_icmppkts[i] > is->is_pkts[i]) + continue; ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += ip->ip_len; - fr = is->is_rule; - break; + is->is_icmppkts[i]++; + is->is_bytes[i] += fin->fin_plen; + return is; } + } RWLOCK_EXIT(&ipf_state); - return fr; - + return NULL; case IPPROTO_TCP : case IPPROTO_UDP : - if (fin->fin_plen < ICMPERR_MAXPKTLEN) - return NULL; break; default : return NULL; } - tcp = (tcphdr_t *)((char *)oip + ohlen); + tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); dport = tcp->th_dport; sport = tcp->th_sport; @@ -1315,108 +1923,119 @@ fr_info_t *fin; hv += dst.in4.s_addr; hv += dport; hv += sport; - hv %= fr_statesize; - /* - * we make an fin entry to be able to feed it to - * matchsrcdst note that not all fields are encessary - * but this is the cleanest way. Note further we fill - * in fin_mp such that if someone uses it we'll get - * a kernel panic. fr_matchsrcdst does not use this. - * - * watch out here, as ip is in host order and oip in network - * order. Any change we make must be undone afterwards. - */ - savelen = oip->ip_len; - oip->ip_len = len; - fr_makefrip(ohlen, oip, &ofin); - oip->ip_len = savelen; + hv = DOUBLE_HASH(hv); + READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; /* * Only allow this icmp though if the * encapsulated packet was allowed through the * other way around. Note that the minimal amount * of info present does not allow for checking against - * tcp internals such as seq and ack numbers. + * tcp internals such as seq and ack numbers. Only the + * ports are known to be present and can be even if the + * short flag is set. */ if ((is->is_p == pr) && (is->is_v == 4) && - fr_matchsrcdst(is, src, dst, &ofin, tcp)) { - fr = is->is_rule; + (is = fr_matchsrcdst(&ofin, is, &src, &dst, tcp))) { + backward = IP6_NEQ(&is->is_dst, &src); + i = (backward << 1) + fin->fin_out; + if (((is->is_pass & FR_NOICMPERR) != 0) || + (is->is_icmppkts[i] > is->is_pkts[i])) + break; ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += fin->fin_plen; + is->is_icmppkts[i]++; + is->is_bytes[i] += fin->fin_plen; /* * we deliberately do not touch the timeouts * for the accompanying state table entry. * It remains to be seen if that is correct. XXX */ - break; + return is; } } RWLOCK_EXIT(&ipf_state); - return fr; + return NULL; } -/* - * Move a state hash table entry from its old location at is->is_hv to - * its new location, indexed by hv % fr_statesize. - */ -static void fr_ipsmove(isp, is, hv) -ipstate_t **isp, *is; +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipsmove */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state table entry */ +/* hv(I) - new hash value for state table entry */ +/* Write Locks: ipf_state */ +/* */ +/* Move a state entry from one position in the hash table to another. */ +/* ------------------------------------------------------------------------ */ +static void fr_ipsmove(is, hv) +ipstate_t *is; u_int hv; { + ipstate_t **isp; u_int hvm; + ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0); + hvm = is->is_hv; /* * Remove the hash from the old location... */ + isp = is->is_phnext; if (is->is_hnext) is->is_hnext->is_phnext = isp; *isp = is->is_hnext; if (ips_table[hvm] == NULL) ips_stats.iss_inuse--; + ips_stats.iss_bucketlen[hvm]--; /* * ...and put the hash in the new one. */ - hvm = hv % fr_statesize; + hvm = DOUBLE_HASH(hv); is->is_hv = hvm; isp = &ips_table[hvm]; if (*isp) (*isp)->is_phnext = &is->is_hnext; else ips_stats.iss_inuse++; + ips_stats.iss_bucketlen[hvm]++; is->is_phnext = isp; is->is_hnext = *isp; *isp = is; } -/* - * Check if a packet has a registered state. - */ -frentry_t *fr_checkstate(ip, fin) -ip_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_stlookup */ +/* Returns: ipstate_t* - NULL == no matching state found, */ +/* else pointer to state information is returned */ +/* Parameters: fin(I) - pointer to packet information */ +/* tcp(I) - pointer to TCP/UDP header. */ +/* */ +/* Search the state table for a matching entry to the packet described by */ +/* the contents of *fin. */ +/* */ +/* If we return NULL then no lock on ipf_state is held. */ +/* If we return non-null then a read-lock on ipf_state is held. */ +/* ------------------------------------------------------------------------ */ +ipstate_t *fr_stlookup(fin, tcp, ifqp) fr_info_t *fin; +tcphdr_t *tcp; +ipftq_t **ifqp; { - union i6addr dst, src; - register ipstate_t *is, **isp; - register u_char pr; - u_int hv, hvm, hlen, tryagain, pass, v; + u_int hv, hvm, pr, v, tryagain; + ipstate_t *is, **isp; + u_short dport, sport; + i6addr_t src, dst; struct icmp *ic; - frentry_t *fr; - tcphdr_t *tcp; - int rev; - - if ((ips_list == NULL) || (fin->fin_off != 0) || fr_state_lock || - (fin->fin_fl & FI_SHORT)) - return NULL; + grehdr_t *gre; + ipftq_t *ifq; is = NULL; - hlen = fin->fin_hlen; - tcp = (tcphdr_t *)((char *)ip + hlen); + ifq = NULL; + tcp = fin->fin_dp; ic = (struct icmp *)tcp; hv = (pr = fin->fin_fi.fi_p); src = fin->fin_fi.fi_src; @@ -1424,18 +2043,12 @@ fr_info_t *fin; hv += src.in4.s_addr; hv += dst.in4.s_addr; - /* - * Search the hash table for matching packet header info. - * At the bottom of this switch statement, the following is expected: - * is == NULL, no lock on ipf_state is held. - * is != NULL, a lock on ipf_state is held. - */ v = fin->fin_fi.fi_v; #ifdef USE_INET6 if (v == 6) { - hv += fin->fin_fi.fi_src.i6[1]; - hv += fin->fin_fi.fi_src.i6[2]; - hv += fin->fin_fi.fi_src.i6[3]; + hv += fin->fin_fi.fi_src.i6[1]; + hv += fin->fin_fi.fi_src.i6[2]; + hv += fin->fin_fi.fi_src.i6[3]; if ((fin->fin_p == IPPROTO_ICMPV6) && IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_dst.in6)) { @@ -1448,7 +2061,10 @@ fr_info_t *fin; } #endif - switch (fin->fin_p) + /* + * Search the hash table for matching packet header info. + */ + switch (pr) { #ifdef USE_INET6 case IPPROTO_ICMPV6 : @@ -1458,33 +2074,36 @@ fr_info_t *fin; if ((ic->icmp_type == ICMP6_ECHO_REQUEST) || (ic->icmp_type == ICMP6_ECHO_REPLY)) { hv += ic->icmp_id; - hv += ic->icmp_seq; } } READ_ENTER(&ipf_state); icmp6again: - hvm = hv % fr_statesize; - for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, NULL) && - fr_matchicmpqueryreply(v, is, ic)) { - rev = fin->fin_rev; - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else if (rev != 0) - is->is_age = fr_icmpacktimeout; - else - is->is_age = fr_icmptimeout; + hvm = DOUBLE_HASH(hv); + for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, NULL); + if (is != NULL && + fr_matchicmpqueryreply(v, &is->is_icmp, + ic, fin->fin_rev)) { + if (!(is->is_sti.tqe_flags & TQE_RULEBASED)) { + if (fin->fin_rev) + ifq = &ips_icmpacktq; + else + ifq = &ips_icmptq; + } break; } + } if (is != NULL) { - if (tryagain && !(is->is_flags & FI_W_DADDR)) { + if ((tryagain != 0) && !(is->is_flags & SI_W_DADDR)) { hv += fin->fin_fi.fi_src.i6[0]; hv += fin->fin_fi.fi_src.i6[1]; hv += fin->fin_fi.fi_src.i6[2]; hv += fin->fin_fi.fi_src.i6[3]; - fr_ipsmove(isp, is, hv); + fr_ipsmove(is, hv); MUTEX_DOWNGRADE(&ipf_state); } break; @@ -1495,7 +2114,7 @@ icmp6again: * No matching icmp state entry. Perhaps this is a * response to another state entry. */ - if ((ips_wild != 0) && (v == 6) && (tryagain == 0) && + if ((ips_stats.iss_wild != 0) && (v == 6) && (tryagain == 0) && !IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_src.in6)) { hv -= fin->fin_fi.fi_src.i6[0]; hv -= fin->fin_fi.fi_src.i6[1]; @@ -1506,115 +2125,119 @@ icmp6again: goto icmp6again; } - fr = fr_checkicmp6matchingstate((ip6_t *)ip, fin); - if (fr) - return fr; + is = fr_checkicmp6matchingstate(fin); + if (is != NULL) + return is; break; #endif + case IPPROTO_ICMP : - tcp = NULL; if (v == 4) { hv += ic->icmp_id; - hv += ic->icmp_seq; } - hvm = hv % fr_statesize; + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, NULL) && - fr_matchicmpqueryreply(v, is, ic)) { - rev = fin->fin_rev; - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else if (fin->fin_rev) - is->is_age = fr_icmpacktimeout; - else - is->is_age = fr_icmptimeout; - break; - } - - if (is != NULL) - break; - RWLOCK_EXIT(&ipf_state); - /* - * No matching icmp state entry. Perhaps this is a - * response to another state entry. - */ - fr = fr_checkicmpmatchingstate(ip, fin); - if (fr) - return fr; - break; - case IPPROTO_TCP : - /* - * Just plain ignore RST flag set with either FIN or SYN. - */ - if ((tcp->th_flags & TH_RST) && - ((tcp->th_flags & (TH_FIN|TH_SYN|TH_RST)) != TH_RST)) - break; - case IPPROTO_UDP : - { - register u_short dport, sport; - - dport = tcp->th_dport; - sport = tcp->th_sport; - tryagain = 0; - hv += dport; - hv += sport; - READ_ENTER(&ipf_state); -retry_tcpudp: - hvm = hv % fr_statesize; - for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, tcp)) { - rev = fin->fin_rev; - if ((pr == IPPROTO_TCP)) { - if (!fr_tcpstate(is, fin, ip, tcp)) - is = NULL; - } else if ((pr == IPPROTO_UDP)) { - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else if (fin->fin_rev) - is->is_age = fr_udpacktimeout; + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, NULL); + if (is != NULL && + fr_matchicmpqueryreply(v, &is->is_icmp, + ic, fin->fin_rev)) { + if (!(is->is_sti.tqe_flags & TQE_RULEBASED)) { + if (fin->fin_rev) + ifq = &ips_icmpacktq; else - is->is_age = fr_udptimeout; + ifq = &ips_icmptq; } break; } - if (is != NULL) { - if (tryagain && - !(is->is_flags & (FI_WILDP|FI_WILDA))) { - hv += dport; - hv += sport; - fr_ipsmove(isp, is, hv); - MUTEX_DOWNGRADE(&ipf_state); - } - break; - } - - RWLOCK_EXIT(&ipf_state); - if (!tryagain && ips_wild) { - hv -= dport; - hv -= sport; - tryagain = 1; - WRITE_ENTER(&ipf_state); - goto retry_tcpudp; - } - break; - } - default : - tcp = NULL; - hv %= fr_statesize; - READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, NULL)) { - rev = fin->fin_rev; - if (is->is_frage[rev] != 0) - is->is_age = is->is_frage[rev]; - else - is->is_age = fr_udptimeout; - break; - } + } + if (is == NULL) { + RWLOCK_EXIT(&ipf_state); + } + break; + + case IPPROTO_GRE : + gre = fin->fin_dp; + hv += gre->gr_call; + tcp = NULL; + ifqp = NULL; + hv = DOUBLE_HASH(hv); + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != IPPROTO_GRE) || (is->is_v != v) || + (is->is_gre.gs_call != gre->gr_call)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, NULL); + if (is != NULL) + break; + } + if (is == NULL) { + RWLOCK_EXIT(&ipf_state); + } + break; + + case IPPROTO_TCP : + case IPPROTO_UDP : + ifqp = NULL; + sport = htons(fin->fin_data[0]); + hv += sport; + dport = htons(fin->fin_data[1]); + hv += dport; + tryagain = 0; + READ_ENTER(&ipf_state); +retry_tcpudp: + hvm = DOUBLE_HASH(hv); + for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, tcp); + if (is != NULL) { + if (pr == IPPROTO_TCP) { + if (!fr_tcpstate(fin, tcp, is)) + continue; + fin->fin_flx &= ~FI_OOW; + } + break; + } + } + if (is != NULL) { + if (tryagain && + !(is->is_flags & (SI_CLONE|SI_WILDP|SI_WILDA))) { + hv += dport; + hv += sport; + fr_ipsmove(is, hv); + MUTEX_DOWNGRADE(&ipf_state); + } + break; + } + RWLOCK_EXIT(&ipf_state); + + if (!tryagain && ips_stats.iss_wild) { + hv -= dport; + hv -= sport; + tryagain = 1; + WRITE_ENTER(&ipf_state); + goto retry_tcpudp; + } + break; + + default : + tcp = NULL; + ifqp = NULL; + hvm = DOUBLE_HASH(hv); + READ_ENTER(&ipf_state); + for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; + if ((is->is_p != pr) || (is->is_v != v)) + continue; + is = fr_matchsrcdst(fin, is, &src, &dst, NULL); + if (is != NULL) + break; } if (is == NULL) { RWLOCK_EXIT(&ipf_state); @@ -1622,52 +2245,288 @@ retry_tcpudp: break; } + if (ifq != NULL && ifqp != NULL) + *ifqp = ifq; + return is; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_updatestate */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to state table entry */ +/* Read Locks: ipf_state */ +/* */ +/* Updates packet and byte counters for a newly received packet. Seeds the */ +/* fragment cache with a new entry as required. */ +/* ------------------------------------------------------------------------ */ +void fr_updatestate(fin, is, ifq) +fr_info_t *fin; +ipstate_t *is; +ipftq_t *ifq; +{ + ipftqent_t *tqe; + int i, pass; + + i = (fin->fin_rev << 1) + fin->fin_out; + + /* + * For TCP packets, ifq == NULL. For all others, check if this new + * queue is different to the last one it was on and move it if so. + */ + MUTEX_ENTER(&is->is_lock); + tqe = &is->is_sti; + if ((tqe->tqe_flags & TQE_RULEBASED) != 0) + ifq = is->is_tqehead[fin->fin_rev]; + + if (ifq != NULL) + fr_movequeue(tqe, tqe->tqe_ifq, ifq); + + is->is_pkts[i]++; + is->is_bytes[i] += fin->fin_plen; + MUTEX_EXIT(&is->is_lock); + +#ifdef IPFILTER_SYNC + ipfsync_update(SMC_STATE, fin, is->is_sync); +#endif + + ATOMIC_INCL(ips_stats.iss_hits); + + fin->fin_fr = is->is_rule; + + /* + * If this packet is a fragment and the rule says to track fragments, + * then create a new fragment cache entry. + */ + pass = is->is_pass; + if ((fin->fin_flx & FI_FRAG) && FR_ISPASS(pass)) + (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkstate */ +/* Returns: frentry_t* - NULL == search failed, */ +/* else pointer to rule for matching state */ +/* Parameters: ifp(I) - pointer to interface */ +/* passp(I) - pointer to filtering result flags */ +/* */ +/* Check if a packet is associated with an entry in the state table. */ +/* ------------------------------------------------------------------------ */ +frentry_t *fr_checkstate(fin, passp) +fr_info_t *fin; +u_32_t *passp; +{ + ipstate_t *is; + frentry_t *fr; + tcphdr_t *tcp; + ipftq_t *ifq; + u_int pass; + + if (fr_state_lock || (ips_list == NULL) || + (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGTAIL|FI_BAD))) + return NULL; + + is = NULL; + if ((fin->fin_flx & FI_TCPUDP) || + (fin->fin_fi.fi_p == IPPROTO_ICMP) +#ifdef USE_INET6 + || (fin->fin_fi.fi_p == IPPROTO_ICMPV6) +#endif + ) + tcp = fin->fin_dp; + else + tcp = NULL; + + /* + * Search the hash table for matching packet header info. + */ + ifq = NULL; + is = fin->fin_state; + if (is == NULL) + is = fr_stlookup(fin, tcp, &ifq); + switch (fin->fin_p) + { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + if (is != NULL) + break; + if (fin->fin_v == 6) { + is = fr_checkicmp6matchingstate(fin); + if (is != NULL) + goto matched; + } + break; +#endif + case IPPROTO_ICMP : + if (is != NULL) + break; + /* + * No matching icmp state entry. Perhaps this is a + * response to another state entry. + */ + is = fr_checkicmpmatchingstate(fin); + if (is != NULL) + goto matched; + break; + case IPPROTO_TCP : + if (is == NULL) + break; + + if (is->is_pass & FR_NEWISN) { + if (fin->fin_out == 0) + fr_fixinisn(fin, is); + else if (fin->fin_out == 1) + fr_fixoutisn(fin, is); + } + break; + default : + if (fin->fin_rev) + ifq = &ips_udpacktq; + else + ifq = &ips_udptq; + break; + } if (is == NULL) { ATOMIC_INCL(ips_stats.iss_miss); return NULL; } - MUTEX_ENTER(&is->is_lock); - is->is_bytes += fin->fin_plen; - ips_stats.iss_hits++; - is->is_pkts++; - MUTEX_EXIT(&is->is_lock); +matched: fr = is->is_rule; + if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { + if (fin->fin_nattag == NULL) + return NULL; + if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) != 0) + return NULL; + } + fin->fin_rule = is->is_rulen; if (fr != NULL) { - fin->fin_group = fr->fr_group; + (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN); fin->fin_icode = fr->fr_icode; } - fin->fin_fr = fr; pass = is->is_pass; + fr_updatestate(fin, is, ifq); + if (fin->fin_out == 1) + fin->fin_nat = is->is_nat[fin->fin_rev]; + + fin->fin_state = is; + is->is_touched = fr_ticks; + MUTEX_ENTER(&is->is_lock); + is->is_ref++; + MUTEX_EXIT(&is->is_lock); RWLOCK_EXIT(&ipf_state); - if ((fin->fin_fl & FI_FRAG) && (pass & FR_KEEPFRAG)) - ipfr_newfrag(ip, fin); -#ifndef _KERNEL - if ((tcp != NULL) && (tcp->th_flags & TCP_CLOSE)) - fr_delstate(is); -#endif + fin->fin_flx |= FI_STATE; + if ((pass & FR_LOGFIRST) != 0) + pass &= ~(FR_LOGFIRST|FR_LOG); + *passp = pass; return fr; } -/* - * Sync. state entries. If interfaces come or go or just change position, - * this is needed. - */ -void ip_statesync(ifp) +/* ------------------------------------------------------------------------ */ +/* Function: fr_fixoutisn */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* */ +/* Called only for outbound packets, adjusts the sequence number and the */ +/* TCP checksum to match that change. */ +/* ------------------------------------------------------------------------ */ +static void fr_fixoutisn(fin, is) +fr_info_t *fin; +ipstate_t *is; +{ + tcphdr_t *tcp; + int rev; + + tcp = fin->fin_dp; + rev = fin->fin_rev; + if ((is->is_flags & IS_ISNSYN) != 0) { + if (rev == 0) { + tcp->th_seq += is->is_isninc[0]; + fix_outcksum(fin, &tcp->th_sum, is->is_sumd[0]); + } + } + if ((is->is_flags & IS_ISNACK) != 0) { + if (rev == 1) { + tcp->th_seq += is->is_isninc[1]; + fix_outcksum(fin, &tcp->th_sum, is->is_sumd[1]); + } + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fixinisn */ +/* Returns: Nil */ +/* Parameters: fin(I) - pointer to packet information */ +/* is(I) - pointer to master state structure */ +/* */ +/* Called only for inbound packets, adjusts the acknowledge number and the */ +/* TCP checksum to match that change. */ +/* ------------------------------------------------------------------------ */ +static void fr_fixinisn(fin, is) +fr_info_t *fin; +ipstate_t *is; +{ + tcphdr_t *tcp; + int rev; + + tcp = fin->fin_dp; + rev = fin->fin_rev; + if ((is->is_flags & IS_ISNSYN) != 0) { + if (rev == 1) { + tcp->th_ack -= is->is_isninc[0]; + fix_incksum(fin, &tcp->th_sum, is->is_sumd[0]); + } + } + if ((is->is_flags & IS_ISNACK) != 0) { + if (rev == 0) { + tcp->th_ack -= is->is_isninc[1]; + fix_incksum(fin, &tcp->th_sum, is->is_sumd[1]); + } + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_statesync */ +/* Returns: Nil */ +/* Parameters: ifp(I) - pointer to interface */ +/* */ +/* Walk through all state entries and if an interface pointer match is */ +/* found then look it up again, based on its name in case the pointer has */ +/* changed since last time. */ +/* ------------------------------------------------------------------------ */ +void fr_statesync(ifp) void *ifp; { - register ipstate_t *is; + ipstate_t *is; int i; + if (fr_running <= 0) + return; + WRITE_ENTER(&ipf_state); + + if (fr_running <= 0) { + RWLOCK_EXIT(&ipf_state); + return; + } + for (is = ips_list; is; is = is->is_next) { + /* + * Look up all the interface names in the state entry. + */ for (i = 0; i < 4; i++) { if (is->is_ifp[i] == ifp) { - is->is_ifpin = GETUNIT(is->is_ifname[i], + is->is_ifname[i][LIFNAMSIZ - 1] = '\0'; + is->is_ifp[i] = GETIFP(is->is_ifname[i], is->is_v); - if (!is->is_ifp[i]) + if (is->is_ifp[i] == NULL) is->is_ifp[i] = (void *)-1; } } @@ -1676,86 +2535,150 @@ void *ifp; } -/* - * Must always be called with fr_ipfstate held as a write lock. - */ -static void fr_delstate(is) +/* ------------------------------------------------------------------------ */ +/* Function: fr_delstate */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure to delete */ +/* why(I) - if not 0, log reason why it was deleted */ +/* Write Locks: ipf_state */ +/* */ +/* Deletes a state entry from the enumerated list as well as the hash table */ +/* and timeout queue lists. Make adjustments to hash table statistics and */ +/* global counters as required. */ +/* ------------------------------------------------------------------------ */ +static void fr_delstate(is, why) ipstate_t *is; +int why; { - frentry_t *fr; + ipftqent_t *tqe; + ipftq_t *ifq; - if (is->is_flags & (FI_WILDP|FI_WILDA)) - ips_wild--; - if (is->is_next) - is->is_next->is_pnext = is->is_pnext; + ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0); + + /* + * Since we want to delete this, remove it from the state table, + * where it can be found & used, first. + */ *is->is_pnext = is->is_next; - if (is->is_hnext) - is->is_hnext->is_phnext = is->is_phnext; + + if (is->is_next != NULL) + is->is_next->is_pnext = is->is_pnext; + + + is->is_pnext = NULL; + is->is_next = NULL; + *is->is_phnext = is->is_hnext; + if (is->is_hnext != NULL) + is->is_hnext->is_phnext = is->is_phnext; if (ips_table[is->is_hv] == NULL) ips_stats.iss_inuse--; - if (is->is_me) - *is->is_me = NULL; + ips_stats.iss_bucketlen[is->is_hv]--; - fr = is->is_rule; - if (fr != NULL) { - fr->fr_ref--; - if (fr->fr_ref == 0) { - KFREE(fr); + is->is_phnext = NULL; + is->is_hnext = NULL; + + /* + * Because ips_stats.iss_wild is a count of entries in the state + * table that have wildcard flags set, only decerement it once + * and do it here. + */ + if (is->is_flags & (SI_WILDP|SI_WILDA)) { + if (!(is->is_flags & SI_CLONED)) { + ATOMIC_DECL(ips_stats.iss_wild); } } -#ifdef _KERNEL - MUTEX_DESTROY(&is->is_lock); + + + /* + * Next, remove it from the timeout queue it is in. + */ + tqe = &is->is_sti; + ifq = tqe->tqe_ifq; + if (tqe->tqe_pnext != NULL) { + *tqe->tqe_pnext = tqe->tqe_next; + if (tqe->tqe_next != NULL) + tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; + else /* we must be the tail anyway */ + ifq->ifq_tail = tqe->tqe_pnext; + tqe->tqe_pnext = NULL; + tqe->tqe_ifq = NULL; + } + + if ((ifq->ifq_flags & IFQF_USER) != 0) + fr_deletetimeoutqueue(ifq); + + /* + * If it is still in use by something else, do not go any further, + * but note that at this point it is now an orphan. + */ + is->is_ref--; + if (is->is_ref > 0) + return; + +#ifdef IPFILTER_SYNC + if (is->is_sync) + ipfsync_del(is->is_sync); #endif +#ifdef IPFILTER_SCAN + (void) ipsc_detachis(is); +#endif + + if (ipstate_logging != 0 && why != 0) + ipstate_log(is, why); + + if (is->is_rule != NULL) { + is->is_rule->fr_statecnt--; + (void)fr_derefrule(&is->is_rule); + } + + MUTEX_DESTROY(&is->is_lock); KFREE(is); ips_num--; } -/* - * Free memory in use by all state info. kept. - */ -void fr_stateunload() -{ - register ipstate_t *is; - - WRITE_ENTER(&ipf_state); - while ((is = ips_list)) - fr_delstate(is); - ips_stats.iss_inuse = 0; - ips_num = 0; - RWLOCK_EXIT(&ipf_state); - if (ips_table) - KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); - ips_table = NULL; -} - - -/* - * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set - * in expectation of this being called twice per second. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_timeoutstate */ +/* Returns: Nil */ +/* Parameters: Nil */ +/* */ +/* Slowly expire held state for thingslike UDP and ICMP. The algorithm */ +/* used here is to keep the queue sorted with the oldest things at the top */ +/* and the youngest at the bottom. So if the top one doesn't need to be */ +/* expired then neither will any under it. */ +/* ------------------------------------------------------------------------ */ void fr_timeoutstate() { - register ipstate_t *is, **isp; -#if defined(_KERNEL) && !SOLARIS + ipftq_t *ifq, *ifqnext; + ipftqent_t *tqe, *tqn; + ipstate_t *is; +#if defined(USE_SPL) && defined(_KERNEL) int s; #endif SPL_NET(s); WRITE_ENTER(&ipf_state); - for (isp = &ips_list; (is = *isp); ) - if (is->is_age && !--is->is_age) { - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; -#ifdef IPFILTER_LOG - ipstate_log(is, ISL_EXPIRE); -#endif - fr_delstate(is); - } else - isp = &is->is_next; + for (ifq = ips_tqtqb; ifq != NULL; ifq = ifq->ifq_next) + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + } + + for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > fr_ticks) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + } + } if (fr_state_doflush) { (void) fr_state_flush(2); fr_state_doflush = 0; @@ -1765,296 +2688,529 @@ void fr_timeoutstate() } -/* - * Original idea freom Pradeep Krishnan for use primarily with NAT code. - * (pkrishna@netcom.com) - * - * Rewritten by Arjan de Vet , 2000-07-29: - * - * - (try to) base state transitions on real evidence only, - * i.e. packets that are sent and have been received by ipfilter; - * diagram 18.12 of TCP/IP volume 1 by W. Richard Stevens was used. - * - * - deal with half-closed connections correctly; - * - * - store the state of the source in state[0] such that ipfstat - * displays the state as source/dest instead of dest/source; the calls - * to fr_tcp_age have been changed accordingly. - * - * Parameters: - * - * state[0] = state of source (host that initiated connection) - * state[1] = state of dest (host that accepted the connection) - * - * dir == 0 : a packet from source to dest - * dir == 1 : a packet from dest to source - * - */ -int fr_tcp_age(age, state, fin, dir, fsm) -u_long *age; -u_char *state; -fr_info_t *fin; -int dir, fsm; +/* ------------------------------------------------------------------------ */ +/* Function: fr_state_flush */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: Nil */ +/* Write Locks: ipf_state */ +/* */ +/* Flush state tables. Three actions currently defined: */ +/* which == 0 : flush all state table entries */ +/* which == 1 : flush TCP connections which have started to close but are */ +/* stuck for some reason. */ +/* which == 2 : flush TCP connections which have been idle for a long time, */ +/* starting at > 4 days idle and working back in successive half-*/ +/* days to at most 12 hours old. If this fails to free enough */ +/* slots then work backwards in half hour slots to 30 minutes. */ +/* If that too fails, then work backwards in 30 second intervals */ +/* for the last 30 minutes to at worst 30 seconds idle. */ +/* ------------------------------------------------------------------------ */ +static int fr_state_flush(which) +int which; { - tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; - u_char flags = tcp->th_flags; - int dlen, ostate; - u_long newage; + ipftq_t *ifq, *ifqnext; + ipftqent_t *tqe, *tqn; + ipstate_t *is, **isp; + int delete, removed; + long try, maxtick; + u_long interval; +#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) + int s; +#endif - ostate = state[1 - dir]; + removed = 0; - dlen = fin->fin_plen - fin->fin_hlen - (tcp->th_off << 2); + SPL_NET(s); + for (isp = &ips_list; ((is = *isp) != NULL); ) { + delete = 0; - if (flags & TH_RST) { - if (!(tcp->th_flags & TH_PUSH) && !dlen) { - *age = fr_tcpclosed; - state[dir] = TCPS_CLOSED; - } else { - *age = fr_tcpclosewait; - state[dir] = TCPS_CLOSE_WAIT; + switch (which) + { + case 0 : + delete = 1; + break; + case 1 : + case 2 : + if (is->is_p != IPPROTO_TCP) + break; + if ((is->is_state[0] != IPF_TCPS_ESTABLISHED) || + (is->is_state[1] != IPF_TCPS_ESTABLISHED)) + delete = 1; + break; } - return 0; + + if (delete) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; + fr_delstate(is, ISL_FLUSH); + removed++; + } else + isp = &is->is_next; } - newage = 0; + if (which != 2) { + SPL_X(s); + return removed; + } - switch(state[dir]) - { - case TCPS_CLOSED: /* 0 */ - if ((flags & TH_OPENING) == TH_OPENING) { - /* - * 'dir' received an S and sends SA in response, - * CLOSED -> SYN_RECEIVED - */ - state[dir] = TCPS_SYN_RECEIVED; - newage = fr_tcptimeout; - } else if ((flags & TH_OPENING) == TH_SYN) { - /* 'dir' sent S, CLOSED -> SYN_SENT */ - state[dir] = TCPS_SYN_SENT; - newage = fr_tcptimeout; + /* + * Asked to remove inactive entries because the table is full, try + * again, 3 times, if first attempt failed with a different criteria + * each time. The order tried in must be in decreasing age. + * Another alternative is to implement random drop and drop N entries + * at random until N have been freed up. + */ + if (fr_ticks - ips_last_force_flush < IPF_TTLVAL(5)) + goto force_flush_skipped; + ips_last_force_flush = fr_ticks; + + if (fr_ticks > IPF_TTLVAL(43200)) + interval = IPF_TTLVAL(43200); + else if (fr_ticks > IPF_TTLVAL(1800)) + interval = IPF_TTLVAL(1800); + else if (fr_ticks > IPF_TTLVAL(30)) + interval = IPF_TTLVAL(30); + else + interval = IPF_TTLVAL(10); + try = fr_ticks - (fr_ticks - interval); + if (try < 0) + goto force_flush_skipped; + + while (removed == 0) { + maxtick = fr_ticks - interval; + if (maxtick < 0) + break; + + while (try < maxtick) { + for (ifq = ips_tqtqb; ifq != NULL; + ifq = ifq->ifq_next) { + for (tqn = ifq->ifq_head; + ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > try) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + removed++; + } + } + + for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + for (tqn = ifq->ifq_head; + ((tqe = tqn) != NULL); ) { + if (tqe->tqe_die > try) + break; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + fr_delstate(is, ISL_EXPIRE); + removed++; + } + } + if (try + interval > maxtick) + break; + try += interval; } - /* - * The next piece of code makes it possible to get - * already established connections into the state table - * after a restart or reload of the filter rules; this - * does not work when a strict 'flags S keep state' is - * used for tcp connections of course - */ - if (!fsm && (flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) { - /* we saw an A, guess 'dir' is in ESTABLISHED mode */ - if (state[1 - dir] == TCPS_CLOSED || - state[1 - dir] == TCPS_ESTABLISHED) { - state[dir] = TCPS_ESTABLISHED; - newage = fr_tcpidletimeout; + + if (removed == 0) { + if (interval == IPF_TTLVAL(43200)) { + interval = IPF_TTLVAL(1800); + } else if (interval == IPF_TTLVAL(1800)) { + interval = IPF_TTLVAL(30); + } else if (interval == IPF_TTLVAL(30)) { + interval = IPF_TTLVAL(10); + } else { + break; } } - /* - * TODO: besides regular ACK packets we can have other - * packets as well; it is yet to be determined how we - * should initialize the states in those cases - */ - break; - - case TCPS_LISTEN: /* 1 */ - /* NOT USED */ - break; - - case TCPS_SYN_SENT: /* 2 */ - if ((flags & ~(TH_ECN|TH_CWR)) == TH_SYN) { - /* - * A retransmitted SYN packet. We do not reset the - * timeout here to fr_tcptimeout because a connection - * connect timeout does not renew after every packet - * that is sent. We need to set newage to something - * to indicate the packet has passed the check for its - * flags being valid in the TCP FSM. - */ - newage = *age; - } else if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { - /* - * We see an A from 'dir' which is in SYN_SENT - * state: 'dir' sent an A in response to an SA - * which it received, SYN_SENT -> ESTABLISHED - */ - state[dir] = TCPS_ESTABLISHED; - newage = fr_tcpidletimeout; - } else if (flags & TH_FIN) { - /* - * We see an F from 'dir' which is in SYN_SENT - * state and wants to close its side of the - * connection; SYN_SENT -> FIN_WAIT_1 - */ - state[dir] = TCPS_FIN_WAIT_1; - newage = fr_tcpidletimeout; /* or fr_tcptimeout? */ - } else if ((flags & TH_OPENING) == TH_OPENING) { - /* - * We see an SA from 'dir' which is already in - * SYN_SENT state, this means we have a - * simultaneous open; SYN_SENT -> SYN_RECEIVED - */ - state[dir] = TCPS_SYN_RECEIVED; - newage = fr_tcptimeout; - } - break; - - case TCPS_SYN_RECEIVED: /* 3 */ - if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { - /* - * We see an A from 'dir' which was in SYN_RECEIVED - * state so it must now be in established state, - * SYN_RECEIVED -> ESTABLISHED - */ - state[dir] = TCPS_ESTABLISHED; - newage = fr_tcpidletimeout; - } else if ((flags & ~(TH_ECN|TH_CWR)) == TH_OPENING) { - /* - * We see an SA from 'dir' which is already in - * SYN_RECEIVED state. - */ - newage = fr_tcptimeout; - } else if (flags & TH_FIN) { - /* - * We see an F from 'dir' which is in SYN_RECEIVED - * state and wants to close its side of the connection; - * SYN_RECEIVED -> FIN_WAIT_1 - */ - state[dir] = TCPS_FIN_WAIT_1; - newage = fr_tcpidletimeout; - } - break; - - case TCPS_ESTABLISHED: /* 4 */ - if (flags & TH_FIN) { - /* - * 'dir' closed its side of the connection; this - * gives us a half-closed connection; - * ESTABLISHED -> FIN_WAIT_1 - */ - state[dir] = TCPS_FIN_WAIT_1; - newage = fr_tcphalfclosed; - } else if (flags & TH_ACK) { - /* an ACK, should we exclude other flags here? */ - if (ostate == TCPS_FIN_WAIT_1) { - /* - * We know the other side did an active close, - * so we are ACKing the recvd FIN packet (does - * the window matching code guarantee this?) - * and go into CLOSE_WAIT state; this gives us - * a half-closed connection - */ - state[dir] = TCPS_CLOSE_WAIT; - newage = fr_tcphalfclosed; - } else if (ostate < TCPS_CLOSE_WAIT) - /* - * Still a fully established connection, - * reset timeout - */ - newage = fr_tcpidletimeout; - } - break; - - case TCPS_CLOSE_WAIT: /* 5 */ - if (flags & TH_FIN) { - /* - * Application closed and 'dir' sent a FIN, we're now - * going into LAST_ACK state - */ - newage = fr_tcplastack; - state[dir] = TCPS_LAST_ACK; - } else { - /* - * We remain in CLOSE_WAIT because the other side has - * closed already and we did not close our side yet; - * reset timeout - */ - newage = fr_tcphalfclosed; - } - break; - - case TCPS_FIN_WAIT_1: /* 6 */ - if ((flags & TH_ACK) && ostate > TCPS_CLOSE_WAIT) { - /* - * If the other side is not active anymore it has sent - * us a FIN packet that we are ack'ing now with an ACK; - * this means both sides have now closed the connection - * and we go into TIME_WAIT - */ - /* - * XXX: how do we know we really are ACKing the FIN - * packet here? does the window code guarantee that? - */ - state[dir] = TCPS_TIME_WAIT; - newage = fr_tcptimeout; - } else - /* - * We closed our side of the connection already but the - * other side is still active (ESTABLISHED/CLOSE_WAIT); - * continue with this half-closed connection - */ - newage = fr_tcphalfclosed; - break; - - case TCPS_CLOSING: /* 7 */ - /* NOT USED */ - break; - - case TCPS_LAST_ACK: /* 8 */ - if (flags & TH_ACK) { - if ((flags & TH_PUSH) || dlen) - /* - * There is still data to be delivered, reset - * timeout - */ - newage = fr_tcplastack; - else - newage = *age; - } - /* - * We cannot detect when we go out of LAST_ACK state to CLOSED - * because that is based on the reception of ACK packets; - * ipfilter can only detect that a packet has been sent by a - * host - */ - break; - - case TCPS_FIN_WAIT_2: /* 9 */ - /* NOT USED */ - break; - - case TCPS_TIME_WAIT: /* 10 */ - newage = fr_tcptimeout; /* default 4 mins */ - /* we're in 2MSL timeout now */ - break; } - - if (newage != 0) { - *age = newage; - return 0; - } - return -1; +force_flush_skipped: + SPL_X(s); + return removed; } -#ifdef IPFILTER_LOG + +/* ------------------------------------------------------------------------ */ +/* Function: fr_tcp_age */ +/* Returns: int - 1 == state transition made, 0 == no change (rejected) */ +/* Parameters: tq(I) - pointer to timeout queue information */ +/* fin(I) - pointer to packet information */ +/* tqtab(I) - TCP timeout queue table this is in */ +/* flags(I) - flags from state/NAT entry */ +/* */ +/* Rewritten by Arjan de Vet , 2000-07-29: */ +/* */ +/* - (try to) base state transitions on real evidence only, */ +/* i.e. packets that are sent and have been received by ipfilter; */ +/* diagram 18.12 of TCP/IP volume 1 by W. Richard Stevens was used. */ +/* */ +/* - deal with half-closed connections correctly; */ +/* */ +/* - store the state of the source in state[0] such that ipfstat */ +/* displays the state as source/dest instead of dest/source; the calls */ +/* to fr_tcp_age have been changed accordingly. */ +/* */ +/* Internal Parameters: */ +/* */ +/* state[0] = state of source (host that initiated connection) */ +/* state[1] = state of dest (host that accepted the connection) */ +/* */ +/* dir == 0 : a packet from source to dest */ +/* dir == 1 : a packet from dest to source */ +/* ------------------------------------------------------------------------ */ +int fr_tcp_age(tqe, fin, tqtab, flags) +ipftqent_t *tqe; +fr_info_t *fin; +ipftq_t *tqtab; +int flags; +{ + int dlen, ostate, nstate, rval, dir; + u_char tcpflags; + tcphdr_t *tcp; + + tcp = fin->fin_dp; + + rval = 0; + dir = fin->fin_rev; + tcpflags = tcp->th_flags; + dlen = fin->fin_plen - fin->fin_hlen - (TCP_OFF(tcp) << 2); + + if (tcpflags & TH_RST) { + if (!(tcpflags & TH_PUSH) && !dlen) + nstate = IPF_TCPS_CLOSED; + else + nstate = IPF_TCPS_CLOSE_WAIT; + rval = 1; + } else { + ostate = tqe->tqe_state[1 - dir]; + nstate = tqe->tqe_state[dir]; + + switch (nstate) + { + case IPF_TCPS_CLOSED: /* 0 */ + if ((tcpflags & TH_OPENING) == TH_OPENING) { + /* + * 'dir' received an S and sends SA in + * response, CLOSED -> SYN_RECEIVED + */ + nstate = IPF_TCPS_SYN_RECEIVED; + rval = 1; + } else if ((tcpflags & TH_OPENING) == TH_SYN) { + /* 'dir' sent S, CLOSED -> SYN_SENT */ + nstate = IPF_TCPS_SYN_SENT; + rval = 1; + } + /* + * the next piece of code makes it possible to get + * already established connections into the state table + * after a restart or reload of the filter rules; this + * does not work when a strict 'flags S keep state' is + * used for tcp connections of course + */ + if (((flags & IS_TCPFSM) == 0) && + ((tcpflags & TH_ACKMASK) == TH_ACK)) { + /* + * we saw an A, guess 'dir' is in ESTABLISHED + * mode + */ + if (ostate == IPF_TCPS_CLOSED) { + nstate = IPF_TCPS_HALF_ESTAB; + rval = 1; + } else if (ostate == IPF_TCPS_ESTABLISHED || + ostate == IPF_TCPS_HALF_ESTAB) { + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + } + } + /* + * TODO: besides regular ACK packets we can have other + * packets as well; it is yet to be determined how we + * should initialize the states in those cases + */ + break; + + case IPF_TCPS_LISTEN: /* 1 */ + /* NOT USED */ + break; + + case IPF_TCPS_SYN_SENT: /* 2 */ + if ((tcpflags & ~(TH_ECN|TH_CWR)) == TH_SYN) { + /* + * A retransmitted SYN packet. We do not reset + * the timeout here to fr_tcptimeout because a + * connection connect timeout does not renew + * after every packet that is sent. We need to + * set newage to something to indicate the + * packet has passed the check for its flags + * being valid in the TCP FSM. + */ + rval = 2; + } else if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == + TH_ACK) { + /* + * we see an A from 'dir' which is in SYN_SENT + * state: 'dir' sent an A in response to an SA + * which it received, SYN_SENT -> ESTABLISHED + */ + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + } else if (tcpflags & TH_FIN) { + /* + * we see an F from 'dir' which is in SYN_SENT + * state and wants to close its side of the + * connection; SYN_SENT -> FIN_WAIT_1 + */ + nstate = IPF_TCPS_FIN_WAIT_1; + rval = 1; + } else if ((tcpflags & TH_OPENING) == TH_OPENING) { + /* + * we see an SA from 'dir' which is already in + * SYN_SENT state, this means we have a + * simultaneous open; SYN_SENT -> SYN_RECEIVED + */ + nstate = IPF_TCPS_SYN_RECEIVED; + rval = 1; + } + break; + + case IPF_TCPS_SYN_RECEIVED: /* 3 */ + if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { + /* + * we see an A from 'dir' which was in + * SYN_RECEIVED state so it must now be in + * established state, SYN_RECEIVED -> + * ESTABLISHED + */ + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + } else if ((tcpflags & ~(TH_ECN|TH_CWR)) == + TH_OPENING) { + /* + * We see an SA from 'dir' which is already in + * SYN_RECEIVED state. + */ + rval = 2; + } else if (tcpflags & TH_FIN) { + /* + * we see an F from 'dir' which is in + * SYN_RECEIVED state and wants to close its + * side of the connection; SYN_RECEIVED -> + * FIN_WAIT_1 + */ + nstate = IPF_TCPS_FIN_WAIT_1; + rval = 1; + } + break; + + case IPF_TCPS_HALF_ESTAB: /* 4 */ + if (ostate >= IPF_TCPS_HALF_ESTAB) { + if ((tcpflags & TH_ACKMASK) == TH_ACK) { + nstate = IPF_TCPS_ESTABLISHED; + rval = 1; + } + } + + break; + + case IPF_TCPS_ESTABLISHED: /* 5 */ + rval = 1; + if (tcpflags & TH_FIN) { + /* + * 'dir' closed its side of the connection; + * this gives us a half-closed connection; + * ESTABLISHED -> FIN_WAIT_1 + */ + nstate = IPF_TCPS_FIN_WAIT_1; + } else if (tcpflags & TH_ACK) { + /* + * an ACK, should we exclude other flags here? + */ + if (ostate == IPF_TCPS_FIN_WAIT_1) { + /* + * We know the other side did an active + * close, so we are ACKing the recvd + * FIN packet (does the window matching + * code guarantee this?) and go into + * CLOSE_WAIT state; this gives us a + * half-closed connection + */ + nstate = IPF_TCPS_CLOSE_WAIT; + } else if (ostate < IPF_TCPS_CLOSE_WAIT) { + /* + * still a fully established + * connection reset timeout + */ + nstate = IPF_TCPS_ESTABLISHED; + } + } + break; + + case IPF_TCPS_CLOSE_WAIT: /* 6 */ + rval = 1; + if (tcpflags & TH_FIN) { + /* + * application closed and 'dir' sent a FIN, + * we're now going into LAST_ACK state + */ + nstate = IPF_TCPS_LAST_ACK; + } else { + /* + * we remain in CLOSE_WAIT because the other + * side has closed already and we did not + * close our side yet; reset timeout + */ + nstate = IPF_TCPS_CLOSE_WAIT; + } + break; + + case IPF_TCPS_FIN_WAIT_1: /* 7 */ + rval = 1; + if ((tcpflags & TH_ACK) && + ostate > IPF_TCPS_CLOSE_WAIT) { + /* + * if the other side is not active anymore + * it has sent us a FIN packet that we are + * ack'ing now with an ACK; this means both + * sides have now closed the connection and + * we go into TIME_WAIT + */ + /* + * XXX: how do we know we really are ACKing + * the FIN packet here? does the window code + * guarantee that? + */ + nstate = IPF_TCPS_TIME_WAIT; + } else { + /* + * we closed our side of the connection + * already but the other side is still active + * (ESTABLISHED/CLOSE_WAIT); continue with + * this half-closed connection + */ + nstate = IPF_TCPS_FIN_WAIT_1; + } + break; + + case IPF_TCPS_CLOSING: /* 8 */ + /* NOT USED */ + break; + + case IPF_TCPS_LAST_ACK: /* 9 */ + if (tcpflags & TH_ACK) { + if ((tcpflags & TH_PUSH) || dlen) + /* + * there is still data to be delivered, + * reset timeout + */ + rval = 1; + else + rval = 2; + } + /* + * we cannot detect when we go out of LAST_ACK state to + * CLOSED because that is based on the reception of ACK + * packets; ipfilter can only detect that a packet + * has been sent by a host + */ + break; + + case IPF_TCPS_FIN_WAIT_2: /* 10 */ + rval = 1; + if ((tcpflags & TH_OPENING) == TH_OPENING) + nstate = IPF_TCPS_SYN_RECEIVED; + else if (tcpflags & TH_SYN) + nstate = IPF_TCPS_SYN_SENT; + break; + + case IPF_TCPS_TIME_WAIT: /* 11 */ + /* we're in 2MSL timeout now */ + rval = 1; + break; + + default : +#if defined(_KERNEL) +# if SOLARIS + cmn_err(CE_NOTE, + "tcp %lx flags %x si %lx nstate %d ostate %d\n", + (u_long)tcp, tcpflags, (u_long)tqe, + nstate, ostate); +# else + printf("tcp %lx flags %x si %lx nstate %d ostate %d\n", + (u_long)tcp, tcpflags, (u_long)tqe, + nstate, ostate); +# endif +# ifdef DIAGNOSTIC + panic("invalid TCP state"); +# endif +#else + abort(); +#endif + break; + } + } + + /* + * If rval == 2 then do not update the queue position, but treat the + * packet as being ok. + */ + if (rval == 2) + rval = 1; + else if (rval == 1) { + tqe->tqe_state[dir] = nstate; + if ((tqe->tqe_flags & TQE_RULEBASED) == 0) + fr_movequeue(tqe, tqe->tqe_ifq, tqtab + nstate); + } + + return rval; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipstate_log */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure */ +/* type(I) - type of log entry to create */ +/* */ +/* Creates a state table log entry using the state structure and type info. */ +/* passed in. Log packet/byte counts, source/destination address and other */ +/* protocol specific information. */ +/* ------------------------------------------------------------------------ */ void ipstate_log(is, type) struct ipstate *is; u_int type; { +#ifdef IPFILTER_LOG struct ipslog ipsl; - void *items[1]; size_t sizes[1]; + void *items[1]; int types[1]; + /* + * Copy information out of the ipstate_t structure and into the + * structure used for logging. + */ ipsl.isl_type = type; - ipsl.isl_pkts = is->is_pkts; - ipsl.isl_bytes = is->is_bytes; + ipsl.isl_pkts[0] = is->is_pkts[0] + is->is_icmppkts[0]; + ipsl.isl_bytes[0] = is->is_bytes[0]; + ipsl.isl_pkts[1] = is->is_pkts[1] + is->is_icmppkts[1]; + ipsl.isl_bytes[1] = is->is_bytes[1]; + ipsl.isl_pkts[2] = is->is_pkts[2] + is->is_icmppkts[2]; + ipsl.isl_bytes[2] = is->is_bytes[2]; + ipsl.isl_pkts[3] = is->is_pkts[3] + is->is_icmppkts[3]; + ipsl.isl_bytes[3] = is->is_bytes[3]; ipsl.isl_src = is->is_src; ipsl.isl_dst = is->is_dst; ipsl.isl_p = is->is_p; ipsl.isl_v = is->is_v; ipsl.isl_flags = is->is_flags; + ipsl.isl_tag = is->is_tag; ipsl.isl_rulen = is->is_rulen; - ipsl.isl_group = is->is_group; + (void) strncpy(ipsl.isl_group, is->is_group, FR_GROUPLEN); + if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) { ipsl.isl_sport = is->is_sport; ipsl.isl_dport = is->is_dport; @@ -2063,38 +3219,52 @@ u_int type; ipsl.isl_state[1] = is->is_state[1]; } } else if (ipsl.isl_p == IPPROTO_ICMP) { - ipsl.isl_itype = is->is_icmp.ics_type; + ipsl.isl_itype = is->is_icmp.ici_type; } else if (ipsl.isl_p == IPPROTO_ICMPV6) { - ipsl.isl_itype = is->is_icmp.ics_type; + ipsl.isl_itype = is->is_icmp.ici_type; } else { ipsl.isl_ps.isl_filler[0] = 0; ipsl.isl_ps.isl_filler[1] = 0; } + items[0] = &ipsl; sizes[0] = sizeof(ipsl); types[0] = 0; - (void) ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1); -} + if (ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1)) { + ATOMIC_INCL(ips_stats.iss_logged); + } else { + ATOMIC_INCL(ips_stats.iss_logfail); + } #endif +} #ifdef USE_INET6 -frentry_t *fr_checkicmp6matchingstate(ip, fin) -ip6_t *ip; +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkicmp6matchingstate */ +/* Returns: ipstate_t* - NULL == no match found, */ +/* else pointer to matching state entry */ +/* Parameters: fin(I) - pointer to packet information */ +/* Locks: NULL == no locks, else Read Lock on ipf_state */ +/* */ +/* If we've got an ICMPv6 error message, using the information stored in */ +/* the ICMPv6 packet, look for a matching state table entry. */ +/* ------------------------------------------------------------------------ */ +static ipstate_t *fr_checkicmp6matchingstate(fin) fr_info_t *fin; { - register ipstate_t *is, **isp; - register u_short sport, dport; - register u_char pr; - struct icmp6_hdr *ic, *oic; - union i6addr dst, src; + struct icmp6_hdr *ic6, *oic; + int type, backward, i; + ipstate_t *is, **isp; + u_short sport, dport; + i6addr_t dst, src; u_short savelen; + icmpinfo_t *ic; fr_info_t ofin; tcphdr_t *tcp; - frentry_t *fr; - ip6_t *oip; - int type; + ip6_t *oip6; + u_char pr; u_int hv; /* @@ -2104,8 +3274,9 @@ fr_info_t *fin; */ if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN)) return NULL; - ic = (struct icmp6_hdr *)fin->fin_dp; - type = ic->icmp6_type; + + ic6 = fin->fin_dp; + type = ic6->icmp6_type; /* * If it's not an error type, then return */ @@ -2113,23 +3284,40 @@ fr_info_t *fin; (type != ICMP6_TIME_EXCEEDED) && (type != ICMP6_PARAM_PROB)) return NULL; - oip = (ip6_t *)((char *)ic + ICMPERR_ICMPHLEN); - if (fin->fin_plen < sizeof(*oip)) + oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN); + if (fin->fin_plen < sizeof(*oip6)) return NULL; - if ((oip->ip6_nxt != IPPROTO_TCP) && (oip->ip6_nxt != IPPROTO_UDP) && - (oip->ip6_nxt != IPPROTO_ICMPV6)) - return NULL; - - bzero((char *)&ofin, sizeof(ofin)); - ofin.fin_out = !fin->fin_out; - ofin.fin_ifp = fin->fin_ifp; + bcopy((char *)fin, (char *)&ofin, sizeof(fin)); ofin.fin_v = 6; + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_m = NULL; /* if dereferenced, panic XXX */ + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ - if (oip->ip6_nxt == IPPROTO_ICMPV6) { - oic = (struct icmp6_hdr *)(oip + 1); + /* + * We make a fin entry to be able to feed it to + * matchsrcdst. Note that not all fields are necessary + * but this is the cleanest way. Note further we fill + * in fin_mp such that if someone uses it we'll get + * a kernel panic. fr_matchsrcdst does not use this. + * + * watch out here, as ip is in host order and oip6 in network + * order. Any change we make must be undone afterwards. + */ + savelen = oip6->ip6_plen; + oip6->ip6_plen = fin->fin_dlen - ICMPERR_ICMPHLEN; + ofin.fin_flx = FI_NOCKSUM; + ofin.fin_ip = (ip_t *)oip6; + ofin.fin_plen = oip6->ip6_plen; + (void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin); + ofin.fin_flx &= ~(FI_BAD|FI_SHORT); + oip6->ip6_plen = savelen; + + if (oip6->ip6_nxt == IPPROTO_ICMPV6) { + oic = (struct icmp6_hdr *)(oip6 + 1); /* - * a ICMP error can only be generated as a result of an + * an ICMP error can only be generated as a result of an * ICMP query, not as the response on an ICMP error * * XXX theoretically ICMP_ECHOREP and the other reply's are @@ -2141,78 +3329,71 @@ fr_info_t *fin; /* * perform a lookup of the ICMP packet in the state table */ - hv = (pr = oip->ip6_nxt); - src.in6 = oip->ip6_src; + hv = (pr = oip6->ip6_nxt); + src.in6 = oip6->ip6_src; hv += src.in4.s_addr; - dst.in6 = oip->ip6_dst; + dst.in6 = oip6->ip6_dst; hv += dst.in4.s_addr; hv += oic->icmp6_id; hv += oic->icmp6_seq; - hv %= fr_statesize; - - oip->ip6_plen = ntohs(oip->ip6_plen); - fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); - oip->ip6_plen = htons(oip->ip6_plen); + hv = DOUBLE_HASH(hv); READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + ic = &is->is_icmp; + isp = &is->is_hnext; if ((is->is_p == pr) && - (oic->icmp6_id == is->is_icmp.ics_id) && - (oic->icmp6_seq == is->is_icmp.ics_seq) && - fr_matchsrcdst(is, src, dst, &ofin, NULL)) { + !(is->is_pass & FR_NOICMPERR) && + (oic->icmp6_id == ic->ici_id) && + (oic->icmp6_seq == ic->ici_seq) && + (is = fr_matchsrcdst(&ofin, is, &src, + &dst, NULL))) { /* * in the state table ICMP query's are stored * with the type of the corresponding ICMP * response. Correct here */ - if (((is->is_type == ICMP6_ECHO_REPLY) && + if (((ic->ici_type == ICMP6_ECHO_REPLY) && (oic->icmp6_type == ICMP6_ECHO_REQUEST)) || - (is->is_type - 1 == oic->icmp6_type )) { + (ic->ici_type - 1 == oic->icmp6_type )) { ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += fin->fin_plen; - return is->is_rule; + backward = IP6_NEQ(&is->is_dst, &src); + i = (backward << 1) + fin->fin_out; + is->is_pkts[i]++; + is->is_bytes[i] += fin->fin_plen; + return is; } } + } RWLOCK_EXIT(&ipf_state); - return NULL; } - tcp = (tcphdr_t *)(oip + 1); - dport = tcp->th_dport; - sport = tcp->th_sport; - - hv = (pr = oip->ip6_nxt); - src.in6 = oip->ip6_src; - hv += src.in4.s_addr; + hv = (pr = oip6->ip6_nxt); + src.in6 = oip6->ip6_src; + hv += src.i6[0]; hv += src.i6[1]; hv += src.i6[2]; hv += src.i6[3]; - dst.in6 = oip->ip6_dst; - hv += dst.in4.s_addr; + dst.in6 = oip6->ip6_dst; + hv += dst.i6[0]; hv += dst.i6[1]; hv += dst.i6[2]; hv += dst.i6[3]; - hv += dport; - hv += sport; - hv %= fr_statesize; - /* - * we make an fin entry to be able to feed it to - * matchsrcdst note that not all fields are encessary - * but this is the cleanest way. Note further we fill - * in fin_mp such that if someone uses it we'll get - * a kernel panic. fr_matchsrcdst does not use this. - * - * watch out here, as ip is in host order and oip in network - * order. Any change we make must be undone afterwards. - */ - savelen = oip->ip6_plen; - oip->ip6_plen = ip->ip6_plen - sizeof(*ip) - ICMPERR_ICMPHLEN; - fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); - oip->ip6_plen = savelen; + + if ((oip6->ip6_nxt == IPPROTO_TCP) || (oip6->ip6_nxt == IPPROTO_UDP)) { + tcp = (tcphdr_t *)(oip6 + 1); + dport = tcp->th_dport; + sport = tcp->th_sport; + hv += dport; + hv += sport; + } else + tcp = NULL; + hv = DOUBLE_HASH(hv); + READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { + isp = &is->is_hnext; /* * Only allow this icmp though if the * encapsulated packet was allowed through the @@ -2220,22 +3401,228 @@ fr_info_t *fin; * of info present does not allow for checking against * tcp internals such as seq and ack numbers. */ - if ((is->is_p == pr) && (is->is_v == 6) && - fr_matchsrcdst(is, src, dst, &ofin, tcp)) { - fr = is->is_rule; + if ((is->is_p != pr) || (is->is_v != 6) || + (is->is_pass & FR_NOICMPERR)) + continue; + is = fr_matchsrcdst(&ofin, is, &src, &dst, tcp); + if (is != NULL) { ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += fin->fin_plen; + backward = IP6_NEQ(&is->is_dst, &src); + i = (backward << 1) + fin->fin_out; + is->is_pkts[i]++; + is->is_bytes[i] += fin->fin_plen; /* * we deliberately do not touch the timeouts * for the accompanying state table entry. * It remains to be seen if that is correct. XXX */ - RWLOCK_EXIT(&ipf_state); - return fr; + return is; } } RWLOCK_EXIT(&ipf_state); return NULL; } #endif + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_sttab_init */ +/* Returns: Nil */ +/* Parameters: tqp(I) - pointer to an array of timeout queues for TCP */ +/* */ +/* Initialise the array of timeout queues for TCP. */ +/* ------------------------------------------------------------------------ */ +void fr_sttab_init(tqp) +ipftq_t *tqp; +{ + int i; + + for (i = IPF_TCP_NSTATES - 1; i >= 0; i--) { + tqp[i].ifq_ttl = 0; + tqp[i].ifq_head = NULL; + tqp[i].ifq_tail = &tqp[i].ifq_head; + tqp[i].ifq_next = tqp + i + 1; + MUTEX_INIT(&tqp[i].ifq_lock, "ipftq tcp tab"); + } + tqp[IPF_TCP_NSTATES - 1].ifq_next = NULL; + tqp[IPF_TCPS_CLOSED].ifq_ttl = fr_tcpclosed; + tqp[IPF_TCPS_LISTEN].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_SYN_SENT].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_SYN_RECEIVED].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_ESTABLISHED].ifq_ttl = fr_tcpidletimeout; + tqp[IPF_TCPS_CLOSE_WAIT].ifq_ttl = fr_tcphalfclosed; + tqp[IPF_TCPS_FIN_WAIT_1].ifq_ttl = fr_tcphalfclosed; + tqp[IPF_TCPS_CLOSING].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_LAST_ACK].ifq_ttl = fr_tcplastack; + tqp[IPF_TCPS_FIN_WAIT_2].ifq_ttl = fr_tcpclosewait; + tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = fr_tcptimeout; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_sttab_destroy */ +/* Returns: Nil */ +/* Parameters: tqp(I) - pointer to an array of timeout queues for TCP */ +/* */ +/* Do whatever is necessary to "destroy" each of the entries in the array */ +/* of timeout queues for TCP. */ +/* ------------------------------------------------------------------------ */ +void fr_sttab_destroy(tqp) +ipftq_t *tqp; +{ + int i; + + for (i = IPF_TCP_NSTATES - 1; i >= 0; i--) + MUTEX_DESTROY(&tqp[i].ifq_lock); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_statederef */ +/* Returns: Nil */ +/* Parameters: isp(I) - pointer to pointer to state table entry */ +/* */ +/* Decrement the reference counter for this state table entry and free it */ +/* if there are no more things using it. */ +/* */ +/* When operating in userland (ipftest), we have no timers to clear a state */ +/* entry. Therefore, we make a few simple tests before deleting an entry */ +/* outright. We compare states on each side looking for a combination of */ +/* TIME_WAIT (should really be FIN_WAIT_2?) and LAST_ACK. Then we factor */ +/* in packet direction with the interface list to make sure we don't */ +/* prematurely delete an entry on a final inbound packet that's we're also */ +/* supposed to route elsewhere. */ +/* */ +/* Internal parameters: */ +/* state[0] = state of source (host that initiated connection) */ +/* state[1] = state of dest (host that accepted the connection) */ +/* */ +/* dir == 0 : a packet from source to dest */ +/* dir == 1 : a packet from dest to source */ +/* ------------------------------------------------------------------------ */ +void fr_statederef(fin, isp) +fr_info_t *fin; +ipstate_t **isp; +{ + ipstate_t *is = *isp; +#if 0 + int nstate, ostate, dir, eol; + + eol = 0; /* End-of-the-line flag. */ + dir = fin->fin_rev; + ostate = is->is_state[1 - dir]; + nstate = is->is_state[dir]; + /* + * Determine whether this packet is local or routed. State entries + * with us as the destination will have an interface list of + * int1,-,-,int1. Entries with us as the origin run as -,int1,int1,-. + */ + if ((fin->fin_p == IPPROTO_TCP) && (fin->fin_out == 0)) { + if ((strcmp(is->is_ifname[0], is->is_ifname[3]) == 0) && + (strcmp(is->is_ifname[1], is->is_ifname[2]) == 0)) { + if ((dir == 0) && + (strcmp(is->is_ifname[1], "-") == 0) && + (strcmp(is->is_ifname[0], "-") != 0)) { + eol = 1; + } else if ((dir == 1) && + (strcmp(is->is_ifname[0], "-") == 0) && + (strcmp(is->is_ifname[1], "-") != 0)) { + eol = 1; + } + } + } +#endif + + fin = fin; /* LINT */ + is = *isp; + *isp = NULL; + MUTEX_ENTER(&is->is_lock); + is->is_ref--; + if (is->is_ref == 0) { + MUTEX_EXIT(&is->is_lock); + WRITE_ENTER(&ipf_state); + fr_delstate(is, ISL_EXPIRE); + RWLOCK_EXIT(&ipf_state); +#ifndef _KERNEL +#if 0 + } else if (((fin->fin_out == 1) || (eol == 1)) && + ((ostate == IPF_TCPS_LAST_ACK) && + (nstate == IPF_TCPS_TIME_WAIT))) { +#else + } else if ((is->is_sti.tqe_state[0] > IPF_TCPS_ESTABLISHED) || + (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) { +#endif + MUTEX_EXIT(&is->is_lock); + WRITE_ENTER(&ipf_state); + fr_delstate(is, ISL_ORPHAN); + RWLOCK_EXIT(&ipf_state); +#endif + } else { + MUTEX_EXIT(&is->is_lock); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_setstatequeue */ +/* Returns: Nil */ +/* Parameters: is(I) - pointer to state structure */ +/* rev(I) - forward(0) or reverse(1) direction */ +/* Locks: ipf_state (read or write) */ +/* */ +/* Put the state entry on its default queue entry, using rev as a helped in */ +/* determining which queue it should be placed on. */ +/* ------------------------------------------------------------------------ */ +void fr_setstatequeue(is, rev) +ipstate_t *is; +int rev; +{ + ipftq_t *oifq, *nifq; + + + if ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) + nifq = is->is_tqehead[rev]; + else + nifq = NULL; + + if (nifq == NULL) { + switch (is->is_p) + { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + if (rev == 1) + nifq = &ips_icmpacktq; + else + nifq = &ips_icmptq; + break; +#endif + case IPPROTO_ICMP : + if (rev == 1) + nifq = &ips_icmpacktq; + else + nifq = &ips_icmptq; + break; + case IPPROTO_TCP : + nifq = ips_tqtqb + is->is_state[rev]; + break; + default : + if (rev == 1) + nifq = &ips_udpacktq; + else + nifq = &ips_udptq; + break; + } + } + + oifq = is->is_sti.tqe_ifq; + /* + * If it's currently on a timeout queue, move it from one queue to + * another, else put it on the end of the newly determined queue. + */ + if (oifq != NULL) + fr_movequeue(&is->is_sti, oifq, nifq); + else + fr_queueappend(&is->is_sti, nifq, is); + return; +} diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h index 740ac92d3625..d08deaa2ba58 100644 --- a/sys/netinet/ip_state.h +++ b/sys/netinet/ip_state.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip_state.h,v 1.23 2002/09/19 08:09:20 martti Exp $ */ +/* $NetBSD: ip_state.h,v 1.24 2004/03/28 09:00:57 martti Exp $ */ /* * Copyright (C) 1995-2001 by Darren Reed. @@ -6,17 +6,19 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * Id: ip_state.h,v 2.13.2.13 2002/06/27 14:40:29 darrenr Exp + * Id: ip_state.h,v 2.68 2003/09/24 16:04:58 darrenr Exp */ #ifndef _NETINET_IP_STATE_H_ #define _NETINET_IP_STATE_H_ #if defined(__STDC__) || defined(__GNUC__) -# define SIOCDELST _IOW('r', 61, struct ipstate *) +# define SIOCDELST _IOW('r', 61, struct ipfobj) #else -# define SIOCDELST _IOW(r, 61, struct ipstate *) +# define SIOCDELST _IOW(r, 61, struct ipfobj) #endif +struct ipscan; + #ifndef IPSTATE_SIZE # define IPSTATE_SIZE 5737 #endif @@ -30,53 +32,34 @@ (s2).s_addr, (d2).s_addr) -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 tcpdata { - u_32_t td_end; - u_32_t td_maxend; - u_32_t td_maxwin; - u_char td_wscale; -} tcpdata_t; - -typedef struct tcpstate { - u_short ts_sport; - u_short ts_dport; - tcpdata_t ts_data[2]; - u_char ts_state[2]; -} tcpstate_t; - typedef struct ipstate { + ipfmutex_t is_lock; struct ipstate *is_next; struct ipstate **is_pnext; struct ipstate *is_hnext; struct ipstate **is_phnext; struct ipstate **is_me; + void *is_ifp[4]; + void *is_sync; + struct nat *is_nat[2]; frentry_t *is_rule; - U_QUAD_T is_pkts; - U_QUAD_T is_bytes; - union i6addr is_src; - union i6addr is_dst; - void *is_ifp[4]; - u_long is_age; - u_int is_frage[2]; /* age from filter rule, forward & reverse */ + struct ipftq *is_tqehead[2]; + struct ipscan *is_isc; + U_QUAD_T is_pkts[4]; + U_QUAD_T is_bytes[4]; + U_QUAD_T is_icmppkts[4]; + struct ipftqent is_sti; + u_int is_frage[2]; + int is_ref; /* reference count */ + int is_isninc[2]; + u_short is_sumd[2]; + i6addr_t is_src; + i6addr_t is_dst; u_int is_pass; u_char is_p; /* Protocol */ - u_char is_v; /* IP version */ - u_char is_fsm; /* 1 = following FSM, 0 = not */ - u_char is_xxx; /* pad */ - u_int is_hv; /* hash value for this in the table */ - u_32_t is_rulen; /* rule number */ - u_32_t is_flags; /* flags for this structure */ + u_char is_v; + u_32_t is_hv; + u_32_t is_tag; u_32_t is_opt; /* packet options set */ u_32_t is_optmsk; /* " " mask */ u_short is_sec; /* security options set */ @@ -84,37 +67,72 @@ typedef struct ipstate { u_short is_auth; /* authentication options set */ u_short is_authmsk; /* " " mask */ union { - icmpstate_t is_ics; - tcpstate_t is_ts; - udpstate_t is_us; + icmpinfo_t is_ics; + tcpinfo_t is_ts; + udpinfo_t is_us; + greinfo_t is_ug; } is_ps; - u_32_t is_group; - char is_ifname[4][IFNAMSIZ]; -#if SOLARIS || defined(__sgi) - kmutex_t is_lock; -#endif + u_32_t is_flags; + int is_flx[2][2]; + u_32_t is_rulen; /* rule number when created */ + u_32_t is_s0[2]; + u_short is_smsk[2]; + char is_group[FR_GROUPLEN]; + char is_sbuf[2][16]; + char is_ifname[4][LIFNAMSIZ]; } ipstate_t; +#define is_die is_sti.tqe_die +#define is_state is_sti.tqe_state +#define is_touched is_sti.tqe_touched #define is_saddr is_src.in4.s_addr #define is_daddr is_dst.in4.s_addr #define is_icmp is_ps.is_ics -#define is_type is_icmp.ics_type -#define is_code is_icmp.ics_code +#define is_type is_icmp.ici_type +#define is_code is_icmp.ici_code #define is_tcp is_ps.is_ts #define is_udp is_ps.is_us #define is_send is_tcp.ts_data[0].td_end #define is_dend is_tcp.ts_data[1].td_end #define is_maxswin is_tcp.ts_data[0].td_maxwin #define is_maxdwin is_tcp.ts_data[1].td_maxwin -#define is_swscale is_tcp.ts_data[0].td_wscale -#define is_dwscale is_tcp.ts_data[1].td_wscale #define is_maxsend is_tcp.ts_data[0].td_maxend #define is_maxdend is_tcp.ts_data[1].td_maxend +#define is_swinscale is_tcp.ts_data[0].td_winscale +#define is_dwinscale is_tcp.ts_data[1].td_winscale +#define is_swinflags is_tcp.ts_data[0].td_winflags +#define is_dwinflags is_tcp.ts_data[1].td_winflags #define is_sport is_tcp.ts_sport #define is_dport is_tcp.ts_dport -#define is_state is_tcp.ts_state #define is_ifpin is_ifp[0] #define is_ifpout is_ifp[2] +#define is_gre is_ps.is_ug + +#define IS_WSPORT SI_W_SPORT /* 0x00100 */ +#define IS_WDPORT SI_W_DPORT /* 0x00200 */ +#define IS_WSADDR SI_W_SADDR /* 0x00400 */ +#define IS_WDADDR SI_W_DADDR /* 0x00800 */ +#define IS_NEWFR SI_NEWFR /* 0x01000 */ +#define IS_CLONE SI_CLONE /* 0x02000 */ +#define IS_CLONED SI_CLONED /* 0x04000 */ +#define IS_TCPFSM 0x10000 +#define IS_STRICT 0x20000 +#define IS_ISNSYN 0x40000 +#define IS_ISNACK 0x80000 +/* + * IS_SC flags are for scan-operations that need to be recognised in state. + */ +#define IS_SC_CLIENT 0x10000000 +#define IS_SC_SERVER 0x20000000 +#define IS_SC_MATCHC 0x40000000 +#define IS_SC_MATCHS 0x80000000 +#define IS_SC_MATCHALL (IS_SC_MATCHC|IS_SC_MATCHC) +#define IS_SC_ALL (IS_SC_MATCHC|IS_SC_MATCHC|IS_SC_CLIENT|IS_SC_SERVER) + +/* + * Flags that can be passed into fr_addstate + */ +#define IS_INHERITED 0x0fffff00 #define TH_OPENING (TH_SYN|TH_ACK) /* @@ -124,6 +142,8 @@ typedef struct ipstate { * Bits 4 - 7 are set from the initial packet and contain what the packet * anded with bits 0-3 must match. * Bits 8,9 are used to indicate wildcard source/destination port matching. + * Bits 10,11 are reserved for other wildcard flag compatibility. + * Bits 12,13 are for scaning. */ typedef struct ipstate_save { @@ -136,10 +156,11 @@ typedef struct ipstate_save { typedef struct ipslog { - U_QUAD_T isl_pkts; - U_QUAD_T isl_bytes; - union i6addr isl_src; - union i6addr isl_dst; + U_QUAD_T isl_pkts[4]; + U_QUAD_T isl_bytes[4]; + i6addr_t isl_src; + i6addr_t isl_dst; + u_32_t isl_tag; u_short isl_type; union { u_short isl_filler[2]; @@ -151,23 +172,28 @@ typedef struct ipslog { u_char isl_flags; u_char isl_state[2]; u_32_t isl_rulen; - u_32_t isl_group; + char isl_group[FR_GROUPLEN]; } ipslog_t; #define isl_sport isl_ps.isl_ports[0] #define isl_dport isl_ps.isl_ports[1] #define isl_itype isl_ps.isl_icmp -#define ISL_NEW 0 -#define ISL_EXPIRE 0xffff -#define ISL_FLUSH 0xfffe -#define ISL_REMOVE 0xfffd +#define ISL_NEW 0 +#define ISL_CLONE 1 +#define ISL_EXPIRE 0xffff +#define ISL_FLUSH 0xfffe +#define ISL_REMOVE 0xfffd +#define ISL_INTERMEDIATE 0xfffc +#define ISL_KILLED 0xfffb +#define ISL_ORPHAN 0xfffa typedef struct ips_stat { u_long iss_hits; u_long iss_miss; u_long iss_max; + u_long iss_maxref; u_long iss_tcp; u_long iss_udp; u_long iss_icmp; @@ -178,8 +204,15 @@ typedef struct ips_stat { u_long iss_logged; u_long iss_logfail; u_long iss_inuse; + u_long iss_wild; + u_long iss_killed; + u_long iss_ticks; + u_long iss_bucketfull; + int iss_statesize; + int iss_statemax; ipstate_t **iss_table; ipstate_t *iss_list; + u_long *iss_bucketlen; } ips_stat_t; @@ -193,21 +226,33 @@ extern u_long fr_udptimeout; extern u_long fr_udpacktimeout; extern u_long fr_icmptimeout; extern u_long fr_icmpacktimeout; -extern ipstate_t *ips_list; +extern int fr_statemax; +extern int fr_statesize; extern int fr_state_lock; +extern int fr_state_maxbucket; +extern int fr_state_maxbucket_reset; +extern ipstate_t *ips_list; +extern ipftq_t *ips_utqe; +extern ipftq_t ips_tqtqb[IPF_TCP_NSTATES]; + extern int fr_stateinit __P((void)); -extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *)); -extern ipstate_t *fr_addstate __P((ip_t *, fr_info_t *, ipstate_t **, u_int)); -extern frentry_t *fr_checkstate __P((ip_t *, fr_info_t *)); -extern void ip_statesync __P((void *)); +extern ipstate_t *fr_addstate __P((fr_info_t *, ipstate_t **, u_int)); +extern frentry_t *fr_checkstate __P((struct fr_info *, u_32_t *)); +extern ipstate_t *fr_stlookup __P((fr_info_t *, tcphdr_t *, ipftq_t **)); +extern void fr_statesync __P((void *)); extern void fr_timeoutstate __P((void)); -extern int fr_tcp_age __P((u_long *, u_char *, fr_info_t *, int, int)); +extern int fr_tcp_age __P((struct ipftqent *, struct fr_info *, + struct ipftq *, int)); +extern int fr_tcpinwindow __P((struct fr_info *, struct tcpdata *, + struct tcpdata *, struct tcphdr *, int)); extern void fr_stateunload __P((void)); extern void ipstate_log __P((struct ipstate *, u_int)); -#if defined(__NetBSD__) || defined(__OpenBSD__) -extern int fr_state_ioctl __P((caddr_t, u_long, int)); -#else -extern int fr_state_ioctl __P((caddr_t, int, int)); -#endif +extern int fr_state_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern void fr_stinsert __P((struct ipstate *, int)); +extern void fr_sttab_init __P((struct ipftq *)); +extern void fr_sttab_destroy __P((struct ipftq *)); +extern void fr_updatestate __P((fr_info_t *, ipstate_t *, ipftq_t *)); +extern void fr_statederef __P((fr_info_t *, ipstate_t **)); +extern void fr_setstatequeue __P((ipstate_t *, int)); #endif /* _NETINET_IP_STATE_H_ */ diff --git a/sys/netinet/ipl.h b/sys/netinet/ipl.h index 8de4ce2dc90c..07bacff1cb34 100644 --- a/sys/netinet/ipl.h +++ b/sys/netinet/ipl.h @@ -1,17 +1,19 @@ -/* $NetBSD: ipl.h,v 1.14 2002/09/19 08:09:20 martti Exp $ */ +/* $NetBSD: ipl.h,v 1.15 2004/03/28 09:00:57 martti Exp $ */ /* - * Copyright (C) 1993-2002 by Darren Reed. + * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ipl.h 1.21 6/5/96 - * Id: ipl.h,v 2.15.2.35 2002/08/28 13:00:50 darrenr Exp + * Id: ipl.h,v 2.52.2.2 2004/03/22 12:28:21 darrenr Exp */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.29" +#define IPL_VERSION "IP Filter: v4.1.1" + +#define IPFILTER_VERSION 4010100 #endif