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/time.h> 20 21 #include <netinet/in.h> 22 #include <netinet/in_systm.h> 23 #include <netinet/ip.h> 24 #include <machine/in_cksum.h> 25 #include <netinet/tcp.h> 26 #include <netinet/udp.h> 27 #include <netinet/ip_icmp.h> 28 #include <sys/ioctl.h> 29 #include <net/if.h> 30 #include <net/route.h> 31 #include <arpa/inet.h> 32 33 #include <alias.h> 34 #include <ctype.h> 35 #include <err.h> 36 #include <errno.h> 37 #include <netdb.h> 38 #include <signal.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <unistd.h> 44 45 #include "natd.h" 46 47 /* 48 * Default values for input and output 49 * divert socket ports. 50 */ 51 52 #define DEFAULT_SERVICE "natd" 53 54 /* 55 * Definition of a port range, and macros to deal with values. 56 * FORMAT: HI 16-bits == first port in range, 0 == all ports. 57 * LO 16-bits == number of ports in range 58 * NOTES: - Port values are not stored in network byte order. 59 */ 60 61 typedef u_long port_range; 62 63 #define GETLOPORT(x) ((x) >> 0x10) 64 #define GETNUMPORTS(x) ((x) & 0x0000ffff) 65 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 66 67 /* Set y to be the low-port value in port_range variable x. */ 68 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 69 70 /* Set y to be the number of ports in port_range variable x. */ 71 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 72 73 /* 74 * Function prototypes. 75 */ 76 77 static void DoAliasing (int fd, int direction); 78 static void DaemonMode (void); 79 static void HandleRoutingInfo (int fd); 80 static void Usage (void); 81 static char* FormatPacket (struct ip*); 82 static void PrintPacket (struct ip*); 83 static void SyslogPacket (struct ip*, int priority, const char *label); 84 static void SetAliasAddressFromIfName (char* ifName); 85 static void InitiateShutdown (int); 86 static void Shutdown (int); 87 static void RefreshAddr (int); 88 static void ParseOption (const char* option, const char* parms, int cmdLine); 89 static void ReadConfigFile (const char* fileName); 90 static void SetupPortRedirect (const char* parms); 91 static void SetupAddressRedirect (const char* parms); 92 static void SetupPptpAlias (const char* parms); 93 static void StrToAddr (const char* str, struct in_addr* addr); 94 static u_short StrToPort (const char* str, const char* proto); 95 static int StrToPortRange (const char* str, const char* proto, port_range *portRange); 96 static int StrToProto (const char* str); 97 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange); 98 static void ParseArgs (int argc, char** argv); 99 static void FlushPacketBuffer (int fd); 100 101 /* 102 * Globals. 103 */ 104 105 static int verbose; 106 static int background; 107 static int running; 108 static int assignAliasAddr; 109 static char* ifName; 110 static int ifIndex; 111 static u_short inPort; 112 static u_short outPort; 113 static u_short inOutPort; 114 static struct in_addr aliasAddr; 115 static int dynamicMode; 116 static int ifMTU; 117 static int aliasOverhead; 118 static int icmpSock; 119 static char packetBuf[IP_MAXPACKET]; 120 static int packetLen; 121 static struct sockaddr_in packetAddr; 122 static int packetSock; 123 static int packetDirection; 124 static int dropIgnoredIncoming; 125 static int logDropped; 126 static int logFacility; 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 fd_set writeMask; 137 int fdMax; 138 /* 139 * Initialize packet aliasing software. 140 * Done already here to be able to alter option bits 141 * during command line and configuration file processing. 142 */ 143 PacketAliasInit (); 144 /* 145 * Parse options. 146 */ 147 inPort = 0; 148 outPort = 0; 149 verbose = 0; 150 inOutPort = 0; 151 ifName = NULL; 152 ifMTU = -1; 153 background = 0; 154 running = 1; 155 assignAliasAddr = 0; 156 aliasAddr.s_addr = INADDR_NONE; 157 aliasOverhead = 12; 158 dynamicMode = 0; 159 logDropped = 0; 160 logFacility = LOG_DAEMON; 161 /* 162 * Mark packet buffer empty. 163 */ 164 packetSock = -1; 165 packetDirection = DONT_KNOW; 166 167 ParseArgs (argc, argv); 168 /* 169 * Open syslog channel. 170 */ 171 openlog ("natd", LOG_CONS | LOG_PID, logFacility); 172 /* 173 * Check that valid aliasing address has been given. 174 */ 175 if (aliasAddr.s_addr == INADDR_NONE && ifName == NULL) 176 errx (1, "aliasing address not given"); 177 178 if (aliasAddr.s_addr != INADDR_NONE && ifName != NULL) 179 errx (1, "both alias address and interface " 180 "name are not allowed"); 181 /* 182 * Check that valid port number is known. 183 */ 184 if (inPort != 0 || outPort != 0) 185 if (inPort == 0 || outPort == 0) 186 errx (1, "both input and output ports are required"); 187 188 if (inPort == 0 && outPort == 0 && inOutPort == 0) 189 ParseOption ("port", DEFAULT_SERVICE, 0); 190 191 /* 192 * Check if ignored packets should be dropped. 193 */ 194 dropIgnoredIncoming = PacketAliasSetMode (0, 0); 195 dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; 196 /* 197 * Create divert sockets. Use only one socket if -p was specified 198 * on command line. Otherwise, create separate sockets for 199 * outgoing and incoming connnections. 200 */ 201 if (inOutPort) { 202 203 divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 204 if (divertInOut == -1) 205 Quit ("Unable to create divert socket."); 206 207 divertIn = -1; 208 divertOut = -1; 209 /* 210 * Bind socket. 211 */ 212 213 addr.sin_family = AF_INET; 214 addr.sin_addr.s_addr = INADDR_ANY; 215 addr.sin_port = inOutPort; 216 217 if (bind (divertInOut, 218 (struct sockaddr*) &addr, 219 sizeof addr) == -1) 220 Quit ("Unable to bind divert socket."); 221 } 222 else { 223 224 divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 225 if (divertIn == -1) 226 Quit ("Unable to create incoming divert socket."); 227 228 divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 229 if (divertOut == -1) 230 Quit ("Unable to create outgoing divert socket."); 231 232 divertInOut = -1; 233 234 /* 235 * Bind divert sockets. 236 */ 237 238 addr.sin_family = AF_INET; 239 addr.sin_addr.s_addr = INADDR_ANY; 240 addr.sin_port = inPort; 241 242 if (bind (divertIn, 243 (struct sockaddr*) &addr, 244 sizeof addr) == -1) 245 Quit ("Unable to bind incoming divert socket."); 246 247 addr.sin_family = AF_INET; 248 addr.sin_addr.s_addr = INADDR_ANY; 249 addr.sin_port = outPort; 250 251 if (bind (divertOut, 252 (struct sockaddr*) &addr, 253 sizeof addr) == -1) 254 Quit ("Unable to bind outgoing divert socket."); 255 } 256 /* 257 * Create routing socket if interface name specified. 258 */ 259 if (ifName && dynamicMode) { 260 261 routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 262 if (routeSock == -1) 263 Quit ("Unable to create routing info socket."); 264 } 265 else 266 routeSock = -1; 267 /* 268 * Create socket for sending ICMP messages. 269 */ 270 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 271 if (icmpSock == -1) 272 Quit ("Unable to create ICMP socket."); 273 274 /* 275 * And disable reads for the socket, otherwise it slowly fills 276 * up with received icmps which we do not use. 277 */ 278 shutdown(icmpSock, SHUT_RD); 279 280 /* 281 * Become a daemon unless verbose mode was requested. 282 */ 283 if (!verbose) 284 DaemonMode (); 285 /* 286 * Catch signals to manage shutdown and 287 * refresh of interface address. 288 */ 289 siginterrupt(SIGTERM, 1); 290 siginterrupt(SIGHUP, 1); 291 signal (SIGTERM, InitiateShutdown); 292 signal (SIGHUP, RefreshAddr); 293 /* 294 * Set alias address if it has been given. 295 */ 296 if (aliasAddr.s_addr != INADDR_NONE) 297 PacketAliasSetAddress (aliasAddr); 298 /* 299 * We need largest descriptor number for select. 300 */ 301 302 fdMax = -1; 303 304 if (divertIn > fdMax) 305 fdMax = divertIn; 306 307 if (divertOut > fdMax) 308 fdMax = divertOut; 309 310 if (divertInOut > fdMax) 311 fdMax = divertInOut; 312 313 if (routeSock > fdMax) 314 fdMax = routeSock; 315 316 while (running) { 317 318 if (divertInOut != -1 && !ifName && packetSock == -1) { 319 /* 320 * When using only one socket, just call 321 * DoAliasing repeatedly to process packets. 322 */ 323 DoAliasing (divertInOut, DONT_KNOW); 324 continue; 325 } 326 /* 327 * Build read mask from socket descriptors to select. 328 */ 329 FD_ZERO (&readMask); 330 FD_ZERO (&writeMask); 331 332 /* 333 * If there is unsent packet in buffer, use select 334 * to check when socket comes writable again. 335 */ 336 if (packetSock != -1) { 337 338 FD_SET (packetSock, &writeMask); 339 } 340 else { 341 /* 342 * No unsent packet exists - safe to check if 343 * new ones are available. 344 */ 345 if (divertIn != -1) 346 FD_SET (divertIn, &readMask); 347 348 if (divertOut != -1) 349 FD_SET (divertOut, &readMask); 350 351 if (divertInOut != -1) 352 FD_SET (divertInOut, &readMask); 353 } 354 /* 355 * Routing info is processed always. 356 */ 357 if (routeSock != -1) 358 FD_SET (routeSock, &readMask); 359 360 if (select (fdMax + 1, 361 &readMask, 362 &writeMask, 363 NULL, 364 NULL) == -1) { 365 366 if (errno == EINTR) 367 continue; 368 369 Quit ("Select failed."); 370 } 371 372 if (packetSock != -1) 373 if (FD_ISSET (packetSock, &writeMask)) 374 FlushPacketBuffer (packetSock); 375 376 if (divertIn != -1) 377 if (FD_ISSET (divertIn, &readMask)) 378 DoAliasing (divertIn, INPUT); 379 380 if (divertOut != -1) 381 if (FD_ISSET (divertOut, &readMask)) 382 DoAliasing (divertOut, OUTPUT); 383 384 if (divertInOut != -1) 385 if (FD_ISSET (divertInOut, &readMask)) 386 DoAliasing (divertInOut, DONT_KNOW); 387 388 if (routeSock != -1) 389 if (FD_ISSET (routeSock, &readMask)) 390 HandleRoutingInfo (routeSock); 391 } 392 393 if (background) 394 unlink (PIDFILE); 395 396 return 0; 397 } 398 399 static void DaemonMode () 400 { 401 FILE* pidFile; 402 403 daemon (0, 0); 404 background = 1; 405 406 pidFile = fopen (PIDFILE, "w"); 407 if (pidFile) { 408 409 fprintf (pidFile, "%d\n", getpid ()); 410 fclose (pidFile); 411 } 412 } 413 414 static void ParseArgs (int argc, char** argv) 415 { 416 int arg; 417 char* parm; 418 char* opt; 419 char parmBuf[256]; 420 421 for (arg = 1; arg < argc; arg++) { 422 423 opt = argv[arg]; 424 if (*opt != '-') { 425 426 warnx ("invalid option %s", opt); 427 Usage (); 428 } 429 430 parm = NULL; 431 parmBuf[0] = '\0'; 432 433 while (arg < argc - 1) { 434 435 if (argv[arg + 1][0] == '-') 436 break; 437 438 if (parm) 439 strcat (parmBuf, " "); 440 441 ++arg; 442 parm = parmBuf; 443 strcat (parmBuf, argv[arg]); 444 } 445 446 ParseOption (opt + 1, parm, 1); 447 } 448 } 449 450 static void DoAliasing (int fd, int direction) 451 { 452 int bytes; 453 int origBytes; 454 int status; 455 int addrSize; 456 struct ip* ip; 457 458 if (assignAliasAddr) { 459 460 SetAliasAddressFromIfName (ifName); 461 assignAliasAddr = 0; 462 } 463 /* 464 * Get packet from socket. 465 */ 466 addrSize = sizeof packetAddr; 467 origBytes = recvfrom (fd, 468 packetBuf, 469 sizeof packetBuf, 470 0, 471 (struct sockaddr*) &packetAddr, 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 a IP packet. 483 */ 484 ip = (struct ip*) packetBuf; 485 if (direction == DONT_KNOW) { 486 if (packetAddr.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 (packetBuf, IP_MAXPACKET); 526 } 527 else { 528 529 /* 530 * Do aliasing. 531 */ 532 status = PacketAliasIn (packetBuf, 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 packetLen = bytes; 568 packetSock = fd; 569 packetDirection = direction; 570 571 FlushPacketBuffer (fd); 572 } 573 574 static void FlushPacketBuffer (int fd) 575 { 576 int wrote; 577 char msgBuf[80]; 578 /* 579 * Put packet back for processing. 580 */ 581 wrote = sendto (fd, 582 packetBuf, 583 packetLen, 584 0, 585 (struct sockaddr*) &packetAddr, 586 sizeof packetAddr); 587 588 if (wrote != packetLen) { 589 /* 590 * If buffer space is not available, 591 * just return. Main loop will take care of 592 * retrying send when space becomes available. 593 */ 594 if (errno == ENOBUFS) 595 return; 596 597 if (errno == EMSGSIZE) { 598 599 if (packetDirection == OUTPUT && 600 ifMTU != -1) 601 SendNeedFragIcmp (icmpSock, 602 (struct ip*) packetBuf, 603 ifMTU - aliasOverhead); 604 } 605 else { 606 607 sprintf (msgBuf, "failed to write packet back"); 608 Warn (msgBuf); 609 } 610 } 611 612 packetSock = -1; 613 } 614 615 static void HandleRoutingInfo (int fd) 616 { 617 int bytes; 618 struct if_msghdr ifMsg; 619 /* 620 * Get packet from socket. 621 */ 622 bytes = read (fd, &ifMsg, sizeof ifMsg); 623 if (bytes == -1) { 624 625 Warn ("read from routing socket failed"); 626 return; 627 } 628 629 if (ifMsg.ifm_version != RTM_VERSION) { 630 631 Warn ("unexpected packet read from routing socket"); 632 return; 633 } 634 635 if (verbose) 636 printf ("Routing message %X received.\n", ifMsg.ifm_type); 637 638 if (ifMsg.ifm_type != RTM_NEWADDR) 639 return; 640 641 if (verbose && ifMsg.ifm_index == ifIndex) 642 printf ("Interface address has changed.\n"); 643 644 if (ifMsg.ifm_index == ifIndex) 645 assignAliasAddr = 1; 646 } 647 648 static void PrintPacket (struct ip* ip) 649 { 650 printf ("%s", FormatPacket (ip)); 651 } 652 653 static void SyslogPacket (struct ip* ip, int priority, const char *label) 654 { 655 syslog (priority, "%s %s", label, FormatPacket (ip)); 656 } 657 658 static char* FormatPacket (struct ip* ip) 659 { 660 static char buf[256]; 661 struct tcphdr* tcphdr; 662 struct udphdr* udphdr; 663 struct icmp* icmphdr; 664 char src[20]; 665 char dst[20]; 666 667 strcpy (src, inet_ntoa (ip->ip_src)); 668 strcpy (dst, inet_ntoa (ip->ip_dst)); 669 670 switch (ip->ip_p) { 671 case IPPROTO_TCP: 672 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 673 sprintf (buf, "[TCP] %s:%d -> %s:%d", 674 src, 675 ntohs (tcphdr->th_sport), 676 dst, 677 ntohs (tcphdr->th_dport)); 678 break; 679 680 case IPPROTO_UDP: 681 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 682 sprintf (buf, "[UDP] %s:%d -> %s:%d", 683 src, 684 ntohs (udphdr->uh_sport), 685 dst, 686 ntohs (udphdr->uh_dport)); 687 break; 688 689 case IPPROTO_ICMP: 690 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 691 sprintf (buf, "[ICMP] %s -> %s %u(%u)", 692 src, 693 dst, 694 icmphdr->icmp_type, 695 icmphdr->icmp_code); 696 break; 697 698 default: 699 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 700 break; 701 } 702 703 return buf; 704 } 705 706 static void SetAliasAddressFromIfName (char* ifn) 707 { 708 struct ifconf cf; 709 struct ifreq buf[32]; 710 char msg[80]; 711 struct ifreq* ifPtr; 712 int extra; 713 int helperSock; 714 int bytes; 715 struct sockaddr_in* addr; 716 int found; 717 struct ifreq req; 718 char last[10]; 719 /* 720 * Create a dummy socket to access interface information. 721 */ 722 helperSock = socket (AF_INET, SOCK_DGRAM, 0); 723 if (helperSock == -1) { 724 725 Quit ("Failed to create helper socket."); 726 exit (1); 727 } 728 729 cf.ifc_len = sizeof (buf); 730 cf.ifc_req = buf; 731 /* 732 * Get interface data. 733 */ 734 if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) { 735 736 Quit ("Ioctl SIOCGIFCONF failed."); 737 exit (1); 738 } 739 740 ifIndex = 0; 741 ifPtr = buf; 742 bytes = cf.ifc_len; 743 found = 0; 744 last[0] = '\0'; 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 while (bytes) { 752 753 if (ifPtr->ifr_addr.sa_family == AF_INET && 754 !strcmp (ifPtr->ifr_name, ifn)) { 755 756 found = 1; 757 break; 758 } 759 760 if (strcmp (last, ifPtr->ifr_name)) { 761 762 strcpy (last, ifPtr->ifr_name); 763 ++ifIndex; 764 } 765 766 extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr); 767 if (extra < 0) 768 extra = 0; 769 770 ifPtr++; 771 ifPtr = (struct ifreq*) ((char*) ifPtr + extra); 772 bytes -= sizeof (struct ifreq) + extra; 773 } 774 775 if (!found) { 776 777 close (helperSock); 778 sprintf (msg, "Unknown interface name %s.\n", ifn); 779 Quit (msg); 780 } 781 /* 782 * Get MTU size. 783 */ 784 strcpy (req.ifr_name, ifn); 785 786 if (ioctl (helperSock, SIOCGIFMTU, &req) == -1) 787 Quit ("Cannot get interface mtu size."); 788 789 ifMTU = req.ifr_mtu; 790 /* 791 * Get interface address. 792 */ 793 if (ioctl (helperSock, SIOCGIFADDR, &req) == -1) 794 Quit ("Cannot get interface address."); 795 796 addr = (struct sockaddr_in*) &req.ifr_addr; 797 PacketAliasSetAddress (addr->sin_addr); 798 syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes", 799 inet_ntoa (addr->sin_addr), 800 ifMTU); 801 802 close (helperSock); 803 } 804 805 void Quit (const char* msg) 806 { 807 Warn (msg); 808 exit (1); 809 } 810 811 void Warn (const char* msg) 812 { 813 if (background) 814 syslog (LOG_ALERT, "%s (%m)", msg); 815 else 816 warn (msg); 817 } 818 819 static void RefreshAddr (int sig) 820 { 821 if (ifName) 822 assignAliasAddr = 1; 823 } 824 825 static void InitiateShutdown (int sig) 826 { 827 /* 828 * Start timer to allow kernel gracefully 829 * shutdown existing connections when system 830 * is shut down. 831 */ 832 siginterrupt(SIGALRM, 1); 833 signal (SIGALRM, Shutdown); 834 alarm (10); 835 } 836 837 static void Shutdown (int sig) 838 { 839 running = 0; 840 } 841 842 /* 843 * Different options recognized by this program. 844 */ 845 846 enum Option { 847 848 PacketAliasOption, 849 Verbose, 850 InPort, 851 OutPort, 852 Port, 853 AliasAddress, 854 InterfaceName, 855 RedirectPort, 856 RedirectAddress, 857 ConfigFile, 858 DynamicMode, 859 PptpAlias, 860 ProxyRule, 861 LogDenied, 862 LogFacility 863 }; 864 865 enum Param { 866 867 YesNo, 868 Numeric, 869 String, 870 None, 871 Address, 872 Service 873 }; 874 875 /* 876 * Option information structure (used by ParseOption). 877 */ 878 879 struct OptionInfo { 880 881 enum Option type; 882 int packetAliasOpt; 883 enum Param parm; 884 const char* parmDescription; 885 const char* description; 886 const char* name; 887 const char* shortName; 888 }; 889 890 /* 891 * Table of known options. 892 */ 893 894 static struct OptionInfo optionTable[] = { 895 896 { PacketAliasOption, 897 PKT_ALIAS_UNREGISTERED_ONLY, 898 YesNo, 899 "[yes|no]", 900 "alias only unregistered addresses", 901 "unregistered_only", 902 "u" }, 903 904 { PacketAliasOption, 905 PKT_ALIAS_LOG, 906 YesNo, 907 "[yes|no]", 908 "enable logging", 909 "log", 910 "l" }, 911 912 { PacketAliasOption, 913 PKT_ALIAS_PROXY_ONLY, 914 YesNo, 915 "[yes|no]", 916 "proxy only", 917 "proxy_only", 918 NULL }, 919 920 { PacketAliasOption, 921 PKT_ALIAS_REVERSE, 922 YesNo, 923 "[yes|no]", 924 "operate in reverse mode", 925 "reverse", 926 NULL }, 927 928 { PacketAliasOption, 929 PKT_ALIAS_DENY_INCOMING, 930 YesNo, 931 "[yes|no]", 932 "allow incoming connections", 933 "deny_incoming", 934 "d" }, 935 936 { PacketAliasOption, 937 PKT_ALIAS_USE_SOCKETS, 938 YesNo, 939 "[yes|no]", 940 "use sockets to inhibit port conflict", 941 "use_sockets", 942 "s" }, 943 944 { PacketAliasOption, 945 PKT_ALIAS_SAME_PORTS, 946 YesNo, 947 "[yes|no]", 948 "try to keep original port numbers for connections", 949 "same_ports", 950 "m" }, 951 952 { Verbose, 953 0, 954 YesNo, 955 "[yes|no]", 956 "verbose mode, dump packet information", 957 "verbose", 958 "v" }, 959 960 { DynamicMode, 961 0, 962 YesNo, 963 "[yes|no]", 964 "dynamic mode, automatically detect interface address changes", 965 "dynamic", 966 NULL }, 967 968 { InPort, 969 0, 970 Service, 971 "number|service_name", 972 "set port for incoming packets", 973 "in_port", 974 "i" }, 975 976 { OutPort, 977 0, 978 Service, 979 "number|service_name", 980 "set port for outgoing packets", 981 "out_port", 982 "o" }, 983 984 { Port, 985 0, 986 Service, 987 "number|service_name", 988 "set port (defaults to natd/divert)", 989 "port", 990 "p" }, 991 992 { AliasAddress, 993 0, 994 Address, 995 "x.x.x.x", 996 "address to use for aliasing", 997 "alias_address", 998 "a" }, 999 1000 { InterfaceName, 1001 0, 1002 String, 1003 "network_if_name", 1004 "take aliasing address from interface", 1005 "interface", 1006 "n" }, 1007 1008 { ProxyRule, 1009 0, 1010 String, 1011 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 1012 "a.b.c.d:yyyy", 1013 "add transparent proxying / destination NAT", 1014 "proxy_rule", 1015 NULL }, 1016 1017 { RedirectPort, 1018 0, 1019 String, 1020 "tcp|udp local_addr:local_port_range [public_addr:]public_port_range" 1021 " [remote_addr[:remote_port_range]]", 1022 "redirect a port (or ports) for incoming traffic", 1023 "redirect_port", 1024 NULL }, 1025 1026 { RedirectAddress, 1027 0, 1028 String, 1029 "local_addr public_addr", 1030 "define mapping between local and public addresses", 1031 "redirect_address", 1032 NULL }, 1033 1034 { PptpAlias, 1035 0, 1036 String, 1037 "src", 1038 "define inside machine for PPTP traffic", 1039 "pptpalias", 1040 NULL }, 1041 1042 { ConfigFile, 1043 0, 1044 String, 1045 "file_name", 1046 "read options from configuration file", 1047 "config", 1048 "f" }, 1049 1050 { LogDenied, 1051 0, 1052 YesNo, 1053 "[yes|no]", 1054 "enable logging of denied incoming packets", 1055 "log_denied", 1056 NULL }, 1057 1058 { LogFacility, 1059 0, 1060 String, 1061 "facility", 1062 "name of syslog facility to use for logging", 1063 "log_facility", 1064 NULL } 1065 1066 }; 1067 1068 static void ParseOption (const char* option, const char* parms, int cmdLine) 1069 { 1070 int i; 1071 struct OptionInfo* info; 1072 int yesNoValue; 1073 int aliasValue; 1074 int numValue; 1075 u_short uNumValue; 1076 const char* strValue; 1077 struct in_addr addrValue; 1078 int max; 1079 char* end; 1080 CODE* fac_record = NULL; 1081 /* 1082 * Find option from table. 1083 */ 1084 max = sizeof (optionTable) / sizeof (struct OptionInfo); 1085 for (i = 0, info = optionTable; i < max; i++, info++) { 1086 1087 if (!strcmp (info->name, option)) 1088 break; 1089 1090 if (info->shortName) 1091 if (!strcmp (info->shortName, option)) 1092 break; 1093 } 1094 1095 if (i >= max) { 1096 1097 warnx ("unknown option %s", option); 1098 Usage (); 1099 } 1100 1101 uNumValue = 0; 1102 yesNoValue = 0; 1103 numValue = 0; 1104 strValue = NULL; 1105 /* 1106 * Check parameters. 1107 */ 1108 switch (info->parm) { 1109 case YesNo: 1110 if (!parms) 1111 parms = "yes"; 1112 1113 if (!strcmp (parms, "yes")) 1114 yesNoValue = 1; 1115 else 1116 if (!strcmp (parms, "no")) 1117 yesNoValue = 0; 1118 else 1119 errx (1, "%s needs yes/no parameter", option); 1120 break; 1121 1122 case Service: 1123 if (!parms) 1124 errx (1, "%s needs service name or " 1125 "port number parameter", 1126 option); 1127 1128 uNumValue = StrToPort (parms, "divert"); 1129 break; 1130 1131 case Numeric: 1132 if (parms) 1133 numValue = strtol (parms, &end, 10); 1134 else 1135 end = NULL; 1136 1137 if (end == parms) 1138 errx (1, "%s needs numeric parameter", option); 1139 break; 1140 1141 case String: 1142 strValue = parms; 1143 if (!strValue) 1144 errx (1, "%s needs parameter", option); 1145 break; 1146 1147 case None: 1148 if (parms) 1149 errx (1, "%s does not take parameters", option); 1150 break; 1151 1152 case Address: 1153 if (!parms) 1154 errx (1, "%s needs address/host parameter", option); 1155 1156 StrToAddr (parms, &addrValue); 1157 break; 1158 } 1159 1160 switch (info->type) { 1161 case PacketAliasOption: 1162 1163 aliasValue = yesNoValue ? info->packetAliasOpt : 0; 1164 PacketAliasSetMode (aliasValue, info->packetAliasOpt); 1165 break; 1166 1167 case Verbose: 1168 verbose = yesNoValue; 1169 break; 1170 1171 case DynamicMode: 1172 dynamicMode = yesNoValue; 1173 break; 1174 1175 case InPort: 1176 inPort = uNumValue; 1177 break; 1178 1179 case OutPort: 1180 outPort = uNumValue; 1181 break; 1182 1183 case Port: 1184 inOutPort = uNumValue; 1185 break; 1186 1187 case AliasAddress: 1188 memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr)); 1189 break; 1190 1191 case RedirectPort: 1192 SetupPortRedirect (strValue); 1193 break; 1194 1195 case RedirectAddress: 1196 SetupAddressRedirect (strValue); 1197 break; 1198 1199 case PptpAlias: 1200 SetupPptpAlias (strValue); 1201 break; 1202 1203 case ProxyRule: 1204 PacketAliasProxyRule (strValue); 1205 break; 1206 1207 case InterfaceName: 1208 if (ifName) 1209 free (ifName); 1210 1211 ifName = strdup (strValue); 1212 assignAliasAddr = 1; 1213 break; 1214 1215 case ConfigFile: 1216 ReadConfigFile (strValue); 1217 break; 1218 1219 case LogDenied: 1220 logDropped = 1; 1221 break; 1222 1223 case LogFacility: 1224 1225 fac_record = facilitynames; 1226 while (fac_record->c_name != NULL) { 1227 1228 if (!strcmp (fac_record->c_name, strValue)) { 1229 1230 logFacility = fac_record->c_val; 1231 break; 1232 1233 } 1234 else 1235 fac_record++; 1236 } 1237 1238 if(fac_record->c_name == NULL) 1239 errx(1, "Unknown log facility name: %s", strValue); 1240 1241 break; 1242 } 1243 } 1244 1245 void ReadConfigFile (const char* fileName) 1246 { 1247 FILE* file; 1248 char buf[128]; 1249 char* ptr; 1250 char* option; 1251 1252 file = fopen (fileName, "r"); 1253 if (!file) { 1254 1255 sprintf (buf, "Cannot open config file %s.\n", fileName); 1256 Quit (buf); 1257 } 1258 1259 while (fgets (buf, sizeof (buf), file)) { 1260 1261 ptr = strchr (buf, '\n'); 1262 if (!ptr) 1263 errx (1, "config line too long: %s", buf); 1264 1265 *ptr = '\0'; 1266 if (buf[0] == '#') 1267 continue; 1268 1269 ptr = buf; 1270 /* 1271 * Skip white space at beginning of line. 1272 */ 1273 while (*ptr && isspace (*ptr)) 1274 ++ptr; 1275 1276 if (*ptr == '\0') 1277 continue; 1278 /* 1279 * Extract option name. 1280 */ 1281 option = ptr; 1282 while (*ptr && !isspace (*ptr)) 1283 ++ptr; 1284 1285 if (*ptr != '\0') { 1286 1287 *ptr = '\0'; 1288 ++ptr; 1289 } 1290 /* 1291 * Skip white space between name and parms. 1292 */ 1293 while (*ptr && isspace (*ptr)) 1294 ++ptr; 1295 1296 ParseOption (option, *ptr ? ptr : NULL, 0); 1297 } 1298 1299 fclose (file); 1300 } 1301 1302 static void Usage () 1303 { 1304 int i; 1305 int max; 1306 struct OptionInfo* info; 1307 1308 fprintf (stderr, "Recognized options:\n\n"); 1309 1310 max = sizeof (optionTable) / sizeof (struct OptionInfo); 1311 for (i = 0, info = optionTable; i < max; i++, info++) { 1312 1313 fprintf (stderr, "-%-20s %s\n", info->name, 1314 info->parmDescription); 1315 1316 if (info->shortName) 1317 fprintf (stderr, "-%-20s %s\n", info->shortName, 1318 info->parmDescription); 1319 1320 fprintf (stderr, " %s\n\n", info->description); 1321 } 1322 1323 exit (1); 1324 } 1325 1326 void SetupPptpAlias (const char* parms) 1327 { 1328 char buf[128]; 1329 char* ptr; 1330 struct in_addr srcAddr; 1331 1332 strcpy (buf, parms); 1333 1334 /* 1335 * Extract source address. 1336 */ 1337 ptr = strtok (buf, " \t"); 1338 if (!ptr) 1339 errx(1, "pptpalias: missing src address"); 1340 1341 StrToAddr (ptr, &srcAddr); 1342 PacketAliasPptp (srcAddr); 1343 } 1344 1345 void SetupPortRedirect (const char* parms) 1346 { 1347 char buf[128]; 1348 char* ptr; 1349 struct in_addr localAddr; 1350 struct in_addr publicAddr; 1351 struct in_addr remoteAddr; 1352 port_range portRange; 1353 u_short localPort = 0; 1354 u_short publicPort = 0; 1355 u_short remotePort = 0; 1356 u_short numLocalPorts = 0; 1357 u_short numPublicPorts = 0; 1358 u_short numRemotePorts = 0; 1359 int proto; 1360 char* protoName; 1361 char* separator; 1362 int i; 1363 1364 strcpy (buf, parms); 1365 /* 1366 * Extract protocol. 1367 */ 1368 protoName = strtok (buf, " \t"); 1369 if (!protoName) 1370 errx (1, "redirect_port: missing protocol"); 1371 1372 proto = StrToProto (protoName); 1373 /* 1374 * Extract local address. 1375 */ 1376 ptr = strtok (NULL, " \t"); 1377 if (!ptr) 1378 errx (1, "redirect_port: missing local address"); 1379 1380 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) 1381 errx (1, "redirect_port: invalid local port range"); 1382 1383 localPort = GETLOPORT(portRange); 1384 numLocalPorts = GETNUMPORTS(portRange); 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 PacketAliasRedirectPort (localAddr, 1448 htons(localPort + i), 1449 remoteAddr, 1450 htons(remotePortCopy), 1451 publicAddr, 1452 htons(publicPort + i), 1453 proto); 1454 } 1455 } 1456 1457 void SetupAddressRedirect (const char* parms) 1458 { 1459 char buf[128]; 1460 char* ptr; 1461 struct in_addr localAddr; 1462 struct in_addr publicAddr; 1463 1464 strcpy (buf, parms); 1465 /* 1466 * Extract local address. 1467 */ 1468 ptr = strtok (buf, " \t"); 1469 if (!ptr) 1470 errx (1, "redirect_address: missing local address"); 1471 1472 StrToAddr (ptr, &localAddr); 1473 /* 1474 * Extract public address. 1475 */ 1476 ptr = strtok (NULL, " \t"); 1477 if (!ptr) 1478 errx (1, "redirect_address: missing public address"); 1479 1480 StrToAddr (ptr, &publicAddr); 1481 PacketAliasRedirectAddr (localAddr, publicAddr); 1482 } 1483 1484 void StrToAddr (const char* str, struct in_addr* addr) 1485 { 1486 struct hostent* hp; 1487 1488 if (inet_aton (str, addr)) 1489 return; 1490 1491 hp = gethostbyname (str); 1492 if (!hp) 1493 errx (1, "unknown host %s", str); 1494 1495 memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 1496 } 1497 1498 u_short StrToPort (const char* str, const char* proto) 1499 { 1500 u_short port; 1501 struct servent* sp; 1502 char* end; 1503 1504 port = strtol (str, &end, 10); 1505 if (end != str) 1506 return htons (port); 1507 1508 sp = getservbyname (str, proto); 1509 if (!sp) 1510 errx (1, "unknown service %s/%s", str, proto); 1511 1512 return sp->s_port; 1513 } 1514 1515 int StrToPortRange (const char* str, const char* proto, port_range *portRange) 1516 { 1517 char* sep; 1518 struct servent* sp; 1519 char* end; 1520 u_short loPort; 1521 u_short hiPort; 1522 1523 /* First see if this is a service, return corresponding port if so. */ 1524 sp = getservbyname (str,proto); 1525 if (sp) { 1526 SETLOPORT(*portRange, ntohs(sp->s_port)); 1527 SETNUMPORTS(*portRange, 1); 1528 return 0; 1529 } 1530 1531 /* Not a service, see if it's a single port or port range. */ 1532 sep = strchr (str, '-'); 1533 if (sep == NULL) { 1534 SETLOPORT(*portRange, strtol(str, &end, 10)); 1535 if (end != str) { 1536 /* Single port. */ 1537 SETNUMPORTS(*portRange, 1); 1538 return 0; 1539 } 1540 1541 /* Error in port range field. */ 1542 errx (1, "unknown service %s/%s", str, proto); 1543 } 1544 1545 /* Port range, get the values and sanity check. */ 1546 sscanf (str, "%hu-%hu", &loPort, &hiPort); 1547 SETLOPORT(*portRange, loPort); 1548 SETNUMPORTS(*portRange, 0); /* Error by default */ 1549 if (loPort <= hiPort) 1550 SETNUMPORTS(*portRange, hiPort - loPort + 1); 1551 1552 if (GETNUMPORTS(*portRange) == 0) 1553 errx (1, "invalid port range %s", str); 1554 1555 return 0; 1556 } 1557 1558 1559 int StrToProto (const char* str) 1560 { 1561 if (!strcmp (str, "tcp")) 1562 return IPPROTO_TCP; 1563 1564 if (!strcmp (str, "udp")) 1565 return IPPROTO_UDP; 1566 1567 errx (1, "unknown protocol %s. Expected tcp or udp", str); 1568 } 1569 1570 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 1571 { 1572 char* ptr; 1573 1574 ptr = strchr (str, ':'); 1575 if (!ptr) 1576 errx (1, "%s is missing port number", str); 1577 1578 *ptr = '\0'; 1579 ++ptr; 1580 1581 StrToAddr (str, addr); 1582 return StrToPortRange (ptr, proto, portRange); 1583 } 1584