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