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