2 * Copyright (c) 2016 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@dragonflybsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/param.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/sysctl.h>
43 #include <arpa/inet.h>
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #include <netinet/ip_icmp.h>
65 #include <netinet/tcp.h>
67 #include <net/if_dl.h>
68 #include <net/route.h>
69 #include <net/ethernet.h>
71 #include "../../sys/net/ipfw3/ip_fw3.h"
72 #include "../../sys/net/ipfw3/ip_fw3_table.h"
73 #include "../../sys/net/ipfw3/ip_fw3_sync.h"
74 #include "../../sys/net/dummynet3/ip_dummynet3.h"
75 #include "../../sys/net/libalias/alias.h"
76 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
77 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
87 struct char_int_map nat_params[] = {
91 { "deny_in", TOK_DENY_INC },
92 { "same_ports", TOK_SAME_PORTS },
93 { "unreg_only", TOK_UNREG_ONLY },
94 { "reset", TOK_RESET_ADDR },
95 { "reverse", TOK_ALIAS_REV },
96 { "proxy_only", TOK_PROXY_ONLY },
97 { "redirect_addr", TOK_REDIR_ADDR },
98 { "redirect_port", TOK_REDIR_PORT },
99 { "redirect_proto", TOK_REDIR_PROTO },
105 nat_config(int ac, char **av)
107 struct cfg_nat *n; /* Nat instance configuration. */
108 int i, len, off, tok;
109 char *id, buf[NAT_BUF_LEN]; /* Buffer for serialized data. */
112 /* Offset in buf: save space for n at the beginning. */
113 off = sizeof(struct cfg_nat);
114 memset(buf, 0, sizeof(buf));
115 n = (struct cfg_nat *)buf;
119 if (ac && isdigit(**av)) {
125 errx(EX_DATAERR, "missing nat id");
127 errx(EX_DATAERR, "missing option");
130 tok = match_token(nat_params, *av);
135 errx(EX_DATAERR, "missing option");
136 if (!inet_aton(av[0], &(n->ip)))
137 errx(EX_DATAERR, "bad ip addr `%s'", av[0]);
142 errx(EX_DATAERR, "missing option");
143 set_addr_dynamic(av[0], n);
147 n->mode |= PKT_ALIAS_LOG;
150 n->mode |= PKT_ALIAS_DENY_INCOMING;
153 n->mode |= PKT_ALIAS_SAME_PORTS;
156 n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
159 n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
162 n->mode |= PKT_ALIAS_REVERSE;
165 n->mode |= PKT_ALIAS_PROXY_ONLY;
168 * All the setup_redir_* functions work
169 * directly in the final
170 * buffer, see above for details.
174 case TOK_REDIR_PROTO:
177 i = setup_redir_addr(&buf[off], len, &ac, &av);
180 i = setup_redir_port(&buf[off], len, &ac, &av);
182 case TOK_REDIR_PROTO:
183 i = setup_redir_proto(&buf[off], len, &ac, &av);
191 errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
194 i = do_set_x(IP_FW_NAT_ADD, buf, off);
196 err(1, "do_set_x(%s)", "IP_FW_NAT_ADD");
199 /* After every modification, we show the resultant rule. */
201 char *_av[] = {"config", id};
206 nat_show_config(char *buf)
212 int i, cnt, flag, off;
214 n = (struct cfg_nat *)buf;
217 printf("ipfw3 nat %u config", n->id);
218 if (strlen(n->if_name) != 0)
219 printf(" if %s", n->if_name);
220 else if (n->ip.s_addr != 0)
221 printf(" ip %s", inet_ntoa(n->ip));
222 while (n->mode != 0) {
223 if (n->mode & PKT_ALIAS_LOG) {
225 n->mode &= ~PKT_ALIAS_LOG;
226 } else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
228 n->mode &= ~PKT_ALIAS_DENY_INCOMING;
229 } else if (n->mode & PKT_ALIAS_SAME_PORTS) {
230 printf(" same_ports");
231 n->mode &= ~PKT_ALIAS_SAME_PORTS;
232 } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
233 printf(" unreg_only");
234 n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
235 } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
237 n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
238 } else if (n->mode & PKT_ALIAS_REVERSE) {
240 n->mode &= ~PKT_ALIAS_REVERSE;
241 } else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
242 printf(" proxy_only");
243 n->mode &= ~PKT_ALIAS_PROXY_ONLY;
247 /* Print all the redirect's data configuration. */
248 for (cnt = 0; cnt < n->redir_cnt; cnt++) {
249 t = (struct cfg_redir *)&buf[off];
253 printf(" redirect_addr");
254 if (t->spool_cnt == 0) {
255 printf(" %s", inet_ntoa(t->laddr));
257 for (i = 0; i < t->spool_cnt; i++) {
258 s = (struct cfg_spool *)&buf[off];
263 printf("%s", inet_ntoa(s->addr));
267 printf(" %s", inet_ntoa(t->paddr));
270 p = getprotobynumber(t->proto);
271 printf(" redirect_port %s ", p->p_name);
273 printf("%s:%u", inet_ntoa(t->laddr), t->lport);
274 if (t->pport_cnt > 1) {
275 printf("-%u", t->lport +
279 for (i=0; i < t->spool_cnt; i++) {
280 s = (struct cfg_spool *)&buf[off];
284 printf("%s:%u", inet_ntoa(s->addr),
290 if (t->paddr.s_addr) {
291 printf("%s:", inet_ntoa(t->paddr));
293 printf("%u", t->pport);
294 if (!t->spool_cnt && t->pport_cnt > 1) {
295 printf("-%u", t->pport + t->pport_cnt - 1);
298 if (t->raddr.s_addr) {
299 printf(" %s", inet_ntoa(t->raddr));
301 printf(":%u", t->rport);
302 if (!t->spool_cnt && t->rport_cnt > 1) {
303 printf("-%u", t->rport +
310 p = getprotobynumber(t->proto);
311 printf(" redirect_proto %s %s", p->p_name,
312 inet_ntoa(t->laddr));
313 if (t->paddr.s_addr != 0) {
314 printf(" %s", inet_ntoa(t->paddr));
315 if (t->raddr.s_addr) {
316 printf(" %s", inet_ntoa(t->raddr));
321 errx(EX_DATAERR, "unknown redir mode");
330 nat_show(int ac, char **av)
334 int i, nbytes, nalloc, size;
335 int nat_cnt, redir_cnt, nat_id;
347 nat_id = strtoul(*av, NULL, 10);
350 while (nbytes >= nalloc) {
353 if ((data = realloc(data, nbytes)) == NULL) {
354 err(EX_OSERR, "realloc");
356 if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) {
357 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)");
365 nat_cnt = *((int *)data);
366 for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
367 n = (struct cfg_nat *)&data[i];
368 if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) {
369 if (nat_id == 0 || n->id == nat_id)
370 nat_show_config(&data[i]);
372 i += sizeof(struct cfg_nat);
373 for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
374 e = (struct cfg_redir *)&data[i];
375 i += sizeof(struct cfg_redir) +
376 e->spool_cnt * sizeof(struct cfg_spool);
382 setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av)
384 char **av, *sep, *protoName;
385 char tmp_spool_buf[NAT_BUF_LEN];
386 int ac, space, lsnat;
388 struct cfg_spool *tmp;
389 u_short numLocalPorts;
390 port_range portRange;
398 if (len >= SOF_REDIR) {
399 r = (struct cfg_redir *)spool_buf;
400 /* Skip cfg_redir at beginning of buf. */
401 spool_buf = &spool_buf[SOF_REDIR];
408 r->mode = REDIR_PORT;
413 errx (EX_DATAERR, "redirect_port: missing protocol");
415 r->proto = str2proto(*av);
420 * Extract local address.
423 errx (EX_DATAERR, "redirect_port: missing local address");
425 sep = strchr(*av, ',');
426 /* LSNAT redirection syntax. */
428 r->laddr.s_addr = INADDR_NONE;
431 /* Preserve av, copy spool servers to tmp_spool_buf. */
432 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
435 if (str2addr_portrange (*av, &r->laddr,
436 protoName, &portRange) != 0)
437 errx(EX_DATAERR, "redirect_port:"
438 "invalid local port range");
440 r->lport = GETLOPORT(portRange);
441 numLocalPorts = GETNUMPORTS(portRange);
446 * Extract public port and optionally address.
449 errx (EX_DATAERR, "redirect_port: missing public port");
451 sep = strchr (*av, ':');
453 if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0)
454 errx(EX_DATAERR, "redirect_port:"
455 "invalid public port range");
457 r->paddr.s_addr = INADDR_ANY;
458 if (str2portrange(*av, protoName, &portRange) != 0)
459 errx(EX_DATAERR, "redirect_port:"
460 "invalid public port range");
463 r->pport = GETLOPORT(portRange);
464 r->pport_cnt = GETNUMPORTS(portRange);
468 * Extract remote address and optionally port.
471 * NB: isalpha(**av) => we've to check that next parameter is really an
472 * option for this redirect entry, else stop here processing arg[cv].
474 if (ac != 0 && !isalpha(**av)) {
475 sep = strchr (*av, ':');
477 if (str2addr_portrange (*av, &r->raddr,
478 protoName, &portRange) != 0) {
479 errx(EX_DATAERR, "redirect_port:"
480 "invalid remote port range");
483 SETLOPORT(portRange, 0);
484 SETNUMPORTS(portRange, 1);
485 str2addr (*av, &r->raddr);
489 SETLOPORT(portRange, 0);
490 SETNUMPORTS(portRange, 1);
491 r->raddr.s_addr = INADDR_ANY;
493 r->rport = GETLOPORT(portRange);
494 r->rport_cnt = GETNUMPORTS(portRange);
497 * Make sure port ranges match up, then add the redirect ports.
499 if (numLocalPorts != r->pport_cnt) {
500 errx(EX_DATAERR, "redirect_port:"
501 "port ranges must be equal in size");
504 /* Remote port range is allowed to be '0' which means all ports. */
505 if (r->rport_cnt != numLocalPorts &&
506 (r->rport_cnt != 1 || r->rport != 0)) {
507 errx(EX_DATAERR, "redirect_port: remote port must"
508 "be 0 or equal to local port range in size");
512 * Setup LSNAT server pool.
515 sep = strtok(tmp_spool_buf, ", ");
516 while (sep != NULL) {
517 tmp = (struct cfg_spool *)spool_buf;
523 if (str2addr_portrange(sep,
524 &tmp->addr, protoName, &portRange) != 0)
525 errx(EX_DATAERR, "redirect_port:"
526 "invalid local port range");
527 if (GETNUMPORTS(portRange) != 1)
528 errx(EX_DATAERR, "redirect_port: local port"
529 "must be single in this context");
530 tmp->port = GETLOPORT(portRange);
532 /* Point to the next possible cfg_spool. */
533 spool_buf = &spool_buf[SOF_SPOOL];
534 sep = strtok(NULL, ", ");
540 errx(EX_DATAERR, "redirect_port: buf is too small\n");
544 setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av)
546 struct protoent *protoent;
554 if (len >= SOF_REDIR) {
555 r = (struct cfg_redir *)spool_buf;
556 /* Skip cfg_redir at beginning of buf. */
557 spool_buf = &spool_buf[SOF_REDIR];
563 r->mode = REDIR_PROTO;
568 errx(EX_DATAERR, "redirect_proto: missing protocol");
570 protoent = getprotobyname(*av);
571 if (protoent == NULL)
572 errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av);
574 r->proto = protoent->p_proto;
579 * Extract local address.
582 errx(EX_DATAERR, "redirect_proto: missing local address");
584 str2addr(*av, &r->laddr);
588 * Extract optional public address.
591 r->paddr.s_addr = INADDR_ANY;
592 r->raddr.s_addr = INADDR_ANY;
594 /* see above in setup_redir_port() */
595 if (!isalpha(**av)) {
596 str2addr(*av, &r->paddr);
600 * Extract optional remote address.
602 /* see above in setup_redir_port() */
603 if (ac != 0 && !isalpha(**av)) {
604 str2addr(*av, &r->raddr);
612 errx(EX_DATAERR, "redirect_proto: buf is too small\n");
616 str2proto(const char* str)
618 if (!strcmp (str, "tcp"))
620 if (!strcmp (str, "udp"))
622 errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str);
626 str2addr_portrange (const char* str, struct in_addr* addr,
627 char* proto, port_range *portRange)
631 ptr = strchr (str, ':');
633 errx (EX_DATAERR, "%s is missing port number", str);
638 str2addr (str, addr);
639 return str2portrange (ptr, proto, portRange);
643 * Search for interface with name "ifn", and fill n accordingly:
645 * n->ip ip address of interface "ifn"
646 * n->if_name copy of interface name "ifn"
649 set_addr_dynamic(const char *ifn, struct cfg_nat *n)
651 struct if_msghdr *ifm;
652 struct ifa_msghdr *ifam;
653 struct sockaddr_dl *sdl;
654 struct sockaddr_in *sin;
655 char *buf, *lim, *next;
664 mib[4] = NET_RT_IFLIST;
668 * Get interface data.
670 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
671 err(1, "iflist-sysctl-estimate");
672 if ((buf = malloc(needed)) == NULL)
673 errx(1, "malloc failed");
674 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
675 err(1, "iflist-sysctl-get");
678 * Loop through interfaces until one with
679 * given name is found. This is done to
680 * find correct interface index for routing
681 * message processing.
686 ifm = (struct if_msghdr *)next;
687 next += ifm->ifm_msglen;
688 if (ifm->ifm_version != RTM_VERSION) {
690 warnx("routing message version %d "
691 "not understood", ifm->ifm_version);
694 if (ifm->ifm_type == RTM_IFINFO) {
695 sdl = (struct sockaddr_dl *)(ifm + 1);
696 if (strlen(ifn) == sdl->sdl_nlen &&
697 strncmp(ifn, sdl->sdl_data,
698 sdl->sdl_nlen) == 0) {
699 ifIndex = ifm->ifm_index;
700 ifMTU = ifm->ifm_data.ifi_mtu;
706 errx(1, "unknown interface name %s", ifn);
708 * Get interface address.
712 ifam = (struct ifa_msghdr *)next;
713 next += ifam->ifam_msglen;
714 if (ifam->ifam_version != RTM_VERSION) {
716 warnx("routing message version %d "
717 "not understood", ifam->ifam_version);
720 if (ifam->ifam_type != RTM_NEWADDR)
722 if (ifam->ifam_addrs & RTA_IFA) {
724 char *cp = (char *)(ifam + 1);
726 for (i = 1; i < RTA_IFA; i <<= 1) {
727 if (ifam->ifam_addrs & i)
728 cp += SA_SIZE((struct sockaddr *)cp);
730 if (((struct sockaddr *)cp)->sa_family == AF_INET) {
731 sin = (struct sockaddr_in *)cp;
737 errx(1, "%s: cannot get interface address", ifn);
739 n->ip = sin->sin_addr;
740 strncpy(n->if_name, ifn, IF_NAMESIZE);
746 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av)
749 struct cfg_spool *tmp;
751 char tmp_spool_buf[NAT_BUF_LEN];
752 int ac, i, space, lsnat;
759 if (len >= SOF_REDIR) {
760 r = (struct cfg_redir *)spool_buf;
761 /* Skip cfg_redir at beginning of buf. */
762 spool_buf = &spool_buf[SOF_REDIR];
769 r->mode = REDIR_ADDR;
770 /* Extract local address. */
772 errx(EX_DATAERR, "redirect_addr: missing local address");
774 sep = strchr(*av, ',');
775 if (sep) { /* LSNAT redirection syntax. */
776 r->laddr.s_addr = INADDR_NONE;
777 /* Preserve av, copy spool servers to tmp_spool_buf. */
778 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
781 str2addr(*av, &r->laddr);
785 /* Extract public address. */
787 errx(EX_DATAERR, "redirect_addr: missing public address");
789 str2addr(*av, &r->paddr);
792 /* Setup LSNAT server pool. */
794 sep = strtok(tmp_spool_buf, ", ");
795 while (sep != NULL) {
796 tmp = (struct cfg_spool *)spool_buf;
802 str2addr(sep, &tmp->addr);
805 /* Point to the next possible cfg_spool. */
806 spool_buf = &spool_buf[SOF_SPOOL];
807 sep = strtok(NULL, ", ");
813 errx(EX_DATAERR, "redirect_addr: buf is too small\n");
817 str2addr(const char* str, struct in_addr* addr)
821 if (inet_aton (str, addr))
824 hp = gethostbyname (str);
826 errx (1, "unknown host %s", str);
828 memcpy (addr, hp->h_addr, sizeof (struct in_addr));
832 str2portrange(const char* str, const char* proto, port_range *portRange)
837 u_short loPort, hiPort;
839 /* First see if this is a service, return corresponding port if so. */
840 sp = getservbyname (str, proto);
842 SETLOPORT(*portRange, ntohs(sp->s_port));
843 SETNUMPORTS(*portRange, 1);
847 /* Not a service, see if it's a single port or port range. */
848 sep = strchr (str, '-');
850 SETLOPORT(*portRange, strtol(str, &end, 10));
853 SETNUMPORTS(*portRange, 1);
857 /* Error in port range field. */
858 errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
861 /* Port range, get the values and sanity check. */
862 sscanf (str, "%hu-%hu", &loPort, &hiPort);
863 SETLOPORT(*portRange, loPort);
864 SETNUMPORTS(*portRange, 0); /* Error by default */
865 if (loPort <= hiPort)
866 SETNUMPORTS(*portRange, hiPort - loPort + 1);
868 if (GETNUMPORTS(*portRange) == 0)
869 errx (EX_DATAERR, "invalid port range %s", str);
875 nat_delete_config(int ac, char *av[])
882 if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1)
883 errx(EX_USAGE, "NAT %d in use or not exists", i);
887 nat_show_state(int ac, char **av)
900 nat_id = strtoul(*av, NULL, 10);
903 while (nbytes >= nalloc) {
906 if ((data = realloc(data, nbytes)) == NULL) {
907 err(EX_OSERR, "realloc");
909 memcpy(data, &nat_id, sizeof(int));
910 if (do_get_x(IP_FW_NAT_GET_RECORD, data, &nbytes) < 0) {
911 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_RECORD)");
916 struct ipfw_ioc_nat_state *nat_state;
917 nat_state =(struct ipfw_ioc_nat_state *)data;
918 int count = nbytes / sizeof( struct ipfw_ioc_nat_state);
920 uptime_sec = get_kern_boottime();
921 for (i = 0; i < count; i ++) {
922 printf("#%d ", nat_state->cpuid);
923 printf("%s:%hu => ",inet_ntoa(nat_state->src_addr),
924 htons(nat_state->src_port));
925 printf("%s:%hu",inet_ntoa(nat_state->alias_addr),
926 htons(nat_state->alias_port));
927 printf(" -> %s:%hu ",inet_ntoa(nat_state->dst_addr),
928 htons(nat_state->dst_port));
931 time_t t = _long_to_time(uptime_sec +
932 nat_state->timestamp);
933 strcpy(timestr, ctime(&t));
934 *strchr(timestr, '\n') = '\0';
935 printf("%s ", timestr);
936 } else if (do_time == 2) {
937 printf( "%10u ", uptime_sec + nat_state->timestamp);
939 struct protoent *pe = getprotobynumber(nat_state->link_type);
940 printf("%s ", pe->p_name);
941 printf(" %s", nat_state->is_outgoing? "out": "in");
948 get_kern_boottime(void)
950 struct timeval boottime;
954 mib[1] = KERN_BOOTTIME;
955 size = sizeof(boottime);
956 if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
957 boottime.tv_sec != 0) {
958 return boottime.tv_sec;
966 int cmd = IP_FW_NAT_FLUSH;
970 printf("Are you sure? [yn] ");
973 c = toupper(getc(stdin));
974 while (c != '\n' && getc(stdin) != '\n')
976 return; /* and do not flush */
977 } while (c != 'Y' && c != 'N');
978 if (c == 'N') /* user said no */
981 if (do_set_x(cmd, NULL, 0) < 0 ) {
982 errx(EX_USAGE, "NAT configuration in use");
985 printf("Flushed all nat configurations");
990 nat_main(int ac, char **av)
992 if (!strncmp(*av, "config", strlen(*av))) {
994 } else if (!strncmp(*av, "flush", strlen(*av))) {
996 } else if (!strncmp(*av, "show", strlen(*av)) ||
997 !strncmp(*av, "list", strlen(*av))) {
998 if (ac > 2 && isdigit(*(av[1]))) {
1004 if (!strncmp(*av, "config", strlen(*av))) {
1006 } else if (!strncmp(*av, "state", strlen(*av))) {
1007 nat_show_state(ac,av);
1010 "bad nat show command `%s'", *av);
1012 } else if (!strncmp(*av, "delete", strlen(*av))) {
1013 nat_delete_config(ac, av);
1015 errx(EX_USAGE, "bad ipfw nat command `%s'", *av);