1 /* 2 * Copyright (c) 2016 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Bill Yuan <bycn82@dragonflybsd.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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. 20 * 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. 33 */ 34 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> 42 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> 60 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> 70 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" 78 79 #include "ipfw3.h" 80 #include "ipfw3nat.h" 81 82 extern int verbose; 83 extern int do_time; 84 extern int do_quiet; 85 extern int do_force; 86 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 }, 101 }; 102 103 104 void 105 nat_config(int ac, char **av) 106 { 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. */ 110 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; 116 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"); 128 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; 167 /* 168 * All the setup_redir_* functions work 169 * directly in the final 170 * buffer, see above for details. 171 */ 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; 185 } 186 n->redir_cnt++; 187 off += i; 188 len -= i; 189 break; 190 default: 191 errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 192 } 193 } 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"); 197 } 198 199 /* After every modification, we show the resultant rule. */ 200 int _ac = 2; 201 char *_av[] = {"config", id}; 202 nat_show(_ac, _av); 203 } 204 205 void 206 nat_show_config(char *buf) 207 { 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; 213 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; 244 } 245 } 246 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; 265 } 266 } 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); 277 } 278 } else 279 for (i=0; i < t->spool_cnt; i++) { 280 s = (struct cfg_spool *)&buf[off]; 281 if (i) { 282 printf(", "); 283 } 284 printf("%s:%u", inet_ntoa(s->addr), 285 s->port); 286 off += SOF_SPOOL; 287 } 288 289 printf(" "); 290 if (t->paddr.s_addr) { 291 printf("%s:", inet_ntoa(t->paddr)); 292 } 293 printf("%u", t->pport); 294 if (!t->spool_cnt && t->pport_cnt > 1) { 295 printf("-%u", t->pport + t->pport_cnt - 1); 296 } 297 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); 305 } 306 } 307 } 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)); 317 } 318 } 319 break; 320 default: 321 errx(EX_DATAERR, "unknown redir mode"); 322 break; 323 } 324 } 325 printf("\n"); 326 } 327 328 329 void 330 nat_show(int ac, char **av) 331 { 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; 337 338 nalloc = 1024; 339 size = 0; 340 data = NULL; 341 342 NEXT_ARG; 343 344 if (ac == 0) 345 nat_id = 0; 346 else 347 nat_id = strtoul(*av, NULL, 10); 348 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"); 355 } 356 if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) { 357 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)"); 358 } 359 } 360 361 if (nbytes == 0) { 362 exit(EX_OK); 363 } 364 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]); 371 } 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); 377 } 378 } 379 } 380 381 int 382 setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av) 383 { 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; 391 392 av = *_av; 393 ac = *_ac; 394 space = 0; 395 lsnat = 0; 396 numLocalPorts = 0; 397 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; 406 } 407 408 r->mode = REDIR_PORT; 409 /* 410 * Extract protocol. 411 */ 412 if (ac == 0) 413 errx (EX_DATAERR, "redirect_port: missing protocol"); 414 415 r->proto = str2proto(*av); 416 protoName = *av; 417 INC_ARGCV(); 418 419 /* 420 * Extract local address. 421 */ 422 if (ac == 0) 423 errx (EX_DATAERR, "redirect_port: missing local address"); 424 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"); 439 440 r->lport = GETLOPORT(portRange); 441 numLocalPorts = GETNUMPORTS(portRange); 442 } 443 INC_ARGCV(); 444 445 /* 446 * Extract public port and optionally address. 447 */ 448 if (ac == 0) 449 errx (EX_DATAERR, "redirect_port: missing public port"); 450 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"); 461 } 462 463 r->pport = GETLOPORT(portRange); 464 r->pport_cnt = GETNUMPORTS(portRange); 465 INC_ARGCV(); 466 467 /* 468 * Extract remote address and optionally port. 469 */ 470 /* 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]. 473 */ 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"); 481 } 482 } else { 483 SETLOPORT(portRange, 0); 484 SETNUMPORTS(portRange, 1); 485 str2addr (*av, &r->raddr); 486 } 487 INC_ARGCV(); 488 } else { 489 SETLOPORT(portRange, 0); 490 SETNUMPORTS(portRange, 1); 491 r->raddr.s_addr = INADDR_ANY; 492 } 493 r->rport = GETLOPORT(portRange); 494 r->rport_cnt = GETNUMPORTS(portRange); 495 496 /* 497 * Make sure port ranges match up, then add the redirect ports. 498 */ 499 if (numLocalPorts != r->pport_cnt) { 500 errx(EX_DATAERR, "redirect_port:" 501 "port ranges must be equal in size"); 502 } 503 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"); 509 } 510 511 /* 512 * Setup LSNAT server pool. 513 */ 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; 520 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, ", "); 535 } 536 } 537 return (space); 538 539 nospace: 540 errx(EX_DATAERR, "redirect_port: buf is too small\n"); 541 } 542 543 int 544 setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av) 545 { 546 struct protoent *protoent; 547 struct cfg_redir *r; 548 int ac, i, space; 549 char **av; 550 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; 562 } 563 r->mode = REDIR_PROTO; 564 /* 565 * Extract protocol. 566 */ 567 if (ac == 0) 568 errx(EX_DATAERR, "redirect_proto: missing protocol"); 569 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; 575 576 INC_ARGCV(); 577 578 /* 579 * Extract local address. 580 */ 581 if (ac == 0) 582 errx(EX_DATAERR, "redirect_proto: missing local address"); 583 else 584 str2addr(*av, &r->laddr); 585 INC_ARGCV(); 586 587 /* 588 * Extract optional public address. 589 */ 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(); 598 599 /* 600 * Extract optional remote address. 601 */ 602 /* see above in setup_redir_port() */ 603 if (ac != 0 && !isalpha(**av)) { 604 str2addr(*av, &r->raddr); 605 INC_ARGCV(); 606 } 607 } 608 } 609 return (space); 610 611 nospace: 612 errx(EX_DATAERR, "redirect_proto: buf is too small\n"); 613 } 614 615 int 616 str2proto(const char* str) 617 { 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); 623 } 624 625 int 626 str2addr_portrange (const char* str, struct in_addr* addr, 627 char* proto, port_range *portRange) 628 { 629 char* ptr; 630 631 ptr = strchr (str, ':'); 632 if (!ptr) 633 errx (EX_DATAERR, "%s is missing port number", str); 634 635 *ptr = '\0'; 636 ++ptr; 637 638 str2addr (str, addr); 639 return str2portrange (ptr, proto, portRange); 640 } 641 642 /* 643 * Search for interface with name "ifn", and fill n accordingly: 644 * 645 * n->ip ip address of interface "ifn" 646 * n->if_name copy of interface name "ifn" 647 */ 648 void 649 set_addr_dynamic(const char *ifn, struct cfg_nat *n) 650 { 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; 659 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; 666 667 /* 668 * Get interface data. 669 */ 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; 677 /* 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. 682 */ 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; 693 } 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; 702 } 703 } 704 } 705 if (!ifIndex) 706 errx(1, "unknown interface name %s", ifn); 707 /* 708 * Get interface address. 709 */ 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; 719 } 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); 725 726 for (i = 1; i < RTA_IFA; i <<= 1) { 727 if (ifam->ifam_addrs & i) 728 cp += SA_SIZE((struct sockaddr *)cp); 729 } 730 if (((struct sockaddr *)cp)->sa_family == AF_INET) { 731 sin = (struct sockaddr_in *)cp; 732 break; 733 } 734 } 735 } 736 if (sin == NULL) 737 errx(1, "%s: cannot get interface address", ifn); 738 739 n->ip = sin->sin_addr; 740 strncpy(n->if_name, ifn, IF_NAMESIZE); 741 742 free(buf); 743 } 744 745 int 746 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av) 747 { 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; 753 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; 767 } 768 769 r->mode = REDIR_ADDR; 770 /* Extract local address. */ 771 if (ac == 0) 772 errx(EX_DATAERR, "redirect_addr: missing local address"); 773 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); 782 } 783 INC_ARGCV(); 784 785 /* Extract public address. */ 786 if (ac == 0) 787 errx(EX_DATAERR, "redirect_addr: missing public address"); 788 789 str2addr(*av, &r->paddr); 790 INC_ARGCV(); 791 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; 799 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, ", "); 808 } 809 } 810 return(space); 811 812 nospace: 813 errx(EX_DATAERR, "redirect_addr: buf is too small\n"); 814 } 815 816 void 817 str2addr(const char* str, struct in_addr* addr) 818 { 819 struct hostent* hp; 820 821 if (inet_aton (str, addr)) 822 return; 823 824 hp = gethostbyname (str); 825 if (!hp) 826 errx (1, "unknown host %s", str); 827 828 memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 829 } 830 831 int 832 str2portrange(const char* str, const char* proto, port_range *portRange) 833 { 834 struct servent* sp; 835 char* sep; 836 char* end; 837 u_short loPort, hiPort; 838 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; 845 } 846 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; 855 } 856 857 /* Error in port range field. */ 858 errx (EX_DATAERR, "%s/%s: unknown service", str, proto); 859 } 860 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); 867 868 if (GETNUMPORTS(*portRange) == 0) 869 errx (EX_DATAERR, "invalid port range %s", str); 870 871 return 0; 872 } 873 874 void 875 nat_delete_config(int ac, char *av[]) 876 { 877 NEXT_ARG; 878 int i = 0; 879 if (ac > 0) { 880 i = atoi(*av); 881 } 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); 884 } 885 886 void 887 nat_show_state(int ac, char **av) 888 { 889 int nbytes, nalloc; 890 int nat_id; 891 uint8_t *data; 892 893 nalloc = 1024; 894 data = NULL; 895 896 NEXT_ARG; 897 if (ac == 0) 898 nat_id = 0; 899 else 900 nat_id = strtoul(*av, NULL, 10); 901 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"); 908 } 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)"); 912 } 913 } 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); 938 } 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++; 944 } 945 } 946 947 int 948 get_kern_boottime(void) 949 { 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; 959 } 960 return -1; 961 } 962 963 void 964 nat_flush() 965 { 966 int cmd = IP_FW_NAT_FLUSH; 967 if (!do_force) { 968 int c; 969 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; 980 } 981 if (do_set_x(cmd, NULL, 0) < 0 ) { 982 errx(EX_USAGE, "NAT configuration in use"); 983 } 984 if (!do_quiet) { 985 printf("Flushed all nat configurations"); 986 } 987 } 988 989 void 990 nat_main(int ac, char **av) 991 { 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; 1002 } 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); 1011 } 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); 1016 } 1017 } 1018