Fix some typos in manual pages.
[dragonfly.git] / sbin / ipfw3 / ipfw3nat.c
blob6685af3c260baf44d4d5dadcd6a3a54284d4132f
1 /*
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
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
35 #include <sys/param.h>
36 #include <sys/mbuf.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/sysctl.h>
40 #include <sys/time.h>
41 #include <sys/wait.h>
43 #include <arpa/inet.h>
44 #include <ctype.h>
45 #include <dlfcn.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <grp.h>
49 #include <limits.h>
50 #include <netdb.h>
51 #include <pwd.h>
52 #include <sysexits.h>
53 #include <signal.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <string.h>
58 #include <timeconv.h>
59 #include <unistd.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>
66 #include <net/if.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"
79 #include "ipfw3.h"
80 #include "ipfw3nat.h"
82 extern int verbose;
83 extern int do_time;
84 extern int do_quiet;
85 extern int do_force;
87 struct char_int_map nat_params[] = {
88 { "ip", TOK_IP },
89 { "if", TOK_IF },
90 { "log", TOK_ALOG },
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 },
100 { NULL, 0 },
104 void
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. */
111 len = NAT_BUF_LEN;
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;
117 NEXT_ARG;
118 /* Nat id. */
119 if (ac && isdigit(**av)) {
120 id = *av;
121 i = atoi(*av);
122 NEXT_ARG;
123 n->id = i;
124 } else
125 errx(EX_DATAERR, "missing nat id");
126 if (ac == 0)
127 errx(EX_DATAERR, "missing option");
129 while (ac > 0) {
130 tok = match_token(nat_params, *av);
131 NEXT_ARG;
132 switch (tok) {
133 case TOK_IP:
134 if (ac == 0)
135 errx(EX_DATAERR, "missing option");
136 if (!inet_aton(av[0], &(n->ip)))
137 errx(EX_DATAERR, "bad ip addr `%s'", av[0]);
138 NEXT_ARG;
139 break;
140 case TOK_IF:
141 if (ac == 0)
142 errx(EX_DATAERR, "missing option");
143 set_addr_dynamic(av[0], n);
144 NEXT_ARG;
145 break;
146 case TOK_ALOG:
147 n->mode |= PKT_ALIAS_LOG;
148 break;
149 case TOK_DENY_INC:
150 n->mode |= PKT_ALIAS_DENY_INCOMING;
151 break;
152 case TOK_SAME_PORTS:
153 n->mode |= PKT_ALIAS_SAME_PORTS;
154 break;
155 case TOK_UNREG_ONLY:
156 n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
157 break;
158 case TOK_RESET_ADDR:
159 n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
160 break;
161 case TOK_ALIAS_REV:
162 n->mode |= PKT_ALIAS_REVERSE;
163 break;
164 case TOK_PROXY_ONLY:
165 n->mode |= PKT_ALIAS_PROXY_ONLY;
166 break;
168 * All the setup_redir_* functions work
169 * directly in the final
170 * buffer, see above for details.
172 case TOK_REDIR_ADDR:
173 case TOK_REDIR_PORT:
174 case TOK_REDIR_PROTO:
175 switch (tok) {
176 case TOK_REDIR_ADDR:
177 i = setup_redir_addr(&buf[off], len, &ac, &av);
178 break;
179 case TOK_REDIR_PORT:
180 i = setup_redir_port(&buf[off], len, &ac, &av);
181 break;
182 case TOK_REDIR_PROTO:
183 i = setup_redir_proto(&buf[off], len, &ac, &av);
184 break;
186 n->redir_cnt++;
187 off += i;
188 len -= i;
189 break;
190 default:
191 errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
194 i = do_set_x(IP_FW_NAT_ADD, buf, off);
195 if (i) {
196 err(1, "do_set_x(%s)", "IP_FW_NAT_ADD");
199 /* After every modification, we show the resultant rule. */
200 int _ac = 2;
201 char *_av[] = {"config", id};
202 nat_show(_ac, _av);
205 void
206 nat_show_config(char *buf)
208 struct cfg_nat *n;
209 struct cfg_redir *t;
210 struct cfg_spool *s;
211 struct protoent *p;
212 int i, cnt, flag, off;
214 n = (struct cfg_nat *)buf;
215 flag = 1;
216 off = sizeof(*n);
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) {
224 printf(" log");
225 n->mode &= ~PKT_ALIAS_LOG;
226 } else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
227 printf(" deny_in");
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) {
236 printf(" reset");
237 n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
238 } else if (n->mode & PKT_ALIAS_REVERSE) {
239 printf(" 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];
250 off += SOF_REDIR;
251 switch (t->mode) {
252 case REDIR_ADDR:
253 printf(" redirect_addr");
254 if (t->spool_cnt == 0) {
255 printf(" %s", inet_ntoa(t->laddr));
256 } else {
257 for (i = 0; i < t->spool_cnt; i++) {
258 s = (struct cfg_spool *)&buf[off];
259 if (i)
260 printf(", ");
261 else
262 printf(" ");
263 printf("%s", inet_ntoa(s->addr));
264 off += SOF_SPOOL;
267 printf(" %s", inet_ntoa(t->paddr));
268 break;
269 case REDIR_PORT:
270 p = getprotobynumber(t->proto);
271 printf(" redirect_port %s ", p->p_name);
272 if (!t->spool_cnt) {
273 printf("%s:%u", inet_ntoa(t->laddr), t->lport);
274 if (t->pport_cnt > 1) {
275 printf("-%u", t->lport +
276 t->pport_cnt - 1);
278 } else
279 for (i=0; i < t->spool_cnt; i++) {
280 s = (struct cfg_spool *)&buf[off];
281 if (i) {
282 printf(", ");
284 printf("%s:%u", inet_ntoa(s->addr),
285 s->port);
286 off += SOF_SPOOL;
289 printf(" ");
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));
300 if (t->rport) {
301 printf(":%u", t->rport);
302 if (!t->spool_cnt && t->rport_cnt > 1) {
303 printf("-%u", t->rport +
304 t->rport_cnt - 1);
308 break;
309 case REDIR_PROTO:
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));
319 break;
320 default:
321 errx(EX_DATAERR, "unknown redir mode");
322 break;
325 printf("\n");
329 void
330 nat_show(int ac, char **av)
332 struct cfg_nat *n;
333 struct cfg_redir *e;
334 int i, nbytes, nalloc, size;
335 int nat_cnt, redir_cnt, nat_id;
336 uint8_t *data;
338 nalloc = 1024;
339 size = 0;
340 data = NULL;
342 NEXT_ARG;
344 if (ac == 0)
345 nat_id = 0;
346 else
347 nat_id = strtoul(*av, NULL, 10);
349 nbytes = nalloc;
350 while (nbytes >= nalloc) {
351 nalloc = nalloc * 2;
352 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)");
361 if (nbytes == 0) {
362 exit(EX_OK);
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;
387 struct cfg_redir *r;
388 struct cfg_spool *tmp;
389 u_short numLocalPorts;
390 port_range portRange;
392 av = *_av;
393 ac = *_ac;
394 space = 0;
395 lsnat = 0;
396 numLocalPorts = 0;
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];
402 space = SOF_REDIR;
403 len -= SOF_REDIR;
404 } else {
405 goto nospace;
408 r->mode = REDIR_PORT;
410 * Extract protocol.
412 if (ac == 0)
413 errx (EX_DATAERR, "redirect_port: missing protocol");
415 r->proto = str2proto(*av);
416 protoName = *av;
417 INC_ARGCV();
420 * Extract local address.
422 if (ac == 0)
423 errx (EX_DATAERR, "redirect_port: missing local address");
425 sep = strchr(*av, ',');
426 /* LSNAT redirection syntax. */
427 if (sep) {
428 r->laddr.s_addr = INADDR_NONE;
429 r->lport = ~0;
430 numLocalPorts = 1;
431 /* Preserve av, copy spool servers to tmp_spool_buf. */
432 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
433 lsnat = 1;
434 } else {
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);
443 INC_ARGCV();
446 * Extract public port and optionally address.
448 if (ac == 0)
449 errx (EX_DATAERR, "redirect_port: missing public port");
451 sep = strchr (*av, ':');
452 if (sep) {
453 if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0)
454 errx(EX_DATAERR, "redirect_port:"
455 "invalid public port range");
456 } else {
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);
465 INC_ARGCV();
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, ':');
476 if (sep) {
477 if (str2addr_portrange (*av, &r->raddr,
478 protoName, &portRange) != 0) {
479 errx(EX_DATAERR, "redirect_port:"
480 "invalid remote port range");
482 } else {
483 SETLOPORT(portRange, 0);
484 SETNUMPORTS(portRange, 1);
485 str2addr (*av, &r->raddr);
487 INC_ARGCV();
488 } else {
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.
514 if (lsnat) {
515 sep = strtok(tmp_spool_buf, ", ");
516 while (sep != NULL) {
517 tmp = (struct cfg_spool *)spool_buf;
518 if (len < SOF_SPOOL)
519 goto nospace;
521 len -= SOF_SPOOL;
522 space += SOF_SPOOL;
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);
531 r->spool_cnt++;
532 /* Point to the next possible cfg_spool. */
533 spool_buf = &spool_buf[SOF_SPOOL];
534 sep = strtok(NULL, ", ");
537 return (space);
539 nospace:
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;
547 struct cfg_redir *r;
548 int ac, i, space;
549 char **av;
551 i=0;
552 av = *_av;
553 ac = *_ac;
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];
558 space = SOF_REDIR;
559 len -= SOF_REDIR;
560 } else {
561 goto nospace;
563 r->mode = REDIR_PROTO;
565 * Extract protocol.
567 if (ac == 0)
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);
573 else
574 r->proto = protoent->p_proto;
576 INC_ARGCV();
579 * Extract local address.
581 if (ac == 0)
582 errx(EX_DATAERR, "redirect_proto: missing local address");
583 else
584 str2addr(*av, &r->laddr);
585 INC_ARGCV();
588 * Extract optional public address.
590 if (ac == 0) {
591 r->paddr.s_addr = INADDR_ANY;
592 r->raddr.s_addr = INADDR_ANY;
593 } else {
594 /* see above in setup_redir_port() */
595 if (!isalpha(**av)) {
596 str2addr(*av, &r->paddr);
597 INC_ARGCV();
600 * Extract optional remote address.
602 /* see above in setup_redir_port() */
603 if (ac != 0 && !isalpha(**av)) {
604 str2addr(*av, &r->raddr);
605 INC_ARGCV();
609 return (space);
611 nospace:
612 errx(EX_DATAERR, "redirect_proto: buf is too small\n");
616 str2proto(const char* str)
618 if (!strcmp (str, "tcp"))
619 return IPPROTO_TCP;
620 if (!strcmp (str, "udp"))
621 return IPPROTO_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)
629 char* ptr;
631 ptr = strchr (str, ':');
632 if (!ptr)
633 errx (EX_DATAERR, "%s is missing port number", str);
635 *ptr = '\0';
636 ++ptr;
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"
648 void
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;
656 size_t needed;
657 int mib[6];
658 int ifIndex, ifMTU;
660 mib[0] = CTL_NET;
661 mib[1] = PF_ROUTE;
662 mib[2] = 0;
663 mib[3] = AF_INET;
664 mib[4] = NET_RT_IFLIST;
665 mib[5] = 0;
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");
676 lim = buf + needed;
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.
683 ifIndex = 0;
684 next = buf;
685 while (next < lim) {
686 ifm = (struct if_msghdr *)next;
687 next += ifm->ifm_msglen;
688 if (ifm->ifm_version != RTM_VERSION) {
689 if (verbose)
690 warnx("routing message version %d "
691 "not understood", ifm->ifm_version);
692 continue;
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;
701 break;
705 if (!ifIndex)
706 errx(1, "unknown interface name %s", ifn);
708 * Get interface address.
710 sin = NULL;
711 while (next < lim) {
712 ifam = (struct ifa_msghdr *)next;
713 next += ifam->ifam_msglen;
714 if (ifam->ifam_version != RTM_VERSION) {
715 if (verbose)
716 warnx("routing message version %d "
717 "not understood", ifam->ifam_version);
718 continue;
720 if (ifam->ifam_type != RTM_NEWADDR)
721 break;
722 if (ifam->ifam_addrs & RTA_IFA) {
723 int i;
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;
732 break;
736 if (sin == NULL)
737 errx(1, "%s: cannot get interface address", ifn);
739 n->ip = sin->sin_addr;
740 strncpy(n->if_name, ifn, IF_NAMESIZE);
742 free(buf);
746 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av)
748 struct cfg_redir *r;
749 struct cfg_spool *tmp;
750 char **av, *sep;
751 char tmp_spool_buf[NAT_BUF_LEN];
752 int ac, i, space, lsnat;
754 i=0;
755 av = *_av;
756 ac = *_ac;
757 space = 0;
758 lsnat = 0;
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];
763 space = SOF_REDIR;
764 len -= SOF_REDIR;
765 } else {
766 goto nospace;
769 r->mode = REDIR_ADDR;
770 /* Extract local address. */
771 if (ac == 0)
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);
779 lsnat = 1;
780 } else {
781 str2addr(*av, &r->laddr);
783 INC_ARGCV();
785 /* Extract public address. */
786 if (ac == 0)
787 errx(EX_DATAERR, "redirect_addr: missing public address");
789 str2addr(*av, &r->paddr);
790 INC_ARGCV();
792 /* Setup LSNAT server pool. */
793 if (sep) {
794 sep = strtok(tmp_spool_buf, ", ");
795 while (sep != NULL) {
796 tmp = (struct cfg_spool *)spool_buf;
797 if (len < SOF_SPOOL)
798 goto nospace;
800 len -= SOF_SPOOL;
801 space += SOF_SPOOL;
802 str2addr(sep, &tmp->addr);
803 tmp->port = ~0;
804 r->spool_cnt++;
805 /* Point to the next possible cfg_spool. */
806 spool_buf = &spool_buf[SOF_SPOOL];
807 sep = strtok(NULL, ", ");
810 return(space);
812 nospace:
813 errx(EX_DATAERR, "redirect_addr: buf is too small\n");
816 void
817 str2addr(const char* str, struct in_addr* addr)
819 struct hostent* hp;
821 if (inet_aton (str, addr))
822 return;
824 hp = gethostbyname (str);
825 if (!hp)
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)
834 struct servent* sp;
835 char* sep;
836 char* end;
837 u_short loPort, hiPort;
839 /* First see if this is a service, return corresponding port if so. */
840 sp = getservbyname (str, proto);
841 if (sp) {
842 SETLOPORT(*portRange, ntohs(sp->s_port));
843 SETNUMPORTS(*portRange, 1);
844 return 0;
847 /* Not a service, see if it's a single port or port range. */
848 sep = strchr (str, '-');
849 if (sep == NULL) {
850 SETLOPORT(*portRange, strtol(str, &end, 10));
851 if (end != str) {
852 /* Single port. */
853 SETNUMPORTS(*portRange, 1);
854 return 0;
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);
871 return 0;
874 void
875 nat_delete_config(int ac, char *av[])
877 NEXT_ARG;
878 int i = 0;
879 if (ac > 0) {
880 i = atoi(*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);
886 void
887 nat_show_state(int ac, char **av)
889 int nbytes, nalloc;
890 int nat_id;
891 uint8_t *data;
893 nalloc = 1024;
894 data = NULL;
896 NEXT_ARG;
897 if (ac == 0)
898 nat_id = 0;
899 else
900 nat_id = strtoul(*av, NULL, 10);
902 nbytes = nalloc;
903 while (nbytes >= nalloc) {
904 nalloc = nalloc * 2;
905 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)");
914 if (nbytes == 0)
915 exit(EX_OK);
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);
919 int i, uptime_sec;
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));
929 if (do_time == 1) {
930 char timestr[30];
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");
942 printf("\n");
943 nat_state++;
948 get_kern_boottime(void)
950 struct timeval boottime;
951 size_t size;
952 int mib[2];
953 mib[0] = CTL_KERN;
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;
960 return -1;
963 void
964 nat_flush()
966 int cmd = IP_FW_NAT_FLUSH;
967 if (!do_force) {
968 int c;
970 printf("Are you sure? [yn] ");
971 fflush(stdout);
972 do {
973 c = toupper(getc(stdin));
974 while (c != '\n' && getc(stdin) != '\n')
975 if (feof(stdin))
976 return; /* and do not flush */
977 } while (c != 'Y' && c != 'N');
978 if (c == 'N') /* user said no */
979 return;
981 if (do_set_x(cmd, NULL, 0) < 0 ) {
982 errx(EX_USAGE, "NAT configuration in use");
984 if (!do_quiet) {
985 printf("Flushed all nat configurations");
989 void
990 nat_main(int ac, char **av)
992 if (!strncmp(*av, "config", strlen(*av))) {
993 nat_config(ac, av);
994 } else if (!strncmp(*av, "flush", strlen(*av))) {
995 nat_flush();
996 } else if (!strncmp(*av, "show", strlen(*av)) ||
997 !strncmp(*av, "list", strlen(*av))) {
998 if (ac > 2 && isdigit(*(av[1]))) {
999 char *p = av[1];
1000 av[1] = av[2];
1001 av[2] = p;
1003 NEXT_ARG;
1004 if (!strncmp(*av, "config", strlen(*av))) {
1005 nat_show(ac, av);
1006 } else if (!strncmp(*av, "state", strlen(*av))) {
1007 nat_show_state(ac,av);
1008 } else {
1009 errx(EX_USAGE,
1010 "bad nat show command `%s'", *av);
1012 } else if (!strncmp(*av, "delete", strlen(*av))) {
1013 nat_delete_config(ac, av);
1014 } else {
1015 errx(EX_USAGE, "bad ipfw nat command `%s'", *av);