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