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 signal (SIGTERM, InitiateShutdown); 290 signal (SIGHUP, RefreshAddr); 291 /* 292 * Set alias address if it has been given. 293 */ 294 if (aliasAddr.s_addr != INADDR_NONE) 295 PacketAliasSetAddress (aliasAddr); 296 /* 297 * We need largest descriptor number for select. 298 */ 299 300 fdMax = -1; 301 302 if (divertIn > fdMax) 303 fdMax = divertIn; 304 305 if (divertOut > fdMax) 306 fdMax = divertOut; 307 308 if (divertInOut > fdMax) 309 fdMax = divertInOut; 310 311 if (routeSock > fdMax) 312 fdMax = routeSock; 313 314 while (running) { 315 316 if (divertInOut != -1 && !ifName && packetSock == -1) { 317 /* 318 * When using only one socket, just call 319 * DoAliasing repeatedly to process packets. 320 */ 321 DoAliasing (divertInOut, DONT_KNOW); 322 continue; 323 } 324 /* 325 * Build read mask from socket descriptors to select. 326 */ 327 FD_ZERO (&readMask); 328 FD_ZERO (&writeMask); 329 330 /* 331 * If there is unsent packet in buffer, use select 332 * to check when socket comes writable again. 333 */ 334 if (packetSock != -1) { 335 336 FD_SET (packetSock, &writeMask); 337 } 338 else { 339 /* 340 * No unsent packet exists - safe to check if 341 * new ones are available. 342 */ 343 if (divertIn != -1) 344 FD_SET (divertIn, &readMask); 345 346 if (divertOut != -1) 347 FD_SET (divertOut, &readMask); 348 349 if (divertInOut != -1) 350 FD_SET (divertInOut, &readMask); 351 } 352 /* 353 * Routing info is processed always. 354 */ 355 if (routeSock != -1) 356 FD_SET (routeSock, &readMask); 357 358 if (select (fdMax + 1, 359 &readMask, 360 &writeMask, 361 NULL, 362 NULL) == -1) { 363 364 if (errno == EINTR) 365 continue; 366 367 Quit ("Select failed."); 368 } 369 370 if (packetSock != -1) 371 if (FD_ISSET (packetSock, &writeMask)) 372 FlushPacketBuffer (packetSock); 373 374 if (divertIn != -1) 375 if (FD_ISSET (divertIn, &readMask)) 376 DoAliasing (divertIn, INPUT); 377 378 if (divertOut != -1) 379 if (FD_ISSET (divertOut, &readMask)) 380 DoAliasing (divertOut, OUTPUT); 381 382 if (divertInOut != -1) 383 if (FD_ISSET (divertInOut, &readMask)) 384 DoAliasing (divertInOut, DONT_KNOW); 385 386 if (routeSock != -1) 387 if (FD_ISSET (routeSock, &readMask)) 388 HandleRoutingInfo (routeSock); 389 } 390 391 if (background) 392 unlink (PIDFILE); 393 394 return 0; 395 } 396 397 static void DaemonMode () 398 { 399 FILE* pidFile; 400 401 daemon (0, 0); 402 background = 1; 403 404 pidFile = fopen (PIDFILE, "w"); 405 if (pidFile) { 406 407 fprintf (pidFile, "%d\n", getpid ()); 408 fclose (pidFile); 409 } 410 } 411 412 static void ParseArgs (int argc, char** argv) 413 { 414 int arg; 415 char* parm; 416 char* opt; 417 char parmBuf[256]; 418 419 for (arg = 1; arg < argc; arg++) { 420 421 opt = argv[arg]; 422 if (*opt != '-') { 423 424 warnx ("invalid option %s", opt); 425 Usage (); 426 } 427 428 parm = NULL; 429 parmBuf[0] = '\0'; 430 431 while (arg < argc - 1) { 432 433 if (argv[arg + 1][0] == '-') 434 break; 435 436 if (parm) 437 strcat (parmBuf, " "); 438 439 ++arg; 440 parm = parmBuf; 441 strcat (parmBuf, argv[arg]); 442 } 443 444 ParseOption (opt + 1, parm, 1); 445 } 446 } 447 448 static void DoAliasing (int fd, int direction) 449 { 450 int bytes; 451 int origBytes; 452 int status; 453 int addrSize; 454 struct ip* ip; 455 456 if (assignAliasAddr) { 457 458 SetAliasAddressFromIfName (ifName); 459 assignAliasAddr = 0; 460 } 461 /* 462 * Get packet from socket. 463 */ 464 addrSize = sizeof packetAddr; 465 origBytes = recvfrom (fd, 466 packetBuf, 467 sizeof packetBuf, 468 0, 469 (struct sockaddr*) &packetAddr, 470 &addrSize); 471 472 if (origBytes == -1) { 473 474 if (errno != EINTR) 475 Warn ("read from divert socket failed"); 476 477 return; 478 } 479 /* 480 * This is a IP packet. 481 */ 482 ip = (struct ip*) packetBuf; 483 if (direction == DONT_KNOW) { 484 if (packetAddr.sin_addr.s_addr == INADDR_ANY) 485 direction = OUTPUT; 486 else 487 direction = INPUT; 488 } 489 490 if (verbose) { 491 /* 492 * Print packet direction and protocol type. 493 */ 494 printf (direction == OUTPUT ? "Out " : "In "); 495 496 switch (ip->ip_p) { 497 case IPPROTO_TCP: 498 printf ("[TCP] "); 499 break; 500 501 case IPPROTO_UDP: 502 printf ("[UDP] "); 503 break; 504 505 case IPPROTO_ICMP: 506 printf ("[ICMP] "); 507 break; 508 509 default: 510 printf ("[%d] ", ip->ip_p); 511 break; 512 } 513 /* 514 * Print addresses. 515 */ 516 PrintPacket (ip); 517 } 518 519 if (direction == OUTPUT) { 520 /* 521 * Outgoing packets. Do aliasing. 522 */ 523 PacketAliasOut (packetBuf, IP_MAXPACKET); 524 } 525 else { 526 527 /* 528 * Do aliasing. 529 */ 530 status = PacketAliasIn (packetBuf, IP_MAXPACKET); 531 if (status == PKT_ALIAS_IGNORED && 532 dropIgnoredIncoming) { 533 534 if (verbose) 535 printf (" dropped.\n"); 536 537 if (logDropped) 538 SyslogPacket (ip, LOG_WARNING, "denied"); 539 540 return; 541 } 542 } 543 /* 544 * Length might have changed during aliasing. 545 */ 546 bytes = ntohs (ip->ip_len); 547 /* 548 * Update alias overhead size for outgoing packets. 549 */ 550 if (direction == OUTPUT && 551 bytes - origBytes > aliasOverhead) 552 aliasOverhead = bytes - origBytes; 553 554 if (verbose) { 555 556 /* 557 * Print addresses after aliasing. 558 */ 559 printf (" aliased to\n"); 560 printf (" "); 561 PrintPacket (ip); 562 printf ("\n"); 563 } 564 565 packetLen = bytes; 566 packetSock = fd; 567 packetDirection = direction; 568 569 FlushPacketBuffer (fd); 570 } 571 572 static void FlushPacketBuffer (int fd) 573 { 574 int wrote; 575 char msgBuf[80]; 576 /* 577 * Put packet back for processing. 578 */ 579 wrote = sendto (fd, 580 packetBuf, 581 packetLen, 582 0, 583 (struct sockaddr*) &packetAddr, 584 sizeof packetAddr); 585 586 if (wrote != packetLen) { 587 /* 588 * If buffer space is not available, 589 * just return. Main loop will take care of 590 * retrying send when space becomes available. 591 */ 592 if (errno == ENOBUFS) 593 return; 594 595 if (errno == EMSGSIZE) { 596 597 if (packetDirection == OUTPUT && 598 ifMTU != -1) 599 SendNeedFragIcmp (icmpSock, 600 (struct ip*) packetBuf, 601 ifMTU - aliasOverhead); 602 } 603 else { 604 605 sprintf (msgBuf, "failed to write packet back"); 606 Warn (msgBuf); 607 } 608 } 609 610 packetSock = -1; 611 } 612 613 static void HandleRoutingInfo (int fd) 614 { 615 int bytes; 616 struct if_msghdr ifMsg; 617 /* 618 * Get packet from socket. 619 */ 620 bytes = read (fd, &ifMsg, sizeof ifMsg); 621 if (bytes == -1) { 622 623 Warn ("read from routing socket failed"); 624 return; 625 } 626 627 if (ifMsg.ifm_version != RTM_VERSION) { 628 629 Warn ("unexpected packet read from routing socket"); 630 return; 631 } 632 633 if (verbose) 634 printf ("Routing message %X received.\n", ifMsg.ifm_type); 635 636 if (ifMsg.ifm_type != RTM_NEWADDR) 637 return; 638 639 if (verbose && ifMsg.ifm_index == ifIndex) 640 printf ("Interface address has changed.\n"); 641 642 if (ifMsg.ifm_index == ifIndex) 643 assignAliasAddr = 1; 644 } 645 646 static void PrintPacket (struct ip* ip) 647 { 648 printf ("%s", FormatPacket (ip)); 649 } 650 651 static void SyslogPacket (struct ip* ip, int priority, const char *label) 652 { 653 syslog (priority, "%s %s", label, FormatPacket (ip)); 654 } 655 656 static char* FormatPacket (struct ip* ip) 657 { 658 static char buf[256]; 659 struct tcphdr* tcphdr; 660 struct udphdr* udphdr; 661 struct icmp* icmphdr; 662 char src[20]; 663 char dst[20]; 664 665 strcpy (src, inet_ntoa (ip->ip_src)); 666 strcpy (dst, inet_ntoa (ip->ip_dst)); 667 668 switch (ip->ip_p) { 669 case IPPROTO_TCP: 670 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 671 sprintf (buf, "[TCP] %s:%d -> %s:%d", 672 src, 673 ntohs (tcphdr->th_sport), 674 dst, 675 ntohs (tcphdr->th_dport)); 676 break; 677 678 case IPPROTO_UDP: 679 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 680 sprintf (buf, "[UDP] %s:%d -> %s:%d", 681 src, 682 ntohs (udphdr->uh_sport), 683 dst, 684 ntohs (udphdr->uh_dport)); 685 break; 686 687 case IPPROTO_ICMP: 688 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 689 sprintf (buf, "[ICMP] %s -> %s %u(%u)", 690 src, 691 dst, 692 icmphdr->icmp_type, 693 icmphdr->icmp_code); 694 break; 695 696 default: 697 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 698 break; 699 } 700 701 return buf; 702 } 703 704 static void SetAliasAddressFromIfName (char* ifn) 705 { 706 struct ifconf cf; 707 struct ifreq buf[32]; 708 char msg[80]; 709 struct ifreq* ifPtr; 710 int extra; 711 int helperSock; 712 int bytes; 713 struct sockaddr_in* addr; 714 int found; 715 struct ifreq req; 716 char last[10]; 717 /* 718 * Create a dummy socket to access interface information. 719 */ 720 helperSock = socket (AF_INET, SOCK_DGRAM, 0); 721 if (helperSock == -1) { 722 723 Quit ("Failed to create helper socket."); 724 exit (1); 725 } 726 727 cf.ifc_len = sizeof (buf); 728 cf.ifc_req = buf; 729 /* 730 * Get interface data. 731 */ 732 if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) { 733 734 Quit ("Ioctl SIOCGIFCONF failed."); 735 exit (1); 736 } 737 738 ifIndex = 0; 739 ifPtr = buf; 740 bytes = cf.ifc_len; 741 found = 0; 742 last[0] = '\0'; 743 /* 744 * Loop through interfaces until one with 745 * given name is found. This is done to 746 * find correct interface index for routing 747 * message processing. 748 */ 749 while (bytes) { 750 751 if (ifPtr->ifr_addr.sa_family == AF_INET && 752 !strcmp (ifPtr->ifr_name, ifn)) { 753 754 found = 1; 755 break; 756 } 757 758 if (strcmp (last, ifPtr->ifr_name)) { 759 760 strcpy (last, ifPtr->ifr_name); 761 ++ifIndex; 762 } 763 764 extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr); 765 if (extra < 0) 766 extra = 0; 767 768 ifPtr++; 769 ifPtr = (struct ifreq*) ((char*) ifPtr + extra); 770 bytes -= sizeof (struct ifreq) + extra; 771 } 772 773 if (!found) { 774 775 close (helperSock); 776 sprintf (msg, "Unknown interface name %s.\n", ifn); 777 Quit (msg); 778 } 779 /* 780 * Get MTU size. 781 */ 782 strcpy (req.ifr_name, ifn); 783 784 if (ioctl (helperSock, SIOCGIFMTU, &req) == -1) 785 Quit ("Cannot get interface mtu size."); 786 787 ifMTU = req.ifr_mtu; 788 /* 789 * Get interface address. 790 */ 791 if (ioctl (helperSock, SIOCGIFADDR, &req) == -1) 792 Quit ("Cannot get interface address."); 793 794 addr = (struct sockaddr_in*) &req.ifr_addr; 795 PacketAliasSetAddress (addr->sin_addr); 796 syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes", 797 inet_ntoa (addr->sin_addr), 798 ifMTU); 799 800 close (helperSock); 801 } 802 803 void Quit (const char* msg) 804 { 805 Warn (msg); 806 exit (1); 807 } 808 809 void Warn (const char* msg) 810 { 811 if (background) 812 syslog (LOG_ALERT, "%s (%m)", msg); 813 else 814 warn (msg); 815 } 816 817 static void RefreshAddr (int sig) 818 { 819 signal (SIGHUP, RefreshAddr); 820 if (ifName) 821 assignAliasAddr = 1; 822 } 823 824 static void InitiateShutdown (int sig) 825 { 826 /* 827 * Start timer to allow kernel gracefully 828 * shutdown existing connections when system 829 * is shut down. 830 */ 831 signal (SIGALRM, Shutdown); 832 alarm (10); 833 } 834 835 static void Shutdown (int sig) 836 { 837 running = 0; 838 } 839 840 /* 841 * Different options recognized by this program. 842 */ 843 844 enum Option { 845 846 PacketAliasOption, 847 Verbose, 848 InPort, 849 OutPort, 850 Port, 851 AliasAddress, 852 InterfaceName, 853 RedirectPort, 854 RedirectAddress, 855 ConfigFile, 856 DynamicMode, 857 PptpAlias, 858 ProxyRule, 859 LogDenied, 860 LogFacility 861 }; 862 863 enum Param { 864 865 YesNo, 866 Numeric, 867 String, 868 None, 869 Address, 870 Service 871 }; 872 873 /* 874 * Option information structure (used by ParseOption). 875 */ 876 877 struct OptionInfo { 878 879 enum Option type; 880 int packetAliasOpt; 881 enum Param parm; 882 const char* parmDescription; 883 const char* description; 884 const char* name; 885 const char* shortName; 886 }; 887 888 /* 889 * Table of known options. 890 */ 891 892 static struct OptionInfo optionTable[] = { 893 894 { PacketAliasOption, 895 PKT_ALIAS_UNREGISTERED_ONLY, 896 YesNo, 897 "[yes|no]", 898 "alias only unregistered addresses", 899 "unregistered_only", 900 "u" }, 901 902 { PacketAliasOption, 903 PKT_ALIAS_LOG, 904 YesNo, 905 "[yes|no]", 906 "enable logging", 907 "log", 908 "l" }, 909 910 { PacketAliasOption, 911 PKT_ALIAS_PROXY_ONLY, 912 YesNo, 913 "[yes|no]", 914 "proxy only", 915 "proxy_only", 916 NULL }, 917 918 { PacketAliasOption, 919 PKT_ALIAS_REVERSE, 920 YesNo, 921 "[yes|no]", 922 "operate in reverse mode", 923 "reverse", 924 NULL }, 925 926 { PacketAliasOption, 927 PKT_ALIAS_DENY_INCOMING, 928 YesNo, 929 "[yes|no]", 930 "allow incoming connections", 931 "deny_incoming", 932 "d" }, 933 934 { PacketAliasOption, 935 PKT_ALIAS_USE_SOCKETS, 936 YesNo, 937 "[yes|no]", 938 "use sockets to inhibit port conflict", 939 "use_sockets", 940 "s" }, 941 942 { PacketAliasOption, 943 PKT_ALIAS_SAME_PORTS, 944 YesNo, 945 "[yes|no]", 946 "try to keep original port numbers for connections", 947 "same_ports", 948 "m" }, 949 950 { Verbose, 951 0, 952 YesNo, 953 "[yes|no]", 954 "verbose mode, dump packet information", 955 "verbose", 956 "v" }, 957 958 { DynamicMode, 959 0, 960 YesNo, 961 "[yes|no]", 962 "dynamic mode, automatically detect interface address changes", 963 "dynamic", 964 NULL }, 965 966 { InPort, 967 0, 968 Service, 969 "number|service_name", 970 "set port for incoming packets", 971 "in_port", 972 "i" }, 973 974 { OutPort, 975 0, 976 Service, 977 "number|service_name", 978 "set port for outgoing packets", 979 "out_port", 980 "o" }, 981 982 { Port, 983 0, 984 Service, 985 "number|service_name", 986 "set port (defaults to natd/divert)", 987 "port", 988 "p" }, 989 990 { AliasAddress, 991 0, 992 Address, 993 "x.x.x.x", 994 "address to use for aliasing", 995 "alias_address", 996 "a" }, 997 998 { InterfaceName, 999 0, 1000 String, 1001 "network_if_name", 1002 "take aliasing address from interface", 1003 "interface", 1004 "n" }, 1005 1006 { ProxyRule, 1007 0, 1008 String, 1009 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 1010 "a.b.c.d:yyyy", 1011 "add transparent proxying / destination NAT", 1012 "proxy_rule", 1013 NULL }, 1014 1015 { RedirectPort, 1016 0, 1017 String, 1018 "tcp|udp local_addr:local_port_range [public_addr:]public_port_range" 1019 " [remote_addr[:remote_port_range]]", 1020 "redirect a port (or ports) for incoming traffic", 1021 "redirect_port", 1022 NULL }, 1023 1024 { RedirectAddress, 1025 0, 1026 String, 1027 "local_addr public_addr", 1028 "define mapping between local and public addresses", 1029 "redirect_address", 1030 NULL }, 1031 1032 { PptpAlias, 1033 0, 1034 String, 1035 "src", 1036 "define inside machine for PPTP traffic", 1037 "pptpalias", 1038 NULL }, 1039 1040 { ConfigFile, 1041 0, 1042 String, 1043 "file_name", 1044 "read options from configuration file", 1045 "config", 1046 "f" }, 1047 1048 { LogDenied, 1049 0, 1050 YesNo, 1051 "[yes|no]", 1052 "enable logging of denied incoming packets", 1053 "log_denied", 1054 NULL }, 1055 1056 { LogFacility, 1057 0, 1058 String, 1059 "facility", 1060 "name of syslog facility to use for logging", 1061 "log_facility", 1062 NULL } 1063 1064 }; 1065 1066 static void ParseOption (const char* option, const char* parms, int cmdLine) 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 RedirectPort: 1190 SetupPortRedirect (strValue); 1191 break; 1192 1193 case RedirectAddress: 1194 SetupAddressRedirect (strValue); 1195 break; 1196 1197 case PptpAlias: 1198 SetupPptpAlias (strValue); 1199 break; 1200 1201 case ProxyRule: 1202 PacketAliasProxyRule (strValue); 1203 break; 1204 1205 case InterfaceName: 1206 if (ifName) 1207 free (ifName); 1208 1209 ifName = strdup (strValue); 1210 assignAliasAddr = 1; 1211 break; 1212 1213 case ConfigFile: 1214 ReadConfigFile (strValue); 1215 break; 1216 1217 case LogDenied: 1218 logDropped = 1; 1219 break; 1220 1221 case LogFacility: 1222 1223 fac_record = facilitynames; 1224 while (fac_record->c_name != NULL) { 1225 1226 if (!strcmp (fac_record->c_name, strValue)) { 1227 1228 logFacility = fac_record->c_val; 1229 break; 1230 1231 } 1232 else 1233 fac_record++; 1234 } 1235 1236 if(fac_record->c_name == NULL) 1237 errx(1, "Unknown log facility name: %s", strValue); 1238 1239 break; 1240 } 1241 } 1242 1243 void ReadConfigFile (const char* fileName) 1244 { 1245 FILE* file; 1246 char buf[128]; 1247 char* ptr; 1248 char* option; 1249 1250 file = fopen (fileName, "r"); 1251 if (!file) { 1252 1253 sprintf (buf, "Cannot open config file %s.\n", fileName); 1254 Quit (buf); 1255 } 1256 1257 while (fgets (buf, sizeof (buf), file)) { 1258 1259 ptr = strchr (buf, '\n'); 1260 if (!ptr) 1261 errx (1, "config line too long: %s", buf); 1262 1263 *ptr = '\0'; 1264 if (buf[0] == '#') 1265 continue; 1266 1267 ptr = buf; 1268 /* 1269 * Skip white space at beginning of line. 1270 */ 1271 while (*ptr && isspace (*ptr)) 1272 ++ptr; 1273 1274 if (*ptr == '\0') 1275 continue; 1276 /* 1277 * Extract option name. 1278 */ 1279 option = ptr; 1280 while (*ptr && !isspace (*ptr)) 1281 ++ptr; 1282 1283 if (*ptr != '\0') { 1284 1285 *ptr = '\0'; 1286 ++ptr; 1287 } 1288 /* 1289 * Skip white space between name and parms. 1290 */ 1291 while (*ptr && isspace (*ptr)) 1292 ++ptr; 1293 1294 ParseOption (option, *ptr ? ptr : NULL, 0); 1295 } 1296 1297 fclose (file); 1298 } 1299 1300 static void Usage () 1301 { 1302 int i; 1303 int max; 1304 struct OptionInfo* info; 1305 1306 fprintf (stderr, "Recognized options:\n\n"); 1307 1308 max = sizeof (optionTable) / sizeof (struct OptionInfo); 1309 for (i = 0, info = optionTable; i < max; i++, info++) { 1310 1311 fprintf (stderr, "-%-20s %s\n", info->name, 1312 info->parmDescription); 1313 1314 if (info->shortName) 1315 fprintf (stderr, "-%-20s %s\n", info->shortName, 1316 info->parmDescription); 1317 1318 fprintf (stderr, " %s\n\n", info->description); 1319 } 1320 1321 exit (1); 1322 } 1323 1324 void SetupPptpAlias (const char* parms) 1325 { 1326 char buf[128]; 1327 char* ptr; 1328 struct in_addr srcAddr; 1329 1330 strcpy (buf, parms); 1331 1332 /* 1333 * Extract source address. 1334 */ 1335 ptr = strtok (buf, " \t"); 1336 if (!ptr) 1337 errx(1, "pptpalias: missing src address"); 1338 1339 StrToAddr (ptr, &srcAddr); 1340 PacketAliasPptp (srcAddr); 1341 } 1342 1343 void SetupPortRedirect (const char* parms) 1344 { 1345 char buf[128]; 1346 char* ptr; 1347 struct in_addr localAddr; 1348 struct in_addr publicAddr; 1349 struct in_addr remoteAddr; 1350 port_range portRange; 1351 u_short localPort = 0; 1352 u_short publicPort = 0; 1353 u_short remotePort = 0; 1354 u_short numLocalPorts = 0; 1355 u_short numPublicPorts = 0; 1356 u_short numRemotePorts = 0; 1357 int proto; 1358 char* protoName; 1359 char* separator; 1360 int i; 1361 1362 strcpy (buf, parms); 1363 /* 1364 * Extract protocol. 1365 */ 1366 protoName = strtok (buf, " \t"); 1367 if (!protoName) 1368 errx (1, "redirect_port: missing protocol"); 1369 1370 proto = StrToProto (protoName); 1371 /* 1372 * Extract local address. 1373 */ 1374 ptr = strtok (NULL, " \t"); 1375 if (!ptr) 1376 errx (1, "redirect_port: missing local address"); 1377 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 1384 /* 1385 * Extract public port and optionally address. 1386 */ 1387 ptr = strtok (NULL, " \t"); 1388 if (!ptr) 1389 errx (1, "redirect_port: missing public port"); 1390 1391 separator = strchr (ptr, ':'); 1392 if (separator) { 1393 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) 1394 errx (1, "redirect_port: invalid public port range"); 1395 } 1396 else { 1397 publicAddr.s_addr = INADDR_ANY; 1398 if (StrToPortRange (ptr, protoName, &portRange) != 0) 1399 errx (1, "redirect_port: invalid public port range"); 1400 } 1401 1402 publicPort = GETLOPORT(portRange); 1403 numPublicPorts = GETNUMPORTS(portRange); 1404 1405 /* 1406 * Extract remote address and optionally port. 1407 */ 1408 ptr = strtok (NULL, " \t"); 1409 if (ptr) { 1410 separator = strchr (ptr, ':'); 1411 if (separator) { 1412 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) 1413 errx (1, "redirect_port: invalid remote port range"); 1414 } else { 1415 SETLOPORT(portRange, 0); 1416 SETNUMPORTS(portRange, 1); 1417 StrToAddr (ptr, &remoteAddr); 1418 } 1419 } 1420 else { 1421 SETLOPORT(portRange, 0); 1422 SETNUMPORTS(portRange, 1); 1423 remoteAddr.s_addr = INADDR_ANY; 1424 } 1425 1426 remotePort = GETLOPORT(portRange); 1427 numRemotePorts = GETNUMPORTS(portRange); 1428 1429 /* 1430 * Make sure port ranges match up, then add the redirect ports. 1431 */ 1432 if (numLocalPorts != numPublicPorts) 1433 errx (1, "redirect_port: port ranges must be equal in size"); 1434 1435 /* Remote port range is allowed to be '0' which means all ports. */ 1436 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) 1437 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); 1438 1439 for (i = 0 ; i < numPublicPorts ; ++i) { 1440 /* If remotePort is all ports, set it to 0. */ 1441 u_short remotePortCopy = remotePort + i; 1442 if (numRemotePorts == 1 && remotePort == 0) 1443 remotePortCopy = 0; 1444 1445 PacketAliasRedirectPort (localAddr, 1446 htons(localPort + i), 1447 remoteAddr, 1448 htons(remotePortCopy), 1449 publicAddr, 1450 htons(publicPort + i), 1451 proto); 1452 } 1453 } 1454 1455 void SetupAddressRedirect (const char* parms) 1456 { 1457 char buf[128]; 1458 char* ptr; 1459 struct in_addr localAddr; 1460 struct in_addr publicAddr; 1461 1462 strcpy (buf, parms); 1463 /* 1464 * Extract local address. 1465 */ 1466 ptr = strtok (buf, " \t"); 1467 if (!ptr) 1468 errx (1, "redirect_address: missing local address"); 1469 1470 StrToAddr (ptr, &localAddr); 1471 /* 1472 * Extract public address. 1473 */ 1474 ptr = strtok (NULL, " \t"); 1475 if (!ptr) 1476 errx (1, "redirect_address: missing public address"); 1477 1478 StrToAddr (ptr, &publicAddr); 1479 PacketAliasRedirectAddr (localAddr, publicAddr); 1480 } 1481 1482 void StrToAddr (const char* str, struct in_addr* addr) 1483 { 1484 struct hostent* hp; 1485 1486 if (inet_aton (str, addr)) 1487 return; 1488 1489 hp = gethostbyname (str); 1490 if (!hp) 1491 errx (1, "unknown host %s", str); 1492 1493 memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 1494 } 1495 1496 u_short StrToPort (const char* str, const char* proto) 1497 { 1498 u_short port; 1499 struct servent* sp; 1500 char* end; 1501 1502 port = strtol (str, &end, 10); 1503 if (end != str) 1504 return htons (port); 1505 1506 sp = getservbyname (str, proto); 1507 if (!sp) 1508 errx (1, "unknown service %s/%s", str, proto); 1509 1510 return sp->s_port; 1511 } 1512 1513 int StrToPortRange (const char* str, const char* proto, port_range *portRange) 1514 { 1515 char* sep; 1516 struct servent* sp; 1517 char* end; 1518 u_short loPort; 1519 u_short hiPort; 1520 1521 /* First see if this is a service, return corresponding port if so. */ 1522 sp = getservbyname (str,proto); 1523 if (sp) { 1524 SETLOPORT(*portRange, ntohs(sp->s_port)); 1525 SETNUMPORTS(*portRange, 1); 1526 return 0; 1527 } 1528 1529 /* Not a service, see if it's a single port or port range. */ 1530 sep = strchr (str, '-'); 1531 if (sep == NULL) { 1532 SETLOPORT(*portRange, strtol(str, &end, 10)); 1533 if (end != str) { 1534 /* Single port. */ 1535 SETNUMPORTS(*portRange, 1); 1536 return 0; 1537 } 1538 1539 /* Error in port range field. */ 1540 errx (1, "unknown service %s/%s", str, proto); 1541 } 1542 1543 /* Port range, get the values and sanity check. */ 1544 sscanf (str, "%hu-%hu", &loPort, &hiPort); 1545 SETLOPORT(*portRange, loPort); 1546 SETNUMPORTS(*portRange, 0); /* Error by default */ 1547 if (loPort <= hiPort) 1548 SETNUMPORTS(*portRange, hiPort - loPort + 1); 1549 1550 if (GETNUMPORTS(*portRange) == 0) 1551 errx (1, "invalid port range %s", str); 1552 1553 return 0; 1554 } 1555 1556 1557 int StrToProto (const char* str) 1558 { 1559 if (!strcmp (str, "tcp")) 1560 return IPPROTO_TCP; 1561 1562 if (!strcmp (str, "udp")) 1563 return IPPROTO_UDP; 1564 1565 errx (1, "unknown protocol %s. Expected tcp or udp", str); 1566 } 1567 1568 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 1569 { 1570 char* ptr; 1571 1572 ptr = strchr (str, ':'); 1573 if (!ptr) 1574 errx (1, "%s is missing port number", str); 1575 1576 *ptr = '\0'; 1577 ++ptr; 1578 1579 StrToAddr (str, addr); 1580 return StrToPortRange (ptr, proto, portRange); 1581 } 1582