alias_db.c revision 145925
1/*- 2 * Copyright (c) 2001 Charles Mott <cm@linktel.net> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_db.c 145925 2005-05-05 20:22:09Z glebius $"); 29 30/* 31 Alias_db.c encapsulates all data structures used for storing 32 packet aliasing data. Other parts of the aliasing software 33 access data through functions provided in this file. 34 35 Data storage is based on the notion of a "link", which is 36 established for ICMP echo/reply packets, UDP datagrams and 37 TCP stream connections. A link stores the original source 38 and destination addresses. For UDP and TCP, it also stores 39 source and destination port numbers, as well as an alias 40 port number. Links are also used to store information about 41 fragments. 42 43 There is a facility for sweeping through and deleting old 44 links as new packets are sent through. A simple timeout is 45 used for ICMP and UDP links. TCP links are left alone unless 46 there is an incomplete connection, in which case the link 47 can be deleted after a certain amount of time. 48 49 50 Initial version: August, 1996 (cjm) 51 52 Version 1.4: September 16, 1996 (cjm) 53 Facility for handling incoming links added. 54 55 Version 1.6: September 18, 1996 (cjm) 56 ICMP data handling simplified. 57 58 Version 1.7: January 9, 1997 (cjm) 59 Fragment handling simplified. 60 Saves pointers for unresolved fragments. 61 Permits links for unspecified remote ports 62 or unspecified remote addresses. 63 Fixed bug which did not properly zero port 64 table entries after a link was deleted. 65 Cleaned up some obsolete comments. 66 67 Version 1.8: January 14, 1997 (cjm) 68 Fixed data type error in StartPoint(). 69 (This error did not exist prior to v1.7 70 and was discovered and fixed by Ari Suutari) 71 72 Version 1.9: February 1, 1997 73 Optionally, connections initiated from packet aliasing host 74 machine will will not have their port number aliased unless it 75 conflicts with an aliasing port already being used. (cjm) 76 77 All options earlier being #ifdef'ed are now available through 78 a new interface, SetPacketAliasMode(). This allows run time 79 control (which is now available in PPP+pktAlias through the 80 'alias' keyword). (ee) 81 82 Added ability to create an alias port without 83 either destination address or port specified. 84 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) 85 86 Removed K&R style function headers 87 and general cleanup. (ee) 88 89 Added packetAliasMode to replace compiler #defines's (ee) 90 91 Allocates sockets for partially specified 92 ports if ALIAS_USE_SOCKETS defined. (cjm) 93 94 Version 2.0: March, 1997 95 SetAliasAddress() will now clean up alias links 96 if the aliasing address is changed. (cjm) 97 98 PacketAliasPermanentLink() function added to support permanent 99 links. (J. Fortes suggested the need for this.) 100 Examples: 101 102 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port 103 104 (192.168.0.2, port 21) <-> alias port 3604, known dest addr 105 unknown dest port 106 107 These permanent links allow for incoming connections to 108 machines on the local network. They can be given with a 109 user-chosen amount of specificity, with increasing specificity 110 meaning more security. (cjm) 111 112 Quite a bit of rework to the basic engine. The portTable[] 113 array, which kept track of which ports were in use was replaced 114 by a table/linked list structure. (cjm) 115 116 SetExpire() function added. (cjm) 117 118 DeleteLink() no longer frees memory association with a pointer 119 to a fragment (this bug was first recognized by E. Eklund in 120 v1.9). 121 122 Version 2.1: May, 1997 (cjm) 123 Packet aliasing engine reworked so that it can handle 124 multiple external addresses rather than just a single 125 host address. 126 127 PacketAliasRedirectPort() and PacketAliasRedirectAddr() 128 added to the API. The first function is a more generalized 129 version of PacketAliasPermanentLink(). The second function 130 implements static network address translation. 131 132 Version 3.2: July, 2000 (salander and satoh) 133 Added FindNewPortGroup to get contiguous range of port values. 134 135 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing 136 link but not actually add one. 137 138 Added FindRtspOut, which is closely derived from FindUdpTcpOut, 139 except that the alias port (from FindNewPortGroup) is provided 140 as input. 141 142 See HISTORY file for additional revisions. 143*/ 144 145#ifdef _KERNEL 146#include <sys/param.h> 147#else 148#include <sys/types.h> 149#endif 150 151#include <sys/errno.h> 152#include <sys/queue.h> 153#include <sys/socket.h> 154#include <sys/time.h> 155 156#ifdef _KERNEL 157#include <sys/systm.h> 158#include <sys/kernel.h> 159#include <sys/malloc.h> 160#include <sys/module.h> 161#else 162#include <stdlib.h> 163#include <stdio.h> 164#include <unistd.h> 165#include <arpa/inet.h> 166#endif 167 168/* BSD network include files */ 169#include <netinet/in_systm.h> 170#include <netinet/in.h> 171#include <netinet/ip.h> 172#include <netinet/tcp.h> 173 174#ifdef _KERNEL 175#include <netinet/libalias/alias.h> 176#include <netinet/libalias/alias_local.h> 177#else 178#include "alias.h" 179#include "alias_local.h" 180#endif 181 182static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); 183 184 185/* 186 Constants (note: constants are also defined 187 near relevant functions or structs) 188*/ 189 190/* Parameters used for cleanup of expired links */ 191#define ALIAS_CLEANUP_INTERVAL_SECS 60 192#define ALIAS_CLEANUP_MAX_SPOKES 30 193 194/* Timeouts (in seconds) for different link types */ 195#define ICMP_EXPIRE_TIME 60 196#define UDP_EXPIRE_TIME 60 197#define PROTO_EXPIRE_TIME 60 198#define FRAGMENT_ID_EXPIRE_TIME 10 199#define FRAGMENT_PTR_EXPIRE_TIME 30 200 201/* TCP link expire time for different cases */ 202/* When the link has been used and closed - minimal grace time to 203 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 204#ifndef TCP_EXPIRE_DEAD 205#define TCP_EXPIRE_DEAD 10 206#endif 207 208/* When the link has been used and closed on one side - the other side 209 is allowed to still send data */ 210#ifndef TCP_EXPIRE_SINGLEDEAD 211#define TCP_EXPIRE_SINGLEDEAD 90 212#endif 213 214/* When the link isn't yet up */ 215#ifndef TCP_EXPIRE_INITIAL 216#define TCP_EXPIRE_INITIAL 300 217#endif 218 219/* When the link is up */ 220#ifndef TCP_EXPIRE_CONNECTED 221#define TCP_EXPIRE_CONNECTED 86400 222#endif 223 224 225/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 226 These constants can be anything except zero, which indicates an 227 unknown port number. */ 228 229#define NO_DEST_PORT 1 230#define NO_SRC_PORT 1 231 232 233 234/* Data Structures 235 236 The fundamental data structure used in this program is 237 "struct alias_link". Whenever a TCP connection is made, 238 a UDP datagram is sent out, or an ICMP echo request is made, 239 a link record is made (if it has not already been created). 240 The link record is identified by the source address/port 241 and the destination address/port. In the case of an ICMP 242 echo request, the source port is treated as being equivalent 243 with the 16-bit ID number of the ICMP packet. 244 245 The link record also can store some auxiliary data. For 246 TCP connections that have had sequence and acknowledgment 247 modifications, data space is available to track these changes. 248 A state field is used to keep track in changes to the TCP 249 connection state. ID numbers of fragments can also be 250 stored in the auxiliary space. Pointers to unresolved 251 fragments can also be stored. 252 253 The link records support two independent chainings. Lookup 254 tables for input and out tables hold the initial pointers 255 the link chains. On input, the lookup table indexes on alias 256 port and link type. On output, the lookup table indexes on 257 source address, destination address, source port, destination 258 port and link type. 259*/ 260 261struct ack_data_record { /* used to save changes to ACK/sequence 262 * numbers */ 263 u_long ack_old; 264 u_long ack_new; 265 int delta; 266 int active; 267}; 268 269struct tcp_state { /* Information about TCP connection */ 270 int in; /* State for outside -> inside */ 271 int out; /* State for inside -> outside */ 272 int index; /* Index to ACK data array */ 273 int ack_modified; /* Indicates whether ACK and 274 * sequence numbers */ 275 /* been modified */ 276}; 277 278#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 279 * saved for a modified TCP stream */ 280struct tcp_dat { 281 struct tcp_state state; 282 struct ack_data_record ack[N_LINK_TCP_DATA]; 283 int fwhole; /* Which firewall record is used for this 284 * hole? */ 285}; 286 287struct server { /* LSNAT server pool (circular list) */ 288 struct in_addr addr; 289 u_short port; 290 struct server *next; 291}; 292 293struct alias_link { /* Main data structure */ 294 struct libalias *la; 295 struct in_addr src_addr; /* Address and port information */ 296 struct in_addr dst_addr; 297 struct in_addr alias_addr; 298 struct in_addr proxy_addr; 299 u_short src_port; 300 u_short dst_port; 301 u_short alias_port; 302 u_short proxy_port; 303 struct server *server; 304 305 int link_type; /* Type of link: TCP, UDP, ICMP, 306 * proto, frag */ 307 308/* values for link_type */ 309#define LINK_ICMP IPPROTO_ICMP 310#define LINK_UDP IPPROTO_UDP 311#define LINK_TCP IPPROTO_TCP 312#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 313#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 314#define LINK_ADDR (IPPROTO_MAX + 3) 315#define LINK_PPTP (IPPROTO_MAX + 4) 316 317 int flags; /* indicates special characteristics */ 318 int pflags; /* protocol-specific flags */ 319 320/* flag bits */ 321#define LINK_UNKNOWN_DEST_PORT 0x01 322#define LINK_UNKNOWN_DEST_ADDR 0x02 323#define LINK_PERMANENT 0x04 324#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 325#define LINK_UNFIREWALLED 0x08 326 327 int timestamp; /* Time link was last accessed */ 328 int expire_time; /* Expire time for link */ 329 330 int sockfd; /* socket descriptor */ 331 332 LIST_ENTRY (alias_link) list_out; /* Linked list of 333 * pointers for */ 334 LIST_ENTRY (alias_link) list_in; /* input and output 335 * lookup tables */ 336 337 union { /* Auxiliary data */ 338 char *frag_ptr; 339 struct in_addr frag_addr; 340 struct tcp_dat *tcp; 341 } data; 342}; 343 344/* Internal utility routines (used only in alias_db.c) 345 346Lookup table starting points: 347 StartPointIn() -- link table initial search point for 348 incoming packets 349 StartPointOut() -- link table initial search point for 350 outgoing packets 351 352Miscellaneous: 353 SeqDiff() -- difference between two TCP sequences 354 ShowAliasStats() -- send alias statistics to a monitor file 355*/ 356 357 358/* Local prototypes */ 359static u_int StartPointIn(struct in_addr, u_short, int); 360 361static u_int 362StartPointOut(struct in_addr, struct in_addr, 363 u_short, u_short, int); 364 365static int SeqDiff(u_long, u_long); 366 367#ifndef NO_FW_PUNCH 368/* Firewall control */ 369static void InitPunchFW(struct libalias *); 370static void UninitPunchFW(struct libalias *); 371static void ClearFWHole(struct alias_link *); 372 373#endif 374 375#ifndef NO_LOGGING 376/* Log file control */ 377static void ShowAliasStats(struct libalias *); 378static void InitPacketAliasLog(struct libalias *); 379static void UninitPacketAliasLog(struct libalias *); 380#endif 381 382static u_int 383StartPointIn(struct in_addr alias_addr, 384 u_short alias_port, 385 int link_type) 386{ 387 u_int n; 388 389 n = alias_addr.s_addr; 390 if (link_type != LINK_PPTP) 391 n += alias_port; 392 n += link_type; 393 return (n % LINK_TABLE_IN_SIZE); 394} 395 396 397static u_int 398StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 399 u_short src_port, u_short dst_port, int link_type) 400{ 401 u_int n; 402 403 n = src_addr.s_addr; 404 n += dst_addr.s_addr; 405 if (link_type != LINK_PPTP) { 406 n += src_port; 407 n += dst_port; 408 } 409 n += link_type; 410 411 return (n % LINK_TABLE_OUT_SIZE); 412} 413 414 415static int 416SeqDiff(u_long x, u_long y) 417{ 418/* Return the difference between two TCP sequence numbers */ 419 420/* 421 This function is encapsulated in case there are any unusual 422 arithmetic conditions that need to be considered. 423*/ 424 425 return (ntohl(y) - ntohl(x)); 426} 427 428 429#ifndef NO_LOGGING 430static void 431ShowAliasStats(struct libalias *la) 432{ 433/* Used for debugging */ 434 435 if (la->monitorFile) { 436 fprintf(la->monitorFile, 437 "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", 438 la->icmpLinkCount, 439 la->udpLinkCount, 440 la->tcpLinkCount, 441 la->pptpLinkCount, 442 la->protoLinkCount, 443 la->fragmentIdLinkCount, 444 la->fragmentPtrLinkCount); 445 446 fprintf(la->monitorFile, " / tot=%d (sock=%d)\n", 447 la->icmpLinkCount + la->udpLinkCount 448 + la->tcpLinkCount 449 + la->pptpLinkCount 450 + la->protoLinkCount 451 + la->fragmentIdLinkCount 452 + la->fragmentPtrLinkCount, 453 la->sockCount); 454 455 fflush(la->monitorFile); 456 } 457} 458#endif 459 460/* Internal routines for finding, deleting and adding links 461 462Port Allocation: 463 GetNewPort() -- find and reserve new alias port number 464 GetSocket() -- try to allocate a socket for a given port 465 466Link creation and deletion: 467 CleanupAliasData() - remove all link chains from lookup table 468 IncrementalCleanup() - look for stale links in a single chain 469 DeleteLink() - remove link 470 AddLink() - add link 471 ReLink() - change link 472 473Link search: 474 FindLinkOut() - find link for outgoing packets 475 FindLinkIn() - find link for incoming packets 476 477Port search: 478 FindNewPortGroup() - find an available group of ports 479*/ 480 481/* Local prototypes */ 482static int GetNewPort(struct libalias *, struct alias_link *, int); 483 484static u_short GetSocket(struct libalias *, u_short, int *, int); 485 486static void CleanupAliasData(struct libalias *); 487 488static void IncrementalCleanup(struct libalias *); 489 490static void DeleteLink(struct alias_link *); 491 492static struct alias_link * 493AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr, 494 u_short, u_short, int, int); 495 496static struct alias_link * 497ReLink(struct alias_link *, 498 struct in_addr, struct in_addr, struct in_addr, 499 u_short, u_short, int, int); 500 501static struct alias_link * 502 FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 503 504static struct alias_link * 505 FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 506 507 508#define ALIAS_PORT_BASE 0x08000 509#define ALIAS_PORT_MASK 0x07fff 510#define ALIAS_PORT_MASK_EVEN 0x07ffe 511#define GET_NEW_PORT_MAX_ATTEMPTS 20 512 513#define GET_ALIAS_PORT -1 514#define GET_ALIAS_ID GET_ALIAS_PORT 515 516#define FIND_EVEN_ALIAS_BASE 1 517 518/* GetNewPort() allocates port numbers. Note that if a port number 519 is already in use, that does not mean that it cannot be used by 520 another link concurrently. This is because GetNewPort() looks for 521 unused triplets: (dest addr, dest port, alias port). */ 522 523static int 524GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) 525{ 526 int i; 527 int max_trials; 528 u_short port_sys; 529 u_short port_net; 530 531/* 532 Description of alias_port_param for GetNewPort(). When 533 this parameter is zero or positive, it precisely specifies 534 the port number. GetNewPort() will return this number 535 without check that it is in use. 536 537 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 538 selected port number. 539*/ 540 541 if (alias_port_param == GET_ALIAS_PORT) { 542 /* 543 * The aliasing port is automatically selected by one of 544 * two methods below: 545 */ 546 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 547 548 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 549 /* 550 * When the PKT_ALIAS_SAME_PORTS option is chosen, 551 * the first try will be the actual source port. If 552 * this is already in use, the remainder of the 553 * trials will be random. 554 */ 555 port_net = lnk->src_port; 556 port_sys = ntohs(port_net); 557 } else { 558 /* First trial and all subsequent are random. */ 559 port_sys = random() & ALIAS_PORT_MASK; 560 port_sys += ALIAS_PORT_BASE; 561 port_net = htons(port_sys); 562 } 563 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { 564 lnk->alias_port = (u_short) alias_port_param; 565 return (0); 566 } else { 567#ifdef DEBUG 568 fprintf(stderr, "PacketAlias/GetNewPort(): "); 569 fprintf(stderr, "input parameter error\n"); 570#endif 571 return (-1); 572 } 573 574 575/* Port number search */ 576 for (i = 0; i < max_trials; i++) { 577 int go_ahead; 578 struct alias_link *search_result; 579 580 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr, 581 lnk->dst_port, port_net, 582 lnk->link_type, 0); 583 584 if (search_result == NULL) 585 go_ahead = 1; 586 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED) 587 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 588 go_ahead = 1; 589 else 590 go_ahead = 0; 591 592 if (go_ahead) { 593 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) 594 && (lnk->flags & LINK_PARTIALLY_SPECIFIED) 595 && ((lnk->link_type == LINK_TCP) || 596 (lnk->link_type == LINK_UDP))) { 597 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) { 598 lnk->alias_port = port_net; 599 return (0); 600 } 601 } else { 602 lnk->alias_port = port_net; 603 return (0); 604 } 605 } 606 port_sys = random() & ALIAS_PORT_MASK; 607 port_sys += ALIAS_PORT_BASE; 608 port_net = htons(port_sys); 609 } 610 611#ifdef DEBUG 612 fprintf(stderr, "PacketAlias/GetnewPort(): "); 613 fprintf(stderr, "could not find free port\n"); 614#endif 615 616 return (-1); 617} 618 619 620static u_short 621GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type) 622{ 623 int err; 624 int sock; 625 struct sockaddr_in sock_addr; 626 627 if (link_type == LINK_TCP) 628 sock = socket(AF_INET, SOCK_STREAM, 0); 629 else if (link_type == LINK_UDP) 630 sock = socket(AF_INET, SOCK_DGRAM, 0); 631 else { 632#ifdef DEBUG 633 fprintf(stderr, "PacketAlias/GetSocket(): "); 634 fprintf(stderr, "incorrect link type\n"); 635#endif 636 return (0); 637 } 638 639 if (sock < 0) { 640#ifdef DEBUG 641 fprintf(stderr, "PacketAlias/GetSocket(): "); 642 fprintf(stderr, "socket() error %d\n", *sockfd); 643#endif 644 return (0); 645 } 646 sock_addr.sin_family = AF_INET; 647 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 648 sock_addr.sin_port = port_net; 649 650 err = bind(sock, 651 (struct sockaddr *)&sock_addr, 652 sizeof(sock_addr)); 653 if (err == 0) { 654 la->sockCount++; 655 *sockfd = sock; 656 return (1); 657 } else { 658 close(sock); 659 return (0); 660 } 661} 662 663 664/* FindNewPortGroup() returns a base port number for an available 665 range of contiguous port numbers. Note that if a port number 666 is already in use, that does not mean that it cannot be used by 667 another link concurrently. This is because FindNewPortGroup() 668 looks for unused triplets: (dest addr, dest port, alias port). */ 669 670int 671FindNewPortGroup(struct libalias *la, 672 struct in_addr dst_addr, 673 struct in_addr alias_addr, 674 u_short src_port, 675 u_short dst_port, 676 u_short port_count, 677 u_char proto, 678 u_char align) 679{ 680 int i, j; 681 int max_trials; 682 u_short port_sys; 683 int link_type; 684 685 /* 686 * Get link_type from protocol 687 */ 688 689 switch (proto) { 690 case IPPROTO_UDP: 691 link_type = LINK_UDP; 692 break; 693 case IPPROTO_TCP: 694 link_type = LINK_TCP; 695 break; 696 default: 697 return (0); 698 break; 699 } 700 701 /* 702 * The aliasing port is automatically selected by one of two 703 * methods below: 704 */ 705 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 706 707 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 708 /* 709 * When the ALIAS_SAME_PORTS option is chosen, the first 710 * try will be the actual source port. If this is already 711 * in use, the remainder of the trials will be random. 712 */ 713 port_sys = ntohs(src_port); 714 715 } else { 716 717 /* First trial and all subsequent are random. */ 718 if (align == FIND_EVEN_ALIAS_BASE) 719 port_sys = random() & ALIAS_PORT_MASK_EVEN; 720 else 721 port_sys = random() & ALIAS_PORT_MASK; 722 723 port_sys += ALIAS_PORT_BASE; 724 } 725 726/* Port number search */ 727 for (i = 0; i < max_trials; i++) { 728 729 struct alias_link *search_result; 730 731 for (j = 0; j < port_count; j++) 732 if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr, 733 dst_port, htons(port_sys + j), 734 link_type, 0))) 735 break; 736 737 /* Found a good range, return base */ 738 if (j == port_count) 739 return (htons(port_sys)); 740 741 /* Find a new base to try */ 742 if (align == FIND_EVEN_ALIAS_BASE) 743 port_sys = random() & ALIAS_PORT_MASK_EVEN; 744 else 745 port_sys = random() & ALIAS_PORT_MASK; 746 747 port_sys += ALIAS_PORT_BASE; 748 } 749 750#ifdef DEBUG 751 fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 752 fprintf(stderr, "could not find free port(s)\n"); 753#endif 754 755 return (0); 756} 757 758static void 759CleanupAliasData(struct libalias *la) 760{ 761 struct alias_link *lnk; 762 int i, icount; 763 764 icount = 0; 765 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 766 lnk = LIST_FIRST(&la->linkTableOut[i]); 767 while (lnk != NULL) { 768 struct alias_link *link_next; 769 770 link_next = LIST_NEXT(lnk, list_out); 771 icount++; 772 DeleteLink(lnk); 773 lnk = link_next; 774 } 775 } 776 777 la->cleanupIndex = 0; 778} 779 780 781static void 782IncrementalCleanup(struct libalias *la) 783{ 784 int icount; 785 struct alias_link *lnk; 786 787 icount = 0; 788 lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]); 789 while (lnk != NULL) { 790 int idelta; 791 struct alias_link *link_next; 792 793 link_next = LIST_NEXT(lnk, list_out); 794 idelta = la->timeStamp - lnk->timestamp; 795 switch (lnk->link_type) { 796 case LINK_TCP: 797 if (idelta > lnk->expire_time) { 798 struct tcp_dat *tcp_aux; 799 800 tcp_aux = lnk->data.tcp; 801 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 802 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) { 803 DeleteLink(lnk); 804 icount++; 805 } 806 } 807 break; 808 default: 809 if (idelta > lnk->expire_time) { 810 DeleteLink(lnk); 811 icount++; 812 } 813 break; 814 } 815 lnk = link_next; 816 } 817 818 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) 819 la->cleanupIndex = 0; 820} 821 822static void 823DeleteLink(struct alias_link *lnk) 824{ 825 struct libalias *la = lnk->la; 826 827/* Don't do anything if the link is marked permanent */ 828 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT) 829 return; 830 831#ifndef NO_FW_PUNCH 832/* Delete associated firewall hole, if any */ 833 ClearFWHole(lnk); 834#endif 835 836/* Free memory allocated for LSNAT server pool */ 837 if (lnk->server != NULL) { 838 struct server *head, *curr, *next; 839 840 head = curr = lnk->server; 841 do { 842 next = curr->next; 843 free(curr); 844 } while ((curr = next) != head); 845 } 846/* Adjust output table pointers */ 847 LIST_REMOVE(lnk, list_out); 848 849/* Adjust input table pointers */ 850 LIST_REMOVE(lnk, list_in); 851 852/* Close socket, if one has been allocated */ 853 if (lnk->sockfd != -1) { 854 la->sockCount--; 855 close(lnk->sockfd); 856 } 857/* Link-type dependent cleanup */ 858 switch (lnk->link_type) { 859 case LINK_ICMP: 860 la->icmpLinkCount--; 861 break; 862 case LINK_UDP: 863 la->udpLinkCount--; 864 break; 865 case LINK_TCP: 866 la->tcpLinkCount--; 867 free(lnk->data.tcp); 868 break; 869 case LINK_PPTP: 870 la->pptpLinkCount--; 871 break; 872 case LINK_FRAGMENT_ID: 873 la->fragmentIdLinkCount--; 874 break; 875 case LINK_FRAGMENT_PTR: 876 la->fragmentPtrLinkCount--; 877 if (lnk->data.frag_ptr != NULL) 878 free(lnk->data.frag_ptr); 879 break; 880 case LINK_ADDR: 881 break; 882 default: 883 la->protoLinkCount--; 884 break; 885 } 886 887/* Free memory */ 888 free(lnk); 889 890#ifndef NO_LOGGING 891/* Write statistics, if logging enabled */ 892 if (la->packetAliasMode & PKT_ALIAS_LOG) { 893 ShowAliasStats(la); 894 } 895#endif 896} 897 898 899static struct alias_link * 900AddLink(struct libalias *la, struct in_addr src_addr, 901 struct in_addr dst_addr, 902 struct in_addr alias_addr, 903 u_short src_port, 904 u_short dst_port, 905 int alias_port_param, /* if less than zero, alias */ 906 int link_type) 907{ /* port will be automatically *//* chosen. 908 * If greater than */ 909 u_int start_point; /* zero, equal to alias port */ 910 struct alias_link *lnk; 911 912 lnk = malloc(sizeof(struct alias_link)); 913 if (lnk != NULL) { 914 /* Basic initialization */ 915 lnk->la = la; 916 lnk->src_addr = src_addr; 917 lnk->dst_addr = dst_addr; 918 lnk->alias_addr = alias_addr; 919 lnk->proxy_addr.s_addr = INADDR_ANY; 920 lnk->src_port = src_port; 921 lnk->dst_port = dst_port; 922 lnk->proxy_port = 0; 923 lnk->server = NULL; 924 lnk->link_type = link_type; 925 lnk->sockfd = -1; 926 lnk->flags = 0; 927 lnk->pflags = 0; 928 lnk->timestamp = la->timeStamp; 929 930 /* Expiration time */ 931 switch (link_type) { 932 case LINK_ICMP: 933 lnk->expire_time = ICMP_EXPIRE_TIME; 934 break; 935 case LINK_UDP: 936 lnk->expire_time = UDP_EXPIRE_TIME; 937 break; 938 case LINK_TCP: 939 lnk->expire_time = TCP_EXPIRE_INITIAL; 940 break; 941 case LINK_PPTP: 942 lnk->flags |= LINK_PERMANENT; /* no timeout. */ 943 break; 944 case LINK_FRAGMENT_ID: 945 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; 946 break; 947 case LINK_FRAGMENT_PTR: 948 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 949 break; 950 case LINK_ADDR: 951 break; 952 default: 953 lnk->expire_time = PROTO_EXPIRE_TIME; 954 break; 955 } 956 957 /* Determine alias flags */ 958 if (dst_addr.s_addr == INADDR_ANY) 959 lnk->flags |= LINK_UNKNOWN_DEST_ADDR; 960 if (dst_port == 0) 961 lnk->flags |= LINK_UNKNOWN_DEST_PORT; 962 963 /* Determine alias port */ 964 if (GetNewPort(la, lnk, alias_port_param) != 0) { 965 free(lnk); 966 return (NULL); 967 } 968 /* Link-type dependent initialization */ 969 switch (link_type) { 970 struct tcp_dat *aux_tcp; 971 972 case LINK_ICMP: 973 la->icmpLinkCount++; 974 break; 975 case LINK_UDP: 976 la->udpLinkCount++; 977 break; 978 case LINK_TCP: 979 aux_tcp = malloc(sizeof(struct tcp_dat)); 980 if (aux_tcp != NULL) { 981 int i; 982 983 la->tcpLinkCount++; 984 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 985 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 986 aux_tcp->state.index = 0; 987 aux_tcp->state.ack_modified = 0; 988 for (i = 0; i < N_LINK_TCP_DATA; i++) 989 aux_tcp->ack[i].active = 0; 990 aux_tcp->fwhole = -1; 991 lnk->data.tcp = aux_tcp; 992 } else { 993#ifdef DEBUG 994 fprintf(stderr, "PacketAlias/AddLink: "); 995 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 996#endif 997 free(lnk); 998 return (NULL); 999 } 1000 break; 1001 case LINK_PPTP: 1002 la->pptpLinkCount++; 1003 break; 1004 case LINK_FRAGMENT_ID: 1005 la->fragmentIdLinkCount++; 1006 break; 1007 case LINK_FRAGMENT_PTR: 1008 la->fragmentPtrLinkCount++; 1009 break; 1010 case LINK_ADDR: 1011 break; 1012 default: 1013 la->protoLinkCount++; 1014 break; 1015 } 1016 1017 /* Set up pointers for output lookup table */ 1018 start_point = StartPointOut(src_addr, dst_addr, 1019 src_port, dst_port, link_type); 1020 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); 1021 1022 /* Set up pointers for input lookup table */ 1023 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); 1024 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); 1025 } else { 1026#ifdef DEBUG 1027 fprintf(stderr, "PacketAlias/AddLink(): "); 1028 fprintf(stderr, "malloc() call failed.\n"); 1029#endif 1030 } 1031#ifndef NO_LOGGING 1032 if (la->packetAliasMode & PKT_ALIAS_LOG) { 1033 ShowAliasStats(la); 1034 } 1035#endif 1036 return (lnk); 1037} 1038 1039static struct alias_link * 1040ReLink(struct alias_link *old_lnk, 1041 struct in_addr src_addr, 1042 struct in_addr dst_addr, 1043 struct in_addr alias_addr, 1044 u_short src_port, 1045 u_short dst_port, 1046 int alias_port_param, /* if less than zero, alias */ 1047 int link_type) 1048{ /* port will be automatically *//* chosen. 1049 * If greater than */ 1050 struct alias_link *new_lnk; /* zero, equal to alias port */ 1051 struct libalias *la = old_lnk->la; 1052 1053 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1054 src_port, dst_port, alias_port_param, 1055 link_type); 1056#ifndef NO_FW_PUNCH 1057 if (new_lnk != NULL && 1058 old_lnk->link_type == LINK_TCP && 1059 old_lnk->data.tcp->fwhole > 0) { 1060 PunchFWHole(new_lnk); 1061 } 1062#endif 1063 DeleteLink(old_lnk); 1064 return (new_lnk); 1065} 1066 1067static struct alias_link * 1068_FindLinkOut(struct libalias *la, struct in_addr src_addr, 1069 struct in_addr dst_addr, 1070 u_short src_port, 1071 u_short dst_port, 1072 int link_type, 1073 int replace_partial_links) 1074{ 1075 u_int i; 1076 struct alias_link *lnk; 1077 1078 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1079 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { 1080 if (lnk->src_addr.s_addr == src_addr.s_addr 1081 && lnk->server == NULL 1082 && lnk->dst_addr.s_addr == dst_addr.s_addr 1083 && lnk->dst_port == dst_port 1084 && lnk->src_port == src_port 1085 && lnk->link_type == link_type) { 1086 lnk->timestamp = la->timeStamp; 1087 break; 1088 } 1089 } 1090 1091/* Search for partially specified links. */ 1092 if (lnk == NULL && replace_partial_links) { 1093 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1094 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1095 link_type, 0); 1096 if (lnk == NULL) 1097 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 1098 dst_port, link_type, 0); 1099 } 1100 if (lnk == NULL && 1101 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1102 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, 1103 link_type, 0); 1104 } 1105 if (lnk != NULL) { 1106 lnk = ReLink(lnk, 1107 src_addr, dst_addr, lnk->alias_addr, 1108 src_port, dst_port, lnk->alias_port, 1109 link_type); 1110 } 1111 } 1112 return (lnk); 1113} 1114 1115static struct alias_link * 1116FindLinkOut(struct libalias *la, struct in_addr src_addr, 1117 struct in_addr dst_addr, 1118 u_short src_port, 1119 u_short dst_port, 1120 int link_type, 1121 int replace_partial_links) 1122{ 1123 struct alias_link *lnk; 1124 1125 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1126 link_type, replace_partial_links); 1127 1128 if (lnk == NULL) { 1129 /* 1130 * The following allows permanent links to be specified as 1131 * using the default source address (i.e. device interface 1132 * address) without knowing in advance what that address 1133 * is. 1134 */ 1135 if (la->aliasAddress.s_addr != INADDR_ANY && 1136 src_addr.s_addr == la->aliasAddress.s_addr) { 1137 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, 1138 link_type, replace_partial_links); 1139 } 1140 } 1141 return (lnk); 1142} 1143 1144 1145static struct alias_link * 1146_FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1147 struct in_addr alias_addr, 1148 u_short dst_port, 1149 u_short alias_port, 1150 int link_type, 1151 int replace_partial_links) 1152{ 1153 int flags_in; 1154 u_int start_point; 1155 struct alias_link *lnk; 1156 struct alias_link *lnk_fully_specified; 1157 struct alias_link *lnk_unknown_all; 1158 struct alias_link *lnk_unknown_dst_addr; 1159 struct alias_link *lnk_unknown_dst_port; 1160 1161/* Initialize pointers */ 1162 lnk_fully_specified = NULL; 1163 lnk_unknown_all = NULL; 1164 lnk_unknown_dst_addr = NULL; 1165 lnk_unknown_dst_port = NULL; 1166 1167/* If either the dest addr or port is unknown, the search 1168 loop will have to know about this. */ 1169 1170 flags_in = 0; 1171 if (dst_addr.s_addr == INADDR_ANY) 1172 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1173 if (dst_port == 0) 1174 flags_in |= LINK_UNKNOWN_DEST_PORT; 1175 1176/* Search loop */ 1177 start_point = StartPointIn(alias_addr, alias_port, link_type); 1178 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { 1179 int flags; 1180 1181 flags = flags_in | lnk->flags; 1182 if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1183 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1184 && lnk->alias_port == alias_port 1185 && lnk->dst_addr.s_addr == dst_addr.s_addr 1186 && lnk->dst_port == dst_port 1187 && lnk->link_type == link_type) { 1188 lnk_fully_specified = lnk; 1189 break; 1190 } 1191 } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1192 && (flags & LINK_UNKNOWN_DEST_PORT)) { 1193 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1194 && lnk->alias_port == alias_port 1195 && lnk->link_type == link_type) { 1196 if (lnk_unknown_all == NULL) 1197 lnk_unknown_all = lnk; 1198 } 1199 } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1200 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1201 && lnk->alias_port == alias_port 1202 && lnk->link_type == link_type 1203 && lnk->dst_port == dst_port) { 1204 if (lnk_unknown_dst_addr == NULL) 1205 lnk_unknown_dst_addr = lnk; 1206 } 1207 } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1208 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1209 && lnk->alias_port == alias_port 1210 && lnk->link_type == link_type 1211 && lnk->dst_addr.s_addr == dst_addr.s_addr) { 1212 if (lnk_unknown_dst_port == NULL) 1213 lnk_unknown_dst_port = lnk; 1214 } 1215 } 1216 } 1217 1218 1219 1220 if (lnk_fully_specified != NULL) { 1221 lnk_fully_specified->timestamp = la->timeStamp; 1222 lnk = lnk_fully_specified; 1223 } else if (lnk_unknown_dst_port != NULL) 1224 lnk = lnk_unknown_dst_port; 1225 else if (lnk_unknown_dst_addr != NULL) 1226 lnk = lnk_unknown_dst_addr; 1227 else if (lnk_unknown_all != NULL) 1228 lnk = lnk_unknown_all; 1229 else 1230 return (NULL); 1231 1232 if (replace_partial_links && 1233 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { 1234 struct in_addr src_addr; 1235 u_short src_port; 1236 1237 if (lnk->server != NULL) { /* LSNAT link */ 1238 src_addr = lnk->server->addr; 1239 src_port = lnk->server->port; 1240 lnk->server = lnk->server->next; 1241 } else { 1242 src_addr = lnk->src_addr; 1243 src_port = lnk->src_port; 1244 } 1245 1246 lnk = ReLink(lnk, 1247 src_addr, dst_addr, alias_addr, 1248 src_port, dst_port, alias_port, 1249 link_type); 1250 } 1251 return (lnk); 1252} 1253 1254static struct alias_link * 1255FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1256 struct in_addr alias_addr, 1257 u_short dst_port, 1258 u_short alias_port, 1259 int link_type, 1260 int replace_partial_links) 1261{ 1262 struct alias_link *lnk; 1263 1264 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1265 link_type, replace_partial_links); 1266 1267 if (lnk == NULL) { 1268 /* 1269 * The following allows permanent links to be specified as 1270 * using the default aliasing address (i.e. device 1271 * interface address) without knowing in advance what that 1272 * address is. 1273 */ 1274 if (la->aliasAddress.s_addr != INADDR_ANY && 1275 alias_addr.s_addr == la->aliasAddress.s_addr) { 1276 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, 1277 link_type, replace_partial_links); 1278 } 1279 } 1280 return (lnk); 1281} 1282 1283 1284 1285 1286/* External routines for finding/adding links 1287 1288-- "external" means outside alias_db.c, but within alias*.c -- 1289 1290 FindIcmpIn(), FindIcmpOut() 1291 FindFragmentIn1(), FindFragmentIn2() 1292 AddFragmentPtrLink(), FindFragmentPtr() 1293 FindProtoIn(), FindProtoOut() 1294 FindUdpTcpIn(), FindUdpTcpOut() 1295 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 1296 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 1297 FindOriginalAddress(), FindAliasAddress() 1298 1299(prototypes in alias_local.h) 1300*/ 1301 1302 1303struct alias_link * 1304FindIcmpIn(struct libalias *la, struct in_addr dst_addr, 1305 struct in_addr alias_addr, 1306 u_short id_alias, 1307 int create) 1308{ 1309 struct alias_link *lnk; 1310 1311 lnk = FindLinkIn(la, dst_addr, alias_addr, 1312 NO_DEST_PORT, id_alias, 1313 LINK_ICMP, 0); 1314 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1315 struct in_addr target_addr; 1316 1317 target_addr = FindOriginalAddress(la, alias_addr); 1318 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1319 id_alias, NO_DEST_PORT, id_alias, 1320 LINK_ICMP); 1321 } 1322 return (lnk); 1323} 1324 1325 1326struct alias_link * 1327FindIcmpOut(struct libalias *la, struct in_addr src_addr, 1328 struct in_addr dst_addr, 1329 u_short id, 1330 int create) 1331{ 1332 struct alias_link *lnk; 1333 1334 lnk = FindLinkOut(la, src_addr, dst_addr, 1335 id, NO_DEST_PORT, 1336 LINK_ICMP, 0); 1337 if (lnk == NULL && create) { 1338 struct in_addr alias_addr; 1339 1340 alias_addr = FindAliasAddress(la, src_addr); 1341 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1342 id, NO_DEST_PORT, GET_ALIAS_ID, 1343 LINK_ICMP); 1344 } 1345 return (lnk); 1346} 1347 1348 1349struct alias_link * 1350FindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1351 struct in_addr alias_addr, 1352 u_short ip_id) 1353{ 1354 struct alias_link *lnk; 1355 1356 lnk = FindLinkIn(la, dst_addr, alias_addr, 1357 NO_DEST_PORT, ip_id, 1358 LINK_FRAGMENT_ID, 0); 1359 1360 if (lnk == NULL) { 1361 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr, 1362 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1363 LINK_FRAGMENT_ID); 1364 } 1365 return (lnk); 1366} 1367 1368 1369struct alias_link * 1370FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if 1371 * one */ 1372 struct in_addr alias_addr, /* is not found. */ 1373 u_short ip_id) 1374{ 1375 return FindLinkIn(la, dst_addr, alias_addr, 1376 NO_DEST_PORT, ip_id, 1377 LINK_FRAGMENT_ID, 0); 1378} 1379 1380 1381struct alias_link * 1382AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1383 u_short ip_id) 1384{ 1385 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress, 1386 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1387 LINK_FRAGMENT_PTR); 1388} 1389 1390 1391struct alias_link * 1392FindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1393 u_short ip_id) 1394{ 1395 return FindLinkIn(la, dst_addr, la->nullAddress, 1396 NO_DEST_PORT, ip_id, 1397 LINK_FRAGMENT_PTR, 0); 1398} 1399 1400 1401struct alias_link * 1402FindProtoIn(struct libalias *la, struct in_addr dst_addr, 1403 struct in_addr alias_addr, 1404 u_char proto) 1405{ 1406 struct alias_link *lnk; 1407 1408 lnk = FindLinkIn(la, dst_addr, alias_addr, 1409 NO_DEST_PORT, 0, 1410 proto, 1); 1411 1412 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1413 struct in_addr target_addr; 1414 1415 target_addr = FindOriginalAddress(la, alias_addr); 1416 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1417 NO_SRC_PORT, NO_DEST_PORT, 0, 1418 proto); 1419 } 1420 return (lnk); 1421} 1422 1423 1424struct alias_link * 1425FindProtoOut(struct libalias *la, struct in_addr src_addr, 1426 struct in_addr dst_addr, 1427 u_char proto) 1428{ 1429 struct alias_link *lnk; 1430 1431 lnk = FindLinkOut(la, src_addr, dst_addr, 1432 NO_SRC_PORT, NO_DEST_PORT, 1433 proto, 1); 1434 1435 if (lnk == NULL) { 1436 struct in_addr alias_addr; 1437 1438 alias_addr = FindAliasAddress(la, src_addr); 1439 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1440 NO_SRC_PORT, NO_DEST_PORT, 0, 1441 proto); 1442 } 1443 return (lnk); 1444} 1445 1446 1447struct alias_link * 1448FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1449 struct in_addr alias_addr, 1450 u_short dst_port, 1451 u_short alias_port, 1452 u_char proto, 1453 int create) 1454{ 1455 int link_type; 1456 struct alias_link *lnk; 1457 1458 switch (proto) { 1459 case IPPROTO_UDP: 1460 link_type = LINK_UDP; 1461 break; 1462 case IPPROTO_TCP: 1463 link_type = LINK_TCP; 1464 break; 1465 default: 1466 return (NULL); 1467 break; 1468 } 1469 1470 lnk = FindLinkIn(la, dst_addr, alias_addr, 1471 dst_port, alias_port, 1472 link_type, create); 1473 1474 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1475 struct in_addr target_addr; 1476 1477 target_addr = FindOriginalAddress(la, alias_addr); 1478 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1479 alias_port, dst_port, alias_port, 1480 link_type); 1481 } 1482 return (lnk); 1483} 1484 1485 1486struct alias_link * 1487FindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1488 struct in_addr dst_addr, 1489 u_short src_port, 1490 u_short dst_port, 1491 u_char proto, 1492 int create) 1493{ 1494 int link_type; 1495 struct alias_link *lnk; 1496 1497 switch (proto) { 1498 case IPPROTO_UDP: 1499 link_type = LINK_UDP; 1500 break; 1501 case IPPROTO_TCP: 1502 link_type = LINK_TCP; 1503 break; 1504 default: 1505 return (NULL); 1506 break; 1507 } 1508 1509 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 1510 1511 if (lnk == NULL && create) { 1512 struct in_addr alias_addr; 1513 1514 alias_addr = FindAliasAddress(la, src_addr); 1515 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1516 src_port, dst_port, GET_ALIAS_PORT, 1517 link_type); 1518 } 1519 return (lnk); 1520} 1521 1522 1523struct alias_link * 1524AddPptp(struct libalias *la, struct in_addr src_addr, 1525 struct in_addr dst_addr, 1526 struct in_addr alias_addr, 1527 u_int16_t src_call_id) 1528{ 1529 struct alias_link *lnk; 1530 1531 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1532 src_call_id, 0, GET_ALIAS_PORT, 1533 LINK_PPTP); 1534 1535 return (lnk); 1536} 1537 1538 1539struct alias_link * 1540FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1541 struct in_addr dst_addr, 1542 u_int16_t src_call_id) 1543{ 1544 u_int i; 1545 struct alias_link *lnk; 1546 1547 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1548 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1549 if (lnk->link_type == LINK_PPTP && 1550 lnk->src_addr.s_addr == src_addr.s_addr && 1551 lnk->dst_addr.s_addr == dst_addr.s_addr && 1552 lnk->src_port == src_call_id) 1553 break; 1554 1555 return (lnk); 1556} 1557 1558 1559struct alias_link * 1560FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1561 struct in_addr dst_addr, 1562 u_int16_t dst_call_id) 1563{ 1564 u_int i; 1565 struct alias_link *lnk; 1566 1567 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1568 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1569 if (lnk->link_type == LINK_PPTP && 1570 lnk->src_addr.s_addr == src_addr.s_addr && 1571 lnk->dst_addr.s_addr == dst_addr.s_addr && 1572 lnk->dst_port == dst_call_id) 1573 break; 1574 1575 return (lnk); 1576} 1577 1578 1579struct alias_link * 1580FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1581 struct in_addr alias_addr, 1582 u_int16_t dst_call_id) 1583{ 1584 u_int i; 1585 struct alias_link *lnk; 1586 1587 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1588 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) 1589 if (lnk->link_type == LINK_PPTP && 1590 lnk->dst_addr.s_addr == dst_addr.s_addr && 1591 lnk->alias_addr.s_addr == alias_addr.s_addr && 1592 lnk->dst_port == dst_call_id) 1593 break; 1594 1595 return (lnk); 1596} 1597 1598 1599struct alias_link * 1600FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1601 struct in_addr alias_addr, 1602 u_int16_t alias_call_id) 1603{ 1604 struct alias_link *lnk; 1605 1606 lnk = FindLinkIn(la, dst_addr, alias_addr, 1607 0 /* any */ , alias_call_id, 1608 LINK_PPTP, 0); 1609 1610 1611 return (lnk); 1612} 1613 1614 1615struct alias_link * 1616FindRtspOut(struct libalias *la, struct in_addr src_addr, 1617 struct in_addr dst_addr, 1618 u_short src_port, 1619 u_short alias_port, 1620 u_char proto) 1621{ 1622 int link_type; 1623 struct alias_link *lnk; 1624 1625 switch (proto) { 1626 case IPPROTO_UDP: 1627 link_type = LINK_UDP; 1628 break; 1629 case IPPROTO_TCP: 1630 link_type = LINK_TCP; 1631 break; 1632 default: 1633 return (NULL); 1634 break; 1635 } 1636 1637 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 1638 1639 if (lnk == NULL) { 1640 struct in_addr alias_addr; 1641 1642 alias_addr = FindAliasAddress(la, src_addr); 1643 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1644 src_port, 0, alias_port, 1645 link_type); 1646 } 1647 return (lnk); 1648} 1649 1650 1651struct in_addr 1652FindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 1653{ 1654 struct alias_link *lnk; 1655 1656 lnk = FindLinkIn(la, la->nullAddress, alias_addr, 1657 0, 0, LINK_ADDR, 0); 1658 if (lnk == NULL) { 1659 la->newDefaultLink = 1; 1660 if (la->targetAddress.s_addr == INADDR_ANY) 1661 return (alias_addr); 1662 else if (la->targetAddress.s_addr == INADDR_NONE) 1663 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1664 la->aliasAddress : alias_addr; 1665 else 1666 return (la->targetAddress); 1667 } else { 1668 if (lnk->server != NULL) { /* LSNAT link */ 1669 struct in_addr src_addr; 1670 1671 src_addr = lnk->server->addr; 1672 lnk->server = lnk->server->next; 1673 return (src_addr); 1674 } else if (lnk->src_addr.s_addr == INADDR_ANY) 1675 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1676 la->aliasAddress : alias_addr; 1677 else 1678 return (lnk->src_addr); 1679 } 1680} 1681 1682 1683struct in_addr 1684FindAliasAddress(struct libalias *la, struct in_addr original_addr) 1685{ 1686 struct alias_link *lnk; 1687 1688 lnk = FindLinkOut(la, original_addr, la->nullAddress, 1689 0, 0, LINK_ADDR, 0); 1690 if (lnk == NULL) { 1691 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1692 la->aliasAddress : original_addr; 1693 } else { 1694 if (lnk->alias_addr.s_addr == INADDR_ANY) 1695 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1696 la->aliasAddress : original_addr; 1697 else 1698 return (lnk->alias_addr); 1699 } 1700} 1701 1702 1703/* External routines for getting or changing link data 1704 (external to alias_db.c, but internal to alias*.c) 1705 1706 SetFragmentData(), GetFragmentData() 1707 SetFragmentPtr(), GetFragmentPtr() 1708 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1709 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1710 GetOriginalPort(), GetAliasPort() 1711 SetAckModified(), GetAckModified() 1712 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1713 SetProtocolFlags(), GetProtocolFlags() 1714 SetDestCallId() 1715*/ 1716 1717 1718void 1719SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 1720{ 1721 lnk->data.frag_addr = src_addr; 1722} 1723 1724 1725void 1726GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 1727{ 1728 *src_addr = lnk->data.frag_addr; 1729} 1730 1731 1732void 1733SetFragmentPtr(struct alias_link *lnk, char *fptr) 1734{ 1735 lnk->data.frag_ptr = fptr; 1736} 1737 1738 1739void 1740GetFragmentPtr(struct alias_link *lnk, char **fptr) 1741{ 1742 *fptr = lnk->data.frag_ptr; 1743} 1744 1745 1746void 1747SetStateIn(struct alias_link *lnk, int state) 1748{ 1749 /* TCP input state */ 1750 switch (state) { 1751 case ALIAS_TCP_STATE_DISCONNECTED: 1752 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1753 lnk->expire_time = TCP_EXPIRE_DEAD; 1754 else 1755 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1756 break; 1757 case ALIAS_TCP_STATE_CONNECTED: 1758 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1759 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1760 break; 1761 default: 1762 abort(); 1763 } 1764 lnk->data.tcp->state.in = state; 1765} 1766 1767 1768void 1769SetStateOut(struct alias_link *lnk, int state) 1770{ 1771 /* TCP output state */ 1772 switch (state) { 1773 case ALIAS_TCP_STATE_DISCONNECTED: 1774 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1775 lnk->expire_time = TCP_EXPIRE_DEAD; 1776 else 1777 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1778 break; 1779 case ALIAS_TCP_STATE_CONNECTED: 1780 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1781 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1782 break; 1783 default: 1784 abort(); 1785 } 1786 lnk->data.tcp->state.out = state; 1787} 1788 1789 1790int 1791GetStateIn(struct alias_link *lnk) 1792{ 1793 /* TCP input state */ 1794 return (lnk->data.tcp->state.in); 1795} 1796 1797 1798int 1799GetStateOut(struct alias_link *lnk) 1800{ 1801 /* TCP output state */ 1802 return (lnk->data.tcp->state.out); 1803} 1804 1805 1806struct in_addr 1807GetOriginalAddress(struct alias_link *lnk) 1808{ 1809 if (lnk->src_addr.s_addr == INADDR_ANY) 1810 return (lnk->la->aliasAddress); 1811 else 1812 return (lnk->src_addr); 1813} 1814 1815 1816struct in_addr 1817GetDestAddress(struct alias_link *lnk) 1818{ 1819 return (lnk->dst_addr); 1820} 1821 1822 1823struct in_addr 1824GetAliasAddress(struct alias_link *lnk) 1825{ 1826 if (lnk->alias_addr.s_addr == INADDR_ANY) 1827 return (lnk->la->aliasAddress); 1828 else 1829 return (lnk->alias_addr); 1830} 1831 1832 1833struct in_addr 1834GetDefaultAliasAddress(struct libalias *la) 1835{ 1836 return (la->aliasAddress); 1837} 1838 1839 1840void 1841SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 1842{ 1843 la->aliasAddress = alias_addr; 1844} 1845 1846 1847u_short 1848GetOriginalPort(struct alias_link *lnk) 1849{ 1850 return (lnk->src_port); 1851} 1852 1853 1854u_short 1855GetAliasPort(struct alias_link *lnk) 1856{ 1857 return (lnk->alias_port); 1858} 1859 1860#ifndef NO_FW_PUNCH 1861static u_short 1862GetDestPort(struct alias_link *lnk) 1863{ 1864 return (lnk->dst_port); 1865} 1866 1867#endif 1868 1869void 1870SetAckModified(struct alias_link *lnk) 1871{ 1872/* Indicate that ACK numbers have been modified in a TCP connection */ 1873 lnk->data.tcp->state.ack_modified = 1; 1874} 1875 1876 1877struct in_addr 1878GetProxyAddress(struct alias_link *lnk) 1879{ 1880 return (lnk->proxy_addr); 1881} 1882 1883 1884void 1885SetProxyAddress(struct alias_link *lnk, struct in_addr addr) 1886{ 1887 lnk->proxy_addr = addr; 1888} 1889 1890 1891u_short 1892GetProxyPort(struct alias_link *lnk) 1893{ 1894 return (lnk->proxy_port); 1895} 1896 1897 1898void 1899SetProxyPort(struct alias_link *lnk, u_short port) 1900{ 1901 lnk->proxy_port = port; 1902} 1903 1904 1905int 1906GetAckModified(struct alias_link *lnk) 1907{ 1908/* See if ACK numbers have been modified */ 1909 return (lnk->data.tcp->state.ack_modified); 1910} 1911 1912 1913int 1914GetDeltaAckIn(struct ip *pip, struct alias_link *lnk) 1915{ 1916/* 1917Find out how much the ACK number has been altered for an incoming 1918TCP packet. To do this, a circular list of ACK numbers where the TCP 1919packet size was altered is searched. 1920*/ 1921 1922 int i; 1923 struct tcphdr *tc; 1924 int delta, ack_diff_min; 1925 u_long ack; 1926 1927 tc = ip_next(pip); 1928 ack = tc->th_ack; 1929 1930 delta = 0; 1931 ack_diff_min = -1; 1932 for (i = 0; i < N_LINK_TCP_DATA; i++) { 1933 struct ack_data_record x; 1934 1935 x = lnk->data.tcp->ack[i]; 1936 if (x.active == 1) { 1937 int ack_diff; 1938 1939 ack_diff = SeqDiff(x.ack_new, ack); 1940 if (ack_diff >= 0) { 1941 if (ack_diff_min >= 0) { 1942 if (ack_diff < ack_diff_min) { 1943 delta = x.delta; 1944 ack_diff_min = ack_diff; 1945 } 1946 } else { 1947 delta = x.delta; 1948 ack_diff_min = ack_diff; 1949 } 1950 } 1951 } 1952 } 1953 return (delta); 1954} 1955 1956 1957int 1958GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk) 1959{ 1960/* 1961Find out how much the sequence number has been altered for an outgoing 1962TCP packet. To do this, a circular list of ACK numbers where the TCP 1963packet size was altered is searched. 1964*/ 1965 1966 int i; 1967 struct tcphdr *tc; 1968 int delta, seq_diff_min; 1969 u_long seq; 1970 1971 tc = ip_next(pip); 1972 seq = tc->th_seq; 1973 1974 delta = 0; 1975 seq_diff_min = -1; 1976 for (i = 0; i < N_LINK_TCP_DATA; i++) { 1977 struct ack_data_record x; 1978 1979 x = lnk->data.tcp->ack[i]; 1980 if (x.active == 1) { 1981 int seq_diff; 1982 1983 seq_diff = SeqDiff(x.ack_old, seq); 1984 if (seq_diff >= 0) { 1985 if (seq_diff_min >= 0) { 1986 if (seq_diff < seq_diff_min) { 1987 delta = x.delta; 1988 seq_diff_min = seq_diff; 1989 } 1990 } else { 1991 delta = x.delta; 1992 seq_diff_min = seq_diff; 1993 } 1994 } 1995 } 1996 } 1997 return (delta); 1998} 1999 2000 2001void 2002AddSeq(struct ip *pip, struct alias_link *lnk, int delta) 2003{ 2004/* 2005When a TCP packet has been altered in length, save this 2006information in a circular list. If enough packets have 2007been altered, then this list will begin to overwrite itself. 2008*/ 2009 2010 struct tcphdr *tc; 2011 struct ack_data_record x; 2012 int hlen, tlen, dlen; 2013 int i; 2014 2015 tc = ip_next(pip); 2016 2017 hlen = (pip->ip_hl + tc->th_off) << 2; 2018 tlen = ntohs(pip->ip_len); 2019 dlen = tlen - hlen; 2020 2021 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2022 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2023 x.delta = delta; 2024 x.active = 1; 2025 2026 i = lnk->data.tcp->state.index; 2027 lnk->data.tcp->ack[i] = x; 2028 2029 i++; 2030 if (i == N_LINK_TCP_DATA) 2031 lnk->data.tcp->state.index = 0; 2032 else 2033 lnk->data.tcp->state.index = i; 2034} 2035 2036void 2037SetExpire(struct alias_link *lnk, int expire) 2038{ 2039 if (expire == 0) { 2040 lnk->flags &= ~LINK_PERMANENT; 2041 DeleteLink(lnk); 2042 } else if (expire == -1) { 2043 lnk->flags |= LINK_PERMANENT; 2044 } else if (expire > 0) { 2045 lnk->expire_time = expire; 2046 } else { 2047#ifdef DEBUG 2048 fprintf(stderr, "PacketAlias/SetExpire(): "); 2049 fprintf(stderr, "error in expire parameter\n"); 2050#endif 2051 } 2052} 2053 2054void 2055ClearCheckNewLink(struct libalias *la) 2056{ 2057 la->newDefaultLink = 0; 2058} 2059 2060void 2061SetProtocolFlags(struct alias_link *lnk, int pflags) 2062{ 2063 2064 lnk->pflags = pflags;; 2065} 2066 2067int 2068GetProtocolFlags(struct alias_link *lnk) 2069{ 2070 2071 return (lnk->pflags); 2072} 2073 2074void 2075SetDestCallId(struct alias_link *lnk, u_int16_t cid) 2076{ 2077 struct libalias *la = lnk->la; 2078 2079 la->deleteAllLinks = 1; 2080 lnk = ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2081 lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2082 la->deleteAllLinks = 0; 2083} 2084 2085 2086/* Miscellaneous Functions 2087 2088 HouseKeeping() 2089 InitPacketAliasLog() 2090 UninitPacketAliasLog() 2091*/ 2092 2093/* 2094 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2095 is called to find and remove timed-out aliasing links. Logic exists 2096 to sweep through the entire table and linked list structure 2097 every 60 seconds. 2098 2099 (prototype in alias_local.h) 2100*/ 2101 2102void 2103HouseKeeping(struct libalias *la) 2104{ 2105 int i, n, n100; 2106 struct timeval tv; 2107 struct timezone tz; 2108 2109 /* 2110 * Save system time (seconds) in global variable timeStamp for use 2111 * by other functions. This is done so as not to unnecessarily 2112 * waste timeline by making system calls. 2113 */ 2114 gettimeofday(&tv, &tz); 2115 la->timeStamp = tv.tv_sec; 2116 2117 /* Compute number of spokes (output table link chains) to cover */ 2118 n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual; 2119 n100 *= la->timeStamp - la->lastCleanupTime; 2120 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2121 2122 n = n100 / 100; 2123 2124 /* Handle different cases */ 2125 if (n > ALIAS_CLEANUP_MAX_SPOKES) { 2126 n = ALIAS_CLEANUP_MAX_SPOKES; 2127 la->lastCleanupTime = la->timeStamp; 2128 la->houseKeepingResidual = 0; 2129 2130 for (i = 0; i < n; i++) 2131 IncrementalCleanup(la); 2132 } else if (n > 0) { 2133 la->lastCleanupTime = la->timeStamp; 2134 la->houseKeepingResidual = n100 - 100 * n; 2135 2136 for (i = 0; i < n; i++) 2137 IncrementalCleanup(la); 2138 } else if (n < 0) { 2139#ifdef DEBUG 2140 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2141 fprintf(stderr, "something unexpected in time values\n"); 2142#endif 2143 la->lastCleanupTime = la->timeStamp; 2144 la->houseKeepingResidual = 0; 2145 } 2146} 2147 2148#ifndef NO_LOGGING 2149/* Init the log file and enable logging */ 2150static void 2151InitPacketAliasLog(struct libalias *la) 2152{ 2153 if ((~la->packetAliasMode & PKT_ALIAS_LOG) 2154 && (la->monitorFile = fopen("/var/log/alias.log", "w"))) { 2155 la->packetAliasMode |= PKT_ALIAS_LOG; 2156 fprintf(la->monitorFile, 2157 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2158 } 2159} 2160 2161/* Close the log-file and disable logging. */ 2162static void 2163UninitPacketAliasLog(struct libalias *la) 2164{ 2165 if (la->monitorFile) { 2166 fclose(la->monitorFile); 2167 la->monitorFile = NULL; 2168 } 2169 la->packetAliasMode &= ~PKT_ALIAS_LOG; 2170} 2171#endif 2172 2173/* Outside world interfaces 2174 2175-- "outside world" means other than alias*.c routines -- 2176 2177 PacketAliasRedirectPort() 2178 PacketAliasAddServer() 2179 PacketAliasRedirectProto() 2180 PacketAliasRedirectAddr() 2181 PacketAliasRedirectDynamic() 2182 PacketAliasRedirectDelete() 2183 PacketAliasSetAddress() 2184 PacketAliasInit() 2185 PacketAliasUninit() 2186 PacketAliasSetMode() 2187 2188(prototypes in alias.h) 2189*/ 2190 2191/* Redirection from a specific public addr:port to a 2192 private addr:port */ 2193struct alias_link * 2194LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2195 struct in_addr dst_addr, u_short dst_port, 2196 struct in_addr alias_addr, u_short alias_port, 2197 u_char proto) 2198{ 2199 int link_type; 2200 struct alias_link *lnk; 2201 2202 switch (proto) { 2203 case IPPROTO_UDP: 2204 link_type = LINK_UDP; 2205 break; 2206 case IPPROTO_TCP: 2207 link_type = LINK_TCP; 2208 break; 2209 default: 2210#ifdef DEBUG 2211 fprintf(stderr, "PacketAliasRedirectPort(): "); 2212 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2213#endif 2214 return (NULL); 2215 } 2216 2217 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2218 src_port, dst_port, alias_port, 2219 link_type); 2220 2221 if (lnk != NULL) { 2222 lnk->flags |= LINK_PERMANENT; 2223 } 2224#ifdef DEBUG 2225 else { 2226 fprintf(stderr, "PacketAliasRedirectPort(): " 2227 "call to AddLink() failed\n"); 2228 } 2229#endif 2230 2231 return (lnk); 2232} 2233 2234/* Add server to the pool of servers */ 2235int 2236LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 2237{ 2238 struct server *server; 2239 2240 (void)la; 2241 2242 server = malloc(sizeof(struct server)); 2243 2244 if (server != NULL) { 2245 struct server *head; 2246 2247 server->addr = addr; 2248 server->port = port; 2249 2250 head = lnk->server; 2251 if (head == NULL) 2252 server->next = server; 2253 else { 2254 struct server *s; 2255 2256 for (s = head; s->next != head; s = s->next); 2257 s->next = server; 2258 server->next = head; 2259 } 2260 lnk->server = server; 2261 return (0); 2262 } else 2263 return (-1); 2264} 2265 2266/* Redirect packets of a given IP protocol from a specific 2267 public address to a private address */ 2268struct alias_link * 2269LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2270 struct in_addr dst_addr, 2271 struct in_addr alias_addr, 2272 u_char proto) 2273{ 2274 struct alias_link *lnk; 2275 2276 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2277 NO_SRC_PORT, NO_DEST_PORT, 0, 2278 proto); 2279 2280 if (lnk != NULL) { 2281 lnk->flags |= LINK_PERMANENT; 2282 } 2283#ifdef DEBUG 2284 else { 2285 fprintf(stderr, "PacketAliasRedirectProto(): " 2286 "call to AddLink() failed\n"); 2287 } 2288#endif 2289 2290 return (lnk); 2291} 2292 2293/* Static address translation */ 2294struct alias_link * 2295LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2296 struct in_addr alias_addr) 2297{ 2298 struct alias_link *lnk; 2299 2300 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, 2301 0, 0, 0, 2302 LINK_ADDR); 2303 2304 if (lnk != NULL) { 2305 lnk->flags |= LINK_PERMANENT; 2306 } 2307#ifdef DEBUG 2308 else { 2309 fprintf(stderr, "PacketAliasRedirectAddr(): " 2310 "call to AddLink() failed\n"); 2311 } 2312#endif 2313 2314 return (lnk); 2315} 2316 2317 2318/* Mark the aliasing link dynamic */ 2319int 2320LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2321{ 2322 2323 (void)la; 2324 2325 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2326 return (-1); 2327 else { 2328 lnk->flags &= ~LINK_PERMANENT; 2329 return (0); 2330 } 2331} 2332 2333 2334void 2335LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2336{ 2337/* This is a dangerous function to put in the API, 2338 because an invalid pointer can crash the program. */ 2339 2340 la->deleteAllLinks = 1; 2341 DeleteLink(lnk); 2342 la->deleteAllLinks = 0; 2343} 2344 2345 2346void 2347LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2348{ 2349 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2350 && la->aliasAddress.s_addr != addr.s_addr) 2351 CleanupAliasData(la); 2352 2353 la->aliasAddress = addr; 2354} 2355 2356 2357void 2358LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2359{ 2360 la->targetAddress = target_addr; 2361} 2362 2363static void 2364finishoff(void) 2365{ 2366 2367 while (!LIST_EMPTY(&instancehead)) 2368 LibAliasUninit(LIST_FIRST(&instancehead)); 2369} 2370 2371struct libalias * 2372LibAliasInit(struct libalias *la) 2373{ 2374 int i; 2375 struct timeval tv; 2376 struct timezone tz; 2377 2378 if (la == NULL) { 2379 la = calloc(sizeof *la, 1); 2380 if (la == NULL) 2381 return (la); 2382 if (LIST_EMPTY(&instancehead)) 2383 atexit(finishoff); 2384 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2385 2386 gettimeofday(&tv, &tz); 2387 la->timeStamp = tv.tv_sec; 2388 la->lastCleanupTime = tv.tv_sec; 2389 la->houseKeepingResidual = 0; 2390 2391 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2392 LIST_INIT(&la->linkTableOut[i]); 2393 for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2394 LIST_INIT(&la->linkTableIn[i]); 2395 2396 } else { 2397 la->deleteAllLinks = 1; 2398 CleanupAliasData(la); 2399 la->deleteAllLinks = 0; 2400 } 2401 2402 la->aliasAddress.s_addr = INADDR_ANY; 2403 la->targetAddress.s_addr = INADDR_ANY; 2404 2405 la->icmpLinkCount = 0; 2406 la->udpLinkCount = 0; 2407 la->tcpLinkCount = 0; 2408 la->pptpLinkCount = 0; 2409 la->protoLinkCount = 0; 2410 la->fragmentIdLinkCount = 0; 2411 la->fragmentPtrLinkCount = 0; 2412 la->sockCount = 0; 2413 2414 la->cleanupIndex = 0; 2415 2416 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2417 | PKT_ALIAS_USE_SOCKETS 2418 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2419#ifndef NO_FW_PUNCH 2420 la->fireWallFD = -1; 2421#endif 2422 return (la); 2423} 2424 2425void 2426LibAliasUninit(struct libalias *la) 2427{ 2428 la->deleteAllLinks = 1; 2429 CleanupAliasData(la); 2430 la->deleteAllLinks = 0; 2431#ifndef NO_LOGGING 2432 UninitPacketAliasLog(la); 2433#endif 2434#ifndef NO_FW_PUNCH 2435 UninitPunchFW(la); 2436#endif 2437 LIST_REMOVE(la, instancelist); 2438 free(la); 2439} 2440 2441/* Change mode for some operations */ 2442unsigned int 2443LibAliasSetMode( 2444 struct libalias *la, 2445 unsigned int flags, /* Which state to bring flags to */ 2446 unsigned int mask /* Mask of which flags to affect (use 0 to 2447 * do a probe for flag values) */ 2448) 2449{ 2450#ifndef NO_LOGGING 2451/* Enable logging? */ 2452 if (flags & mask & PKT_ALIAS_LOG) { 2453 InitPacketAliasLog(la); /* Do the enable */ 2454 } else 2455/* _Disable_ logging? */ 2456 if (~flags & mask & PKT_ALIAS_LOG) { 2457 UninitPacketAliasLog(la); 2458 } 2459#endif 2460#ifndef NO_FW_PUNCH 2461/* Start punching holes in the firewall? */ 2462 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2463 InitPunchFW(la); 2464 } else 2465/* Stop punching holes in the firewall? */ 2466 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2467 UninitPunchFW(la); 2468 } 2469#endif 2470 2471/* Other flags can be set/cleared without special action */ 2472 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2473 return (la->packetAliasMode); 2474} 2475 2476 2477int 2478LibAliasCheckNewLink(struct libalias *la) 2479{ 2480 return (la->newDefaultLink); 2481} 2482 2483 2484#ifndef NO_FW_PUNCH 2485 2486/***************** 2487 Code to support firewall punching. This shouldn't really be in this 2488 file, but making variables global is evil too. 2489 ****************/ 2490 2491/* Firewall include files */ 2492#include <net/if.h> 2493#include <netinet/ip_fw.h> 2494#include <string.h> 2495#include <err.h> 2496 2497/* 2498 * helper function, updates the pointer to cmd with the length 2499 * of the current command, and also cleans up the first word of 2500 * the new command in case it has been clobbered before. 2501 */ 2502static ipfw_insn * 2503next_cmd(ipfw_insn * cmd) 2504{ 2505 cmd += F_LEN(cmd); 2506 bzero(cmd, sizeof(*cmd)); 2507 return (cmd); 2508} 2509 2510/* 2511 * A function to fill simple commands of size 1. 2512 * Existing flags are preserved. 2513 */ 2514static ipfw_insn * 2515fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2516 int flags, u_int16_t arg) 2517{ 2518 cmd->opcode = opcode; 2519 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2520 cmd->arg1 = arg; 2521 return next_cmd(cmd); 2522} 2523 2524static ipfw_insn * 2525fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2526{ 2527 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 2528 2529 cmd->addr.s_addr = addr; 2530 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2531} 2532 2533static ipfw_insn * 2534fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2535{ 2536 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 2537 2538 cmd->ports[0] = cmd->ports[1] = port; 2539 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2540} 2541 2542static int 2543fill_rule(void *buf, int bufsize, int rulenum, 2544 enum ipfw_opcodes action, int proto, 2545 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2546{ 2547 struct ip_fw *rule = (struct ip_fw *)buf; 2548 ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 2549 2550 bzero(buf, bufsize); 2551 rule->rulenum = rulenum; 2552 2553 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2554 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2555 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2556 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2557 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2558 2559 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2560 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2561 2562 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2563 2564 return ((char *)cmd - (char *)buf); 2565} 2566 2567static void ClearAllFWHoles(struct libalias *la); 2568 2569 2570#define fw_setfield(la, field, num) \ 2571do { \ 2572 (field)[(num) - la->fireWallBaseNum] = 1; \ 2573} /*lint -save -e717 */ while(0)/* lint -restore */ 2574 2575#define fw_clrfield(la, field, num) \ 2576do { \ 2577 (field)[(num) - la->fireWallBaseNum] = 0; \ 2578} /*lint -save -e717 */ while(0)/* lint -restore */ 2579 2580#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2581 2582static void 2583InitPunchFW(struct libalias *la) 2584{ 2585 2586 la->fireWallField = malloc(la->fireWallNumNums); 2587 if (la->fireWallField) { 2588 memset(la->fireWallField, 0, la->fireWallNumNums); 2589 if (la->fireWallFD < 0) { 2590 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2591 } 2592 ClearAllFWHoles(la); 2593 la->fireWallActiveNum = la->fireWallBaseNum; 2594 } 2595} 2596 2597static void 2598UninitPunchFW(struct libalias *la) 2599{ 2600 ClearAllFWHoles(la); 2601 if (la->fireWallFD >= 0) 2602 close(la->fireWallFD); 2603 la->fireWallFD = -1; 2604 if (la->fireWallField) 2605 free(la->fireWallField); 2606 la->fireWallField = NULL; 2607 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2608} 2609 2610/* Make a certain link go through the firewall */ 2611void 2612PunchFWHole(struct alias_link *lnk) 2613{ 2614 struct libalias *la; 2615 int r; /* Result code */ 2616 struct ip_fw rule; /* On-the-fly built rule */ 2617 int fwhole; /* Where to punch hole */ 2618 2619 la = lnk->la; 2620 2621/* Don't do anything unless we are asked to */ 2622 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2623 la->fireWallFD < 0 || 2624 lnk->link_type != LINK_TCP) 2625 return; 2626 2627 memset(&rule, 0, sizeof rule); 2628 2629/** Build rule **/ 2630 2631 /* Find empty slot */ 2632 for (fwhole = la->fireWallActiveNum; 2633 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2634 fw_tstfield(la, la->fireWallField, fwhole); 2635 fwhole++); 2636 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2637 for (fwhole = la->fireWallBaseNum; 2638 fwhole < la->fireWallActiveNum && 2639 fw_tstfield(la, la->fireWallField, fwhole); 2640 fwhole++); 2641 if (fwhole == la->fireWallActiveNum) { 2642 /* No rule point empty - we can't punch more holes. */ 2643 la->fireWallActiveNum = la->fireWallBaseNum; 2644#ifdef DEBUG 2645 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2646#endif 2647 return; 2648 } 2649 } 2650 /* Start next search at next position */ 2651 la->fireWallActiveNum = fwhole + 1; 2652 2653 /* 2654 * generate two rules of the form 2655 * 2656 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2657 * accept tcp from DAddr DPort to OAddr OPort 2658 */ 2659 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2660 u_int32_t rulebuf[255]; 2661 int i; 2662 2663 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2664 O_ACCEPT, IPPROTO_TCP, 2665 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2666 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2667 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2668 if (r) 2669 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2670 2671 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2672 O_ACCEPT, IPPROTO_TCP, 2673 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2674 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2675 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2676 if (r) 2677 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2678 } 2679 2680/* Indicate hole applied */ 2681 lnk->data.tcp->fwhole = fwhole; 2682 fw_setfield(la, la->fireWallField, fwhole); 2683} 2684 2685/* Remove a hole in a firewall associated with a particular alias 2686 lnk. Calling this too often is harmless. */ 2687static void 2688ClearFWHole(struct alias_link *lnk) 2689{ 2690 2691 struct libalias *la; 2692 2693 la = lnk->la; 2694 if (lnk->link_type == LINK_TCP) { 2695 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall 2696 * hole? */ 2697 struct ip_fw rule; 2698 2699 if (fwhole < 0) 2700 return; 2701 2702 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2703 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2704 &fwhole, sizeof fwhole)); 2705 fw_clrfield(la, la->fireWallField, fwhole); 2706 lnk->data.tcp->fwhole = -1; 2707 } 2708} 2709 2710/* Clear out the entire range dedicated to firewall holes. */ 2711static void 2712ClearAllFWHoles(struct libalias *la) 2713{ 2714 struct ip_fw rule; /* On-the-fly built rule */ 2715 int i; 2716 2717 if (la->fireWallFD < 0) 2718 return; 2719 2720 memset(&rule, 0, sizeof rule); 2721 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2722 int r = i; 2723 2724 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2725 } 2726 /* XXX: third arg correct here ? /phk */ 2727 memset(la->fireWallField, 0, la->fireWallNumNums); 2728} 2729 2730#endif 2731 2732void 2733LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2734{ 2735#ifndef NO_FW_PUNCH 2736 la->fireWallBaseNum = base; 2737 la->fireWallNumNums = num; 2738#endif 2739} 2740 2741void 2742LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2743{ 2744 la->skinnyPort = port; 2745} 2746