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