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 13 #include <sys/cdefs.h> 14 __FBSDID("$FreeBSD$"); 15 16 #define SYSLOG_NAMES 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/sysctl.h> 21 #include <sys/time.h> 22 #include <sys/queue.h> 23 24 #include <netinet/in.h> 25 #include <netinet/in_systm.h> 26 #include <netinet/ip.h> 27 #include <machine/in_cksum.h> 28 #include <netinet/tcp.h> 29 #include <netinet/udp.h> 30 #include <netinet/ip_icmp.h> 31 #include <net/if.h> 32 #include <net/if_dl.h> 33 #include <net/route.h> 34 #include <arpa/inet.h> 35 36 #include <alias.h> 37 #include <ctype.h> 38 #include <err.h> 39 #include <errno.h> 40 #include <netdb.h> 41 #include <signal.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <syslog.h> 46 #include <unistd.h> 47 48 #include "natd.h" 49 50 struct instance { 51 const char *name; 52 struct libalias *la; 53 LIST_ENTRY(instance) list; 54 55 int ifIndex; 56 int assignAliasAddr; 57 char* ifName; 58 int logDropped; 59 u_short inPort; 60 u_short outPort; 61 u_short inOutPort; 62 struct in_addr aliasAddr; 63 int ifMTU; 64 int aliasOverhead; 65 int dropIgnoredIncoming; 66 int divertIn; 67 int divertOut; 68 int divertInOut; 69 }; 70 71 static LIST_HEAD(, instance) root = LIST_HEAD_INITIALIZER(&root); 72 73 struct libalias *mla; 74 struct instance *mip; 75 int ninstance = 1; 76 77 /* 78 * Default values for input and output 79 * divert socket ports. 80 */ 81 82 #define DEFAULT_SERVICE "natd" 83 84 /* 85 * Definition of a port range, and macros to deal with values. 86 * FORMAT: HI 16-bits == first port in range, 0 == all ports. 87 * LO 16-bits == number of ports in range 88 * NOTES: - Port values are not stored in network byte order. 89 */ 90 91 typedef u_long port_range; 92 93 #define GETLOPORT(x) ((x) >> 0x10) 94 #define GETNUMPORTS(x) ((x) & 0x0000ffff) 95 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 96 97 /* Set y to be the low-port value in port_range variable x. */ 98 #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 99 100 /* Set y to be the number of ports in port_range variable x. */ 101 #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 102 103 /* 104 * Function prototypes. 105 */ 106 107 static void DoAliasing (int fd, int direction); 108 static void DaemonMode (void); 109 static void HandleRoutingInfo (int fd); 110 static void Usage (void); 111 static char* FormatPacket (struct ip*); 112 static void PrintPacket (struct ip*); 113 static void SyslogPacket (struct ip*, int priority, const char *label); 114 static void SetAliasAddressFromIfName (const char *ifName); 115 static void InitiateShutdown (int); 116 static void Shutdown (int); 117 static void RefreshAddr (int); 118 static void ParseOption (const char* option, const char* parms); 119 static void ReadConfigFile (const char* fileName); 120 static void SetupPortRedirect (const char* parms); 121 static void SetupProtoRedirect(const char* parms); 122 static void SetupAddressRedirect (const char* parms); 123 static void StrToAddr (const char* str, struct in_addr* addr); 124 static u_short StrToPort (const char* str, const char* proto); 125 static int StrToPortRange (const char* str, const char* proto, port_range *portRange); 126 static int StrToProto (const char* str); 127 static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange); 128 static void ParseArgs (int argc, char** argv); 129 static void SetupPunchFW(const char *strValue); 130 static void SetupSkinnyPort(const char *strValue); 131 static void NewInstance(const char *name); 132 static void DoGlobal (int fd); 133 134 /* 135 * Globals. 136 */ 137 138 static int verbose; 139 static int background; 140 static int running; 141 static int logFacility; 142 143 static int dynamicMode; 144 static int icmpSock; 145 static int logIpfwDenied; 146 static char* pidName; 147 static int routeSock; 148 static int globalPort; 149 static int divertGlobal; 150 151 int main (int argc, char** argv) 152 { 153 struct sockaddr_in addr; 154 fd_set readMask; 155 int fdMax; 156 /* 157 * Initialize packet aliasing software. 158 * Done already here to be able to alter option bits 159 * during command line and configuration file processing. 160 */ 161 NewInstance("default"); 162 163 /* 164 * Parse options. 165 */ 166 verbose = 0; 167 background = 0; 168 running = 1; 169 dynamicMode = 0; 170 logFacility = LOG_DAEMON; 171 logIpfwDenied = -1; 172 pidName = PIDFILE; 173 routeSock = -1; 174 icmpSock = -1; 175 fdMax = -1; 176 divertGlobal = -1; 177 178 ParseArgs (argc, argv); 179 /* 180 * Log ipfw(8) denied packets by default in verbose mode. 181 */ 182 if (logIpfwDenied == -1) 183 logIpfwDenied = verbose; 184 /* 185 * Open syslog channel. 186 */ 187 openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0), 188 logFacility); 189 190 LIST_FOREACH(mip, &root, list) { 191 mla = mip->la; 192 /* 193 * If not doing the transparent proxying only, 194 * check that valid aliasing address has been given. 195 */ 196 if (mip->aliasAddr.s_addr == INADDR_NONE && mip->ifName == NULL && 197 !(LibAliasSetMode(mla, 0,0) & PKT_ALIAS_PROXY_ONLY)) 198 errx (1, "instance %s: aliasing address not given", mip->name); 199 200 if (mip->aliasAddr.s_addr != INADDR_NONE && mip->ifName != NULL) 201 errx (1, "both alias address and interface " 202 "name are not allowed"); 203 /* 204 * Check that valid port number is known. 205 */ 206 if (mip->inPort != 0 || mip->outPort != 0) 207 if (mip->inPort == 0 || mip->outPort == 0) 208 errx (1, "both input and output ports are required"); 209 210 if (mip->inPort == 0 && mip->outPort == 0 && mip->inOutPort == 0) 211 ParseOption ("port", DEFAULT_SERVICE); 212 213 /* 214 * Check if ignored packets should be dropped. 215 */ 216 mip->dropIgnoredIncoming = LibAliasSetMode (mla, 0, 0); 217 mip->dropIgnoredIncoming &= PKT_ALIAS_DENY_INCOMING; 218 /* 219 * Create divert sockets. Use only one socket if -p was specified 220 * on command line. Otherwise, create separate sockets for 221 * outgoing and incoming connnections. 222 */ 223 if (mip->inOutPort) { 224 225 mip->divertInOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 226 if (mip->divertInOut == -1) 227 Quit ("Unable to create divert socket."); 228 if (mip->divertInOut > fdMax) 229 fdMax = mip->divertInOut; 230 231 mip->divertIn = -1; 232 mip->divertOut = -1; 233 /* 234 * Bind socket. 235 */ 236 237 addr.sin_family = AF_INET; 238 addr.sin_addr.s_addr = INADDR_ANY; 239 addr.sin_port = mip->inOutPort; 240 241 if (bind (mip->divertInOut, 242 (struct sockaddr*) &addr, 243 sizeof addr) == -1) 244 Quit ("Unable to bind divert socket."); 245 } 246 else { 247 248 mip->divertIn = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 249 if (mip->divertIn == -1) 250 Quit ("Unable to create incoming divert socket."); 251 if (mip->divertIn > fdMax) 252 fdMax = mip->divertIn; 253 254 255 mip->divertOut = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 256 if (mip->divertOut == -1) 257 Quit ("Unable to create outgoing divert socket."); 258 if (mip->divertOut > fdMax) 259 fdMax = mip->divertOut; 260 261 mip->divertInOut = -1; 262 263 /* 264 * Bind divert sockets. 265 */ 266 267 addr.sin_family = AF_INET; 268 addr.sin_addr.s_addr = INADDR_ANY; 269 addr.sin_port = mip->inPort; 270 271 if (bind (mip->divertIn, 272 (struct sockaddr*) &addr, 273 sizeof addr) == -1) 274 Quit ("Unable to bind incoming divert socket."); 275 276 addr.sin_family = AF_INET; 277 addr.sin_addr.s_addr = INADDR_ANY; 278 addr.sin_port = mip->outPort; 279 280 if (bind (mip->divertOut, 281 (struct sockaddr*) &addr, 282 sizeof addr) == -1) 283 Quit ("Unable to bind outgoing divert socket."); 284 } 285 /* 286 * Create routing socket if interface name specified and in dynamic mode. 287 */ 288 if (mip->ifName) { 289 if (dynamicMode) { 290 291 if (routeSock == -1) 292 routeSock = socket (PF_ROUTE, SOCK_RAW, 0); 293 if (routeSock == -1) 294 Quit ("Unable to create routing info socket."); 295 if (routeSock > fdMax) 296 fdMax = routeSock; 297 298 mip->assignAliasAddr = 1; 299 } 300 else 301 SetAliasAddressFromIfName (mip->ifName); 302 } 303 304 } 305 if (globalPort) { 306 307 divertGlobal = socket (PF_INET, SOCK_RAW, IPPROTO_DIVERT); 308 if (divertGlobal == -1) 309 Quit ("Unable to create divert socket."); 310 if (divertGlobal > fdMax) 311 fdMax = divertGlobal; 312 313 /* 314 * Bind socket. 315 */ 316 317 addr.sin_family = AF_INET; 318 addr.sin_addr.s_addr = INADDR_ANY; 319 addr.sin_port = globalPort; 320 321 if (bind (divertGlobal, 322 (struct sockaddr*) &addr, 323 sizeof addr) == -1) 324 Quit ("Unable to bind global divert socket."); 325 } 326 /* 327 * Create socket for sending ICMP messages. 328 */ 329 icmpSock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 330 if (icmpSock == -1) 331 Quit ("Unable to create ICMP socket."); 332 333 /* 334 * And disable reads for the socket, otherwise it slowly fills 335 * up with received icmps which we do not use. 336 */ 337 shutdown(icmpSock, SHUT_RD); 338 339 /* 340 * Become a daemon unless verbose mode was requested. 341 */ 342 if (!verbose) 343 DaemonMode (); 344 /* 345 * Catch signals to manage shutdown and 346 * refresh of interface address. 347 */ 348 siginterrupt(SIGTERM, 1); 349 siginterrupt(SIGHUP, 1); 350 signal (SIGTERM, InitiateShutdown); 351 signal (SIGHUP, RefreshAddr); 352 /* 353 * Set alias address if it has been given. 354 */ 355 mip = LIST_FIRST(&root); /* XXX: simon */ 356 LIST_FOREACH(mip, &root, list) { 357 mla = mip->la; 358 if (mip->aliasAddr.s_addr != INADDR_NONE) 359 LibAliasSetAddress (mla, mip->aliasAddr); 360 } 361 362 while (running) { 363 mip = LIST_FIRST(&root); /* XXX: simon */ 364 365 if (mip->divertInOut != -1 && !mip->ifName && ninstance == 1) { 366 /* 367 * When using only one socket, just call 368 * DoAliasing repeatedly to process packets. 369 */ 370 DoAliasing (mip->divertInOut, DONT_KNOW); 371 continue; 372 } 373 /* 374 * Build read mask from socket descriptors to select. 375 */ 376 FD_ZERO (&readMask); 377 /* 378 * Check if new packets are available. 379 */ 380 LIST_FOREACH(mip, &root, list) { 381 if (mip->divertIn != -1) 382 FD_SET (mip->divertIn, &readMask); 383 384 if (mip->divertOut != -1) 385 FD_SET (mip->divertOut, &readMask); 386 387 if (mip->divertInOut != -1) 388 FD_SET (mip->divertInOut, &readMask); 389 } 390 /* 391 * Routing info is processed always. 392 */ 393 if (routeSock != -1) 394 FD_SET (routeSock, &readMask); 395 396 if (divertGlobal != -1) 397 FD_SET (divertGlobal, &readMask); 398 399 if (select (fdMax + 1, 400 &readMask, 401 NULL, 402 NULL, 403 NULL) == -1) { 404 405 if (errno == EINTR) 406 continue; 407 408 Quit ("Select failed."); 409 } 410 411 if (divertGlobal != -1) 412 if (FD_ISSET (divertGlobal, &readMask)) 413 DoGlobal (divertGlobal); 414 LIST_FOREACH(mip, &root, list) { 415 mla = mip->la; 416 if (mip->divertIn != -1) 417 if (FD_ISSET (mip->divertIn, &readMask)) 418 DoAliasing (mip->divertIn, INPUT); 419 420 if (mip->divertOut != -1) 421 if (FD_ISSET (mip->divertOut, &readMask)) 422 DoAliasing (mip->divertOut, OUTPUT); 423 424 if (mip->divertInOut != -1) 425 if (FD_ISSET (mip->divertInOut, &readMask)) 426 DoAliasing (mip->divertInOut, DONT_KNOW); 427 428 } 429 if (routeSock != -1) 430 if (FD_ISSET (routeSock, &readMask)) 431 HandleRoutingInfo (routeSock); 432 } 433 434 if (background) 435 unlink (pidName); 436 437 return 0; 438 } 439 440 static void DaemonMode () 441 { 442 FILE* pidFile; 443 444 daemon (0, 0); 445 background = 1; 446 447 pidFile = fopen (pidName, "w"); 448 if (pidFile) { 449 450 fprintf (pidFile, "%d\n", getpid ()); 451 fclose (pidFile); 452 } 453 } 454 455 static void ParseArgs (int argc, char** argv) 456 { 457 int arg; 458 char* opt; 459 char parmBuf[256]; 460 int len; /* bounds checking */ 461 462 for (arg = 1; arg < argc; arg++) { 463 464 opt = argv[arg]; 465 if (*opt != '-') { 466 467 warnx ("invalid option %s", opt); 468 Usage (); 469 } 470 471 parmBuf[0] = '\0'; 472 len = 0; 473 474 while (arg < argc - 1) { 475 476 if (argv[arg + 1][0] == '-') 477 break; 478 479 if (len) { 480 strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1)); 481 len += strlen(parmBuf + len); 482 } 483 484 ++arg; 485 strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1)); 486 len += strlen(parmBuf + len); 487 488 } 489 490 ParseOption (opt + 1, (len ? parmBuf : NULL)); 491 492 } 493 } 494 495 static void DoGlobal (int fd) 496 { 497 int bytes; 498 int origBytes; 499 char buf[IP_MAXPACKET]; 500 struct sockaddr_in addr; 501 int wrote; 502 int status; 503 int addrSize; 504 struct ip* ip; 505 char msgBuf[80]; 506 507 /* 508 * Get packet from socket. 509 */ 510 addrSize = sizeof addr; 511 origBytes = recvfrom (fd, 512 buf, 513 sizeof buf, 514 0, 515 (struct sockaddr*) &addr, 516 &addrSize); 517 518 if (origBytes == -1) { 519 520 if (errno != EINTR) 521 Warn ("read from divert socket failed"); 522 523 return; 524 } 525 526 #if 0 527 if (mip->assignAliasAddr) { 528 SetAliasAddressFromIfName (mip->ifName); 529 mip->assignAliasAddr = 0; 530 } 531 #endif 532 /* 533 * This is an IP packet. 534 */ 535 ip = (struct ip*) buf; 536 537 if (verbose) { 538 /* 539 * Print packet direction and protocol type. 540 */ 541 printf ("Glb "); 542 543 switch (ip->ip_p) { 544 case IPPROTO_TCP: 545 printf ("[TCP] "); 546 break; 547 548 case IPPROTO_UDP: 549 printf ("[UDP] "); 550 break; 551 552 case IPPROTO_ICMP: 553 printf ("[ICMP] "); 554 break; 555 556 default: 557 printf ("[%d] ", ip->ip_p); 558 break; 559 } 560 /* 561 * Print addresses. 562 */ 563 PrintPacket (ip); 564 } 565 566 LIST_FOREACH(mip, &root, list) { 567 mla = mip->la; 568 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED) 569 break; 570 } 571 /* 572 * Length might have changed during aliasing. 573 */ 574 bytes = ntohs (ip->ip_len); 575 /* 576 * Update alias overhead size for outgoing packets. 577 */ 578 if (mip != NULL && bytes - origBytes > mip->aliasOverhead) 579 mip->aliasOverhead = bytes - origBytes; 580 581 if (verbose) { 582 583 /* 584 * Print addresses after aliasing. 585 */ 586 printf (" aliased to\n"); 587 printf (" "); 588 PrintPacket (ip); 589 printf ("\n"); 590 } 591 592 /* 593 * Put packet back for processing. 594 */ 595 wrote = sendto (fd, 596 buf, 597 bytes, 598 0, 599 (struct sockaddr*) &addr, 600 sizeof addr); 601 602 if (wrote != bytes) { 603 604 if (errno == EMSGSIZE) { 605 606 if (mip->ifMTU != -1) 607 SendNeedFragIcmp (icmpSock, 608 (struct ip*) buf, 609 mip->ifMTU - mip->aliasOverhead); 610 } 611 else if (errno == EACCES && logIpfwDenied) { 612 613 sprintf (msgBuf, "failed to write packet back"); 614 Warn (msgBuf); 615 } 616 } 617 } 618 619 620 static void DoAliasing (int fd, int direction) 621 { 622 int bytes; 623 int origBytes; 624 char buf[IP_MAXPACKET]; 625 struct sockaddr_in addr; 626 int wrote; 627 int status; 628 int addrSize; 629 struct ip* ip; 630 char msgBuf[80]; 631 632 if (mip->assignAliasAddr) { 633 634 SetAliasAddressFromIfName (mip->ifName); 635 mip->assignAliasAddr = 0; 636 } 637 /* 638 * Get packet from socket. 639 */ 640 addrSize = sizeof addr; 641 origBytes = recvfrom (fd, 642 buf, 643 sizeof buf, 644 0, 645 (struct sockaddr*) &addr, 646 &addrSize); 647 648 if (origBytes == -1) { 649 650 if (errno != EINTR) 651 Warn ("read from divert socket failed"); 652 653 return; 654 } 655 /* 656 * This is an IP packet. 657 */ 658 ip = (struct ip*) buf; 659 if (direction == DONT_KNOW) { 660 if (addr.sin_addr.s_addr == INADDR_ANY) 661 direction = OUTPUT; 662 else 663 direction = INPUT; 664 } 665 666 if (verbose) { 667 /* 668 * Print packet direction and protocol type. 669 */ 670 printf (direction == OUTPUT ? "Out " : "In "); 671 if (ninstance > 1) 672 printf ("{%s} %08x", mip->name); 673 674 switch (ip->ip_p) { 675 case IPPROTO_TCP: 676 printf ("[TCP] "); 677 break; 678 679 case IPPROTO_UDP: 680 printf ("[UDP] "); 681 break; 682 683 case IPPROTO_ICMP: 684 printf ("[ICMP] "); 685 break; 686 687 default: 688 printf ("[%d] ", ip->ip_p); 689 break; 690 } 691 /* 692 * Print addresses. 693 */ 694 PrintPacket (ip); 695 } 696 697 if (direction == OUTPUT) { 698 /* 699 * Outgoing packets. Do aliasing. 700 */ 701 LibAliasOut (mla, buf, IP_MAXPACKET); 702 } 703 else { 704 705 /* 706 * Do aliasing. 707 */ 708 status = LibAliasIn (mla, buf, IP_MAXPACKET); 709 if (status == PKT_ALIAS_IGNORED && 710 mip->dropIgnoredIncoming) { 711 712 if (verbose) 713 printf (" dropped.\n"); 714 715 if (mip->logDropped) 716 SyslogPacket (ip, LOG_WARNING, "denied"); 717 718 return; 719 } 720 } 721 /* 722 * Length might have changed during aliasing. 723 */ 724 bytes = ntohs (ip->ip_len); 725 /* 726 * Update alias overhead size for outgoing packets. 727 */ 728 if (direction == OUTPUT && 729 bytes - origBytes > mip->aliasOverhead) 730 mip->aliasOverhead = bytes - origBytes; 731 732 if (verbose) { 733 734 /* 735 * Print addresses after aliasing. 736 */ 737 printf (" aliased to\n"); 738 printf (" "); 739 PrintPacket (ip); 740 printf ("\n"); 741 } 742 743 /* 744 * Put packet back for processing. 745 */ 746 wrote = sendto (fd, 747 buf, 748 bytes, 749 0, 750 (struct sockaddr*) &addr, 751 sizeof addr); 752 753 if (wrote != bytes) { 754 755 if (errno == EMSGSIZE) { 756 757 if (direction == OUTPUT && 758 mip->ifMTU != -1) 759 SendNeedFragIcmp (icmpSock, 760 (struct ip*) buf, 761 mip->ifMTU - mip->aliasOverhead); 762 } 763 else if (errno == EACCES && logIpfwDenied) { 764 765 sprintf (msgBuf, "failed to write packet back"); 766 Warn (msgBuf); 767 } 768 } 769 } 770 771 static void HandleRoutingInfo (int fd) 772 { 773 int bytes; 774 struct if_msghdr ifMsg; 775 /* 776 * Get packet from socket. 777 */ 778 bytes = read (fd, &ifMsg, sizeof ifMsg); 779 if (bytes == -1) { 780 781 Warn ("read from routing socket failed"); 782 return; 783 } 784 785 if (ifMsg.ifm_version != RTM_VERSION) { 786 787 Warn ("unexpected packet read from routing socket"); 788 return; 789 } 790 791 if (verbose) 792 printf ("Routing message %#x received.\n", ifMsg.ifm_type); 793 794 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) { 795 LIST_FOREACH(mip, &root, list) { 796 mla = mip->la; 797 if (ifMsg.ifm_index == mip->ifIndex) { 798 if (verbose) 799 printf("Interface address/MTU has probably changed.\n"); 800 mip->assignAliasAddr = 1; 801 } 802 } 803 } 804 } 805 806 static void PrintPacket (struct ip* ip) 807 { 808 printf ("%s", FormatPacket (ip)); 809 } 810 811 static void SyslogPacket (struct ip* ip, int priority, const char *label) 812 { 813 syslog (priority, "%s %s", label, FormatPacket (ip)); 814 } 815 816 static char* FormatPacket (struct ip* ip) 817 { 818 static char buf[256]; 819 struct tcphdr* tcphdr; 820 struct udphdr* udphdr; 821 struct icmp* icmphdr; 822 char src[20]; 823 char dst[20]; 824 825 strcpy (src, inet_ntoa (ip->ip_src)); 826 strcpy (dst, inet_ntoa (ip->ip_dst)); 827 828 switch (ip->ip_p) { 829 case IPPROTO_TCP: 830 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 831 sprintf (buf, "[TCP] %s:%d -> %s:%d", 832 src, 833 ntohs (tcphdr->th_sport), 834 dst, 835 ntohs (tcphdr->th_dport)); 836 break; 837 838 case IPPROTO_UDP: 839 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 840 sprintf (buf, "[UDP] %s:%d -> %s:%d", 841 src, 842 ntohs (udphdr->uh_sport), 843 dst, 844 ntohs (udphdr->uh_dport)); 845 break; 846 847 case IPPROTO_ICMP: 848 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 849 sprintf (buf, "[ICMP] %s -> %s %u(%u)", 850 src, 851 dst, 852 icmphdr->icmp_type, 853 icmphdr->icmp_code); 854 break; 855 856 default: 857 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 858 break; 859 } 860 861 return buf; 862 } 863 864 static void 865 SetAliasAddressFromIfName(const char *ifn) 866 { 867 size_t needed; 868 int mib[6]; 869 char *buf, *lim, *next; 870 struct if_msghdr *ifm; 871 struct ifa_msghdr *ifam; 872 struct sockaddr_dl *sdl; 873 struct sockaddr_in *sin; 874 875 mib[0] = CTL_NET; 876 mib[1] = PF_ROUTE; 877 mib[2] = 0; 878 mib[3] = AF_INET; /* Only IP addresses please */ 879 mib[4] = NET_RT_IFLIST; 880 mib[5] = 0; /* ifIndex??? */ 881 /* 882 * Get interface data. 883 */ 884 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 885 err(1, "iflist-sysctl-estimate"); 886 if ((buf = malloc(needed)) == NULL) 887 errx(1, "malloc failed"); 888 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 889 err(1, "iflist-sysctl-get"); 890 lim = buf + needed; 891 /* 892 * Loop through interfaces until one with 893 * given name is found. This is done to 894 * find correct interface index for routing 895 * message processing. 896 */ 897 mip->ifIndex = 0; 898 next = buf; 899 while (next < lim) { 900 ifm = (struct if_msghdr *)next; 901 next += ifm->ifm_msglen; 902 if (ifm->ifm_version != RTM_VERSION) { 903 if (verbose) 904 warnx("routing message version %d " 905 "not understood", ifm->ifm_version); 906 continue; 907 } 908 if (ifm->ifm_type == RTM_IFINFO) { 909 sdl = (struct sockaddr_dl *)(ifm + 1); 910 if (strlen(ifn) == sdl->sdl_nlen && 911 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 912 mip->ifIndex = ifm->ifm_index; 913 mip->ifMTU = ifm->ifm_data.ifi_mtu; 914 break; 915 } 916 } 917 } 918 if (!mip->ifIndex) 919 errx(1, "unknown interface name %s", ifn); 920 /* 921 * Get interface address. 922 */ 923 sin = NULL; 924 while (next < lim) { 925 ifam = (struct ifa_msghdr *)next; 926 next += ifam->ifam_msglen; 927 if (ifam->ifam_version != RTM_VERSION) { 928 if (verbose) 929 warnx("routing message version %d " 930 "not understood", ifam->ifam_version); 931 continue; 932 } 933 if (ifam->ifam_type != RTM_NEWADDR) 934 break; 935 if (ifam->ifam_addrs & RTA_IFA) { 936 int i; 937 char *cp = (char *)(ifam + 1); 938 939 for (i = 1; i < RTA_IFA; i <<= 1) 940 if (ifam->ifam_addrs & i) 941 cp += SA_SIZE((struct sockaddr *)cp); 942 if (((struct sockaddr *)cp)->sa_family == AF_INET) { 943 sin = (struct sockaddr_in *)cp; 944 break; 945 } 946 } 947 } 948 if (sin == NULL) 949 errx(1, "%s: cannot get interface address", ifn); 950 951 LibAliasSetAddress(mla, sin->sin_addr); 952 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", 953 inet_ntoa(sin->sin_addr), mip->ifMTU); 954 955 free(buf); 956 } 957 958 void Quit (const char* msg) 959 { 960 Warn (msg); 961 exit (1); 962 } 963 964 void Warn (const char* msg) 965 { 966 if (background) 967 syslog (LOG_ALERT, "%s (%m)", msg); 968 else 969 warn ("%s", msg); 970 } 971 972 static void RefreshAddr (int sig) 973 { 974 if (mip->ifName) 975 mip->assignAliasAddr = 1; 976 } 977 978 static void InitiateShutdown (int sig) 979 { 980 /* 981 * Start timer to allow kernel gracefully 982 * shutdown existing connections when system 983 * is shut down. 984 */ 985 siginterrupt(SIGALRM, 1); 986 signal (SIGALRM, Shutdown); 987 alarm (10); 988 } 989 990 static void Shutdown (int sig) 991 { 992 running = 0; 993 } 994 995 /* 996 * Different options recognized by this program. 997 */ 998 999 enum Option { 1000 1001 LibAliasOption, 1002 Instance, 1003 Verbose, 1004 InPort, 1005 OutPort, 1006 Port, 1007 GlobalPort, 1008 AliasAddress, 1009 TargetAddress, 1010 InterfaceName, 1011 RedirectPort, 1012 RedirectProto, 1013 RedirectAddress, 1014 ConfigFile, 1015 DynamicMode, 1016 ProxyRule, 1017 LogDenied, 1018 LogFacility, 1019 PunchFW, 1020 SkinnyPort, 1021 LogIpfwDenied, 1022 PidFile 1023 }; 1024 1025 enum Param { 1026 1027 YesNo, 1028 Numeric, 1029 String, 1030 None, 1031 Address, 1032 Service 1033 }; 1034 1035 /* 1036 * Option information structure (used by ParseOption). 1037 */ 1038 1039 struct OptionInfo { 1040 1041 enum Option type; 1042 int packetAliasOpt; 1043 enum Param parm; 1044 const char* parmDescription; 1045 const char* description; 1046 const char* name; 1047 const char* shortName; 1048 }; 1049 1050 /* 1051 * Table of known options. 1052 */ 1053 1054 static struct OptionInfo optionTable[] = { 1055 1056 { LibAliasOption, 1057 PKT_ALIAS_UNREGISTERED_ONLY, 1058 YesNo, 1059 "[yes|no]", 1060 "alias only unregistered addresses", 1061 "unregistered_only", 1062 "u" }, 1063 1064 { LibAliasOption, 1065 PKT_ALIAS_LOG, 1066 YesNo, 1067 "[yes|no]", 1068 "enable logging", 1069 "log", 1070 "l" }, 1071 1072 { LibAliasOption, 1073 PKT_ALIAS_PROXY_ONLY, 1074 YesNo, 1075 "[yes|no]", 1076 "proxy only", 1077 "proxy_only", 1078 NULL }, 1079 1080 { LibAliasOption, 1081 PKT_ALIAS_REVERSE, 1082 YesNo, 1083 "[yes|no]", 1084 "operate in reverse mode", 1085 "reverse", 1086 NULL }, 1087 1088 { LibAliasOption, 1089 PKT_ALIAS_DENY_INCOMING, 1090 YesNo, 1091 "[yes|no]", 1092 "allow incoming connections", 1093 "deny_incoming", 1094 "d" }, 1095 1096 { LibAliasOption, 1097 PKT_ALIAS_USE_SOCKETS, 1098 YesNo, 1099 "[yes|no]", 1100 "use sockets to inhibit port conflict", 1101 "use_sockets", 1102 "s" }, 1103 1104 { LibAliasOption, 1105 PKT_ALIAS_SAME_PORTS, 1106 YesNo, 1107 "[yes|no]", 1108 "try to keep original port numbers for connections", 1109 "same_ports", 1110 "m" }, 1111 1112 { Verbose, 1113 0, 1114 YesNo, 1115 "[yes|no]", 1116 "verbose mode, dump packet information", 1117 "verbose", 1118 "v" }, 1119 1120 { DynamicMode, 1121 0, 1122 YesNo, 1123 "[yes|no]", 1124 "dynamic mode, automatically detect interface address changes", 1125 "dynamic", 1126 NULL }, 1127 1128 { InPort, 1129 0, 1130 Service, 1131 "number|service_name", 1132 "set port for incoming packets", 1133 "in_port", 1134 "i" }, 1135 1136 { OutPort, 1137 0, 1138 Service, 1139 "number|service_name", 1140 "set port for outgoing packets", 1141 "out_port", 1142 "o" }, 1143 1144 { Port, 1145 0, 1146 Service, 1147 "number|service_name", 1148 "set port (defaults to natd/divert)", 1149 "port", 1150 "p" }, 1151 1152 { GlobalPort, 1153 0, 1154 Service, 1155 "number|service_name", 1156 "set globalport", 1157 "globalport", 1158 NULL }, 1159 1160 { AliasAddress, 1161 0, 1162 Address, 1163 "x.x.x.x", 1164 "address to use for aliasing", 1165 "alias_address", 1166 "a" }, 1167 1168 { TargetAddress, 1169 0, 1170 Address, 1171 "x.x.x.x", 1172 "address to use for incoming sessions", 1173 "target_address", 1174 "t" }, 1175 1176 { InterfaceName, 1177 0, 1178 String, 1179 "network_if_name", 1180 "take aliasing address from interface", 1181 "interface", 1182 "n" }, 1183 1184 { ProxyRule, 1185 0, 1186 String, 1187 "[type encode_ip_hdr|encode_tcp_stream] port xxxx server " 1188 "a.b.c.d:yyyy", 1189 "add transparent proxying / destination NAT", 1190 "proxy_rule", 1191 NULL }, 1192 1193 { RedirectPort, 1194 0, 1195 String, 1196 "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range" 1197 " [remote_addr[:remote_port_range]]", 1198 "redirect a port (or ports) for incoming traffic", 1199 "redirect_port", 1200 NULL }, 1201 1202 { RedirectProto, 1203 0, 1204 String, 1205 "proto local_addr [public_addr] [remote_addr]", 1206 "redirect packets of a given proto", 1207 "redirect_proto", 1208 NULL }, 1209 1210 { RedirectAddress, 1211 0, 1212 String, 1213 "local_addr[,...] public_addr", 1214 "define mapping between local and public addresses", 1215 "redirect_address", 1216 NULL }, 1217 1218 { ConfigFile, 1219 0, 1220 String, 1221 "file_name", 1222 "read options from configuration file", 1223 "config", 1224 "f" }, 1225 1226 { LogDenied, 1227 0, 1228 YesNo, 1229 "[yes|no]", 1230 "enable logging of denied incoming packets", 1231 "log_denied", 1232 NULL }, 1233 1234 { LogFacility, 1235 0, 1236 String, 1237 "facility", 1238 "name of syslog facility to use for logging", 1239 "log_facility", 1240 NULL }, 1241 1242 { PunchFW, 1243 0, 1244 String, 1245 "basenumber:count", 1246 "punch holes in the firewall for incoming FTP/IRC DCC connections", 1247 "punch_fw", 1248 NULL }, 1249 1250 { SkinnyPort, 1251 0, 1252 String, 1253 "port", 1254 "set the TCP port for use with the Skinny Station protocol", 1255 "skinny_port", 1256 NULL }, 1257 1258 { LogIpfwDenied, 1259 0, 1260 YesNo, 1261 "[yes|no]", 1262 "log packets converted by natd, but denied by ipfw", 1263 "log_ipfw_denied", 1264 NULL }, 1265 1266 { PidFile, 1267 0, 1268 String, 1269 "file_name", 1270 "store PID in an alternate file", 1271 "pid_file", 1272 "P" }, 1273 { Instance, 1274 0, 1275 String, 1276 "instance name", 1277 "name of aliasing engine instance", 1278 "instance", 1279 NULL }, 1280 }; 1281 1282 static void ParseOption (const char* option, const char* parms) 1283 { 1284 int i; 1285 struct OptionInfo* info; 1286 int yesNoValue; 1287 int aliasValue; 1288 int numValue; 1289 u_short uNumValue; 1290 const char* strValue; 1291 struct in_addr addrValue; 1292 int max; 1293 char* end; 1294 CODE* fac_record = NULL; 1295 /* 1296 * Find option from table. 1297 */ 1298 max = sizeof (optionTable) / sizeof (struct OptionInfo); 1299 for (i = 0, info = optionTable; i < max; i++, info++) { 1300 1301 if (!strcmp (info->name, option)) 1302 break; 1303 1304 if (info->shortName) 1305 if (!strcmp (info->shortName, option)) 1306 break; 1307 } 1308 1309 if (i >= max) { 1310 1311 warnx ("unknown option %s", option); 1312 Usage (); 1313 } 1314 1315 uNumValue = 0; 1316 yesNoValue = 0; 1317 numValue = 0; 1318 strValue = NULL; 1319 /* 1320 * Check parameters. 1321 */ 1322 switch (info->parm) { 1323 case YesNo: 1324 if (!parms) 1325 parms = "yes"; 1326 1327 if (!strcmp (parms, "yes")) 1328 yesNoValue = 1; 1329 else 1330 if (!strcmp (parms, "no")) 1331 yesNoValue = 0; 1332 else 1333 errx (1, "%s needs yes/no parameter", option); 1334 break; 1335 1336 case Service: 1337 if (!parms) 1338 errx (1, "%s needs service name or " 1339 "port number parameter", 1340 option); 1341 1342 uNumValue = StrToPort (parms, "divert"); 1343 break; 1344 1345 case Numeric: 1346 if (parms) 1347 numValue = strtol (parms, &end, 10); 1348 else 1349 end = NULL; 1350 1351 if (end == parms) 1352 errx (1, "%s needs numeric parameter", option); 1353 break; 1354 1355 case String: 1356 strValue = parms; 1357 if (!strValue) 1358 errx (1, "%s needs parameter", option); 1359 break; 1360 1361 case None: 1362 if (parms) 1363 errx (1, "%s does not take parameters", option); 1364 break; 1365 1366 case Address: 1367 if (!parms) 1368 errx (1, "%s needs address/host parameter", option); 1369 1370 StrToAddr (parms, &addrValue); 1371 break; 1372 } 1373 1374 switch (info->type) { 1375 case LibAliasOption: 1376 1377 aliasValue = yesNoValue ? info->packetAliasOpt : 0; 1378 LibAliasSetMode (mla, aliasValue, info->packetAliasOpt); 1379 break; 1380 1381 case Verbose: 1382 verbose = yesNoValue; 1383 break; 1384 1385 case DynamicMode: 1386 dynamicMode = yesNoValue; 1387 break; 1388 1389 case InPort: 1390 mip->inPort = uNumValue; 1391 break; 1392 1393 case OutPort: 1394 mip->outPort = uNumValue; 1395 break; 1396 1397 case Port: 1398 mip->inOutPort = uNumValue; 1399 break; 1400 1401 case GlobalPort: 1402 globalPort = uNumValue; 1403 break; 1404 1405 case AliasAddress: 1406 memcpy (&mip->aliasAddr, &addrValue, sizeof (struct in_addr)); 1407 break; 1408 1409 case TargetAddress: 1410 LibAliasSetTarget(mla, addrValue); 1411 break; 1412 1413 case RedirectPort: 1414 SetupPortRedirect (strValue); 1415 break; 1416 1417 case RedirectProto: 1418 SetupProtoRedirect(strValue); 1419 break; 1420 1421 case RedirectAddress: 1422 SetupAddressRedirect (strValue); 1423 break; 1424 1425 case ProxyRule: 1426 LibAliasProxyRule (mla, strValue); 1427 break; 1428 1429 case InterfaceName: 1430 if (mip->ifName) 1431 free (mip->ifName); 1432 1433 mip->ifName = strdup (strValue); 1434 break; 1435 1436 case ConfigFile: 1437 ReadConfigFile (strValue); 1438 break; 1439 1440 case LogDenied: 1441 mip->logDropped = yesNoValue; 1442 break; 1443 1444 case LogFacility: 1445 1446 fac_record = facilitynames; 1447 while (fac_record->c_name != NULL) { 1448 1449 if (!strcmp (fac_record->c_name, strValue)) { 1450 1451 logFacility = fac_record->c_val; 1452 break; 1453 1454 } 1455 else 1456 fac_record++; 1457 } 1458 1459 if(fac_record->c_name == NULL) 1460 errx(1, "Unknown log facility name: %s", strValue); 1461 1462 break; 1463 1464 case PunchFW: 1465 SetupPunchFW(strValue); 1466 break; 1467 1468 case SkinnyPort: 1469 SetupSkinnyPort(strValue); 1470 break; 1471 1472 case LogIpfwDenied: 1473 logIpfwDenied = yesNoValue;; 1474 break; 1475 1476 case PidFile: 1477 pidName = strdup (strValue); 1478 break; 1479 case Instance: 1480 NewInstance(strValue); 1481 break; 1482 } 1483 } 1484 1485 void ReadConfigFile (const char* fileName) 1486 { 1487 FILE* file; 1488 char *buf; 1489 size_t len; 1490 char *ptr, *p; 1491 char* option; 1492 1493 file = fopen (fileName, "r"); 1494 if (!file) 1495 err(1, "cannot open config file %s", fileName); 1496 1497 while ((buf = fgetln(file, &len)) != NULL) { 1498 if (buf[len - 1] == '\n') 1499 buf[len - 1] = '\0'; 1500 else 1501 errx(1, "config file format error: " 1502 "last line should end with newline"); 1503 1504 /* 1505 * Check for comments, strip off trailing spaces. 1506 */ 1507 if ((ptr = strchr(buf, '#'))) 1508 *ptr = '\0'; 1509 for (ptr = buf; isspace(*ptr); ++ptr) 1510 continue; 1511 if (*ptr == '\0') 1512 continue; 1513 for (p = strchr(buf, '\0'); isspace(*--p);) 1514 continue; 1515 *++p = '\0'; 1516 1517 /* 1518 * Extract option name. 1519 */ 1520 option = ptr; 1521 while (*ptr && !isspace (*ptr)) 1522 ++ptr; 1523 1524 if (*ptr != '\0') { 1525 1526 *ptr = '\0'; 1527 ++ptr; 1528 } 1529 /* 1530 * Skip white space between name and parms. 1531 */ 1532 while (*ptr && isspace (*ptr)) 1533 ++ptr; 1534 1535 ParseOption (option, *ptr ? ptr : NULL); 1536 } 1537 1538 fclose (file); 1539 } 1540 1541 static void Usage () 1542 { 1543 int i; 1544 int max; 1545 struct OptionInfo* info; 1546 1547 fprintf (stderr, "Recognized options:\n\n"); 1548 1549 max = sizeof (optionTable) / sizeof (struct OptionInfo); 1550 for (i = 0, info = optionTable; i < max; i++, info++) { 1551 1552 fprintf (stderr, "-%-20s %s\n", info->name, 1553 info->parmDescription); 1554 1555 if (info->shortName) 1556 fprintf (stderr, "-%-20s %s\n", info->shortName, 1557 info->parmDescription); 1558 1559 fprintf (stderr, " %s\n\n", info->description); 1560 } 1561 1562 exit (1); 1563 } 1564 1565 void SetupPortRedirect (const char* parms) 1566 { 1567 char buf[128]; 1568 char* ptr; 1569 char* serverPool; 1570 struct in_addr localAddr; 1571 struct in_addr publicAddr; 1572 struct in_addr remoteAddr; 1573 port_range portRange; 1574 u_short localPort = 0; 1575 u_short publicPort = 0; 1576 u_short remotePort = 0; 1577 u_short numLocalPorts = 0; 1578 u_short numPublicPorts = 0; 1579 u_short numRemotePorts = 0; 1580 int proto; 1581 char* protoName; 1582 char* separator; 1583 int i; 1584 struct alias_link *link = NULL; 1585 1586 strlcpy (buf, parms, sizeof(buf)); 1587 /* 1588 * Extract protocol. 1589 */ 1590 protoName = strtok (buf, " \t"); 1591 if (!protoName) 1592 errx (1, "redirect_port: missing protocol"); 1593 1594 proto = StrToProto (protoName); 1595 /* 1596 * Extract local address. 1597 */ 1598 ptr = strtok (NULL, " \t"); 1599 if (!ptr) 1600 errx (1, "redirect_port: missing local address"); 1601 1602 separator = strchr(ptr, ','); 1603 if (separator) { /* LSNAT redirection syntax. */ 1604 localAddr.s_addr = INADDR_NONE; 1605 localPort = ~0; 1606 numLocalPorts = 1; 1607 serverPool = ptr; 1608 } else { 1609 if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) 1610 errx (1, "redirect_port: invalid local port range"); 1611 1612 localPort = GETLOPORT(portRange); 1613 numLocalPorts = GETNUMPORTS(portRange); 1614 serverPool = NULL; 1615 } 1616 1617 /* 1618 * Extract public port and optionally address. 1619 */ 1620 ptr = strtok (NULL, " \t"); 1621 if (!ptr) 1622 errx (1, "redirect_port: missing public port"); 1623 1624 separator = strchr (ptr, ':'); 1625 if (separator) { 1626 if (StrToAddrAndPortRange (ptr, &publicAddr, protoName, &portRange) != 0 ) 1627 errx (1, "redirect_port: invalid public port range"); 1628 } 1629 else { 1630 publicAddr.s_addr = INADDR_ANY; 1631 if (StrToPortRange (ptr, protoName, &portRange) != 0) 1632 errx (1, "redirect_port: invalid public port range"); 1633 } 1634 1635 publicPort = GETLOPORT(portRange); 1636 numPublicPorts = GETNUMPORTS(portRange); 1637 1638 /* 1639 * Extract remote address and optionally port. 1640 */ 1641 ptr = strtok (NULL, " \t"); 1642 if (ptr) { 1643 separator = strchr (ptr, ':'); 1644 if (separator) { 1645 if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) 1646 errx (1, "redirect_port: invalid remote port range"); 1647 } else { 1648 SETLOPORT(portRange, 0); 1649 SETNUMPORTS(portRange, 1); 1650 StrToAddr (ptr, &remoteAddr); 1651 } 1652 } 1653 else { 1654 SETLOPORT(portRange, 0); 1655 SETNUMPORTS(portRange, 1); 1656 remoteAddr.s_addr = INADDR_ANY; 1657 } 1658 1659 remotePort = GETLOPORT(portRange); 1660 numRemotePorts = GETNUMPORTS(portRange); 1661 1662 /* 1663 * Make sure port ranges match up, then add the redirect ports. 1664 */ 1665 if (numLocalPorts != numPublicPorts) 1666 errx (1, "redirect_port: port ranges must be equal in size"); 1667 1668 /* Remote port range is allowed to be '0' which means all ports. */ 1669 if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) 1670 errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); 1671 1672 for (i = 0 ; i < numPublicPorts ; ++i) { 1673 /* If remotePort is all ports, set it to 0. */ 1674 u_short remotePortCopy = remotePort + i; 1675 if (numRemotePorts == 1 && remotePort == 0) 1676 remotePortCopy = 0; 1677 1678 link = LibAliasRedirectPort (mla, localAddr, 1679 htons(localPort + i), 1680 remoteAddr, 1681 htons(remotePortCopy), 1682 publicAddr, 1683 htons(publicPort + i), 1684 proto); 1685 } 1686 1687 /* 1688 * Setup LSNAT server pool. 1689 */ 1690 if (serverPool != NULL && link != NULL) { 1691 ptr = strtok(serverPool, ","); 1692 while (ptr != NULL) { 1693 if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0) 1694 errx(1, "redirect_port: invalid local port range"); 1695 1696 localPort = GETLOPORT(portRange); 1697 if (GETNUMPORTS(portRange) != 1) 1698 errx(1, "redirect_port: local port must be single in this context"); 1699 LibAliasAddServer(mla, link, localAddr, htons(localPort)); 1700 ptr = strtok(NULL, ","); 1701 } 1702 } 1703 } 1704 1705 void 1706 SetupProtoRedirect(const char* parms) 1707 { 1708 char buf[128]; 1709 char* ptr; 1710 struct in_addr localAddr; 1711 struct in_addr publicAddr; 1712 struct in_addr remoteAddr; 1713 int proto; 1714 char* protoName; 1715 struct protoent *protoent; 1716 1717 strlcpy (buf, parms, sizeof(buf)); 1718 /* 1719 * Extract protocol. 1720 */ 1721 protoName = strtok(buf, " \t"); 1722 if (!protoName) 1723 errx(1, "redirect_proto: missing protocol"); 1724 1725 protoent = getprotobyname(protoName); 1726 if (protoent == NULL) 1727 errx(1, "redirect_proto: unknown protocol %s", protoName); 1728 else 1729 proto = protoent->p_proto; 1730 /* 1731 * Extract local address. 1732 */ 1733 ptr = strtok(NULL, " \t"); 1734 if (!ptr) 1735 errx(1, "redirect_proto: missing local address"); 1736 else 1737 StrToAddr(ptr, &localAddr); 1738 /* 1739 * Extract optional public address. 1740 */ 1741 ptr = strtok(NULL, " \t"); 1742 if (ptr) 1743 StrToAddr(ptr, &publicAddr); 1744 else 1745 publicAddr.s_addr = INADDR_ANY; 1746 /* 1747 * Extract optional remote address. 1748 */ 1749 ptr = strtok(NULL, " \t"); 1750 if (ptr) 1751 StrToAddr(ptr, &remoteAddr); 1752 else 1753 remoteAddr.s_addr = INADDR_ANY; 1754 /* 1755 * Create aliasing link. 1756 */ 1757 (void)LibAliasRedirectProto(mla, localAddr, remoteAddr, publicAddr, 1758 proto); 1759 } 1760 1761 void SetupAddressRedirect (const char* parms) 1762 { 1763 char buf[128]; 1764 char* ptr; 1765 char* separator; 1766 struct in_addr localAddr; 1767 struct in_addr publicAddr; 1768 char* serverPool; 1769 struct alias_link *link; 1770 1771 strlcpy (buf, parms, sizeof(buf)); 1772 /* 1773 * Extract local address. 1774 */ 1775 ptr = strtok (buf, " \t"); 1776 if (!ptr) 1777 errx (1, "redirect_address: missing local address"); 1778 1779 separator = strchr(ptr, ','); 1780 if (separator) { /* LSNAT redirection syntax. */ 1781 localAddr.s_addr = INADDR_NONE; 1782 serverPool = ptr; 1783 } else { 1784 StrToAddr (ptr, &localAddr); 1785 serverPool = NULL; 1786 } 1787 /* 1788 * Extract public address. 1789 */ 1790 ptr = strtok (NULL, " \t"); 1791 if (!ptr) 1792 errx (1, "redirect_address: missing public address"); 1793 1794 StrToAddr (ptr, &publicAddr); 1795 link = LibAliasRedirectAddr(mla, localAddr, publicAddr); 1796 1797 /* 1798 * Setup LSNAT server pool. 1799 */ 1800 if (serverPool != NULL && link != NULL) { 1801 ptr = strtok(serverPool, ","); 1802 while (ptr != NULL) { 1803 StrToAddr(ptr, &localAddr); 1804 LibAliasAddServer(mla, link, localAddr, htons(~0)); 1805 ptr = strtok(NULL, ","); 1806 } 1807 } 1808 } 1809 1810 void StrToAddr (const char* str, struct in_addr* addr) 1811 { 1812 struct hostent* hp; 1813 1814 if (inet_aton (str, addr)) 1815 return; 1816 1817 hp = gethostbyname (str); 1818 if (!hp) 1819 errx (1, "unknown host %s", str); 1820 1821 memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 1822 } 1823 1824 u_short StrToPort (const char* str, const char* proto) 1825 { 1826 u_short port; 1827 struct servent* sp; 1828 char* end; 1829 1830 port = strtol (str, &end, 10); 1831 if (end != str) 1832 return htons (port); 1833 1834 sp = getservbyname (str, proto); 1835 if (!sp) 1836 errx (1, "%s/%s: unknown service", str, proto); 1837 1838 return sp->s_port; 1839 } 1840 1841 int StrToPortRange (const char* str, const char* proto, port_range *portRange) 1842 { 1843 char* sep; 1844 struct servent* sp; 1845 char* end; 1846 u_short loPort; 1847 u_short hiPort; 1848 1849 /* First see if this is a service, return corresponding port if so. */ 1850 sp = getservbyname (str,proto); 1851 if (sp) { 1852 SETLOPORT(*portRange, ntohs(sp->s_port)); 1853 SETNUMPORTS(*portRange, 1); 1854 return 0; 1855 } 1856 1857 /* Not a service, see if it's a single port or port range. */ 1858 sep = strchr (str, '-'); 1859 if (sep == NULL) { 1860 SETLOPORT(*portRange, strtol(str, &end, 10)); 1861 if (end != str) { 1862 /* Single port. */ 1863 SETNUMPORTS(*portRange, 1); 1864 return 0; 1865 } 1866 1867 /* Error in port range field. */ 1868 errx (1, "%s/%s: unknown service", str, proto); 1869 } 1870 1871 /* Port range, get the values and sanity check. */ 1872 sscanf (str, "%hu-%hu", &loPort, &hiPort); 1873 SETLOPORT(*portRange, loPort); 1874 SETNUMPORTS(*portRange, 0); /* Error by default */ 1875 if (loPort <= hiPort) 1876 SETNUMPORTS(*portRange, hiPort - loPort + 1); 1877 1878 if (GETNUMPORTS(*portRange) == 0) 1879 errx (1, "invalid port range %s", str); 1880 1881 return 0; 1882 } 1883 1884 1885 int StrToProto (const char* str) 1886 { 1887 if (!strcmp (str, "tcp")) 1888 return IPPROTO_TCP; 1889 1890 if (!strcmp (str, "udp")) 1891 return IPPROTO_UDP; 1892 1893 errx (1, "unknown protocol %s. Expected tcp or udp", str); 1894 } 1895 1896 int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange) 1897 { 1898 char* ptr; 1899 1900 ptr = strchr (str, ':'); 1901 if (!ptr) 1902 errx (1, "%s is missing port number", str); 1903 1904 *ptr = '\0'; 1905 ++ptr; 1906 1907 StrToAddr (str, addr); 1908 return StrToPortRange (ptr, proto, portRange); 1909 } 1910 1911 static void 1912 SetupPunchFW(const char *strValue) 1913 { 1914 unsigned int base, num; 1915 1916 if (sscanf(strValue, "%u:%u", &base, &num) != 2) 1917 errx(1, "punch_fw: basenumber:count parameter required"); 1918 1919 LibAliasSetFWBase(mla, base, num); 1920 (void)LibAliasSetMode(mla, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 1921 } 1922 1923 static void 1924 SetupSkinnyPort(const char *strValue) 1925 { 1926 unsigned int port; 1927 1928 if (sscanf(strValue, "%u", &port) != 1) 1929 errx(1, "skinny_port: port parameter required"); 1930 1931 LibAliasSetSkinnyPort(mla, port); 1932 } 1933 1934 static void 1935 NewInstance(const char *name) 1936 { 1937 struct instance *ip; 1938 1939 LIST_FOREACH(ip, &root, list) { 1940 if (!strcmp(ip->name, name)) { 1941 mla = ip->la; 1942 mip = ip; 1943 return; 1944 } 1945 } 1946 ninstance++; 1947 ip = calloc(sizeof *ip, 1); 1948 ip->name = strdup(name); 1949 ip->la = LibAliasInit (ip->la); 1950 ip->assignAliasAddr = 0; 1951 ip->ifName = NULL; 1952 ip->logDropped = 0; 1953 ip->inPort = 0; 1954 ip->outPort = 0; 1955 ip->inOutPort = 0; 1956 ip->aliasAddr.s_addr = INADDR_NONE; 1957 ip->ifMTU = -1; 1958 ip->aliasOverhead = 12; 1959 LIST_INSERT_HEAD(&root, ip, list); 1960 mla = ip->la; 1961 mip = ip; 1962 } 1963