alias_db.c revision 179480
117683Spst/*- 239291Sfenner * Copyright (c) 2001 Charles Mott <cm@linktel.net> 317683Spst * All rights reserved. 417683Spst * 517683Spst * Redistribution and use in source and binary forms, with or without 617683Spst * modification, are permitted provided that the following conditions 717683Spst * are met: 817683Spst * 1. Redistributions of source code must retain the above copyright 917683Spst * notice, this list of conditions and the following disclaimer. 1017683Spst * 2. Redistributions in binary form must reproduce the above copyright 1117683Spst * notice, this list of conditions and the following disclaimer in the 1217683Spst * documentation and/or other materials provided with the distribution. 1317683Spst * 1417683Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1517683Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1617683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1717683Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1817683Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1917683Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20162020Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21162020Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2217683Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2317683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24127664Sbms * SUCH DAMAGE. 25162012Ssam */ 2617683Spst 2717683Spst#include <sys/cdefs.h> 2875107Sfenner__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_db.c 179480 2008-06-01 18:34:58Z mav $"); 2975107Sfenner 3075107Sfenner/* 3175107Sfenner Alias_db.c encapsulates all data structures used for storing 3217683Spst packet aliasing data. Other parts of the aliasing software 3317683Spst access data through functions provided in this file. 3417683Spst 3517683Spst Data storage is based on the notion of a "link", which is 3617683Spst established for ICMP echo/reply packets, UDP datagrams and 3717683Spst TCP stream connections. A link stores the original source 38127664Sbms and destination addresses. For UDP and TCP, it also stores 3917683Spst source and destination port numbers, as well as an alias 4017683Spst port number. Links are also used to store information about 41127664Sbms fragments. 4298530Sfenner 43127664Sbms There is a facility for sweeping through and deleting old 4498530Sfenner links as new packets are sent through. A simple timeout is 45127664Sbms used for ICMP and UDP links. TCP links are left alone unless 46127664Sbms there is an incomplete connection, in which case the link 4798530Sfenner can be deleted after a certain amount of time. 48127664Sbms 49127664Sbms 50127664Sbms Initial version: August, 1996 (cjm) 51127664Sbms 52127664Sbms Version 1.4: September 16, 1996 (cjm) 53127664Sbms Facility for handling incoming links added. 54127664Sbms 55127664Sbms Version 1.6: September 18, 1996 (cjm) 56127664Sbms ICMP data handling simplified. 57127664Sbms 58127664Sbms Version 1.7: January 9, 1997 (cjm) 59127664Sbms Fragment handling simplified. 60127664Sbms Saves pointers for unresolved fragments. 6198530Sfenner Permits links for unspecified remote ports 62127664Sbms or unspecified remote addresses. 63127664Sbms Fixed bug which did not properly zero port 64147894Ssam table entries after a link was deleted. 65127664Sbms Cleaned up some obsolete comments. 6617683Spst 67127664Sbms Version 1.8: January 14, 1997 (cjm) 68127664Sbms Fixed data type error in StartPoint(). 69127664Sbms (This error did not exist prior to v1.7 70127664Sbms and was discovered and fixed by Ari Suutari) 71127664Sbms 72127664Sbms Version 1.9: February 1, 1997 73127664Sbms Optionally, connections initiated from packet aliasing host 74127664Sbms machine will will not have their port number aliased unless it 75127664Sbms conflicts with an aliasing port already being used. (cjm) 76127664Sbms 77127664Sbms All options earlier being #ifdef'ed are now available through 78127664Sbms a new interface, SetPacketAliasMode(). This allows run time 79127664Sbms control (which is now available in PPP+pktAlias through the 80127664Sbms 'alias' keyword). (ee) 81127664Sbms 82127664Sbms Added ability to create an alias port without 83127664Sbms either destination address or port specified. 84127664Sbms port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) 85127664Sbms 86127664Sbms Removed K&R style function headers 87127664Sbms and general cleanup. (ee) 88127664Sbms 8917683Spst Added packetAliasMode to replace compiler #defines's (ee) 9017683Spst 9117683Spst Allocates sockets for partially specified 9217683Spst ports if ALIAS_USE_SOCKETS defined. (cjm) 9317683Spst 9417683Spst Version 2.0: March, 1997 9517683Spst SetAliasAddress() will now clean up alias links 9617683Spst if the aliasing address is changed. (cjm) 9717683Spst 9817683Spst PacketAliasPermanentLink() function added to support permanent 99127664Sbms links. (J. Fortes suggested the need for this.) 100127664Sbms Examples: 101127664Sbms 102127664Sbms (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port 10317683Spst 10417683Spst (192.168.0.2, port 21) <-> alias port 3604, known dest addr 10517683Spst unknown dest port 10617683Spst 107127664Sbms These permanent links allow for incoming connections to 10856889Sfenner machines on the local network. They can be given with a 109127664Sbms user-chosen amount of specificity, with increasing specificity 110162012Ssam meaning more security. (cjm) 111127664Sbms 112127664Sbms Quite a bit of rework to the basic engine. The portTable[] 113127664Sbms array, which kept track of which ports were in use was replaced 114127664Sbms by a table/linked list structure. (cjm) 11517683Spst 11617683Spst SetExpire() function added. (cjm) 11717683Spst 11898530Sfenner DeleteLink() no longer frees memory association with a pointer 11998530Sfenner to a fragment (this bug was first recognized by E. Eklund in 12098530Sfenner v1.9). 12198530Sfenner 12298530Sfenner Version 2.1: May, 1997 (cjm) 12398530Sfenner Packet aliasing engine reworked so that it can handle 12498530Sfenner multiple external addresses rather than just a single 12598530Sfenner host address. 12698530Sfenner 12798530Sfenner PacketAliasRedirectPort() and PacketAliasRedirectAddr() 12898530Sfenner added to the API. The first function is a more generalized 12998530Sfenner version of PacketAliasPermanentLink(). The second function 13098530Sfenner implements static network address translation. 13117683Spst 13275107Sfenner Version 3.2: July, 2000 (salander and satoh) 13375107Sfenner Added FindNewPortGroup to get contiguous range of port values. 13417683Spst 13517683Spst Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing 13617683Spst link but not actually add one. 13717683Spst 13817683Spst Added FindRtspOut, which is closely derived from FindUdpTcpOut, 13917683Spst except that the alias port (from FindNewPortGroup) is provided 14017683Spst as input. 14117683Spst 142127664Sbms See HISTORY file for additional revisions. 143127664Sbms*/ 14417683Spst 14517683Spst#ifdef _KERNEL 14617683Spst#include <machine/stdarg.h> 14717683Spst#include <sys/param.h> 148146768Ssam#include <sys/kernel.h> 149127664Sbms#include <sys/module.h> 150146768Ssam#include <sys/syslog.h> 151146768Ssam#else 152146768Ssam#include <stdarg.h> 15317683Spst#include <stdlib.h> 154127664Sbms#include <stdio.h> 15517683Spst#include <sys/errno.h> 156127664Sbms#include <sys/time.h> 157127664Sbms#include <unistd.h> 158127664Sbms#endif 159127664Sbms 160127664Sbms#include <sys/socket.h> 161127664Sbms#include <netinet/tcp.h> 162127664Sbms 163127664Sbms#ifdef _KERNEL 164127664Sbms#include <netinet/libalias/alias.h> 165127664Sbms#include <netinet/libalias/alias_local.h> 166127664Sbms#include <netinet/libalias/alias_mod.h> 167127664Sbms#include <net/if.h> 16817683Spst#else 16917683Spst#include "alias.h" 17017683Spst#include "alias_local.h" 17117683Spst#include "alias_mod.h" 17217683Spst#endif 17317683Spst 17417683Spststatic LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); 17517683Spst 17617683Spst 17717683Spst/* 178127664Sbms Constants (note: constants are also defined 179127664Sbms near relevant functions or structs) 180127664Sbms*/ 181127664Sbms 182127664Sbms/* Parameters used for cleanup of expired links */ 183127664Sbms/* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */ 184127664Sbms#define ALIAS_CLEANUP_INTERVAL_SECS 64 185127664Sbms#define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5) 186127664Sbms 187127664Sbms/* Timeouts (in seconds) for different link types */ 188127664Sbms#define ICMP_EXPIRE_TIME 60 189127664Sbms#define UDP_EXPIRE_TIME 60 190127664Sbms#define PROTO_EXPIRE_TIME 60 191127664Sbms#define FRAGMENT_ID_EXPIRE_TIME 10 192127664Sbms#define FRAGMENT_PTR_EXPIRE_TIME 30 193127664Sbms 194127664Sbms/* TCP link expire time for different cases */ 195127664Sbms/* When the link has been used and closed - minimal grace time to 196127664Sbms allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 197127664Sbms#ifndef TCP_EXPIRE_DEAD 198127664Sbms#define TCP_EXPIRE_DEAD 10 199127664Sbms#endif 200127664Sbms 201127664Sbms/* When the link has been used and closed on one side - the other side 202127664Sbms is allowed to still send data */ 203127664Sbms#ifndef TCP_EXPIRE_SINGLEDEAD 20417683Spst#define TCP_EXPIRE_SINGLEDEAD 90 20517683Spst#endif 20617683Spst 20717683Spst/* When the link isn't yet up */ 20817683Spst#ifndef TCP_EXPIRE_INITIAL 20917683Spst#define TCP_EXPIRE_INITIAL 300 21017683Spst#endif 21117683Spst 21217683Spst/* When the link is up */ 21317683Spst#ifndef TCP_EXPIRE_CONNECTED 21417683Spst#define TCP_EXPIRE_CONNECTED 86400 21517683Spst#endif 21617683Spst 21717683Spst 21817683Spst/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 21917683Spst These constants can be anything except zero, which indicates an 22017683Spst unknown port number. */ 22175107Sfenner 22275107Sfenner#define NO_DEST_PORT 1 22317683Spst#define NO_SRC_PORT 1 22417683Spst 22517683Spst 22617683Spst 22717683Spst/* Data Structures 22817683Spst 22917683Spst The fundamental data structure used in this program is 23017683Spst "struct alias_link". Whenever a TCP connection is made, 23117683Spst a UDP datagram is sent out, or an ICMP echo request is made, 23217683Spst a link record is made (if it has not already been created). 23317683Spst The link record is identified by the source address/port 234146768Ssam and the destination address/port. In the case of an ICMP 235146768Ssam echo request, the source port is treated as being equivalent 236146768Ssam with the 16-bit ID number of the ICMP packet. 23717683Spst 23817683Spst The link record also can store some auxiliary data. For 239127664Sbms TCP connections that have had sequence and acknowledgment 240127664Sbms modifications, data space is available to track these changes. 241127664Sbms A state field is used to keep track in changes to the TCP 242127664Sbms connection state. ID numbers of fragments can also be 243127664Sbms stored in the auxiliary space. Pointers to unresolved 244127664Sbms fragments can also be stored. 245127664Sbms 246127664Sbms The link records support two independent chainings. Lookup 247127664Sbms tables for input and out tables hold the initial pointers 248127664Sbms the link chains. On input, the lookup table indexes on alias 249127664Sbms port and link type. On output, the lookup table indexes on 250127664Sbms source address, destination address, source port, destination 251127664Sbms port and link type. 252127664Sbms*/ 253127664Sbms 254127664Sbmsstruct ack_data_record { /* used to save changes to ACK/sequence 255127664Sbms * numbers */ 256127664Sbms u_long ack_old; 257127664Sbms u_long ack_new; 258127664Sbms int delta; 259127664Sbms int active; 26017683Spst}; 26117683Spst 262146768Ssamstruct tcp_state { /* Information about TCP connection */ 26317683Spst int in; /* State for outside -> inside */ 264127664Sbms int out; /* State for inside -> outside */ 265127664Sbms int index; /* Index to ACK data array */ 266146768Ssam int ack_modified; /* Indicates whether ACK and 267146768Ssam * sequence numbers */ 268146768Ssam /* been modified */ 269146768Ssam}; 270146768Ssam 271146768Ssam#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 272146768Ssam * saved for a modified TCP stream */ 273146768Ssamstruct tcp_dat { 27417683Spst struct tcp_state state; 275127664Sbms struct ack_data_record ack[N_LINK_TCP_DATA]; 276146768Ssam int fwhole; /* Which firewall record is used for this 277146768Ssam * hole? */ 278146768Ssam}; 279146768Ssam 28098530Sfennerstruct server { /* LSNAT server pool (circular list) */ 281127664Sbms struct in_addr addr; 282127664Sbms u_short port; 283127664Sbms struct server *next; 284127664Sbms}; 285146768Ssam 286146768Ssamstruct alias_link { /* Main data structure */ 287146768Ssam struct libalias *la; 28898530Sfenner struct in_addr src_addr; /* Address and port information */ 289146768Ssam struct in_addr dst_addr; 290146768Ssam struct in_addr alias_addr; 291146768Ssam struct in_addr proxy_addr; 292146768Ssam u_short src_port; 293146768Ssam u_short dst_port; 294146768Ssam u_short alias_port; 295146768Ssam u_short proxy_port; 296146768Ssam struct server *server; 297146768Ssam 298146768Ssam int link_type; /* Type of link: TCP, UDP, ICMP, 299146768Ssam * proto, frag */ 300146768Ssam 301146768Ssam/* values for link_type */ 302146768Ssam#define LINK_ICMP IPPROTO_ICMP 303146768Ssam#define LINK_UDP IPPROTO_UDP 304127664Sbms#define LINK_TCP IPPROTO_TCP 305127664Sbms#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 306127664Sbms#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 307127664Sbms#define LINK_ADDR (IPPROTO_MAX + 3) 308127664Sbms#define LINK_PPTP (IPPROTO_MAX + 4) 309127664Sbms 310127664Sbms int flags; /* indicates special characteristics */ 311127664Sbms int pflags; /* protocol-specific flags */ 312127664Sbms 313127664Sbms/* flag bits */ 314127664Sbms#define LINK_UNKNOWN_DEST_PORT 0x01 31517683Spst#define LINK_UNKNOWN_DEST_ADDR 0x02 31617683Spst#define LINK_PERMANENT 0x04 31717683Spst#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 31817683Spst#define LINK_UNFIREWALLED 0x08 31917683Spst 32017683Spst int timestamp; /* Time link was last accessed */ 32117683Spst int expire_time; /* Expire time for link */ 322146768Ssam#ifndef NO_USE_SOCKETS 323146768Ssam int sockfd; /* socket descriptor */ 324146768Ssam#endif 325146768Ssam LIST_ENTRY (alias_link) list_out; /* Linked list of 326146768Ssam * pointers for */ 327146768Ssam LIST_ENTRY (alias_link) list_in; /* input and output 328146768Ssam * lookup tables */ 329146768Ssam 330146768Ssam union { /* Auxiliary data */ 331146768Ssam char *frag_ptr; 332146768Ssam struct in_addr frag_addr; 333146768Ssam struct tcp_dat *tcp; 334146768Ssam } data; 335146768Ssam}; 336146768Ssam 337146768Ssam/* Clean up procedure. */ 338146768Ssamstatic void finishoff(void); 339146768Ssam 340146768Ssam/* Kernel module definition. */ 341146768Ssam#ifdef _KERNEL 342146768SsamMALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing"); 343146768Ssam 344146768SsamMODULE_VERSION(libalias, 1); 345146768Ssam 346146768Ssamstatic int 347146768Ssamalias_mod_handler(module_t mod, int type, void *data) 348146768Ssam{ 349146768Ssam int error; 350146768Ssam 351146768Ssam switch (type) { 352146768Ssam case MOD_LOAD: 353146768Ssam error = 0; 354146768Ssam handler_chain_init(); 355146768Ssam break; 356146768Ssam case MOD_QUIESCE: 357146768Ssam case MOD_UNLOAD: 358146768Ssam handler_chain_destroy(); 359146768Ssam finishoff(); 360146768Ssam error = 0; 361146768Ssam break; 362146768Ssam default: 363146768Ssam error = EINVAL; 364146768Ssam } 365146768Ssam 366146768Ssam return (error); 367146768Ssam} 368146768Ssam 369146768Ssamstatic moduledata_t alias_mod = { 370146768Ssam "alias", alias_mod_handler, NULL 371127664Sbms}; 372127664Sbms 373127664SbmsDECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); 374127664Sbms#endif 375127664Sbms 376127664Sbms/* Internal utility routines (used only in alias_db.c) 377127664Sbms 378127664SbmsLookup table starting points: 379127664Sbms StartPointIn() -- link table initial search point for 380127664Sbms incoming packets 381127664Sbms StartPointOut() -- link table initial search point for 382127664Sbms outgoing packets 383127664Sbms 384127664SbmsMiscellaneous: 385127664Sbms SeqDiff() -- difference between two TCP sequences 386127664Sbms ShowAliasStats() -- send alias statistics to a monitor file 387127664Sbms*/ 388127664Sbms 389127664Sbms 390127664Sbms/* Local prototypes */ 391127664Sbmsstatic u_int StartPointIn(struct in_addr, u_short, int); 392127664Sbms 393127664Sbmsstatic u_int 394127664SbmsStartPointOut(struct in_addr, struct in_addr, 395127664Sbms u_short, u_short, int); 396127664Sbms 397127664Sbmsstatic int SeqDiff(u_long, u_long); 398127664Sbms 399127664Sbms#ifndef NO_FW_PUNCH 400127664Sbms/* Firewall control */ 401127664Sbmsstatic void InitPunchFW(struct libalias *); 402127664Sbmsstatic void UninitPunchFW(struct libalias *); 403127664Sbmsstatic void ClearFWHole(struct alias_link *); 404127664Sbms 405127664Sbms#endif 406127664Sbms 407127664Sbms/* Log file control */ 408127664Sbmsstatic void ShowAliasStats(struct libalias *); 409127664Sbmsstatic int InitPacketAliasLog(struct libalias *); 410127664Sbmsstatic void UninitPacketAliasLog(struct libalias *); 411127664Sbms 412127664Sbmsstatic u_int 413127664SbmsStartPointIn(struct in_addr alias_addr, 414127664Sbms u_short alias_port, 415127664Sbms int link_type) 416127664Sbms{ 417127664Sbms u_int n; 418127664Sbms 419127664Sbms n = alias_addr.s_addr; 420127664Sbms if (link_type != LINK_PPTP) 421127664Sbms n += alias_port; 422127664Sbms n += link_type; 423127664Sbms return (n % LINK_TABLE_IN_SIZE); 424127664Sbms} 425127664Sbms 426127664Sbms 427127664Sbmsstatic u_int 428127664SbmsStartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 429127664Sbms u_short src_port, u_short dst_port, int link_type) 430127664Sbms{ 431127664Sbms u_int n; 432127664Sbms 433127664Sbms n = src_addr.s_addr; 434127664Sbms n += dst_addr.s_addr; 435127664Sbms if (link_type != LINK_PPTP) { 436127664Sbms n += src_port; 437127664Sbms n += dst_port; 438127664Sbms } 439127664Sbms n += link_type; 440127664Sbms 441127664Sbms return (n % LINK_TABLE_OUT_SIZE); 442127664Sbms} 443127664Sbms 444127664Sbms 445127664Sbmsstatic int 446127664SbmsSeqDiff(u_long x, u_long y) 447127664Sbms{ 448127664Sbms/* Return the difference between two TCP sequence numbers */ 449127664Sbms 450127664Sbms/* 451127664Sbms This function is encapsulated in case there are any unusual 452127664Sbms arithmetic conditions that need to be considered. 453127664Sbms*/ 454127664Sbms 455127664Sbms return (ntohl(y) - ntohl(x)); 456127664Sbms} 457127664Sbms 458127664Sbms#ifdef _KERNEL 459127664Sbms 460127664Sbmsstatic void 461127664SbmsAliasLog(char *str, const char *format, ...) 462127664Sbms{ 463127664Sbms va_list ap; 464127664Sbms 465127664Sbms va_start(ap, format); 466127664Sbms vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap); 467127664Sbms va_end(ap); 468127664Sbms} 469127664Sbms#else 470127664Sbmsstatic void 471127664SbmsAliasLog(FILE *stream, const char *format, ...) 472127664Sbms{ 473127664Sbms va_list ap; 474127664Sbms 475127664Sbms va_start(ap, format); 476127664Sbms vfprintf(stream, format, ap); 477127664Sbms va_end(ap); 478127664Sbms fflush(stream); 479127664Sbms} 480127664Sbms#endif 481127664Sbms 482127664Sbmsstatic void 483127664SbmsShowAliasStats(struct libalias *la) 484127664Sbms{ 485127664Sbms 486127664Sbms LIBALIAS_LOCK_ASSERT(la); 487127664Sbms/* Used for debugging */ 488127664Sbms if (la->logDesc) { 489127664Sbms int tot = la->icmpLinkCount + la->udpLinkCount + 490127664Sbms la->tcpLinkCount + la->pptpLinkCount + 491127664Sbms la->protoLinkCount + la->fragmentIdLinkCount + 492127664Sbms la->fragmentPtrLinkCount; 493127664Sbms 494127664Sbms AliasLog(la->logDesc, 495127664Sbms "icmp=%u, udp=%u, tcp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u", 496127664Sbms la->icmpLinkCount, 497127664Sbms la->udpLinkCount, 498127664Sbms la->tcpLinkCount, 499127664Sbms la->pptpLinkCount, 500127664Sbms la->protoLinkCount, 501127664Sbms la->fragmentIdLinkCount, 502127664Sbms la->fragmentPtrLinkCount, tot); 503127664Sbms#ifndef _KERNEL 504127664Sbms AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount); 505127664Sbms#endif 506127664Sbms } 507127664Sbms} 508127664Sbms 509127664Sbms/* Internal routines for finding, deleting and adding links 510127664Sbms 511127664SbmsPort Allocation: 512127664Sbms GetNewPort() -- find and reserve new alias port number 513127664Sbms GetSocket() -- try to allocate a socket for a given port 514127664Sbms 515127664SbmsLink creation and deletion: 516127664Sbms CleanupAliasData() - remove all link chains from lookup table 517127664Sbms IncrementalCleanup() - look for stale links in a single chain 518127664Sbms DeleteLink() - remove link 519127664Sbms AddLink() - add link 520127664Sbms ReLink() - change link 521127664Sbms 522127664SbmsLink search: 523127664Sbms FindLinkOut() - find link for outgoing packets 52417683Spst FindLinkIn() - find link for incoming packets 52517683Spst 52617683SpstPort search: 52717683Spst FindNewPortGroup() - find an available group of ports 52817683Spst*/ 52975107Sfenner 53017683Spst/* Local prototypes */ 531127664Sbmsstatic int GetNewPort(struct libalias *, struct alias_link *, int); 53217683Spst#ifndef NO_USE_SOCKETS 533127664Sbmsstatic u_short GetSocket(struct libalias *, u_short, int *, int); 534127664Sbms#endif 535127664Sbmsstatic void CleanupAliasData(struct libalias *); 536127664Sbms 537127664Sbmsstatic void IncrementalCleanup(struct libalias *); 538127664Sbms 539127664Sbmsstatic void DeleteLink(struct alias_link *); 540127664Sbms 541127664Sbmsstatic struct alias_link * 54217683SpstAddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr, 54317683Spst u_short, u_short, int, int); 54417683Spst 54575107Sfennerstatic struct alias_link * 546146768SsamReLink(struct alias_link *, 547146768Ssam struct in_addr, struct in_addr, struct in_addr, 548146768Ssam u_short, u_short, int, int); 549146768Ssam 550146768Ssamstatic struct alias_link * 551146768Ssam FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 552146768Ssam 553146768Ssamstatic struct alias_link * 554146768Ssam FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 555146768Ssam 556146768Ssam 557146768Ssam#define ALIAS_PORT_BASE 0x08000 558146768Ssam#define ALIAS_PORT_MASK 0x07fff 559146768Ssam#define ALIAS_PORT_MASK_EVEN 0x07ffe 560146768Ssam#define GET_NEW_PORT_MAX_ATTEMPTS 20 561146768Ssam 562146768Ssam#define GET_ALIAS_PORT -1 56317683Spst#define GET_ALIAS_ID GET_ALIAS_PORT 56417683Spst 56517683Spst#define FIND_EVEN_ALIAS_BASE 1 56617683Spst 56717683Spst/* GetNewPort() allocates port numbers. Note that if a port number 56817683Spst is already in use, that does not mean that it cannot be used by 56975107Sfenner another link concurrently. This is because GetNewPort() looks for 57075107Sfenner unused triplets: (dest addr, dest port, alias port). */ 57117683Spst 57217683Spststatic int 57317683SpstGetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) 57417683Spst{ 575127664Sbms int i; 576146768Ssam int max_trials; 577146768Ssam u_short port_sys; 578127664Sbms u_short port_net; 579146768Ssam 580146768Ssam LIBALIAS_LOCK_ASSERT(la); 581146768Ssam/* 582146768Ssam Description of alias_port_param for GetNewPort(). When 58317683Spst this parameter is zero or positive, it precisely specifies 584127664Sbms the port number. GetNewPort() will return this number 585127664Sbms without check that it is in use. 58617683Spst 58717683Spst When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 58817683Spst selected port number. 58917683Spst*/ 590127664Sbms 591109839Sfenner if (alias_port_param == GET_ALIAS_PORT) { 592127664Sbms /* 593146768Ssam * The aliasing port is automatically selected by one of 594146768Ssam * two methods below: 595146768Ssam */ 59617683Spst max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 59717683Spst 598146768Ssam if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 599146768Ssam /* 600127664Sbms * When the PKT_ALIAS_SAME_PORTS option is chosen, 60117683Spst * the first try will be the actual source port. If 602127664Sbms * this is already in use, the remainder of the 603127664Sbms * trials will be random. 604127664Sbms */ 605127664Sbms port_net = lnk->src_port; 606127664Sbms port_sys = ntohs(port_net); 607109839Sfenner } else { 608127664Sbms /* First trial and all subsequent are random. */ 609127664Sbms port_sys = random() & ALIAS_PORT_MASK; 610127664Sbms port_sys += ALIAS_PORT_BASE; 611127664Sbms port_net = htons(port_sys); 61217683Spst } 61317683Spst } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { 61475107Sfenner lnk->alias_port = (u_short) alias_port_param; 61575107Sfenner return (0); 61617683Spst } else { 61717683Spst#ifdef LIBALIAS_DEBUG 61875107Sfenner fprintf(stderr, "PacketAlias/GetNewPort(): "); 61917683Spst fprintf(stderr, "input parameter error\n"); 62017683Spst#endif 62117683Spst return (-1); 62217683Spst } 62317683Spst 62417683Spst 62517683Spst/* Port number search */ 62617683Spst for (i = 0; i < max_trials; i++) { 62775107Sfenner int go_ahead; 62875107Sfenner struct alias_link *search_result; 62917683Spst 63017683Spst search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr, 63117683Spst lnk->dst_port, port_net, 63217683Spst lnk->link_type, 0); 63375107Sfenner 63475107Sfenner if (search_result == NULL) 63517683Spst go_ahead = 1; 63617683Spst else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED) 63775107Sfenner && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 63875107Sfenner go_ahead = 1; 63975107Sfenner else 64075107Sfenner go_ahead = 0; 641127664Sbms 642127664Sbms if (go_ahead) { 64375107Sfenner#ifndef NO_USE_SOCKETS 64475107Sfenner if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) 64575107Sfenner && (lnk->flags & LINK_PARTIALLY_SPECIFIED) 64639291Sfenner && ((lnk->link_type == LINK_TCP) || 647127664Sbms (lnk->link_type == LINK_UDP))) { 648127664Sbms if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) { 649127664Sbms lnk->alias_port = port_net; 65075107Sfenner return (0); 65175107Sfenner } 65275107Sfenner } else { 65375107Sfenner#endif 65475107Sfenner lnk->alias_port = port_net; 65575107Sfenner return (0); 65639291Sfenner#ifndef NO_USE_SOCKETS 65775107Sfenner } 65875107Sfenner#endif 65975107Sfenner } 66075107Sfenner port_sys = random() & ALIAS_PORT_MASK; 66175107Sfenner port_sys += ALIAS_PORT_BASE; 66275107Sfenner port_net = htons(port_sys); 66375107Sfenner } 66475107Sfenner 66575107Sfenner#ifdef LIBALIAS_DEBUG 66675107Sfenner fprintf(stderr, "PacketAlias/GetnewPort(): "); 66775107Sfenner fprintf(stderr, "could not find free port\n"); 66875107Sfenner#endif 66975107Sfenner 67075107Sfenner return (-1); 67117683Spst} 67217683Spst 67375107Sfenner#ifndef NO_USE_SOCKETS 67417683Spststatic u_short 67517683SpstGetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type) 67675107Sfenner{ 67775107Sfenner int err; 67817683Spst int sock; 67917683Spst struct sockaddr_in sock_addr; 68098530Sfenner 68198530Sfenner LIBALIAS_LOCK_ASSERT(la); 68298530Sfenner if (link_type == LINK_TCP) 68398530Sfenner sock = socket(AF_INET, SOCK_STREAM, 0); 68456889Sfenner else if (link_type == LINK_UDP) 68598530Sfenner sock = socket(AF_INET, SOCK_DGRAM, 0); 68698530Sfenner else { 68798530Sfenner#ifdef LIBALIAS_DEBUG 68898530Sfenner fprintf(stderr, "PacketAlias/GetSocket(): "); 68998530Sfenner fprintf(stderr, "incorrect link type\n"); 69098530Sfenner#endif 69198530Sfenner return (0); 69298530Sfenner } 69398530Sfenner 69498530Sfenner if (sock < 0) { 69598530Sfenner#ifdef LIBALIAS_DEBUG 69698530Sfenner fprintf(stderr, "PacketAlias/GetSocket(): "); 69798530Sfenner fprintf(stderr, "socket() error %d\n", *sockfd); 69898530Sfenner#endif 699127664Sbms return (0); 700127664Sbms } 701127664Sbms sock_addr.sin_family = AF_INET; 702127664Sbms sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 70398530Sfenner sock_addr.sin_port = port_net; 70475107Sfenner 70598530Sfenner err = bind(sock, 70675107Sfenner (struct sockaddr *)&sock_addr, 707127664Sbms sizeof(sock_addr)); 70898530Sfenner if (err == 0) { 70998530Sfenner la->sockCount++; 71056889Sfenner *sockfd = sock; 71156889Sfenner return (1); 71239291Sfenner } else { 71339291Sfenner close(sock); 71439291Sfenner return (0); 71539291Sfenner } 71639291Sfenner} 71739291Sfenner#endif 71839291Sfenner 71939291Sfenner/* FindNewPortGroup() returns a base port number for an available 72039291Sfenner range of contiguous port numbers. Note that if a port number 72139291Sfenner is already in use, that does not mean that it cannot be used by 72239291Sfenner another link concurrently. This is because FindNewPortGroup() 72356889Sfenner looks for unused triplets: (dest addr, dest port, alias port). */ 72456889Sfenner 725127664Sbmsint 72656889SfennerFindNewPortGroup(struct libalias *la, 72756889Sfenner struct in_addr dst_addr, 72856889Sfenner struct in_addr alias_addr, 72956889Sfenner u_short src_port, 73056889Sfenner u_short dst_port, 73139291Sfenner u_short port_count, 73239291Sfenner u_char proto, 733146768Ssam u_char align) 734146768Ssam{ 735147894Ssam int i, j; 736146768Ssam int max_trials; 737146768Ssam u_short port_sys; 738146768Ssam int link_type; 73917683Spst 74017683Spst LIBALIAS_LOCK_ASSERT(la); 741127664Sbms /* 742109839Sfenner * Get link_type from protocol 743127664Sbms */ 744127664Sbms 745127664Sbms switch (proto) { 746109839Sfenner case IPPROTO_UDP: 747127664Sbms link_type = LINK_UDP; 748146768Ssam break; 749146768Ssam case IPPROTO_TCP: 750146768Ssam link_type = LINK_TCP; 751162020Ssam break; 752109839Sfenner default: 753109839Sfenner return (0); 754109839Sfenner break; 755109839Sfenner } 756109839Sfenner 757109839Sfenner /* 758127664Sbms * The aliasing port is automatically selected by one of two 759109839Sfenner * methods below: 760109839Sfenner */ 761146768Ssam max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 762109839Sfenner 763109839Sfenner if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 764109839Sfenner /* 765146768Ssam * When the ALIAS_SAME_PORTS option is chosen, the first 766146768Ssam * try will be the actual source port. If this is already 767146768Ssam * in use, the remainder of the trials will be random. 768146768Ssam */ 769146768Ssam port_sys = ntohs(src_port); 770146768Ssam 771146768Ssam } else { 772146768Ssam 773146768Ssam /* First trial and all subsequent are random. */ 774146768Ssam if (align == FIND_EVEN_ALIAS_BASE) 775146768Ssam port_sys = random() & ALIAS_PORT_MASK_EVEN; 776146768Ssam else 777146768Ssam port_sys = random() & ALIAS_PORT_MASK; 778146768Ssam 779146768Ssam port_sys += ALIAS_PORT_BASE; 780146768Ssam } 781146768Ssam 782146768Ssam/* Port number search */ 783146768Ssam for (i = 0; i < max_trials; i++) { 784146768Ssam 785146768Ssam struct alias_link *search_result; 786146768Ssam 787146768Ssam for (j = 0; j < port_count; j++) 788146768Ssam if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr, 789146768Ssam dst_port, htons(port_sys + j), 790146768Ssam link_type, 0))) 791146768Ssam break; 792146768Ssam 793146768Ssam /* Found a good range, return base */ 794146768Ssam if (j == port_count) 795146768Ssam return (htons(port_sys)); 796146768Ssam 797146768Ssam /* Find a new base to try */ 798146768Ssam if (align == FIND_EVEN_ALIAS_BASE) 799109839Sfenner port_sys = random() & ALIAS_PORT_MASK_EVEN; 800109839Sfenner else 801127664Sbms port_sys = random() & ALIAS_PORT_MASK; 802127664Sbms 803127664Sbms port_sys += ALIAS_PORT_BASE; 804127664Sbms } 805127664Sbms 806127664Sbms#ifdef LIBALIAS_DEBUG 807109839Sfenner fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 808127664Sbms fprintf(stderr, "could not find free port(s)\n"); 809109839Sfenner#endif 810146768Ssam 811146768Ssam return (0); 812146768Ssam} 813146768Ssam 814146768Ssamstatic void 815146768SsamCleanupAliasData(struct libalias *la) 816146768Ssam{ 817146768Ssam struct alias_link *lnk; 818146768Ssam int i; 819146768Ssam 820146768Ssam LIBALIAS_LOCK_ASSERT(la); 821146768Ssam for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 822146768Ssam while ((lnk = LIST_FIRST(&la->linkTableOut[i])) != NULL) 823146768Ssam DeleteLink(lnk); 824146768Ssam } 825146768Ssam 826146768Ssam la->cleanupIndex = 0; 827146768Ssam} 828146768Ssam 829146768Ssam 830146768Ssamstatic void 831146768SsamIncrementalCleanup(struct libalias *la) 832146768Ssam{ 833146768Ssam struct alias_link *lnk, *lnk_tmp; 834146768Ssam 835146768Ssam LIBALIAS_LOCK_ASSERT(la); 836146768Ssam LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++], 837146768Ssam list_out, lnk_tmp) { 838146768Ssam if (la->timeStamp - lnk->timestamp > lnk->expire_time) 839146768Ssam DeleteLink(lnk); 840146768Ssam } 841146768Ssam 842146768Ssam if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) 843146768Ssam la->cleanupIndex = 0; 844146768Ssam} 845146768Ssam 84617683Spststatic void 84717683SpstDeleteLink(struct alias_link *lnk) 848127664Sbms{ 849127664Sbms struct libalias *la = lnk->la; 850127664Sbms 851127664Sbms LIBALIAS_LOCK_ASSERT(la); 852127664Sbms/* Don't do anything if the link is marked permanent */ 85317683Spst if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT) 85417683Spst return; 85517683Spst 85617683Spst#ifndef NO_FW_PUNCH 85775107Sfenner/* Delete associated firewall hole, if any */ 85875107Sfenner ClearFWHole(lnk); 85917683Spst#endif 86017683Spst 86117683Spst/* Free memory allocated for LSNAT server pool */ 86275107Sfenner if (lnk->server != NULL) { 86375107Sfenner struct server *head, *curr, *next; 86475107Sfenner 86575107Sfenner head = curr = lnk->server; 86675107Sfenner do { 86775107Sfenner next = curr->next; 86875107Sfenner free(curr); 86975107Sfenner } while ((curr = next) != head); 87075107Sfenner } 87175107Sfenner/* Adjust output table pointers */ 87275107Sfenner LIST_REMOVE(lnk, list_out); 87375107Sfenner 87475107Sfenner/* Adjust input table pointers */ 87575107Sfenner LIST_REMOVE(lnk, list_in); 87675107Sfenner#ifndef NO_USE_SOCKETS 87775107Sfenner/* Close socket, if one has been allocated */ 87875107Sfenner if (lnk->sockfd != -1) { 87975107Sfenner la->sockCount--; 88075107Sfenner close(lnk->sockfd); 88175107Sfenner } 88275107Sfenner#endif 88375107Sfenner/* Link-type dependent cleanup */ 88475107Sfenner switch (lnk->link_type) { 88575107Sfenner case LINK_ICMP: 88675107Sfenner la->icmpLinkCount--; 88775107Sfenner break; 88875107Sfenner case LINK_UDP: 88975107Sfenner la->udpLinkCount--; 89075107Sfenner break; 89175107Sfenner case LINK_TCP: 89275107Sfenner la->tcpLinkCount--; 89375107Sfenner free(lnk->data.tcp); 89475107Sfenner break; 89575107Sfenner case LINK_PPTP: 89675107Sfenner la->pptpLinkCount--; 89775107Sfenner break; 89875107Sfenner case LINK_FRAGMENT_ID: 89975107Sfenner la->fragmentIdLinkCount--; 90075107Sfenner break; 90175107Sfenner case LINK_FRAGMENT_PTR: 90275107Sfenner la->fragmentPtrLinkCount--; 90375107Sfenner if (lnk->data.frag_ptr != NULL) 90475107Sfenner free(lnk->data.frag_ptr); 90575107Sfenner break; 90675107Sfenner case LINK_ADDR: 90775107Sfenner break; 90875107Sfenner default: 90975107Sfenner la->protoLinkCount--; 91075107Sfenner break; 91175107Sfenner } 91275107Sfenner 91375107Sfenner/* Free memory */ 91475107Sfenner free(lnk); 91575107Sfenner 91675107Sfenner/* Write statistics, if logging enabled */ 91775107Sfenner if (la->packetAliasMode & PKT_ALIAS_LOG) { 91875107Sfenner ShowAliasStats(la); 91975107Sfenner } 92098530Sfenner} 92117683Spst 92298530Sfenner 92398530Sfennerstatic struct alias_link * 92498530SfennerAddLink(struct libalias *la, struct in_addr src_addr, 92598530Sfenner struct in_addr dst_addr, 92698530Sfenner struct in_addr alias_addr, 92717683Spst u_short src_port, 92817683Spst u_short dst_port, 92975107Sfenner int alias_port_param, /* if less than zero, alias */ 93075107Sfenner int link_type) 93117683Spst{ /* port will be automatically *//* chosen. 93217683Spst * If greater than */ 93317683Spst u_int start_point; /* zero, equal to alias port */ 93417683Spst struct alias_link *lnk; 93517683Spst 93675107Sfenner LIBALIAS_LOCK_ASSERT(la); 93775107Sfenner lnk = malloc(sizeof(struct alias_link)); 93817683Spst if (lnk != NULL) { 93917683Spst /* Basic initialization */ 940127664Sbms lnk->la = la; 941127664Sbms lnk->src_addr = src_addr; 942127664Sbms lnk->dst_addr = dst_addr; 943127664Sbms lnk->alias_addr = alias_addr; 944127664Sbms lnk->proxy_addr.s_addr = INADDR_ANY; 94517683Spst lnk->src_port = src_port; 946127664Sbms lnk->dst_port = dst_port; 947146768Ssam lnk->proxy_port = 0; 948146768Ssam lnk->server = NULL; 949146768Ssam lnk->link_type = link_type; 950146768Ssam#ifndef NO_USE_SOCKETS 951146768Ssam lnk->sockfd = -1; 952146768Ssam#endif 953146768Ssam lnk->flags = 0; 954146768Ssam lnk->pflags = 0; 955146768Ssam lnk->timestamp = la->timeStamp; 956146768Ssam 957146768Ssam /* Expiration time */ 958146768Ssam switch (link_type) { 959146768Ssam case LINK_ICMP: 960146768Ssam lnk->expire_time = ICMP_EXPIRE_TIME; 961146768Ssam break; 962146768Ssam case LINK_UDP: 963146768Ssam lnk->expire_time = UDP_EXPIRE_TIME; 964146768Ssam break; 965146768Ssam case LINK_TCP: 966146768Ssam lnk->expire_time = TCP_EXPIRE_INITIAL; 967146768Ssam break; 968146768Ssam case LINK_PPTP: 969127664Sbms lnk->flags |= LINK_PERMANENT; /* no timeout. */ 970127664Sbms break; 971127664Sbms case LINK_FRAGMENT_ID: 972127664Sbms lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; 973127664Sbms break; 974127664Sbms case LINK_FRAGMENT_PTR: 975127664Sbms lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 976127664Sbms break; 977127664Sbms case LINK_ADDR: 978127664Sbms break; 979127664Sbms default: 980127664Sbms lnk->expire_time = PROTO_EXPIRE_TIME; 981127664Sbms break; 982127664Sbms } 983127664Sbms 984127664Sbms /* Determine alias flags */ 985127664Sbms if (dst_addr.s_addr == INADDR_ANY) 986127664Sbms lnk->flags |= LINK_UNKNOWN_DEST_ADDR; 987127664Sbms if (dst_port == 0) 988127664Sbms lnk->flags |= LINK_UNKNOWN_DEST_PORT; 989127664Sbms 990127664Sbms /* Determine alias port */ 991127664Sbms if (GetNewPort(la, lnk, alias_port_param) != 0) { 992127664Sbms free(lnk); 993127664Sbms return (NULL); 994127664Sbms } 995127664Sbms /* Link-type dependent initialization */ 996127664Sbms switch (link_type) { 997127664Sbms struct tcp_dat *aux_tcp; 998127664Sbms 999127664Sbms case LINK_ICMP: 1000127664Sbms la->icmpLinkCount++; 1001127664Sbms break; 1002127664Sbms case LINK_UDP: 1003127664Sbms la->udpLinkCount++; 1004147894Ssam break; 1005127664Sbms case LINK_TCP: 1006127664Sbms aux_tcp = malloc(sizeof(struct tcp_dat)); 1007127664Sbms if (aux_tcp != NULL) { 1008127664Sbms int i; 1009147894Ssam 1010147894Ssam la->tcpLinkCount++; 1011147894Ssam aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 1012147894Ssam aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1013147894Ssam aux_tcp->state.index = 0; 1014127664Sbms aux_tcp->state.ack_modified = 0; 1015127664Sbms for (i = 0; i < N_LINK_TCP_DATA; i++) 1016127664Sbms aux_tcp->ack[i].active = 0; 1017146768Ssam aux_tcp->fwhole = -1; 1018127664Sbms lnk->data.tcp = aux_tcp; 1019147894Ssam } else { 1020127664Sbms#ifdef LIBALIAS_DEBUG 1021127664Sbms fprintf(stderr, "PacketAlias/AddLink: "); 1022127664Sbms fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 1023127664Sbms#endif 1024146768Ssam free(lnk); 1025127664Sbms return (NULL); 102617683Spst } 102717683Spst break; 102817683Spst case LINK_PPTP: 1029146768Ssam la->pptpLinkCount++; 1030146768Ssam break; 103117683Spst case LINK_FRAGMENT_ID: 103217683Spst la->fragmentIdLinkCount++; 103317683Spst break; 103417683Spst case LINK_FRAGMENT_PTR: 103517683Spst la->fragmentPtrLinkCount++; 1036127664Sbms break; 103717683Spst case LINK_ADDR: 1038127664Sbms break; 1039127664Sbms default: 1040127664Sbms la->protoLinkCount++; 1041127664Sbms break; 1042127664Sbms } 1043127664Sbms 1044127664Sbms /* Set up pointers for output lookup table */ 1045127664Sbms start_point = StartPointOut(src_addr, dst_addr, 1046127664Sbms src_port, dst_port, link_type); 1047127664Sbms LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); 1048127664Sbms 104956889Sfenner /* Set up pointers for input lookup table */ 105056889Sfenner start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); 105156889Sfenner LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); 105256889Sfenner } else { 105356889Sfenner#ifdef LIBALIAS_DEBUG 105475107Sfenner fprintf(stderr, "PacketAlias/AddLink(): "); 1055127664Sbms fprintf(stderr, "malloc() call failed.\n"); 1056127664Sbms#endif 1057127664Sbms } 105875107Sfenner if (la->packetAliasMode & PKT_ALIAS_LOG) { 105975107Sfenner ShowAliasStats(la); 1060127664Sbms } 1061127664Sbms return (lnk); 1062127664Sbms} 1063127664Sbms 1064127664Sbmsstatic struct alias_link * 1065127664SbmsReLink(struct alias_link *old_lnk, 1066127664Sbms struct in_addr src_addr, 1067127664Sbms struct in_addr dst_addr, 1068127664Sbms struct in_addr alias_addr, 1069127664Sbms u_short src_port, 1070127664Sbms u_short dst_port, 1071127664Sbms int alias_port_param, /* if less than zero, alias */ 1072127664Sbms int link_type) 107375107Sfenner{ /* port will be automatically *//* chosen. 107475107Sfenner * If greater than */ 107517683Spst struct alias_link *new_lnk; /* zero, equal to alias port */ 107617683Spst struct libalias *la = old_lnk->la; 1077127664Sbms 1078146768Ssam LIBALIAS_LOCK_ASSERT(la); 1079146768Ssam new_lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1080146768Ssam src_port, dst_port, alias_port_param, 1081146768Ssam link_type); 1082146768Ssam#ifndef NO_FW_PUNCH 1083146768Ssam if (new_lnk != NULL && 1084146768Ssam old_lnk->link_type == LINK_TCP && 1085146768Ssam old_lnk->data.tcp->fwhole > 0) { 108617683Spst PunchFWHole(new_lnk); 108717683Spst } 1088109839Sfenner#endif 1089147894Ssam DeleteLink(old_lnk); 1090147894Ssam return (new_lnk); 1091147894Ssam} 1092147894Ssam 1093127664Sbmsstatic struct alias_link * 1094162012Ssam_FindLinkOut(struct libalias *la, struct in_addr src_addr, 1095147894Ssam struct in_addr dst_addr, 1096147894Ssam u_short src_port, 1097147894Ssam u_short dst_port, 1098147894Ssam int link_type, 1099147894Ssam int replace_partial_links) 1100147894Ssam{ 1101162012Ssam u_int i; 1102147894Ssam struct alias_link *lnk; 1103162012Ssam 1104147894Ssam LIBALIAS_LOCK_ASSERT(la); 1105162012Ssam i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1106147894Ssam LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { 1107147894Ssam if (lnk->dst_addr.s_addr == dst_addr.s_addr && 1108147894Ssam lnk->src_addr.s_addr == src_addr.s_addr && 1109162012Ssam lnk->src_port == src_port && 1110147894Ssam lnk->dst_port == dst_port && 1111147894Ssam lnk->link_type == link_type && 1112147894Ssam lnk->server == NULL) { 1113162012Ssam lnk->timestamp = la->timeStamp; 1114147894Ssam break; 1115147894Ssam } 1116147894Ssam } 1117147894Ssam 1118147894Ssam/* Search for partially specified links. */ 1119147894Ssam if (lnk == NULL && replace_partial_links) { 1120147894Ssam if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1121147894Ssam lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1122147894Ssam link_type, 0); 1123147894Ssam if (lnk == NULL) 1124147894Ssam lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 1125147894Ssam dst_port, link_type, 0); 1126127664Sbms } 1127109839Sfenner if (lnk == NULL && 1128127664Sbms (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1129109839Sfenner lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, 1130109839Sfenner link_type, 0); 1131109839Sfenner } 1132127664Sbms if (lnk != NULL) { 1133109839Sfenner lnk = ReLink(lnk, 1134127664Sbms src_addr, dst_addr, lnk->alias_addr, 1135127664Sbms src_port, dst_port, lnk->alias_port, 1136109839Sfenner link_type); 1137 } 1138 } 1139 return (lnk); 1140} 1141 1142static struct alias_link * 1143FindLinkOut(struct libalias *la, struct in_addr src_addr, 1144 struct in_addr dst_addr, 1145 u_short src_port, 1146 u_short dst_port, 1147 int link_type, 1148 int replace_partial_links) 1149{ 1150 struct alias_link *lnk; 1151 1152 LIBALIAS_LOCK_ASSERT(la); 1153 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1154 link_type, replace_partial_links); 1155 1156 if (lnk == NULL) { 1157 /* 1158 * The following allows permanent links to be specified as 1159 * using the default source address (i.e. device interface 1160 * address) without knowing in advance what that address 1161 * is. 1162 */ 1163 if (la->aliasAddress.s_addr != INADDR_ANY && 1164 src_addr.s_addr == la->aliasAddress.s_addr) { 1165 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, 1166 link_type, replace_partial_links); 1167 } 1168 } 1169 return (lnk); 1170} 1171 1172 1173static struct alias_link * 1174_FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1175 struct in_addr alias_addr, 1176 u_short dst_port, 1177 u_short alias_port, 1178 int link_type, 1179 int replace_partial_links) 1180{ 1181 int flags_in; 1182 u_int start_point; 1183 struct alias_link *lnk; 1184 struct alias_link *lnk_fully_specified; 1185 struct alias_link *lnk_unknown_all; 1186 struct alias_link *lnk_unknown_dst_addr; 1187 struct alias_link *lnk_unknown_dst_port; 1188 1189 LIBALIAS_LOCK_ASSERT(la); 1190/* Initialize pointers */ 1191 lnk_fully_specified = NULL; 1192 lnk_unknown_all = NULL; 1193 lnk_unknown_dst_addr = NULL; 1194 lnk_unknown_dst_port = NULL; 1195 1196/* If either the dest addr or port is unknown, the search 1197 loop will have to know about this. */ 1198 1199 flags_in = 0; 1200 if (dst_addr.s_addr == INADDR_ANY) 1201 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1202 if (dst_port == 0) 1203 flags_in |= LINK_UNKNOWN_DEST_PORT; 1204 1205/* Search loop */ 1206 start_point = StartPointIn(alias_addr, alias_port, link_type); 1207 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { 1208 int flags; 1209 1210 flags = flags_in | lnk->flags; 1211 if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1212 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1213 && lnk->alias_port == alias_port 1214 && lnk->dst_addr.s_addr == dst_addr.s_addr 1215 && lnk->dst_port == dst_port 1216 && lnk->link_type == link_type) { 1217 lnk_fully_specified = lnk; 1218 break; 1219 } 1220 } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1221 && (flags & LINK_UNKNOWN_DEST_PORT)) { 1222 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1223 && lnk->alias_port == alias_port 1224 && lnk->link_type == link_type) { 1225 if (lnk_unknown_all == NULL) 1226 lnk_unknown_all = lnk; 1227 } 1228 } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1229 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1230 && lnk->alias_port == alias_port 1231 && lnk->link_type == link_type 1232 && lnk->dst_port == dst_port) { 1233 if (lnk_unknown_dst_addr == NULL) 1234 lnk_unknown_dst_addr = lnk; 1235 } 1236 } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1237 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1238 && lnk->alias_port == alias_port 1239 && lnk->link_type == link_type 1240 && lnk->dst_addr.s_addr == dst_addr.s_addr) { 1241 if (lnk_unknown_dst_port == NULL) 1242 lnk_unknown_dst_port = lnk; 1243 } 1244 } 1245 } 1246 1247 1248 1249 if (lnk_fully_specified != NULL) { 1250 lnk_fully_specified->timestamp = la->timeStamp; 1251 lnk = lnk_fully_specified; 1252 } else if (lnk_unknown_dst_port != NULL) 1253 lnk = lnk_unknown_dst_port; 1254 else if (lnk_unknown_dst_addr != NULL) 1255 lnk = lnk_unknown_dst_addr; 1256 else if (lnk_unknown_all != NULL) 1257 lnk = lnk_unknown_all; 1258 else 1259 return (NULL); 1260 1261 if (replace_partial_links && 1262 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { 1263 struct in_addr src_addr; 1264 u_short src_port; 1265 1266 if (lnk->server != NULL) { /* LSNAT link */ 1267 src_addr = lnk->server->addr; 1268 src_port = lnk->server->port; 1269 lnk->server = lnk->server->next; 1270 } else { 1271 src_addr = lnk->src_addr; 1272 src_port = lnk->src_port; 1273 } 1274 1275 lnk = ReLink(lnk, 1276 src_addr, dst_addr, alias_addr, 1277 src_port, dst_port, alias_port, 1278 link_type); 1279 } 1280 return (lnk); 1281} 1282 1283static struct alias_link * 1284FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1285 struct in_addr alias_addr, 1286 u_short dst_port, 1287 u_short alias_port, 1288 int link_type, 1289 int replace_partial_links) 1290{ 1291 struct alias_link *lnk; 1292 1293 LIBALIAS_LOCK_ASSERT(la); 1294 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1295 link_type, replace_partial_links); 1296 1297 if (lnk == NULL) { 1298 /* 1299 * The following allows permanent links to be specified as 1300 * using the default aliasing address (i.e. device 1301 * interface address) without knowing in advance what that 1302 * address is. 1303 */ 1304 if (la->aliasAddress.s_addr != INADDR_ANY && 1305 alias_addr.s_addr == la->aliasAddress.s_addr) { 1306 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, 1307 link_type, replace_partial_links); 1308 } 1309 } 1310 return (lnk); 1311} 1312 1313 1314 1315 1316/* External routines for finding/adding links 1317 1318-- "external" means outside alias_db.c, but within alias*.c -- 1319 1320 FindIcmpIn(), FindIcmpOut() 1321 FindFragmentIn1(), FindFragmentIn2() 1322 AddFragmentPtrLink(), FindFragmentPtr() 1323 FindProtoIn(), FindProtoOut() 1324 FindUdpTcpIn(), FindUdpTcpOut() 1325 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 1326 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 1327 FindOriginalAddress(), FindAliasAddress() 1328 1329(prototypes in alias_local.h) 1330*/ 1331 1332 1333struct alias_link * 1334FindIcmpIn(struct libalias *la, struct in_addr dst_addr, 1335 struct in_addr alias_addr, 1336 u_short id_alias, 1337 int create) 1338{ 1339 struct alias_link *lnk; 1340 1341 LIBALIAS_LOCK_ASSERT(la); 1342 lnk = FindLinkIn(la, dst_addr, alias_addr, 1343 NO_DEST_PORT, id_alias, 1344 LINK_ICMP, 0); 1345 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1346 struct in_addr target_addr; 1347 1348 target_addr = FindOriginalAddress(la, alias_addr); 1349 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1350 id_alias, NO_DEST_PORT, id_alias, 1351 LINK_ICMP); 1352 } 1353 return (lnk); 1354} 1355 1356 1357struct alias_link * 1358FindIcmpOut(struct libalias *la, struct in_addr src_addr, 1359 struct in_addr dst_addr, 1360 u_short id, 1361 int create) 1362{ 1363 struct alias_link *lnk; 1364 1365 LIBALIAS_LOCK_ASSERT(la); 1366 lnk = FindLinkOut(la, src_addr, dst_addr, 1367 id, NO_DEST_PORT, 1368 LINK_ICMP, 0); 1369 if (lnk == NULL && create) { 1370 struct in_addr alias_addr; 1371 1372 alias_addr = FindAliasAddress(la, src_addr); 1373 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1374 id, NO_DEST_PORT, GET_ALIAS_ID, 1375 LINK_ICMP); 1376 } 1377 return (lnk); 1378} 1379 1380 1381struct alias_link * 1382FindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1383 struct in_addr alias_addr, 1384 u_short ip_id) 1385{ 1386 struct alias_link *lnk; 1387 1388 LIBALIAS_LOCK_ASSERT(la); 1389 lnk = FindLinkIn(la, dst_addr, alias_addr, 1390 NO_DEST_PORT, ip_id, 1391 LINK_FRAGMENT_ID, 0); 1392 1393 if (lnk == NULL) { 1394 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr, 1395 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1396 LINK_FRAGMENT_ID); 1397 } 1398 return (lnk); 1399} 1400 1401 1402struct alias_link * 1403FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if 1404 * one */ 1405 struct in_addr alias_addr, /* is not found. */ 1406 u_short ip_id) 1407{ 1408 1409 LIBALIAS_LOCK_ASSERT(la); 1410 return FindLinkIn(la, dst_addr, alias_addr, 1411 NO_DEST_PORT, ip_id, 1412 LINK_FRAGMENT_ID, 0); 1413} 1414 1415 1416struct alias_link * 1417AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1418 u_short ip_id) 1419{ 1420 1421 LIBALIAS_LOCK_ASSERT(la); 1422 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress, 1423 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1424 LINK_FRAGMENT_PTR); 1425} 1426 1427 1428struct alias_link * 1429FindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1430 u_short ip_id) 1431{ 1432 1433 LIBALIAS_LOCK_ASSERT(la); 1434 return FindLinkIn(la, dst_addr, la->nullAddress, 1435 NO_DEST_PORT, ip_id, 1436 LINK_FRAGMENT_PTR, 0); 1437} 1438 1439 1440struct alias_link * 1441FindProtoIn(struct libalias *la, struct in_addr dst_addr, 1442 struct in_addr alias_addr, 1443 u_char proto) 1444{ 1445 struct alias_link *lnk; 1446 1447 LIBALIAS_LOCK_ASSERT(la); 1448 lnk = FindLinkIn(la, dst_addr, alias_addr, 1449 NO_DEST_PORT, 0, 1450 proto, 1); 1451 1452 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1453 struct in_addr target_addr; 1454 1455 target_addr = FindOriginalAddress(la, alias_addr); 1456 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1457 NO_SRC_PORT, NO_DEST_PORT, 0, 1458 proto); 1459 } 1460 return (lnk); 1461} 1462 1463 1464struct alias_link * 1465FindProtoOut(struct libalias *la, struct in_addr src_addr, 1466 struct in_addr dst_addr, 1467 u_char proto) 1468{ 1469 struct alias_link *lnk; 1470 1471 LIBALIAS_LOCK_ASSERT(la); 1472 lnk = FindLinkOut(la, src_addr, dst_addr, 1473 NO_SRC_PORT, NO_DEST_PORT, 1474 proto, 1); 1475 1476 if (lnk == NULL) { 1477 struct in_addr alias_addr; 1478 1479 alias_addr = FindAliasAddress(la, src_addr); 1480 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1481 NO_SRC_PORT, NO_DEST_PORT, 0, 1482 proto); 1483 } 1484 return (lnk); 1485} 1486 1487 1488struct alias_link * 1489FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1490 struct in_addr alias_addr, 1491 u_short dst_port, 1492 u_short alias_port, 1493 u_char proto, 1494 int create) 1495{ 1496 int link_type; 1497 struct alias_link *lnk; 1498 1499 LIBALIAS_LOCK_ASSERT(la); 1500 switch (proto) { 1501 case IPPROTO_UDP: 1502 link_type = LINK_UDP; 1503 break; 1504 case IPPROTO_TCP: 1505 link_type = LINK_TCP; 1506 break; 1507 default: 1508 return (NULL); 1509 break; 1510 } 1511 1512 lnk = FindLinkIn(la, dst_addr, alias_addr, 1513 dst_port, alias_port, 1514 link_type, create); 1515 1516 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1517 struct in_addr target_addr; 1518 1519 target_addr = FindOriginalAddress(la, alias_addr); 1520 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1521 alias_port, dst_port, alias_port, 1522 link_type); 1523 } 1524 return (lnk); 1525} 1526 1527 1528struct alias_link * 1529FindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1530 struct in_addr dst_addr, 1531 u_short src_port, 1532 u_short dst_port, 1533 u_char proto, 1534 int create) 1535{ 1536 int link_type; 1537 struct alias_link *lnk; 1538 1539 LIBALIAS_LOCK_ASSERT(la); 1540 switch (proto) { 1541 case IPPROTO_UDP: 1542 link_type = LINK_UDP; 1543 break; 1544 case IPPROTO_TCP: 1545 link_type = LINK_TCP; 1546 break; 1547 default: 1548 return (NULL); 1549 break; 1550 } 1551 1552 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 1553 1554 if (lnk == NULL && create) { 1555 struct in_addr alias_addr; 1556 1557 alias_addr = FindAliasAddress(la, src_addr); 1558 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1559 src_port, dst_port, GET_ALIAS_PORT, 1560 link_type); 1561 } 1562 return (lnk); 1563} 1564 1565 1566struct alias_link * 1567AddPptp(struct libalias *la, struct in_addr src_addr, 1568 struct in_addr dst_addr, 1569 struct in_addr alias_addr, 1570 u_int16_t src_call_id) 1571{ 1572 struct alias_link *lnk; 1573 1574 LIBALIAS_LOCK_ASSERT(la); 1575 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1576 src_call_id, 0, GET_ALIAS_PORT, 1577 LINK_PPTP); 1578 1579 return (lnk); 1580} 1581 1582 1583struct alias_link * 1584FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1585 struct in_addr dst_addr, 1586 u_int16_t src_call_id) 1587{ 1588 u_int i; 1589 struct alias_link *lnk; 1590 1591 LIBALIAS_LOCK_ASSERT(la); 1592 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1593 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1594 if (lnk->link_type == LINK_PPTP && 1595 lnk->src_addr.s_addr == src_addr.s_addr && 1596 lnk->dst_addr.s_addr == dst_addr.s_addr && 1597 lnk->src_port == src_call_id) 1598 break; 1599 1600 return (lnk); 1601} 1602 1603 1604struct alias_link * 1605FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1606 struct in_addr dst_addr, 1607 u_int16_t dst_call_id) 1608{ 1609 u_int i; 1610 struct alias_link *lnk; 1611 1612 LIBALIAS_LOCK_ASSERT(la); 1613 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1614 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1615 if (lnk->link_type == LINK_PPTP && 1616 lnk->src_addr.s_addr == src_addr.s_addr && 1617 lnk->dst_addr.s_addr == dst_addr.s_addr && 1618 lnk->dst_port == dst_call_id) 1619 break; 1620 1621 return (lnk); 1622} 1623 1624 1625struct alias_link * 1626FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1627 struct in_addr alias_addr, 1628 u_int16_t dst_call_id) 1629{ 1630 u_int i; 1631 struct alias_link *lnk; 1632 1633 LIBALIAS_LOCK_ASSERT(la); 1634 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1635 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) 1636 if (lnk->link_type == LINK_PPTP && 1637 lnk->dst_addr.s_addr == dst_addr.s_addr && 1638 lnk->alias_addr.s_addr == alias_addr.s_addr && 1639 lnk->dst_port == dst_call_id) 1640 break; 1641 1642 return (lnk); 1643} 1644 1645 1646struct alias_link * 1647FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1648 struct in_addr alias_addr, 1649 u_int16_t alias_call_id) 1650{ 1651 struct alias_link *lnk; 1652 1653 LIBALIAS_LOCK_ASSERT(la); 1654 lnk = FindLinkIn(la, dst_addr, alias_addr, 1655 0 /* any */ , alias_call_id, 1656 LINK_PPTP, 0); 1657 1658 1659 return (lnk); 1660} 1661 1662 1663struct alias_link * 1664FindRtspOut(struct libalias *la, struct in_addr src_addr, 1665 struct in_addr dst_addr, 1666 u_short src_port, 1667 u_short alias_port, 1668 u_char proto) 1669{ 1670 int link_type; 1671 struct alias_link *lnk; 1672 1673 LIBALIAS_LOCK_ASSERT(la); 1674 switch (proto) { 1675 case IPPROTO_UDP: 1676 link_type = LINK_UDP; 1677 break; 1678 case IPPROTO_TCP: 1679 link_type = LINK_TCP; 1680 break; 1681 default: 1682 return (NULL); 1683 break; 1684 } 1685 1686 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 1687 1688 if (lnk == NULL) { 1689 struct in_addr alias_addr; 1690 1691 alias_addr = FindAliasAddress(la, src_addr); 1692 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1693 src_port, 0, alias_port, 1694 link_type); 1695 } 1696 return (lnk); 1697} 1698 1699 1700struct in_addr 1701FindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 1702{ 1703 struct alias_link *lnk; 1704 1705 LIBALIAS_LOCK_ASSERT(la); 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 LIBALIAS_LOCK_ASSERT(la); 1739 lnk = FindLinkOut(la, original_addr, la->nullAddress, 1740 0, 0, LINK_ADDR, 0); 1741 if (lnk == NULL) { 1742 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1743 la->aliasAddress : original_addr; 1744 } else { 1745 if (lnk->alias_addr.s_addr == INADDR_ANY) 1746 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1747 la->aliasAddress : original_addr; 1748 else 1749 return (lnk->alias_addr); 1750 } 1751} 1752 1753 1754/* External routines for getting or changing link data 1755 (external to alias_db.c, but internal to alias*.c) 1756 1757 SetFragmentData(), GetFragmentData() 1758 SetFragmentPtr(), GetFragmentPtr() 1759 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1760 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1761 GetOriginalPort(), GetAliasPort() 1762 SetAckModified(), GetAckModified() 1763 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1764 SetProtocolFlags(), GetProtocolFlags() 1765 SetDestCallId() 1766*/ 1767 1768 1769void 1770SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 1771{ 1772 lnk->data.frag_addr = src_addr; 1773} 1774 1775 1776void 1777GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 1778{ 1779 *src_addr = lnk->data.frag_addr; 1780} 1781 1782 1783void 1784SetFragmentPtr(struct alias_link *lnk, char *fptr) 1785{ 1786 lnk->data.frag_ptr = fptr; 1787} 1788 1789 1790void 1791GetFragmentPtr(struct alias_link *lnk, char **fptr) 1792{ 1793 *fptr = lnk->data.frag_ptr; 1794} 1795 1796 1797void 1798SetStateIn(struct alias_link *lnk, int state) 1799{ 1800 /* TCP input state */ 1801 switch (state) { 1802 case ALIAS_TCP_STATE_DISCONNECTED: 1803 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1804 lnk->expire_time = TCP_EXPIRE_DEAD; 1805 else 1806 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1807 break; 1808 case ALIAS_TCP_STATE_CONNECTED: 1809 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1810 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1811 break; 1812 default: 1813#ifdef _KERNEL 1814 panic("libalias:SetStateIn() unknown state"); 1815#else 1816 abort(); 1817#endif 1818 } 1819 lnk->data.tcp->state.in = state; 1820} 1821 1822 1823void 1824SetStateOut(struct alias_link *lnk, int state) 1825{ 1826 /* TCP output state */ 1827 switch (state) { 1828 case ALIAS_TCP_STATE_DISCONNECTED: 1829 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1830 lnk->expire_time = TCP_EXPIRE_DEAD; 1831 else 1832 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1833 break; 1834 case ALIAS_TCP_STATE_CONNECTED: 1835 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1836 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1837 break; 1838 default: 1839#ifdef _KERNEL 1840 panic("libalias:SetStateOut() unknown state"); 1841#else 1842 abort(); 1843#endif 1844 } 1845 lnk->data.tcp->state.out = state; 1846} 1847 1848 1849int 1850GetStateIn(struct alias_link *lnk) 1851{ 1852 /* TCP input state */ 1853 return (lnk->data.tcp->state.in); 1854} 1855 1856 1857int 1858GetStateOut(struct alias_link *lnk) 1859{ 1860 /* TCP output state */ 1861 return (lnk->data.tcp->state.out); 1862} 1863 1864 1865struct in_addr 1866GetOriginalAddress(struct alias_link *lnk) 1867{ 1868 if (lnk->src_addr.s_addr == INADDR_ANY) 1869 return (lnk->la->aliasAddress); 1870 else 1871 return (lnk->src_addr); 1872} 1873 1874 1875struct in_addr 1876GetDestAddress(struct alias_link *lnk) 1877{ 1878 return (lnk->dst_addr); 1879} 1880 1881 1882struct in_addr 1883GetAliasAddress(struct alias_link *lnk) 1884{ 1885 if (lnk->alias_addr.s_addr == INADDR_ANY) 1886 return (lnk->la->aliasAddress); 1887 else 1888 return (lnk->alias_addr); 1889} 1890 1891 1892struct in_addr 1893GetDefaultAliasAddress(struct libalias *la) 1894{ 1895 1896 LIBALIAS_LOCK_ASSERT(la); 1897 return (la->aliasAddress); 1898} 1899 1900 1901void 1902SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 1903{ 1904 1905 LIBALIAS_LOCK_ASSERT(la); 1906 la->aliasAddress = alias_addr; 1907} 1908 1909 1910u_short 1911GetOriginalPort(struct alias_link *lnk) 1912{ 1913 return (lnk->src_port); 1914} 1915 1916 1917u_short 1918GetAliasPort(struct alias_link *lnk) 1919{ 1920 return (lnk->alias_port); 1921} 1922 1923#ifndef NO_FW_PUNCH 1924static u_short 1925GetDestPort(struct alias_link *lnk) 1926{ 1927 return (lnk->dst_port); 1928} 1929 1930#endif 1931 1932void 1933SetAckModified(struct alias_link *lnk) 1934{ 1935/* Indicate that ACK numbers have been modified in a TCP connection */ 1936 lnk->data.tcp->state.ack_modified = 1; 1937} 1938 1939 1940struct in_addr 1941GetProxyAddress(struct alias_link *lnk) 1942{ 1943 return (lnk->proxy_addr); 1944} 1945 1946 1947void 1948SetProxyAddress(struct alias_link *lnk, struct in_addr addr) 1949{ 1950 lnk->proxy_addr = addr; 1951} 1952 1953 1954u_short 1955GetProxyPort(struct alias_link *lnk) 1956{ 1957 return (lnk->proxy_port); 1958} 1959 1960 1961void 1962SetProxyPort(struct alias_link *lnk, u_short port) 1963{ 1964 lnk->proxy_port = port; 1965} 1966 1967 1968int 1969GetAckModified(struct alias_link *lnk) 1970{ 1971/* See if ACK numbers have been modified */ 1972 return (lnk->data.tcp->state.ack_modified); 1973} 1974 1975// XXX ip free 1976int 1977GetDeltaAckIn(u_long ack, struct alias_link *lnk) 1978{ 1979/* 1980Find out how much the ACK number has been altered for an incoming 1981TCP packet. To do this, a circular list of ACK numbers where the TCP 1982packet size was altered is searched. 1983*/ 1984 1985 int i; 1986 int delta, ack_diff_min; 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// XXX ip free 2015int 2016GetDeltaSeqOut(u_long seq, 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 int delta, seq_diff_min; 2026 2027 delta = 0; 2028 seq_diff_min = -1; 2029 for (i = 0; i < N_LINK_TCP_DATA; i++) { 2030 struct ack_data_record x; 2031 2032 x = lnk->data.tcp->ack[i]; 2033 if (x.active == 1) { 2034 int seq_diff; 2035 2036 seq_diff = SeqDiff(x.ack_old, seq); 2037 if (seq_diff >= 0) { 2038 if (seq_diff_min >= 0) { 2039 if (seq_diff < seq_diff_min) { 2040 delta = x.delta; 2041 seq_diff_min = seq_diff; 2042 } 2043 } else { 2044 delta = x.delta; 2045 seq_diff_min = seq_diff; 2046 } 2047 } 2048 } 2049 } 2050 return (delta); 2051} 2052 2053// XXX ip free 2054void 2055AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 2056 u_long th_seq, u_int th_off) 2057{ 2058/* 2059When a TCP packet has been altered in length, save this 2060information in a circular list. If enough packets have 2061been altered, then this list will begin to overwrite itself. 2062*/ 2063 2064 struct ack_data_record x; 2065 int hlen, tlen, dlen; 2066 int i; 2067 2068 hlen = (ip_hl + th_off) << 2; 2069 tlen = ntohs(ip_len); 2070 dlen = tlen - hlen; 2071 2072 x.ack_old = htonl(ntohl(th_seq) + dlen); 2073 x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 2074 x.delta = delta; 2075 x.active = 1; 2076 2077 i = lnk->data.tcp->state.index; 2078 lnk->data.tcp->ack[i] = x; 2079 2080 i++; 2081 if (i == N_LINK_TCP_DATA) 2082 lnk->data.tcp->state.index = 0; 2083 else 2084 lnk->data.tcp->state.index = i; 2085} 2086 2087void 2088SetExpire(struct alias_link *lnk, int expire) 2089{ 2090 if (expire == 0) { 2091 lnk->flags &= ~LINK_PERMANENT; 2092 DeleteLink(lnk); 2093 } else if (expire == -1) { 2094 lnk->flags |= LINK_PERMANENT; 2095 } else if (expire > 0) { 2096 lnk->expire_time = expire; 2097 } else { 2098#ifdef LIBALIAS_DEBUG 2099 fprintf(stderr, "PacketAlias/SetExpire(): "); 2100 fprintf(stderr, "error in expire parameter\n"); 2101#endif 2102 } 2103} 2104 2105void 2106ClearCheckNewLink(struct libalias *la) 2107{ 2108 2109 LIBALIAS_LOCK_ASSERT(la); 2110 la->newDefaultLink = 0; 2111} 2112 2113void 2114SetProtocolFlags(struct alias_link *lnk, int pflags) 2115{ 2116 2117 lnk->pflags = pflags;; 2118} 2119 2120int 2121GetProtocolFlags(struct alias_link *lnk) 2122{ 2123 2124 return (lnk->pflags); 2125} 2126 2127void 2128SetDestCallId(struct alias_link *lnk, u_int16_t cid) 2129{ 2130 struct libalias *la = lnk->la; 2131 2132 LIBALIAS_LOCK_ASSERT(la); 2133 la->deleteAllLinks = 1; 2134 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2135 lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2136 la->deleteAllLinks = 0; 2137} 2138 2139 2140/* Miscellaneous Functions 2141 2142 HouseKeeping() 2143 InitPacketAliasLog() 2144 UninitPacketAliasLog() 2145*/ 2146 2147/* 2148 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2149 is called to find and remove timed-out aliasing links. Logic exists 2150 to sweep through the entire table and linked list structure 2151 every 60 seconds. 2152 2153 (prototype in alias_local.h) 2154*/ 2155 2156void 2157HouseKeeping(struct libalias *la) 2158{ 2159 int i, n; 2160#ifndef _KERNEL 2161 struct timeval tv; 2162 struct timezone tz; 2163#endif 2164 2165 LIBALIAS_LOCK_ASSERT(la); 2166 /* 2167 * Save system time (seconds) in global variable timeStamp for use 2168 * by other functions. This is done so as not to unnecessarily 2169 * waste timeline by making system calls. 2170 */ 2171#ifdef _KERNEL 2172 la->timeStamp = time_uptime; 2173#else 2174 gettimeofday(&tv, &tz); 2175 la->timeStamp = tv.tv_sec; 2176#endif 2177 2178 /* Compute number of spokes (output table link chains) to cover */ 2179 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime); 2180 n /= ALIAS_CLEANUP_INTERVAL_SECS; 2181 2182 /* Handle different cases */ 2183 if (n > 0) { 2184 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2185 n = ALIAS_CLEANUP_MAX_SPOKES; 2186 la->lastCleanupTime = la->timeStamp; 2187 for (i = 0; i < n; i++) 2188 IncrementalCleanup(la); 2189 } else if (n < 0) { 2190#ifdef LIBALIAS_DEBUG 2191 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2192 fprintf(stderr, "something unexpected in time values\n"); 2193#endif 2194 la->lastCleanupTime = la->timeStamp; 2195 } 2196} 2197 2198/* Init the log file and enable logging */ 2199static int 2200InitPacketAliasLog(struct libalias *la) 2201{ 2202 2203 LIBALIAS_LOCK_ASSERT(la); 2204 if (~la->packetAliasMode & PKT_ALIAS_LOG) { 2205#ifdef _KERNEL 2206 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 2207 ; 2208#else 2209 if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 2210 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2211#endif 2212 else 2213 return (ENOMEM); /* log initialization failed */ 2214 la->packetAliasMode |= PKT_ALIAS_LOG; 2215 } 2216 2217 return (1); 2218} 2219 2220/* Close the log-file and disable logging. */ 2221static void 2222UninitPacketAliasLog(struct libalias *la) 2223{ 2224 2225 LIBALIAS_LOCK_ASSERT(la); 2226 if (la->logDesc) { 2227#ifdef _KERNEL 2228 free(la->logDesc); 2229#else 2230 fclose(la->logDesc); 2231#endif 2232 la->logDesc = NULL; 2233 } 2234 la->packetAliasMode &= ~PKT_ALIAS_LOG; 2235} 2236 2237/* Outside world interfaces 2238 2239-- "outside world" means other than alias*.c routines -- 2240 2241 PacketAliasRedirectPort() 2242 PacketAliasAddServer() 2243 PacketAliasRedirectProto() 2244 PacketAliasRedirectAddr() 2245 PacketAliasRedirectDynamic() 2246 PacketAliasRedirectDelete() 2247 PacketAliasSetAddress() 2248 PacketAliasInit() 2249 PacketAliasUninit() 2250 PacketAliasSetMode() 2251 2252(prototypes in alias.h) 2253*/ 2254 2255/* Redirection from a specific public addr:port to a 2256 private addr:port */ 2257struct alias_link * 2258LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2259 struct in_addr dst_addr, u_short dst_port, 2260 struct in_addr alias_addr, u_short alias_port, 2261 u_char proto) 2262{ 2263 int link_type; 2264 struct alias_link *lnk; 2265 2266 LIBALIAS_LOCK(la); 2267 switch (proto) { 2268 case IPPROTO_UDP: 2269 link_type = LINK_UDP; 2270 break; 2271 case IPPROTO_TCP: 2272 link_type = LINK_TCP; 2273 break; 2274 default: 2275#ifdef LIBALIAS_DEBUG 2276 fprintf(stderr, "PacketAliasRedirectPort(): "); 2277 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2278#endif 2279 lnk = NULL; 2280 goto getout; 2281 } 2282 2283 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2284 src_port, dst_port, alias_port, 2285 link_type); 2286 2287 if (lnk != NULL) { 2288 lnk->flags |= LINK_PERMANENT; 2289 } 2290#ifdef LIBALIAS_DEBUG 2291 else { 2292 fprintf(stderr, "PacketAliasRedirectPort(): " 2293 "call to AddLink() failed\n"); 2294 } 2295#endif 2296 2297getout: 2298 LIBALIAS_UNLOCK(la); 2299 return (lnk); 2300} 2301 2302/* Add server to the pool of servers */ 2303int 2304LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 2305{ 2306 struct server *server; 2307 int res; 2308 2309 LIBALIAS_LOCK(la); 2310 (void)la; 2311 2312 server = malloc(sizeof(struct server)); 2313 2314 if (server != NULL) { 2315 struct server *head; 2316 2317 server->addr = addr; 2318 server->port = port; 2319 2320 head = lnk->server; 2321 if (head == NULL) 2322 server->next = server; 2323 else { 2324 struct server *s; 2325 2326 for (s = head; s->next != head; s = s->next); 2327 s->next = server; 2328 server->next = head; 2329 } 2330 lnk->server = server; 2331 res = 0; 2332 } else 2333 res = -1; 2334 2335 LIBALIAS_UNLOCK(la); 2336 return (res); 2337} 2338 2339/* Redirect packets of a given IP protocol from a specific 2340 public address to a private address */ 2341struct alias_link * 2342LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2343 struct in_addr dst_addr, 2344 struct in_addr alias_addr, 2345 u_char proto) 2346{ 2347 struct alias_link *lnk; 2348 2349 LIBALIAS_LOCK(la); 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 LIBALIAS_UNLOCK(la); 2365 return (lnk); 2366} 2367 2368/* Static address translation */ 2369struct alias_link * 2370LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2371 struct in_addr alias_addr) 2372{ 2373 struct alias_link *lnk; 2374 2375 LIBALIAS_LOCK(la); 2376 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, 2377 0, 0, 0, 2378 LINK_ADDR); 2379 2380 if (lnk != NULL) { 2381 lnk->flags |= LINK_PERMANENT; 2382 } 2383#ifdef LIBALIAS_DEBUG 2384 else { 2385 fprintf(stderr, "PacketAliasRedirectAddr(): " 2386 "call to AddLink() failed\n"); 2387 } 2388#endif 2389 2390 LIBALIAS_UNLOCK(la); 2391 return (lnk); 2392} 2393 2394 2395/* Mark the aliasing link dynamic */ 2396int 2397LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2398{ 2399 int res; 2400 2401 LIBALIAS_LOCK(la); 2402 (void)la; 2403 2404 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2405 res = -1; 2406 else { 2407 lnk->flags &= ~LINK_PERMANENT; 2408 res = 0; 2409 } 2410 LIBALIAS_UNLOCK(la); 2411 return (res); 2412} 2413 2414 2415void 2416LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2417{ 2418/* This is a dangerous function to put in the API, 2419 because an invalid pointer can crash the program. */ 2420 2421 LIBALIAS_LOCK(la); 2422 la->deleteAllLinks = 1; 2423 DeleteLink(lnk); 2424 la->deleteAllLinks = 0; 2425 LIBALIAS_UNLOCK(la); 2426} 2427 2428 2429void 2430LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2431{ 2432 2433 LIBALIAS_LOCK(la); 2434 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2435 && la->aliasAddress.s_addr != addr.s_addr) 2436 CleanupAliasData(la); 2437 2438 la->aliasAddress = addr; 2439 LIBALIAS_UNLOCK(la); 2440} 2441 2442 2443void 2444LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2445{ 2446 2447 LIBALIAS_LOCK(la); 2448 la->targetAddress = target_addr; 2449 LIBALIAS_UNLOCK(la); 2450} 2451 2452static void 2453finishoff(void) 2454{ 2455 2456 while (!LIST_EMPTY(&instancehead)) 2457 LibAliasUninit(LIST_FIRST(&instancehead)); 2458} 2459 2460struct libalias * 2461LibAliasInit(struct libalias *la) 2462{ 2463 int i; 2464#ifndef _KERNEL 2465 struct timeval tv; 2466 struct timezone tz; 2467#endif 2468 2469 if (la == NULL) { 2470 la = calloc(sizeof *la, 1); 2471 if (la == NULL) 2472 return (la); 2473 2474#ifndef _KERNEL /* kernel cleans up on module unload */ 2475 if (LIST_EMPTY(&instancehead)) 2476 atexit(finishoff); 2477#endif 2478 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2479 2480#ifdef _KERNEL 2481 la->timeStamp = time_uptime; 2482 la->lastCleanupTime = time_uptime; 2483#else 2484 gettimeofday(&tv, &tz); 2485 la->timeStamp = tv.tv_sec; 2486 la->lastCleanupTime = tv.tv_sec; 2487#endif 2488 2489 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2490 LIST_INIT(&la->linkTableOut[i]); 2491 for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2492 LIST_INIT(&la->linkTableIn[i]); 2493 LIBALIAS_LOCK_INIT(la); 2494 LIBALIAS_LOCK(la); 2495 } else { 2496 LIBALIAS_LOCK(la); 2497 la->deleteAllLinks = 1; 2498 CleanupAliasData(la); 2499 la->deleteAllLinks = 0; 2500 } 2501 2502 la->aliasAddress.s_addr = INADDR_ANY; 2503 la->targetAddress.s_addr = INADDR_ANY; 2504 2505 la->icmpLinkCount = 0; 2506 la->udpLinkCount = 0; 2507 la->tcpLinkCount = 0; 2508 la->pptpLinkCount = 0; 2509 la->protoLinkCount = 0; 2510 la->fragmentIdLinkCount = 0; 2511 la->fragmentPtrLinkCount = 0; 2512 la->sockCount = 0; 2513 2514 la->cleanupIndex = 0; 2515 2516 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2517#ifndef NO_USE_SOCKETS 2518 | PKT_ALIAS_USE_SOCKETS 2519#endif 2520 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2521#ifndef NO_FW_PUNCH 2522 la->fireWallFD = -1; 2523#endif 2524#ifndef _KERNEL 2525 LibAliasRefreshModules(); 2526#endif 2527 LIBALIAS_UNLOCK(la); 2528 return (la); 2529} 2530 2531void 2532LibAliasUninit(struct libalias *la) 2533{ 2534 2535 LIBALIAS_LOCK(la); 2536 la->deleteAllLinks = 1; 2537 CleanupAliasData(la); 2538 la->deleteAllLinks = 0; 2539 UninitPacketAliasLog(la); 2540#ifndef NO_FW_PUNCH 2541 UninitPunchFW(la); 2542#endif 2543 LIST_REMOVE(la, instancelist); 2544 LIBALIAS_UNLOCK(la); 2545 LIBALIAS_LOCK_DESTROY(la); 2546 free(la); 2547} 2548 2549/* Change mode for some operations */ 2550unsigned int 2551LibAliasSetMode( 2552 struct libalias *la, 2553 unsigned int flags, /* Which state to bring flags to */ 2554 unsigned int mask /* Mask of which flags to affect (use 0 to 2555 * do a probe for flag values) */ 2556) 2557{ 2558 int res = -1; 2559 2560 LIBALIAS_LOCK(la); 2561/* Enable logging? */ 2562 if (flags & mask & PKT_ALIAS_LOG) { 2563 /* Do the enable */ 2564 if (InitPacketAliasLog(la) == ENOMEM) 2565 goto getout; 2566 } else 2567/* _Disable_ logging? */ 2568 if (~flags & mask & PKT_ALIAS_LOG) { 2569 UninitPacketAliasLog(la); 2570 } 2571#ifndef NO_FW_PUNCH 2572/* Start punching holes in the firewall? */ 2573 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2574 InitPunchFW(la); 2575 } else 2576/* Stop punching holes in the firewall? */ 2577 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2578 UninitPunchFW(la); 2579 } 2580#endif 2581 2582/* Other flags can be set/cleared without special action */ 2583 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2584 res = la->packetAliasMode; 2585getout: 2586 LIBALIAS_UNLOCK(la); 2587 return (res); 2588} 2589 2590 2591int 2592LibAliasCheckNewLink(struct libalias *la) 2593{ 2594 int res; 2595 2596 LIBALIAS_LOCK(la); 2597 res = la->newDefaultLink; 2598 LIBALIAS_UNLOCK(la); 2599 return (res); 2600} 2601 2602 2603#ifndef NO_FW_PUNCH 2604 2605/***************** 2606 Code to support firewall punching. This shouldn't really be in this 2607 file, but making variables global is evil too. 2608 ****************/ 2609 2610/* Firewall include files */ 2611#include <net/if.h> 2612#include <netinet/ip_fw.h> 2613#include <string.h> 2614#include <err.h> 2615 2616/* 2617 * helper function, updates the pointer to cmd with the length 2618 * of the current command, and also cleans up the first word of 2619 * the new command in case it has been clobbered before. 2620 */ 2621static ipfw_insn * 2622next_cmd(ipfw_insn * cmd) 2623{ 2624 cmd += F_LEN(cmd); 2625 bzero(cmd, sizeof(*cmd)); 2626 return (cmd); 2627} 2628 2629/* 2630 * A function to fill simple commands of size 1. 2631 * Existing flags are preserved. 2632 */ 2633static ipfw_insn * 2634fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2635 int flags, u_int16_t arg) 2636{ 2637 cmd->opcode = opcode; 2638 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2639 cmd->arg1 = arg; 2640 return next_cmd(cmd); 2641} 2642 2643static ipfw_insn * 2644fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2645{ 2646 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 2647 2648 cmd->addr.s_addr = addr; 2649 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2650} 2651 2652static ipfw_insn * 2653fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2654{ 2655 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 2656 2657 cmd->ports[0] = cmd->ports[1] = port; 2658 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2659} 2660 2661static int 2662fill_rule(void *buf, int bufsize, int rulenum, 2663 enum ipfw_opcodes action, int proto, 2664 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2665{ 2666 struct ip_fw *rule = (struct ip_fw *)buf; 2667 ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 2668 2669 bzero(buf, bufsize); 2670 rule->rulenum = rulenum; 2671 2672 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2673 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2674 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2675 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2676 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2677 2678 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2679 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2680 2681 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2682 2683 return ((char *)cmd - (char *)buf); 2684} 2685 2686static void ClearAllFWHoles(struct libalias *la); 2687 2688 2689#define fw_setfield(la, field, num) \ 2690do { \ 2691 (field)[(num) - la->fireWallBaseNum] = 1; \ 2692} /*lint -save -e717 */ while(0)/* lint -restore */ 2693 2694#define fw_clrfield(la, field, num) \ 2695do { \ 2696 (field)[(num) - la->fireWallBaseNum] = 0; \ 2697} /*lint -save -e717 */ while(0)/* lint -restore */ 2698 2699#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2700 2701static void 2702InitPunchFW(struct libalias *la) 2703{ 2704 2705 LIBALIAS_LOCK_ASSERT(la); 2706 la->fireWallField = malloc(la->fireWallNumNums); 2707 if (la->fireWallField) { 2708 memset(la->fireWallField, 0, la->fireWallNumNums); 2709 if (la->fireWallFD < 0) { 2710 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2711 } 2712 ClearAllFWHoles(la); 2713 la->fireWallActiveNum = la->fireWallBaseNum; 2714 } 2715} 2716 2717static void 2718UninitPunchFW(struct libalias *la) 2719{ 2720 2721 LIBALIAS_LOCK_ASSERT(la); 2722 ClearAllFWHoles(la); 2723 if (la->fireWallFD >= 0) 2724 close(la->fireWallFD); 2725 la->fireWallFD = -1; 2726 if (la->fireWallField) 2727 free(la->fireWallField); 2728 la->fireWallField = NULL; 2729 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2730} 2731 2732/* Make a certain link go through the firewall */ 2733void 2734PunchFWHole(struct alias_link *lnk) 2735{ 2736 struct libalias *la; 2737 int r; /* Result code */ 2738 struct ip_fw rule; /* On-the-fly built rule */ 2739 int fwhole; /* Where to punch hole */ 2740 2741 LIBALIAS_LOCK_ASSERT(la); 2742 la = lnk->la; 2743 2744/* Don't do anything unless we are asked to */ 2745 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2746 la->fireWallFD < 0 || 2747 lnk->link_type != LINK_TCP) 2748 return; 2749 2750 memset(&rule, 0, sizeof rule); 2751 2752/** Build rule **/ 2753 2754 /* Find empty slot */ 2755 for (fwhole = la->fireWallActiveNum; 2756 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2757 fw_tstfield(la, la->fireWallField, fwhole); 2758 fwhole++); 2759 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2760 for (fwhole = la->fireWallBaseNum; 2761 fwhole < la->fireWallActiveNum && 2762 fw_tstfield(la, la->fireWallField, fwhole); 2763 fwhole++); 2764 if (fwhole == la->fireWallActiveNum) { 2765 /* No rule point empty - we can't punch more holes. */ 2766 la->fireWallActiveNum = la->fireWallBaseNum; 2767#ifdef LIBALIAS_DEBUG 2768 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2769#endif 2770 return; 2771 } 2772 } 2773 /* Start next search at next position */ 2774 la->fireWallActiveNum = fwhole + 1; 2775 2776 /* 2777 * generate two rules of the form 2778 * 2779 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2780 * accept tcp from DAddr DPort to OAddr OPort 2781 */ 2782 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2783 u_int32_t rulebuf[255]; 2784 int i; 2785 2786 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2787 O_ACCEPT, IPPROTO_TCP, 2788 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2789 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2790 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2791 if (r) 2792 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2793 2794 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2795 O_ACCEPT, IPPROTO_TCP, 2796 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2797 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2798 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2799 if (r) 2800 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2801 } 2802 2803/* Indicate hole applied */ 2804 lnk->data.tcp->fwhole = fwhole; 2805 fw_setfield(la, la->fireWallField, fwhole); 2806} 2807 2808/* Remove a hole in a firewall associated with a particular alias 2809 lnk. Calling this too often is harmless. */ 2810static void 2811ClearFWHole(struct alias_link *lnk) 2812{ 2813 struct libalias *la; 2814 2815 LIBALIAS_LOCK_ASSERT(la); 2816 la = lnk->la; 2817 if (lnk->link_type == LINK_TCP) { 2818 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall 2819 * hole? */ 2820 struct ip_fw rule; 2821 2822 if (fwhole < 0) 2823 return; 2824 2825 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2826 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2827 &fwhole, sizeof fwhole)); 2828 fw_clrfield(la, la->fireWallField, fwhole); 2829 lnk->data.tcp->fwhole = -1; 2830 } 2831} 2832 2833/* Clear out the entire range dedicated to firewall holes. */ 2834static void 2835ClearAllFWHoles(struct libalias *la) 2836{ 2837 struct ip_fw rule; /* On-the-fly built rule */ 2838 int i; 2839 2840 LIBALIAS_LOCK_ASSERT(la); 2841 if (la->fireWallFD < 0) 2842 return; 2843 2844 memset(&rule, 0, sizeof rule); 2845 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2846 int r = i; 2847 2848 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2849 } 2850 /* XXX: third arg correct here ? /phk */ 2851 memset(la->fireWallField, 0, la->fireWallNumNums); 2852} 2853 2854#endif 2855 2856void 2857LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2858{ 2859 2860 LIBALIAS_LOCK(la); 2861#ifndef NO_FW_PUNCH 2862 la->fireWallBaseNum = base; 2863 la->fireWallNumNums = num; 2864#endif 2865 LIBALIAS_UNLOCK(la); 2866} 2867 2868void 2869LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2870{ 2871 2872 LIBALIAS_LOCK(la); 2873 la->skinnyPort = port; 2874 LIBALIAS_UNLOCK(la); 2875} 2876