alias_db.c revision 131613
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 131613 2004-07-05 10:55:23Z des $"); 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 14526026Sbrian 14626026Sbrian/* System include files */ 14751491Sbrian#include <errno.h> 14826026Sbrian#include <stdlib.h> 14926026Sbrian#include <stdio.h> 15026026Sbrian#include <unistd.h> 15144307Sbrian 15264643Sru#include <sys/queue.h> 15326026Sbrian#include <sys/socket.h> 15426026Sbrian#include <sys/time.h> 15526026Sbrian#include <sys/types.h> 15626026Sbrian 15726026Sbrian/* BSD network include files */ 15826026Sbrian#include <netinet/in_systm.h> 15926026Sbrian#include <netinet/in.h> 16026026Sbrian#include <netinet/ip.h> 16126026Sbrian#include <netinet/tcp.h> 16226026Sbrian#include <arpa/inet.h> 16326026Sbrian 16426026Sbrian#include "alias.h" 16526026Sbrian#include "alias_local.h" 16626026Sbrian 16726026Sbrian 168127094Sdesstatic LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); 16926026Sbrian 170124621Sphk 17126026Sbrian/* 17226026Sbrian Constants (note: constants are also defined 173131612Sdes near relevant functions or structs) 17426026Sbrian*/ 17526026Sbrian 17626026Sbrian/* Parameters used for cleanup of expired links */ 17744307Sbrian#define ALIAS_CLEANUP_INTERVAL_SECS 60 17826026Sbrian#define ALIAS_CLEANUP_MAX_SPOKES 30 17926026Sbrian 18051494Sru/* Timeouts (in seconds) for different link types */ 18126026Sbrian#define ICMP_EXPIRE_TIME 60 18226026Sbrian#define UDP_EXPIRE_TIME 60 18359726Sru#define PROTO_EXPIRE_TIME 60 18426026Sbrian#define FRAGMENT_ID_EXPIRE_TIME 10 18526026Sbrian#define FRAGMENT_PTR_EXPIRE_TIME 30 18626026Sbrian 18732377Seivind/* TCP link expire time for different cases */ 18832377Seivind/* When the link has been used and closed - minimal grace time to 18932377Seivind allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 19032377Seivind#ifndef TCP_EXPIRE_DEAD 191127094Sdes#define TCP_EXPIRE_DEAD 10 19232377Seivind#endif 19332377Seivind 19432377Seivind/* When the link has been used and closed on one side - the other side 19532377Seivind is allowed to still send data */ 19632377Seivind#ifndef TCP_EXPIRE_SINGLEDEAD 197127094Sdes#define TCP_EXPIRE_SINGLEDEAD 90 19832377Seivind#endif 19932377Seivind 20032377Seivind/* When the link isn't yet up */ 20132377Seivind#ifndef TCP_EXPIRE_INITIAL 202127094Sdes#define TCP_EXPIRE_INITIAL 300 20332377Seivind#endif 20432377Seivind 20532377Seivind/* When the link is up */ 20632377Seivind#ifndef TCP_EXPIRE_CONNECTED 207127094Sdes#define TCP_EXPIRE_CONNECTED 86400 20832377Seivind#endif 20932377Seivind 21032377Seivind 21126026Sbrian/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 21226026Sbrian These constants can be anything except zero, which indicates an 21344307Sbrian unknown port number. */ 21426026Sbrian 21526026Sbrian#define NO_DEST_PORT 1 21626026Sbrian#define NO_SRC_PORT 1 21726026Sbrian 21826026Sbrian 21926026Sbrian 22044307Sbrian/* Data Structures 22126026Sbrian 22226026Sbrian The fundamental data structure used in this program is 22326026Sbrian "struct alias_link". Whenever a TCP connection is made, 22426026Sbrian a UDP datagram is sent out, or an ICMP echo request is made, 22526026Sbrian a link record is made (if it has not already been created). 22626026Sbrian The link record is identified by the source address/port 22726026Sbrian and the destination address/port. In the case of an ICMP 22826026Sbrian echo request, the source port is treated as being equivalent 22959356Sru with the 16-bit ID number of the ICMP packet. 23026026Sbrian 23126026Sbrian The link record also can store some auxiliary data. For 23226026Sbrian TCP connections that have had sequence and acknowledgment 23326026Sbrian modifications, data space is available to track these changes. 23459356Sru A state field is used to keep track in changes to the TCP 23559356Sru connection state. ID numbers of fragments can also be 23626026Sbrian stored in the auxiliary space. Pointers to unresolved 23759356Sru fragments can also be stored. 23826026Sbrian 23926026Sbrian The link records support two independent chainings. Lookup 24026026Sbrian tables for input and out tables hold the initial pointers 24126026Sbrian the link chains. On input, the lookup table indexes on alias 24226026Sbrian port and link type. On output, the lookup table indexes on 24359356Sru source address, destination address, source port, destination 24426026Sbrian port and link type. 24526026Sbrian*/ 24626026Sbrian 247127094Sdesstruct ack_data_record { /* used to save changes to ACK/sequence 248127094Sdes * numbers */ 249127094Sdes u_long ack_old; 250127094Sdes u_long ack_new; 251127094Sdes int delta; 252127094Sdes int active; 25326026Sbrian}; 25426026Sbrian 255127094Sdesstruct tcp_state { /* Information about TCP connection */ 256127094Sdes int in; /* State for outside -> inside */ 257127094Sdes int out; /* State for inside -> outside */ 258127094Sdes int index; /* Index to ACK data array */ 259127094Sdes int ack_modified; /* Indicates whether ACK and 260127094Sdes * sequence numbers */ 261127094Sdes /* been modified */ 26226026Sbrian}; 26326026Sbrian 264127094Sdes#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 265127094Sdes * saved for a modified TCP stream */ 266127094Sdesstruct tcp_dat { 267127094Sdes struct tcp_state state; 268127094Sdes struct ack_data_record ack[N_LINK_TCP_DATA]; 269127094Sdes int fwhole; /* Which firewall record is used for this 270127094Sdes * hole? */ 27126026Sbrian}; 27226026Sbrian 273127094Sdesstruct server { /* LSNAT server pool (circular list) */ 274127094Sdes struct in_addr addr; 275127094Sdes u_short port; 276127094Sdes struct server *next; 27759702Sru}; 27859702Sru 279127094Sdesstruct alias_link { /* Main data structure */ 280127094Sdes struct libalias *la; 281127094Sdes struct in_addr src_addr; /* Address and port information */ 282127094Sdes struct in_addr dst_addr; 283127094Sdes struct in_addr alias_addr; 284127094Sdes struct in_addr proxy_addr; 285127094Sdes u_short src_port; 286127094Sdes u_short dst_port; 287127094Sdes u_short alias_port; 288127094Sdes u_short proxy_port; 289127094Sdes struct server *server; 29026026Sbrian 291127094Sdes int link_type; /* Type of link: TCP, UDP, ICMP, 292127094Sdes * proto, frag */ 29326026Sbrian 29426026Sbrian/* values for link_type */ 29559726Sru#define LINK_ICMP IPPROTO_ICMP 29659726Sru#define LINK_UDP IPPROTO_UDP 29759726Sru#define LINK_TCP IPPROTO_TCP 29859726Sru#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 29959726Sru#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 30059726Sru#define LINK_ADDR (IPPROTO_MAX + 3) 30161861Sru#define LINK_PPTP (IPPROTO_MAX + 4) 30226026Sbrian 303127094Sdes int flags; /* indicates special characteristics */ 304127094Sdes int pflags; /* protocol-specific flags */ 30526026Sbrian 30626026Sbrian/* flag bits */ 30726026Sbrian#define LINK_UNKNOWN_DEST_PORT 0x01 30826026Sbrian#define LINK_UNKNOWN_DEST_ADDR 0x02 30926026Sbrian#define LINK_PERMANENT 0x04 310127094Sdes#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 31132377Seivind#define LINK_UNFIREWALLED 0x08 31226026Sbrian 313127094Sdes int timestamp; /* Time link was last accessed */ 314127094Sdes int expire_time; /* Expire time for link */ 31526026Sbrian 316127094Sdes int sockfd; /* socket descriptor */ 31726026Sbrian 318127094Sdes LIST_ENTRY (alias_link) list_out; /* Linked list of 319127094Sdes * pointers for */ 320127094Sdes LIST_ENTRY (alias_link) list_in; /* input and output 321127094Sdes * lookup tables */ 32226026Sbrian 323127094Sdes union { /* Auxiliary data */ 324127094Sdes char *frag_ptr; 325127094Sdes struct in_addr frag_addr; 326127094Sdes struct tcp_dat *tcp; 327127094Sdes } data; 32826026Sbrian}; 32926026Sbrian 33026026Sbrian/* Internal utility routines (used only in alias_db.c) 33126026Sbrian 33226026SbrianLookup table starting points: 33326026Sbrian StartPointIn() -- link table initial search point for 334131612Sdes incoming packets 33559356Sru StartPointOut() -- link table initial search point for 336131612Sdes outgoing packets 33799207Sbrian 33826026SbrianMiscellaneous: 33926026Sbrian SeqDiff() -- difference between two TCP sequences 34026026Sbrian ShowAliasStats() -- send alias statistics to a monitor file 34126026Sbrian*/ 34226026Sbrian 34326026Sbrian 34426026Sbrian/* Local prototypes */ 345127094Sdesstatic u_int StartPointIn(struct in_addr, u_short, int); 34626026Sbrian 347127094Sdesstatic u_int 348127094SdesStartPointOut(struct in_addr, struct in_addr, 349127094Sdes u_short, u_short, int); 35026026Sbrian 351127094Sdesstatic int SeqDiff(u_long, u_long); 35226026Sbrian 353127094Sdesstatic void ShowAliasStats(struct libalias *); 35426026Sbrian 35535314Sbrian#ifndef NO_FW_PUNCH 35632377Seivind/* Firewall control */ 357127094Sdesstatic void InitPunchFW(struct libalias *la); 358127094Sdesstatic void UninitPunchFW(struct libalias *la); 359127094Sdesstatic void ClearFWHole(struct alias_link *link); 360127094Sdes 36135314Sbrian#endif 36226026Sbrian 36332377Seivind/* Log file control */ 364127094Sdesstatic void InitPacketAliasLog(struct libalias *la); 365127094Sdesstatic void UninitPacketAliasLog(struct libalias *la); 36632377Seivind 367127094Sdesstatic u_int 36826026SbrianStartPointIn(struct in_addr alias_addr, 369127094Sdes u_short alias_port, 370127094Sdes int link_type) 37126026Sbrian{ 372127094Sdes u_int n; 37326026Sbrian 374127094Sdes n = alias_addr.s_addr; 375127094Sdes if (link_type != LINK_PPTP) 376127094Sdes n += alias_port; 377127094Sdes n += link_type; 378127094Sdes return (n % LINK_TABLE_IN_SIZE); 37926026Sbrian} 38026026Sbrian 38126026Sbrian 382127094Sdesstatic u_int 38326026SbrianStartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 384127094Sdes u_short src_port, u_short dst_port, int link_type) 38526026Sbrian{ 386127094Sdes u_int n; 38726026Sbrian 388127094Sdes n = src_addr.s_addr; 389127094Sdes n += dst_addr.s_addr; 390127094Sdes if (link_type != LINK_PPTP) { 391127094Sdes n += src_port; 392127094Sdes n += dst_port; 393127094Sdes } 394127094Sdes n += link_type; 39526026Sbrian 396127094Sdes return (n % LINK_TABLE_OUT_SIZE); 39726026Sbrian} 39826026Sbrian 39926026Sbrian 40026026Sbrianstatic int 40126026SbrianSeqDiff(u_long x, u_long y) 40226026Sbrian{ 40326026Sbrian/* Return the difference between two TCP sequence numbers */ 40426026Sbrian 40526026Sbrian/* 40626026Sbrian This function is encapsulated in case there are any unusual 40726026Sbrian arithmetic conditions that need to be considered. 40826026Sbrian*/ 40926026Sbrian 410127094Sdes return (ntohl(y) - ntohl(x)); 41126026Sbrian} 41226026Sbrian 41326026Sbrian 41426026Sbrianstatic void 415124621SphkShowAliasStats(struct libalias *la) 41626026Sbrian{ 41726026Sbrian/* Used for debugging */ 41826026Sbrian 419127094Sdes if (la->monitorFile) { 420127094Sdes fprintf(la->monitorFile, 421127094Sdes "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", 422127094Sdes la->icmpLinkCount, 423127094Sdes la->udpLinkCount, 424127094Sdes la->tcpLinkCount, 425127094Sdes la->pptpLinkCount, 426127094Sdes la->protoLinkCount, 427127094Sdes la->fragmentIdLinkCount, 428127094Sdes la->fragmentPtrLinkCount); 42926026Sbrian 430127094Sdes fprintf(la->monitorFile, " / tot=%d (sock=%d)\n", 431127094Sdes la->icmpLinkCount + la->udpLinkCount 432127094Sdes + la->tcpLinkCount 433127094Sdes + la->pptpLinkCount 434127094Sdes + la->protoLinkCount 435127094Sdes + la->fragmentIdLinkCount 436127094Sdes + la->fragmentPtrLinkCount, 437127094Sdes la->sockCount); 43826026Sbrian 439127094Sdes fflush(la->monitorFile); 440127094Sdes } 44126026Sbrian} 44226026Sbrian 44326026Sbrian 44426026Sbrian 44526026Sbrian 44626026Sbrian 44726026Sbrian/* Internal routines for finding, deleting and adding links 44826026Sbrian 44926026SbrianPort Allocation: 45026026Sbrian GetNewPort() -- find and reserve new alias port number 45126026Sbrian GetSocket() -- try to allocate a socket for a given port 45226026Sbrian 45326026SbrianLink creation and deletion: 45426026Sbrian CleanupAliasData() - remove all link chains from lookup table 45526026Sbrian IncrementalCleanup() - look for stale links in a single chain 45626026Sbrian DeleteLink() - remove link 45799207Sbrian AddLink() - add link 45899207Sbrian ReLink() - change link 45926026Sbrian 46026026SbrianLink search: 46126026Sbrian FindLinkOut() - find link for outgoing packets 46226026Sbrian FindLinkIn() - find link for incoming packets 46363899Sarchie 46463899SarchiePort search: 46599207Sbrian FindNewPortGroup() - find an available group of ports 46626026Sbrian*/ 46726026Sbrian 46826026Sbrian/* Local prototypes */ 469127094Sdesstatic int GetNewPort(struct libalias *, struct alias_link *, int); 47026026Sbrian 471127094Sdesstatic u_short GetSocket(struct libalias *, u_short, int *, int); 47226026Sbrian 473127094Sdesstatic void CleanupAliasData(struct libalias *); 47426026Sbrian 475127094Sdesstatic void IncrementalCleanup(struct libalias *); 47626026Sbrian 477127094Sdesstatic void DeleteLink(struct alias_link *); 47826026Sbrian 47926026Sbrianstatic struct alias_link * 480124621SphkAddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr, 481127094Sdes u_short, u_short, int, int); 48226026Sbrian 48326026Sbrianstatic struct alias_link * 48432377SeivindReLink(struct alias_link *, 485127094Sdes struct in_addr, struct in_addr, struct in_addr, 486127094Sdes u_short, u_short, int, int); 48732377Seivind 48832377Seivindstatic struct alias_link * 489127094Sdes FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 49026026Sbrian 49126026Sbrianstatic struct alias_link * 492127094Sdes FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 49326026Sbrian 49426026Sbrian 49526026Sbrian#define ALIAS_PORT_BASE 0x08000 49626026Sbrian#define ALIAS_PORT_MASK 0x07fff 49763899Sarchie#define ALIAS_PORT_MASK_EVEN 0x07ffe 49826026Sbrian#define GET_NEW_PORT_MAX_ATTEMPTS 20 49926026Sbrian 50026026Sbrian#define GET_ALIAS_PORT -1 50126026Sbrian#define GET_ALIAS_ID GET_ALIAS_PORT 50226026Sbrian 50363899Sarchie#define FIND_EVEN_ALIAS_BASE 1 50463899Sarchie 50526026Sbrian/* GetNewPort() allocates port numbers. Note that if a port number 50626026Sbrian is already in use, that does not mean that it cannot be used by 50726026Sbrian another link concurrently. This is because GetNewPort() looks for 50826026Sbrian unused triplets: (dest addr, dest port, alias port). */ 50926026Sbrian 51026026Sbrianstatic int 511124621SphkGetNewPort(struct libalias *la, struct alias_link *link, int alias_port_param) 51226026Sbrian{ 513127094Sdes int i; 514127094Sdes int max_trials; 515127094Sdes u_short port_sys; 516127094Sdes u_short port_net; 51726026Sbrian 51826026Sbrian/* 51926026Sbrian Description of alias_port_param for GetNewPort(). When 52026026Sbrian this parameter is zero or positive, it precisely specifies 52126026Sbrian the port number. GetNewPort() will return this number 52226026Sbrian without check that it is in use. 52326026Sbrian 52461861Sru When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 52526026Sbrian selected port number. 52626026Sbrian*/ 52799207Sbrian 528127094Sdes if (alias_port_param == GET_ALIAS_PORT) { 529127094Sdes /* 530127094Sdes * The aliasing port is automatically selected by one of 531127094Sdes * two methods below: 532127094Sdes */ 533127094Sdes max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 53426026Sbrian 535127094Sdes if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 536127094Sdes /* 537127094Sdes * When the PKT_ALIAS_SAME_PORTS option is chosen, 538127094Sdes * the first try will be the actual source port. If 539127094Sdes * this is already in use, the remainder of the 540127094Sdes * trials will be random. 541127094Sdes */ 542127094Sdes port_net = link->src_port; 543127094Sdes port_sys = ntohs(port_net); 544127094Sdes } else { 545127094Sdes /* First trial and all subsequent are random. */ 546127094Sdes port_sys = random() & ALIAS_PORT_MASK; 547127094Sdes port_sys += ALIAS_PORT_BASE; 548127094Sdes port_net = htons(port_sys); 549127094Sdes } 550127094Sdes } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { 551127094Sdes link->alias_port = (u_short) alias_port_param; 552127094Sdes return (0); 553127094Sdes } else { 55444616Sbrian#ifdef DEBUG 555127094Sdes fprintf(stderr, "PacketAlias/GetNewPort(): "); 556127094Sdes fprintf(stderr, "input parameter error\n"); 55744616Sbrian#endif 558127094Sdes return (-1); 559127094Sdes } 56026026Sbrian 56126026Sbrian 56226026Sbrian/* Port number search */ 563127094Sdes for (i = 0; i < max_trials; i++) { 564127094Sdes int go_ahead; 565127094Sdes struct alias_link *search_result; 56626026Sbrian 567127094Sdes search_result = FindLinkIn(la, link->dst_addr, link->alias_addr, 568127094Sdes link->dst_port, port_net, 569127094Sdes link->link_type, 0); 57026026Sbrian 571127094Sdes if (search_result == NULL) 572127094Sdes go_ahead = 1; 573127094Sdes else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 574127094Sdes && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 575127094Sdes go_ahead = 1; 576127094Sdes else 577127094Sdes go_ahead = 0; 57826026Sbrian 579127094Sdes if (go_ahead) { 580127094Sdes if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) 581127094Sdes && (link->flags & LINK_PARTIALLY_SPECIFIED) 582127094Sdes && ((link->link_type == LINK_TCP) || 583127094Sdes (link->link_type == LINK_UDP))) { 584127094Sdes if (GetSocket(la, port_net, &link->sockfd, link->link_type)) { 585127094Sdes link->alias_port = port_net; 586127094Sdes return (0); 587127094Sdes } 588127094Sdes } else { 589127094Sdes link->alias_port = port_net; 590127094Sdes return (0); 591127094Sdes } 592127094Sdes } 593127094Sdes port_sys = random() & ALIAS_PORT_MASK; 594127094Sdes port_sys += ALIAS_PORT_BASE; 595127094Sdes port_net = htons(port_sys); 596127094Sdes } 59726026Sbrian 59844616Sbrian#ifdef DEBUG 599127094Sdes fprintf(stderr, "PacketAlias/GetnewPort(): "); 600127094Sdes fprintf(stderr, "could not find free port\n"); 60144616Sbrian#endif 60226026Sbrian 603127094Sdes return (-1); 60426026Sbrian} 60526026Sbrian 60626026Sbrian 607127094Sdesstatic u_short 608124621SphkGetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type) 60926026Sbrian{ 610127094Sdes int err; 611127094Sdes int sock; 612127094Sdes struct sockaddr_in sock_addr; 61326026Sbrian 614127094Sdes if (link_type == LINK_TCP) 615127094Sdes sock = socket(AF_INET, SOCK_STREAM, 0); 616127094Sdes else if (link_type == LINK_UDP) 617127094Sdes sock = socket(AF_INET, SOCK_DGRAM, 0); 618127094Sdes else { 61944616Sbrian#ifdef DEBUG 620127094Sdes fprintf(stderr, "PacketAlias/GetSocket(): "); 621127094Sdes fprintf(stderr, "incorrect link type\n"); 62244616Sbrian#endif 623127094Sdes return (0); 624127094Sdes } 62526026Sbrian 626127094Sdes if (sock < 0) { 62744616Sbrian#ifdef DEBUG 628127094Sdes fprintf(stderr, "PacketAlias/GetSocket(): "); 629127094Sdes fprintf(stderr, "socket() error %d\n", *sockfd); 63044616Sbrian#endif 631127094Sdes return (0); 632127094Sdes } 633127094Sdes sock_addr.sin_family = AF_INET; 634127094Sdes sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 635127094Sdes sock_addr.sin_port = port_net; 63626026Sbrian 637127094Sdes err = bind(sock, 638127094Sdes (struct sockaddr *)&sock_addr, 639127094Sdes sizeof(sock_addr)); 640127094Sdes if (err == 0) { 641127094Sdes la->sockCount++; 642127094Sdes *sockfd = sock; 643127094Sdes return (1); 644127094Sdes } else { 645127094Sdes close(sock); 646127094Sdes return (0); 647127094Sdes } 64826026Sbrian} 64926026Sbrian 65026026Sbrian 65199207Sbrian/* FindNewPortGroup() returns a base port number for an available 65263899Sarchie range of contiguous port numbers. Note that if a port number 65363899Sarchie is already in use, that does not mean that it cannot be used by 65463899Sarchie another link concurrently. This is because FindNewPortGroup() 65563899Sarchie looks for unused triplets: (dest addr, dest port, alias port). */ 65663899Sarchie 65763899Sarchieint 658124621SphkFindNewPortGroup(struct libalias *la, 659127094Sdes struct in_addr dst_addr, 660127094Sdes struct in_addr alias_addr, 661127094Sdes u_short src_port, 662127094Sdes u_short dst_port, 663127094Sdes u_short port_count, 664127094Sdes u_char proto, 665127094Sdes u_char align) 66663899Sarchie{ 667127094Sdes int i, j; 668127094Sdes int max_trials; 669127094Sdes u_short port_sys; 670127094Sdes int link_type; 67163899Sarchie 672127094Sdes /* 673127094Sdes * Get link_type from protocol 674127094Sdes */ 67563899Sarchie 676127094Sdes switch (proto) { 677127094Sdes case IPPROTO_UDP: 678127094Sdes link_type = LINK_UDP; 679127094Sdes break; 680127094Sdes case IPPROTO_TCP: 681127094Sdes link_type = LINK_TCP; 682127094Sdes break; 683127094Sdes default: 684127094Sdes return (0); 685127094Sdes break; 686127094Sdes } 68763899Sarchie 688127094Sdes /* 689127094Sdes * The aliasing port is automatically selected by one of two 690127094Sdes * methods below: 691127094Sdes */ 692127094Sdes max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 69363899Sarchie 694127094Sdes if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 695127094Sdes /* 696127094Sdes * When the ALIAS_SAME_PORTS option is chosen, the first 697127094Sdes * try will be the actual source port. If this is already 698127094Sdes * in use, the remainder of the trials will be random. 699127094Sdes */ 700127094Sdes port_sys = ntohs(src_port); 70163899Sarchie 702127094Sdes } else { 70363899Sarchie 704127094Sdes /* First trial and all subsequent are random. */ 705127094Sdes if (align == FIND_EVEN_ALIAS_BASE) 706127094Sdes port_sys = random() & ALIAS_PORT_MASK_EVEN; 707127094Sdes else 708127094Sdes port_sys = random() & ALIAS_PORT_MASK; 70963899Sarchie 710127094Sdes port_sys += ALIAS_PORT_BASE; 711127094Sdes } 71263899Sarchie 71363899Sarchie/* Port number search */ 714127094Sdes for (i = 0; i < max_trials; i++) { 71563899Sarchie 716127094Sdes struct alias_link *search_result; 71763899Sarchie 718127094Sdes for (j = 0; j < port_count; j++) 719127094Sdes if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr, 720127094Sdes dst_port, htons(port_sys + j), 721127094Sdes link_type, 0))) 722127094Sdes break; 72363899Sarchie 724127094Sdes /* Found a good range, return base */ 725127094Sdes if (j == port_count) 726127094Sdes return (htons(port_sys)); 72763899Sarchie 728127094Sdes /* Find a new base to try */ 729127094Sdes if (align == FIND_EVEN_ALIAS_BASE) 730127094Sdes port_sys = random() & ALIAS_PORT_MASK_EVEN; 731127094Sdes else 732127094Sdes port_sys = random() & ALIAS_PORT_MASK; 73363899Sarchie 734127094Sdes port_sys += ALIAS_PORT_BASE; 735127094Sdes } 73663899Sarchie 73763899Sarchie#ifdef DEBUG 738127094Sdes fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 739127094Sdes fprintf(stderr, "could not find free port(s)\n"); 74063899Sarchie#endif 74163899Sarchie 742127094Sdes return (0); 74363899Sarchie} 74463899Sarchie 74526026Sbrianstatic void 746124621SphkCleanupAliasData(struct libalias *la) 74726026Sbrian{ 748127094Sdes struct alias_link *link; 749127094Sdes int i, icount; 75026026Sbrian 751127094Sdes icount = 0; 752127094Sdes for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 753127094Sdes link = LIST_FIRST(&la->linkTableOut[i]); 754127094Sdes while (link != NULL) { 755127094Sdes struct alias_link *link_next; 75626026Sbrian 757127094Sdes link_next = LIST_NEXT(link, list_out); 758127094Sdes icount++; 759127094Sdes DeleteLink(link); 760127094Sdes link = link_next; 761127094Sdes } 762127094Sdes } 763127094Sdes 764127094Sdes la->cleanupIndex = 0; 76526026Sbrian} 76626026Sbrian 76726026Sbrian 76826026Sbrianstatic void 769124621SphkIncrementalCleanup(struct libalias *la) 77026026Sbrian{ 771127094Sdes int icount; 772127094Sdes struct alias_link *link; 77326026Sbrian 774127094Sdes icount = 0; 775127094Sdes link = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]); 776127094Sdes while (link != NULL) { 777127094Sdes int idelta; 778127094Sdes struct alias_link *link_next; 77926026Sbrian 780127094Sdes link_next = LIST_NEXT(link, list_out); 781127094Sdes idelta = la->timeStamp - link->timestamp; 782127094Sdes switch (link->link_type) { 783127094Sdes case LINK_TCP: 784127094Sdes if (idelta > link->expire_time) { 785127094Sdes struct tcp_dat *tcp_aux; 78626026Sbrian 787127094Sdes tcp_aux = link->data.tcp; 788127094Sdes if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 789127094Sdes || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) { 790127094Sdes DeleteLink(link); 791127094Sdes icount++; 792127094Sdes } 793127094Sdes } 794127094Sdes break; 795127094Sdes default: 796127094Sdes if (idelta > link->expire_time) { 797127094Sdes DeleteLink(link); 798127094Sdes icount++; 799127094Sdes } 800127094Sdes break; 801127094Sdes } 802127094Sdes link = link_next; 803127094Sdes } 80426026Sbrian 805127094Sdes if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) 806127094Sdes la->cleanupIndex = 0; 80726026Sbrian} 80826026Sbrian 80964643Srustatic void 81026026SbrianDeleteLink(struct alias_link *link) 81126026Sbrian{ 812127094Sdes struct libalias *la = link->la; 81326026Sbrian 81426026Sbrian/* Don't do anything if the link is marked permanent */ 815127094Sdes if (la->deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 816127094Sdes return; 81726026Sbrian 81835314Sbrian#ifndef NO_FW_PUNCH 81959356Sru/* Delete associated firewall hole, if any */ 820127094Sdes ClearFWHole(link); 82135314Sbrian#endif 82232377Seivind 82359702Sru/* Free memory allocated for LSNAT server pool */ 824127094Sdes if (link->server != NULL) { 825127094Sdes struct server *head, *curr, *next; 82659702Sru 827127094Sdes head = curr = link->server; 828127094Sdes do { 829127094Sdes next = curr->next; 830127094Sdes free(curr); 831127094Sdes } while ((curr = next) != head); 832127094Sdes } 83326026Sbrian/* Adjust output table pointers */ 834127094Sdes LIST_REMOVE(link, list_out); 83526026Sbrian 83626026Sbrian/* Adjust input table pointers */ 837127094Sdes LIST_REMOVE(link, list_in); 83826026Sbrian 83926026Sbrian/* Close socket, if one has been allocated */ 840127094Sdes if (link->sockfd != -1) { 841127094Sdes la->sockCount--; 842127094Sdes close(link->sockfd); 843127094Sdes } 84426026Sbrian/* Link-type dependent cleanup */ 845127094Sdes switch (link->link_type) { 846127094Sdes case LINK_ICMP: 847127094Sdes la->icmpLinkCount--; 848127094Sdes break; 849127094Sdes case LINK_UDP: 850127094Sdes la->udpLinkCount--; 851127094Sdes break; 852127094Sdes case LINK_TCP: 853127094Sdes la->tcpLinkCount--; 854127094Sdes free(link->data.tcp); 855127094Sdes break; 856127094Sdes case LINK_PPTP: 857127094Sdes la->pptpLinkCount--; 858127094Sdes break; 859127094Sdes case LINK_FRAGMENT_ID: 860127094Sdes la->fragmentIdLinkCount--; 861127094Sdes break; 862127094Sdes case LINK_FRAGMENT_PTR: 863127094Sdes la->fragmentPtrLinkCount--; 864127094Sdes if (link->data.frag_ptr != NULL) 865127094Sdes free(link->data.frag_ptr); 866127094Sdes break; 86759726Sru case LINK_ADDR: 868127094Sdes break; 869127094Sdes default: 870127094Sdes la->protoLinkCount--; 871127094Sdes break; 872127094Sdes } 87326026Sbrian 87426026Sbrian/* Free memory */ 875127094Sdes free(link); 87626026Sbrian 87726026Sbrian/* Write statistics, if logging enabled */ 878127094Sdes if (la->packetAliasMode & PKT_ALIAS_LOG) { 879127094Sdes ShowAliasStats(la); 880127094Sdes } 88126026Sbrian} 88226026Sbrian 88326026Sbrian 88426026Sbrianstatic struct alias_link * 885127094SdesAddLink(struct libalias *la, struct in_addr src_addr, 886127094Sdes struct in_addr dst_addr, 887127094Sdes struct in_addr alias_addr, 888127094Sdes u_short src_port, 889127094Sdes u_short dst_port, 890127094Sdes int alias_port_param, /* if less than zero, alias */ 891127094Sdes int link_type) 892127094Sdes{ /* port will be automatically *//* chosen. 893127094Sdes * If greater than */ 894127094Sdes u_int start_point; /* zero, equal to alias port */ 895127094Sdes struct alias_link *link; 89626026Sbrian 897127094Sdes link = malloc(sizeof(struct alias_link)); 898127094Sdes if (link != NULL) { 899127094Sdes /* Basic initialization */ 900127094Sdes link->la = la; 901127094Sdes link->src_addr = src_addr; 902127094Sdes link->dst_addr = dst_addr; 903127094Sdes link->alias_addr = alias_addr; 904127094Sdes link->proxy_addr.s_addr = INADDR_ANY; 905127094Sdes link->src_port = src_port; 906127094Sdes link->dst_port = dst_port; 907127094Sdes link->proxy_port = 0; 908127094Sdes link->server = NULL; 909127094Sdes link->link_type = link_type; 910127094Sdes link->sockfd = -1; 911127094Sdes link->flags = 0; 912127094Sdes link->pflags = 0; 913127094Sdes link->timestamp = la->timeStamp; 91426026Sbrian 915127094Sdes /* Expiration time */ 916127094Sdes switch (link_type) { 917127094Sdes case LINK_ICMP: 918127094Sdes link->expire_time = ICMP_EXPIRE_TIME; 919127094Sdes break; 920127094Sdes case LINK_UDP: 921127094Sdes link->expire_time = UDP_EXPIRE_TIME; 922127094Sdes break; 923127094Sdes case LINK_TCP: 924127094Sdes link->expire_time = TCP_EXPIRE_INITIAL; 925127094Sdes break; 926127094Sdes case LINK_PPTP: 927127094Sdes link->flags |= LINK_PERMANENT; /* no timeout. */ 928127094Sdes break; 929127094Sdes case LINK_FRAGMENT_ID: 930127094Sdes link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 931127094Sdes break; 932127094Sdes case LINK_FRAGMENT_PTR: 933127094Sdes link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 934127094Sdes break; 935127094Sdes case LINK_ADDR: 936127094Sdes break; 937127094Sdes default: 938127094Sdes link->expire_time = PROTO_EXPIRE_TIME; 939127094Sdes break; 940127094Sdes } 94126026Sbrian 942127094Sdes /* Determine alias flags */ 943127094Sdes if (dst_addr.s_addr == INADDR_ANY) 944127094Sdes link->flags |= LINK_UNKNOWN_DEST_ADDR; 945127094Sdes if (dst_port == 0) 946127094Sdes link->flags |= LINK_UNKNOWN_DEST_PORT; 94726026Sbrian 948127094Sdes /* Determine alias port */ 949127094Sdes if (GetNewPort(la, link, alias_port_param) != 0) { 950127094Sdes free(link); 951127094Sdes return (NULL); 952127094Sdes } 953127094Sdes /* Link-type dependent initialization */ 954127094Sdes switch (link_type) { 955127094Sdes struct tcp_dat *aux_tcp; 95626026Sbrian 957127094Sdes case LINK_ICMP: 958127094Sdes la->icmpLinkCount++; 959127094Sdes break; 960127094Sdes case LINK_UDP: 961127094Sdes la->udpLinkCount++; 962127094Sdes break; 963127094Sdes case LINK_TCP: 964127094Sdes aux_tcp = malloc(sizeof(struct tcp_dat)); 965127094Sdes if (aux_tcp != NULL) { 966127094Sdes int i; 96726026Sbrian 968127094Sdes la->tcpLinkCount++; 969127094Sdes aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 970127094Sdes aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 971127094Sdes aux_tcp->state.index = 0; 972127094Sdes aux_tcp->state.ack_modified = 0; 973127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) 974127094Sdes aux_tcp->ack[i].active = 0; 975127094Sdes aux_tcp->fwhole = -1; 976127094Sdes link->data.tcp = aux_tcp; 977127094Sdes } else { 97844616Sbrian#ifdef DEBUG 979127094Sdes fprintf(stderr, "PacketAlias/AddLink: "); 980127094Sdes fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 98144616Sbrian#endif 982127094Sdes free(link); 983127094Sdes return (NULL); 984127094Sdes } 985127094Sdes break; 986127094Sdes case LINK_PPTP: 987127094Sdes la->pptpLinkCount++; 988127094Sdes break; 989127094Sdes case LINK_FRAGMENT_ID: 990127094Sdes la->fragmentIdLinkCount++; 991127094Sdes break; 992127094Sdes case LINK_FRAGMENT_PTR: 993127094Sdes la->fragmentPtrLinkCount++; 994127094Sdes break; 995127094Sdes case LINK_ADDR: 996127094Sdes break; 997127094Sdes default: 998127094Sdes la->protoLinkCount++; 999127094Sdes break; 1000127094Sdes } 100167316Sru 1002127094Sdes /* Set up pointers for output lookup table */ 1003127094Sdes start_point = StartPointOut(src_addr, dst_addr, 1004127094Sdes src_port, dst_port, link_type); 1005127094Sdes LIST_INSERT_HEAD(&la->linkTableOut[start_point], link, list_out); 100667316Sru 1007127094Sdes /* Set up pointers for input lookup table */ 1008127094Sdes start_point = StartPointIn(alias_addr, link->alias_port, link_type); 1009127094Sdes LIST_INSERT_HEAD(&la->linkTableIn[start_point], link, list_in); 1010127094Sdes } else { 101144616Sbrian#ifdef DEBUG 1012127094Sdes fprintf(stderr, "PacketAlias/AddLink(): "); 1013127094Sdes fprintf(stderr, "malloc() call failed.\n"); 101444616Sbrian#endif 1015127094Sdes } 101626026Sbrian 1017127094Sdes if (la->packetAliasMode & PKT_ALIAS_LOG) { 1018127094Sdes ShowAliasStats(la); 1019127094Sdes } 1020127094Sdes return (link); 102126026Sbrian} 102226026Sbrian 102332377Seivindstatic struct alias_link * 102432377SeivindReLink(struct alias_link *old_link, 1025127094Sdes struct in_addr src_addr, 1026127094Sdes struct in_addr dst_addr, 1027127094Sdes struct in_addr alias_addr, 1028127094Sdes u_short src_port, 1029127094Sdes u_short dst_port, 1030127094Sdes int alias_port_param, /* if less than zero, alias */ 1031127094Sdes int link_type) 1032127094Sdes{ /* port will be automatically *//* chosen. 1033127094Sdes * If greater than */ 1034127094Sdes struct alias_link *new_link; /* zero, equal to alias port */ 1035127094Sdes struct libalias *la = old_link->la; 103626026Sbrian 1037127094Sdes new_link = AddLink(la, src_addr, dst_addr, alias_addr, 1038127094Sdes src_port, dst_port, alias_port_param, 1039127094Sdes link_type); 104035314Sbrian#ifndef NO_FW_PUNCH 1041127094Sdes if (new_link != NULL && 1042127094Sdes old_link->link_type == LINK_TCP && 1043127094Sdes old_link->data.tcp->fwhole > 0) { 1044127094Sdes PunchFWHole(new_link); 1045127094Sdes } 104635314Sbrian#endif 1047127094Sdes DeleteLink(old_link); 1048131613Sdes return (new_link); 104932377Seivind} 105032377Seivind 105126026Sbrianstatic struct alias_link * 1052124621Sphk_FindLinkOut(struct libalias *la, struct in_addr src_addr, 1053127094Sdes struct in_addr dst_addr, 1054127094Sdes u_short src_port, 1055127094Sdes u_short dst_port, 1056127094Sdes int link_type, 1057127094Sdes int replace_partial_links) 105826026Sbrian{ 1059127094Sdes u_int i; 1060127094Sdes struct alias_link *link; 106126026Sbrian 1062127094Sdes i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1063127094Sdes LIST_FOREACH(link, &la->linkTableOut[i], list_out) { 1064127094Sdes if (link->src_addr.s_addr == src_addr.s_addr 1065127094Sdes && link->server == NULL 1066127094Sdes && link->dst_addr.s_addr == dst_addr.s_addr 1067127094Sdes && link->dst_port == dst_port 1068127094Sdes && link->src_port == src_port 1069127094Sdes && link->link_type == link_type) { 1070127094Sdes link->timestamp = la->timeStamp; 1071127094Sdes break; 1072127094Sdes } 1073127094Sdes } 107426026Sbrian 107551494Sru/* Search for partially specified links. */ 1076127094Sdes if (link == NULL && replace_partial_links) { 1077127094Sdes if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1078127094Sdes link = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1079127094Sdes link_type, 0); 1080127094Sdes if (link == NULL) 1081127094Sdes link = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 1082127094Sdes dst_port, link_type, 0); 1083127094Sdes } 1084127094Sdes if (link == NULL && 1085127094Sdes (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1086127094Sdes link = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, 1087127094Sdes link_type, 0); 1088127094Sdes } 1089127094Sdes if (link != NULL) { 1090127094Sdes link = ReLink(link, 1091127094Sdes src_addr, dst_addr, link->alias_addr, 1092127094Sdes src_port, dst_port, link->alias_port, 1093127094Sdes link_type); 1094127094Sdes } 1095127094Sdes } 1096127094Sdes return (link); 109726026Sbrian} 109826026Sbrian 109951727Srustatic struct alias_link * 1100124621SphkFindLinkOut(struct libalias *la, struct in_addr src_addr, 1101127094Sdes struct in_addr dst_addr, 1102127094Sdes u_short src_port, 1103127094Sdes u_short dst_port, 1104127094Sdes int link_type, 1105127094Sdes int replace_partial_links) 110651727Sru{ 1107127094Sdes struct alias_link *link; 110826026Sbrian 1109127094Sdes link = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1110127094Sdes link_type, replace_partial_links); 111151727Sru 1112127094Sdes if (link == NULL) { 1113127094Sdes /* 1114127094Sdes * The following allows permanent links to be specified as 1115127094Sdes * using the default source address (i.e. device interface 1116127094Sdes * address) without knowing in advance what that address 1117127094Sdes * is. 1118127094Sdes */ 1119127094Sdes if (la->aliasAddress.s_addr != INADDR_ANY && 1120127094Sdes src_addr.s_addr == la->aliasAddress.s_addr) { 1121127094Sdes link = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, 1122127094Sdes link_type, replace_partial_links); 1123127094Sdes } 1124127094Sdes } 1125127094Sdes return (link); 112651727Sru} 112751727Sru 112851727Sru 112958279Sbrianstatic struct alias_link * 1130124621Sphk_FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1131127094Sdes struct in_addr alias_addr, 1132127094Sdes u_short dst_port, 1133127094Sdes u_short alias_port, 1134127094Sdes int link_type, 1135127094Sdes int replace_partial_links) 113626026Sbrian{ 1137127094Sdes int flags_in; 1138127094Sdes u_int start_point; 1139127094Sdes struct alias_link *link; 1140127094Sdes struct alias_link *link_fully_specified; 1141127094Sdes struct alias_link *link_unknown_all; 1142127094Sdes struct alias_link *link_unknown_dst_addr; 1143127094Sdes struct alias_link *link_unknown_dst_port; 114426026Sbrian 114526026Sbrian/* Initialize pointers */ 1146127094Sdes link_fully_specified = NULL; 1147127094Sdes link_unknown_all = NULL; 1148127094Sdes link_unknown_dst_addr = NULL; 1149127094Sdes link_unknown_dst_port = NULL; 115026026Sbrian 115126026Sbrian/* If either the dest addr or port is unknown, the search 115226026Sbrian loop will have to know about this. */ 115326026Sbrian 1154127094Sdes flags_in = 0; 1155127094Sdes if (dst_addr.s_addr == INADDR_ANY) 1156127094Sdes flags_in |= LINK_UNKNOWN_DEST_ADDR; 1157127094Sdes if (dst_port == 0) 1158127094Sdes flags_in |= LINK_UNKNOWN_DEST_PORT; 115926026Sbrian 116026026Sbrian/* Search loop */ 1161127094Sdes start_point = StartPointIn(alias_addr, alias_port, link_type); 1162127094Sdes LIST_FOREACH(link, &la->linkTableIn[start_point], list_in) { 1163127094Sdes int flags; 116426026Sbrian 1165127094Sdes flags = flags_in | link->flags; 1166127094Sdes if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1167127094Sdes if (link->alias_addr.s_addr == alias_addr.s_addr 1168127094Sdes && link->alias_port == alias_port 1169127094Sdes && link->dst_addr.s_addr == dst_addr.s_addr 1170127094Sdes && link->dst_port == dst_port 1171127094Sdes && link->link_type == link_type) { 1172127094Sdes link_fully_specified = link; 1173127094Sdes break; 1174127094Sdes } 1175127094Sdes } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1176127094Sdes && (flags & LINK_UNKNOWN_DEST_PORT)) { 1177127094Sdes if (link->alias_addr.s_addr == alias_addr.s_addr 1178127094Sdes && link->alias_port == alias_port 1179127094Sdes && link->link_type == link_type) { 1180127094Sdes if (link_unknown_all == NULL) 1181127094Sdes link_unknown_all = link; 1182127094Sdes } 1183127094Sdes } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1184127094Sdes if (link->alias_addr.s_addr == alias_addr.s_addr 1185127094Sdes && link->alias_port == alias_port 1186127094Sdes && link->link_type == link_type 1187127094Sdes && link->dst_port == dst_port) { 1188127094Sdes if (link_unknown_dst_addr == NULL) 1189127094Sdes link_unknown_dst_addr = link; 1190127094Sdes } 1191127094Sdes } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1192127094Sdes if (link->alias_addr.s_addr == alias_addr.s_addr 1193127094Sdes && link->alias_port == alias_port 1194127094Sdes && link->link_type == link_type 1195127094Sdes && link->dst_addr.s_addr == dst_addr.s_addr) { 1196127094Sdes if (link_unknown_dst_port == NULL) 1197127094Sdes link_unknown_dst_port = link; 1198127094Sdes } 1199127094Sdes } 1200127094Sdes } 120126026Sbrian 120226026Sbrian 120326026Sbrian 1204127094Sdes if (link_fully_specified != NULL) { 1205127094Sdes link_fully_specified->timestamp = la->timeStamp; 1206127094Sdes link = link_fully_specified; 1207127094Sdes } else if (link_unknown_dst_port != NULL) 1208127094Sdes link = link_unknown_dst_port; 1209127094Sdes else if (link_unknown_dst_addr != NULL) 1210127094Sdes link = link_unknown_dst_addr; 1211127094Sdes else if (link_unknown_all != NULL) 1212127094Sdes link = link_unknown_all; 1213127094Sdes else 1214127094Sdes return (NULL); 121559702Sru 1216127094Sdes if (replace_partial_links && 1217127094Sdes (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) { 1218127094Sdes struct in_addr src_addr; 1219127094Sdes u_short src_port; 122059702Sru 1221127094Sdes if (link->server != NULL) { /* LSNAT link */ 1222127094Sdes src_addr = link->server->addr; 1223127094Sdes src_port = link->server->port; 1224127094Sdes link->server = link->server->next; 1225127094Sdes } else { 1226127094Sdes src_addr = link->src_addr; 1227127094Sdes src_port = link->src_port; 1228127094Sdes } 1229127094Sdes 1230127094Sdes link = ReLink(link, 1231127094Sdes src_addr, dst_addr, alias_addr, 1232127094Sdes src_port, dst_port, alias_port, 1233127094Sdes link_type); 123459702Sru } 1235127094Sdes return (link); 123626026Sbrian} 123726026Sbrian 123859181Srustatic struct alias_link * 1239124621SphkFindLinkIn(struct libalias *la, struct in_addr dst_addr, 1240127094Sdes struct in_addr alias_addr, 1241127094Sdes u_short dst_port, 1242127094Sdes u_short alias_port, 1243127094Sdes int link_type, 1244127094Sdes int replace_partial_links) 124551727Sru{ 1246127094Sdes struct alias_link *link; 124726026Sbrian 1248127094Sdes link = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1249127094Sdes link_type, replace_partial_links); 125026026Sbrian 1251127094Sdes if (link == NULL) { 1252127094Sdes /* 1253127094Sdes * The following allows permanent links to be specified as 1254127094Sdes * using the default aliasing address (i.e. device 1255127094Sdes * interface address) without knowing in advance what that 1256127094Sdes * address is. 1257127094Sdes */ 1258127094Sdes if (la->aliasAddress.s_addr != INADDR_ANY && 1259127094Sdes alias_addr.s_addr == la->aliasAddress.s_addr) { 1260127094Sdes link = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, 1261127094Sdes link_type, replace_partial_links); 1262127094Sdes } 1263127094Sdes } 1264127094Sdes return (link); 126551727Sru} 126651727Sru 126751727Sru 126851727Sru 126951727Sru 127026026Sbrian/* External routines for finding/adding links 127126026Sbrian 127226026Sbrian-- "external" means outside alias_db.c, but within alias*.c -- 127326026Sbrian 127426026Sbrian FindIcmpIn(), FindIcmpOut() 127526026Sbrian FindFragmentIn1(), FindFragmentIn2() 127626026Sbrian AddFragmentPtrLink(), FindFragmentPtr() 127759726Sru FindProtoIn(), FindProtoOut() 127826026Sbrian FindUdpTcpIn(), FindUdpTcpOut() 127967966Sru AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 128067966Sru FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 128126026Sbrian FindOriginalAddress(), FindAliasAddress() 128226026Sbrian 128326026Sbrian(prototypes in alias_local.h) 128426026Sbrian*/ 128526026Sbrian 128626026Sbrian 128726026Sbrianstruct alias_link * 1288124621SphkFindIcmpIn(struct libalias *la, struct in_addr dst_addr, 1289127094Sdes struct in_addr alias_addr, 1290127094Sdes u_short id_alias, 1291127094Sdes int create) 129226026Sbrian{ 1293127094Sdes struct alias_link *link; 129465280Sru 1295127094Sdes link = FindLinkIn(la, dst_addr, alias_addr, 1296127094Sdes NO_DEST_PORT, id_alias, 1297127094Sdes LINK_ICMP, 0); 1298127094Sdes if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1299127094Sdes struct in_addr target_addr; 130065280Sru 1301127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1302127094Sdes link = AddLink(la, target_addr, dst_addr, alias_addr, 1303127094Sdes id_alias, NO_DEST_PORT, id_alias, 1304127094Sdes LINK_ICMP); 1305127094Sdes } 1306127094Sdes return (link); 130726026Sbrian} 130826026Sbrian 130926026Sbrian 131026026Sbrianstruct alias_link * 1311124621SphkFindIcmpOut(struct libalias *la, struct in_addr src_addr, 1312127094Sdes struct in_addr dst_addr, 1313127094Sdes u_short id, 1314127094Sdes int create) 131526026Sbrian{ 1316127094Sdes struct alias_link *link; 131726026Sbrian 1318127094Sdes link = FindLinkOut(la, src_addr, dst_addr, 1319127094Sdes id, NO_DEST_PORT, 1320127094Sdes LINK_ICMP, 0); 1321127094Sdes if (link == NULL && create) { 1322127094Sdes struct in_addr alias_addr; 132326026Sbrian 1324127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1325127094Sdes link = AddLink(la, src_addr, dst_addr, alias_addr, 1326127094Sdes id, NO_DEST_PORT, GET_ALIAS_ID, 1327127094Sdes LINK_ICMP); 1328127094Sdes } 1329127094Sdes return (link); 133026026Sbrian} 133126026Sbrian 133226026Sbrian 133326026Sbrianstruct alias_link * 1334124621SphkFindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1335127094Sdes struct in_addr alias_addr, 1336127094Sdes u_short ip_id) 133726026Sbrian{ 1338127094Sdes struct alias_link *link; 133926026Sbrian 1340127094Sdes link = FindLinkIn(la, dst_addr, alias_addr, 1341127094Sdes NO_DEST_PORT, ip_id, 1342127094Sdes LINK_FRAGMENT_ID, 0); 134326026Sbrian 1344127094Sdes if (link == NULL) { 1345127094Sdes link = AddLink(la, la->nullAddress, dst_addr, alias_addr, 1346127094Sdes NO_SRC_PORT, NO_DEST_PORT, ip_id, 1347127094Sdes LINK_FRAGMENT_ID); 1348127094Sdes } 1349127094Sdes return (link); 135026026Sbrian} 135126026Sbrian 135226026Sbrian 135326026Sbrianstruct alias_link * 1354127094SdesFindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if 1355127094Sdes * one */ 1356127094Sdes struct in_addr alias_addr, /* is not found. */ 1357127094Sdes u_short ip_id) 135826026Sbrian{ 1359127094Sdes return FindLinkIn(la, dst_addr, alias_addr, 1360127094Sdes NO_DEST_PORT, ip_id, 1361127094Sdes LINK_FRAGMENT_ID, 0); 136226026Sbrian} 136326026Sbrian 136426026Sbrian 136526026Sbrianstruct alias_link * 1366124621SphkAddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1367127094Sdes u_short ip_id) 136826026Sbrian{ 1369127094Sdes return AddLink(la, la->nullAddress, dst_addr, la->nullAddress, 1370127094Sdes NO_SRC_PORT, NO_DEST_PORT, ip_id, 1371127094Sdes LINK_FRAGMENT_PTR); 137226026Sbrian} 137326026Sbrian 137426026Sbrian 137526026Sbrianstruct alias_link * 1376124621SphkFindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1377127094Sdes u_short ip_id) 137826026Sbrian{ 1379127094Sdes return FindLinkIn(la, dst_addr, la->nullAddress, 1380127094Sdes NO_DEST_PORT, ip_id, 1381127094Sdes LINK_FRAGMENT_PTR, 0); 138226026Sbrian} 138326026Sbrian 138426026Sbrian 138526026Sbrianstruct alias_link * 1386124621SphkFindProtoIn(struct libalias *la, struct in_addr dst_addr, 1387127094Sdes struct in_addr alias_addr, 1388127094Sdes u_char proto) 138959356Sru{ 1390127094Sdes struct alias_link *link; 139159356Sru 1392127094Sdes link = FindLinkIn(la, dst_addr, alias_addr, 1393127094Sdes NO_DEST_PORT, 0, 1394127094Sdes proto, 1); 139559356Sru 1396127094Sdes if (link == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1397127094Sdes struct in_addr target_addr; 139859356Sru 1399127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1400127094Sdes link = AddLink(la, target_addr, dst_addr, alias_addr, 1401127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 1402127094Sdes proto); 1403127094Sdes } 1404127094Sdes return (link); 140559356Sru} 140659356Sru 140759356Sru 140859356Srustruct alias_link * 1409124621SphkFindProtoOut(struct libalias *la, struct in_addr src_addr, 1410127094Sdes struct in_addr dst_addr, 1411127094Sdes u_char proto) 141259356Sru{ 1413127094Sdes struct alias_link *link; 141459356Sru 1415127094Sdes link = FindLinkOut(la, src_addr, dst_addr, 1416127094Sdes NO_SRC_PORT, NO_DEST_PORT, 1417127094Sdes proto, 1); 141859356Sru 1419127094Sdes if (link == NULL) { 1420127094Sdes struct in_addr alias_addr; 142159356Sru 1422127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1423127094Sdes link = AddLink(la, src_addr, dst_addr, alias_addr, 1424127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 1425127094Sdes proto); 1426127094Sdes } 1427127094Sdes return (link); 142859356Sru} 142959356Sru 143059356Sru 143159356Srustruct alias_link * 1432124621SphkFindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1433127094Sdes struct in_addr alias_addr, 1434127094Sdes u_short dst_port, 1435127094Sdes u_short alias_port, 1436127094Sdes u_char proto, 1437127094Sdes int create) 143826026Sbrian{ 1439127094Sdes int link_type; 1440127094Sdes struct alias_link *link; 144126026Sbrian 1442127094Sdes switch (proto) { 1443127094Sdes case IPPROTO_UDP: 1444127094Sdes link_type = LINK_UDP; 1445127094Sdes break; 1446127094Sdes case IPPROTO_TCP: 1447127094Sdes link_type = LINK_TCP; 1448127094Sdes break; 1449127094Sdes default: 1450131613Sdes return (NULL); 1451127094Sdes break; 1452127094Sdes } 145326026Sbrian 1454127094Sdes link = FindLinkIn(la, dst_addr, alias_addr, 1455127094Sdes dst_port, alias_port, 1456127094Sdes link_type, create); 145726026Sbrian 1458127094Sdes if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1459127094Sdes struct in_addr target_addr; 146026026Sbrian 1461127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1462127094Sdes link = AddLink(la, target_addr, dst_addr, alias_addr, 1463127094Sdes alias_port, dst_port, alias_port, 1464127094Sdes link_type); 1465127094Sdes } 1466127094Sdes return (link); 146726026Sbrian} 146826026Sbrian 146926026Sbrian 147099207Sbrianstruct alias_link * 1471127094SdesFindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1472127094Sdes struct in_addr dst_addr, 1473127094Sdes u_short src_port, 1474127094Sdes u_short dst_port, 1475127094Sdes u_char proto, 1476127094Sdes int create) 147726026Sbrian{ 1478127094Sdes int link_type; 1479127094Sdes struct alias_link *link; 148026026Sbrian 1481127094Sdes switch (proto) { 1482127094Sdes case IPPROTO_UDP: 1483127094Sdes link_type = LINK_UDP; 1484127094Sdes break; 1485127094Sdes case IPPROTO_TCP: 1486127094Sdes link_type = LINK_TCP; 1487127094Sdes break; 1488127094Sdes default: 1489131613Sdes return (NULL); 1490127094Sdes break; 1491127094Sdes } 149226026Sbrian 1493127094Sdes link = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 149426026Sbrian 1495127094Sdes if (link == NULL && create) { 1496127094Sdes struct in_addr alias_addr; 149726026Sbrian 1498127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1499127094Sdes link = AddLink(la, src_addr, dst_addr, alias_addr, 1500127094Sdes src_port, dst_port, GET_ALIAS_PORT, 1501127094Sdes link_type); 1502127094Sdes } 1503127094Sdes return (link); 150426026Sbrian} 150526026Sbrian 150626026Sbrian 150761861Srustruct alias_link * 1508127094SdesAddPptp(struct libalias *la, struct in_addr src_addr, 1509127094Sdes struct in_addr dst_addr, 1510127094Sdes struct in_addr alias_addr, 1511127094Sdes u_int16_t src_call_id) 151267966Sru{ 1513127094Sdes struct alias_link *link; 151463899Sarchie 1515127094Sdes link = AddLink(la, src_addr, dst_addr, alias_addr, 1516127094Sdes src_call_id, 0, GET_ALIAS_PORT, 1517127094Sdes LINK_PPTP); 151867966Sru 1519127094Sdes return (link); 152067966Sru} 152167966Sru 152267966Sru 152367966Srustruct alias_link * 1524124621SphkFindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1525127094Sdes struct in_addr dst_addr, 1526127094Sdes u_int16_t src_call_id) 152767966Sru{ 1528127094Sdes u_int i; 1529127094Sdes struct alias_link *link; 153067966Sru 1531127094Sdes i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1532127094Sdes LIST_FOREACH(link, &la->linkTableOut[i], list_out) 1533127094Sdes if (link->link_type == LINK_PPTP && 153467966Sru link->src_addr.s_addr == src_addr.s_addr && 153567966Sru link->dst_addr.s_addr == dst_addr.s_addr && 153667966Sru link->src_port == src_call_id) 153767966Sru break; 153867966Sru 1539127094Sdes return (link); 154067966Sru} 154167966Sru 154267966Sru 154367966Srustruct alias_link * 1544124621SphkFindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1545127094Sdes struct in_addr dst_addr, 1546127094Sdes u_int16_t dst_call_id) 154767966Sru{ 1548127094Sdes u_int i; 1549127094Sdes struct alias_link *link; 155067966Sru 1551127094Sdes i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1552127094Sdes LIST_FOREACH(link, &la->linkTableOut[i], list_out) 1553127094Sdes if (link->link_type == LINK_PPTP && 155467966Sru link->src_addr.s_addr == src_addr.s_addr && 155567966Sru link->dst_addr.s_addr == dst_addr.s_addr && 155667966Sru link->dst_port == dst_call_id) 155767966Sru break; 155867966Sru 1559127094Sdes return (link); 156067966Sru} 156167966Sru 156267966Sru 156367966Srustruct alias_link * 1564124621SphkFindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1565127094Sdes struct in_addr alias_addr, 1566127094Sdes u_int16_t dst_call_id) 156767966Sru{ 1568127094Sdes u_int i; 1569127094Sdes struct alias_link *link; 157067966Sru 1571127094Sdes i = StartPointIn(alias_addr, 0, LINK_PPTP); 1572127094Sdes LIST_FOREACH(link, &la->linkTableIn[i], list_in) 1573127094Sdes if (link->link_type == LINK_PPTP && 157467966Sru link->dst_addr.s_addr == dst_addr.s_addr && 157567966Sru link->alias_addr.s_addr == alias_addr.s_addr && 157667966Sru link->dst_port == dst_call_id) 157767966Sru break; 157867966Sru 1579127094Sdes return (link); 158067966Sru} 158167966Sru 158267966Sru 158367966Srustruct alias_link * 1584124621SphkFindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1585127094Sdes struct in_addr alias_addr, 1586127094Sdes u_int16_t alias_call_id) 158767966Sru{ 1588127094Sdes struct alias_link *link; 158967966Sru 1590127094Sdes link = FindLinkIn(la, dst_addr, alias_addr, 1591127094Sdes 0 /* any */ , alias_call_id, 1592127094Sdes LINK_PPTP, 0); 159367966Sru 159467966Sru 1595127094Sdes return (link); 159667966Sru} 159767966Sru 159867966Sru 159999207Sbrianstruct alias_link * 1600127094SdesFindRtspOut(struct libalias *la, struct in_addr src_addr, 1601127094Sdes struct in_addr dst_addr, 1602127094Sdes u_short src_port, 1603127094Sdes u_short alias_port, 1604127094Sdes u_char proto) 160563899Sarchie{ 1606127094Sdes int link_type; 1607127094Sdes struct alias_link *link; 160863899Sarchie 1609127094Sdes switch (proto) { 1610127094Sdes case IPPROTO_UDP: 1611127094Sdes link_type = LINK_UDP; 1612127094Sdes break; 1613127094Sdes case IPPROTO_TCP: 1614127094Sdes link_type = LINK_TCP; 1615127094Sdes break; 1616127094Sdes default: 1617131613Sdes return (NULL); 1618127094Sdes break; 1619127094Sdes } 162063899Sarchie 1621127094Sdes link = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 162263899Sarchie 1623127094Sdes if (link == NULL) { 1624127094Sdes struct in_addr alias_addr; 162563899Sarchie 1626127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1627127094Sdes link = AddLink(la, src_addr, dst_addr, alias_addr, 1628127094Sdes src_port, 0, alias_port, 1629127094Sdes link_type); 1630127094Sdes } 1631127094Sdes return (link); 163263899Sarchie} 163363899Sarchie 163463899Sarchie 163526026Sbrianstruct in_addr 1636124621SphkFindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 163726026Sbrian{ 1638127094Sdes struct alias_link *link; 163999207Sbrian 1640127094Sdes link = FindLinkIn(la, la->nullAddress, alias_addr, 1641127094Sdes 0, 0, LINK_ADDR, 0); 1642127094Sdes if (link == NULL) { 1643127094Sdes la->newDefaultLink = 1; 1644127094Sdes if (la->targetAddress.s_addr == INADDR_ANY) 1645131613Sdes return (alias_addr); 1646127094Sdes else if (la->targetAddress.s_addr == INADDR_NONE) 1647127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1648127094Sdes la->aliasAddress : alias_addr; 1649127094Sdes else 1650131613Sdes return (la->targetAddress); 1651127094Sdes } else { 1652127094Sdes if (link->server != NULL) { /* LSNAT link */ 1653127094Sdes struct in_addr src_addr; 165459702Sru 1655127094Sdes src_addr = link->server->addr; 1656127094Sdes link->server = link->server->next; 1657127094Sdes return (src_addr); 1658127094Sdes } else if (link->src_addr.s_addr == INADDR_ANY) 1659127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1660127094Sdes la->aliasAddress : alias_addr; 1661127094Sdes else 1662131613Sdes return (link->src_addr); 1663127094Sdes } 166426026Sbrian} 166526026Sbrian 166626026Sbrian 166726026Sbrianstruct in_addr 1668124621SphkFindAliasAddress(struct libalias *la, struct in_addr original_addr) 166926026Sbrian{ 1670127094Sdes struct alias_link *link; 167199207Sbrian 1672127094Sdes link = FindLinkOut(la, original_addr, la->nullAddress, 1673127094Sdes 0, 0, LINK_ADDR, 0); 1674127094Sdes if (link == NULL) { 1675127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1676127094Sdes la->aliasAddress : original_addr; 1677127094Sdes } else { 1678127094Sdes if (link->alias_addr.s_addr == INADDR_ANY) 1679127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1680127094Sdes la->aliasAddress : original_addr; 1681127094Sdes else 1682131613Sdes return (link->alias_addr); 1683127094Sdes } 168426026Sbrian} 168526026Sbrian 168626026Sbrian 168726026Sbrian/* External routines for getting or changing link data 168826026Sbrian (external to alias_db.c, but internal to alias*.c) 168926026Sbrian 169026026Sbrian SetFragmentData(), GetFragmentData() 169126026Sbrian SetFragmentPtr(), GetFragmentPtr() 169226026Sbrian SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 169326026Sbrian GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 169426026Sbrian GetOriginalPort(), GetAliasPort() 169526026Sbrian SetAckModified(), GetAckModified() 169626026Sbrian GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 169777485Sru SetProtocolFlags(), GetProtocolFlags() 169867966Sru SetDestCallId() 169926026Sbrian*/ 170026026Sbrian 170126026Sbrian 170226026Sbrianvoid 170326026SbrianSetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 170426026Sbrian{ 1705127094Sdes link->data.frag_addr = src_addr; 170626026Sbrian} 170726026Sbrian 170826026Sbrian 170926026Sbrianvoid 171026026SbrianGetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 171126026Sbrian{ 1712127094Sdes *src_addr = link->data.frag_addr; 171326026Sbrian} 171426026Sbrian 171526026Sbrian 171626026Sbrianvoid 171726026SbrianSetFragmentPtr(struct alias_link *link, char *fptr) 171826026Sbrian{ 1719127094Sdes link->data.frag_ptr = fptr; 172026026Sbrian} 172126026Sbrian 172226026Sbrian 172326026Sbrianvoid 172426026SbrianGetFragmentPtr(struct alias_link *link, char **fptr) 172526026Sbrian{ 1726127094Sdes *fptr = link->data.frag_ptr; 172726026Sbrian} 172826026Sbrian 172926026Sbrian 173026026Sbrianvoid 173126026SbrianSetStateIn(struct alias_link *link, int state) 173226026Sbrian{ 1733127094Sdes /* TCP input state */ 1734127094Sdes switch (state) { 1735127094Sdes case ALIAS_TCP_STATE_DISCONNECTED: 1736127094Sdes if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1737127094Sdes link->expire_time = TCP_EXPIRE_DEAD; 1738127094Sdes else 1739127094Sdes link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1740127094Sdes break; 1741127094Sdes case ALIAS_TCP_STATE_CONNECTED: 1742127094Sdes if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1743127094Sdes link->expire_time = TCP_EXPIRE_CONNECTED; 1744127094Sdes break; 1745127094Sdes default: 1746127094Sdes abort(); 1747127094Sdes } 1748127094Sdes link->data.tcp->state.in = state; 174926026Sbrian} 175026026Sbrian 175126026Sbrian 175226026Sbrianvoid 175326026SbrianSetStateOut(struct alias_link *link, int state) 175426026Sbrian{ 1755127094Sdes /* TCP output state */ 1756127094Sdes switch (state) { 1757127094Sdes case ALIAS_TCP_STATE_DISCONNECTED: 1758127094Sdes if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1759127094Sdes link->expire_time = TCP_EXPIRE_DEAD; 1760127094Sdes else 1761127094Sdes link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1762127094Sdes break; 1763127094Sdes case ALIAS_TCP_STATE_CONNECTED: 1764127094Sdes if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1765127094Sdes link->expire_time = TCP_EXPIRE_CONNECTED; 1766127094Sdes break; 1767127094Sdes default: 1768127094Sdes abort(); 1769127094Sdes } 1770127094Sdes link->data.tcp->state.out = state; 177126026Sbrian} 177226026Sbrian 177326026Sbrian 177426026Sbrianint 177526026SbrianGetStateIn(struct alias_link *link) 177626026Sbrian{ 1777127094Sdes /* TCP input state */ 1778131613Sdes return (link->data.tcp->state.in); 177926026Sbrian} 178026026Sbrian 178126026Sbrian 178226026Sbrianint 178326026SbrianGetStateOut(struct alias_link *link) 178426026Sbrian{ 1785127094Sdes /* TCP output state */ 1786131613Sdes return (link->data.tcp->state.out); 178726026Sbrian} 178826026Sbrian 178926026Sbrian 179026026Sbrianstruct in_addr 179126026SbrianGetOriginalAddress(struct alias_link *link) 179226026Sbrian{ 1793127094Sdes if (link->src_addr.s_addr == INADDR_ANY) 1794131613Sdes return (link->la->aliasAddress); 1795127094Sdes else 1796127094Sdes return (link->src_addr); 179726026Sbrian} 179826026Sbrian 179926026Sbrian 180026026Sbrianstruct in_addr 180126026SbrianGetDestAddress(struct alias_link *link) 180226026Sbrian{ 1803127094Sdes return (link->dst_addr); 180426026Sbrian} 180526026Sbrian 180626026Sbrian 180726026Sbrianstruct in_addr 180826026SbrianGetAliasAddress(struct alias_link *link) 180926026Sbrian{ 1810127094Sdes if (link->alias_addr.s_addr == INADDR_ANY) 1811131613Sdes return (link->la->aliasAddress); 1812127094Sdes else 1813131613Sdes return (link->alias_addr); 181426026Sbrian} 181526026Sbrian 181626026Sbrian 181726026Sbrianstruct in_addr 1818124621SphkGetDefaultAliasAddress(struct libalias *la) 181926026Sbrian{ 1820131613Sdes return (la->aliasAddress); 182126026Sbrian} 182226026Sbrian 182326026Sbrian 182426026Sbrianvoid 1825124621SphkSetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 182626026Sbrian{ 1827127094Sdes la->aliasAddress = alias_addr; 182826026Sbrian} 182926026Sbrian 183026026Sbrian 183126026Sbrianu_short 183226026SbrianGetOriginalPort(struct alias_link *link) 183326026Sbrian{ 1834127094Sdes return (link->src_port); 183526026Sbrian} 183626026Sbrian 183726026Sbrian 183826026Sbrianu_short 183926026SbrianGetAliasPort(struct alias_link *link) 184026026Sbrian{ 1841127094Sdes return (link->alias_port); 184226026Sbrian} 184326026Sbrian 184458279Sbrian#ifndef NO_FW_PUNCH 1845127094Sdesstatic u_short 184632377SeivindGetDestPort(struct alias_link *link) 184732377Seivind{ 1848127094Sdes return (link->dst_port); 184932377Seivind} 1850127094Sdes 185158279Sbrian#endif 185226026Sbrian 185326026Sbrianvoid 185426026SbrianSetAckModified(struct alias_link *link) 185526026Sbrian{ 185659356Sru/* Indicate that ACK numbers have been modified in a TCP connection */ 1857127094Sdes link->data.tcp->state.ack_modified = 1; 185826026Sbrian} 185926026Sbrian 186026026Sbrian 186144307Sbrianstruct in_addr 186244307SbrianGetProxyAddress(struct alias_link *link) 186344307Sbrian{ 1864131613Sdes return (link->proxy_addr); 186544307Sbrian} 186644307Sbrian 186744307Sbrian 186844307Sbrianvoid 186944307SbrianSetProxyAddress(struct alias_link *link, struct in_addr addr) 187044307Sbrian{ 1871127094Sdes link->proxy_addr = addr; 187244307Sbrian} 187344307Sbrian 187444307Sbrian 187544307Sbrianu_short 187644307SbrianGetProxyPort(struct alias_link *link) 187744307Sbrian{ 1878131613Sdes return (link->proxy_port); 187944307Sbrian} 188044307Sbrian 188144307Sbrian 188244307Sbrianvoid 188344307SbrianSetProxyPort(struct alias_link *link, u_short port) 188444307Sbrian{ 1885127094Sdes link->proxy_port = port; 188644307Sbrian} 188744307Sbrian 188844307Sbrian 188926026Sbrianint 189026026SbrianGetAckModified(struct alias_link *link) 189126026Sbrian{ 189259356Sru/* See if ACK numbers have been modified */ 1893131613Sdes return (link->data.tcp->state.ack_modified); 189426026Sbrian} 189526026Sbrian 189626026Sbrian 189726026Sbrianint 189826026SbrianGetDeltaAckIn(struct ip *pip, struct alias_link *link) 189926026Sbrian{ 190026026Sbrian/* 190159356SruFind out how much the ACK number has been altered for an incoming 190259356SruTCP packet. To do this, a circular list of ACK numbers where the TCP 190399207Sbrianpacket size was altered is searched. 190426026Sbrian*/ 190526026Sbrian 1906127094Sdes int i; 1907127094Sdes struct tcphdr *tc; 1908127094Sdes int delta, ack_diff_min; 1909127094Sdes u_long ack; 191026026Sbrian 1911127094Sdes tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 1912127094Sdes ack = tc->th_ack; 191326026Sbrian 1914127094Sdes delta = 0; 1915127094Sdes ack_diff_min = -1; 1916127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) { 1917127094Sdes struct ack_data_record x; 191826026Sbrian 1919127094Sdes x = link->data.tcp->ack[i]; 1920127094Sdes if (x.active == 1) { 1921127094Sdes int ack_diff; 192226026Sbrian 1923127094Sdes ack_diff = SeqDiff(x.ack_new, ack); 1924127094Sdes if (ack_diff >= 0) { 1925127094Sdes if (ack_diff_min >= 0) { 1926127094Sdes if (ack_diff < ack_diff_min) { 1927127094Sdes delta = x.delta; 1928127094Sdes ack_diff_min = ack_diff; 1929127094Sdes } 1930127094Sdes } else { 1931127094Sdes delta = x.delta; 1932127094Sdes ack_diff_min = ack_diff; 1933127094Sdes } 1934127094Sdes } 1935127094Sdes } 1936127094Sdes } 1937127094Sdes return (delta); 193826026Sbrian} 193926026Sbrian 194026026Sbrian 194126026Sbrianint 194226026SbrianGetDeltaSeqOut(struct ip *pip, struct alias_link *link) 194326026Sbrian{ 194426026Sbrian/* 194559356SruFind out how much the sequence number has been altered for an outgoing 194659356SruTCP packet. To do this, a circular list of ACK numbers where the TCP 194799207Sbrianpacket size was altered is searched. 194826026Sbrian*/ 194926026Sbrian 1950127094Sdes int i; 1951127094Sdes struct tcphdr *tc; 1952127094Sdes int delta, seq_diff_min; 1953127094Sdes u_long seq; 195426026Sbrian 1955127094Sdes tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 1956127094Sdes seq = tc->th_seq; 195726026Sbrian 1958127094Sdes delta = 0; 1959127094Sdes seq_diff_min = -1; 1960127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) { 1961127094Sdes struct ack_data_record x; 196226026Sbrian 1963127094Sdes x = link->data.tcp->ack[i]; 1964127094Sdes if (x.active == 1) { 1965127094Sdes int seq_diff; 196626026Sbrian 1967127094Sdes seq_diff = SeqDiff(x.ack_old, seq); 1968127094Sdes if (seq_diff >= 0) { 1969127094Sdes if (seq_diff_min >= 0) { 1970127094Sdes if (seq_diff < seq_diff_min) { 1971127094Sdes delta = x.delta; 1972127094Sdes seq_diff_min = seq_diff; 1973127094Sdes } 1974127094Sdes } else { 1975127094Sdes delta = x.delta; 1976127094Sdes seq_diff_min = seq_diff; 1977127094Sdes } 1978127094Sdes } 1979127094Sdes } 1980127094Sdes } 1981127094Sdes return (delta); 198226026Sbrian} 198326026Sbrian 198426026Sbrian 198526026Sbrianvoid 198626026SbrianAddSeq(struct ip *pip, struct alias_link *link, int delta) 198726026Sbrian{ 198826026Sbrian/* 198926026SbrianWhen a TCP packet has been altered in length, save this 199026026Sbrianinformation in a circular list. If enough packets have 199126026Sbrianbeen altered, then this list will begin to overwrite itself. 199226026Sbrian*/ 199326026Sbrian 1994127094Sdes struct tcphdr *tc; 1995127094Sdes struct ack_data_record x; 1996127094Sdes int hlen, tlen, dlen; 1997127094Sdes int i; 199826026Sbrian 1999127094Sdes tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 200026026Sbrian 2001127094Sdes hlen = (pip->ip_hl + tc->th_off) << 2; 2002127094Sdes tlen = ntohs(pip->ip_len); 2003127094Sdes dlen = tlen - hlen; 200426026Sbrian 2005127094Sdes x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2006127094Sdes x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2007127094Sdes x.delta = delta; 2008127094Sdes x.active = 1; 200926026Sbrian 2010127094Sdes i = link->data.tcp->state.index; 2011127094Sdes link->data.tcp->ack[i] = x; 201226026Sbrian 2013127094Sdes i++; 2014127094Sdes if (i == N_LINK_TCP_DATA) 2015127094Sdes link->data.tcp->state.index = 0; 2016127094Sdes else 2017127094Sdes link->data.tcp->state.index = i; 201826026Sbrian} 201926026Sbrian 202026026Sbrianvoid 202126026SbrianSetExpire(struct alias_link *link, int expire) 202226026Sbrian{ 2023127094Sdes if (expire == 0) { 2024127094Sdes link->flags &= ~LINK_PERMANENT; 2025127094Sdes DeleteLink(link); 2026127094Sdes } else if (expire == -1) { 2027127094Sdes link->flags |= LINK_PERMANENT; 2028127094Sdes } else if (expire > 0) { 2029127094Sdes link->expire_time = expire; 2030127094Sdes } else { 203144616Sbrian#ifdef DEBUG 2032127094Sdes fprintf(stderr, "PacketAlias/SetExpire(): "); 2033127094Sdes fprintf(stderr, "error in expire parameter\n"); 203444616Sbrian#endif 2035127094Sdes } 203626026Sbrian} 203726026Sbrian 203826026Sbrianvoid 2039124621SphkClearCheckNewLink(struct libalias *la) 204026026Sbrian{ 2041127094Sdes la->newDefaultLink = 0; 204226026Sbrian} 204326026Sbrian 204461677Sruvoid 204577485SruSetProtocolFlags(struct alias_link *link, int pflags) 204661677Sru{ 204726026Sbrian 2048127094Sdes link->pflags = pflags;; 204961677Sru} 205061677Sru 205161677Sruint 205277485SruGetProtocolFlags(struct alias_link *link) 205361677Sru{ 205461677Sru 2055127094Sdes return (link->pflags); 205661677Sru} 205761677Sru 205867966Sruvoid 205967966SruSetDestCallId(struct alias_link *link, u_int16_t cid) 206067966Sru{ 2061127094Sdes struct libalias *la = link->la; 206261677Sru 2063127094Sdes la->deleteAllLinks = 1; 2064127094Sdes link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, 2065127094Sdes link->src_port, cid, link->alias_port, link->link_type); 2066127094Sdes la->deleteAllLinks = 0; 206767966Sru} 206867966Sru 206967966Sru 207027864Sbrian/* Miscellaneous Functions 207126026Sbrian 207227864Sbrian HouseKeeping() 207327864Sbrian InitPacketAliasLog() 207427864Sbrian UninitPacketAliasLog() 207527864Sbrian*/ 207626026Sbrian 207726026Sbrian/* 207826026Sbrian Whenever an outgoing or incoming packet is handled, HouseKeeping() 207926026Sbrian is called to find and remove timed-out aliasing links. Logic exists 208026026Sbrian to sweep through the entire table and linked list structure 208126026Sbrian every 60 seconds. 208226026Sbrian 208326026Sbrian (prototype in alias_local.h) 208426026Sbrian*/ 208526026Sbrian 208626026Sbrianvoid 2087124621SphkHouseKeeping(struct libalias *la) 208826026Sbrian{ 2089127094Sdes int i, n, n100; 2090127094Sdes struct timeval tv; 2091127094Sdes struct timezone tz; 209226026Sbrian 2093127094Sdes /* 2094127094Sdes * Save system time (seconds) in global variable timeStamp for use 2095127094Sdes * by other functions. This is done so as not to unnecessarily 2096127094Sdes * waste timeline by making system calls. 2097127094Sdes */ 2098127094Sdes gettimeofday(&tv, &tz); 2099127094Sdes la->timeStamp = tv.tv_sec; 210026026Sbrian 2101127094Sdes /* Compute number of spokes (output table link chains) to cover */ 2102127094Sdes n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual; 2103127094Sdes n100 *= la->timeStamp - la->lastCleanupTime; 2104127094Sdes n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 210526026Sbrian 2106127094Sdes n = n100 / 100; 210726026Sbrian 2108127094Sdes /* Handle different cases */ 2109127094Sdes if (n > ALIAS_CLEANUP_MAX_SPOKES) { 2110127094Sdes n = ALIAS_CLEANUP_MAX_SPOKES; 2111127094Sdes la->lastCleanupTime = la->timeStamp; 2112127094Sdes la->houseKeepingResidual = 0; 211326026Sbrian 2114127094Sdes for (i = 0; i < n; i++) 2115127094Sdes IncrementalCleanup(la); 2116127094Sdes } else if (n > 0) { 2117127094Sdes la->lastCleanupTime = la->timeStamp; 2118127094Sdes la->houseKeepingResidual = n100 - 100 * n; 211926026Sbrian 2120127094Sdes for (i = 0; i < n; i++) 2121127094Sdes IncrementalCleanup(la); 2122127094Sdes } else if (n < 0) { 212344616Sbrian#ifdef DEBUG 2124127094Sdes fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2125127094Sdes fprintf(stderr, "something unexpected in time values\n"); 212644616Sbrian#endif 2127127094Sdes la->lastCleanupTime = la->timeStamp; 2128127094Sdes la->houseKeepingResidual = 0; 2129127094Sdes } 213026026Sbrian} 213126026Sbrian 213226026Sbrian 213327864Sbrian/* Init the log file and enable logging */ 213432377Seivindstatic void 2135124621SphkInitPacketAliasLog(struct libalias *la) 213627864Sbrian{ 2137127094Sdes if ((~la->packetAliasMode & PKT_ALIAS_LOG) 2138127094Sdes && (la->monitorFile = fopen("/var/log/alias.log", "w"))) { 2139127094Sdes la->packetAliasMode |= PKT_ALIAS_LOG; 2140127094Sdes fprintf(la->monitorFile, 2141127094Sdes "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2142127094Sdes } 214327864Sbrian} 214426026Sbrian 214526026Sbrian 214627864Sbrian/* Close the log-file and disable logging. */ 214732377Seivindstatic void 2148124621SphkUninitPacketAliasLog(struct libalias *la) 214927864Sbrian{ 2150127094Sdes if (la->monitorFile) { 2151127094Sdes fclose(la->monitorFile); 2152127094Sdes la->monitorFile = NULL; 2153127094Sdes } 2154127094Sdes la->packetAliasMode &= ~PKT_ALIAS_LOG; 215527864Sbrian} 215626026Sbrian 215727864Sbrian 215827864Sbrian 215927864Sbrian 216027864Sbrian 216127864Sbrian 216226026Sbrian/* Outside world interfaces 216326026Sbrian 216426026Sbrian-- "outside world" means other than alias*.c routines -- 216526026Sbrian 216626026Sbrian PacketAliasRedirectPort() 216759702Sru PacketAliasAddServer() 216859726Sru PacketAliasRedirectProto() 216926026Sbrian PacketAliasRedirectAddr() 2170115650Sru PacketAliasRedirectDynamic() 217127864Sbrian PacketAliasRedirectDelete() 217227864Sbrian PacketAliasSetAddress() 217327864Sbrian PacketAliasInit() 217432377Seivind PacketAliasUninit() 217527864Sbrian PacketAliasSetMode() 217626026Sbrian 217726026Sbrian(prototypes in alias.h) 217826026Sbrian*/ 217926026Sbrian 218026026Sbrian/* Redirection from a specific public addr:port to a 218159356Sru private addr:port */ 218226026Sbrianstruct alias_link * 2183127094SdesLibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2184127094Sdes struct in_addr dst_addr, u_short dst_port, 2185127094Sdes struct in_addr alias_addr, u_short alias_port, 2186127094Sdes u_char proto) 218726026Sbrian{ 2188127094Sdes int link_type; 2189127094Sdes struct alias_link *link; 219026026Sbrian 2191127094Sdes switch (proto) { 2192127094Sdes case IPPROTO_UDP: 2193127094Sdes link_type = LINK_UDP; 2194127094Sdes break; 2195127094Sdes case IPPROTO_TCP: 2196127094Sdes link_type = LINK_TCP; 2197127094Sdes break; 2198127094Sdes default: 219944616Sbrian#ifdef DEBUG 2200127094Sdes fprintf(stderr, "PacketAliasRedirectPort(): "); 2201127094Sdes fprintf(stderr, "only TCP and UDP protocols allowed\n"); 220244616Sbrian#endif 2203131613Sdes return (NULL); 2204127094Sdes } 220526026Sbrian 2206127094Sdes link = AddLink(la, src_addr, dst_addr, alias_addr, 2207127094Sdes src_port, dst_port, alias_port, 2208127094Sdes link_type); 220926026Sbrian 2210127094Sdes if (link != NULL) { 2211127094Sdes link->flags |= LINK_PERMANENT; 2212127094Sdes } 221344616Sbrian#ifdef DEBUG 2214127094Sdes else { 2215127094Sdes fprintf(stderr, "PacketAliasRedirectPort(): " 2216127094Sdes "call to AddLink() failed\n"); 2217127094Sdes } 221844616Sbrian#endif 221926026Sbrian 2220131613Sdes return (link); 222126026Sbrian} 222226026Sbrian 222359702Sru/* Add server to the pool of servers */ 222459702Sruint 2225124621SphkLibAliasAddServer(struct libalias *la, struct alias_link *link, struct in_addr addr, u_short port) 222659702Sru{ 2227127094Sdes struct server *server; 222859702Sru 2229127094Sdes server = malloc(sizeof(struct server)); 223059702Sru 2231127094Sdes if (server != NULL) { 2232127094Sdes struct server *head; 223359702Sru 2234127094Sdes server->addr = addr; 2235127094Sdes server->port = port; 223659702Sru 2237127094Sdes head = link->server; 2238127094Sdes if (head == NULL) 2239127094Sdes server->next = server; 2240127094Sdes else { 2241127094Sdes struct server *s; 224259702Sru 2243127094Sdes for (s = head; s->next != head; s = s->next); 2244127094Sdes s->next = server; 2245127094Sdes server->next = head; 2246127094Sdes } 2247127094Sdes link->server = server; 2248127094Sdes return (0); 2249127094Sdes } else 2250127094Sdes return (-1); 225159702Sru} 225259702Sru 225359726Sru/* Redirect packets of a given IP protocol from a specific 225459356Sru public address to a private address */ 225559356Srustruct alias_link * 2256124621SphkLibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2257127094Sdes struct in_addr dst_addr, 2258127094Sdes struct in_addr alias_addr, 2259127094Sdes u_char proto) 226044307Sbrian{ 2261127094Sdes struct alias_link *link; 226244307Sbrian 2263127094Sdes link = AddLink(la, src_addr, dst_addr, alias_addr, 2264127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 2265127094Sdes proto); 226659356Sru 2267127094Sdes if (link != NULL) { 2268127094Sdes link->flags |= LINK_PERMANENT; 2269127094Sdes } 227059356Sru#ifdef DEBUG 2271127094Sdes else { 2272127094Sdes fprintf(stderr, "PacketAliasRedirectProto(): " 2273127094Sdes "call to AddLink() failed\n"); 2274127094Sdes } 227559356Sru#endif 227659356Sru 2277131613Sdes return (link); 227844307Sbrian} 227944307Sbrian 228026026Sbrian/* Static address translation */ 228126026Sbrianstruct alias_link * 2282124621SphkLibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2283127094Sdes struct in_addr alias_addr) 228426026Sbrian{ 2285127094Sdes struct alias_link *link; 228626026Sbrian 2287127094Sdes link = AddLink(la, src_addr, la->nullAddress, alias_addr, 2288127094Sdes 0, 0, 0, 2289127094Sdes LINK_ADDR); 229026026Sbrian 2291127094Sdes if (link != NULL) { 2292127094Sdes link->flags |= LINK_PERMANENT; 2293127094Sdes } 229444616Sbrian#ifdef DEBUG 2295127094Sdes else { 2296127094Sdes fprintf(stderr, "PacketAliasRedirectAddr(): " 2297127094Sdes "call to AddLink() failed\n"); 2298127094Sdes } 229944616Sbrian#endif 230026026Sbrian 2301131613Sdes return (link); 230226026Sbrian} 230326026Sbrian 230426026Sbrian 2305115650Sru/* Mark the aliasing link dynamic */ 2306115650Sruint 2307124621SphkLibAliasRedirectDynamic(struct libalias *la, struct alias_link *link) 2308115650Sru{ 2309115650Sru 2310127094Sdes if (link->flags & LINK_PARTIALLY_SPECIFIED) 2311127094Sdes return (-1); 2312127094Sdes else { 2313127094Sdes link->flags &= ~LINK_PERMANENT; 2314127094Sdes return (0); 2315127094Sdes } 2316115650Sru} 2317115650Sru 2318115650Sru 231926026Sbrianvoid 2320124621SphkLibAliasRedirectDelete(struct libalias *la, struct alias_link *link) 232126026Sbrian{ 232227864Sbrian/* This is a dangerous function to put in the API, 232326026Sbrian because an invalid pointer can crash the program. */ 232426026Sbrian 2325127094Sdes la->deleteAllLinks = 1; 2326127094Sdes DeleteLink(link); 2327127094Sdes la->deleteAllLinks = 0; 232826026Sbrian} 232926026Sbrian 233026026Sbrian 233126026Sbrianvoid 2332124621SphkLibAliasSetAddress(struct libalias *la, struct in_addr addr) 233326026Sbrian{ 2334127094Sdes if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2335127094Sdes && la->aliasAddress.s_addr != addr.s_addr) 2336127094Sdes CleanupAliasData(la); 233733897Sbrian 2338127094Sdes la->aliasAddress = addr; 233926026Sbrian} 234026026Sbrian 234126026Sbrian 234226026Sbrianvoid 2343124621SphkLibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 234426026Sbrian{ 2345127094Sdes la->targetAddress = target_addr; 234626026Sbrian} 234726026Sbrian 2348124621Sphkstatic void 2349124621Sphkfinishoff(void) 2350124621Sphk{ 235126026Sbrian 2352127094Sdes while (!LIST_EMPTY(&instancehead)) 2353124621Sphk LibAliasUninit(LIST_FIRST(&instancehead)); 2354124621Sphk} 2355124621Sphk 2356124621Sphkstruct libalias * 2357124621SphkLibAliasInit(struct libalias *la) 235826026Sbrian{ 2359127094Sdes int i; 2360127094Sdes struct timeval tv; 2361127094Sdes struct timezone tz; 236226026Sbrian 2363127094Sdes if (la == NULL) { 2364127094Sdes la = calloc(sizeof *la, 1); 2365127094Sdes if (la == NULL) 2366127094Sdes return (la); 2367127094Sdes if (LIST_EMPTY(&instancehead)) 2368127094Sdes atexit(finishoff); 2369127094Sdes LIST_INSERT_HEAD(&instancehead, la, instancelist); 237026026Sbrian 2371127094Sdes gettimeofday(&tv, &tz); 2372127094Sdes la->timeStamp = tv.tv_sec; 2373127094Sdes la->lastCleanupTime = tv.tv_sec; 2374127094Sdes la->houseKeepingResidual = 0; 237526026Sbrian 2376127094Sdes for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2377127094Sdes LIST_INIT(&la->linkTableOut[i]); 2378127094Sdes for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2379127094Sdes LIST_INIT(&la->linkTableIn[i]); 238026026Sbrian 2381127094Sdes } else { 2382127094Sdes la->deleteAllLinks = 1; 2383127094Sdes CleanupAliasData(la); 2384127094Sdes la->deleteAllLinks = 0; 2385127094Sdes } 238626026Sbrian 2387127094Sdes la->aliasAddress.s_addr = INADDR_ANY; 2388127094Sdes la->targetAddress.s_addr = INADDR_ANY; 238926026Sbrian 2390127094Sdes la->icmpLinkCount = 0; 2391127094Sdes la->udpLinkCount = 0; 2392127094Sdes la->tcpLinkCount = 0; 2393127094Sdes la->pptpLinkCount = 0; 2394127094Sdes la->protoLinkCount = 0; 2395127094Sdes la->fragmentIdLinkCount = 0; 2396127094Sdes la->fragmentPtrLinkCount = 0; 2397127094Sdes la->sockCount = 0; 239826026Sbrian 2399127094Sdes la->cleanupIndex = 0; 2400127094Sdes 2401127094Sdes la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2402127094Sdes | PKT_ALIAS_USE_SOCKETS 2403127094Sdes | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2404124621Sphk#ifndef NO_FW_PUNCH 2405127094Sdes la->fireWallFD = -1; 2406124621Sphk#endif 2407127094Sdes return (la); 240826026Sbrian} 240926026Sbrian 241032377Seivindvoid 2411127094SdesLibAliasUninit(struct libalias *la) 2412127094Sdes{ 2413127094Sdes la->deleteAllLinks = 1; 2414127094Sdes CleanupAliasData(la); 2415127094Sdes la->deleteAllLinks = 0; 2416127094Sdes UninitPacketAliasLog(la); 241735314Sbrian#ifndef NO_FW_PUNCH 2418127094Sdes UninitPunchFW(la); 241935314Sbrian#endif 2420127094Sdes LIST_REMOVE(la, instancelist); 2421127094Sdes free(la); 242232377Seivind} 242326026Sbrian 242426026Sbrian/* Change mode for some operations */ 242526026Sbrianunsigned int 2426124621SphkLibAliasSetMode( 2427124621Sphk struct libalias *la, 2428127094Sdes unsigned int flags, /* Which state to bring flags to */ 2429127094Sdes unsigned int mask /* Mask of which flags to affect (use 0 to 2430127094Sdes * do a probe for flag values) */ 243126026Sbrian) 243226026Sbrian{ 243326026Sbrian/* Enable logging? */ 2434127094Sdes if (flags & mask & PKT_ALIAS_LOG) { 2435127094Sdes InitPacketAliasLog(la); /* Do the enable */ 2436127094Sdes } else 243726026Sbrian/* _Disable_ logging? */ 2438127094Sdes if (~flags & mask & PKT_ALIAS_LOG) { 2439127094Sdes UninitPacketAliasLog(la); 2440127094Sdes } 244135314Sbrian#ifndef NO_FW_PUNCH 244232377Seivind/* Start punching holes in the firewall? */ 2443127094Sdes if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2444127094Sdes InitPunchFW(la); 2445127094Sdes } else 244632377Seivind/* Stop punching holes in the firewall? */ 2447127094Sdes if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2448127094Sdes UninitPunchFW(la); 2449127094Sdes } 245035314Sbrian#endif 245132377Seivind 245226026Sbrian/* Other flags can be set/cleared without special action */ 2453127094Sdes la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2454131613Sdes return (la->packetAliasMode); 245526026Sbrian} 245626026Sbrian 245726026Sbrian 245827864Sbrianint 2459124621SphkLibAliasCheckNewLink(struct libalias *la) 246027864Sbrian{ 2461131613Sdes return (la->newDefaultLink); 246227864Sbrian} 246332377Seivind 246432377Seivind 246535314Sbrian#ifndef NO_FW_PUNCH 246635314Sbrian 246732377Seivind/***************** 246832377Seivind Code to support firewall punching. This shouldn't really be in this 246932377Seivind file, but making variables global is evil too. 247032377Seivind ****************/ 247132377Seivind 2472100288Sluigi#ifndef IPFW2 2473127094Sdes#define IPFW2 1 /* use new ipfw code */ 2474100288Sluigi#endif 2475100288Sluigi 247632377Seivind/* Firewall include files */ 247732392Sjkh#include <net/if.h> 247832377Seivind#include <netinet/ip_fw.h> 247932377Seivind#include <string.h> 248032377Seivind#include <err.h> 248132377Seivind 2482127094Sdes#if IPFW2 /* support for new firewall code */ 248398943Sluigi/* 248498943Sluigi * helper function, updates the pointer to cmd with the length 248598943Sluigi * of the current command, and also cleans up the first word of 248698943Sluigi * the new command in case it has been clobbered before. 248798943Sluigi */ 248898943Sluigistatic ipfw_insn * 2489127094Sdesnext_cmd(ipfw_insn * cmd) 249098943Sluigi{ 2491127094Sdes cmd += F_LEN(cmd); 2492127094Sdes bzero(cmd, sizeof(*cmd)); 2493131613Sdes return (cmd); 249498943Sluigi} 249598943Sluigi 249699623Sluigi/* 249799623Sluigi * A function to fill simple commands of size 1. 249899623Sluigi * Existing flags are preserved. 249999623Sluigi */ 250099623Sluigistatic ipfw_insn * 2501127094Sdesfill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2502127094Sdes int flags, u_int16_t arg) 250398943Sluigi{ 2504127094Sdes cmd->opcode = opcode; 2505127094Sdes cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2506127094Sdes cmd->arg1 = arg; 2507127094Sdes return next_cmd(cmd); 250899623Sluigi} 250999623Sluigi 251099623Sluigistatic ipfw_insn * 2511127094Sdesfill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 251299623Sluigi{ 2513127094Sdes ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 251499623Sluigi 2515127094Sdes cmd->addr.s_addr = addr; 2516127094Sdes return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 251798943Sluigi} 251898943Sluigi 251999623Sluigistatic ipfw_insn * 2520127094Sdesfill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 252198943Sluigi{ 2522127094Sdes ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 252399623Sluigi 2524127094Sdes cmd->ports[0] = cmd->ports[1] = port; 2525127094Sdes return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 252698943Sluigi} 252798943Sluigi 252898943Sluigistatic int 252998943Sluigifill_rule(void *buf, int bufsize, int rulenum, 2530127094Sdes enum ipfw_opcodes action, int proto, 2531127094Sdes struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 253298943Sluigi{ 2533127094Sdes struct ip_fw *rule = (struct ip_fw *)buf; 2534127094Sdes ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 253598943Sluigi 2536127094Sdes bzero(buf, bufsize); 2537127094Sdes rule->rulenum = rulenum; 253898943Sluigi 2539127094Sdes cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2540127094Sdes cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2541127094Sdes cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2542127094Sdes cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2543127094Sdes cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 254498943Sluigi 2545127094Sdes rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2546127094Sdes cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 254799207Sbrian 2548127094Sdes rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 254998943Sluigi 2550127094Sdes return ((char *)cmd - (char *)buf); 255198943Sluigi} 255298943Sluigi 2553127094Sdes#endif /* IPFW2 */ 255432377Seivind 2555127094Sdesstatic void ClearAllFWHoles(struct libalias *la); 255632377Seivind 2557127094Sdes 2558124621Sphk#define fw_setfield(la, field, num) \ 255932377Seivinddo { \ 2560124621Sphk (field)[(num) - la->fireWallBaseNum] = 1; \ 2561127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */ 2562124621Sphk 2563124621Sphk#define fw_clrfield(la, field, num) \ 256432377Seivinddo { \ 2565124621Sphk (field)[(num) - la->fireWallBaseNum] = 0; \ 2566127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */ 256732377Seivind 2568124621Sphk#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2569124621Sphk 257032377Seivindstatic void 2571124621SphkInitPunchFW(struct libalias *la) 2572124621Sphk{ 2573124621Sphk 2574127094Sdes la->fireWallField = malloc(la->fireWallNumNums); 2575127094Sdes if (la->fireWallField) { 2576127094Sdes memset(la->fireWallField, 0, la->fireWallNumNums); 2577127094Sdes if (la->fireWallFD < 0) { 2578127094Sdes la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2579127094Sdes } 2580127094Sdes ClearAllFWHoles(la); 2581127094Sdes la->fireWallActiveNum = la->fireWallBaseNum; 2582127094Sdes } 258332377Seivind} 258432377Seivind 258532377Seivindstatic void 2586124621SphkUninitPunchFW(struct libalias *la) 2587124621Sphk{ 2588127094Sdes ClearAllFWHoles(la); 2589127094Sdes if (la->fireWallFD >= 0) 2590127094Sdes close(la->fireWallFD); 2591127094Sdes la->fireWallFD = -1; 2592127094Sdes if (la->fireWallField) 2593127094Sdes free(la->fireWallField); 2594127094Sdes la->fireWallField = NULL; 2595127094Sdes la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 259632377Seivind} 259732377Seivind 259832377Seivind/* Make a certain link go through the firewall */ 259932377Seivindvoid 2600124621SphkPunchFWHole(struct alias_link *link) 2601124621Sphk{ 2602127094Sdes struct libalias *la; 2603127094Sdes int r; /* Result code */ 2604127094Sdes struct ip_fw rule; /* On-the-fly built rule */ 2605127094Sdes int fwhole; /* Where to punch hole */ 260632377Seivind 2607127094Sdes la = link->la; 2608124621Sphk 260932377Seivind/* Don't do anything unless we are asked to */ 2610127094Sdes if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2611127094Sdes la->fireWallFD < 0 || 2612127094Sdes link->link_type != LINK_TCP) 2613127094Sdes return; 261432377Seivind 2615127094Sdes memset(&rule, 0, sizeof rule); 261632377Seivind 261732377Seivind/** Build rule **/ 261832377Seivind 2619127094Sdes /* Find empty slot */ 2620127094Sdes for (fwhole = la->fireWallActiveNum; 2621127094Sdes fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2622127094Sdes fw_tstfield(la, la->fireWallField, fwhole); 2623127094Sdes fwhole++); 2624127094Sdes if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2625127094Sdes for (fwhole = la->fireWallBaseNum; 2626127094Sdes fwhole < la->fireWallActiveNum && 2627127094Sdes fw_tstfield(la, la->fireWallField, fwhole); 2628127094Sdes fwhole++); 2629127094Sdes if (fwhole == la->fireWallActiveNum) { 2630127094Sdes /* No rule point empty - we can't punch more holes. */ 2631127094Sdes la->fireWallActiveNum = la->fireWallBaseNum; 263244616Sbrian#ifdef DEBUG 2633127094Sdes fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 263444616Sbrian#endif 2635127094Sdes return; 2636127094Sdes } 2637127094Sdes } 2638127094Sdes /* Start next search at next position */ 2639127094Sdes la->fireWallActiveNum = fwhole + 1; 264032377Seivind 2641127094Sdes /* 2642127094Sdes * generate two rules of the form 2643131612Sdes * 2644127094Sdes * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2645127094Sdes * accept tcp from DAddr DPort to OAddr OPort 2646127094Sdes */ 264799623Sluigi#if IPFW2 2648127094Sdes if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) { 2649127094Sdes u_int32_t rulebuf[255]; 2650127094Sdes int i; 265198943Sluigi 2652127094Sdes i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2653127094Sdes O_ACCEPT, IPPROTO_TCP, 2654127094Sdes GetOriginalAddress(link), ntohs(GetOriginalPort(link)), 2655127094Sdes GetDestAddress(link), ntohs(GetDestPort(link))); 2656127094Sdes r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2657127094Sdes if (r) 2658127094Sdes err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 265998943Sluigi 2660127094Sdes i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2661127094Sdes O_ACCEPT, IPPROTO_TCP, 2662127094Sdes GetDestAddress(link), ntohs(GetDestPort(link)), 2663127094Sdes GetOriginalAddress(link), ntohs(GetOriginalPort(link))); 2664127094Sdes r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2665127094Sdes if (r) 2666127094Sdes err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2667127094Sdes } 2668127094Sdes#else /* !IPFW2, old code to generate ipfw rule */ 266998943Sluigi 2670127094Sdes /* Build generic part of the two rules */ 2671127094Sdes rule.fw_number = fwhole; 2672127094Sdes IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */ 2673127094Sdes IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */ 2674127094Sdes rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT; 2675127094Sdes rule.fw_prot = IPPROTO_TCP; 2676127094Sdes rule.fw_smsk.s_addr = INADDR_BROADCAST; 2677127094Sdes rule.fw_dmsk.s_addr = INADDR_BROADCAST; 267832377Seivind 2679127094Sdes /* Build and apply specific part of the rules */ 2680127094Sdes rule.fw_src = GetOriginalAddress(link); 2681127094Sdes rule.fw_dst = GetDestAddress(link); 2682127094Sdes rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2683127094Sdes rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 268432377Seivind 2685127094Sdes /* 2686127094Sdes * Skip non-bound links - XXX should not be strictly necessary, but 2687127094Sdes * seems to leave hole if not done. Leak of non-bound links? (Code 2688127094Sdes * should be left even if the problem is fixed - it is a clear 2689127094Sdes * optimization) 2690127094Sdes */ 2691127094Sdes if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2692127094Sdes r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 269344616Sbrian#ifdef DEBUG 2694127094Sdes if (r) 2695127094Sdes err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 269644616Sbrian#endif 2697127094Sdes rule.fw_src = GetDestAddress(link); 2698127094Sdes rule.fw_dst = GetOriginalAddress(link); 2699127094Sdes rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2700127094Sdes rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2701127094Sdes r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 270244616Sbrian#ifdef DEBUG 2703127094Sdes if (r) 2704127094Sdes err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 270544616Sbrian#endif 2706127094Sdes } 2707127094Sdes#endif /* !IPFW2 */ 270832377Seivind/* Indicate hole applied */ 2709127094Sdes link->data.tcp->fwhole = fwhole; 2710127094Sdes fw_setfield(la, la->fireWallField, fwhole); 271132377Seivind} 271232377Seivind 271332377Seivind/* Remove a hole in a firewall associated with a particular alias 271432377Seivind link. Calling this too often is harmless. */ 271532377Seivindstatic void 2716124621SphkClearFWHole(struct alias_link *link) 2717124621Sphk{ 2718124621Sphk 2719127094Sdes struct libalias *la; 2720124621Sphk 2721127094Sdes la = link->la; 2722127094Sdes if (link->link_type == LINK_TCP) { 2723127094Sdes int fwhole = link->data.tcp->fwhole; /* Where is the firewall 2724127094Sdes * hole? */ 2725127094Sdes struct ip_fw rule; 272632377Seivind 2727127094Sdes if (fwhole < 0) 2728127094Sdes return; 272932377Seivind 2730127094Sdes memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 273199623Sluigi#if IPFW2 2732127094Sdes while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2733127094Sdes &fwhole, sizeof fwhole)); 2734127094Sdes#else /* !IPFW2 */ 2735127094Sdes rule.fw_number = fwhole; 2736127094Sdes while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, 2737127094Sdes &rule, sizeof rule)); 2738127094Sdes#endif /* !IPFW2 */ 2739127094Sdes fw_clrfield(la, la->fireWallField, fwhole); 2740127094Sdes link->data.tcp->fwhole = -1; 2741127094Sdes } 274232377Seivind} 274332377Seivind 274432377Seivind/* Clear out the entire range dedicated to firewall holes. */ 274532377Seivindstatic void 2746127094SdesClearAllFWHoles(struct libalias *la) 2747127094Sdes{ 2748127094Sdes struct ip_fw rule; /* On-the-fly built rule */ 2749127094Sdes int i; 275099207Sbrian 2751127094Sdes if (la->fireWallFD < 0) 2752127094Sdes return; 275332377Seivind 2754127094Sdes memset(&rule, 0, sizeof rule); 2755127094Sdes for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 275699623Sluigi#if IPFW2 2757127094Sdes int r = i; 2758127094Sdes 2759127094Sdes while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2760127094Sdes#else /* !IPFW2 */ 2761127094Sdes rule.fw_number = i; 2762127094Sdes while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)); 2763127094Sdes#endif /* !IPFW2 */ 2764127094Sdes } 2765127094Sdes /* XXX: third arg correct here ? /phk */ 2766127094Sdes memset(la->fireWallField, 0, la->fireWallNumNums); 276732377Seivind} 2768127094Sdes 276935314Sbrian#endif 277074778Sbrian 277174778Sbrianvoid 2772127094SdesLibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2773127094Sdes{ 277474778Sbrian#ifndef NO_FW_PUNCH 2775127094Sdes la->fireWallBaseNum = base; 2776127094Sdes la->fireWallNumNums = num; 277774778Sbrian#endif 277874778Sbrian} 2779120372Smarcus 2780120372Smarcusvoid 2781127094SdesLibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2782127094Sdes{ 2783127094Sdes la->skinnyPort = port; 2784120372Smarcus} 2785