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