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