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