1 /* 2 * natd - Network Address Translation Daemon for FreeBSD. 3 * 4 * This software is provided free of charge, with no 5 * warranty of any kind, either expressed or implied. 6 * Use at your own risk. 7 * 8 * You may copy, modify and distribute this software (natd.c) freely. 9 * 10 * Ari Suutari <suutari@iki.fi> 11 * 12 * $FreeBSD$ 13 */ 14 15 #define SYSLOG_NAMES 16 17 #include <sys/types.h> 18 #include <sys/socket.h> 19 #include <sys/sysctl.h> 20 #include <sys/time.h> 21 22 #include <netinet/in.h> 23 #include <netinet/in_systm.h> 24 #include <netinet/ip.h> 25 #include <machine/in_cksum.h> 26 #include <netinet/tcp.h> 27 #include <netinet/udp.h> 28 #include <netinet/ip_icmp.h> 29 #include <net/if.h> 30 #include <net/if_dl.h> 31 #include <net/route.h> 32 #include <arpa/inet.h> 33 34 #include <alias.h> 35 #include <ctype.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <netdb.h> 39 #include <signal.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <syslog.h> 44 #include <unistd.h> 45 46 #include "natd.h" 47 48 /* 49 * Default values for input and output 50 * divert socket ports. 51 */ 52 53 #define DEFAULT_SERVICE "natd" 54 55 /* 56 * Definition of a port range, and macros to deal with values. 57 * FORMAT: HI 16-bits == first port in range, 0 == all ports. 58 * LO 16-bits == number of ports in range 59 * NOTES: - Port values are not stored in network byte order. 60 */ 61 62 typedef u_long port_range; 63 64 #define GETLOPORT(x) ((x) >> 0x10) 65 #define GETNUMPORTS(x) ((x) & 0x0000ffff) 66 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 67 68 /* Set y to be the low-port value in port_range variable x. */ 69 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 70 71 /* Set y to be the number of ports in port_range variable x. */ 72 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 73 74 /* 75 * Function prototypes. 76 */ 77 78 static void DoAliasing (int fd, int direction); 79 static void DaemonMode (void); 80 static void HandleRoutingInfo (int fd); 81 static void Usage (void); 82 static char* FormatPacket (struct ip*); 83 static void PrintPacket (struct ip*); 84 static void SyslogPacket (struct ip*, int priority, const char *label); 85 static void SetAliasAddressFromIfName (const char *ifName); 86 static void InitiateShutdown (int); 87 static void Shutdown (int); 88 static void RefreshAddr (int); 89 static void ParseOption (const char* option, const char* parms); 90 static void ReadConfigFile (const char* fileName); 91 static void SetupPortRedirect (const char* parms); 92 static void SetupProtoRedirect(const char* parms); 93 static void SetupAddressRedirect (const char* parms); 94 static void StrToAddr (const char* str, struct in_addr* addr); 95 static u_short StrToPort (const char* str, const char* proto); 96 static int StrToPortRange (const char* str, const char* proto, port_range *portRange); 97 static int StrToProto (const char* str); 98 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange); 99 static void ParseArgs (int argc, char** argv); 100 static void FlushPacketBuffer (int fd); 101 static void SetupPunchFW(const char *strValue); 102 103 /* 104 * Globals. 105 */ 106 107 static int verbose; 108 static int background; 109 static int running; 110 static int assignAliasAddr; 111 static char* ifName; 112 static int ifIndex; 113 static u_short inPort; 114 static u_short outPort; 115 static u_short inOutPort; 116 static struct in_addr aliasAddr; 117 static int dynamicMode; 118 static int ifMTU; 119 static int aliasOverhead; 120 static int icmpSock; 121 static char packetBuf[IP_MAXPACKET]; 122 static int packetLen; 123 static struct sockaddr_in packetAddr; 124 static int packetSock; 125 static int packetDirection; 126 static int dropIgnoredIncoming; 127 static int logDropped; 128 static int logFacility; 129 static int logIpfwDenied; 130 131 int main (int argc, char** argv) 132 { 133 int divertIn; 134 int divertOut; 135 int divertInOut; 136 int routeSock; 137 struct sockaddr_in addr; 138 fd_set readMask; 139 fd_set writeMask; 140 int fdMax; 141 /* 142 * Initialize packet aliasing software. 143 * Done already here to be able to alter option bits 144 * during command line and configuration file processing. 145 */ 146 PacketAliasInit (); 147 /* 148 * Parse options. 149 */ 150 inPort = 0; 151 outPort = 0; 152 verbose = 0; 153 inOutPort = 0; 154 ifName = NULL; 155 ifMTU = -1; 156 background = 0; 157 running = 1; 158 assignAliasAddr = 0; 159 aliasAddr.s_addr = INADDR_NONE; 160 aliasOverhead = 12; 161 dynamicMode = 0; 162 logDropped = 0; 163 logFacility = LOG_DAEMON; 164 logIpfwDenied = -1; 165 /* 166 * Mark packet buffer empty. 167 */ 168 packetSock = -1; 169 packetDirection = DONT_KNOW; 170 171 ParseArgs (argc, argv); 172 /* 173 * Log ipfw(8) denied packets by default in verbose mode. 174 */ 175 if (logIpfwDenied == -1) 176 logIpfwDenied = verbose; 177 /* 178 * Open syslog channel. 179 */ 180 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0), 181 logFacility); 182 /* 183 * Check that valid aliasing address has been given. 184 */ 185 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL) 186 errx (1, "aliasing address not given"); 187 188 if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL) 189 errx (1, "both alias address and interface " 190 "name are not allowed"); 191 /* 192 * Check that valid port number is known. 193 */ 194 if (inPort != 0 || outPort != 0) 195 if (inPort == 0 || outPort == 0) 196 errx (1, "both input and output ports are required"); 197 198 if (inPort == 0 && outPort == 0 && inOutPort == 0) 199 ParseOption ("port", DEFAULT_SERVICE); 200 201 /* 202 * Check if ignored packets should be dropped. 203 */ 204 dropIgnoredIncoming = PacketAliasSetMode (0, 0); 205 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; 206 /* 207 * Create divert sockets. Use only one socket if -p was specified 208 * on command line. Otherwise, create separate sockets for 209 * outgoing and incoming connnections. 210 */ 211 if (inOutPort) { 212 213 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 214 if (divertInOut == -1) 215 Quit ("Unable to create divert socket."); 216 217 divertIn = -1; 218 divertOut = -1; 219 /* 220 * Bind socket. 221 */ 222 223 addr.sin_family = AF_INET; 224 addr.sin_addr.s_addr = INADDR_ANY; 225 addr.sin_port = inOutPort; 226 227 if (bind (divertInOut, 228 (struct sockaddr*) &addr, 229 sizeof addr) == -1) 230 Quit ("Unable to bind divert socket."); 231 } 232 else { 233 234 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 235 if (divertIn == -1) 236 Quit ("Unable to create incoming divert socket."); 237 238 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 239 if (divertOut == -1) 240 Quit ("Unable to create outgoing divert socket."); 241 242 divertInOut = -1; 243 244 /* 245 * Bind divert sockets. 246 */ 247 248 addr.sin_family = AF_INET; 249 addr.sin_addr.s_addr = INADDR_ANY; 250 addr.sin_port = inPort; 251 252 if (bind (divertIn, 253 (struct sockaddr*) &addr, 254 sizeof addr) == -1) 255 Quit ("Unable to bind incoming divert socket."); 256 257 addr.sin_family = AF_INET; 258 addr.sin_addr.s_addr = INADDR_ANY; 259 addr.sin_port = outPort; 260 261 if (bind (divertOut, 262 (struct sockaddr*) &addr, 263 sizeof addr) == -1) 264 Quit ("Unable to bind outgoing divert socket."); 265 } 266 /* 267 * Create routing socket if interface name specified and in dynamic mode. 268 */ 269 routeSock = -1; 270 if (ifName) { 271 if (dynamicMode) { 272 273 routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 274 if (routeSock == -1) 275 Quit ("Unable to create routing info socket."); 276 277 assignAliasAddr = 1; 278 } 279 else 280 SetAliasAddressFromIfName (ifName); 281 } 282 /* 283 * Create socket for sending ICMP messages. 284 */ 285 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 286 if (icmpSock == -1) 287 Quit ("Unable to create ICMP socket."); 288 289 /* 290 * And disable reads for the socket, otherwise it slowly fills 291 * up with received icmps which we do not use. 292 */ 293 shutdown(icmpSock, SHUT_RD); 294 295 /* 296 * Become a daemon unless verbose mode was requested. 297 */ 298 if (!verbose) 299 DaemonMode (); 300 /* 301 * Catch signals to manage shutdown and 302 * refresh of interface address. 303 */ 304 siginterrupt(SIGTERM, 1); 305 siginterrupt(SIGHUP, 1); 306 signal (SIGTERM, InitiateShutdown); 307 signal (SIGHUP, RefreshAddr); 308 /* 309 * Set alias address if it has been given. 310 */ 311 if (aliasAddr.s_addr != INADDR_NONE) 312 PacketAliasSetAddress (aliasAddr); 313 /* 314 * We need largest descriptor number for select. 315 */ 316 317 fdMax = -1; 318 319 if (divertIn > fdMax) 320 fdMax = divertIn; 321 322 if (divertOut > fdMax) 323 fdMax = divertOut; 324 325 if (divertInOut > fdMax) 326 fdMax = divertInOut; 327 328 if (routeSock > fdMax) 329 fdMax = routeSock; 330 331 while (running) { 332 333 if (divertInOut != -1 && !ifName && packetSock == -1) { 334 /* 335 * When using only one socket, just call 336 * DoAliasing repeatedly to process packets. 337 */ 338 DoAliasing (divertInOut, DONT_KNOW); 339 continue; 340 } 341 /* 342 * Build read mask from socket descriptors to select. 343 */ 344 FD_ZERO (&readMask); 345 FD_ZERO (&writeMask); 346 347 /* 348 * If there is unsent packet in buffer, use select 349 * to check when socket comes writable again. 350 */ 351 if (packetSock != -1) { 352 353 FD_SET (packetSock, &writeMask); 354 } 355 else { 356 /* 357 * No unsent packet exists - safe to check if 358 * new ones are available. 359 */ 360 if (divertIn != -1) 361 FD_SET (divertIn, &readMask); 362 363 if (divertOut != -1) 364 FD_SET (divertOut, &readMask); 365 366 if (divertInOut != -1) 367 FD_SET (divertInOut, &readMask); 368 } 369 /* 370 * Routing info is processed always. 371 */ 372 if (routeSock != -1) 373 FD_SET (routeSock, &readMask); 374 375 if (select (fdMax + 1, 376 &readMask, 377 &writeMask, 378 NULL, 379 NULL) == -1) { 380 381 if (errno == EINTR) 382 continue; 383 384 Quit ("Select failed."); 385 } 386 387 if (packetSock != -1) 388 if (FD_ISSET (packetSock, &writeMask)) 389 FlushPacketBuffer (packetSock); 390 391 if (divertIn != -1) 392 if (FD_ISSET (divertIn, &readMask)) 393 DoAliasing (divertIn, INPUT); 394 395 if (divertOut != -1) 396 if (FD_ISSET (divertOut, &readMask)) 397 DoAliasing (divertOut, OUTPUT); 398 399 if (divertInOut != -1) 400 if (FD_ISSET (divertInOut, &readMask)) 401 DoAliasing (divertInOut, DONT_KNOW); 402 403 if (routeSock != -1) 404 if (FD_ISSET (routeSock, &readMask)) 405 HandleRoutingInfo (routeSock); 406 } 407 408 if (background) 409 unlink (PIDFILE); 410 411 return 0; 412 } 413 414 static void DaemonMode () 415 { 416 FILE* pidFile; 417 418 daemon (0, 0); 419 background = 1; 420 421 pidFile = fopen (PIDFILE, "w"); 422 if (pidFile) { 423 424 fprintf (pidFile, "%d\n", getpid ()); 425 fclose (pidFile); 426 } 427 } 428 429 static void ParseArgs (int argc, char** argv) 430 { 431 int arg; 432 char* opt; 433 char parmBuf[256]; 434 int len; /* bounds checking */ 435 436 for (arg = 1; arg < argc; arg++) { 437 438 opt = argv[arg]; 439 if (*opt != '-') { 440 441 warnx ("invalid option %s", opt); 442 Usage (); 443 } 444 445 parmBuf[0] = '\0'; 446 len = 0; 447 448 while (arg < argc - 1) { 449 450 if (argv[arg + 1][0] == '-') 451 break; 452 453 if (len) { 454 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1)); 455 len += strlen(parmBuf + len); 456 } 457 458 ++arg; 459 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1)); 460 len += strlen(parmBuf + len); 461 462 } 463 464 ParseOption (opt + 1, (len ? parmBuf : NULL)); 465 466 } 467 } 468 469 static void DoAliasing (int fd, int direction) 470 { 471 int bytes; 472 int origBytes; 473 int status; 474 int addrSize; 475 struct ip* ip; 476 477 if (assignAliasAddr) { 478 479 SetAliasAddressFromIfName (ifName); 480 assignAliasAddr = 0; 481 } 482 /* 483 * Get packet from socket. 484 */ 485 addrSize = sizeof packetAddr; 486 origBytes = recvfrom (fd, 487 packetBuf, 488 sizeof packetBuf, 489 0, 490 (struct sockaddr*) &packetAddr, 491 &addrSize); 492 493 if (origBytes == -1) { 494 495 if (errno != EINTR) 496 Warn ("read from divert socket failed"); 497 498 return; 499 } 500 /* 501 * This is a IP packet. 502 */ 503 ip = (struct ip*) packetBuf; 504 if (direction == DONT_KNOW) { 505 if (packetAddr.sin_addr.s_addr == INADDR_ANY) 506 direction = OUTPUT; 507 else 508 direction = INPUT; 509 } 510 511 if (verbose) { 512 /* 513 * Print packet direction and protocol type. 514 */ 515 printf (direction == OUTPUT ? "Out " : "In "); 516 517 switch (ip->ip_p) { 518 case IPPROTO_TCP: 519 printf ("[TCP] "); 520 break; 521 522 case IPPROTO_UDP: 523 printf ("[UDP] "); 524 break; 525 526 case IPPROTO_ICMP: 527 printf ("[ICMP] "); 528 break; 529 530 default: 531 printf ("[%d] ", ip->ip_p); 532 break; 533 } 534 /* 535 * Print addresses. 536 */ 537 PrintPacket (ip); 538 } 539 540 if (direction == OUTPUT) { 541 /* 542 * Outgoing packets. Do aliasing. 543 */ 544 PacketAliasOut (packetBuf, IP_MAXPACKET); 545 } 546 else { 547 548 /* 549 * Do aliasing. 550 */ 551 status = PacketAliasIn (packetBuf, IP_MAXPACKET); 552 if (status == PKT_ALIAS_IGNORED && 553 dropIgnoredIncoming) { 554 555 if (verbose) 556 printf (" dropped.\n"); 557 558 if (logDropped) 559 SyslogPacket (ip, LOG_WARNING, "denied"); 560 561 return; 562 } 563 } 564 /* 565 * Length might have changed during aliasing. 566 */ 567 bytes = ntohs (ip->ip_len); 568 /* 569 * Update alias overhead size for outgoing packets. 570 */ 571 if (direction == OUTPUT && 572 bytes - origBytes > aliasOverhead) 573 aliasOverhead = bytes - origBytes; 574 575 if (verbose) { 576 577 /* 578 * Print addresses after aliasing. 579 */ 580 printf (" aliased to\n"); 581 printf (" "); 582 PrintPacket (ip); 583 printf ("\n"); 584 } 585 586 packetLen = bytes; 587 packetSock = fd; 588 packetDirection = direction; 589 590 FlushPacketBuffer (fd); 591 } 592 593 static void FlushPacketBuffer (int fd) 594 { 595 int wrote; 596 char msgBuf[80]; 597 /* 598 * Put packet back for processing. 599 */ 600 wrote = sendto (fd, 601 packetBuf, 602 packetLen, 603 0, 604 (struct sockaddr*) &packetAddr, 605 sizeof packetAddr); 606 607 if (wrote != packetLen) { 608 /* 609 * If buffer space is not available, 610 * just return. Main loop will take care of 611 * retrying send when space becomes available. 612 */ 613 if (errno == ENOBUFS) 614 return; 615 616 if (errno == EMSGSIZE) { 617 618 if (packetDirection == OUTPUT && 619 ifMTU != -1) 620 SendNeedFragIcmp (icmpSock, 621 (struct ip*) packetBuf, 622 ifMTU - aliasOverhead); 623 } 624 else if (errno == EACCES && logIpfwDenied) { 625 626 sprintf (msgBuf, "failed to write packet back"); 627 Warn (msgBuf); 628 } 629 } 630 631 packetSock = -1; 632 } 633 634 static void HandleRoutingInfo (int fd) 635 { 636 int bytes; 637 struct if_msghdr ifMsg; 638 /* 639 * Get packet from socket. 640 */ 641 bytes = read (fd, &ifMsg, sizeof ifMsg); 642 if (bytes == -1) { 643 644 Warn ("read from routing socket failed"); 645 return; 646 } 647 648 if (ifMsg.ifm_version != RTM_VERSION) { 649 650 Warn ("unexpected packet read from routing socket"); 651 return; 652 } 653 654 if (verbose) 655 printf ("Routing message %#x received.\n", ifMsg.ifm_type); 656 657 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) && 658 ifMsg.ifm_index == ifIndex) { 659 if (verbose) 660 printf("Interface address/MTU has probably changed.\n"); 661 assignAliasAddr = 1; 662 } 663 } 664 665 static void PrintPacket (struct ip* ip) 666 { 667 printf ("%s", FormatPacket (ip)); 668 } 669 670 static void SyslogPacket (struct ip* ip, int priority, const char *label) 671 { 672 syslog (priority, "%s %s", label, FormatPacket (ip)); 673 } 674 675 static char* FormatPacket (struct ip* ip) 676 { 677 static char buf[256]; 678 struct tcphdr* tcphdr; 679 struct udphdr* udphdr; 680 struct icmp* icmphdr; 681 char src[20]; 682 char dst[20]; 683 684 strcpy (src, inet_ntoa (ip->ip_src)); 685 strcpy (dst, inet_ntoa (ip->ip_dst)); 686 687 switch (ip->ip_p) { 688 case IPPROTO_TCP: 689 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 690 sprintf (buf, "[TCP] %s:%d -> %s:%d", 691 src, 692 ntohs (tcphdr->th_sport), 693 dst, 694 ntohs (tcphdr->th_dport)); 695 break; 696 697 case IPPROTO_UDP: 698 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 699 sprintf (buf, "[UDP] %s:%d -> %s:%d", 700 src, 701 ntohs (udphdr->uh_sport), 702 dst, 703 ntohs (udphdr->uh_dport)); 704 break; 705 706 case IPPROTO_ICMP: 707 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 708 sprintf (buf, "[ICMP] %s -> %s %u(%u)", 709 src, 710 dst, 711 icmphdr->icmp_type, 712 icmphdr->icmp_code); 713 break; 714 715 default: 716 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 717 break; 718 } 719 720 return buf; 721 } 722 723 static void 724 SetAliasAddressFromIfName(const char *ifn) 725 { 726 size_t needed; 727 int mib[6]; 728 char *buf, *lim, *next; 729 struct if_msghdr *ifm; 730 struct ifa_msghdr *ifam; 731 struct sockaddr_dl *sdl; 732 struct sockaddr_in *sin; 733 734 mib[0] = CTL_NET; 735 mib[1] = PF_ROUTE; 736 mib[2] = 0; 737 mib[3] = AF_INET; /* Only IP addresses please */ 738 mib[4] = NET_RT_IFLIST; 739 mib[5] = 0; /* ifIndex??? */ 740 /* 741 * Get interface data. 742 */ 743 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 744 err(1, "iflist-sysctl-estimate"); 745 if ((buf = malloc(needed)) == NULL) 746 errx(1, "malloc failed"); 747 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 748 err(1, "iflist-sysctl-get"); 749 lim = buf + needed; 750 /* 751 * Loop through interfaces until one with 752 * given name is found. This is done to 753 * find correct interface index for routing 754 * message processing. 755 */ 756 ifIndex = 0; 757 next = buf; 758 while (next < lim) { 759 ifm = (struct if_msghdr *)next; 760 next += ifm->ifm_msglen; 761 if (ifm->ifm_version != RTM_VERSION) { 762 if (verbose) 763 warnx("routing message version %d " 764 "not understood", ifm->ifm_version); 765 continue; 766 } 767 if (ifm->ifm_type == RTM_IFINFO) { 768 sdl = (struct sockaddr_dl *)(ifm + 1); 769 if (strlen(ifn) == sdl->sdl_nlen && 770 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 771 ifIndex = ifm->ifm_index; 772 ifMTU = ifm->ifm_data.ifi_mtu; 773 break; 774 } 775 } 776 } 777 if (!ifIndex) 778 errx(1, "unknown interface name %s", ifn); 779 /* 780 * Get interface address. 781 */ 782 sin = NULL; 783 while (next < lim) { 784 ifam = (struct ifa_msghdr *)next; 785 next += ifam->ifam_msglen; 786 if (ifam->ifam_version != RTM_VERSION) { 787 if (verbose) 788 warnx("routing message version %d " 789 "not understood", ifam->ifam_version); 790 continue; 791 } 792 if (ifam->ifam_type != RTM_NEWADDR) 793 break; 794 if (ifam->ifam_addrs & RTA_IFA) { 795 int i; 796 char *cp = (char *)(ifam + 1); 797 798 #define ROUNDUP(a) \ 799 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 800 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 801 802 for (i = 1; i < RTA_IFA; i <<= 1) 803 if (ifam->ifam_addrs & i) 804 ADVANCE(cp, (struct sockaddr *)cp); 805 if (((struct sockaddr *)cp)->sa_family == AF_INET) { 806 sin = (struct sockaddr_in *)cp; 807 break; 808 } 809 } 810 } 811 if (sin == NULL) 812 errx(1, "%s: cannot get interface address", ifn); 813 814 PacketAliasSetAddress(sin->sin_addr); 815 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", 816 inet_ntoa(sin->sin_addr), ifMTU); 817 818 free(buf); 819 } 820 821 void Quit (const char* msg) 822 { 823 Warn (msg); 824 exit (1); 825 } 826 827 void Warn (const char* msg) 828 { 829 if (background) 830 syslog (LOG_ALERT, "%s (%m)", msg); 831 else 832 warn ("%s", msg); 833 } 834 835 static void RefreshAddr (int sig) 836 { 837 if (ifName) 838 assignAliasAddr = 1; 839 } 840 841 static void InitiateShutdown (int sig) 842 { 843 /* 844 * Start timer to allow kernel gracefully 845 * shutdown existing connections when system 846 * is shut down. 847 */ 848 siginterrupt(SIGALRM, 1); 849 signal (SIGALRM, Shutdown); 850 alarm (10); 851 } 852 853 static void Shutdown (int sig) 854 { 855 running = 0; 856 } 857 858 /* 859 * Different options recognized by this program. 860 */ 861 862 enum Option { 863 864 PacketAliasOption, 865 Verbose, 866 InPort, 867 OutPort, 868 Port, 869 AliasAddress, 870 TargetAddress, 871 InterfaceName, 872 RedirectPort, 873 RedirectProto, 874 RedirectAddress, 875 ConfigFile, 876 DynamicMode, 877 ProxyRule, 878 LogDenied, 879 LogFacility, 880 PunchFW, 881 LogIpfwDenied 882 }; 883 884 enum Param { 885 886 YesNo, 887 Numeric, 888 String, 889 None, 890 Address, 891 Service 892 }; 893 894 /* 895 * Option information structure (used by ParseOption). 896 */ 897 898 struct OptionInfo { 899 900 enum Option type; 901 int packetAliasOpt; 902 enum Param parm; 903 const char* parmDescription; 904 const char* description; 905 const char* name; 906 const char* shortName; 907 }; 908 909 /* 910 * Table of known options. 911 */ 912 913 static struct OptionInfo optionTable[] = { 914 915 { PacketAliasOption, 916 PKT_ALIAS_UNREGISTERED_ONLY, 917 YesNo, 918 "[yes|no]", 919 "alias only unregistered addresses", 920 "unregistered_only", 921 "u" }, 922 923 { PacketAliasOption, 924 PKT_ALIAS_LOG, 925 YesNo, 926 "[yes|no]", 927 "enable logging", 928 "log", 929 "l" }, 930 931 { PacketAliasOption, 932 PKT_ALIAS_PROXY_ONLY, 933 YesNo, 934 "[yes|no]", 935 "proxy only", 936 "proxy_only", 937 NULL }, 938 939 { PacketAliasOption, 940 PKT_ALIAS_REVERSE, 941 YesNo, 942 "[yes|no]", 943 "operate in reverse mode", 944 "reverse", 945 NULL }, 946 947 { PacketAliasOption, 948 PKT_ALIAS_DENY_INCOMING, 949 YesNo, 950 "[yes|no]", 951 "allow incoming connections", 952 "deny_incoming", 953 "d" }, 954 955 { PacketAliasOption, 956 PKT_ALIAS_USE_SOCKETS, 957 YesNo, 958 "[yes|no]", 959 "use sockets to inhibit port conflict", 960 "use_sockets", 961 "s" }, 962 963 { PacketAliasOption, 964 PKT_ALIAS_SAME_PORTS, 965 YesNo, 966 "[yes|no]", 967 "try to keep original port numbers for connections", 968 "same_ports", 969 "m" }, 970 971 { Verbose, 972 0, 973 YesNo, 974 "[yes|no]", 975 "verbose mode, dump packet information", 976 "verbose", 977 "v" }, 978 979 { DynamicMode, 980 0, 981 YesNo, 982 "[yes|no]", 983 "dynamic mode, automatically detect interface address changes", 984 "dynamic", 985 NULL }, 986 987 { InPort, 988 0, 989 Service, 990 "number|service_name", 991 "set port for incoming packets", 992 "in_port", 993 "i" }, 994 995 { OutPort, 996 0, 997 Service, 998 "number|service_name", 999 "set port for outgoing packets", 1000 "out_port", 1001 "o" }, 1002 1003 { Port, 1004 0, 1005 Service, 1006 "number|service_name", 1007 "set port (defaults to natd/divert)", 1008 "port", 1009 "p" }, 1010 1011 { AliasAddress, 1012 0, 1013 Address, 1014 "x.x.x.x", 1015 "address to use for aliasing", 1016 "alias_address", 1017 "a" }, 1018 1019 { TargetAddress, 1020 0, 1021 Address, 1022 "x.x.x.x", 1023 "address to use for incoming sessions", 1024 "target_address", 1025 "t" }, 1026 1027 { InterfaceName, 1028 0, 1029 String, 1030 "network_if_name", 1031 "take aliasing address from interface", 1032 "interface", 1033 "n" }, 1034 1035 { ProxyRule, 1036 0, 1037 String, 1038 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 1039 "a.b.c.d:yyyy", 1040 "add transparent proxying / destination NAT", 1041 "proxy_rule", 1042 NULL }, 1043 1044 { RedirectPort, 1045 0, 1046 String, 1047 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range" 1048 " [remote_addr[:remote_port_range]]", 1049 "redirect a port (or ports) for incoming traffic", 1050 "redirect_port", 1051 NULL }, 1052 1053 { RedirectProto, 1054 0, 1055 String, 1056 "proto local_addr [public_addr] [remote_addr]", 1057 "redirect packets of a given proto", 1058 "redirect_proto", 1059 NULL }, 1060 1061 { RedirectAddress, 1062 0, 1063 String, 1064 "local_addr[,...] public_addr", 1065 "define mapping between local and public addresses", 1066 "redirect_address", 1067 NULL }, 1068 1069 { ConfigFile, 1070 0, 1071 String, 1072 "file_name", 1073 "read options from configuration file", 1074 "config", 1075 "f" }, 1076 1077 { LogDenied, 1078 0, 1079 YesNo, 1080 "[yes|no]", 1081 "enable logging of denied incoming packets", 1082 "log_denied", 1083 NULL }, 1084 1085 { LogFacility, 1086 0, 1087 String, 1088 "facility", 1089 "name of syslog facility to use for logging", 1090 "log_facility", 1091 NULL }, 1092 1093 { PunchFW, 1094 0, 1095 String, 1096 "basenumber:count", 1097 "punch holes in the firewall for incoming FTP/IRC DCC connections", 1098 "punch_fw", 1099 NULL }, 1100 1101 { LogIpfwDenied, 1102 0, 1103 YesNo, 1104 "[yes|no]", 1105 "log packets converted by natd, but denied by ipfw", 1106 "log_ipfw_denied", 1107 NULL }, 1108 }; 1109 1110 static void ParseOption (const char* option, const char* parms) 1111 { 1112 int i; 1113 struct OptionInfo* info; 1114 int yesNoValue; 1115 int aliasValue; 1116 int numValue; 1117 u_short uNumValue; 1118 const char* strValue; 1119 struct in_addr addrValue; 1120 int max; 1121 char* end; 1122 CODE* fac_record = NULL; 1123 /* 1124 * Find option from table. 1125 */ 1126 max = sizeof (optionTable) / sizeof (struct OptionInfo); 1127 for (i = 0, info = optionTable; i < max; i++, info++) { 1128 1129 if (!strcmp (info->name, option)) 1130 break; 1131 1132 if (info->shortName) 1133 if (!strcmp (info->shortName, option)) 1134 break; 1135 } 1136 1137 if (i >= max) { 1138 1139 warnx ("unknown option %s", option); 1140 Usage (); 1141 } 1142 1143 uNumValue = 0; 1144 yesNoValue = 0; 1145 numValue = 0; 1146 strValue = NULL; 1147 /* 1148 * Check parameters. 1149 */ 1150 switch (info->parm) { 1151 case YesNo: 1152 if (!parms) 1153 parms = "yes"; 1154 1155 if (!strcmp (parms, "yes")) 1156 yesNoValue = 1; 1157 else 1158 if (!strcmp (parms, "no")) 1159 yesNoValue = 0; 1160 else 1161 errx (1, "%s needs yes/no parameter", option); 1162 break; 1163 1164 case Service: 1165 if (!parms) 1166 errx (1, "%s needs service name or " 1167 "port number parameter", 1168 option); 1169 1170 uNumValue = StrToPort (parms, "divert"); 1171 break; 1172 1173 case Numeric: 1174 if (parms) 1175 numValue = strtol (parms, &end, 10); 1176 else 1177 end = NULL; 1178 1179 if (end == parms) 1180 errx (1, "%s needs numeric parameter", option); 1181 break; 1182 1183 case String: 1184 strValue = parms; 1185 if (!strValue) 1186 errx (1, "%s needs parameter", option); 1187 break; 1188 1189 case None: 1190 if (parms) 1191 errx (1, "%s does not take parameters", option); 1192 break; 1193 1194 case Address: 1195 if (!parms) 1196 errx (1, "%s needs address/host parameter", option); 1197 1198 StrToAddr (parms, &addrValue); 1199 break; 1200 } 1201 1202 switch (info->type) { 1203 case PacketAliasOption: 1204 1205 aliasValue = yesNoValue ? info->packetAliasOpt : 0; 1206 PacketAliasSetMode (aliasValue, info->packetAliasOpt); 1207 break; 1208 1209 case Verbose: 1210 verbose = yesNoValue; 1211 break; 1212 1213 case DynamicMode: 1214 dynamicMode = yesNoValue; 1215 break; 1216 1217 case InPort: 1218 inPort = uNumValue; 1219 break; 1220 1221 case OutPort: 1222 outPort = uNumValue; 1223 break; 1224 1225 case Port: 1226 inOutPort = uNumValue; 1227 break; 1228 1229 case AliasAddress: 1230 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr)); 1231 break; 1232 1233 case TargetAddress: 1234 PacketAliasSetTarget(addrValue); 1235 break; 1236 1237 case RedirectPort: 1238 SetupPortRedirect (strValue); 1239 break; 1240 1241 case RedirectProto: 1242 SetupProtoRedirect(strValue); 1243 break; 1244 1245 case RedirectAddress: 1246 SetupAddressRedirect (strValue); 1247 break; 1248 1249 case ProxyRule: 1250 PacketAliasProxyRule (strValue); 1251 break; 1252 1253 case InterfaceName: 1254 if (ifName) 1255 free (ifName); 1256 1257 ifName = strdup (strValue); 1258 break; 1259 1260 case ConfigFile: 1261 ReadConfigFile (strValue); 1262 break; 1263 1264 case LogDenied: 1265 logDropped = yesNoValue; 1266 break; 1267 1268 case LogFacility: 1269 1270 fac_record = facilitynames; 1271 while (fac_record->c_name != NULL) { 1272 1273 if (!strcmp (fac_record->c_name, strValue)) { 1274 1275 logFacility = fac_record->c_val; 1276 break; 1277 1278 } 1279 else 1280 fac_record++; 1281 } 1282 1283 if(fac_record->c_name == NULL) 1284 errx(1, "Unknown log facility name: %s", strValue); 1285 1286 break; 1287 1288 case PunchFW: 1289 SetupPunchFW(strValue); 1290 break; 1291 1292 case LogIpfwDenied: 1293 logIpfwDenied = yesNoValue;; 1294 break; 1295 } 1296 } 1297 1298 void ReadConfigFile (const char* fileName) 1299 { 1300 FILE* file; 1301 char *buf; 1302 size_t len; 1303 char *ptr, *p; 1304 char* option; 1305 1306 file = fopen (fileName, "r"); 1307 if (!file) 1308 err(1, "cannot open config file %s", fileName); 1309 1310 while ((buf = fgetln(file, &len)) != NULL) { 1311 if (buf[len - 1] == '\n') 1312 buf[len - 1] = '\0'; 1313 else 1314 errx(1, "config file format error: " 1315 "last line should end with newline"); 1316 1317 /* 1318 * Check for comments, strip off trailing spaces. 1319 */ 1320 if ((ptr = strchr(buf, '#'))) 1321 *ptr = '\0'; 1322 for (ptr = buf; isspace(*ptr); ++ptr) 1323 continue; 1324 if (*ptr == '\0') 1325 continue; 1326 for (p = strchr(buf, '\0'); isspace(*--p);) 1327 continue; 1328 *++p = '\0'; 1329 1330 /* 1331 * Extract option name. 1332 */ 1333 option = ptr; 1334 while (*ptr && !isspace (*ptr)) 1335 ++ptr; 1336 1337 if (*ptr != '\0') { 1338 1339 *ptr = '\0'; 1340 ++ptr; 1341 } 1342 /* 1343 * Skip white space between name and parms. 1344 */ 1345 while (*ptr && isspace (*ptr)) 1346 ++ptr; 1347 1348 ParseOption (option, *ptr ? ptr : NULL); 1349 } 1350 1351 fclose (file); 1352 } 1353 1354 static void Usage () 1355 { 1356 int i; 1357 int max; 1358 struct OptionInfo* info; 1359 1360 fprintf (stderr, "Recognized options:\n\n"); 1361 1362 max = sizeof (optionTable) / sizeof (struct OptionInfo); 1363 for (i = 0, info = optionTable; i < max; i++, info++) { 1364 1365 fprintf (stderr, "-%-20s %s\n", info->name, 1366 info->parmDescription); 1367 1368 if (info->shortName) 1369 fprintf (stderr, "-%-20s %s\n", info->shortName, 1370 info->parmDescription); 1371 1372 fprintf (stderr, " %s\n\n", info->description); 1373 } 1374 1375 exit (1); 1376 } 1377 1378 void SetupPortRedirect (const char* parms) 1379 { 1380 char buf[128]; 1381 char* ptr; 1382 char* serverPool; 1383 struct in_addr localAddr; 1384 struct in_addr publicAddr; 1385 struct in_addr remoteAddr; 1386 port_range portRange; 1387 u_short localPort = 0; 1388 u_short publicPort = 0; 1389 u_short remotePort = 0; 1390 u_short numLocalPorts = 0; 1391 u_short numPublicPorts = 0; 1392 u_short numRemotePorts = 0; 1393 int proto; 1394 char* protoName; 1395 char* separator; 1396 int i; 1397 struct alias_link *link = NULL; 1398 1399 strcpy (buf, parms); 1400 /* 1401 * Extract protocol. 1402 */ 1403 protoName = strtok (buf, " \t"); 1404 if (!protoName) 1405 errx (1, "redirect_port: missing protocol"); 1406 1407 proto = StrToProto (protoName); 1408 /* 1409 * Extract local address. 1410 */ 1411 ptr = strtok (NULL, " \t"); 1412 if (!ptr) 1413 errx (1, "redirect_port: missing local address"); 1414 1415 separator = strchr(ptr, ','); 1416 if (separator) { /* LSNAT redirection syntax. */ 1417 localAddr.s_addr = INADDR_NONE; 1418 localPort = ~0; 1419 numLocalPorts = 1; 1420 serverPool = ptr; 1421 } else { 1422 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) 1423 errx (1, "redirect_port: invalid local port range"); 1424 1425 localPort = GETLOPORT(portRange); 1426 numLocalPorts = GETNUMPORTS(portRange); 1427 serverPool = NULL; 1428 } 1429 1430 /* 1431 * Extract public port and optionally address. 1432 */ 1433 ptr = strtok (NULL, " \t"); 1434 if (!ptr) 1435 errx (1, "redirect_port: missing public port"); 1436 1437 separator = strchr (ptr, ':'); 1438 if (separator) { 1439 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) 1440 errx (1, "redirect_port: invalid public port range"); 1441 } 1442 else { 1443 publicAddr.s_addr = INADDR_ANY; 1444 if (StrToPortRange (ptr, protoName, &portRange) != 0) 1445 errx (1, "redirect_port: invalid public port range"); 1446 } 1447 1448 publicPort = GETLOPORT(portRange); 1449 numPublicPorts = GETNUMPORTS(portRange); 1450 1451 /* 1452 * Extract remote address and optionally port. 1453 */ 1454 ptr = strtok (NULL, " \t"); 1455 if (ptr) { 1456 separator = strchr (ptr, ':'); 1457 if (separator) { 1458 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) 1459 errx (1, "redirect_port: invalid remote port range"); 1460 } else { 1461 SETLOPORT(portRange, 0); 1462 SETNUMPORTS(portRange, 1); 1463 StrToAddr (ptr, &remoteAddr); 1464 } 1465 } 1466 else { 1467 SETLOPORT(portRange, 0); 1468 SETNUMPORTS(portRange, 1); 1469 remoteAddr.s_addr = INADDR_ANY; 1470 } 1471 1472 remotePort = GETLOPORT(portRange); 1473 numRemotePorts = GETNUMPORTS(portRange); 1474 1475 /* 1476 * Make sure port ranges match up, then add the redirect ports. 1477 */ 1478 if (numLocalPorts != numPublicPorts) 1479 errx (1, "redirect_port: port ranges must be equal in size"); 1480 1481 /* Remote port range is allowed to be '0' which means all ports. */ 1482 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) 1483 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); 1484 1485 for (i = 0 ; i < numPublicPorts ; ++i) { 1486 /* If remotePort is all ports, set it to 0. */ 1487 u_short remotePortCopy = remotePort + i; 1488 if (numRemotePorts == 1 && remotePort == 0) 1489 remotePortCopy = 0; 1490 1491 link = PacketAliasRedirectPort (localAddr, 1492 htons(localPort + i), 1493 remoteAddr, 1494 htons(remotePortCopy), 1495 publicAddr, 1496 htons(publicPort + i), 1497 proto); 1498 } 1499 1500 /* 1501 * Setup LSNAT server pool. 1502 */ 1503 if (serverPool != NULL && link != NULL) { 1504 ptr = strtok(serverPool, ","); 1505 while (ptr != NULL) { 1506 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0) 1507 errx(1, "redirect_port: invalid local port range"); 1508 1509 localPort = GETLOPORT(portRange); 1510 if (GETNUMPORTS(portRange) != 1) 1511 errx(1, "redirect_port: local port must be single in this context"); 1512 PacketAliasAddServer(link, localAddr, htons(localPort)); 1513 ptr = strtok(NULL, ","); 1514 } 1515 } 1516 } 1517 1518 void 1519 SetupProtoRedirect(const char* parms) 1520 { 1521 char buf[128]; 1522 char* ptr; 1523 struct in_addr localAddr; 1524 struct in_addr publicAddr; 1525 struct in_addr remoteAddr; 1526 int proto; 1527 char* protoName; 1528 struct protoent *protoent; 1529 1530 strcpy (buf, parms); 1531 /* 1532 * Extract protocol. 1533 */ 1534 protoName = strtok(buf, " \t"); 1535 if (!protoName) 1536 errx(1, "redirect_proto: missing protocol"); 1537 1538 protoent = getprotobyname(protoName); 1539 if (protoent == NULL) 1540 errx(1, "redirect_proto: unknown protocol %s", protoName); 1541 else 1542 proto = protoent->p_proto; 1543 /* 1544 * Extract local address. 1545 */ 1546 ptr = strtok(NULL, " \t"); 1547 if (!ptr) 1548 errx(1, "redirect_proto: missing local address"); 1549 else 1550 StrToAddr(ptr, &localAddr); 1551 /* 1552 * Extract optional public address. 1553 */ 1554 ptr = strtok(NULL, " \t"); 1555 if (ptr) 1556 StrToAddr(ptr, &publicAddr); 1557 else 1558 publicAddr.s_addr = INADDR_ANY; 1559 /* 1560 * Extract optional remote address. 1561 */ 1562 ptr = strtok(NULL, " \t"); 1563 if (ptr) 1564 StrToAddr(ptr, &remoteAddr); 1565 else 1566 remoteAddr.s_addr = INADDR_ANY; 1567 /* 1568 * Create aliasing link. 1569 */ 1570 (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr, 1571 proto); 1572 } 1573 1574 void SetupAddressRedirect (const char* parms) 1575 { 1576 char buf[128]; 1577 char* ptr; 1578 char* separator; 1579 struct in_addr localAddr; 1580 struct in_addr publicAddr; 1581 char* serverPool; 1582 struct alias_link *link; 1583 1584 strcpy (buf, parms); 1585 /* 1586 * Extract local address. 1587 */ 1588 ptr = strtok (buf, " \t"); 1589 if (!ptr) 1590 errx (1, "redirect_address: missing local address"); 1591 1592 separator = strchr(ptr, ','); 1593 if (separator) { /* LSNAT redirection syntax. */ 1594 localAddr.s_addr = INADDR_NONE; 1595 serverPool = ptr; 1596 } else { 1597 StrToAddr (ptr, &localAddr); 1598 serverPool = NULL; 1599 } 1600 /* 1601 * Extract public address. 1602 */ 1603 ptr = strtok (NULL, " \t"); 1604 if (!ptr) 1605 errx (1, "redirect_address: missing public address"); 1606 1607 StrToAddr (ptr, &publicAddr); 1608 link = PacketAliasRedirectAddr(localAddr, publicAddr); 1609 1610 /* 1611 * Setup LSNAT server pool. 1612 */ 1613 if (serverPool != NULL && link != NULL) { 1614 ptr = strtok(serverPool, ","); 1615 while (ptr != NULL) { 1616 StrToAddr(ptr, &localAddr); 1617 PacketAliasAddServer(link, localAddr, htons(~0)); 1618 ptr = strtok(NULL, ","); 1619 } 1620 } 1621 } 1622 1623 void StrToAddr (const char* str, struct in_addr* addr) 1624 { 1625 struct hostent* hp; 1626 1627 if (inet_aton (str, addr)) 1628 return; 1629 1630 hp = gethostbyname (str); 1631 if (!hp) 1632 errx (1, "unknown host %s", str); 1633 1634 memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 1635 } 1636 1637 u_short StrToPort (const char* str, const char* proto) 1638 { 1639 u_short port; 1640 struct servent* sp; 1641 char* end; 1642 1643 port = strtol (str, &end, 10); 1644 if (end != str) 1645 return htons (port); 1646 1647 sp = getservbyname (str, proto); 1648 if (!sp) 1649 errx (1, "unknown service %s/%s", str, proto); 1650 1651 return sp->s_port; 1652 } 1653 1654 int StrToPortRange (const char* str, const char* proto, port_range *portRange) 1655 { 1656 char* sep; 1657 struct servent* sp; 1658 char* end; 1659 u_short loPort; 1660 u_short hiPort; 1661 1662 /* First see if this is a service, return corresponding port if so. */ 1663 sp = getservbyname (str,proto); 1664 if (sp) { 1665 SETLOPORT(*portRange, ntohs(sp->s_port)); 1666 SETNUMPORTS(*portRange, 1); 1667 return 0; 1668 } 1669 1670 /* Not a service, see if it's a single port or port range. */ 1671 sep = strchr (str, '-'); 1672 if (sep == NULL) { 1673 SETLOPORT(*portRange, strtol(str, &end, 10)); 1674 if (end != str) { 1675 /* Single port. */ 1676 SETNUMPORTS(*portRange, 1); 1677 return 0; 1678 } 1679 1680 /* Error in port range field. */ 1681 errx (1, "unknown service %s/%s", str, proto); 1682 } 1683 1684 /* Port range, get the values and sanity check. */ 1685 sscanf (str, "%hu-%hu", &loPort, &hiPort); 1686 SETLOPORT(*portRange, loPort); 1687 SETNUMPORTS(*portRange, 0); /* Error by default */ 1688 if (loPort <= hiPort) 1689 SETNUMPORTS(*portRange, hiPort - loPort + 1); 1690 1691 if (GETNUMPORTS(*portRange) == 0) 1692 errx (1, "invalid port range %s", str); 1693 1694 return 0; 1695 } 1696 1697 1698 int StrToProto (const char* str) 1699 { 1700 if (!strcmp (str, "tcp")) 1701 return IPPROTO_TCP; 1702 1703 if (!strcmp (str, "udp")) 1704 return IPPROTO_UDP; 1705 1706 errx (1, "unknown protocol %s. Expected tcp or udp", str); 1707 } 1708 1709 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 1710 { 1711 char* ptr; 1712 1713 ptr = strchr (str, ':'); 1714 if (!ptr) 1715 errx (1, "%s is missing port number", str); 1716 1717 *ptr = '\0'; 1718 ++ptr; 1719 1720 StrToAddr (str, addr); 1721 return StrToPortRange (ptr, proto, portRange); 1722 } 1723 1724 static void 1725 SetupPunchFW(const char *strValue) 1726 { 1727 unsigned int base, num; 1728 1729 if (sscanf(strValue, "%u:%u", &base, &num) != 2) 1730 errx(1, "punch_fw: basenumber:count parameter required"); 1731 1732 PacketAliasSetFWBase(base, num); 1733 (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 1734 } 1735