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