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