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 const 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 socklen_t addrSize; 503 struct ip* ip; 504 char msgBuf[80]; 505 506 /* 507 * Get packet from socket. 508 */ 509 addrSize = sizeof addr; 510 origBytes = recvfrom (fd, 511 buf, 512 sizeof buf, 513 0, 514 (struct sockaddr*) &addr, 515 &addrSize); 516 517 if (origBytes == -1) { 518 519 if (errno != EINTR) 520 Warn ("read from divert socket failed"); 521 522 return; 523 } 524 525 #if 0 526 if (mip->assignAliasAddr) { 527 SetAliasAddressFromIfName (mip->ifName); 528 mip->assignAliasAddr = 0; 529 } 530 #endif 531 /* 532 * This is an IP packet. 533 */ 534 ip = (struct ip*) buf; 535 536 if (verbose) { 537 /* 538 * Print packet direction and protocol type. 539 */ 540 printf ("Glb "); 541 542 switch (ip->ip_p) { 543 case IPPROTO_TCP: 544 printf ("[TCP] "); 545 break; 546 547 case IPPROTO_UDP: 548 printf ("[UDP] "); 549 break; 550 551 case IPPROTO_ICMP: 552 printf ("[ICMP] "); 553 break; 554 555 default: 556 printf ("[%d] ", ip->ip_p); 557 break; 558 } 559 /* 560 * Print addresses. 561 */ 562 PrintPacket (ip); 563 } 564 565 LIST_FOREACH(mip, &root, list) { 566 mla = mip->la; 567 if (LibAliasOutTry (mla, buf, IP_MAXPACKET, 0) != PKT_ALIAS_IGNORED) 568 break; 569 } 570 /* 571 * Length might have changed during aliasing. 572 */ 573 bytes = ntohs (ip->ip_len); 574 /* 575 * Update alias overhead size for outgoing packets. 576 */ 577 if (mip != NULL && bytes - origBytes > mip->aliasOverhead) 578 mip->aliasOverhead = bytes - origBytes; 579 580 if (verbose) { 581 582 /* 583 * Print addresses after aliasing. 584 */ 585 printf (" aliased to\n"); 586 printf (" "); 587 PrintPacket (ip); 588 printf ("\n"); 589 } 590 591 /* 592 * Put packet back for processing. 593 */ 594 wrote = sendto (fd, 595 buf, 596 bytes, 597 0, 598 (struct sockaddr*) &addr, 599 sizeof addr); 600 601 if (wrote != bytes) { 602 603 if (errno == EMSGSIZE) { 604 605 if (mip->ifMTU != -1) 606 SendNeedFragIcmp (icmpSock, 607 (struct ip*) buf, 608 mip->ifMTU - mip->aliasOverhead); 609 } 610 else if (errno == EACCES && logIpfwDenied) { 611 612 sprintf (msgBuf, "failed to write packet back"); 613 Warn (msgBuf); 614 } 615 } 616 } 617 618 619 static void DoAliasing (int fd, int direction) 620 { 621 int bytes; 622 int origBytes; 623 char buf[IP_MAXPACKET]; 624 struct sockaddr_in addr; 625 int wrote; 626 int status; 627 socklen_t addrSize; 628 struct ip* ip; 629 char msgBuf[80]; 630 631 if (mip->assignAliasAddr) { 632 633 SetAliasAddressFromIfName (mip->ifName); 634 mip->assignAliasAddr = 0; 635 } 636 /* 637 * Get packet from socket. 638 */ 639 addrSize = sizeof addr; 640 origBytes = recvfrom (fd, 641 buf, 642 sizeof buf, 643 0, 644 (struct sockaddr*) &addr, 645 &addrSize); 646 647 if (origBytes == -1) { 648 649 if (errno != EINTR) 650 Warn ("read from divert socket failed"); 651 652 return; 653 } 654 /* 655 * This is an IP packet. 656 */ 657 ip = (struct ip*) buf; 658 if (direction == DONT_KNOW) { 659 if (addr.sin_addr.s_addr == INADDR_ANY) 660 direction = OUTPUT; 661 else 662 direction = INPUT; 663 } 664 665 if (verbose) { 666 /* 667 * Print packet direction and protocol type. 668 */ 669 printf (direction == OUTPUT ? "Out " : "In "); 670 if (ninstance > 1) 671 printf ("{%s}", mip->name); 672 673 switch (ip->ip_p) { 674 case IPPROTO_TCP: 675 printf ("[TCP] "); 676 break; 677 678 case IPPROTO_UDP: 679 printf ("[UDP] "); 680 break; 681 682 case IPPROTO_ICMP: 683 printf ("[ICMP] "); 684 break; 685 686 default: 687 printf ("[%d] ", ip->ip_p); 688 break; 689 } 690 /* 691 * Print addresses. 692 */ 693 PrintPacket (ip); 694 } 695 696 if (direction == OUTPUT) { 697 /* 698 * Outgoing packets. Do aliasing. 699 */ 700 LibAliasOut (mla, buf, IP_MAXPACKET); 701 } 702 else { 703 704 /* 705 * Do aliasing. 706 */ 707 status = LibAliasIn (mla, buf, IP_MAXPACKET); 708 if (status == PKT_ALIAS_IGNORED && 709 mip->dropIgnoredIncoming) { 710 711 if (verbose) 712 printf (" dropped.\n"); 713 714 if (mip->logDropped) 715 SyslogPacket (ip, LOG_WARNING, "denied"); 716 717 return; 718 } 719 } 720 /* 721 * Length might have changed during aliasing. 722 */ 723 bytes = ntohs (ip->ip_len); 724 /* 725 * Update alias overhead size for outgoing packets. 726 */ 727 if (direction == OUTPUT && 728 bytes - origBytes > mip->aliasOverhead) 729 mip->aliasOverhead = bytes - origBytes; 730 731 if (verbose) { 732 733 /* 734 * Print addresses after aliasing. 735 */ 736 printf (" aliased to\n"); 737 printf (" "); 738 PrintPacket (ip); 739 printf ("\n"); 740 } 741 742 /* 743 * Put packet back for processing. 744 */ 745 wrote = sendto (fd, 746 buf, 747 bytes, 748 0, 749 (struct sockaddr*) &addr, 750 sizeof addr); 751 752 if (wrote != bytes) { 753 754 if (errno == EMSGSIZE) { 755 756 if (direction == OUTPUT && 757 mip->ifMTU != -1) 758 SendNeedFragIcmp (icmpSock, 759 (struct ip*) buf, 760 mip->ifMTU - mip->aliasOverhead); 761 } 762 else if (errno == EACCES && logIpfwDenied) { 763 764 sprintf (msgBuf, "failed to write packet back"); 765 Warn (msgBuf); 766 } 767 } 768 } 769 770 static void HandleRoutingInfo (int fd) 771 { 772 int bytes; 773 struct if_msghdr ifMsg; 774 /* 775 * Get packet from socket. 776 */ 777 bytes = read (fd, &ifMsg, sizeof ifMsg); 778 if (bytes == -1) { 779 780 Warn ("read from routing socket failed"); 781 return; 782 } 783 784 if (ifMsg.ifm_version != RTM_VERSION) { 785 786 Warn ("unexpected packet read from routing socket"); 787 return; 788 } 789 790 if (verbose) 791 printf ("Routing message %#x received.\n", ifMsg.ifm_type); 792 793 if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO)) { 794 LIST_FOREACH(mip, &root, list) { 795 mla = mip->la; 796 if (ifMsg.ifm_index == mip->ifIndex) { 797 if (verbose) 798 printf("Interface address/MTU has probably changed.\n"); 799 mip->assignAliasAddr = 1; 800 } 801 } 802 } 803 } 804 805 static void PrintPacket (struct ip* ip) 806 { 807 printf ("%s", FormatPacket (ip)); 808 } 809 810 static void SyslogPacket (struct ip* ip, int priority, const char *label) 811 { 812 syslog (priority, "%s %s", label, FormatPacket (ip)); 813 } 814 815 static char* FormatPacket (struct ip* ip) 816 { 817 static char buf[256]; 818 struct tcphdr* tcphdr; 819 struct udphdr* udphdr; 820 struct icmp* icmphdr; 821 char src[20]; 822 char dst[20]; 823 824 strcpy (src, inet_ntoa (ip->ip_src)); 825 strcpy (dst, inet_ntoa (ip->ip_dst)); 826 827 switch (ip->ip_p) { 828 case IPPROTO_TCP: 829 tcphdr = (struct tcphdr*) ((char*) ip + (ip->ip_hl << 2)); 830 sprintf (buf, "[TCP] %s:%d -> %s:%d", 831 src, 832 ntohs (tcphdr->th_sport), 833 dst, 834 ntohs (tcphdr->th_dport)); 835 break; 836 837 case IPPROTO_UDP: 838 udphdr = (struct udphdr*) ((char*) ip + (ip->ip_hl << 2)); 839 sprintf (buf, "[UDP] %s:%d -> %s:%d", 840 src, 841 ntohs (udphdr->uh_sport), 842 dst, 843 ntohs (udphdr->uh_dport)); 844 break; 845 846 case IPPROTO_ICMP: 847 icmphdr = (struct icmp*) ((char*) ip + (ip->ip_hl << 2)); 848 sprintf (buf, "[ICMP] %s -> %s %u(%u)", 849 src, 850 dst, 851 icmphdr->icmp_type, 852 icmphdr->icmp_code); 853 break; 854 855 default: 856 sprintf (buf, "[%d] %s -> %s ", ip->ip_p, src, dst); 857 break; 858 } 859 860 return buf; 861 } 862 863 static void 864 SetAliasAddressFromIfName(const char *ifn) 865 { 866 size_t needed; 867 int mib[6]; 868 char *buf, *lim, *next; 869 struct if_msghdr *ifm; 870 struct ifa_msghdr *ifam; 871 struct sockaddr_dl *sdl; 872 struct sockaddr_in *sin; 873 874 mib[0] = CTL_NET; 875 mib[1] = PF_ROUTE; 876 mib[2] = 0; 877 mib[3] = AF_INET; /* Only IP addresses please */ 878 mib[4] = NET_RT_IFLIST; 879 mib[5] = 0; /* ifIndex??? */ 880 /* 881 * Get interface data. 882 */ 883 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 884 err(1, "iflist-sysctl-estimate"); 885 if ((buf = malloc(needed)) == NULL) 886 errx(1, "malloc failed"); 887 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 888 err(1, "iflist-sysctl-get"); 889 lim = buf + needed; 890 /* 891 * Loop through interfaces until one with 892 * given name is found. This is done to 893 * find correct interface index for routing 894 * message processing. 895 */ 896 mip->ifIndex = 0; 897 next = buf; 898 while (next < lim) { 899 ifm = (struct if_msghdr *)next; 900 next += ifm->ifm_msglen; 901 if (ifm->ifm_version != RTM_VERSION) { 902 if (verbose) 903 warnx("routing message version %d " 904 "not understood", ifm->ifm_version); 905 continue; 906 } 907 if (ifm->ifm_type == RTM_IFINFO) { 908 sdl = (struct sockaddr_dl *)(ifm + 1); 909 if (strlen(ifn) == sdl->sdl_nlen && 910 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 911 mip->ifIndex = ifm->ifm_index; 912 mip->ifMTU = ifm->ifm_data.ifi_mtu; 913 break; 914 } 915 } 916 } 917 if (!mip->ifIndex) 918 errx(1, "unknown interface name %s", ifn); 919 /* 920 * Get interface address. 921 */ 922 sin = NULL; 923 while (next < lim) { 924 ifam = (struct ifa_msghdr *)next; 925 next += ifam->ifam_msglen; 926 if (ifam->ifam_version != RTM_VERSION) { 927 if (verbose) 928 warnx("routing message version %d " 929 "not understood", ifam->ifam_version); 930 continue; 931 } 932 if (ifam->ifam_type != RTM_NEWADDR) 933 break; 934 if (ifam->ifam_addrs & RTA_IFA) { 935 int i; 936 char *cp = (char *)(ifam + 1); 937 938 for (i = 1; i < RTA_IFA; i <<= 1) 939 if (ifam->ifam_addrs & i) 940 cp += SA_SIZE((struct sockaddr *)cp); 941 if (((struct sockaddr *)cp)->sa_family == AF_INET) { 942 sin = (struct sockaddr_in *)cp; 943 break; 944 } 945 } 946 } 947 if (sin == NULL) 948 errx(1, "%s: cannot get interface address", ifn); 949 950 LibAliasSetAddress(mla, sin->sin_addr); 951 syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", 952 inet_ntoa(sin->sin_addr), mip->ifMTU); 953 954 free(buf); 955 } 956 957 void Quit (const char* msg) 958 { 959 Warn (msg); 960 exit (1); 961 } 962 963 void Warn (const char* msg) 964 { 965 if (background) 966 syslog (LOG_ALERT, "%s (%m)", msg); 967 else 968 warn ("%s", msg); 969 } 970 971 static void RefreshAddr (int sig __unused) 972 { 973 LibAliasRefreshModules(); 974 if (mip != NULL && mip->ifName != NULL) 975 mip->assignAliasAddr = 1; 976 } 977 978 static void InitiateShutdown (int sig __unused) 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 __unused) 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 *aliaslink = 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 aliaslink = 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 && aliaslink != 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, aliaslink, 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 *aliaslink; 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 aliaslink = LibAliasRedirectAddr(mla, localAddr, publicAddr); 1796 1797 /* 1798 * Setup LSNAT server pool. 1799 */ 1800 if (serverPool != NULL && aliaslink != NULL) { 1801 ptr = strtok(serverPool, ","); 1802 while (ptr != NULL) { 1803 StrToAddr(ptr, &localAddr); 1804 LibAliasAddServer(mla, aliaslink, 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