alias_db.c revision 150350
177701Sbrian/*- 285964Sbrian * Copyright (c) 2001 Charles Mott <cm@linktel.net> 377701Sbrian * All rights reserved. 477701Sbrian * 577701Sbrian * Redistribution and use in source and binary forms, with or without 677701Sbrian * modification, are permitted provided that the following conditions 777701Sbrian * are met: 877701Sbrian * 1. Redistributions of source code must retain the above copyright 977701Sbrian * notice, this list of conditions and the following disclaimer. 1077701Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1177701Sbrian * notice, this list of conditions and the following disclaimer in the 1277701Sbrian * documentation and/or other materials provided with the distribution. 1377701Sbrian * 1477701Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1577701Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1677701Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1777701Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1877701Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1977701Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2077701Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2177701Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2277701Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2377701Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2477701Sbrian * SUCH DAMAGE. 2577701Sbrian */ 2677701Sbrian 2784195Sdillon#include <sys/cdefs.h> 2884195Sdillon__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_db.c 150350 2005-09-19 22:31:45Z andre $"); 2984195Sdillon 3077701Sbrian/* 3126026Sbrian Alias_db.c encapsulates all data structures used for storing 3226026Sbrian packet aliasing data. Other parts of the aliasing software 3326026Sbrian access data through functions provided in this file. 3426026Sbrian 3526026Sbrian Data storage is based on the notion of a "link", which is 3626026Sbrian established for ICMP echo/reply packets, UDP datagrams and 3726026Sbrian TCP stream connections. A link stores the original source 3826026Sbrian and destination addresses. For UDP and TCP, it also stores 3926026Sbrian source and destination port numbers, as well as an alias 4026026Sbrian port number. Links are also used to store information about 4126026Sbrian fragments. 4226026Sbrian 4326026Sbrian There is a facility for sweeping through and deleting old 4426026Sbrian links as new packets are sent through. A simple timeout is 4526026Sbrian used for ICMP and UDP links. TCP links are left alone unless 4626026Sbrian there is an incomplete connection, in which case the link 4726026Sbrian can be deleted after a certain amount of time. 4826026Sbrian 4926026Sbrian 5026026Sbrian Initial version: August, 1996 (cjm) 5126026Sbrian 5226026Sbrian Version 1.4: September 16, 1996 (cjm) 53131612Sdes Facility for handling incoming links added. 5426026Sbrian 5526026Sbrian Version 1.6: September 18, 1996 (cjm) 56131612Sdes ICMP data handling simplified. 5726026Sbrian 5826026Sbrian Version 1.7: January 9, 1997 (cjm) 59131612Sdes Fragment handling simplified. 60131612Sdes Saves pointers for unresolved fragments. 61131612Sdes Permits links for unspecified remote ports 62131612Sdes or unspecified remote addresses. 63131612Sdes Fixed bug which did not properly zero port 64131612Sdes table entries after a link was deleted. 65131612Sdes Cleaned up some obsolete comments. 6626026Sbrian 6726026Sbrian Version 1.8: January 14, 1997 (cjm) 68131612Sdes Fixed data type error in StartPoint(). 69131612Sdes (This error did not exist prior to v1.7 70131612Sdes and was discovered and fixed by Ari Suutari) 7126026Sbrian 7226026Sbrian Version 1.9: February 1, 1997 73131612Sdes Optionally, connections initiated from packet aliasing host 74131612Sdes machine will will not have their port number aliased unless it 75131612Sdes conflicts with an aliasing port already being used. (cjm) 7626026Sbrian 77131612Sdes All options earlier being #ifdef'ed are now available through 78131612Sdes a new interface, SetPacketAliasMode(). This allows run time 79131612Sdes control (which is now available in PPP+pktAlias through the 80131612Sdes 'alias' keyword). (ee) 8126026Sbrian 82131612Sdes Added ability to create an alias port without 83131612Sdes either destination address or port specified. 84131612Sdes port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) 8544307Sbrian 86131612Sdes Removed K&R style function headers 87131612Sdes and general cleanup. (ee) 8826026Sbrian 89131612Sdes Added packetAliasMode to replace compiler #defines's (ee) 9044307Sbrian 91131612Sdes Allocates sockets for partially specified 92131612Sdes ports if ALIAS_USE_SOCKETS defined. (cjm) 9326026Sbrian 9426026Sbrian Version 2.0: March, 1997 95131612Sdes SetAliasAddress() will now clean up alias links 96131612Sdes if the aliasing address is changed. (cjm) 9726026Sbrian 98131612Sdes PacketAliasPermanentLink() function added to support permanent 99131612Sdes links. (J. Fortes suggested the need for this.) 100131612Sdes Examples: 10126026Sbrian 102131612Sdes (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port 10326026Sbrian 104131612Sdes (192.168.0.2, port 21) <-> alias port 3604, known dest addr 105131612Sdes unknown dest port 10626026Sbrian 107131612Sdes These permanent links allow for incoming connections to 108131612Sdes machines on the local network. They can be given with a 109131612Sdes user-chosen amount of specificity, with increasing specificity 110131612Sdes meaning more security. (cjm) 11126026Sbrian 112131612Sdes Quite a bit of rework to the basic engine. The portTable[] 113131612Sdes array, which kept track of which ports were in use was replaced 114131612Sdes by a table/linked list structure. (cjm) 11526026Sbrian 116131612Sdes SetExpire() function added. (cjm) 11726026Sbrian 118131612Sdes DeleteLink() no longer frees memory association with a pointer 119131612Sdes to a fragment (this bug was first recognized by E. Eklund in 120131612Sdes v1.9). 12126026Sbrian 12226026Sbrian Version 2.1: May, 1997 (cjm) 123131612Sdes Packet aliasing engine reworked so that it can handle 124131612Sdes multiple external addresses rather than just a single 125131612Sdes host address. 12626026Sbrian 127131612Sdes PacketAliasRedirectPort() and PacketAliasRedirectAddr() 128131612Sdes added to the API. The first function is a more generalized 129131612Sdes version of PacketAliasPermanentLink(). The second function 130131612Sdes implements static network address translation. 13132377Seivind 13263899Sarchie Version 3.2: July, 2000 (salander and satoh) 133131612Sdes Added FindNewPortGroup to get contiguous range of port values. 13463899Sarchie 135131612Sdes Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing 13663899Sarchie link but not actually add one. 13763899Sarchie 138131612Sdes Added FindRtspOut, which is closely derived from FindUdpTcpOut, 13963899Sarchie except that the alias port (from FindNewPortGroup) is provided 14063899Sarchie as input. 14163899Sarchie 14232377Seivind See HISTORY file for additional revisions. 14326026Sbrian*/ 14426026Sbrian 145145921Sglebius#ifdef _KERNEL 146145921Sglebius#include <sys/param.h> 147145921Sglebius#else 148145921Sglebius#include <sys/types.h> 149145921Sglebius#endif 15026026Sbrian 151145921Sglebius#include <sys/errno.h> 15264643Sru#include <sys/queue.h> 15326026Sbrian#include <sys/socket.h> 15426026Sbrian#include <sys/time.h> 15526026Sbrian 156145921Sglebius#ifdef _KERNEL 157145921Sglebius#include <sys/systm.h> 158145921Sglebius#include <sys/kernel.h> 159145921Sglebius#include <sys/malloc.h> 160145921Sglebius#include <sys/module.h> 161145921Sglebius#else 162145921Sglebius#include <stdlib.h> 163145921Sglebius#include <stdio.h> 164145921Sglebius#include <unistd.h> 165145921Sglebius#include <arpa/inet.h> 166145921Sglebius#endif 167145921Sglebius 16826026Sbrian/* BSD network include files */ 16926026Sbrian#include <netinet/in_systm.h> 17026026Sbrian#include <netinet/in.h> 17126026Sbrian#include <netinet/ip.h> 17226026Sbrian#include <netinet/tcp.h> 17326026Sbrian 174145921Sglebius#ifdef _KERNEL 175145921Sglebius#include <netinet/libalias/alias.h> 176145921Sglebius#include <netinet/libalias/alias_local.h> 177145921Sglebius#else 17826026Sbrian#include "alias.h" 17926026Sbrian#include "alias_local.h" 180145921Sglebius#endif 18126026Sbrian 182127094Sdesstatic LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); 18326026Sbrian 184124621Sphk 18526026Sbrian/* 18626026Sbrian Constants (note: constants are also defined 187131612Sdes near relevant functions or structs) 18826026Sbrian*/ 18926026Sbrian 19026026Sbrian/* Parameters used for cleanup of expired links */ 19144307Sbrian#define ALIAS_CLEANUP_INTERVAL_SECS 60 19226026Sbrian#define ALIAS_CLEANUP_MAX_SPOKES 30 19326026Sbrian 19451494Sru/* Timeouts (in seconds) for different link types */ 19526026Sbrian#define ICMP_EXPIRE_TIME 60 19626026Sbrian#define UDP_EXPIRE_TIME 60 19759726Sru#define PROTO_EXPIRE_TIME 60 19826026Sbrian#define FRAGMENT_ID_EXPIRE_TIME 10 19926026Sbrian#define FRAGMENT_PTR_EXPIRE_TIME 30 20026026Sbrian 20132377Seivind/* TCP link expire time for different cases */ 20232377Seivind/* When the link has been used and closed - minimal grace time to 20332377Seivind allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 20432377Seivind#ifndef TCP_EXPIRE_DEAD 205127094Sdes#define TCP_EXPIRE_DEAD 10 20632377Seivind#endif 20732377Seivind 20832377Seivind/* When the link has been used and closed on one side - the other side 20932377Seivind is allowed to still send data */ 21032377Seivind#ifndef TCP_EXPIRE_SINGLEDEAD 211127094Sdes#define TCP_EXPIRE_SINGLEDEAD 90 21232377Seivind#endif 21332377Seivind 21432377Seivind/* When the link isn't yet up */ 21532377Seivind#ifndef TCP_EXPIRE_INITIAL 216127094Sdes#define TCP_EXPIRE_INITIAL 300 21732377Seivind#endif 21832377Seivind 21932377Seivind/* When the link is up */ 22032377Seivind#ifndef TCP_EXPIRE_CONNECTED 221127094Sdes#define TCP_EXPIRE_CONNECTED 86400 22232377Seivind#endif 22332377Seivind 22432377Seivind 22526026Sbrian/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 22626026Sbrian These constants can be anything except zero, which indicates an 22744307Sbrian unknown port number. */ 22826026Sbrian 22926026Sbrian#define NO_DEST_PORT 1 23026026Sbrian#define NO_SRC_PORT 1 23126026Sbrian 23226026Sbrian 23326026Sbrian 23444307Sbrian/* Data Structures 23526026Sbrian 23626026Sbrian The fundamental data structure used in this program is 23726026Sbrian "struct alias_link". Whenever a TCP connection is made, 23826026Sbrian a UDP datagram is sent out, or an ICMP echo request is made, 23926026Sbrian a link record is made (if it has not already been created). 24026026Sbrian The link record is identified by the source address/port 24126026Sbrian and the destination address/port. In the case of an ICMP 24226026Sbrian echo request, the source port is treated as being equivalent 24359356Sru with the 16-bit ID number of the ICMP packet. 24426026Sbrian 24526026Sbrian The link record also can store some auxiliary data. For 24626026Sbrian TCP connections that have had sequence and acknowledgment 24726026Sbrian modifications, data space is available to track these changes. 24859356Sru A state field is used to keep track in changes to the TCP 24959356Sru connection state. ID numbers of fragments can also be 25026026Sbrian stored in the auxiliary space. Pointers to unresolved 25159356Sru fragments can also be stored. 25226026Sbrian 25326026Sbrian The link records support two independent chainings. Lookup 25426026Sbrian tables for input and out tables hold the initial pointers 25526026Sbrian the link chains. On input, the lookup table indexes on alias 25626026Sbrian port and link type. On output, the lookup table indexes on 25759356Sru source address, destination address, source port, destination 25826026Sbrian port and link type. 25926026Sbrian*/ 26026026Sbrian 261127094Sdesstruct ack_data_record { /* used to save changes to ACK/sequence 262127094Sdes * numbers */ 263127094Sdes u_long ack_old; 264127094Sdes u_long ack_new; 265127094Sdes int delta; 266127094Sdes int active; 26726026Sbrian}; 26826026Sbrian 269127094Sdesstruct tcp_state { /* Information about TCP connection */ 270127094Sdes int in; /* State for outside -> inside */ 271127094Sdes int out; /* State for inside -> outside */ 272127094Sdes int index; /* Index to ACK data array */ 273127094Sdes int ack_modified; /* Indicates whether ACK and 274127094Sdes * sequence numbers */ 275127094Sdes /* been modified */ 27626026Sbrian}; 27726026Sbrian 278127094Sdes#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 279127094Sdes * saved for a modified TCP stream */ 280127094Sdesstruct tcp_dat { 281127094Sdes struct tcp_state state; 282127094Sdes struct ack_data_record ack[N_LINK_TCP_DATA]; 283127094Sdes int fwhole; /* Which firewall record is used for this 284127094Sdes * hole? */ 28526026Sbrian}; 28626026Sbrian 287127094Sdesstruct server { /* LSNAT server pool (circular list) */ 288127094Sdes struct in_addr addr; 289127094Sdes u_short port; 290127094Sdes struct server *next; 29159702Sru}; 29259702Sru 293127094Sdesstruct alias_link { /* Main data structure */ 294127094Sdes struct libalias *la; 295127094Sdes struct in_addr src_addr; /* Address and port information */ 296127094Sdes struct in_addr dst_addr; 297127094Sdes struct in_addr alias_addr; 298127094Sdes struct in_addr proxy_addr; 299127094Sdes u_short src_port; 300127094Sdes u_short dst_port; 301127094Sdes u_short alias_port; 302127094Sdes u_short proxy_port; 303127094Sdes struct server *server; 30426026Sbrian 305127094Sdes int link_type; /* Type of link: TCP, UDP, ICMP, 306127094Sdes * proto, frag */ 30726026Sbrian 30826026Sbrian/* values for link_type */ 30959726Sru#define LINK_ICMP IPPROTO_ICMP 31059726Sru#define LINK_UDP IPPROTO_UDP 31159726Sru#define LINK_TCP IPPROTO_TCP 31259726Sru#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 31359726Sru#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 31459726Sru#define LINK_ADDR (IPPROTO_MAX + 3) 31561861Sru#define LINK_PPTP (IPPROTO_MAX + 4) 31626026Sbrian 317127094Sdes int flags; /* indicates special characteristics */ 318127094Sdes int pflags; /* protocol-specific flags */ 31926026Sbrian 32026026Sbrian/* flag bits */ 32126026Sbrian#define LINK_UNKNOWN_DEST_PORT 0x01 32226026Sbrian#define LINK_UNKNOWN_DEST_ADDR 0x02 32326026Sbrian#define LINK_PERMANENT 0x04 324127094Sdes#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 32532377Seivind#define LINK_UNFIREWALLED 0x08 32626026Sbrian 327127094Sdes int timestamp; /* Time link was last accessed */ 328127094Sdes int expire_time; /* Expire time for link */ 329145926Sglebius#ifndef NO_USE_SOCKETS 330127094Sdes int sockfd; /* socket descriptor */ 331145926Sglebius#endif 332127094Sdes LIST_ENTRY (alias_link) list_out; /* Linked list of 333127094Sdes * pointers for */ 334127094Sdes LIST_ENTRY (alias_link) list_in; /* input and output 335127094Sdes * lookup tables */ 33626026Sbrian 337127094Sdes union { /* Auxiliary data */ 338127094Sdes char *frag_ptr; 339127094Sdes struct in_addr frag_addr; 340127094Sdes struct tcp_dat *tcp; 341127094Sdes } data; 34226026Sbrian}; 34326026Sbrian 344145927Sglebius/* Clean up procedure. */ 345145927Sglebiusstatic void finishoff(void); 346145927Sglebius 347145927Sglebius/* Kernel module definition. */ 348145927Sglebius#ifdef _KERNEL 349145927SglebiusMALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing"); 350145927Sglebius 351145927SglebiusMODULE_VERSION(libalias, 1); 352145927Sglebius 353145927Sglebiusstatic int 354145927Sglebiusalias_mod_handler(module_t mod, int type, void *data) 355145927Sglebius{ 356145927Sglebius int error; 357145927Sglebius 358145927Sglebius switch (type) { 359145927Sglebius case MOD_LOAD: 360145927Sglebius error = 0; 361145927Sglebius break; 362145927Sglebius case MOD_QUIESCE: 363145927Sglebius case MOD_UNLOAD: 364145927Sglebius finishoff(); 365145927Sglebius error = 0; 366145927Sglebius break; 367145927Sglebius default: 368145927Sglebius error = EINVAL; 369145927Sglebius } 370145927Sglebius 371145927Sglebius return (error); 372145927Sglebius} 373145927Sglebius 374145927Sglebiusstatic moduledata_t alias_mod = { 375145927Sglebius "alias", alias_mod_handler, NULL 376145927Sglebius}; 377145927Sglebius 378145927SglebiusDECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); 379145927Sglebius#endif 380145927Sglebius 38126026Sbrian/* Internal utility routines (used only in alias_db.c) 38226026Sbrian 38326026SbrianLookup table starting points: 38426026Sbrian StartPointIn() -- link table initial search point for 385131612Sdes incoming packets 38659356Sru StartPointOut() -- link table initial search point for 387131612Sdes outgoing packets 38899207Sbrian 38926026SbrianMiscellaneous: 39026026Sbrian SeqDiff() -- difference between two TCP sequences 39126026Sbrian ShowAliasStats() -- send alias statistics to a monitor file 39226026Sbrian*/ 39326026Sbrian 39426026Sbrian 39526026Sbrian/* Local prototypes */ 396127094Sdesstatic u_int StartPointIn(struct in_addr, u_short, int); 39726026Sbrian 398127094Sdesstatic u_int 399127094SdesStartPointOut(struct in_addr, struct in_addr, 400127094Sdes u_short, u_short, int); 40126026Sbrian 402127094Sdesstatic int SeqDiff(u_long, u_long); 40326026Sbrian 40435314Sbrian#ifndef NO_FW_PUNCH 40532377Seivind/* Firewall control */ 406131614Sdesstatic void InitPunchFW(struct libalias *); 407131614Sdesstatic void UninitPunchFW(struct libalias *); 408131614Sdesstatic void ClearFWHole(struct alias_link *); 409127094Sdes 41035314Sbrian#endif 41126026Sbrian 412145925Sglebius#ifndef NO_LOGGING 41332377Seivind/* Log file control */ 414145925Sglebiusstatic void ShowAliasStats(struct libalias *); 415131614Sdesstatic void InitPacketAliasLog(struct libalias *); 416131614Sdesstatic void UninitPacketAliasLog(struct libalias *); 417145925Sglebius#endif 41832377Seivind 419127094Sdesstatic u_int 42026026SbrianStartPointIn(struct in_addr alias_addr, 421127094Sdes u_short alias_port, 422127094Sdes int link_type) 42326026Sbrian{ 424127094Sdes u_int n; 42526026Sbrian 426127094Sdes n = alias_addr.s_addr; 427127094Sdes if (link_type != LINK_PPTP) 428127094Sdes n += alias_port; 429127094Sdes n += link_type; 430127094Sdes return (n % LINK_TABLE_IN_SIZE); 43126026Sbrian} 43226026Sbrian 43326026Sbrian 434127094Sdesstatic u_int 43526026SbrianStartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 436127094Sdes u_short src_port, u_short dst_port, int link_type) 43726026Sbrian{ 438127094Sdes u_int n; 43926026Sbrian 440127094Sdes n = src_addr.s_addr; 441127094Sdes n += dst_addr.s_addr; 442127094Sdes if (link_type != LINK_PPTP) { 443127094Sdes n += src_port; 444127094Sdes n += dst_port; 445127094Sdes } 446127094Sdes n += link_type; 44726026Sbrian 448127094Sdes return (n % LINK_TABLE_OUT_SIZE); 44926026Sbrian} 45026026Sbrian 45126026Sbrian 45226026Sbrianstatic int 45326026SbrianSeqDiff(u_long x, u_long y) 45426026Sbrian{ 45526026Sbrian/* Return the difference between two TCP sequence numbers */ 45626026Sbrian 45726026Sbrian/* 45826026Sbrian This function is encapsulated in case there are any unusual 45926026Sbrian arithmetic conditions that need to be considered. 46026026Sbrian*/ 46126026Sbrian 462127094Sdes return (ntohl(y) - ntohl(x)); 46326026Sbrian} 46426026Sbrian 46526026Sbrian 466145925Sglebius#ifndef NO_LOGGING 46726026Sbrianstatic void 468124621SphkShowAliasStats(struct libalias *la) 46926026Sbrian{ 47026026Sbrian/* Used for debugging */ 47126026Sbrian 472127094Sdes if (la->monitorFile) { 473127094Sdes fprintf(la->monitorFile, 474127094Sdes "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", 475127094Sdes la->icmpLinkCount, 476127094Sdes la->udpLinkCount, 477127094Sdes la->tcpLinkCount, 478127094Sdes la->pptpLinkCount, 479127094Sdes la->protoLinkCount, 480127094Sdes la->fragmentIdLinkCount, 481127094Sdes la->fragmentPtrLinkCount); 48226026Sbrian 483127094Sdes fprintf(la->monitorFile, " / tot=%d (sock=%d)\n", 484127094Sdes la->icmpLinkCount + la->udpLinkCount 485127094Sdes + la->tcpLinkCount 486127094Sdes + la->pptpLinkCount 487127094Sdes + la->protoLinkCount 488127094Sdes + la->fragmentIdLinkCount 489127094Sdes + la->fragmentPtrLinkCount, 490127094Sdes la->sockCount); 49126026Sbrian 492127094Sdes fflush(la->monitorFile); 493127094Sdes } 49426026Sbrian} 495145925Sglebius#endif 49626026Sbrian 49726026Sbrian/* Internal routines for finding, deleting and adding links 49826026Sbrian 49926026SbrianPort Allocation: 50026026Sbrian GetNewPort() -- find and reserve new alias port number 50126026Sbrian GetSocket() -- try to allocate a socket for a given port 50226026Sbrian 50326026SbrianLink creation and deletion: 50426026Sbrian CleanupAliasData() - remove all link chains from lookup table 50526026Sbrian IncrementalCleanup() - look for stale links in a single chain 50626026Sbrian DeleteLink() - remove link 50799207Sbrian AddLink() - add link 50899207Sbrian ReLink() - change link 50926026Sbrian 51026026SbrianLink search: 51126026Sbrian FindLinkOut() - find link for outgoing packets 51226026Sbrian FindLinkIn() - find link for incoming packets 51363899Sarchie 51463899SarchiePort search: 51599207Sbrian FindNewPortGroup() - find an available group of ports 51626026Sbrian*/ 51726026Sbrian 51826026Sbrian/* Local prototypes */ 519127094Sdesstatic int GetNewPort(struct libalias *, struct alias_link *, int); 520145926Sglebius#ifndef NO_USE_SOCKETS 521127094Sdesstatic u_short GetSocket(struct libalias *, u_short, int *, int); 522145926Sglebius#endif 523127094Sdesstatic void CleanupAliasData(struct libalias *); 52426026Sbrian 525127094Sdesstatic void IncrementalCleanup(struct libalias *); 52626026Sbrian 527127094Sdesstatic void DeleteLink(struct alias_link *); 52826026Sbrian 52926026Sbrianstatic struct alias_link * 530124621SphkAddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr, 531127094Sdes u_short, u_short, int, int); 53226026Sbrian 53326026Sbrianstatic struct alias_link * 53432377SeivindReLink(struct alias_link *, 535127094Sdes struct in_addr, struct in_addr, struct in_addr, 536127094Sdes u_short, u_short, int, int); 53732377Seivind 53832377Seivindstatic struct alias_link * 539127094Sdes FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 54026026Sbrian 54126026Sbrianstatic struct alias_link * 542127094Sdes FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 54326026Sbrian 54426026Sbrian 54526026Sbrian#define ALIAS_PORT_BASE 0x08000 54626026Sbrian#define ALIAS_PORT_MASK 0x07fff 54763899Sarchie#define ALIAS_PORT_MASK_EVEN 0x07ffe 54826026Sbrian#define GET_NEW_PORT_MAX_ATTEMPTS 20 54926026Sbrian 55026026Sbrian#define GET_ALIAS_PORT -1 55126026Sbrian#define GET_ALIAS_ID GET_ALIAS_PORT 55226026Sbrian 55363899Sarchie#define FIND_EVEN_ALIAS_BASE 1 55463899Sarchie 55526026Sbrian/* GetNewPort() allocates port numbers. Note that if a port number 55626026Sbrian is already in use, that does not mean that it cannot be used by 55726026Sbrian another link concurrently. This is because GetNewPort() looks for 55826026Sbrian unused triplets: (dest addr, dest port, alias port). */ 55926026Sbrian 56026026Sbrianstatic int 561131614SdesGetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) 56226026Sbrian{ 563127094Sdes int i; 564127094Sdes int max_trials; 565127094Sdes u_short port_sys; 566127094Sdes u_short port_net; 56726026Sbrian 56826026Sbrian/* 56926026Sbrian Description of alias_port_param for GetNewPort(). When 57026026Sbrian this parameter is zero or positive, it precisely specifies 57126026Sbrian the port number. GetNewPort() will return this number 57226026Sbrian without check that it is in use. 57326026Sbrian 57461861Sru When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 57526026Sbrian selected port number. 57626026Sbrian*/ 57799207Sbrian 578127094Sdes if (alias_port_param == GET_ALIAS_PORT) { 579127094Sdes /* 580127094Sdes * The aliasing port is automatically selected by one of 581127094Sdes * two methods below: 582127094Sdes */ 583127094Sdes max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 58426026Sbrian 585127094Sdes if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 586127094Sdes /* 587127094Sdes * When the PKT_ALIAS_SAME_PORTS option is chosen, 588127094Sdes * the first try will be the actual source port. If 589127094Sdes * this is already in use, the remainder of the 590127094Sdes * trials will be random. 591127094Sdes */ 592131614Sdes port_net = lnk->src_port; 593127094Sdes port_sys = ntohs(port_net); 594127094Sdes } else { 595127094Sdes /* First trial and all subsequent are random. */ 596127094Sdes port_sys = random() & ALIAS_PORT_MASK; 597127094Sdes port_sys += ALIAS_PORT_BASE; 598127094Sdes port_net = htons(port_sys); 599127094Sdes } 600127094Sdes } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { 601131614Sdes lnk->alias_port = (u_short) alias_port_param; 602127094Sdes return (0); 603127094Sdes } else { 604145961Sglebius#ifdef LIBALIAS_DEBUG 605127094Sdes fprintf(stderr, "PacketAlias/GetNewPort(): "); 606127094Sdes fprintf(stderr, "input parameter error\n"); 60744616Sbrian#endif 608127094Sdes return (-1); 609127094Sdes } 61026026Sbrian 61126026Sbrian 61226026Sbrian/* Port number search */ 613127094Sdes for (i = 0; i < max_trials; i++) { 614127094Sdes int go_ahead; 615127094Sdes struct alias_link *search_result; 61626026Sbrian 617131614Sdes search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr, 618131614Sdes lnk->dst_port, port_net, 619131614Sdes lnk->link_type, 0); 62026026Sbrian 621127094Sdes if (search_result == NULL) 622127094Sdes go_ahead = 1; 623131614Sdes else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED) 624127094Sdes && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 625127094Sdes go_ahead = 1; 626127094Sdes else 627127094Sdes go_ahead = 0; 62826026Sbrian 629127094Sdes if (go_ahead) { 630145926Sglebius#ifndef NO_USE_SOCKETS 631127094Sdes if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) 632131614Sdes && (lnk->flags & LINK_PARTIALLY_SPECIFIED) 633131614Sdes && ((lnk->link_type == LINK_TCP) || 634131614Sdes (lnk->link_type == LINK_UDP))) { 635131614Sdes if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) { 636131614Sdes lnk->alias_port = port_net; 637127094Sdes return (0); 638127094Sdes } 639127094Sdes } else { 640145926Sglebius#endif 641131614Sdes lnk->alias_port = port_net; 642127094Sdes return (0); 643145926Sglebius#ifndef NO_USE_SOCKETS 644127094Sdes } 645145926Sglebius#endif 646127094Sdes } 647127094Sdes port_sys = random() & ALIAS_PORT_MASK; 648127094Sdes port_sys += ALIAS_PORT_BASE; 649127094Sdes port_net = htons(port_sys); 650127094Sdes } 65126026Sbrian 652145961Sglebius#ifdef LIBALIAS_DEBUG 653127094Sdes fprintf(stderr, "PacketAlias/GetnewPort(): "); 654127094Sdes fprintf(stderr, "could not find free port\n"); 65544616Sbrian#endif 65626026Sbrian 657127094Sdes return (-1); 65826026Sbrian} 65926026Sbrian 660145926Sglebius#ifndef NO_USE_SOCKETS 661127094Sdesstatic u_short 662124621SphkGetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type) 66326026Sbrian{ 664127094Sdes int err; 665127094Sdes int sock; 666127094Sdes struct sockaddr_in sock_addr; 66726026Sbrian 668127094Sdes if (link_type == LINK_TCP) 669127094Sdes sock = socket(AF_INET, SOCK_STREAM, 0); 670127094Sdes else if (link_type == LINK_UDP) 671127094Sdes sock = socket(AF_INET, SOCK_DGRAM, 0); 672127094Sdes else { 673145961Sglebius#ifdef LIBALIAS_DEBUG 674127094Sdes fprintf(stderr, "PacketAlias/GetSocket(): "); 675127094Sdes fprintf(stderr, "incorrect link type\n"); 67644616Sbrian#endif 677127094Sdes return (0); 678127094Sdes } 67926026Sbrian 680127094Sdes if (sock < 0) { 681145961Sglebius#ifdef LIBALIAS_DEBUG 682127094Sdes fprintf(stderr, "PacketAlias/GetSocket(): "); 683127094Sdes fprintf(stderr, "socket() error %d\n", *sockfd); 68444616Sbrian#endif 685127094Sdes return (0); 686127094Sdes } 687127094Sdes sock_addr.sin_family = AF_INET; 688127094Sdes sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 689127094Sdes sock_addr.sin_port = port_net; 69026026Sbrian 691127094Sdes err = bind(sock, 692127094Sdes (struct sockaddr *)&sock_addr, 693127094Sdes sizeof(sock_addr)); 694127094Sdes if (err == 0) { 695127094Sdes la->sockCount++; 696127094Sdes *sockfd = sock; 697127094Sdes return (1); 698127094Sdes } else { 699127094Sdes close(sock); 700127094Sdes return (0); 701127094Sdes } 70226026Sbrian} 703145926Sglebius#endif 70426026Sbrian 70599207Sbrian/* FindNewPortGroup() returns a base port number for an available 70663899Sarchie range of contiguous port numbers. Note that if a port number 70763899Sarchie is already in use, that does not mean that it cannot be used by 70863899Sarchie another link concurrently. This is because FindNewPortGroup() 70963899Sarchie looks for unused triplets: (dest addr, dest port, alias port). */ 71063899Sarchie 71163899Sarchieint 712124621SphkFindNewPortGroup(struct libalias *la, 713127094Sdes struct in_addr dst_addr, 714127094Sdes struct in_addr alias_addr, 715127094Sdes u_short src_port, 716127094Sdes u_short dst_port, 717127094Sdes u_short port_count, 718127094Sdes u_char proto, 719127094Sdes u_char align) 72063899Sarchie{ 721127094Sdes int i, j; 722127094Sdes int max_trials; 723127094Sdes u_short port_sys; 724127094Sdes int link_type; 72563899Sarchie 726127094Sdes /* 727127094Sdes * Get link_type from protocol 728127094Sdes */ 72963899Sarchie 730127094Sdes switch (proto) { 731127094Sdes case IPPROTO_UDP: 732127094Sdes link_type = LINK_UDP; 733127094Sdes break; 734127094Sdes case IPPROTO_TCP: 735127094Sdes link_type = LINK_TCP; 736127094Sdes break; 737127094Sdes default: 738127094Sdes return (0); 739127094Sdes break; 740127094Sdes } 74163899Sarchie 742127094Sdes /* 743127094Sdes * The aliasing port is automatically selected by one of two 744127094Sdes * methods below: 745127094Sdes */ 746127094Sdes max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 74763899Sarchie 748127094Sdes if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 749127094Sdes /* 750127094Sdes * When the ALIAS_SAME_PORTS option is chosen, the first 751127094Sdes * try will be the actual source port. If this is already 752127094Sdes * in use, the remainder of the trials will be random. 753127094Sdes */ 754127094Sdes port_sys = ntohs(src_port); 75563899Sarchie 756127094Sdes } else { 75763899Sarchie 758127094Sdes /* First trial and all subsequent are random. */ 759127094Sdes if (align == FIND_EVEN_ALIAS_BASE) 760127094Sdes port_sys = random() & ALIAS_PORT_MASK_EVEN; 761127094Sdes else 762127094Sdes port_sys = random() & ALIAS_PORT_MASK; 76363899Sarchie 764127094Sdes port_sys += ALIAS_PORT_BASE; 765127094Sdes } 76663899Sarchie 76763899Sarchie/* Port number search */ 768127094Sdes for (i = 0; i < max_trials; i++) { 76963899Sarchie 770127094Sdes struct alias_link *search_result; 77163899Sarchie 772127094Sdes for (j = 0; j < port_count; j++) 773127094Sdes if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr, 774127094Sdes dst_port, htons(port_sys + j), 775127094Sdes link_type, 0))) 776127094Sdes break; 77763899Sarchie 778127094Sdes /* Found a good range, return base */ 779127094Sdes if (j == port_count) 780127094Sdes return (htons(port_sys)); 78163899Sarchie 782127094Sdes /* Find a new base to try */ 783127094Sdes if (align == FIND_EVEN_ALIAS_BASE) 784127094Sdes port_sys = random() & ALIAS_PORT_MASK_EVEN; 785127094Sdes else 786127094Sdes port_sys = random() & ALIAS_PORT_MASK; 78763899Sarchie 788127094Sdes port_sys += ALIAS_PORT_BASE; 789127094Sdes } 79063899Sarchie 791145961Sglebius#ifdef LIBALIAS_DEBUG 792127094Sdes fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 793127094Sdes fprintf(stderr, "could not find free port(s)\n"); 79463899Sarchie#endif 79563899Sarchie 796127094Sdes return (0); 79763899Sarchie} 79863899Sarchie 79926026Sbrianstatic void 800124621SphkCleanupAliasData(struct libalias *la) 80126026Sbrian{ 802131614Sdes struct alias_link *lnk; 803127094Sdes int i, icount; 80426026Sbrian 805127094Sdes icount = 0; 806127094Sdes for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 807131614Sdes lnk = LIST_FIRST(&la->linkTableOut[i]); 808131614Sdes while (lnk != NULL) { 809127094Sdes struct alias_link *link_next; 81026026Sbrian 811131614Sdes link_next = LIST_NEXT(lnk, list_out); 812127094Sdes icount++; 813131614Sdes DeleteLink(lnk); 814131614Sdes lnk = link_next; 815127094Sdes } 816127094Sdes } 817127094Sdes 818127094Sdes la->cleanupIndex = 0; 81926026Sbrian} 82026026Sbrian 82126026Sbrian 82226026Sbrianstatic void 823124621SphkIncrementalCleanup(struct libalias *la) 82426026Sbrian{ 825127094Sdes int icount; 826131614Sdes struct alias_link *lnk; 82726026Sbrian 828127094Sdes icount = 0; 829131614Sdes lnk = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]); 830131614Sdes while (lnk != NULL) { 831127094Sdes int idelta; 832127094Sdes struct alias_link *link_next; 83326026Sbrian 834131614Sdes link_next = LIST_NEXT(lnk, list_out); 835131614Sdes idelta = la->timeStamp - lnk->timestamp; 836131614Sdes switch (lnk->link_type) { 837127094Sdes case LINK_TCP: 838131614Sdes if (idelta > lnk->expire_time) { 839127094Sdes struct tcp_dat *tcp_aux; 84026026Sbrian 841131614Sdes tcp_aux = lnk->data.tcp; 842127094Sdes if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 843127094Sdes || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) { 844131614Sdes DeleteLink(lnk); 845127094Sdes icount++; 846127094Sdes } 847127094Sdes } 848127094Sdes break; 849127094Sdes default: 850131614Sdes if (idelta > lnk->expire_time) { 851131614Sdes DeleteLink(lnk); 852127094Sdes icount++; 853127094Sdes } 854127094Sdes break; 855127094Sdes } 856131614Sdes lnk = link_next; 857127094Sdes } 85826026Sbrian 859127094Sdes if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) 860127094Sdes la->cleanupIndex = 0; 86126026Sbrian} 86226026Sbrian 86364643Srustatic void 864131614SdesDeleteLink(struct alias_link *lnk) 86526026Sbrian{ 866131614Sdes struct libalias *la = lnk->la; 86726026Sbrian 86826026Sbrian/* Don't do anything if the link is marked permanent */ 869131614Sdes if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT) 870127094Sdes return; 87126026Sbrian 87235314Sbrian#ifndef NO_FW_PUNCH 87359356Sru/* Delete associated firewall hole, if any */ 874131614Sdes ClearFWHole(lnk); 87535314Sbrian#endif 87632377Seivind 87759702Sru/* Free memory allocated for LSNAT server pool */ 878131614Sdes if (lnk->server != NULL) { 879127094Sdes struct server *head, *curr, *next; 88059702Sru 881131614Sdes head = curr = lnk->server; 882127094Sdes do { 883127094Sdes next = curr->next; 884127094Sdes free(curr); 885127094Sdes } while ((curr = next) != head); 886127094Sdes } 88726026Sbrian/* Adjust output table pointers */ 888131614Sdes LIST_REMOVE(lnk, list_out); 88926026Sbrian 89026026Sbrian/* Adjust input table pointers */ 891131614Sdes LIST_REMOVE(lnk, list_in); 892145926Sglebius#ifndef NO_USE_SOCKETS 89326026Sbrian/* Close socket, if one has been allocated */ 894131614Sdes if (lnk->sockfd != -1) { 895127094Sdes la->sockCount--; 896131614Sdes close(lnk->sockfd); 897127094Sdes } 898145926Sglebius#endif 89926026Sbrian/* Link-type dependent cleanup */ 900131614Sdes switch (lnk->link_type) { 901127094Sdes case LINK_ICMP: 902127094Sdes la->icmpLinkCount--; 903127094Sdes break; 904127094Sdes case LINK_UDP: 905127094Sdes la->udpLinkCount--; 906127094Sdes break; 907127094Sdes case LINK_TCP: 908127094Sdes la->tcpLinkCount--; 909131614Sdes free(lnk->data.tcp); 910127094Sdes break; 911127094Sdes case LINK_PPTP: 912127094Sdes la->pptpLinkCount--; 913127094Sdes break; 914127094Sdes case LINK_FRAGMENT_ID: 915127094Sdes la->fragmentIdLinkCount--; 916127094Sdes break; 917127094Sdes case LINK_FRAGMENT_PTR: 918127094Sdes la->fragmentPtrLinkCount--; 919131614Sdes if (lnk->data.frag_ptr != NULL) 920131614Sdes free(lnk->data.frag_ptr); 921127094Sdes break; 92259726Sru case LINK_ADDR: 923127094Sdes break; 924127094Sdes default: 925127094Sdes la->protoLinkCount--; 926127094Sdes break; 927127094Sdes } 92826026Sbrian 92926026Sbrian/* Free memory */ 930131614Sdes free(lnk); 93126026Sbrian 932145925Sglebius#ifndef NO_LOGGING 93326026Sbrian/* Write statistics, if logging enabled */ 934127094Sdes if (la->packetAliasMode & PKT_ALIAS_LOG) { 935127094Sdes ShowAliasStats(la); 936127094Sdes } 937145925Sglebius#endif 93826026Sbrian} 93926026Sbrian 94026026Sbrian 94126026Sbrianstatic struct alias_link * 942127094SdesAddLink(struct libalias *la, struct in_addr src_addr, 943127094Sdes struct in_addr dst_addr, 944127094Sdes struct in_addr alias_addr, 945127094Sdes u_short src_port, 946127094Sdes u_short dst_port, 947127094Sdes int alias_port_param, /* if less than zero, alias */ 948127094Sdes int link_type) 949127094Sdes{ /* port will be automatically *//* chosen. 950127094Sdes * If greater than */ 951127094Sdes u_int start_point; /* zero, equal to alias port */ 952131614Sdes struct alias_link *lnk; 95326026Sbrian 954131614Sdes lnk = malloc(sizeof(struct alias_link)); 955131614Sdes if (lnk != NULL) { 956127094Sdes /* Basic initialization */ 957131614Sdes lnk->la = la; 958131614Sdes lnk->src_addr = src_addr; 959131614Sdes lnk->dst_addr = dst_addr; 960131614Sdes lnk->alias_addr = alias_addr; 961131614Sdes lnk->proxy_addr.s_addr = INADDR_ANY; 962131614Sdes lnk->src_port = src_port; 963131614Sdes lnk->dst_port = dst_port; 964131614Sdes lnk->proxy_port = 0; 965131614Sdes lnk->server = NULL; 966131614Sdes lnk->link_type = link_type; 967145926Sglebius#ifndef NO_USE_SOCKETS 968131614Sdes lnk->sockfd = -1; 969145926Sglebius#endif 970131614Sdes lnk->flags = 0; 971131614Sdes lnk->pflags = 0; 972131614Sdes lnk->timestamp = la->timeStamp; 97326026Sbrian 974127094Sdes /* Expiration time */ 975127094Sdes switch (link_type) { 976127094Sdes case LINK_ICMP: 977131614Sdes lnk->expire_time = ICMP_EXPIRE_TIME; 978127094Sdes break; 979127094Sdes case LINK_UDP: 980131614Sdes lnk->expire_time = UDP_EXPIRE_TIME; 981127094Sdes break; 982127094Sdes case LINK_TCP: 983131614Sdes lnk->expire_time = TCP_EXPIRE_INITIAL; 984127094Sdes break; 985127094Sdes case LINK_PPTP: 986131614Sdes lnk->flags |= LINK_PERMANENT; /* no timeout. */ 987127094Sdes break; 988127094Sdes case LINK_FRAGMENT_ID: 989131614Sdes lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; 990127094Sdes break; 991127094Sdes case LINK_FRAGMENT_PTR: 992131614Sdes lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 993127094Sdes break; 994127094Sdes case LINK_ADDR: 995127094Sdes break; 996127094Sdes default: 997131614Sdes lnk->expire_time = PROTO_EXPIRE_TIME; 998127094Sdes break; 999127094Sdes } 100026026Sbrian 1001127094Sdes /* Determine alias flags */ 1002127094Sdes if (dst_addr.s_addr == INADDR_ANY) 1003131614Sdes lnk->flags |= LINK_UNKNOWN_DEST_ADDR; 1004127094Sdes if (dst_port == 0) 1005131614Sdes lnk->flags |= LINK_UNKNOWN_DEST_PORT; 100626026Sbrian 1007127094Sdes /* Determine alias port */ 1008131614Sdes if (GetNewPort(la, lnk, alias_port_param) != 0) { 1009131614Sdes free(lnk); 1010127094Sdes return (NULL); 1011127094Sdes } 1012127094Sdes /* Link-type dependent initialization */ 1013127094Sdes switch (link_type) { 1014127094Sdes struct tcp_dat *aux_tcp; 101526026Sbrian 1016127094Sdes case LINK_ICMP: 1017127094Sdes la->icmpLinkCount++; 1018127094Sdes break; 1019127094Sdes case LINK_UDP: 1020127094Sdes la->udpLinkCount++; 1021127094Sdes break; 1022127094Sdes case LINK_TCP: 1023127094Sdes aux_tcp = malloc(sizeof(struct tcp_dat)); 1024127094Sdes if (aux_tcp != NULL) { 1025127094Sdes int i; 102626026Sbrian 1027127094Sdes la->tcpLinkCount++; 1028127094Sdes aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 1029127094Sdes aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1030127094Sdes aux_tcp->state.index = 0; 1031127094Sdes aux_tcp->state.ack_modified = 0; 1032127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) 1033127094Sdes aux_tcp->ack[i].active = 0; 1034127094Sdes aux_tcp->fwhole = -1; 1035131614Sdes lnk->data.tcp = aux_tcp; 1036127094Sdes } else { 1037145961Sglebius#ifdef LIBALIAS_DEBUG 1038127094Sdes fprintf(stderr, "PacketAlias/AddLink: "); 1039127094Sdes fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 104044616Sbrian#endif 1041131614Sdes free(lnk); 1042127094Sdes return (NULL); 1043127094Sdes } 1044127094Sdes break; 1045127094Sdes case LINK_PPTP: 1046127094Sdes la->pptpLinkCount++; 1047127094Sdes break; 1048127094Sdes case LINK_FRAGMENT_ID: 1049127094Sdes la->fragmentIdLinkCount++; 1050127094Sdes break; 1051127094Sdes case LINK_FRAGMENT_PTR: 1052127094Sdes la->fragmentPtrLinkCount++; 1053127094Sdes break; 1054127094Sdes case LINK_ADDR: 1055127094Sdes break; 1056127094Sdes default: 1057127094Sdes la->protoLinkCount++; 1058127094Sdes break; 1059127094Sdes } 106067316Sru 1061127094Sdes /* Set up pointers for output lookup table */ 1062127094Sdes start_point = StartPointOut(src_addr, dst_addr, 1063127094Sdes src_port, dst_port, link_type); 1064131614Sdes LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); 106567316Sru 1066127094Sdes /* Set up pointers for input lookup table */ 1067131614Sdes start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); 1068131614Sdes LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); 1069127094Sdes } else { 1070145961Sglebius#ifdef LIBALIAS_DEBUG 1071127094Sdes fprintf(stderr, "PacketAlias/AddLink(): "); 1072127094Sdes fprintf(stderr, "malloc() call failed.\n"); 107344616Sbrian#endif 1074127094Sdes } 1075145925Sglebius#ifndef NO_LOGGING 1076127094Sdes if (la->packetAliasMode & PKT_ALIAS_LOG) { 1077127094Sdes ShowAliasStats(la); 1078127094Sdes } 1079145925Sglebius#endif 1080131614Sdes return (lnk); 108126026Sbrian} 108226026Sbrian 108332377Seivindstatic struct alias_link * 1084131614SdesReLink(struct alias_link *old_lnk, 1085127094Sdes struct in_addr src_addr, 1086127094Sdes struct in_addr dst_addr, 1087127094Sdes struct in_addr alias_addr, 1088127094Sdes u_short src_port, 1089127094Sdes u_short dst_port, 1090127094Sdes int alias_port_param, /* if less than zero, alias */ 1091127094Sdes int link_type) 1092127094Sdes{ /* port will be automatically *//* chosen. 1093127094Sdes * If greater than */ 1094131614Sdes struct alias_link *new_lnk; /* zero, equal to alias port */ 1095131614Sdes struct libalias *la = old_lnk->la; 109626026Sbrian 1097131614Sdes new_lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1098127094Sdes src_port, dst_port, alias_port_param, 1099127094Sdes link_type); 110035314Sbrian#ifndef NO_FW_PUNCH 1101131614Sdes if (new_lnk != NULL && 1102131614Sdes old_lnk->link_type == LINK_TCP && 1103131614Sdes old_lnk->data.tcp->fwhole > 0) { 1104131614Sdes PunchFWHole(new_lnk); 1105127094Sdes } 110635314Sbrian#endif 1107131614Sdes DeleteLink(old_lnk); 1108131614Sdes return (new_lnk); 110932377Seivind} 111032377Seivind 111126026Sbrianstatic struct alias_link * 1112124621Sphk_FindLinkOut(struct libalias *la, struct in_addr src_addr, 1113127094Sdes struct in_addr dst_addr, 1114127094Sdes u_short src_port, 1115127094Sdes u_short dst_port, 1116127094Sdes int link_type, 1117127094Sdes int replace_partial_links) 111826026Sbrian{ 1119127094Sdes u_int i; 1120131614Sdes struct alias_link *lnk; 112126026Sbrian 1122127094Sdes i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1123131614Sdes LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { 1124131614Sdes if (lnk->src_addr.s_addr == src_addr.s_addr 1125131614Sdes && lnk->server == NULL 1126131614Sdes && lnk->dst_addr.s_addr == dst_addr.s_addr 1127131614Sdes && lnk->dst_port == dst_port 1128131614Sdes && lnk->src_port == src_port 1129131614Sdes && lnk->link_type == link_type) { 1130131614Sdes lnk->timestamp = la->timeStamp; 1131127094Sdes break; 1132127094Sdes } 1133127094Sdes } 113426026Sbrian 113551494Sru/* Search for partially specified links. */ 1136131614Sdes if (lnk == NULL && replace_partial_links) { 1137127094Sdes if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1138131614Sdes lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1139127094Sdes link_type, 0); 1140131614Sdes if (lnk == NULL) 1141131614Sdes lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 1142127094Sdes dst_port, link_type, 0); 1143127094Sdes } 1144131614Sdes if (lnk == NULL && 1145127094Sdes (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1146131614Sdes lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, 1147127094Sdes link_type, 0); 1148127094Sdes } 1149131614Sdes if (lnk != NULL) { 1150131614Sdes lnk = ReLink(lnk, 1151131614Sdes src_addr, dst_addr, lnk->alias_addr, 1152131614Sdes src_port, dst_port, lnk->alias_port, 1153127094Sdes link_type); 1154127094Sdes } 1155127094Sdes } 1156131614Sdes return (lnk); 115726026Sbrian} 115826026Sbrian 115951727Srustatic struct alias_link * 1160124621SphkFindLinkOut(struct libalias *la, struct in_addr src_addr, 1161127094Sdes struct in_addr dst_addr, 1162127094Sdes u_short src_port, 1163127094Sdes u_short dst_port, 1164127094Sdes int link_type, 1165127094Sdes int replace_partial_links) 116651727Sru{ 1167131614Sdes struct alias_link *lnk; 116826026Sbrian 1169131614Sdes lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1170127094Sdes link_type, replace_partial_links); 117151727Sru 1172131614Sdes if (lnk == NULL) { 1173127094Sdes /* 1174127094Sdes * The following allows permanent links to be specified as 1175127094Sdes * using the default source address (i.e. device interface 1176127094Sdes * address) without knowing in advance what that address 1177127094Sdes * is. 1178127094Sdes */ 1179127094Sdes if (la->aliasAddress.s_addr != INADDR_ANY && 1180127094Sdes src_addr.s_addr == la->aliasAddress.s_addr) { 1181131614Sdes lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, 1182127094Sdes link_type, replace_partial_links); 1183127094Sdes } 1184127094Sdes } 1185131614Sdes return (lnk); 118651727Sru} 118751727Sru 118851727Sru 118958279Sbrianstatic struct alias_link * 1190124621Sphk_FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1191127094Sdes struct in_addr alias_addr, 1192127094Sdes u_short dst_port, 1193127094Sdes u_short alias_port, 1194127094Sdes int link_type, 1195127094Sdes int replace_partial_links) 119626026Sbrian{ 1197127094Sdes int flags_in; 1198127094Sdes u_int start_point; 1199131614Sdes struct alias_link *lnk; 1200131614Sdes struct alias_link *lnk_fully_specified; 1201131614Sdes struct alias_link *lnk_unknown_all; 1202131614Sdes struct alias_link *lnk_unknown_dst_addr; 1203131614Sdes struct alias_link *lnk_unknown_dst_port; 120426026Sbrian 120526026Sbrian/* Initialize pointers */ 1206131614Sdes lnk_fully_specified = NULL; 1207131614Sdes lnk_unknown_all = NULL; 1208131614Sdes lnk_unknown_dst_addr = NULL; 1209131614Sdes lnk_unknown_dst_port = NULL; 121026026Sbrian 121126026Sbrian/* If either the dest addr or port is unknown, the search 121226026Sbrian loop will have to know about this. */ 121326026Sbrian 1214127094Sdes flags_in = 0; 1215127094Sdes if (dst_addr.s_addr == INADDR_ANY) 1216127094Sdes flags_in |= LINK_UNKNOWN_DEST_ADDR; 1217127094Sdes if (dst_port == 0) 1218127094Sdes flags_in |= LINK_UNKNOWN_DEST_PORT; 121926026Sbrian 122026026Sbrian/* Search loop */ 1221127094Sdes start_point = StartPointIn(alias_addr, alias_port, link_type); 1222131614Sdes LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { 1223127094Sdes int flags; 122426026Sbrian 1225131614Sdes flags = flags_in | lnk->flags; 1226127094Sdes if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1227131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1228131614Sdes && lnk->alias_port == alias_port 1229131614Sdes && lnk->dst_addr.s_addr == dst_addr.s_addr 1230131614Sdes && lnk->dst_port == dst_port 1231131614Sdes && lnk->link_type == link_type) { 1232131614Sdes lnk_fully_specified = lnk; 1233127094Sdes break; 1234127094Sdes } 1235127094Sdes } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1236127094Sdes && (flags & LINK_UNKNOWN_DEST_PORT)) { 1237131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1238131614Sdes && lnk->alias_port == alias_port 1239131614Sdes && lnk->link_type == link_type) { 1240131614Sdes if (lnk_unknown_all == NULL) 1241131614Sdes lnk_unknown_all = lnk; 1242127094Sdes } 1243127094Sdes } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1244131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1245131614Sdes && lnk->alias_port == alias_port 1246131614Sdes && lnk->link_type == link_type 1247131614Sdes && lnk->dst_port == dst_port) { 1248131614Sdes if (lnk_unknown_dst_addr == NULL) 1249131614Sdes lnk_unknown_dst_addr = lnk; 1250127094Sdes } 1251127094Sdes } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1252131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1253131614Sdes && lnk->alias_port == alias_port 1254131614Sdes && lnk->link_type == link_type 1255131614Sdes && lnk->dst_addr.s_addr == dst_addr.s_addr) { 1256131614Sdes if (lnk_unknown_dst_port == NULL) 1257131614Sdes lnk_unknown_dst_port = lnk; 1258127094Sdes } 1259127094Sdes } 1260127094Sdes } 126126026Sbrian 126226026Sbrian 126326026Sbrian 1264131614Sdes if (lnk_fully_specified != NULL) { 1265131614Sdes lnk_fully_specified->timestamp = la->timeStamp; 1266131614Sdes lnk = lnk_fully_specified; 1267131614Sdes } else if (lnk_unknown_dst_port != NULL) 1268131614Sdes lnk = lnk_unknown_dst_port; 1269131614Sdes else if (lnk_unknown_dst_addr != NULL) 1270131614Sdes lnk = lnk_unknown_dst_addr; 1271131614Sdes else if (lnk_unknown_all != NULL) 1272131614Sdes lnk = lnk_unknown_all; 1273127094Sdes else 1274127094Sdes return (NULL); 127559702Sru 1276127094Sdes if (replace_partial_links && 1277131614Sdes (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { 1278127094Sdes struct in_addr src_addr; 1279127094Sdes u_short src_port; 128059702Sru 1281131614Sdes if (lnk->server != NULL) { /* LSNAT link */ 1282131614Sdes src_addr = lnk->server->addr; 1283131614Sdes src_port = lnk->server->port; 1284131614Sdes lnk->server = lnk->server->next; 1285127094Sdes } else { 1286131614Sdes src_addr = lnk->src_addr; 1287131614Sdes src_port = lnk->src_port; 1288127094Sdes } 1289127094Sdes 1290131614Sdes lnk = ReLink(lnk, 1291127094Sdes src_addr, dst_addr, alias_addr, 1292127094Sdes src_port, dst_port, alias_port, 1293127094Sdes link_type); 129459702Sru } 1295131614Sdes return (lnk); 129626026Sbrian} 129726026Sbrian 129859181Srustatic struct alias_link * 1299124621SphkFindLinkIn(struct libalias *la, struct in_addr dst_addr, 1300127094Sdes struct in_addr alias_addr, 1301127094Sdes u_short dst_port, 1302127094Sdes u_short alias_port, 1303127094Sdes int link_type, 1304127094Sdes int replace_partial_links) 130551727Sru{ 1306131614Sdes struct alias_link *lnk; 130726026Sbrian 1308131614Sdes lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1309127094Sdes link_type, replace_partial_links); 131026026Sbrian 1311131614Sdes if (lnk == NULL) { 1312127094Sdes /* 1313127094Sdes * The following allows permanent links to be specified as 1314127094Sdes * using the default aliasing address (i.e. device 1315127094Sdes * interface address) without knowing in advance what that 1316127094Sdes * address is. 1317127094Sdes */ 1318127094Sdes if (la->aliasAddress.s_addr != INADDR_ANY && 1319127094Sdes alias_addr.s_addr == la->aliasAddress.s_addr) { 1320131614Sdes lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, 1321127094Sdes link_type, replace_partial_links); 1322127094Sdes } 1323127094Sdes } 1324131614Sdes return (lnk); 132551727Sru} 132651727Sru 132751727Sru 132851727Sru 132951727Sru 133026026Sbrian/* External routines for finding/adding links 133126026Sbrian 133226026Sbrian-- "external" means outside alias_db.c, but within alias*.c -- 133326026Sbrian 133426026Sbrian FindIcmpIn(), FindIcmpOut() 133526026Sbrian FindFragmentIn1(), FindFragmentIn2() 133626026Sbrian AddFragmentPtrLink(), FindFragmentPtr() 133759726Sru FindProtoIn(), FindProtoOut() 133826026Sbrian FindUdpTcpIn(), FindUdpTcpOut() 133967966Sru AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 134067966Sru FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 134126026Sbrian FindOriginalAddress(), FindAliasAddress() 134226026Sbrian 134326026Sbrian(prototypes in alias_local.h) 134426026Sbrian*/ 134526026Sbrian 134626026Sbrian 134726026Sbrianstruct alias_link * 1348124621SphkFindIcmpIn(struct libalias *la, struct in_addr dst_addr, 1349127094Sdes struct in_addr alias_addr, 1350127094Sdes u_short id_alias, 1351127094Sdes int create) 135226026Sbrian{ 1353131614Sdes struct alias_link *lnk; 135465280Sru 1355131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1356127094Sdes NO_DEST_PORT, id_alias, 1357127094Sdes LINK_ICMP, 0); 1358131614Sdes if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1359127094Sdes struct in_addr target_addr; 136065280Sru 1361127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1362131614Sdes lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1363127094Sdes id_alias, NO_DEST_PORT, id_alias, 1364127094Sdes LINK_ICMP); 1365127094Sdes } 1366131614Sdes return (lnk); 136726026Sbrian} 136826026Sbrian 136926026Sbrian 137026026Sbrianstruct alias_link * 1371124621SphkFindIcmpOut(struct libalias *la, struct in_addr src_addr, 1372127094Sdes struct in_addr dst_addr, 1373127094Sdes u_short id, 1374127094Sdes int create) 137526026Sbrian{ 1376131614Sdes struct alias_link *lnk; 137726026Sbrian 1378131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, 1379127094Sdes id, NO_DEST_PORT, 1380127094Sdes LINK_ICMP, 0); 1381131614Sdes if (lnk == NULL && create) { 1382127094Sdes struct in_addr alias_addr; 138326026Sbrian 1384127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1385131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1386127094Sdes id, NO_DEST_PORT, GET_ALIAS_ID, 1387127094Sdes LINK_ICMP); 1388127094Sdes } 1389131614Sdes return (lnk); 139026026Sbrian} 139126026Sbrian 139226026Sbrian 139326026Sbrianstruct alias_link * 1394124621SphkFindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1395127094Sdes struct in_addr alias_addr, 1396127094Sdes u_short ip_id) 139726026Sbrian{ 1398131614Sdes struct alias_link *lnk; 139926026Sbrian 1400131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1401127094Sdes NO_DEST_PORT, ip_id, 1402127094Sdes LINK_FRAGMENT_ID, 0); 140326026Sbrian 1404131614Sdes if (lnk == NULL) { 1405131614Sdes lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr, 1406127094Sdes NO_SRC_PORT, NO_DEST_PORT, ip_id, 1407127094Sdes LINK_FRAGMENT_ID); 1408127094Sdes } 1409131614Sdes return (lnk); 141026026Sbrian} 141126026Sbrian 141226026Sbrian 141326026Sbrianstruct alias_link * 1414127094SdesFindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if 1415127094Sdes * one */ 1416127094Sdes struct in_addr alias_addr, /* is not found. */ 1417127094Sdes u_short ip_id) 141826026Sbrian{ 1419127094Sdes return FindLinkIn(la, dst_addr, alias_addr, 1420127094Sdes NO_DEST_PORT, ip_id, 1421127094Sdes LINK_FRAGMENT_ID, 0); 142226026Sbrian} 142326026Sbrian 142426026Sbrian 142526026Sbrianstruct alias_link * 1426124621SphkAddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1427127094Sdes u_short ip_id) 142826026Sbrian{ 1429127094Sdes return AddLink(la, la->nullAddress, dst_addr, la->nullAddress, 1430127094Sdes NO_SRC_PORT, NO_DEST_PORT, ip_id, 1431127094Sdes LINK_FRAGMENT_PTR); 143226026Sbrian} 143326026Sbrian 143426026Sbrian 143526026Sbrianstruct alias_link * 1436124621SphkFindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1437127094Sdes u_short ip_id) 143826026Sbrian{ 1439127094Sdes return FindLinkIn(la, dst_addr, la->nullAddress, 1440127094Sdes NO_DEST_PORT, ip_id, 1441127094Sdes LINK_FRAGMENT_PTR, 0); 144226026Sbrian} 144326026Sbrian 144426026Sbrian 144526026Sbrianstruct alias_link * 1446124621SphkFindProtoIn(struct libalias *la, struct in_addr dst_addr, 1447127094Sdes struct in_addr alias_addr, 1448127094Sdes u_char proto) 144959356Sru{ 1450131614Sdes struct alias_link *lnk; 145159356Sru 1452131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1453127094Sdes NO_DEST_PORT, 0, 1454127094Sdes proto, 1); 145559356Sru 1456131614Sdes if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1457127094Sdes struct in_addr target_addr; 145859356Sru 1459127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1460131614Sdes lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1461127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 1462127094Sdes proto); 1463127094Sdes } 1464131614Sdes return (lnk); 146559356Sru} 146659356Sru 146759356Sru 146859356Srustruct alias_link * 1469124621SphkFindProtoOut(struct libalias *la, struct in_addr src_addr, 1470127094Sdes struct in_addr dst_addr, 1471127094Sdes u_char proto) 147259356Sru{ 1473131614Sdes struct alias_link *lnk; 147459356Sru 1475131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, 1476127094Sdes NO_SRC_PORT, NO_DEST_PORT, 1477127094Sdes proto, 1); 147859356Sru 1479131614Sdes if (lnk == NULL) { 1480127094Sdes struct in_addr alias_addr; 148159356Sru 1482127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1483131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1484127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 1485127094Sdes proto); 1486127094Sdes } 1487131614Sdes return (lnk); 148859356Sru} 148959356Sru 149059356Sru 149159356Srustruct alias_link * 1492124621SphkFindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1493127094Sdes struct in_addr alias_addr, 1494127094Sdes u_short dst_port, 1495127094Sdes u_short alias_port, 1496127094Sdes u_char proto, 1497127094Sdes int create) 149826026Sbrian{ 1499127094Sdes int link_type; 1500131614Sdes struct alias_link *lnk; 150126026Sbrian 1502127094Sdes switch (proto) { 1503127094Sdes case IPPROTO_UDP: 1504127094Sdes link_type = LINK_UDP; 1505127094Sdes break; 1506127094Sdes case IPPROTO_TCP: 1507127094Sdes link_type = LINK_TCP; 1508127094Sdes break; 1509127094Sdes default: 1510131613Sdes return (NULL); 1511127094Sdes break; 1512127094Sdes } 151326026Sbrian 1514131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1515127094Sdes dst_port, alias_port, 1516127094Sdes link_type, create); 151726026Sbrian 1518131614Sdes if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1519127094Sdes struct in_addr target_addr; 152026026Sbrian 1521127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1522131614Sdes lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1523127094Sdes alias_port, dst_port, alias_port, 1524127094Sdes link_type); 1525127094Sdes } 1526131614Sdes return (lnk); 152726026Sbrian} 152826026Sbrian 152926026Sbrian 153099207Sbrianstruct alias_link * 1531127094SdesFindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1532127094Sdes struct in_addr dst_addr, 1533127094Sdes u_short src_port, 1534127094Sdes u_short dst_port, 1535127094Sdes u_char proto, 1536127094Sdes int create) 153726026Sbrian{ 1538127094Sdes int link_type; 1539131614Sdes struct alias_link *lnk; 154026026Sbrian 1541127094Sdes switch (proto) { 1542127094Sdes case IPPROTO_UDP: 1543127094Sdes link_type = LINK_UDP; 1544127094Sdes break; 1545127094Sdes case IPPROTO_TCP: 1546127094Sdes link_type = LINK_TCP; 1547127094Sdes break; 1548127094Sdes default: 1549131613Sdes return (NULL); 1550127094Sdes break; 1551127094Sdes } 155226026Sbrian 1553131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 155426026Sbrian 1555131614Sdes if (lnk == NULL && create) { 1556127094Sdes struct in_addr alias_addr; 155726026Sbrian 1558127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1559131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1560127094Sdes src_port, dst_port, GET_ALIAS_PORT, 1561127094Sdes link_type); 1562127094Sdes } 1563131614Sdes return (lnk); 156426026Sbrian} 156526026Sbrian 156626026Sbrian 156761861Srustruct alias_link * 1568127094SdesAddPptp(struct libalias *la, struct in_addr src_addr, 1569127094Sdes struct in_addr dst_addr, 1570127094Sdes struct in_addr alias_addr, 1571127094Sdes u_int16_t src_call_id) 157267966Sru{ 1573131614Sdes struct alias_link *lnk; 157463899Sarchie 1575131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1576127094Sdes src_call_id, 0, GET_ALIAS_PORT, 1577127094Sdes LINK_PPTP); 157867966Sru 1579131614Sdes return (lnk); 158067966Sru} 158167966Sru 158267966Sru 158367966Srustruct alias_link * 1584124621SphkFindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1585127094Sdes struct in_addr dst_addr, 1586127094Sdes u_int16_t src_call_id) 158767966Sru{ 1588127094Sdes u_int i; 1589131614Sdes struct alias_link *lnk; 159067966Sru 1591127094Sdes i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1592131614Sdes LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1593131614Sdes if (lnk->link_type == LINK_PPTP && 1594131614Sdes lnk->src_addr.s_addr == src_addr.s_addr && 1595131614Sdes lnk->dst_addr.s_addr == dst_addr.s_addr && 1596131614Sdes lnk->src_port == src_call_id) 159767966Sru break; 159867966Sru 1599131614Sdes return (lnk); 160067966Sru} 160167966Sru 160267966Sru 160367966Srustruct alias_link * 1604124621SphkFindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1605127094Sdes struct in_addr dst_addr, 1606127094Sdes u_int16_t dst_call_id) 160767966Sru{ 1608127094Sdes u_int i; 1609131614Sdes struct alias_link *lnk; 161067966Sru 1611127094Sdes i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1612131614Sdes LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1613131614Sdes if (lnk->link_type == LINK_PPTP && 1614131614Sdes lnk->src_addr.s_addr == src_addr.s_addr && 1615131614Sdes lnk->dst_addr.s_addr == dst_addr.s_addr && 1616131614Sdes lnk->dst_port == dst_call_id) 161767966Sru break; 161867966Sru 1619131614Sdes return (lnk); 162067966Sru} 162167966Sru 162267966Sru 162367966Srustruct alias_link * 1624124621SphkFindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1625127094Sdes struct in_addr alias_addr, 1626127094Sdes u_int16_t dst_call_id) 162767966Sru{ 1628127094Sdes u_int i; 1629131614Sdes struct alias_link *lnk; 163067966Sru 1631127094Sdes i = StartPointIn(alias_addr, 0, LINK_PPTP); 1632131614Sdes LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) 1633131614Sdes if (lnk->link_type == LINK_PPTP && 1634131614Sdes lnk->dst_addr.s_addr == dst_addr.s_addr && 1635131614Sdes lnk->alias_addr.s_addr == alias_addr.s_addr && 1636131614Sdes lnk->dst_port == dst_call_id) 163767966Sru break; 163867966Sru 1639131614Sdes return (lnk); 164067966Sru} 164167966Sru 164267966Sru 164367966Srustruct alias_link * 1644124621SphkFindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1645127094Sdes struct in_addr alias_addr, 1646127094Sdes u_int16_t alias_call_id) 164767966Sru{ 1648131614Sdes struct alias_link *lnk; 164967966Sru 1650131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1651127094Sdes 0 /* any */ , alias_call_id, 1652127094Sdes LINK_PPTP, 0); 165367966Sru 165467966Sru 1655131614Sdes return (lnk); 165667966Sru} 165767966Sru 165867966Sru 165999207Sbrianstruct alias_link * 1660127094SdesFindRtspOut(struct libalias *la, struct in_addr src_addr, 1661127094Sdes struct in_addr dst_addr, 1662127094Sdes u_short src_port, 1663127094Sdes u_short alias_port, 1664127094Sdes u_char proto) 166563899Sarchie{ 1666127094Sdes int link_type; 1667131614Sdes struct alias_link *lnk; 166863899Sarchie 1669127094Sdes switch (proto) { 1670127094Sdes case IPPROTO_UDP: 1671127094Sdes link_type = LINK_UDP; 1672127094Sdes break; 1673127094Sdes case IPPROTO_TCP: 1674127094Sdes link_type = LINK_TCP; 1675127094Sdes break; 1676127094Sdes default: 1677131613Sdes return (NULL); 1678127094Sdes break; 1679127094Sdes } 168063899Sarchie 1681131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 168263899Sarchie 1683131614Sdes if (lnk == NULL) { 1684127094Sdes struct in_addr alias_addr; 168563899Sarchie 1686127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1687131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1688127094Sdes src_port, 0, alias_port, 1689127094Sdes link_type); 1690127094Sdes } 1691131614Sdes return (lnk); 169263899Sarchie} 169363899Sarchie 169463899Sarchie 169526026Sbrianstruct in_addr 1696124621SphkFindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 169726026Sbrian{ 1698131614Sdes struct alias_link *lnk; 169999207Sbrian 1700131614Sdes lnk = FindLinkIn(la, la->nullAddress, alias_addr, 1701127094Sdes 0, 0, LINK_ADDR, 0); 1702131614Sdes if (lnk == NULL) { 1703127094Sdes la->newDefaultLink = 1; 1704127094Sdes if (la->targetAddress.s_addr == INADDR_ANY) 1705131613Sdes return (alias_addr); 1706127094Sdes else if (la->targetAddress.s_addr == INADDR_NONE) 1707127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1708127094Sdes la->aliasAddress : alias_addr; 1709127094Sdes else 1710131613Sdes return (la->targetAddress); 1711127094Sdes } else { 1712131614Sdes if (lnk->server != NULL) { /* LSNAT link */ 1713127094Sdes struct in_addr src_addr; 171459702Sru 1715131614Sdes src_addr = lnk->server->addr; 1716131614Sdes lnk->server = lnk->server->next; 1717127094Sdes return (src_addr); 1718131614Sdes } else if (lnk->src_addr.s_addr == INADDR_ANY) 1719127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1720127094Sdes la->aliasAddress : alias_addr; 1721127094Sdes else 1722131614Sdes return (lnk->src_addr); 1723127094Sdes } 172426026Sbrian} 172526026Sbrian 172626026Sbrian 172726026Sbrianstruct in_addr 1728124621SphkFindAliasAddress(struct libalias *la, struct in_addr original_addr) 172926026Sbrian{ 1730131614Sdes struct alias_link *lnk; 173199207Sbrian 1732131614Sdes lnk = FindLinkOut(la, original_addr, la->nullAddress, 1733127094Sdes 0, 0, LINK_ADDR, 0); 1734131614Sdes if (lnk == NULL) { 1735127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1736127094Sdes la->aliasAddress : original_addr; 1737127094Sdes } else { 1738131614Sdes if (lnk->alias_addr.s_addr == INADDR_ANY) 1739127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1740127094Sdes la->aliasAddress : original_addr; 1741127094Sdes else 1742131614Sdes return (lnk->alias_addr); 1743127094Sdes } 174426026Sbrian} 174526026Sbrian 174626026Sbrian 174726026Sbrian/* External routines for getting or changing link data 174826026Sbrian (external to alias_db.c, but internal to alias*.c) 174926026Sbrian 175026026Sbrian SetFragmentData(), GetFragmentData() 175126026Sbrian SetFragmentPtr(), GetFragmentPtr() 175226026Sbrian SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 175326026Sbrian GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 175426026Sbrian GetOriginalPort(), GetAliasPort() 175526026Sbrian SetAckModified(), GetAckModified() 175626026Sbrian GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 175777485Sru SetProtocolFlags(), GetProtocolFlags() 175867966Sru SetDestCallId() 175926026Sbrian*/ 176026026Sbrian 176126026Sbrian 176226026Sbrianvoid 1763131614SdesSetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 176426026Sbrian{ 1765131614Sdes lnk->data.frag_addr = src_addr; 176626026Sbrian} 176726026Sbrian 176826026Sbrian 176926026Sbrianvoid 1770131614SdesGetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 177126026Sbrian{ 1772131614Sdes *src_addr = lnk->data.frag_addr; 177326026Sbrian} 177426026Sbrian 177526026Sbrian 177626026Sbrianvoid 1777131614SdesSetFragmentPtr(struct alias_link *lnk, char *fptr) 177826026Sbrian{ 1779131614Sdes lnk->data.frag_ptr = fptr; 178026026Sbrian} 178126026Sbrian 178226026Sbrian 178326026Sbrianvoid 1784131614SdesGetFragmentPtr(struct alias_link *lnk, char **fptr) 178526026Sbrian{ 1786131614Sdes *fptr = lnk->data.frag_ptr; 178726026Sbrian} 178826026Sbrian 178926026Sbrian 179026026Sbrianvoid 1791131614SdesSetStateIn(struct alias_link *lnk, int state) 179226026Sbrian{ 1793127094Sdes /* TCP input state */ 1794127094Sdes switch (state) { 1795127094Sdes case ALIAS_TCP_STATE_DISCONNECTED: 1796131614Sdes if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1797131614Sdes lnk->expire_time = TCP_EXPIRE_DEAD; 1798127094Sdes else 1799131614Sdes lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1800127094Sdes break; 1801127094Sdes case ALIAS_TCP_STATE_CONNECTED: 1802131614Sdes if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1803131614Sdes lnk->expire_time = TCP_EXPIRE_CONNECTED; 1804127094Sdes break; 1805127094Sdes default: 1806145927Sglebius#ifdef _KERNEL 1807145927Sglebius panic("libalias:SetStateIn() unknown state"); 1808145927Sglebius#else 1809127094Sdes abort(); 1810145927Sglebius#endif 1811127094Sdes } 1812131614Sdes lnk->data.tcp->state.in = state; 181326026Sbrian} 181426026Sbrian 181526026Sbrian 181626026Sbrianvoid 1817131614SdesSetStateOut(struct alias_link *lnk, int state) 181826026Sbrian{ 1819127094Sdes /* TCP output state */ 1820127094Sdes switch (state) { 1821127094Sdes case ALIAS_TCP_STATE_DISCONNECTED: 1822131614Sdes if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1823131614Sdes lnk->expire_time = TCP_EXPIRE_DEAD; 1824127094Sdes else 1825131614Sdes lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1826127094Sdes break; 1827127094Sdes case ALIAS_TCP_STATE_CONNECTED: 1828131614Sdes if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1829131614Sdes lnk->expire_time = TCP_EXPIRE_CONNECTED; 1830127094Sdes break; 1831127094Sdes default: 1832145927Sglebius#ifdef _KERNEL 1833145927Sglebius panic("libalias:SetStateOut() unknown state"); 1834145927Sglebius#else 1835127094Sdes abort(); 1836145927Sglebius#endif 1837127094Sdes } 1838131614Sdes lnk->data.tcp->state.out = state; 183926026Sbrian} 184026026Sbrian 184126026Sbrian 184226026Sbrianint 1843131614SdesGetStateIn(struct alias_link *lnk) 184426026Sbrian{ 1845127094Sdes /* TCP input state */ 1846131614Sdes return (lnk->data.tcp->state.in); 184726026Sbrian} 184826026Sbrian 184926026Sbrian 185026026Sbrianint 1851131614SdesGetStateOut(struct alias_link *lnk) 185226026Sbrian{ 1853127094Sdes /* TCP output state */ 1854131614Sdes return (lnk->data.tcp->state.out); 185526026Sbrian} 185626026Sbrian 185726026Sbrian 185826026Sbrianstruct in_addr 1859131614SdesGetOriginalAddress(struct alias_link *lnk) 186026026Sbrian{ 1861131614Sdes if (lnk->src_addr.s_addr == INADDR_ANY) 1862131614Sdes return (lnk->la->aliasAddress); 1863127094Sdes else 1864131614Sdes return (lnk->src_addr); 186526026Sbrian} 186626026Sbrian 186726026Sbrian 186826026Sbrianstruct in_addr 1869131614SdesGetDestAddress(struct alias_link *lnk) 187026026Sbrian{ 1871131614Sdes return (lnk->dst_addr); 187226026Sbrian} 187326026Sbrian 187426026Sbrian 187526026Sbrianstruct in_addr 1876131614SdesGetAliasAddress(struct alias_link *lnk) 187726026Sbrian{ 1878131614Sdes if (lnk->alias_addr.s_addr == INADDR_ANY) 1879131614Sdes return (lnk->la->aliasAddress); 1880127094Sdes else 1881131614Sdes return (lnk->alias_addr); 188226026Sbrian} 188326026Sbrian 188426026Sbrian 188526026Sbrianstruct in_addr 1886124621SphkGetDefaultAliasAddress(struct libalias *la) 188726026Sbrian{ 1888131613Sdes return (la->aliasAddress); 188926026Sbrian} 189026026Sbrian 189126026Sbrian 189226026Sbrianvoid 1893124621SphkSetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 189426026Sbrian{ 1895127094Sdes la->aliasAddress = alias_addr; 189626026Sbrian} 189726026Sbrian 189826026Sbrian 189926026Sbrianu_short 1900131614SdesGetOriginalPort(struct alias_link *lnk) 190126026Sbrian{ 1902131614Sdes return (lnk->src_port); 190326026Sbrian} 190426026Sbrian 190526026Sbrian 190626026Sbrianu_short 1907131614SdesGetAliasPort(struct alias_link *lnk) 190826026Sbrian{ 1909131614Sdes return (lnk->alias_port); 191026026Sbrian} 191126026Sbrian 191258279Sbrian#ifndef NO_FW_PUNCH 1913127094Sdesstatic u_short 1914131614SdesGetDestPort(struct alias_link *lnk) 191532377Seivind{ 1916131614Sdes return (lnk->dst_port); 191732377Seivind} 1918127094Sdes 191958279Sbrian#endif 192026026Sbrian 192126026Sbrianvoid 1922131614SdesSetAckModified(struct alias_link *lnk) 192326026Sbrian{ 192459356Sru/* Indicate that ACK numbers have been modified in a TCP connection */ 1925131614Sdes lnk->data.tcp->state.ack_modified = 1; 192626026Sbrian} 192726026Sbrian 192826026Sbrian 192944307Sbrianstruct in_addr 1930131614SdesGetProxyAddress(struct alias_link *lnk) 193144307Sbrian{ 1932131614Sdes return (lnk->proxy_addr); 193344307Sbrian} 193444307Sbrian 193544307Sbrian 193644307Sbrianvoid 1937131614SdesSetProxyAddress(struct alias_link *lnk, struct in_addr addr) 193844307Sbrian{ 1939131614Sdes lnk->proxy_addr = addr; 194044307Sbrian} 194144307Sbrian 194244307Sbrian 194344307Sbrianu_short 1944131614SdesGetProxyPort(struct alias_link *lnk) 194544307Sbrian{ 1946131614Sdes return (lnk->proxy_port); 194744307Sbrian} 194844307Sbrian 194944307Sbrian 195044307Sbrianvoid 1951131614SdesSetProxyPort(struct alias_link *lnk, u_short port) 195244307Sbrian{ 1953131614Sdes lnk->proxy_port = port; 195444307Sbrian} 195544307Sbrian 195644307Sbrian 195726026Sbrianint 1958131614SdesGetAckModified(struct alias_link *lnk) 195926026Sbrian{ 196059356Sru/* See if ACK numbers have been modified */ 1961131614Sdes return (lnk->data.tcp->state.ack_modified); 196226026Sbrian} 196326026Sbrian 196426026Sbrian 196526026Sbrianint 1966131614SdesGetDeltaAckIn(struct ip *pip, struct alias_link *lnk) 196726026Sbrian{ 196826026Sbrian/* 196959356SruFind out how much the ACK number has been altered for an incoming 197059356SruTCP packet. To do this, a circular list of ACK numbers where the TCP 197199207Sbrianpacket size was altered is searched. 197226026Sbrian*/ 197326026Sbrian 1974127094Sdes int i; 1975127094Sdes struct tcphdr *tc; 1976127094Sdes int delta, ack_diff_min; 1977127094Sdes u_long ack; 197826026Sbrian 1979131699Sdes tc = ip_next(pip); 1980127094Sdes ack = tc->th_ack; 198126026Sbrian 1982127094Sdes delta = 0; 1983127094Sdes ack_diff_min = -1; 1984127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) { 1985127094Sdes struct ack_data_record x; 198626026Sbrian 1987131614Sdes x = lnk->data.tcp->ack[i]; 1988127094Sdes if (x.active == 1) { 1989127094Sdes int ack_diff; 199026026Sbrian 1991127094Sdes ack_diff = SeqDiff(x.ack_new, ack); 1992127094Sdes if (ack_diff >= 0) { 1993127094Sdes if (ack_diff_min >= 0) { 1994127094Sdes if (ack_diff < ack_diff_min) { 1995127094Sdes delta = x.delta; 1996127094Sdes ack_diff_min = ack_diff; 1997127094Sdes } 1998127094Sdes } else { 1999127094Sdes delta = x.delta; 2000127094Sdes ack_diff_min = ack_diff; 2001127094Sdes } 2002127094Sdes } 2003127094Sdes } 2004127094Sdes } 2005127094Sdes return (delta); 200626026Sbrian} 200726026Sbrian 200826026Sbrian 200926026Sbrianint 2010131614SdesGetDeltaSeqOut(struct ip *pip, struct alias_link *lnk) 201126026Sbrian{ 201226026Sbrian/* 201359356SruFind out how much the sequence number has been altered for an outgoing 201459356SruTCP packet. To do this, a circular list of ACK numbers where the TCP 201599207Sbrianpacket size was altered is searched. 201626026Sbrian*/ 201726026Sbrian 2018127094Sdes int i; 2019127094Sdes struct tcphdr *tc; 2020127094Sdes int delta, seq_diff_min; 2021127094Sdes u_long seq; 202226026Sbrian 2023131699Sdes tc = ip_next(pip); 2024127094Sdes seq = tc->th_seq; 202526026Sbrian 2026127094Sdes delta = 0; 2027127094Sdes seq_diff_min = -1; 2028127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) { 2029127094Sdes struct ack_data_record x; 203026026Sbrian 2031131614Sdes x = lnk->data.tcp->ack[i]; 2032127094Sdes if (x.active == 1) { 2033127094Sdes int seq_diff; 203426026Sbrian 2035127094Sdes seq_diff = SeqDiff(x.ack_old, seq); 2036127094Sdes if (seq_diff >= 0) { 2037127094Sdes if (seq_diff_min >= 0) { 2038127094Sdes if (seq_diff < seq_diff_min) { 2039127094Sdes delta = x.delta; 2040127094Sdes seq_diff_min = seq_diff; 2041127094Sdes } 2042127094Sdes } else { 2043127094Sdes delta = x.delta; 2044127094Sdes seq_diff_min = seq_diff; 2045127094Sdes } 2046127094Sdes } 2047127094Sdes } 2048127094Sdes } 2049127094Sdes return (delta); 205026026Sbrian} 205126026Sbrian 205226026Sbrian 205326026Sbrianvoid 2054131614SdesAddSeq(struct ip *pip, struct alias_link *lnk, int delta) 205526026Sbrian{ 205626026Sbrian/* 205726026SbrianWhen a TCP packet has been altered in length, save this 205826026Sbrianinformation in a circular list. If enough packets have 205926026Sbrianbeen altered, then this list will begin to overwrite itself. 206026026Sbrian*/ 206126026Sbrian 2062127094Sdes struct tcphdr *tc; 2063127094Sdes struct ack_data_record x; 2064127094Sdes int hlen, tlen, dlen; 2065127094Sdes int i; 206626026Sbrian 2067131699Sdes tc = ip_next(pip); 206826026Sbrian 2069127094Sdes hlen = (pip->ip_hl + tc->th_off) << 2; 2070127094Sdes tlen = ntohs(pip->ip_len); 2071127094Sdes dlen = tlen - hlen; 207226026Sbrian 2073127094Sdes x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2074127094Sdes x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2075127094Sdes x.delta = delta; 2076127094Sdes x.active = 1; 207726026Sbrian 2078131614Sdes i = lnk->data.tcp->state.index; 2079131614Sdes lnk->data.tcp->ack[i] = x; 208026026Sbrian 2081127094Sdes i++; 2082127094Sdes if (i == N_LINK_TCP_DATA) 2083131614Sdes lnk->data.tcp->state.index = 0; 2084127094Sdes else 2085131614Sdes lnk->data.tcp->state.index = i; 208626026Sbrian} 208726026Sbrian 208826026Sbrianvoid 2089131614SdesSetExpire(struct alias_link *lnk, int expire) 209026026Sbrian{ 2091127094Sdes if (expire == 0) { 2092131614Sdes lnk->flags &= ~LINK_PERMANENT; 2093131614Sdes DeleteLink(lnk); 2094127094Sdes } else if (expire == -1) { 2095131614Sdes lnk->flags |= LINK_PERMANENT; 2096127094Sdes } else if (expire > 0) { 2097131614Sdes lnk->expire_time = expire; 2098127094Sdes } else { 2099145961Sglebius#ifdef LIBALIAS_DEBUG 2100127094Sdes fprintf(stderr, "PacketAlias/SetExpire(): "); 2101127094Sdes fprintf(stderr, "error in expire parameter\n"); 210244616Sbrian#endif 2103127094Sdes } 210426026Sbrian} 210526026Sbrian 210626026Sbrianvoid 2107124621SphkClearCheckNewLink(struct libalias *la) 210826026Sbrian{ 2109127094Sdes la->newDefaultLink = 0; 211026026Sbrian} 211126026Sbrian 211261677Sruvoid 2113131614SdesSetProtocolFlags(struct alias_link *lnk, int pflags) 211461677Sru{ 211526026Sbrian 2116131614Sdes lnk->pflags = pflags;; 211761677Sru} 211861677Sru 211961677Sruint 2120131614SdesGetProtocolFlags(struct alias_link *lnk) 212161677Sru{ 212261677Sru 2123131614Sdes return (lnk->pflags); 212461677Sru} 212561677Sru 212667966Sruvoid 2127131614SdesSetDestCallId(struct alias_link *lnk, u_int16_t cid) 212867966Sru{ 2129131614Sdes struct libalias *la = lnk->la; 213061677Sru 2131127094Sdes la->deleteAllLinks = 1; 2132131614Sdes lnk = ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2133131614Sdes lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2134127094Sdes la->deleteAllLinks = 0; 213567966Sru} 213667966Sru 213767966Sru 213827864Sbrian/* Miscellaneous Functions 213926026Sbrian 214027864Sbrian HouseKeeping() 214127864Sbrian InitPacketAliasLog() 214227864Sbrian UninitPacketAliasLog() 214327864Sbrian*/ 214426026Sbrian 214526026Sbrian/* 214626026Sbrian Whenever an outgoing or incoming packet is handled, HouseKeeping() 214726026Sbrian is called to find and remove timed-out aliasing links. Logic exists 214826026Sbrian to sweep through the entire table and linked list structure 214926026Sbrian every 60 seconds. 215026026Sbrian 215126026Sbrian (prototype in alias_local.h) 215226026Sbrian*/ 215326026Sbrian 215426026Sbrianvoid 2155124621SphkHouseKeeping(struct libalias *la) 215626026Sbrian{ 2157127094Sdes int i, n, n100; 2158145927Sglebius#ifndef _KERNEL 2159127094Sdes struct timeval tv; 2160127094Sdes struct timezone tz; 2161145927Sglebius#endif 216226026Sbrian 2163127094Sdes /* 2164127094Sdes * Save system time (seconds) in global variable timeStamp for use 2165127094Sdes * by other functions. This is done so as not to unnecessarily 2166127094Sdes * waste timeline by making system calls. 2167127094Sdes */ 2168145927Sglebius#ifdef _KERNEL 2169150350Sandre la->timeStamp = time_uptime; 2170145927Sglebius#else 2171127094Sdes gettimeofday(&tv, &tz); 2172127094Sdes la->timeStamp = tv.tv_sec; 2173145927Sglebius#endif 217426026Sbrian 2175127094Sdes /* Compute number of spokes (output table link chains) to cover */ 2176127094Sdes n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual; 2177127094Sdes n100 *= la->timeStamp - la->lastCleanupTime; 2178127094Sdes n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 217926026Sbrian 2180127094Sdes n = n100 / 100; 218126026Sbrian 2182127094Sdes /* Handle different cases */ 2183127094Sdes if (n > ALIAS_CLEANUP_MAX_SPOKES) { 2184127094Sdes n = ALIAS_CLEANUP_MAX_SPOKES; 2185127094Sdes la->lastCleanupTime = la->timeStamp; 2186127094Sdes la->houseKeepingResidual = 0; 218726026Sbrian 2188127094Sdes for (i = 0; i < n; i++) 2189127094Sdes IncrementalCleanup(la); 2190127094Sdes } else if (n > 0) { 2191127094Sdes la->lastCleanupTime = la->timeStamp; 2192127094Sdes la->houseKeepingResidual = n100 - 100 * n; 219326026Sbrian 2194127094Sdes for (i = 0; i < n; i++) 2195127094Sdes IncrementalCleanup(la); 2196127094Sdes } else if (n < 0) { 2197145961Sglebius#ifdef LIBALIAS_DEBUG 2198127094Sdes fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2199127094Sdes fprintf(stderr, "something unexpected in time values\n"); 220044616Sbrian#endif 2201127094Sdes la->lastCleanupTime = la->timeStamp; 2202127094Sdes la->houseKeepingResidual = 0; 2203127094Sdes } 220426026Sbrian} 220526026Sbrian 2206145925Sglebius#ifndef NO_LOGGING 220727864Sbrian/* Init the log file and enable logging */ 220832377Seivindstatic void 2209124621SphkInitPacketAliasLog(struct libalias *la) 221027864Sbrian{ 2211127094Sdes if ((~la->packetAliasMode & PKT_ALIAS_LOG) 2212127094Sdes && (la->monitorFile = fopen("/var/log/alias.log", "w"))) { 2213127094Sdes la->packetAliasMode |= PKT_ALIAS_LOG; 2214127094Sdes fprintf(la->monitorFile, 2215127094Sdes "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2216127094Sdes } 221727864Sbrian} 221826026Sbrian 221927864Sbrian/* Close the log-file and disable logging. */ 222032377Seivindstatic void 2221124621SphkUninitPacketAliasLog(struct libalias *la) 222227864Sbrian{ 2223127094Sdes if (la->monitorFile) { 2224127094Sdes fclose(la->monitorFile); 2225127094Sdes la->monitorFile = NULL; 2226127094Sdes } 2227127094Sdes la->packetAliasMode &= ~PKT_ALIAS_LOG; 222827864Sbrian} 2229145925Sglebius#endif 223026026Sbrian 223126026Sbrian/* Outside world interfaces 223226026Sbrian 223326026Sbrian-- "outside world" means other than alias*.c routines -- 223426026Sbrian 223526026Sbrian PacketAliasRedirectPort() 223659702Sru PacketAliasAddServer() 223759726Sru PacketAliasRedirectProto() 223826026Sbrian PacketAliasRedirectAddr() 2239115650Sru PacketAliasRedirectDynamic() 224027864Sbrian PacketAliasRedirectDelete() 224127864Sbrian PacketAliasSetAddress() 224227864Sbrian PacketAliasInit() 224332377Seivind PacketAliasUninit() 224427864Sbrian PacketAliasSetMode() 224526026Sbrian 224626026Sbrian(prototypes in alias.h) 224726026Sbrian*/ 224826026Sbrian 224926026Sbrian/* Redirection from a specific public addr:port to a 225059356Sru private addr:port */ 225126026Sbrianstruct alias_link * 2252127094SdesLibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2253127094Sdes struct in_addr dst_addr, u_short dst_port, 2254127094Sdes struct in_addr alias_addr, u_short alias_port, 2255127094Sdes u_char proto) 225626026Sbrian{ 2257127094Sdes int link_type; 2258131614Sdes struct alias_link *lnk; 225926026Sbrian 2260127094Sdes switch (proto) { 2261127094Sdes case IPPROTO_UDP: 2262127094Sdes link_type = LINK_UDP; 2263127094Sdes break; 2264127094Sdes case IPPROTO_TCP: 2265127094Sdes link_type = LINK_TCP; 2266127094Sdes break; 2267127094Sdes default: 2268145961Sglebius#ifdef LIBALIAS_DEBUG 2269127094Sdes fprintf(stderr, "PacketAliasRedirectPort(): "); 2270127094Sdes fprintf(stderr, "only TCP and UDP protocols allowed\n"); 227144616Sbrian#endif 2272131613Sdes return (NULL); 2273127094Sdes } 227426026Sbrian 2275131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2276127094Sdes src_port, dst_port, alias_port, 2277127094Sdes link_type); 227826026Sbrian 2279131614Sdes if (lnk != NULL) { 2280131614Sdes lnk->flags |= LINK_PERMANENT; 2281127094Sdes } 2282145961Sglebius#ifdef LIBALIAS_DEBUG 2283127094Sdes else { 2284127094Sdes fprintf(stderr, "PacketAliasRedirectPort(): " 2285127094Sdes "call to AddLink() failed\n"); 2286127094Sdes } 228744616Sbrian#endif 228826026Sbrian 2289131614Sdes return (lnk); 229026026Sbrian} 229126026Sbrian 229259702Sru/* Add server to the pool of servers */ 229359702Sruint 2294131614SdesLibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 229559702Sru{ 2296127094Sdes struct server *server; 229759702Sru 2298131614Sdes (void)la; 2299131614Sdes 2300127094Sdes server = malloc(sizeof(struct server)); 230159702Sru 2302127094Sdes if (server != NULL) { 2303127094Sdes struct server *head; 230459702Sru 2305127094Sdes server->addr = addr; 2306127094Sdes server->port = port; 230759702Sru 2308131614Sdes head = lnk->server; 2309127094Sdes if (head == NULL) 2310127094Sdes server->next = server; 2311127094Sdes else { 2312127094Sdes struct server *s; 231359702Sru 2314127094Sdes for (s = head; s->next != head; s = s->next); 2315127094Sdes s->next = server; 2316127094Sdes server->next = head; 2317127094Sdes } 2318131614Sdes lnk->server = server; 2319127094Sdes return (0); 2320127094Sdes } else 2321127094Sdes return (-1); 232259702Sru} 232359702Sru 232459726Sru/* Redirect packets of a given IP protocol from a specific 232559356Sru public address to a private address */ 232659356Srustruct alias_link * 2327124621SphkLibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2328127094Sdes struct in_addr dst_addr, 2329127094Sdes struct in_addr alias_addr, 2330127094Sdes u_char proto) 233144307Sbrian{ 2332131614Sdes struct alias_link *lnk; 233344307Sbrian 2334131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2335127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 2336127094Sdes proto); 233759356Sru 2338131614Sdes if (lnk != NULL) { 2339131614Sdes lnk->flags |= LINK_PERMANENT; 2340127094Sdes } 2341145961Sglebius#ifdef LIBALIAS_DEBUG 2342127094Sdes else { 2343127094Sdes fprintf(stderr, "PacketAliasRedirectProto(): " 2344127094Sdes "call to AddLink() failed\n"); 2345127094Sdes } 234659356Sru#endif 234759356Sru 2348131614Sdes return (lnk); 234944307Sbrian} 235044307Sbrian 235126026Sbrian/* Static address translation */ 235226026Sbrianstruct alias_link * 2353124621SphkLibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2354127094Sdes struct in_addr alias_addr) 235526026Sbrian{ 2356131614Sdes struct alias_link *lnk; 235726026Sbrian 2358131614Sdes lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, 2359127094Sdes 0, 0, 0, 2360127094Sdes LINK_ADDR); 236126026Sbrian 2362131614Sdes if (lnk != NULL) { 2363131614Sdes lnk->flags |= LINK_PERMANENT; 2364127094Sdes } 2365145961Sglebius#ifdef LIBALIAS_DEBUG 2366127094Sdes else { 2367127094Sdes fprintf(stderr, "PacketAliasRedirectAddr(): " 2368127094Sdes "call to AddLink() failed\n"); 2369127094Sdes } 237044616Sbrian#endif 237126026Sbrian 2372131614Sdes return (lnk); 237326026Sbrian} 237426026Sbrian 237526026Sbrian 2376115650Sru/* Mark the aliasing link dynamic */ 2377115650Sruint 2378131614SdesLibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2379115650Sru{ 2380115650Sru 2381131614Sdes (void)la; 2382131614Sdes 2383131614Sdes if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2384127094Sdes return (-1); 2385127094Sdes else { 2386131614Sdes lnk->flags &= ~LINK_PERMANENT; 2387127094Sdes return (0); 2388127094Sdes } 2389115650Sru} 2390115650Sru 2391115650Sru 239226026Sbrianvoid 2393131614SdesLibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 239426026Sbrian{ 239527864Sbrian/* This is a dangerous function to put in the API, 239626026Sbrian because an invalid pointer can crash the program. */ 239726026Sbrian 2398127094Sdes la->deleteAllLinks = 1; 2399131614Sdes DeleteLink(lnk); 2400127094Sdes la->deleteAllLinks = 0; 240126026Sbrian} 240226026Sbrian 240326026Sbrian 240426026Sbrianvoid 2405124621SphkLibAliasSetAddress(struct libalias *la, struct in_addr addr) 240626026Sbrian{ 2407127094Sdes if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2408127094Sdes && la->aliasAddress.s_addr != addr.s_addr) 2409127094Sdes CleanupAliasData(la); 241033897Sbrian 2411127094Sdes la->aliasAddress = addr; 241226026Sbrian} 241326026Sbrian 241426026Sbrian 241526026Sbrianvoid 2416124621SphkLibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 241726026Sbrian{ 2418127094Sdes la->targetAddress = target_addr; 241926026Sbrian} 242026026Sbrian 2421124621Sphkstatic void 2422124621Sphkfinishoff(void) 2423124621Sphk{ 242426026Sbrian 2425127094Sdes while (!LIST_EMPTY(&instancehead)) 2426124621Sphk LibAliasUninit(LIST_FIRST(&instancehead)); 2427124621Sphk} 2428124621Sphk 2429124621Sphkstruct libalias * 2430124621SphkLibAliasInit(struct libalias *la) 243126026Sbrian{ 2432127094Sdes int i; 2433145927Sglebius#ifndef _KERNEL 2434127094Sdes struct timeval tv; 2435127094Sdes struct timezone tz; 2436145927Sglebius#endif 243726026Sbrian 2438127094Sdes if (la == NULL) { 2439127094Sdes la = calloc(sizeof *la, 1); 2440127094Sdes if (la == NULL) 2441127094Sdes return (la); 2442145927Sglebius 2443145927Sglebius#ifndef _KERNEL /* kernel cleans up on module unload */ 2444127094Sdes if (LIST_EMPTY(&instancehead)) 2445127094Sdes atexit(finishoff); 2446145927Sglebius#endif 2447127094Sdes LIST_INSERT_HEAD(&instancehead, la, instancelist); 244826026Sbrian 2449145927Sglebius#ifdef _KERNEL 2450150350Sandre la->timeStamp = time_uptime; 2451150350Sandre la->lastCleanupTime = time_uptime; 2452145927Sglebius#else 2453127094Sdes gettimeofday(&tv, &tz); 2454127094Sdes la->timeStamp = tv.tv_sec; 2455127094Sdes la->lastCleanupTime = tv.tv_sec; 2456145927Sglebius#endif 2457127094Sdes la->houseKeepingResidual = 0; 245826026Sbrian 2459127094Sdes for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2460127094Sdes LIST_INIT(&la->linkTableOut[i]); 2461127094Sdes for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2462127094Sdes LIST_INIT(&la->linkTableIn[i]); 246326026Sbrian 2464127094Sdes } else { 2465127094Sdes la->deleteAllLinks = 1; 2466127094Sdes CleanupAliasData(la); 2467127094Sdes la->deleteAllLinks = 0; 2468127094Sdes } 246926026Sbrian 2470127094Sdes la->aliasAddress.s_addr = INADDR_ANY; 2471127094Sdes la->targetAddress.s_addr = INADDR_ANY; 247226026Sbrian 2473127094Sdes la->icmpLinkCount = 0; 2474127094Sdes la->udpLinkCount = 0; 2475127094Sdes la->tcpLinkCount = 0; 2476127094Sdes la->pptpLinkCount = 0; 2477127094Sdes la->protoLinkCount = 0; 2478127094Sdes la->fragmentIdLinkCount = 0; 2479127094Sdes la->fragmentPtrLinkCount = 0; 2480127094Sdes la->sockCount = 0; 248126026Sbrian 2482127094Sdes la->cleanupIndex = 0; 2483127094Sdes 2484127094Sdes la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2485145926Sglebius#ifndef NO_USE_SOCKETS 2486127094Sdes | PKT_ALIAS_USE_SOCKETS 2487145926Sglebius#endif 2488127094Sdes | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2489124621Sphk#ifndef NO_FW_PUNCH 2490127094Sdes la->fireWallFD = -1; 2491124621Sphk#endif 2492127094Sdes return (la); 249326026Sbrian} 249426026Sbrian 249532377Seivindvoid 2496127094SdesLibAliasUninit(struct libalias *la) 2497127094Sdes{ 2498127094Sdes la->deleteAllLinks = 1; 2499127094Sdes CleanupAliasData(la); 2500127094Sdes la->deleteAllLinks = 0; 2501145925Sglebius#ifndef NO_LOGGING 2502127094Sdes UninitPacketAliasLog(la); 2503145925Sglebius#endif 250435314Sbrian#ifndef NO_FW_PUNCH 2505127094Sdes UninitPunchFW(la); 250635314Sbrian#endif 2507127094Sdes LIST_REMOVE(la, instancelist); 2508127094Sdes free(la); 250932377Seivind} 251026026Sbrian 251126026Sbrian/* Change mode for some operations */ 251226026Sbrianunsigned int 2513124621SphkLibAliasSetMode( 2514124621Sphk struct libalias *la, 2515127094Sdes unsigned int flags, /* Which state to bring flags to */ 2516127094Sdes unsigned int mask /* Mask of which flags to affect (use 0 to 2517127094Sdes * do a probe for flag values) */ 251826026Sbrian) 251926026Sbrian{ 2520145925Sglebius#ifndef NO_LOGGING 252126026Sbrian/* Enable logging? */ 2522127094Sdes if (flags & mask & PKT_ALIAS_LOG) { 2523127094Sdes InitPacketAliasLog(la); /* Do the enable */ 2524127094Sdes } else 252526026Sbrian/* _Disable_ logging? */ 2526127094Sdes if (~flags & mask & PKT_ALIAS_LOG) { 2527127094Sdes UninitPacketAliasLog(la); 2528127094Sdes } 2529145925Sglebius#endif 253035314Sbrian#ifndef NO_FW_PUNCH 253132377Seivind/* Start punching holes in the firewall? */ 2532127094Sdes if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2533127094Sdes InitPunchFW(la); 2534127094Sdes } else 253532377Seivind/* Stop punching holes in the firewall? */ 2536127094Sdes if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2537127094Sdes UninitPunchFW(la); 2538127094Sdes } 253935314Sbrian#endif 254032377Seivind 254126026Sbrian/* Other flags can be set/cleared without special action */ 2542127094Sdes la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2543131613Sdes return (la->packetAliasMode); 254426026Sbrian} 254526026Sbrian 254626026Sbrian 254727864Sbrianint 2548124621SphkLibAliasCheckNewLink(struct libalias *la) 254927864Sbrian{ 2550131613Sdes return (la->newDefaultLink); 255127864Sbrian} 255232377Seivind 255332377Seivind 255435314Sbrian#ifndef NO_FW_PUNCH 255535314Sbrian 255632377Seivind/***************** 255732377Seivind Code to support firewall punching. This shouldn't really be in this 255832377Seivind file, but making variables global is evil too. 255932377Seivind ****************/ 256032377Seivind 256132377Seivind/* Firewall include files */ 256232392Sjkh#include <net/if.h> 256332377Seivind#include <netinet/ip_fw.h> 256432377Seivind#include <string.h> 256532377Seivind#include <err.h> 256632377Seivind 256798943Sluigi/* 256898943Sluigi * helper function, updates the pointer to cmd with the length 256998943Sluigi * of the current command, and also cleans up the first word of 257098943Sluigi * the new command in case it has been clobbered before. 257198943Sluigi */ 257298943Sluigistatic ipfw_insn * 2573127094Sdesnext_cmd(ipfw_insn * cmd) 257498943Sluigi{ 2575127094Sdes cmd += F_LEN(cmd); 2576127094Sdes bzero(cmd, sizeof(*cmd)); 2577131613Sdes return (cmd); 257898943Sluigi} 257998943Sluigi 258099623Sluigi/* 258199623Sluigi * A function to fill simple commands of size 1. 258299623Sluigi * Existing flags are preserved. 258399623Sluigi */ 258499623Sluigistatic ipfw_insn * 2585127094Sdesfill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2586127094Sdes int flags, u_int16_t arg) 258798943Sluigi{ 2588127094Sdes cmd->opcode = opcode; 2589127094Sdes cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2590127094Sdes cmd->arg1 = arg; 2591127094Sdes return next_cmd(cmd); 259299623Sluigi} 259399623Sluigi 259499623Sluigistatic ipfw_insn * 2595127094Sdesfill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 259699623Sluigi{ 2597127094Sdes ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 259899623Sluigi 2599127094Sdes cmd->addr.s_addr = addr; 2600127094Sdes return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 260198943Sluigi} 260298943Sluigi 260399623Sluigistatic ipfw_insn * 2604127094Sdesfill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 260598943Sluigi{ 2606127094Sdes ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 260799623Sluigi 2608127094Sdes cmd->ports[0] = cmd->ports[1] = port; 2609127094Sdes return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 261098943Sluigi} 261198943Sluigi 261298943Sluigistatic int 261398943Sluigifill_rule(void *buf, int bufsize, int rulenum, 2614127094Sdes enum ipfw_opcodes action, int proto, 2615127094Sdes struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 261698943Sluigi{ 2617127094Sdes struct ip_fw *rule = (struct ip_fw *)buf; 2618127094Sdes ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 261998943Sluigi 2620127094Sdes bzero(buf, bufsize); 2621127094Sdes rule->rulenum = rulenum; 262298943Sluigi 2623127094Sdes cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2624127094Sdes cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2625127094Sdes cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2626127094Sdes cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2627127094Sdes cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 262898943Sluigi 2629127094Sdes rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2630127094Sdes cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 263199207Sbrian 2632127094Sdes rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 263398943Sluigi 2634127094Sdes return ((char *)cmd - (char *)buf); 263598943Sluigi} 263698943Sluigi 2637127094Sdesstatic void ClearAllFWHoles(struct libalias *la); 263832377Seivind 2639127094Sdes 2640124621Sphk#define fw_setfield(la, field, num) \ 264132377Seivinddo { \ 2642124621Sphk (field)[(num) - la->fireWallBaseNum] = 1; \ 2643127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */ 2644124621Sphk 2645124621Sphk#define fw_clrfield(la, field, num) \ 264632377Seivinddo { \ 2647124621Sphk (field)[(num) - la->fireWallBaseNum] = 0; \ 2648127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */ 264932377Seivind 2650124621Sphk#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2651124621Sphk 265232377Seivindstatic void 2653124621SphkInitPunchFW(struct libalias *la) 2654124621Sphk{ 2655124621Sphk 2656127094Sdes la->fireWallField = malloc(la->fireWallNumNums); 2657127094Sdes if (la->fireWallField) { 2658127094Sdes memset(la->fireWallField, 0, la->fireWallNumNums); 2659127094Sdes if (la->fireWallFD < 0) { 2660127094Sdes la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2661127094Sdes } 2662127094Sdes ClearAllFWHoles(la); 2663127094Sdes la->fireWallActiveNum = la->fireWallBaseNum; 2664127094Sdes } 266532377Seivind} 266632377Seivind 266732377Seivindstatic void 2668124621SphkUninitPunchFW(struct libalias *la) 2669124621Sphk{ 2670127094Sdes ClearAllFWHoles(la); 2671127094Sdes if (la->fireWallFD >= 0) 2672127094Sdes close(la->fireWallFD); 2673127094Sdes la->fireWallFD = -1; 2674127094Sdes if (la->fireWallField) 2675127094Sdes free(la->fireWallField); 2676127094Sdes la->fireWallField = NULL; 2677127094Sdes la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 267832377Seivind} 267932377Seivind 268032377Seivind/* Make a certain link go through the firewall */ 268132377Seivindvoid 2682131614SdesPunchFWHole(struct alias_link *lnk) 2683124621Sphk{ 2684127094Sdes struct libalias *la; 2685127094Sdes int r; /* Result code */ 2686127094Sdes struct ip_fw rule; /* On-the-fly built rule */ 2687127094Sdes int fwhole; /* Where to punch hole */ 268832377Seivind 2689131614Sdes la = lnk->la; 2690124621Sphk 269132377Seivind/* Don't do anything unless we are asked to */ 2692127094Sdes if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2693127094Sdes la->fireWallFD < 0 || 2694131614Sdes lnk->link_type != LINK_TCP) 2695127094Sdes return; 269632377Seivind 2697127094Sdes memset(&rule, 0, sizeof rule); 269832377Seivind 269932377Seivind/** Build rule **/ 270032377Seivind 2701127094Sdes /* Find empty slot */ 2702127094Sdes for (fwhole = la->fireWallActiveNum; 2703127094Sdes fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2704127094Sdes fw_tstfield(la, la->fireWallField, fwhole); 2705127094Sdes fwhole++); 2706127094Sdes if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2707127094Sdes for (fwhole = la->fireWallBaseNum; 2708127094Sdes fwhole < la->fireWallActiveNum && 2709127094Sdes fw_tstfield(la, la->fireWallField, fwhole); 2710127094Sdes fwhole++); 2711127094Sdes if (fwhole == la->fireWallActiveNum) { 2712127094Sdes /* No rule point empty - we can't punch more holes. */ 2713127094Sdes la->fireWallActiveNum = la->fireWallBaseNum; 2714145961Sglebius#ifdef LIBALIAS_DEBUG 2715127094Sdes fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 271644616Sbrian#endif 2717127094Sdes return; 2718127094Sdes } 2719127094Sdes } 2720127094Sdes /* Start next search at next position */ 2721127094Sdes la->fireWallActiveNum = fwhole + 1; 272232377Seivind 2723127094Sdes /* 2724127094Sdes * generate two rules of the form 2725131612Sdes * 2726127094Sdes * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2727127094Sdes * accept tcp from DAddr DPort to OAddr OPort 2728127094Sdes */ 2729131614Sdes if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2730127094Sdes u_int32_t rulebuf[255]; 2731127094Sdes int i; 273298943Sluigi 2733127094Sdes i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2734127094Sdes O_ACCEPT, IPPROTO_TCP, 2735131614Sdes GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2736131614Sdes GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2737127094Sdes r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2738127094Sdes if (r) 2739127094Sdes err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 274098943Sluigi 2741127094Sdes i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2742127094Sdes O_ACCEPT, IPPROTO_TCP, 2743131614Sdes GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2744131614Sdes GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2745127094Sdes r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2746127094Sdes if (r) 2747127094Sdes err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2748127094Sdes } 274998943Sluigi 275032377Seivind/* Indicate hole applied */ 2751131614Sdes lnk->data.tcp->fwhole = fwhole; 2752127094Sdes fw_setfield(la, la->fireWallField, fwhole); 275332377Seivind} 275432377Seivind 275532377Seivind/* Remove a hole in a firewall associated with a particular alias 2756131614Sdes lnk. Calling this too often is harmless. */ 275732377Seivindstatic void 2758131614SdesClearFWHole(struct alias_link *lnk) 2759124621Sphk{ 2760124621Sphk 2761127094Sdes struct libalias *la; 2762124621Sphk 2763131614Sdes la = lnk->la; 2764131614Sdes if (lnk->link_type == LINK_TCP) { 2765131614Sdes int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall 2766127094Sdes * hole? */ 2767127094Sdes struct ip_fw rule; 276832377Seivind 2769127094Sdes if (fwhole < 0) 2770127094Sdes return; 277132377Seivind 2772127094Sdes memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2773127094Sdes while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2774127094Sdes &fwhole, sizeof fwhole)); 2775127094Sdes fw_clrfield(la, la->fireWallField, fwhole); 2776131614Sdes lnk->data.tcp->fwhole = -1; 2777127094Sdes } 277832377Seivind} 277932377Seivind 278032377Seivind/* Clear out the entire range dedicated to firewall holes. */ 278132377Seivindstatic void 2782127094SdesClearAllFWHoles(struct libalias *la) 2783127094Sdes{ 2784127094Sdes struct ip_fw rule; /* On-the-fly built rule */ 2785127094Sdes int i; 278699207Sbrian 2787127094Sdes if (la->fireWallFD < 0) 2788127094Sdes return; 278932377Seivind 2790127094Sdes memset(&rule, 0, sizeof rule); 2791127094Sdes for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2792127094Sdes int r = i; 2793127094Sdes 2794127094Sdes while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2795127094Sdes } 2796127094Sdes /* XXX: third arg correct here ? /phk */ 2797127094Sdes memset(la->fireWallField, 0, la->fireWallNumNums); 279832377Seivind} 2799127094Sdes 280035314Sbrian#endif 280174778Sbrian 280274778Sbrianvoid 2803127094SdesLibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2804127094Sdes{ 280574778Sbrian#ifndef NO_FW_PUNCH 2806127094Sdes la->fireWallBaseNum = base; 2807127094Sdes la->fireWallNumNums = num; 280874778Sbrian#endif 280974778Sbrian} 2810120372Smarcus 2811120372Smarcusvoid 2812127094SdesLibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2813127094Sdes{ 2814127094Sdes la->skinnyPort = port; 2815120372Smarcus} 2816