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$"); 2984195Sdillon 3077701Sbrian/* 3126026Sbrian Alias_db.c encapsulates all data structures used for storing 3226026Sbrian packet aliasing data. Other parts of the aliasing software 3326026Sbrian access data through functions provided in this file. 3426026Sbrian 3526026Sbrian Data storage is based on the notion of a "link", which is 3626026Sbrian established for ICMP echo/reply packets, UDP datagrams and 3726026Sbrian TCP stream connections. A link stores the original source 3826026Sbrian and destination addresses. For UDP and TCP, it also stores 3926026Sbrian source and destination port numbers, as well as an alias 4026026Sbrian port number. Links are also used to store information about 4126026Sbrian fragments. 4226026Sbrian 4326026Sbrian There is a facility for sweeping through and deleting old 4426026Sbrian links as new packets are sent through. A simple timeout is 4526026Sbrian used for ICMP and UDP links. TCP links are left alone unless 4626026Sbrian there is an incomplete connection, in which case the link 4726026Sbrian can be deleted after a certain amount of time. 4826026Sbrian 4926026Sbrian 5026026Sbrian Initial version: August, 1996 (cjm) 5126026Sbrian 5226026Sbrian Version 1.4: September 16, 1996 (cjm) 53131612Sdes Facility for handling incoming links added. 5426026Sbrian 5526026Sbrian Version 1.6: September 18, 1996 (cjm) 56131612Sdes ICMP data handling simplified. 5726026Sbrian 5826026Sbrian Version 1.7: January 9, 1997 (cjm) 59131612Sdes Fragment handling simplified. 60131612Sdes Saves pointers for unresolved fragments. 61131612Sdes Permits links for unspecified remote ports 62131612Sdes or unspecified remote addresses. 63131612Sdes Fixed bug which did not properly zero port 64131612Sdes table entries after a link was deleted. 65131612Sdes Cleaned up some obsolete comments. 6626026Sbrian 6726026Sbrian Version 1.8: January 14, 1997 (cjm) 68131612Sdes Fixed data type error in StartPoint(). 69131612Sdes (This error did not exist prior to v1.7 70131612Sdes and was discovered and fixed by Ari Suutari) 7126026Sbrian 7226026Sbrian Version 1.9: February 1, 1997 73131612Sdes Optionally, connections initiated from packet aliasing host 74131612Sdes machine will will not have their port number aliased unless it 75131612Sdes conflicts with an aliasing port already being used. (cjm) 7626026Sbrian 77131612Sdes All options earlier being #ifdef'ed are now available through 78131612Sdes a new interface, SetPacketAliasMode(). This allows run time 79131612Sdes control (which is now available in PPP+pktAlias through the 80131612Sdes 'alias' keyword). (ee) 8126026Sbrian 82131612Sdes Added ability to create an alias port without 83131612Sdes either destination address or port specified. 84131612Sdes port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) 8544307Sbrian 86131612Sdes Removed K&R style function headers 87131612Sdes and general cleanup. (ee) 8826026Sbrian 89131612Sdes Added packetAliasMode to replace compiler #defines's (ee) 9044307Sbrian 91131612Sdes Allocates sockets for partially specified 92131612Sdes ports if ALIAS_USE_SOCKETS defined. (cjm) 9326026Sbrian 9426026Sbrian Version 2.0: March, 1997 95131612Sdes SetAliasAddress() will now clean up alias links 96131612Sdes if the aliasing address is changed. (cjm) 9726026Sbrian 98131612Sdes PacketAliasPermanentLink() function added to support permanent 99131612Sdes links. (J. Fortes suggested the need for this.) 100131612Sdes Examples: 10126026Sbrian 102131612Sdes (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port 10326026Sbrian 104131612Sdes (192.168.0.2, port 21) <-> alias port 3604, known dest addr 105131612Sdes unknown dest port 10626026Sbrian 107131612Sdes These permanent links allow for incoming connections to 108131612Sdes machines on the local network. They can be given with a 109131612Sdes user-chosen amount of specificity, with increasing specificity 110131612Sdes meaning more security. (cjm) 11126026Sbrian 112131612Sdes Quite a bit of rework to the basic engine. The portTable[] 113131612Sdes array, which kept track of which ports were in use was replaced 114131612Sdes by a table/linked list structure. (cjm) 11526026Sbrian 116131612Sdes SetExpire() function added. (cjm) 11726026Sbrian 118131612Sdes DeleteLink() no longer frees memory association with a pointer 119131612Sdes to a fragment (this bug was first recognized by E. Eklund in 120131612Sdes v1.9). 12126026Sbrian 12226026Sbrian Version 2.1: May, 1997 (cjm) 123131612Sdes Packet aliasing engine reworked so that it can handle 124131612Sdes multiple external addresses rather than just a single 125131612Sdes host address. 12626026Sbrian 127131612Sdes PacketAliasRedirectPort() and PacketAliasRedirectAddr() 128131612Sdes added to the API. The first function is a more generalized 129131612Sdes version of PacketAliasPermanentLink(). The second function 130131612Sdes implements static network address translation. 13132377Seivind 13263899Sarchie Version 3.2: July, 2000 (salander and satoh) 133131612Sdes Added FindNewPortGroup to get contiguous range of port values. 13463899Sarchie 135131612Sdes Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing 13663899Sarchie link but not actually add one. 13763899Sarchie 138131612Sdes Added FindRtspOut, which is closely derived from FindUdpTcpOut, 13963899Sarchie except that the alias port (from FindNewPortGroup) is provided 14063899Sarchie as input. 14163899Sarchie 14232377Seivind See HISTORY file for additional revisions. 14326026Sbrian*/ 14426026Sbrian 145145921Sglebius#ifdef _KERNEL 146162674Spiso#include <machine/stdarg.h> 147145921Sglebius#include <sys/param.h> 148145921Sglebius#include <sys/kernel.h> 149185895Szec#include <sys/lock.h> 150145921Sglebius#include <sys/module.h> 151185895Szec#include <sys/rwlock.h> 152162674Spiso#include <sys/syslog.h> 153162674Spiso#else 154162674Spiso#include <stdarg.h> 155145921Sglebius#include <stdlib.h> 156145921Sglebius#include <stdio.h> 157162674Spiso#include <sys/errno.h> 158162674Spiso#include <sys/time.h> 159145921Sglebius#include <unistd.h> 160145921Sglebius#endif 161145921Sglebius 162162674Spiso#include <sys/socket.h> 16326026Sbrian#include <netinet/tcp.h> 16426026Sbrian 165145921Sglebius#ifdef _KERNEL 166145921Sglebius#include <netinet/libalias/alias.h> 167145921Sglebius#include <netinet/libalias/alias_local.h> 168162674Spiso#include <netinet/libalias/alias_mod.h> 169162674Spiso#include <net/if.h> 170145921Sglebius#else 17126026Sbrian#include "alias.h" 17226026Sbrian#include "alias_local.h" 173162674Spiso#include "alias_mod.h" 174145921Sglebius#endif 17526026Sbrian 176127094Sdesstatic LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); 17726026Sbrian 178124621Sphk 17926026Sbrian/* 18026026Sbrian Constants (note: constants are also defined 181131612Sdes near relevant functions or structs) 18226026Sbrian*/ 18326026Sbrian 18426026Sbrian/* Parameters used for cleanup of expired links */ 185179480Smav/* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */ 186179480Smav#define ALIAS_CLEANUP_INTERVAL_SECS 64 187179480Smav#define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5) 18826026Sbrian 18951494Sru/* Timeouts (in seconds) for different link types */ 19026026Sbrian#define ICMP_EXPIRE_TIME 60 19126026Sbrian#define UDP_EXPIRE_TIME 60 19259726Sru#define PROTO_EXPIRE_TIME 60 19326026Sbrian#define FRAGMENT_ID_EXPIRE_TIME 10 19426026Sbrian#define FRAGMENT_PTR_EXPIRE_TIME 30 19526026Sbrian 19632377Seivind/* TCP link expire time for different cases */ 19732377Seivind/* When the link has been used and closed - minimal grace time to 19832377Seivind allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 19932377Seivind#ifndef TCP_EXPIRE_DEAD 200127094Sdes#define TCP_EXPIRE_DEAD 10 20132377Seivind#endif 20232377Seivind 20332377Seivind/* When the link has been used and closed on one side - the other side 20432377Seivind is allowed to still send data */ 20532377Seivind#ifndef TCP_EXPIRE_SINGLEDEAD 206127094Sdes#define TCP_EXPIRE_SINGLEDEAD 90 20732377Seivind#endif 20832377Seivind 20932377Seivind/* When the link isn't yet up */ 21032377Seivind#ifndef TCP_EXPIRE_INITIAL 211127094Sdes#define TCP_EXPIRE_INITIAL 300 21232377Seivind#endif 21332377Seivind 21432377Seivind/* When the link is up */ 21532377Seivind#ifndef TCP_EXPIRE_CONNECTED 216127094Sdes#define TCP_EXPIRE_CONNECTED 86400 21732377Seivind#endif 21832377Seivind 21932377Seivind 22026026Sbrian/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 22126026Sbrian These constants can be anything except zero, which indicates an 22244307Sbrian unknown port number. */ 22326026Sbrian 22426026Sbrian#define NO_DEST_PORT 1 22526026Sbrian#define NO_SRC_PORT 1 22626026Sbrian 22726026Sbrian 22826026Sbrian 22944307Sbrian/* Data Structures 23026026Sbrian 23126026Sbrian The fundamental data structure used in this program is 23226026Sbrian "struct alias_link". Whenever a TCP connection is made, 23326026Sbrian a UDP datagram is sent out, or an ICMP echo request is made, 23426026Sbrian a link record is made (if it has not already been created). 23526026Sbrian The link record is identified by the source address/port 23626026Sbrian and the destination address/port. In the case of an ICMP 23726026Sbrian echo request, the source port is treated as being equivalent 23859356Sru with the 16-bit ID number of the ICMP packet. 23926026Sbrian 24026026Sbrian The link record also can store some auxiliary data. For 24126026Sbrian TCP connections that have had sequence and acknowledgment 24226026Sbrian modifications, data space is available to track these changes. 24359356Sru A state field is used to keep track in changes to the TCP 24459356Sru connection state. ID numbers of fragments can also be 24526026Sbrian stored in the auxiliary space. Pointers to unresolved 24659356Sru fragments can also be stored. 24726026Sbrian 24826026Sbrian The link records support two independent chainings. Lookup 24926026Sbrian tables for input and out tables hold the initial pointers 25026026Sbrian the link chains. On input, the lookup table indexes on alias 25126026Sbrian port and link type. On output, the lookup table indexes on 25259356Sru source address, destination address, source port, destination 25326026Sbrian port and link type. 25426026Sbrian*/ 25526026Sbrian 256127094Sdesstruct ack_data_record { /* used to save changes to ACK/sequence 257127094Sdes * numbers */ 258127094Sdes u_long ack_old; 259127094Sdes u_long ack_new; 260127094Sdes int delta; 261127094Sdes int active; 26226026Sbrian}; 26326026Sbrian 264127094Sdesstruct tcp_state { /* Information about TCP connection */ 265127094Sdes int in; /* State for outside -> inside */ 266127094Sdes int out; /* State for inside -> outside */ 267127094Sdes int index; /* Index to ACK data array */ 268127094Sdes int ack_modified; /* Indicates whether ACK and 269127094Sdes * sequence numbers */ 270127094Sdes /* been modified */ 27126026Sbrian}; 27226026Sbrian 273127094Sdes#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 274127094Sdes * saved for a modified TCP stream */ 275127094Sdesstruct tcp_dat { 276127094Sdes struct tcp_state state; 277127094Sdes struct ack_data_record ack[N_LINK_TCP_DATA]; 278127094Sdes int fwhole; /* Which firewall record is used for this 279127094Sdes * hole? */ 28026026Sbrian}; 28126026Sbrian 282127094Sdesstruct server { /* LSNAT server pool (circular list) */ 283127094Sdes struct in_addr addr; 284127094Sdes u_short port; 285127094Sdes struct server *next; 28659702Sru}; 28759702Sru 288127094Sdesstruct alias_link { /* Main data structure */ 289127094Sdes struct libalias *la; 290127094Sdes struct in_addr src_addr; /* Address and port information */ 291127094Sdes struct in_addr dst_addr; 292127094Sdes struct in_addr alias_addr; 293127094Sdes struct in_addr proxy_addr; 294127094Sdes u_short src_port; 295127094Sdes u_short dst_port; 296127094Sdes u_short alias_port; 297127094Sdes u_short proxy_port; 298127094Sdes struct server *server; 29926026Sbrian 300127094Sdes int link_type; /* Type of link: TCP, UDP, ICMP, 301127094Sdes * proto, frag */ 30226026Sbrian 30326026Sbrian/* values for link_type */ 30459726Sru#define LINK_ICMP IPPROTO_ICMP 30559726Sru#define LINK_UDP IPPROTO_UDP 30659726Sru#define LINK_TCP IPPROTO_TCP 30759726Sru#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 30859726Sru#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 30959726Sru#define LINK_ADDR (IPPROTO_MAX + 3) 31061861Sru#define LINK_PPTP (IPPROTO_MAX + 4) 31126026Sbrian 312127094Sdes int flags; /* indicates special characteristics */ 313127094Sdes int pflags; /* protocol-specific flags */ 31426026Sbrian 31526026Sbrian/* flag bits */ 31626026Sbrian#define LINK_UNKNOWN_DEST_PORT 0x01 31726026Sbrian#define LINK_UNKNOWN_DEST_ADDR 0x02 31826026Sbrian#define LINK_PERMANENT 0x04 319127094Sdes#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 32032377Seivind#define LINK_UNFIREWALLED 0x08 32126026Sbrian 322127094Sdes int timestamp; /* Time link was last accessed */ 323127094Sdes int expire_time; /* Expire time for link */ 324145926Sglebius#ifndef NO_USE_SOCKETS 325127094Sdes int sockfd; /* socket descriptor */ 326145926Sglebius#endif 327127094Sdes LIST_ENTRY (alias_link) list_out; /* Linked list of 328127094Sdes * pointers for */ 329127094Sdes LIST_ENTRY (alias_link) list_in; /* input and output 330127094Sdes * lookup tables */ 33126026Sbrian 332127094Sdes union { /* Auxiliary data */ 333127094Sdes char *frag_ptr; 334127094Sdes struct in_addr frag_addr; 335127094Sdes struct tcp_dat *tcp; 336127094Sdes } data; 33726026Sbrian}; 33826026Sbrian 339145927Sglebius/* Clean up procedure. */ 340145927Sglebiusstatic void finishoff(void); 341145927Sglebius 342145927Sglebius/* Kernel module definition. */ 343145927Sglebius#ifdef _KERNEL 344145927SglebiusMALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing"); 345145927Sglebius 346145927SglebiusMODULE_VERSION(libalias, 1); 347145927Sglebius 348145927Sglebiusstatic int 349145927Sglebiusalias_mod_handler(module_t mod, int type, void *data) 350145927Sglebius{ 351145927Sglebius int error; 352145927Sglebius 353145927Sglebius switch (type) { 354145927Sglebius case MOD_LOAD: 355145927Sglebius error = 0; 356162674Spiso handler_chain_init(); 357145927Sglebius break; 358145927Sglebius case MOD_QUIESCE: 359145927Sglebius case MOD_UNLOAD: 360162674Spiso handler_chain_destroy(); 361162674Spiso finishoff(); 362145927Sglebius error = 0; 363145927Sglebius break; 364145927Sglebius default: 365145927Sglebius error = EINVAL; 366145927Sglebius } 367145927Sglebius 368145927Sglebius return (error); 369145927Sglebius} 370145927Sglebius 371145927Sglebiusstatic moduledata_t alias_mod = { 372145927Sglebius "alias", alias_mod_handler, NULL 373145927Sglebius}; 374145927Sglebius 375145927SglebiusDECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); 376145927Sglebius#endif 377145927Sglebius 37826026Sbrian/* Internal utility routines (used only in alias_db.c) 37926026Sbrian 38026026SbrianLookup table starting points: 38126026Sbrian StartPointIn() -- link table initial search point for 382131612Sdes incoming packets 38359356Sru StartPointOut() -- link table initial search point for 384131612Sdes outgoing packets 38599207Sbrian 38626026SbrianMiscellaneous: 38726026Sbrian SeqDiff() -- difference between two TCP sequences 38826026Sbrian ShowAliasStats() -- send alias statistics to a monitor file 38926026Sbrian*/ 39026026Sbrian 39126026Sbrian 39226026Sbrian/* Local prototypes */ 393127094Sdesstatic u_int StartPointIn(struct in_addr, u_short, int); 39426026Sbrian 395127094Sdesstatic u_int 396127094SdesStartPointOut(struct in_addr, struct in_addr, 397127094Sdes u_short, u_short, int); 39826026Sbrian 399127094Sdesstatic int SeqDiff(u_long, u_long); 40026026Sbrian 40135314Sbrian#ifndef NO_FW_PUNCH 40232377Seivind/* Firewall control */ 403131614Sdesstatic void InitPunchFW(struct libalias *); 404131614Sdesstatic void UninitPunchFW(struct libalias *); 405131614Sdesstatic void ClearFWHole(struct alias_link *); 406127094Sdes 40735314Sbrian#endif 40826026Sbrian 40932377Seivind/* Log file control */ 410145925Sglebiusstatic void ShowAliasStats(struct libalias *); 411162674Spisostatic int InitPacketAliasLog(struct libalias *); 412131614Sdesstatic void UninitPacketAliasLog(struct libalias *); 41332377Seivind 414188294Spisovoid SctpShowAliasStats(struct libalias *la); 415188294Spiso 416127094Sdesstatic u_int 41726026SbrianStartPointIn(struct in_addr alias_addr, 418127094Sdes u_short alias_port, 419127094Sdes int link_type) 42026026Sbrian{ 421127094Sdes u_int n; 42226026Sbrian 423127094Sdes n = alias_addr.s_addr; 424127094Sdes if (link_type != LINK_PPTP) 425127094Sdes n += alias_port; 426127094Sdes n += link_type; 427127094Sdes return (n % LINK_TABLE_IN_SIZE); 42826026Sbrian} 42926026Sbrian 43026026Sbrian 431127094Sdesstatic u_int 43226026SbrianStartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 433127094Sdes u_short src_port, u_short dst_port, int link_type) 43426026Sbrian{ 435127094Sdes u_int n; 43626026Sbrian 437127094Sdes n = src_addr.s_addr; 438127094Sdes n += dst_addr.s_addr; 439127094Sdes if (link_type != LINK_PPTP) { 440127094Sdes n += src_port; 441127094Sdes n += dst_port; 442127094Sdes } 443127094Sdes n += link_type; 44426026Sbrian 445127094Sdes return (n % LINK_TABLE_OUT_SIZE); 44626026Sbrian} 44726026Sbrian 44826026Sbrian 44926026Sbrianstatic int 45026026SbrianSeqDiff(u_long x, u_long y) 45126026Sbrian{ 45226026Sbrian/* Return the difference between two TCP sequence numbers */ 45326026Sbrian 45426026Sbrian/* 45526026Sbrian This function is encapsulated in case there are any unusual 45626026Sbrian arithmetic conditions that need to be considered. 45726026Sbrian*/ 45826026Sbrian 459127094Sdes return (ntohl(y) - ntohl(x)); 46026026Sbrian} 46126026Sbrian 462162674Spiso#ifdef _KERNEL 46326026Sbrian 46426026Sbrianstatic void 465162674SpisoAliasLog(char *str, const char *format, ...) 466162674Spiso{ 467162674Spiso va_list ap; 468162674Spiso 469162674Spiso va_start(ap, format); 470162674Spiso vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap); 471162674Spiso va_end(ap); 472162674Spiso} 473162674Spiso#else 474162674Spisostatic void 475162674SpisoAliasLog(FILE *stream, const char *format, ...) 476162674Spiso{ 477162674Spiso va_list ap; 478162674Spiso 479162674Spiso va_start(ap, format); 480162674Spiso vfprintf(stream, format, ap); 481162674Spiso va_end(ap); 482162674Spiso fflush(stream); 483162674Spiso} 484162674Spiso#endif 485162674Spiso 486162674Spisostatic void 487124621SphkShowAliasStats(struct libalias *la) 48826026Sbrian{ 489165243Spiso 490165243Spiso LIBALIAS_LOCK_ASSERT(la); 49126026Sbrian/* Used for debugging */ 492162674Spiso if (la->logDesc) { 493162674Spiso int tot = la->icmpLinkCount + la->udpLinkCount + 494188294Spiso (la->sctpLinkCount>>1) + /* sctp counts half associations */ 495162674Spiso la->tcpLinkCount + la->pptpLinkCount + 496162674Spiso la->protoLinkCount + la->fragmentIdLinkCount + 497162674Spiso la->fragmentPtrLinkCount; 498162674Spiso 499162674Spiso AliasLog(la->logDesc, 500188294Spiso "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u", 501162674Spiso la->icmpLinkCount, 502162674Spiso la->udpLinkCount, 503162674Spiso la->tcpLinkCount, 504188294Spiso la->sctpLinkCount>>1, /* sctp counts half associations */ 505162674Spiso la->pptpLinkCount, 506162674Spiso la->protoLinkCount, 507162674Spiso la->fragmentIdLinkCount, 508162674Spiso la->fragmentPtrLinkCount, tot); 509162674Spiso#ifndef _KERNEL 510162674Spiso AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount); 511162674Spiso#endif 512127094Sdes } 51326026Sbrian} 51426026Sbrian 515188294Spisovoid SctpShowAliasStats(struct libalias *la) 516188294Spiso{ 517188294Spiso 518188294Spiso ShowAliasStats(la); 519188294Spiso} 520188294Spiso 521188294Spiso 52226026Sbrian/* Internal routines for finding, deleting and adding links 52326026Sbrian 52426026SbrianPort Allocation: 52526026Sbrian GetNewPort() -- find and reserve new alias port number 52626026Sbrian GetSocket() -- try to allocate a socket for a given port 52726026Sbrian 52826026SbrianLink creation and deletion: 52926026Sbrian CleanupAliasData() - remove all link chains from lookup table 53026026Sbrian IncrementalCleanup() - look for stale links in a single chain 53126026Sbrian DeleteLink() - remove link 53299207Sbrian AddLink() - add link 53399207Sbrian ReLink() - change link 53426026Sbrian 53526026SbrianLink search: 53626026Sbrian FindLinkOut() - find link for outgoing packets 53726026Sbrian FindLinkIn() - find link for incoming packets 53863899Sarchie 53963899SarchiePort search: 54099207Sbrian FindNewPortGroup() - find an available group of ports 54126026Sbrian*/ 54226026Sbrian 54326026Sbrian/* Local prototypes */ 544127094Sdesstatic int GetNewPort(struct libalias *, struct alias_link *, int); 545145926Sglebius#ifndef NO_USE_SOCKETS 546127094Sdesstatic u_short GetSocket(struct libalias *, u_short, int *, int); 547145926Sglebius#endif 548127094Sdesstatic void CleanupAliasData(struct libalias *); 54926026Sbrian 550127094Sdesstatic void IncrementalCleanup(struct libalias *); 55126026Sbrian 552127094Sdesstatic void DeleteLink(struct alias_link *); 55326026Sbrian 55426026Sbrianstatic struct alias_link * 55532377SeivindReLink(struct alias_link *, 556127094Sdes struct in_addr, struct in_addr, struct in_addr, 557127094Sdes u_short, u_short, int, int); 55832377Seivind 55932377Seivindstatic struct alias_link * 560127094Sdes FindLinkOut (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 56126026Sbrian 56226026Sbrianstatic struct alias_link * 563127094Sdes FindLinkIn (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 56426026Sbrian 56526026Sbrian 56626026Sbrian#define ALIAS_PORT_BASE 0x08000 56726026Sbrian#define ALIAS_PORT_MASK 0x07fff 56863899Sarchie#define ALIAS_PORT_MASK_EVEN 0x07ffe 56926026Sbrian#define GET_NEW_PORT_MAX_ATTEMPTS 20 57026026Sbrian 57163899Sarchie#define FIND_EVEN_ALIAS_BASE 1 57263899Sarchie 57326026Sbrian/* GetNewPort() allocates port numbers. Note that if a port number 57426026Sbrian is already in use, that does not mean that it cannot be used by 57526026Sbrian another link concurrently. This is because GetNewPort() looks for 57626026Sbrian unused triplets: (dest addr, dest port, alias port). */ 57726026Sbrian 57826026Sbrianstatic int 579131614SdesGetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) 58026026Sbrian{ 581127094Sdes int i; 582127094Sdes int max_trials; 583127094Sdes u_short port_sys; 584127094Sdes u_short port_net; 58526026Sbrian 586165243Spiso LIBALIAS_LOCK_ASSERT(la); 58726026Sbrian/* 58826026Sbrian Description of alias_port_param for GetNewPort(). When 58926026Sbrian this parameter is zero or positive, it precisely specifies 59026026Sbrian the port number. GetNewPort() will return this number 59126026Sbrian without check that it is in use. 59226026Sbrian 59361861Sru When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 59426026Sbrian selected port number. 59526026Sbrian*/ 59699207Sbrian 597127094Sdes if (alias_port_param == GET_ALIAS_PORT) { 598127094Sdes /* 599127094Sdes * The aliasing port is automatically selected by one of 600127094Sdes * two methods below: 601127094Sdes */ 602127094Sdes max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 60326026Sbrian 604127094Sdes if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 605127094Sdes /* 606127094Sdes * When the PKT_ALIAS_SAME_PORTS option is chosen, 607127094Sdes * the first try will be the actual source port. If 608127094Sdes * this is already in use, the remainder of the 609127094Sdes * trials will be random. 610127094Sdes */ 611131614Sdes port_net = lnk->src_port; 612127094Sdes port_sys = ntohs(port_net); 613127094Sdes } else { 614127094Sdes /* First trial and all subsequent are random. */ 615182488Scsjp port_sys = arc4random() & ALIAS_PORT_MASK; 616127094Sdes port_sys += ALIAS_PORT_BASE; 617127094Sdes port_net = htons(port_sys); 618127094Sdes } 619127094Sdes } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { 620131614Sdes lnk->alias_port = (u_short) alias_port_param; 621127094Sdes return (0); 622127094Sdes } else { 623145961Sglebius#ifdef LIBALIAS_DEBUG 624127094Sdes fprintf(stderr, "PacketAlias/GetNewPort(): "); 625127094Sdes fprintf(stderr, "input parameter error\n"); 62644616Sbrian#endif 627127094Sdes return (-1); 628127094Sdes } 62926026Sbrian 63026026Sbrian 63126026Sbrian/* Port number search */ 632127094Sdes for (i = 0; i < max_trials; i++) { 633127094Sdes int go_ahead; 634127094Sdes struct alias_link *search_result; 63526026Sbrian 636131614Sdes search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr, 637131614Sdes lnk->dst_port, port_net, 638131614Sdes lnk->link_type, 0); 63926026Sbrian 640127094Sdes if (search_result == NULL) 641127094Sdes go_ahead = 1; 642131614Sdes else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED) 643127094Sdes && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 644127094Sdes go_ahead = 1; 645127094Sdes else 646127094Sdes go_ahead = 0; 64726026Sbrian 648127094Sdes if (go_ahead) { 649145926Sglebius#ifndef NO_USE_SOCKETS 650127094Sdes if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) 651131614Sdes && (lnk->flags & LINK_PARTIALLY_SPECIFIED) 652131614Sdes && ((lnk->link_type == LINK_TCP) || 653131614Sdes (lnk->link_type == LINK_UDP))) { 654131614Sdes if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) { 655131614Sdes lnk->alias_port = port_net; 656127094Sdes return (0); 657127094Sdes } 658127094Sdes } else { 659145926Sglebius#endif 660131614Sdes lnk->alias_port = port_net; 661127094Sdes return (0); 662145926Sglebius#ifndef NO_USE_SOCKETS 663127094Sdes } 664145926Sglebius#endif 665127094Sdes } 666182488Scsjp port_sys = arc4random() & ALIAS_PORT_MASK; 667127094Sdes port_sys += ALIAS_PORT_BASE; 668127094Sdes port_net = htons(port_sys); 669127094Sdes } 67026026Sbrian 671145961Sglebius#ifdef LIBALIAS_DEBUG 672127094Sdes fprintf(stderr, "PacketAlias/GetnewPort(): "); 673127094Sdes fprintf(stderr, "could not find free port\n"); 67444616Sbrian#endif 67526026Sbrian 676127094Sdes return (-1); 67726026Sbrian} 67826026Sbrian 679145926Sglebius#ifndef NO_USE_SOCKETS 680127094Sdesstatic u_short 681124621SphkGetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type) 68226026Sbrian{ 683127094Sdes int err; 684127094Sdes int sock; 685127094Sdes struct sockaddr_in sock_addr; 68626026Sbrian 687165243Spiso LIBALIAS_LOCK_ASSERT(la); 688127094Sdes if (link_type == LINK_TCP) 689127094Sdes sock = socket(AF_INET, SOCK_STREAM, 0); 690127094Sdes else if (link_type == LINK_UDP) 691127094Sdes sock = socket(AF_INET, SOCK_DGRAM, 0); 692127094Sdes else { 693145961Sglebius#ifdef LIBALIAS_DEBUG 694127094Sdes fprintf(stderr, "PacketAlias/GetSocket(): "); 695127094Sdes fprintf(stderr, "incorrect link type\n"); 69644616Sbrian#endif 697127094Sdes return (0); 698127094Sdes } 69926026Sbrian 700127094Sdes if (sock < 0) { 701145961Sglebius#ifdef LIBALIAS_DEBUG 702127094Sdes fprintf(stderr, "PacketAlias/GetSocket(): "); 703127094Sdes fprintf(stderr, "socket() error %d\n", *sockfd); 70444616Sbrian#endif 705127094Sdes return (0); 706127094Sdes } 707127094Sdes sock_addr.sin_family = AF_INET; 708127094Sdes sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 709127094Sdes sock_addr.sin_port = port_net; 71026026Sbrian 711127094Sdes err = bind(sock, 712127094Sdes (struct sockaddr *)&sock_addr, 713127094Sdes sizeof(sock_addr)); 714127094Sdes if (err == 0) { 715127094Sdes la->sockCount++; 716127094Sdes *sockfd = sock; 717127094Sdes return (1); 718127094Sdes } else { 719127094Sdes close(sock); 720127094Sdes return (0); 721127094Sdes } 72226026Sbrian} 723145926Sglebius#endif 72426026Sbrian 72599207Sbrian/* FindNewPortGroup() returns a base port number for an available 72663899Sarchie range of contiguous port numbers. Note that if a port number 72763899Sarchie is already in use, that does not mean that it cannot be used by 72863899Sarchie another link concurrently. This is because FindNewPortGroup() 72963899Sarchie looks for unused triplets: (dest addr, dest port, alias port). */ 73063899Sarchie 73163899Sarchieint 732124621SphkFindNewPortGroup(struct libalias *la, 733127094Sdes struct in_addr dst_addr, 734127094Sdes struct in_addr alias_addr, 735127094Sdes u_short src_port, 736127094Sdes u_short dst_port, 737127094Sdes u_short port_count, 738127094Sdes u_char proto, 739127094Sdes u_char align) 74063899Sarchie{ 741127094Sdes int i, j; 742127094Sdes int max_trials; 743127094Sdes u_short port_sys; 744127094Sdes int link_type; 74563899Sarchie 746165243Spiso LIBALIAS_LOCK_ASSERT(la); 747127094Sdes /* 748127094Sdes * Get link_type from protocol 749127094Sdes */ 75063899Sarchie 751127094Sdes switch (proto) { 752127094Sdes case IPPROTO_UDP: 753127094Sdes link_type = LINK_UDP; 754127094Sdes break; 755127094Sdes case IPPROTO_TCP: 756127094Sdes link_type = LINK_TCP; 757127094Sdes break; 758127094Sdes default: 759127094Sdes return (0); 760127094Sdes break; 761127094Sdes } 76263899Sarchie 763127094Sdes /* 764127094Sdes * The aliasing port is automatically selected by one of two 765127094Sdes * methods below: 766127094Sdes */ 767127094Sdes max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 76863899Sarchie 769127094Sdes if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 770127094Sdes /* 771127094Sdes * When the ALIAS_SAME_PORTS option is chosen, the first 772127094Sdes * try will be the actual source port. If this is already 773127094Sdes * in use, the remainder of the trials will be random. 774127094Sdes */ 775127094Sdes port_sys = ntohs(src_port); 77663899Sarchie 777127094Sdes } else { 77863899Sarchie 779127094Sdes /* First trial and all subsequent are random. */ 780127094Sdes if (align == FIND_EVEN_ALIAS_BASE) 781182488Scsjp port_sys = arc4random() & ALIAS_PORT_MASK_EVEN; 782127094Sdes else 783182488Scsjp port_sys = arc4random() & ALIAS_PORT_MASK; 78463899Sarchie 785127094Sdes port_sys += ALIAS_PORT_BASE; 786127094Sdes } 78763899Sarchie 78863899Sarchie/* Port number search */ 789127094Sdes for (i = 0; i < max_trials; i++) { 79063899Sarchie 791127094Sdes struct alias_link *search_result; 79263899Sarchie 793127094Sdes for (j = 0; j < port_count; j++) 794127094Sdes if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr, 795127094Sdes dst_port, htons(port_sys + j), 796127094Sdes link_type, 0))) 797127094Sdes break; 79863899Sarchie 799127094Sdes /* Found a good range, return base */ 800127094Sdes if (j == port_count) 801127094Sdes return (htons(port_sys)); 80263899Sarchie 803127094Sdes /* Find a new base to try */ 804127094Sdes if (align == FIND_EVEN_ALIAS_BASE) 805182488Scsjp port_sys = arc4random() & ALIAS_PORT_MASK_EVEN; 806127094Sdes else 807182488Scsjp port_sys = arc4random() & ALIAS_PORT_MASK; 80863899Sarchie 809127094Sdes port_sys += ALIAS_PORT_BASE; 810127094Sdes } 81163899Sarchie 812145961Sglebius#ifdef LIBALIAS_DEBUG 813127094Sdes fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 814127094Sdes fprintf(stderr, "could not find free port(s)\n"); 81563899Sarchie#endif 81663899Sarchie 817127094Sdes return (0); 81863899Sarchie} 81963899Sarchie 82026026Sbrianstatic void 821124621SphkCleanupAliasData(struct libalias *la) 82226026Sbrian{ 823131614Sdes struct alias_link *lnk; 824179480Smav int i; 82526026Sbrian 826165243Spiso LIBALIAS_LOCK_ASSERT(la); 827127094Sdes for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 828179924Smav lnk = LIST_FIRST(&la->linkTableOut[i]); 829179924Smav while (lnk != NULL) { 830179924Smav struct alias_link *link_next = LIST_NEXT(lnk, list_out); 831131614Sdes DeleteLink(lnk); 832179924Smav lnk = link_next; 833179924Smav } 834127094Sdes } 835127094Sdes 836127094Sdes la->cleanupIndex = 0; 83726026Sbrian} 83826026Sbrian 83926026Sbrian 84026026Sbrianstatic void 841124621SphkIncrementalCleanup(struct libalias *la) 84226026Sbrian{ 843179480Smav struct alias_link *lnk, *lnk_tmp; 84426026Sbrian 845165243Spiso LIBALIAS_LOCK_ASSERT(la); 846179480Smav LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++], 847179480Smav list_out, lnk_tmp) { 848179480Smav if (la->timeStamp - lnk->timestamp > lnk->expire_time) 849179480Smav DeleteLink(lnk); 850127094Sdes } 85126026Sbrian 852127094Sdes if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) 853127094Sdes la->cleanupIndex = 0; 85426026Sbrian} 85526026Sbrian 85664643Srustatic void 857131614SdesDeleteLink(struct alias_link *lnk) 85826026Sbrian{ 859131614Sdes struct libalias *la = lnk->la; 86026026Sbrian 861165243Spiso LIBALIAS_LOCK_ASSERT(la); 86226026Sbrian/* Don't do anything if the link is marked permanent */ 863131614Sdes if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT) 864127094Sdes return; 86526026Sbrian 86635314Sbrian#ifndef NO_FW_PUNCH 86759356Sru/* Delete associated firewall hole, if any */ 868131614Sdes ClearFWHole(lnk); 86935314Sbrian#endif 87032377Seivind 87159702Sru/* Free memory allocated for LSNAT server pool */ 872131614Sdes if (lnk->server != NULL) { 873127094Sdes struct server *head, *curr, *next; 87459702Sru 875131614Sdes head = curr = lnk->server; 876127094Sdes do { 877127094Sdes next = curr->next; 878127094Sdes free(curr); 879127094Sdes } while ((curr = next) != head); 880127094Sdes } 88126026Sbrian/* Adjust output table pointers */ 882131614Sdes LIST_REMOVE(lnk, list_out); 88326026Sbrian 88426026Sbrian/* Adjust input table pointers */ 885131614Sdes LIST_REMOVE(lnk, list_in); 886145926Sglebius#ifndef NO_USE_SOCKETS 88726026Sbrian/* Close socket, if one has been allocated */ 888131614Sdes if (lnk->sockfd != -1) { 889127094Sdes la->sockCount--; 890131614Sdes close(lnk->sockfd); 891127094Sdes } 892145926Sglebius#endif 89326026Sbrian/* Link-type dependent cleanup */ 894131614Sdes switch (lnk->link_type) { 895127094Sdes case LINK_ICMP: 896127094Sdes la->icmpLinkCount--; 897127094Sdes break; 898127094Sdes case LINK_UDP: 899127094Sdes la->udpLinkCount--; 900127094Sdes break; 901127094Sdes case LINK_TCP: 902127094Sdes la->tcpLinkCount--; 903131614Sdes free(lnk->data.tcp); 904127094Sdes break; 905127094Sdes case LINK_PPTP: 906127094Sdes la->pptpLinkCount--; 907127094Sdes break; 908127094Sdes case LINK_FRAGMENT_ID: 909127094Sdes la->fragmentIdLinkCount--; 910127094Sdes break; 911127094Sdes case LINK_FRAGMENT_PTR: 912127094Sdes la->fragmentPtrLinkCount--; 913131614Sdes if (lnk->data.frag_ptr != NULL) 914131614Sdes free(lnk->data.frag_ptr); 915127094Sdes break; 91659726Sru case LINK_ADDR: 917127094Sdes break; 918127094Sdes default: 919127094Sdes la->protoLinkCount--; 920127094Sdes break; 921127094Sdes } 92226026Sbrian 92326026Sbrian/* Free memory */ 924131614Sdes free(lnk); 92526026Sbrian 92626026Sbrian/* Write statistics, if logging enabled */ 927127094Sdes if (la->packetAliasMode & PKT_ALIAS_LOG) { 928127094Sdes ShowAliasStats(la); 929127094Sdes } 93026026Sbrian} 93126026Sbrian 93226026Sbrian 933223437Saestruct alias_link * 934223437SaeAddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, 935223437Sae struct in_addr alias_addr, u_short src_port, u_short dst_port, 936223437Sae int alias_port_param, int link_type) 937223437Sae{ 938223437Sae u_int start_point; 939131614Sdes struct alias_link *lnk; 94026026Sbrian 941165243Spiso LIBALIAS_LOCK_ASSERT(la); 942131614Sdes lnk = malloc(sizeof(struct alias_link)); 943131614Sdes if (lnk != NULL) { 944127094Sdes /* Basic initialization */ 945131614Sdes lnk->la = la; 946131614Sdes lnk->src_addr = src_addr; 947131614Sdes lnk->dst_addr = dst_addr; 948131614Sdes lnk->alias_addr = alias_addr; 949131614Sdes lnk->proxy_addr.s_addr = INADDR_ANY; 950131614Sdes lnk->src_port = src_port; 951131614Sdes lnk->dst_port = dst_port; 952131614Sdes lnk->proxy_port = 0; 953131614Sdes lnk->server = NULL; 954131614Sdes lnk->link_type = link_type; 955145926Sglebius#ifndef NO_USE_SOCKETS 956131614Sdes lnk->sockfd = -1; 957145926Sglebius#endif 958131614Sdes lnk->flags = 0; 959131614Sdes lnk->pflags = 0; 960131614Sdes lnk->timestamp = la->timeStamp; 96126026Sbrian 962127094Sdes /* Expiration time */ 963127094Sdes switch (link_type) { 964127094Sdes case LINK_ICMP: 965131614Sdes lnk->expire_time = ICMP_EXPIRE_TIME; 966127094Sdes break; 967127094Sdes case LINK_UDP: 968131614Sdes lnk->expire_time = UDP_EXPIRE_TIME; 969127094Sdes break; 970127094Sdes case LINK_TCP: 971131614Sdes lnk->expire_time = TCP_EXPIRE_INITIAL; 972127094Sdes break; 973127094Sdes case LINK_PPTP: 974131614Sdes lnk->flags |= LINK_PERMANENT; /* no timeout. */ 975127094Sdes break; 976127094Sdes case LINK_FRAGMENT_ID: 977131614Sdes lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; 978127094Sdes break; 979127094Sdes case LINK_FRAGMENT_PTR: 980131614Sdes lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 981127094Sdes break; 982127094Sdes case LINK_ADDR: 983127094Sdes break; 984127094Sdes default: 985131614Sdes lnk->expire_time = PROTO_EXPIRE_TIME; 986127094Sdes break; 987127094Sdes } 98826026Sbrian 989127094Sdes /* Determine alias flags */ 990127094Sdes if (dst_addr.s_addr == INADDR_ANY) 991131614Sdes lnk->flags |= LINK_UNKNOWN_DEST_ADDR; 992127094Sdes if (dst_port == 0) 993131614Sdes lnk->flags |= LINK_UNKNOWN_DEST_PORT; 99426026Sbrian 995127094Sdes /* Determine alias port */ 996131614Sdes if (GetNewPort(la, lnk, alias_port_param) != 0) { 997131614Sdes free(lnk); 998127094Sdes return (NULL); 999127094Sdes } 1000127094Sdes /* Link-type dependent initialization */ 1001127094Sdes switch (link_type) { 1002127094Sdes struct tcp_dat *aux_tcp; 100326026Sbrian 1004127094Sdes case LINK_ICMP: 1005127094Sdes la->icmpLinkCount++; 1006127094Sdes break; 1007127094Sdes case LINK_UDP: 1008127094Sdes la->udpLinkCount++; 1009127094Sdes break; 1010127094Sdes case LINK_TCP: 1011127094Sdes aux_tcp = malloc(sizeof(struct tcp_dat)); 1012127094Sdes if (aux_tcp != NULL) { 1013127094Sdes int i; 101426026Sbrian 1015127094Sdes la->tcpLinkCount++; 1016127094Sdes aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 1017127094Sdes aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1018127094Sdes aux_tcp->state.index = 0; 1019127094Sdes aux_tcp->state.ack_modified = 0; 1020127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) 1021127094Sdes aux_tcp->ack[i].active = 0; 1022127094Sdes aux_tcp->fwhole = -1; 1023131614Sdes lnk->data.tcp = aux_tcp; 1024127094Sdes } else { 1025145961Sglebius#ifdef LIBALIAS_DEBUG 1026127094Sdes fprintf(stderr, "PacketAlias/AddLink: "); 1027127094Sdes fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 102844616Sbrian#endif 1029131614Sdes free(lnk); 1030127094Sdes return (NULL); 1031127094Sdes } 1032127094Sdes break; 1033127094Sdes case LINK_PPTP: 1034127094Sdes la->pptpLinkCount++; 1035127094Sdes break; 1036127094Sdes case LINK_FRAGMENT_ID: 1037127094Sdes la->fragmentIdLinkCount++; 1038127094Sdes break; 1039127094Sdes case LINK_FRAGMENT_PTR: 1040127094Sdes la->fragmentPtrLinkCount++; 1041127094Sdes break; 1042127094Sdes case LINK_ADDR: 1043127094Sdes break; 1044127094Sdes default: 1045127094Sdes la->protoLinkCount++; 1046127094Sdes break; 1047127094Sdes } 104867316Sru 1049127094Sdes /* Set up pointers for output lookup table */ 1050127094Sdes start_point = StartPointOut(src_addr, dst_addr, 1051127094Sdes src_port, dst_port, link_type); 1052131614Sdes LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); 105367316Sru 1054127094Sdes /* Set up pointers for input lookup table */ 1055131614Sdes start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); 1056131614Sdes LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); 1057127094Sdes } else { 1058145961Sglebius#ifdef LIBALIAS_DEBUG 1059127094Sdes fprintf(stderr, "PacketAlias/AddLink(): "); 1060127094Sdes fprintf(stderr, "malloc() call failed.\n"); 106144616Sbrian#endif 1062127094Sdes } 1063127094Sdes if (la->packetAliasMode & PKT_ALIAS_LOG) { 1064127094Sdes ShowAliasStats(la); 1065127094Sdes } 1066131614Sdes return (lnk); 106726026Sbrian} 106826026Sbrian 106932377Seivindstatic struct alias_link * 1070131614SdesReLink(struct alias_link *old_lnk, 1071127094Sdes struct in_addr src_addr, 1072127094Sdes struct in_addr dst_addr, 1073127094Sdes struct in_addr alias_addr, 1074127094Sdes u_short src_port, 1075127094Sdes u_short dst_port, 1076127094Sdes int alias_port_param, /* if less than zero, alias */ 1077127094Sdes int link_type) 1078127094Sdes{ /* port will be automatically *//* chosen. 1079127094Sdes * If greater than */ 1080131614Sdes struct alias_link *new_lnk; /* zero, equal to alias port */ 1081131614Sdes struct libalias *la = old_lnk->la; 108226026Sbrian 1083165243Spiso LIBALIAS_LOCK_ASSERT(la); 1084131614Sdes new_lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1085127094Sdes src_port, dst_port, alias_port_param, 1086127094Sdes link_type); 108735314Sbrian#ifndef NO_FW_PUNCH 1088131614Sdes if (new_lnk != NULL && 1089131614Sdes old_lnk->link_type == LINK_TCP && 1090131614Sdes old_lnk->data.tcp->fwhole > 0) { 1091131614Sdes PunchFWHole(new_lnk); 1092127094Sdes } 109335314Sbrian#endif 1094131614Sdes DeleteLink(old_lnk); 1095131614Sdes return (new_lnk); 109632377Seivind} 109732377Seivind 109826026Sbrianstatic struct alias_link * 1099124621Sphk_FindLinkOut(struct libalias *la, struct in_addr src_addr, 1100127094Sdes struct in_addr dst_addr, 1101127094Sdes u_short src_port, 1102127094Sdes u_short dst_port, 1103127094Sdes int link_type, 1104127094Sdes int replace_partial_links) 110526026Sbrian{ 1106127094Sdes u_int i; 1107131614Sdes struct alias_link *lnk; 110826026Sbrian 1109165243Spiso LIBALIAS_LOCK_ASSERT(la); 1110127094Sdes i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1111131614Sdes LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { 1112179480Smav if (lnk->dst_addr.s_addr == dst_addr.s_addr && 1113179480Smav lnk->src_addr.s_addr == src_addr.s_addr && 1114179480Smav lnk->src_port == src_port && 1115179480Smav lnk->dst_port == dst_port && 1116179480Smav lnk->link_type == link_type && 1117179480Smav lnk->server == NULL) { 1118131614Sdes lnk->timestamp = la->timeStamp; 1119127094Sdes break; 1120127094Sdes } 1121127094Sdes } 112226026Sbrian 112351494Sru/* Search for partially specified links. */ 1124131614Sdes if (lnk == NULL && replace_partial_links) { 1125127094Sdes if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1126131614Sdes lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1127127094Sdes link_type, 0); 1128131614Sdes if (lnk == NULL) 1129131614Sdes lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 1130127094Sdes dst_port, link_type, 0); 1131127094Sdes } 1132131614Sdes if (lnk == NULL && 1133127094Sdes (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1134131614Sdes lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, 1135127094Sdes link_type, 0); 1136127094Sdes } 1137131614Sdes if (lnk != NULL) { 1138131614Sdes lnk = ReLink(lnk, 1139131614Sdes src_addr, dst_addr, lnk->alias_addr, 1140131614Sdes src_port, dst_port, lnk->alias_port, 1141127094Sdes link_type); 1142127094Sdes } 1143127094Sdes } 1144131614Sdes return (lnk); 114526026Sbrian} 114626026Sbrian 114751727Srustatic struct alias_link * 1148124621SphkFindLinkOut(struct libalias *la, struct in_addr src_addr, 1149127094Sdes struct in_addr dst_addr, 1150127094Sdes u_short src_port, 1151127094Sdes u_short dst_port, 1152127094Sdes int link_type, 1153127094Sdes int replace_partial_links) 115451727Sru{ 1155131614Sdes struct alias_link *lnk; 115626026Sbrian 1157165243Spiso LIBALIAS_LOCK_ASSERT(la); 1158131614Sdes lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1159127094Sdes link_type, replace_partial_links); 116051727Sru 1161131614Sdes if (lnk == NULL) { 1162127094Sdes /* 1163127094Sdes * The following allows permanent links to be specified as 1164127094Sdes * using the default source address (i.e. device interface 1165127094Sdes * address) without knowing in advance what that address 1166127094Sdes * is. 1167127094Sdes */ 1168127094Sdes if (la->aliasAddress.s_addr != INADDR_ANY && 1169127094Sdes src_addr.s_addr == la->aliasAddress.s_addr) { 1170131614Sdes lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, 1171127094Sdes link_type, replace_partial_links); 1172127094Sdes } 1173127094Sdes } 1174131614Sdes return (lnk); 117551727Sru} 117651727Sru 117751727Sru 117858279Sbrianstatic struct alias_link * 1179124621Sphk_FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1180127094Sdes struct in_addr alias_addr, 1181127094Sdes u_short dst_port, 1182127094Sdes u_short alias_port, 1183127094Sdes int link_type, 1184127094Sdes int replace_partial_links) 118526026Sbrian{ 1186127094Sdes int flags_in; 1187127094Sdes u_int start_point; 1188131614Sdes struct alias_link *lnk; 1189131614Sdes struct alias_link *lnk_fully_specified; 1190131614Sdes struct alias_link *lnk_unknown_all; 1191131614Sdes struct alias_link *lnk_unknown_dst_addr; 1192131614Sdes struct alias_link *lnk_unknown_dst_port; 119326026Sbrian 1194165243Spiso LIBALIAS_LOCK_ASSERT(la); 119526026Sbrian/* Initialize pointers */ 1196131614Sdes lnk_fully_specified = NULL; 1197131614Sdes lnk_unknown_all = NULL; 1198131614Sdes lnk_unknown_dst_addr = NULL; 1199131614Sdes lnk_unknown_dst_port = NULL; 120026026Sbrian 120126026Sbrian/* If either the dest addr or port is unknown, the search 120226026Sbrian loop will have to know about this. */ 120326026Sbrian 1204127094Sdes flags_in = 0; 1205127094Sdes if (dst_addr.s_addr == INADDR_ANY) 1206127094Sdes flags_in |= LINK_UNKNOWN_DEST_ADDR; 1207127094Sdes if (dst_port == 0) 1208127094Sdes flags_in |= LINK_UNKNOWN_DEST_PORT; 120926026Sbrian 121026026Sbrian/* Search loop */ 1211127094Sdes start_point = StartPointIn(alias_addr, alias_port, link_type); 1212131614Sdes LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { 1213127094Sdes int flags; 121426026Sbrian 1215131614Sdes flags = flags_in | lnk->flags; 1216127094Sdes if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1217131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1218131614Sdes && lnk->alias_port == alias_port 1219131614Sdes && lnk->dst_addr.s_addr == dst_addr.s_addr 1220131614Sdes && lnk->dst_port == dst_port 1221131614Sdes && lnk->link_type == link_type) { 1222131614Sdes lnk_fully_specified = lnk; 1223127094Sdes break; 1224127094Sdes } 1225127094Sdes } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1226127094Sdes && (flags & LINK_UNKNOWN_DEST_PORT)) { 1227131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1228131614Sdes && lnk->alias_port == alias_port 1229131614Sdes && lnk->link_type == link_type) { 1230131614Sdes if (lnk_unknown_all == NULL) 1231131614Sdes lnk_unknown_all = lnk; 1232127094Sdes } 1233127094Sdes } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1234131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1235131614Sdes && lnk->alias_port == alias_port 1236131614Sdes && lnk->link_type == link_type 1237131614Sdes && lnk->dst_port == dst_port) { 1238131614Sdes if (lnk_unknown_dst_addr == NULL) 1239131614Sdes lnk_unknown_dst_addr = lnk; 1240127094Sdes } 1241127094Sdes } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1242131614Sdes if (lnk->alias_addr.s_addr == alias_addr.s_addr 1243131614Sdes && lnk->alias_port == alias_port 1244131614Sdes && lnk->link_type == link_type 1245131614Sdes && lnk->dst_addr.s_addr == dst_addr.s_addr) { 1246131614Sdes if (lnk_unknown_dst_port == NULL) 1247131614Sdes lnk_unknown_dst_port = lnk; 1248127094Sdes } 1249127094Sdes } 1250127094Sdes } 125126026Sbrian 125226026Sbrian 125326026Sbrian 1254131614Sdes if (lnk_fully_specified != NULL) { 1255131614Sdes lnk_fully_specified->timestamp = la->timeStamp; 1256131614Sdes lnk = lnk_fully_specified; 1257131614Sdes } else if (lnk_unknown_dst_port != NULL) 1258131614Sdes lnk = lnk_unknown_dst_port; 1259131614Sdes else if (lnk_unknown_dst_addr != NULL) 1260131614Sdes lnk = lnk_unknown_dst_addr; 1261131614Sdes else if (lnk_unknown_all != NULL) 1262131614Sdes lnk = lnk_unknown_all; 1263127094Sdes else 1264127094Sdes return (NULL); 126559702Sru 1266127094Sdes if (replace_partial_links && 1267131614Sdes (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { 1268127094Sdes struct in_addr src_addr; 1269127094Sdes u_short src_port; 127059702Sru 1271131614Sdes if (lnk->server != NULL) { /* LSNAT link */ 1272131614Sdes src_addr = lnk->server->addr; 1273131614Sdes src_port = lnk->server->port; 1274131614Sdes lnk->server = lnk->server->next; 1275127094Sdes } else { 1276131614Sdes src_addr = lnk->src_addr; 1277131614Sdes src_port = lnk->src_port; 1278127094Sdes } 1279127094Sdes 1280188294Spiso if (link_type == LINK_SCTP) { 1281188294Spiso lnk->src_addr = src_addr; 1282188294Spiso lnk->src_port = src_port; 1283188294Spiso return(lnk); 1284188294Spiso } 1285131614Sdes lnk = ReLink(lnk, 1286127094Sdes src_addr, dst_addr, alias_addr, 1287127094Sdes src_port, dst_port, alias_port, 1288127094Sdes link_type); 128959702Sru } 1290131614Sdes return (lnk); 129126026Sbrian} 129226026Sbrian 129359181Srustatic struct alias_link * 1294124621SphkFindLinkIn(struct libalias *la, struct in_addr dst_addr, 1295127094Sdes struct in_addr alias_addr, 1296127094Sdes u_short dst_port, 1297127094Sdes u_short alias_port, 1298127094Sdes int link_type, 1299127094Sdes int replace_partial_links) 130051727Sru{ 1301131614Sdes struct alias_link *lnk; 130226026Sbrian 1303165243Spiso LIBALIAS_LOCK_ASSERT(la); 1304131614Sdes lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1305127094Sdes link_type, replace_partial_links); 130626026Sbrian 1307131614Sdes if (lnk == NULL) { 1308127094Sdes /* 1309127094Sdes * The following allows permanent links to be specified as 1310127094Sdes * using the default aliasing address (i.e. device 1311127094Sdes * interface address) without knowing in advance what that 1312127094Sdes * address is. 1313127094Sdes */ 1314127094Sdes if (la->aliasAddress.s_addr != INADDR_ANY && 1315127094Sdes alias_addr.s_addr == la->aliasAddress.s_addr) { 1316131614Sdes lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, 1317127094Sdes link_type, replace_partial_links); 1318127094Sdes } 1319127094Sdes } 1320131614Sdes return (lnk); 132151727Sru} 132251727Sru 132351727Sru 132451727Sru 132551727Sru 132626026Sbrian/* External routines for finding/adding links 132726026Sbrian 132826026Sbrian-- "external" means outside alias_db.c, but within alias*.c -- 132926026Sbrian 133026026Sbrian FindIcmpIn(), FindIcmpOut() 133126026Sbrian FindFragmentIn1(), FindFragmentIn2() 133226026Sbrian AddFragmentPtrLink(), FindFragmentPtr() 133359726Sru FindProtoIn(), FindProtoOut() 133426026Sbrian FindUdpTcpIn(), FindUdpTcpOut() 133567966Sru AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 133667966Sru FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 133726026Sbrian FindOriginalAddress(), FindAliasAddress() 133826026Sbrian 133926026Sbrian(prototypes in alias_local.h) 134026026Sbrian*/ 134126026Sbrian 134226026Sbrian 134326026Sbrianstruct alias_link * 1344124621SphkFindIcmpIn(struct libalias *la, struct in_addr dst_addr, 1345127094Sdes struct in_addr alias_addr, 1346127094Sdes u_short id_alias, 1347127094Sdes int create) 134826026Sbrian{ 1349131614Sdes struct alias_link *lnk; 135065280Sru 1351165243Spiso LIBALIAS_LOCK_ASSERT(la); 1352131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1353127094Sdes NO_DEST_PORT, id_alias, 1354127094Sdes LINK_ICMP, 0); 1355131614Sdes if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1356127094Sdes struct in_addr target_addr; 135765280Sru 1358127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1359131614Sdes lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1360127094Sdes id_alias, NO_DEST_PORT, id_alias, 1361127094Sdes LINK_ICMP); 1362127094Sdes } 1363131614Sdes return (lnk); 136426026Sbrian} 136526026Sbrian 136626026Sbrian 136726026Sbrianstruct alias_link * 1368124621SphkFindIcmpOut(struct libalias *la, struct in_addr src_addr, 1369127094Sdes struct in_addr dst_addr, 1370127094Sdes u_short id, 1371127094Sdes int create) 137226026Sbrian{ 1373131614Sdes struct alias_link *lnk; 137426026Sbrian 1375165243Spiso LIBALIAS_LOCK_ASSERT(la); 1376131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, 1377127094Sdes id, NO_DEST_PORT, 1378127094Sdes LINK_ICMP, 0); 1379131614Sdes if (lnk == NULL && create) { 1380127094Sdes struct in_addr alias_addr; 138126026Sbrian 1382127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1383131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1384127094Sdes id, NO_DEST_PORT, GET_ALIAS_ID, 1385127094Sdes LINK_ICMP); 1386127094Sdes } 1387131614Sdes return (lnk); 138826026Sbrian} 138926026Sbrian 139026026Sbrian 139126026Sbrianstruct alias_link * 1392124621SphkFindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1393127094Sdes struct in_addr alias_addr, 1394127094Sdes u_short ip_id) 139526026Sbrian{ 1396131614Sdes struct alias_link *lnk; 139726026Sbrian 1398165243Spiso LIBALIAS_LOCK_ASSERT(la); 1399131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1400127094Sdes NO_DEST_PORT, ip_id, 1401127094Sdes LINK_FRAGMENT_ID, 0); 140226026Sbrian 1403131614Sdes if (lnk == NULL) { 1404131614Sdes lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr, 1405127094Sdes NO_SRC_PORT, NO_DEST_PORT, ip_id, 1406127094Sdes LINK_FRAGMENT_ID); 1407127094Sdes } 1408131614Sdes return (lnk); 140926026Sbrian} 141026026Sbrian 141126026Sbrian 141226026Sbrianstruct alias_link * 1413127094SdesFindFragmentIn2(struct libalias *la, struct in_addr dst_addr, /* Doesn't add a link if 1414127094Sdes * one */ 1415127094Sdes struct in_addr alias_addr, /* is not found. */ 1416127094Sdes u_short ip_id) 141726026Sbrian{ 1418165243Spiso 1419165243Spiso LIBALIAS_LOCK_ASSERT(la); 1420127094Sdes return FindLinkIn(la, dst_addr, alias_addr, 1421127094Sdes NO_DEST_PORT, ip_id, 1422127094Sdes LINK_FRAGMENT_ID, 0); 142326026Sbrian} 142426026Sbrian 142526026Sbrian 142626026Sbrianstruct alias_link * 1427124621SphkAddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1428127094Sdes u_short ip_id) 142926026Sbrian{ 1430165243Spiso 1431165243Spiso LIBALIAS_LOCK_ASSERT(la); 1432127094Sdes return AddLink(la, la->nullAddress, dst_addr, la->nullAddress, 1433127094Sdes NO_SRC_PORT, NO_DEST_PORT, ip_id, 1434127094Sdes LINK_FRAGMENT_PTR); 143526026Sbrian} 143626026Sbrian 143726026Sbrian 143826026Sbrianstruct alias_link * 1439124621SphkFindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1440127094Sdes u_short ip_id) 144126026Sbrian{ 1442165243Spiso 1443165243Spiso LIBALIAS_LOCK_ASSERT(la); 1444127094Sdes return FindLinkIn(la, dst_addr, la->nullAddress, 1445127094Sdes NO_DEST_PORT, ip_id, 1446127094Sdes LINK_FRAGMENT_PTR, 0); 144726026Sbrian} 144826026Sbrian 144926026Sbrian 145026026Sbrianstruct alias_link * 1451124621SphkFindProtoIn(struct libalias *la, struct in_addr dst_addr, 1452127094Sdes struct in_addr alias_addr, 1453127094Sdes u_char proto) 145459356Sru{ 1455131614Sdes struct alias_link *lnk; 145659356Sru 1457165243Spiso LIBALIAS_LOCK_ASSERT(la); 1458131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1459127094Sdes NO_DEST_PORT, 0, 1460127094Sdes proto, 1); 146159356Sru 1462131614Sdes if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1463127094Sdes struct in_addr target_addr; 146459356Sru 1465127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1466131614Sdes lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1467127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 1468127094Sdes proto); 1469127094Sdes } 1470131614Sdes return (lnk); 147159356Sru} 147259356Sru 147359356Sru 147459356Srustruct alias_link * 1475124621SphkFindProtoOut(struct libalias *la, struct in_addr src_addr, 1476127094Sdes struct in_addr dst_addr, 1477127094Sdes u_char proto) 147859356Sru{ 1479131614Sdes struct alias_link *lnk; 148059356Sru 1481165243Spiso LIBALIAS_LOCK_ASSERT(la); 1482131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, 1483127094Sdes NO_SRC_PORT, NO_DEST_PORT, 1484127094Sdes proto, 1); 148559356Sru 1486131614Sdes if (lnk == NULL) { 1487127094Sdes struct in_addr alias_addr; 148859356Sru 1489127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1490131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1491127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 1492127094Sdes proto); 1493127094Sdes } 1494131614Sdes return (lnk); 149559356Sru} 149659356Sru 149759356Sru 149859356Srustruct alias_link * 1499124621SphkFindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1500127094Sdes struct in_addr alias_addr, 1501127094Sdes u_short dst_port, 1502127094Sdes u_short alias_port, 1503127094Sdes u_char proto, 1504127094Sdes int create) 150526026Sbrian{ 1506127094Sdes int link_type; 1507131614Sdes struct alias_link *lnk; 150826026Sbrian 1509165243Spiso LIBALIAS_LOCK_ASSERT(la); 1510127094Sdes switch (proto) { 1511127094Sdes case IPPROTO_UDP: 1512127094Sdes link_type = LINK_UDP; 1513127094Sdes break; 1514127094Sdes case IPPROTO_TCP: 1515127094Sdes link_type = LINK_TCP; 1516127094Sdes break; 1517127094Sdes default: 1518131613Sdes return (NULL); 1519127094Sdes break; 1520127094Sdes } 152126026Sbrian 1522131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1523127094Sdes dst_port, alias_port, 1524127094Sdes link_type, create); 152526026Sbrian 1526131614Sdes if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1527127094Sdes struct in_addr target_addr; 152826026Sbrian 1529127094Sdes target_addr = FindOriginalAddress(la, alias_addr); 1530131614Sdes lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1531127094Sdes alias_port, dst_port, alias_port, 1532127094Sdes link_type); 1533127094Sdes } 1534131614Sdes return (lnk); 153526026Sbrian} 153626026Sbrian 153726026Sbrian 153899207Sbrianstruct alias_link * 1539127094SdesFindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1540127094Sdes struct in_addr dst_addr, 1541127094Sdes u_short src_port, 1542127094Sdes u_short dst_port, 1543127094Sdes u_char proto, 1544127094Sdes int create) 154526026Sbrian{ 1546127094Sdes int link_type; 1547131614Sdes struct alias_link *lnk; 154826026Sbrian 1549165243Spiso LIBALIAS_LOCK_ASSERT(la); 1550127094Sdes switch (proto) { 1551127094Sdes case IPPROTO_UDP: 1552127094Sdes link_type = LINK_UDP; 1553127094Sdes break; 1554127094Sdes case IPPROTO_TCP: 1555127094Sdes link_type = LINK_TCP; 1556127094Sdes break; 1557127094Sdes default: 1558131613Sdes return (NULL); 1559127094Sdes break; 1560127094Sdes } 156126026Sbrian 1562131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 156326026Sbrian 1564131614Sdes if (lnk == NULL && create) { 1565127094Sdes struct in_addr alias_addr; 156626026Sbrian 1567127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1568131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1569127094Sdes src_port, dst_port, GET_ALIAS_PORT, 1570127094Sdes link_type); 1571127094Sdes } 1572131614Sdes return (lnk); 157326026Sbrian} 157426026Sbrian 157526026Sbrian 157661861Srustruct alias_link * 1577127094SdesAddPptp(struct libalias *la, struct in_addr src_addr, 1578127094Sdes struct in_addr dst_addr, 1579127094Sdes struct in_addr alias_addr, 1580127094Sdes u_int16_t src_call_id) 158167966Sru{ 1582131614Sdes struct alias_link *lnk; 158363899Sarchie 1584165243Spiso LIBALIAS_LOCK_ASSERT(la); 1585131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1586127094Sdes src_call_id, 0, GET_ALIAS_PORT, 1587127094Sdes LINK_PPTP); 158867966Sru 1589131614Sdes return (lnk); 159067966Sru} 159167966Sru 159267966Sru 159367966Srustruct alias_link * 1594124621SphkFindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1595127094Sdes struct in_addr dst_addr, 1596127094Sdes u_int16_t src_call_id) 159767966Sru{ 1598127094Sdes u_int i; 1599131614Sdes struct alias_link *lnk; 160067966Sru 1601165243Spiso LIBALIAS_LOCK_ASSERT(la); 1602127094Sdes i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1603131614Sdes LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1604131614Sdes if (lnk->link_type == LINK_PPTP && 1605131614Sdes lnk->src_addr.s_addr == src_addr.s_addr && 1606131614Sdes lnk->dst_addr.s_addr == dst_addr.s_addr && 1607131614Sdes lnk->src_port == src_call_id) 160867966Sru break; 160967966Sru 1610131614Sdes return (lnk); 161167966Sru} 161267966Sru 161367966Sru 161467966Srustruct alias_link * 1615124621SphkFindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1616127094Sdes struct in_addr dst_addr, 1617127094Sdes u_int16_t dst_call_id) 161867966Sru{ 1619127094Sdes u_int i; 1620131614Sdes struct alias_link *lnk; 162167966Sru 1622165243Spiso LIBALIAS_LOCK_ASSERT(la); 1623127094Sdes i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1624131614Sdes LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1625131614Sdes if (lnk->link_type == LINK_PPTP && 1626131614Sdes lnk->src_addr.s_addr == src_addr.s_addr && 1627131614Sdes lnk->dst_addr.s_addr == dst_addr.s_addr && 1628131614Sdes lnk->dst_port == dst_call_id) 162967966Sru break; 163067966Sru 1631131614Sdes return (lnk); 163267966Sru} 163367966Sru 163467966Sru 163567966Srustruct alias_link * 1636124621SphkFindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1637127094Sdes struct in_addr alias_addr, 1638127094Sdes u_int16_t dst_call_id) 163967966Sru{ 1640127094Sdes u_int i; 1641131614Sdes struct alias_link *lnk; 164267966Sru 1643165243Spiso LIBALIAS_LOCK_ASSERT(la); 1644127094Sdes i = StartPointIn(alias_addr, 0, LINK_PPTP); 1645131614Sdes LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) 1646131614Sdes if (lnk->link_type == LINK_PPTP && 1647131614Sdes lnk->dst_addr.s_addr == dst_addr.s_addr && 1648131614Sdes lnk->alias_addr.s_addr == alias_addr.s_addr && 1649131614Sdes lnk->dst_port == dst_call_id) 165067966Sru break; 165167966Sru 1652131614Sdes return (lnk); 165367966Sru} 165467966Sru 165567966Sru 165667966Srustruct alias_link * 1657124621SphkFindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1658127094Sdes struct in_addr alias_addr, 1659127094Sdes u_int16_t alias_call_id) 166067966Sru{ 1661131614Sdes struct alias_link *lnk; 166267966Sru 1663165243Spiso LIBALIAS_LOCK_ASSERT(la); 1664131614Sdes lnk = FindLinkIn(la, dst_addr, alias_addr, 1665127094Sdes 0 /* any */ , alias_call_id, 1666127094Sdes LINK_PPTP, 0); 166767966Sru 166867966Sru 1669131614Sdes return (lnk); 167067966Sru} 167167966Sru 167267966Sru 167399207Sbrianstruct alias_link * 1674127094SdesFindRtspOut(struct libalias *la, struct in_addr src_addr, 1675127094Sdes struct in_addr dst_addr, 1676127094Sdes u_short src_port, 1677127094Sdes u_short alias_port, 1678127094Sdes u_char proto) 167963899Sarchie{ 1680127094Sdes int link_type; 1681131614Sdes struct alias_link *lnk; 168263899Sarchie 1683165243Spiso LIBALIAS_LOCK_ASSERT(la); 1684127094Sdes switch (proto) { 1685127094Sdes case IPPROTO_UDP: 1686127094Sdes link_type = LINK_UDP; 1687127094Sdes break; 1688127094Sdes case IPPROTO_TCP: 1689127094Sdes link_type = LINK_TCP; 1690127094Sdes break; 1691127094Sdes default: 1692131613Sdes return (NULL); 1693127094Sdes break; 1694127094Sdes } 169563899Sarchie 1696131614Sdes lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 169763899Sarchie 1698131614Sdes if (lnk == NULL) { 1699127094Sdes struct in_addr alias_addr; 170063899Sarchie 1701127094Sdes alias_addr = FindAliasAddress(la, src_addr); 1702131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1703127094Sdes src_port, 0, alias_port, 1704127094Sdes link_type); 1705127094Sdes } 1706131614Sdes return (lnk); 170763899Sarchie} 170863899Sarchie 170963899Sarchie 171026026Sbrianstruct in_addr 1711124621SphkFindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 171226026Sbrian{ 1713131614Sdes struct alias_link *lnk; 171499207Sbrian 1715165243Spiso LIBALIAS_LOCK_ASSERT(la); 1716131614Sdes lnk = FindLinkIn(la, la->nullAddress, alias_addr, 1717127094Sdes 0, 0, LINK_ADDR, 0); 1718131614Sdes if (lnk == NULL) { 1719127094Sdes la->newDefaultLink = 1; 1720127094Sdes if (la->targetAddress.s_addr == INADDR_ANY) 1721131613Sdes return (alias_addr); 1722127094Sdes else if (la->targetAddress.s_addr == INADDR_NONE) 1723127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1724127094Sdes la->aliasAddress : alias_addr; 1725127094Sdes else 1726131613Sdes return (la->targetAddress); 1727127094Sdes } else { 1728131614Sdes if (lnk->server != NULL) { /* LSNAT link */ 1729127094Sdes struct in_addr src_addr; 173059702Sru 1731131614Sdes src_addr = lnk->server->addr; 1732131614Sdes lnk->server = lnk->server->next; 1733127094Sdes return (src_addr); 1734131614Sdes } else if (lnk->src_addr.s_addr == INADDR_ANY) 1735127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1736127094Sdes la->aliasAddress : alias_addr; 1737127094Sdes else 1738131614Sdes return (lnk->src_addr); 1739127094Sdes } 174026026Sbrian} 174126026Sbrian 174226026Sbrian 174326026Sbrianstruct in_addr 1744124621SphkFindAliasAddress(struct libalias *la, struct in_addr original_addr) 174526026Sbrian{ 1746131614Sdes struct alias_link *lnk; 174799207Sbrian 1748165243Spiso LIBALIAS_LOCK_ASSERT(la); 1749131614Sdes lnk = FindLinkOut(la, original_addr, la->nullAddress, 1750127094Sdes 0, 0, LINK_ADDR, 0); 1751131614Sdes if (lnk == NULL) { 1752127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1753127094Sdes la->aliasAddress : original_addr; 1754127094Sdes } else { 1755131614Sdes if (lnk->alias_addr.s_addr == INADDR_ANY) 1756127094Sdes return (la->aliasAddress.s_addr != INADDR_ANY) ? 1757127094Sdes la->aliasAddress : original_addr; 1758127094Sdes else 1759131614Sdes return (lnk->alias_addr); 1760127094Sdes } 176126026Sbrian} 176226026Sbrian 176326026Sbrian 176426026Sbrian/* External routines for getting or changing link data 176526026Sbrian (external to alias_db.c, but internal to alias*.c) 176626026Sbrian 176726026Sbrian SetFragmentData(), GetFragmentData() 176826026Sbrian SetFragmentPtr(), GetFragmentPtr() 176926026Sbrian SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 177026026Sbrian GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 177126026Sbrian GetOriginalPort(), GetAliasPort() 177226026Sbrian SetAckModified(), GetAckModified() 177326026Sbrian GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 177477485Sru SetProtocolFlags(), GetProtocolFlags() 177567966Sru SetDestCallId() 177626026Sbrian*/ 177726026Sbrian 177826026Sbrian 177926026Sbrianvoid 1780131614SdesSetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 178126026Sbrian{ 1782131614Sdes lnk->data.frag_addr = src_addr; 178326026Sbrian} 178426026Sbrian 178526026Sbrian 178626026Sbrianvoid 1787131614SdesGetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 178826026Sbrian{ 1789131614Sdes *src_addr = lnk->data.frag_addr; 179026026Sbrian} 179126026Sbrian 179226026Sbrian 179326026Sbrianvoid 1794131614SdesSetFragmentPtr(struct alias_link *lnk, char *fptr) 179526026Sbrian{ 1796131614Sdes lnk->data.frag_ptr = fptr; 179726026Sbrian} 179826026Sbrian 179926026Sbrian 180026026Sbrianvoid 1801131614SdesGetFragmentPtr(struct alias_link *lnk, char **fptr) 180226026Sbrian{ 1803131614Sdes *fptr = lnk->data.frag_ptr; 180426026Sbrian} 180526026Sbrian 180626026Sbrian 180726026Sbrianvoid 1808131614SdesSetStateIn(struct alias_link *lnk, int state) 180926026Sbrian{ 1810127094Sdes /* TCP input state */ 1811127094Sdes switch (state) { 1812127094Sdes case ALIAS_TCP_STATE_DISCONNECTED: 1813131614Sdes if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1814131614Sdes lnk->expire_time = TCP_EXPIRE_DEAD; 1815127094Sdes else 1816131614Sdes lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1817127094Sdes break; 1818127094Sdes case ALIAS_TCP_STATE_CONNECTED: 1819131614Sdes if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1820131614Sdes lnk->expire_time = TCP_EXPIRE_CONNECTED; 1821127094Sdes break; 1822127094Sdes default: 1823145927Sglebius#ifdef _KERNEL 1824145927Sglebius panic("libalias:SetStateIn() unknown state"); 1825145927Sglebius#else 1826127094Sdes abort(); 1827145927Sglebius#endif 1828127094Sdes } 1829131614Sdes lnk->data.tcp->state.in = state; 183026026Sbrian} 183126026Sbrian 183226026Sbrian 183326026Sbrianvoid 1834131614SdesSetStateOut(struct alias_link *lnk, int state) 183526026Sbrian{ 1836127094Sdes /* TCP output state */ 1837127094Sdes switch (state) { 1838127094Sdes case ALIAS_TCP_STATE_DISCONNECTED: 1839131614Sdes if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1840131614Sdes lnk->expire_time = TCP_EXPIRE_DEAD; 1841127094Sdes else 1842131614Sdes lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1843127094Sdes break; 1844127094Sdes case ALIAS_TCP_STATE_CONNECTED: 1845131614Sdes if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1846131614Sdes lnk->expire_time = TCP_EXPIRE_CONNECTED; 1847127094Sdes break; 1848127094Sdes default: 1849145927Sglebius#ifdef _KERNEL 1850145927Sglebius panic("libalias:SetStateOut() unknown state"); 1851145927Sglebius#else 1852127094Sdes abort(); 1853145927Sglebius#endif 1854127094Sdes } 1855131614Sdes lnk->data.tcp->state.out = state; 185626026Sbrian} 185726026Sbrian 185826026Sbrian 185926026Sbrianint 1860131614SdesGetStateIn(struct alias_link *lnk) 186126026Sbrian{ 1862127094Sdes /* TCP input state */ 1863131614Sdes return (lnk->data.tcp->state.in); 186426026Sbrian} 186526026Sbrian 186626026Sbrian 186726026Sbrianint 1868131614SdesGetStateOut(struct alias_link *lnk) 186926026Sbrian{ 1870127094Sdes /* TCP output state */ 1871131614Sdes return (lnk->data.tcp->state.out); 187226026Sbrian} 187326026Sbrian 187426026Sbrian 187526026Sbrianstruct in_addr 1876131614SdesGetOriginalAddress(struct alias_link *lnk) 187726026Sbrian{ 1878131614Sdes if (lnk->src_addr.s_addr == INADDR_ANY) 1879131614Sdes return (lnk->la->aliasAddress); 1880127094Sdes else 1881131614Sdes return (lnk->src_addr); 188226026Sbrian} 188326026Sbrian 188426026Sbrian 188526026Sbrianstruct in_addr 1886131614SdesGetDestAddress(struct alias_link *lnk) 188726026Sbrian{ 1888131614Sdes return (lnk->dst_addr); 188926026Sbrian} 189026026Sbrian 189126026Sbrian 189226026Sbrianstruct in_addr 1893131614SdesGetAliasAddress(struct alias_link *lnk) 189426026Sbrian{ 1895131614Sdes if (lnk->alias_addr.s_addr == INADDR_ANY) 1896131614Sdes return (lnk->la->aliasAddress); 1897127094Sdes else 1898131614Sdes return (lnk->alias_addr); 189926026Sbrian} 190026026Sbrian 190126026Sbrian 190226026Sbrianstruct in_addr 1903124621SphkGetDefaultAliasAddress(struct libalias *la) 190426026Sbrian{ 1905165243Spiso 1906165243Spiso LIBALIAS_LOCK_ASSERT(la); 1907131613Sdes return (la->aliasAddress); 190826026Sbrian} 190926026Sbrian 191026026Sbrian 191126026Sbrianvoid 1912124621SphkSetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 191326026Sbrian{ 1914165243Spiso 1915165243Spiso LIBALIAS_LOCK_ASSERT(la); 1916127094Sdes la->aliasAddress = alias_addr; 191726026Sbrian} 191826026Sbrian 191926026Sbrian 192026026Sbrianu_short 1921131614SdesGetOriginalPort(struct alias_link *lnk) 192226026Sbrian{ 1923131614Sdes return (lnk->src_port); 192426026Sbrian} 192526026Sbrian 192626026Sbrian 192726026Sbrianu_short 1928131614SdesGetAliasPort(struct alias_link *lnk) 192926026Sbrian{ 1930131614Sdes return (lnk->alias_port); 193126026Sbrian} 193226026Sbrian 193358279Sbrian#ifndef NO_FW_PUNCH 1934127094Sdesstatic u_short 1935131614SdesGetDestPort(struct alias_link *lnk) 193632377Seivind{ 1937131614Sdes return (lnk->dst_port); 193832377Seivind} 1939127094Sdes 194058279Sbrian#endif 194126026Sbrian 194226026Sbrianvoid 1943131614SdesSetAckModified(struct alias_link *lnk) 194426026Sbrian{ 194559356Sru/* Indicate that ACK numbers have been modified in a TCP connection */ 1946131614Sdes lnk->data.tcp->state.ack_modified = 1; 194726026Sbrian} 194826026Sbrian 194926026Sbrian 195044307Sbrianstruct in_addr 1951131614SdesGetProxyAddress(struct alias_link *lnk) 195244307Sbrian{ 1953131614Sdes return (lnk->proxy_addr); 195444307Sbrian} 195544307Sbrian 195644307Sbrian 195744307Sbrianvoid 1958131614SdesSetProxyAddress(struct alias_link *lnk, struct in_addr addr) 195944307Sbrian{ 1960131614Sdes lnk->proxy_addr = addr; 196144307Sbrian} 196244307Sbrian 196344307Sbrian 196444307Sbrianu_short 1965131614SdesGetProxyPort(struct alias_link *lnk) 196644307Sbrian{ 1967131614Sdes return (lnk->proxy_port); 196844307Sbrian} 196944307Sbrian 197044307Sbrian 197144307Sbrianvoid 1972131614SdesSetProxyPort(struct alias_link *lnk, u_short port) 197344307Sbrian{ 1974131614Sdes lnk->proxy_port = port; 197544307Sbrian} 197644307Sbrian 197744307Sbrian 197826026Sbrianint 1979131614SdesGetAckModified(struct alias_link *lnk) 198026026Sbrian{ 198159356Sru/* See if ACK numbers have been modified */ 1982131614Sdes return (lnk->data.tcp->state.ack_modified); 198326026Sbrian} 198426026Sbrian 1985176884Spiso// XXX ip free 198626026Sbrianint 1987176884SpisoGetDeltaAckIn(u_long ack, struct alias_link *lnk) 198826026Sbrian{ 198926026Sbrian/* 199059356SruFind out how much the ACK number has been altered for an incoming 199159356SruTCP packet. To do this, a circular list of ACK numbers where the TCP 199299207Sbrianpacket size was altered is searched. 199326026Sbrian*/ 199426026Sbrian 1995127094Sdes int i; 1996127094Sdes int delta, ack_diff_min; 199726026Sbrian 1998127094Sdes delta = 0; 1999127094Sdes ack_diff_min = -1; 2000127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) { 2001127094Sdes struct ack_data_record x; 200226026Sbrian 2003131614Sdes x = lnk->data.tcp->ack[i]; 2004127094Sdes if (x.active == 1) { 2005127094Sdes int ack_diff; 200626026Sbrian 2007127094Sdes ack_diff = SeqDiff(x.ack_new, ack); 2008127094Sdes if (ack_diff >= 0) { 2009127094Sdes if (ack_diff_min >= 0) { 2010127094Sdes if (ack_diff < ack_diff_min) { 2011127094Sdes delta = x.delta; 2012127094Sdes ack_diff_min = ack_diff; 2013127094Sdes } 2014127094Sdes } else { 2015127094Sdes delta = x.delta; 2016127094Sdes ack_diff_min = ack_diff; 2017127094Sdes } 2018127094Sdes } 2019127094Sdes } 2020127094Sdes } 2021127094Sdes return (delta); 202226026Sbrian} 202326026Sbrian 2024176884Spiso// XXX ip free 202526026Sbrianint 2026176884SpisoGetDeltaSeqOut(u_long seq, struct alias_link *lnk) 202726026Sbrian{ 202826026Sbrian/* 202959356SruFind out how much the sequence number has been altered for an outgoing 203059356SruTCP packet. To do this, a circular list of ACK numbers where the TCP 203199207Sbrianpacket size was altered is searched. 203226026Sbrian*/ 203326026Sbrian 2034127094Sdes int i; 2035127094Sdes int delta, seq_diff_min; 203626026Sbrian 2037127094Sdes delta = 0; 2038127094Sdes seq_diff_min = -1; 2039127094Sdes for (i = 0; i < N_LINK_TCP_DATA; i++) { 2040127094Sdes struct ack_data_record x; 204126026Sbrian 2042131614Sdes x = lnk->data.tcp->ack[i]; 2043127094Sdes if (x.active == 1) { 2044127094Sdes int seq_diff; 204526026Sbrian 2046127094Sdes seq_diff = SeqDiff(x.ack_old, seq); 2047127094Sdes if (seq_diff >= 0) { 2048127094Sdes if (seq_diff_min >= 0) { 2049127094Sdes if (seq_diff < seq_diff_min) { 2050127094Sdes delta = x.delta; 2051127094Sdes seq_diff_min = seq_diff; 2052127094Sdes } 2053127094Sdes } else { 2054127094Sdes delta = x.delta; 2055127094Sdes seq_diff_min = seq_diff; 2056127094Sdes } 2057127094Sdes } 2058127094Sdes } 2059127094Sdes } 2060127094Sdes return (delta); 206126026Sbrian} 206226026Sbrian 2063176884Spiso// XXX ip free 206426026Sbrianvoid 2065176884SpisoAddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 2066176884Spiso u_long th_seq, u_int th_off) 206726026Sbrian{ 206826026Sbrian/* 206926026SbrianWhen a TCP packet has been altered in length, save this 207026026Sbrianinformation in a circular list. If enough packets have 207126026Sbrianbeen altered, then this list will begin to overwrite itself. 207226026Sbrian*/ 207326026Sbrian 2074127094Sdes struct ack_data_record x; 2075127094Sdes int hlen, tlen, dlen; 2076127094Sdes int i; 207726026Sbrian 2078176884Spiso hlen = (ip_hl + th_off) << 2; 2079176884Spiso tlen = ntohs(ip_len); 2080127094Sdes dlen = tlen - hlen; 208126026Sbrian 2082176884Spiso x.ack_old = htonl(ntohl(th_seq) + dlen); 2083176884Spiso x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 2084127094Sdes x.delta = delta; 2085127094Sdes x.active = 1; 208626026Sbrian 2087131614Sdes i = lnk->data.tcp->state.index; 2088131614Sdes lnk->data.tcp->ack[i] = x; 208926026Sbrian 2090127094Sdes i++; 2091127094Sdes if (i == N_LINK_TCP_DATA) 2092131614Sdes lnk->data.tcp->state.index = 0; 2093127094Sdes else 2094131614Sdes lnk->data.tcp->state.index = i; 209526026Sbrian} 209626026Sbrian 209726026Sbrianvoid 2098131614SdesSetExpire(struct alias_link *lnk, int expire) 209926026Sbrian{ 2100127094Sdes if (expire == 0) { 2101131614Sdes lnk->flags &= ~LINK_PERMANENT; 2102131614Sdes DeleteLink(lnk); 2103127094Sdes } else if (expire == -1) { 2104131614Sdes lnk->flags |= LINK_PERMANENT; 2105127094Sdes } else if (expire > 0) { 2106131614Sdes lnk->expire_time = expire; 2107127094Sdes } else { 2108145961Sglebius#ifdef LIBALIAS_DEBUG 2109127094Sdes fprintf(stderr, "PacketAlias/SetExpire(): "); 2110127094Sdes fprintf(stderr, "error in expire parameter\n"); 211144616Sbrian#endif 2112127094Sdes } 211326026Sbrian} 211426026Sbrian 211526026Sbrianvoid 2116124621SphkClearCheckNewLink(struct libalias *la) 211726026Sbrian{ 2118165243Spiso 2119165243Spiso LIBALIAS_LOCK_ASSERT(la); 2120127094Sdes la->newDefaultLink = 0; 212126026Sbrian} 212226026Sbrian 212361677Sruvoid 2124131614SdesSetProtocolFlags(struct alias_link *lnk, int pflags) 212561677Sru{ 212626026Sbrian 2127201758Smbr lnk->pflags = pflags; 212861677Sru} 212961677Sru 213061677Sruint 2131131614SdesGetProtocolFlags(struct alias_link *lnk) 213261677Sru{ 213361677Sru 2134131614Sdes return (lnk->pflags); 213561677Sru} 213661677Sru 213767966Sruvoid 2138131614SdesSetDestCallId(struct alias_link *lnk, u_int16_t cid) 213967966Sru{ 2140131614Sdes struct libalias *la = lnk->la; 214161677Sru 2142165243Spiso LIBALIAS_LOCK_ASSERT(la); 2143127094Sdes la->deleteAllLinks = 1; 2144168458Spiso ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2145131614Sdes lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2146127094Sdes la->deleteAllLinks = 0; 214767966Sru} 214867966Sru 214967966Sru 215027864Sbrian/* Miscellaneous Functions 215126026Sbrian 215227864Sbrian HouseKeeping() 215327864Sbrian InitPacketAliasLog() 215427864Sbrian UninitPacketAliasLog() 215527864Sbrian*/ 215626026Sbrian 215726026Sbrian/* 215826026Sbrian Whenever an outgoing or incoming packet is handled, HouseKeeping() 215926026Sbrian is called to find and remove timed-out aliasing links. Logic exists 216026026Sbrian to sweep through the entire table and linked list structure 216126026Sbrian every 60 seconds. 216226026Sbrian 216326026Sbrian (prototype in alias_local.h) 216426026Sbrian*/ 216526026Sbrian 216626026Sbrianvoid 2167124621SphkHouseKeeping(struct libalias *la) 216826026Sbrian{ 2169179480Smav int i, n; 2170145927Sglebius#ifndef _KERNEL 2171127094Sdes struct timeval tv; 2172145927Sglebius#endif 217326026Sbrian 2174165243Spiso LIBALIAS_LOCK_ASSERT(la); 2175127094Sdes /* 2176127094Sdes * Save system time (seconds) in global variable timeStamp for use 2177127094Sdes * by other functions. This is done so as not to unnecessarily 2178127094Sdes * waste timeline by making system calls. 2179127094Sdes */ 2180145927Sglebius#ifdef _KERNEL 2181150350Sandre la->timeStamp = time_uptime; 2182145927Sglebius#else 2183211057Sed gettimeofday(&tv, NULL); 2184127094Sdes la->timeStamp = tv.tv_sec; 2185145927Sglebius#endif 218626026Sbrian 2187127094Sdes /* Compute number of spokes (output table link chains) to cover */ 2188179480Smav n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime); 2189179480Smav n /= ALIAS_CLEANUP_INTERVAL_SECS; 219026026Sbrian 2191127094Sdes /* Handle different cases */ 2192179480Smav if (n > 0) { 2193179480Smav if (n > ALIAS_CLEANUP_MAX_SPOKES) 2194179480Smav n = ALIAS_CLEANUP_MAX_SPOKES; 2195127094Sdes la->lastCleanupTime = la->timeStamp; 2196127094Sdes for (i = 0; i < n; i++) 2197127094Sdes IncrementalCleanup(la); 2198127094Sdes } else if (n < 0) { 2199145961Sglebius#ifdef LIBALIAS_DEBUG 2200127094Sdes fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2201127094Sdes fprintf(stderr, "something unexpected in time values\n"); 220244616Sbrian#endif 2203127094Sdes la->lastCleanupTime = la->timeStamp; 2204127094Sdes } 220526026Sbrian} 220626026Sbrian 220727864Sbrian/* Init the log file and enable logging */ 2208162674Spisostatic int 2209124621SphkInitPacketAliasLog(struct libalias *la) 221027864Sbrian{ 2211165243Spiso 2212165243Spiso LIBALIAS_LOCK_ASSERT(la); 2213162674Spiso if (~la->packetAliasMode & PKT_ALIAS_LOG) { 2214162674Spiso#ifdef _KERNEL 2215162674Spiso if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 2216162674Spiso ; 2217162674Spiso#else 2218162674Spiso if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 2219162674Spiso fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2220162674Spiso#endif 2221162674Spiso else 2222162674Spiso return (ENOMEM); /* log initialization failed */ 2223127094Sdes la->packetAliasMode |= PKT_ALIAS_LOG; 2224127094Sdes } 2225162674Spiso 2226162674Spiso return (1); 222727864Sbrian} 222826026Sbrian 222927864Sbrian/* Close the log-file and disable logging. */ 223032377Seivindstatic void 2231124621SphkUninitPacketAliasLog(struct libalias *la) 223227864Sbrian{ 2233165243Spiso 2234165243Spiso LIBALIAS_LOCK_ASSERT(la); 2235165243Spiso if (la->logDesc) { 2236162674Spiso#ifdef _KERNEL 2237165243Spiso free(la->logDesc); 2238162674Spiso#else 2239165243Spiso fclose(la->logDesc); 2240162674Spiso#endif 2241165243Spiso la->logDesc = NULL; 2242165243Spiso } 2243127094Sdes la->packetAliasMode &= ~PKT_ALIAS_LOG; 224427864Sbrian} 224526026Sbrian 224626026Sbrian/* Outside world interfaces 224726026Sbrian 224826026Sbrian-- "outside world" means other than alias*.c routines -- 224926026Sbrian 225026026Sbrian PacketAliasRedirectPort() 225159702Sru PacketAliasAddServer() 225259726Sru PacketAliasRedirectProto() 225326026Sbrian PacketAliasRedirectAddr() 2254115650Sru PacketAliasRedirectDynamic() 225527864Sbrian PacketAliasRedirectDelete() 225627864Sbrian PacketAliasSetAddress() 225727864Sbrian PacketAliasInit() 225832377Seivind PacketAliasUninit() 225927864Sbrian PacketAliasSetMode() 226026026Sbrian 226126026Sbrian(prototypes in alias.h) 226226026Sbrian*/ 226326026Sbrian 226426026Sbrian/* Redirection from a specific public addr:port to a 226559356Sru private addr:port */ 226626026Sbrianstruct alias_link * 2267127094SdesLibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2268127094Sdes struct in_addr dst_addr, u_short dst_port, 2269127094Sdes struct in_addr alias_addr, u_short alias_port, 2270127094Sdes u_char proto) 227126026Sbrian{ 2272127094Sdes int link_type; 2273131614Sdes struct alias_link *lnk; 227426026Sbrian 2275165243Spiso LIBALIAS_LOCK(la); 2276127094Sdes switch (proto) { 2277127094Sdes case IPPROTO_UDP: 2278127094Sdes link_type = LINK_UDP; 2279127094Sdes break; 2280127094Sdes case IPPROTO_TCP: 2281127094Sdes link_type = LINK_TCP; 2282127094Sdes break; 2283188294Spiso case IPPROTO_SCTP: 2284188294Spiso link_type = LINK_SCTP; 2285188294Spiso break; 2286127094Sdes default: 2287145961Sglebius#ifdef LIBALIAS_DEBUG 2288127094Sdes fprintf(stderr, "PacketAliasRedirectPort(): "); 2289188294Spiso fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n"); 229044616Sbrian#endif 2291165243Spiso lnk = NULL; 2292165243Spiso goto getout; 2293127094Sdes } 229426026Sbrian 2295131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2296127094Sdes src_port, dst_port, alias_port, 2297127094Sdes link_type); 229826026Sbrian 2299131614Sdes if (lnk != NULL) { 2300131614Sdes lnk->flags |= LINK_PERMANENT; 2301127094Sdes } 2302145961Sglebius#ifdef LIBALIAS_DEBUG 2303127094Sdes else { 2304127094Sdes fprintf(stderr, "PacketAliasRedirectPort(): " 2305127094Sdes "call to AddLink() failed\n"); 2306127094Sdes } 230744616Sbrian#endif 230826026Sbrian 2309165243Spisogetout: 2310165243Spiso LIBALIAS_UNLOCK(la); 2311131614Sdes return (lnk); 231226026Sbrian} 231326026Sbrian 231459702Sru/* Add server to the pool of servers */ 231559702Sruint 2316131614SdesLibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 231759702Sru{ 2318127094Sdes struct server *server; 2319165243Spiso int res; 232059702Sru 2321165243Spiso LIBALIAS_LOCK(la); 2322131614Sdes (void)la; 2323131614Sdes 2324127094Sdes server = malloc(sizeof(struct server)); 232559702Sru 2326127094Sdes if (server != NULL) { 2327127094Sdes struct server *head; 232859702Sru 2329127094Sdes server->addr = addr; 2330127094Sdes server->port = port; 233159702Sru 2332131614Sdes head = lnk->server; 2333127094Sdes if (head == NULL) 2334127094Sdes server->next = server; 2335127094Sdes else { 2336127094Sdes struct server *s; 233759702Sru 2338127094Sdes for (s = head; s->next != head; s = s->next); 2339127094Sdes s->next = server; 2340127094Sdes server->next = head; 2341127094Sdes } 2342131614Sdes lnk->server = server; 2343165243Spiso res = 0; 2344127094Sdes } else 2345165243Spiso res = -1; 2346165243Spiso 2347165243Spiso LIBALIAS_UNLOCK(la); 2348165243Spiso return (res); 234959702Sru} 235059702Sru 235159726Sru/* Redirect packets of a given IP protocol from a specific 235259356Sru public address to a private address */ 235359356Srustruct alias_link * 2354124621SphkLibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2355127094Sdes struct in_addr dst_addr, 2356127094Sdes struct in_addr alias_addr, 2357127094Sdes u_char proto) 235844307Sbrian{ 2359131614Sdes struct alias_link *lnk; 236044307Sbrian 2361165243Spiso LIBALIAS_LOCK(la); 2362131614Sdes lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2363127094Sdes NO_SRC_PORT, NO_DEST_PORT, 0, 2364127094Sdes proto); 236559356Sru 2366131614Sdes if (lnk != NULL) { 2367131614Sdes lnk->flags |= LINK_PERMANENT; 2368127094Sdes } 2369145961Sglebius#ifdef LIBALIAS_DEBUG 2370127094Sdes else { 2371127094Sdes fprintf(stderr, "PacketAliasRedirectProto(): " 2372127094Sdes "call to AddLink() failed\n"); 2373127094Sdes } 237459356Sru#endif 237559356Sru 2376165243Spiso LIBALIAS_UNLOCK(la); 2377131614Sdes return (lnk); 237844307Sbrian} 237944307Sbrian 238026026Sbrian/* Static address translation */ 238126026Sbrianstruct alias_link * 2382124621SphkLibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2383127094Sdes struct in_addr alias_addr) 238426026Sbrian{ 2385131614Sdes struct alias_link *lnk; 238626026Sbrian 2387165243Spiso LIBALIAS_LOCK(la); 2388131614Sdes lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, 2389127094Sdes 0, 0, 0, 2390127094Sdes LINK_ADDR); 239126026Sbrian 2392131614Sdes if (lnk != NULL) { 2393131614Sdes lnk->flags |= LINK_PERMANENT; 2394127094Sdes } 2395145961Sglebius#ifdef LIBALIAS_DEBUG 2396127094Sdes else { 2397127094Sdes fprintf(stderr, "PacketAliasRedirectAddr(): " 2398127094Sdes "call to AddLink() failed\n"); 2399127094Sdes } 240044616Sbrian#endif 240126026Sbrian 2402165243Spiso LIBALIAS_UNLOCK(la); 2403131614Sdes return (lnk); 240426026Sbrian} 240526026Sbrian 240626026Sbrian 2407115650Sru/* Mark the aliasing link dynamic */ 2408115650Sruint 2409131614SdesLibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2410115650Sru{ 2411165243Spiso int res; 2412115650Sru 2413165243Spiso LIBALIAS_LOCK(la); 2414131614Sdes (void)la; 2415131614Sdes 2416131614Sdes if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2417165243Spiso res = -1; 2418127094Sdes else { 2419131614Sdes lnk->flags &= ~LINK_PERMANENT; 2420165243Spiso res = 0; 2421127094Sdes } 2422165243Spiso LIBALIAS_UNLOCK(la); 2423165243Spiso return (res); 2424115650Sru} 2425115650Sru 2426115650Sru 242726026Sbrianvoid 2428131614SdesLibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 242926026Sbrian{ 243027864Sbrian/* This is a dangerous function to put in the API, 243126026Sbrian because an invalid pointer can crash the program. */ 243226026Sbrian 2433165243Spiso LIBALIAS_LOCK(la); 2434127094Sdes la->deleteAllLinks = 1; 2435131614Sdes DeleteLink(lnk); 2436127094Sdes la->deleteAllLinks = 0; 2437165243Spiso LIBALIAS_UNLOCK(la); 243826026Sbrian} 243926026Sbrian 244026026Sbrian 244126026Sbrianvoid 2442124621SphkLibAliasSetAddress(struct libalias *la, struct in_addr addr) 244326026Sbrian{ 2444165243Spiso 2445165243Spiso LIBALIAS_LOCK(la); 2446127094Sdes if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2447127094Sdes && la->aliasAddress.s_addr != addr.s_addr) 2448127094Sdes CleanupAliasData(la); 244933897Sbrian 2450127094Sdes la->aliasAddress = addr; 2451165243Spiso LIBALIAS_UNLOCK(la); 245226026Sbrian} 245326026Sbrian 245426026Sbrian 245526026Sbrianvoid 2456124621SphkLibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 245726026Sbrian{ 2458165243Spiso 2459165243Spiso LIBALIAS_LOCK(la); 2460127094Sdes la->targetAddress = target_addr; 2461165243Spiso LIBALIAS_UNLOCK(la); 246226026Sbrian} 246326026Sbrian 2464124621Sphkstatic void 2465124621Sphkfinishoff(void) 2466124621Sphk{ 246726026Sbrian 2468127094Sdes while (!LIST_EMPTY(&instancehead)) 2469124621Sphk LibAliasUninit(LIST_FIRST(&instancehead)); 2470124621Sphk} 2471124621Sphk 2472124621Sphkstruct libalias * 2473124621SphkLibAliasInit(struct libalias *la) 247426026Sbrian{ 2475127094Sdes int i; 2476145927Sglebius#ifndef _KERNEL 2477127094Sdes struct timeval tv; 2478145927Sglebius#endif 247926026Sbrian 2480127094Sdes if (la == NULL) { 2481220800Sglebius#ifdef _KERNEL 2482220800Sglebius#undef malloc /* XXX: ugly */ 2483220800Sglebius la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO); 2484220800Sglebius#else 2485127094Sdes la = calloc(sizeof *la, 1); 2486127094Sdes if (la == NULL) 2487127094Sdes return (la); 2488220800Sglebius#endif 2489145927Sglebius 2490145927Sglebius#ifndef _KERNEL /* kernel cleans up on module unload */ 2491127094Sdes if (LIST_EMPTY(&instancehead)) 2492127094Sdes atexit(finishoff); 2493145927Sglebius#endif 2494127094Sdes LIST_INSERT_HEAD(&instancehead, la, instancelist); 249526026Sbrian 2496145927Sglebius#ifdef _KERNEL 2497150350Sandre la->timeStamp = time_uptime; 2498150350Sandre la->lastCleanupTime = time_uptime; 2499145927Sglebius#else 2500211057Sed gettimeofday(&tv, NULL); 2501127094Sdes la->timeStamp = tv.tv_sec; 2502127094Sdes la->lastCleanupTime = tv.tv_sec; 2503145927Sglebius#endif 250426026Sbrian 2505127094Sdes for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2506127094Sdes LIST_INIT(&la->linkTableOut[i]); 2507127094Sdes for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2508127094Sdes LIST_INIT(&la->linkTableIn[i]); 2509188294Spiso#ifdef _KERNEL 2510188294Spiso AliasSctpInit(la); 2511188294Spiso#endif 2512165243Spiso LIBALIAS_LOCK_INIT(la); 2513165243Spiso LIBALIAS_LOCK(la); 2514127094Sdes } else { 2515165243Spiso LIBALIAS_LOCK(la); 2516127094Sdes la->deleteAllLinks = 1; 2517127094Sdes CleanupAliasData(la); 2518127094Sdes la->deleteAllLinks = 0; 2519188294Spiso#ifdef _KERNEL 2520188294Spiso AliasSctpTerm(la); 2521188294Spiso AliasSctpInit(la); 2522188294Spiso#endif 2523127094Sdes } 252426026Sbrian 2525127094Sdes la->aliasAddress.s_addr = INADDR_ANY; 2526127094Sdes la->targetAddress.s_addr = INADDR_ANY; 252726026Sbrian 2528127094Sdes la->icmpLinkCount = 0; 2529127094Sdes la->udpLinkCount = 0; 2530127094Sdes la->tcpLinkCount = 0; 2531188294Spiso la->sctpLinkCount = 0; 2532127094Sdes la->pptpLinkCount = 0; 2533127094Sdes la->protoLinkCount = 0; 2534127094Sdes la->fragmentIdLinkCount = 0; 2535127094Sdes la->fragmentPtrLinkCount = 0; 2536127094Sdes la->sockCount = 0; 253726026Sbrian 2538127094Sdes la->cleanupIndex = 0; 2539127094Sdes 2540127094Sdes la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2541145926Sglebius#ifndef NO_USE_SOCKETS 2542127094Sdes | PKT_ALIAS_USE_SOCKETS 2543145926Sglebius#endif 2544127094Sdes | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2545124621Sphk#ifndef NO_FW_PUNCH 2546127094Sdes la->fireWallFD = -1; 2547124621Sphk#endif 2548162674Spiso#ifndef _KERNEL 2549162674Spiso LibAliasRefreshModules(); 2550162674Spiso#endif 2551165243Spiso LIBALIAS_UNLOCK(la); 2552127094Sdes return (la); 255326026Sbrian} 255426026Sbrian 255532377Seivindvoid 2556127094SdesLibAliasUninit(struct libalias *la) 2557127094Sdes{ 2558165243Spiso 2559165243Spiso LIBALIAS_LOCK(la); 2560188294Spiso#ifdef _KERNEL 2561188294Spiso AliasSctpTerm(la); 2562188294Spiso#endif 2563127094Sdes la->deleteAllLinks = 1; 2564127094Sdes CleanupAliasData(la); 2565127094Sdes la->deleteAllLinks = 0; 2566127094Sdes UninitPacketAliasLog(la); 256735314Sbrian#ifndef NO_FW_PUNCH 2568127094Sdes UninitPunchFW(la); 256935314Sbrian#endif 2570127094Sdes LIST_REMOVE(la, instancelist); 2571165243Spiso LIBALIAS_UNLOCK(la); 2572165243Spiso LIBALIAS_LOCK_DESTROY(la); 2573127094Sdes free(la); 257432377Seivind} 257526026Sbrian 257626026Sbrian/* Change mode for some operations */ 257726026Sbrianunsigned int 2578124621SphkLibAliasSetMode( 2579124621Sphk struct libalias *la, 2580127094Sdes unsigned int flags, /* Which state to bring flags to */ 2581127094Sdes unsigned int mask /* Mask of which flags to affect (use 0 to 2582127094Sdes * do a probe for flag values) */ 258326026Sbrian) 258426026Sbrian{ 2585165243Spiso int res = -1; 2586165243Spiso 2587165243Spiso LIBALIAS_LOCK(la); 258826026Sbrian/* Enable logging? */ 2589127094Sdes if (flags & mask & PKT_ALIAS_LOG) { 2590162674Spiso /* Do the enable */ 2591162674Spiso if (InitPacketAliasLog(la) == ENOMEM) 2592165243Spiso goto getout; 2593127094Sdes } else 259426026Sbrian/* _Disable_ logging? */ 2595127094Sdes if (~flags & mask & PKT_ALIAS_LOG) { 2596127094Sdes UninitPacketAliasLog(la); 2597127094Sdes } 259835314Sbrian#ifndef NO_FW_PUNCH 259932377Seivind/* Start punching holes in the firewall? */ 2600127094Sdes if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2601127094Sdes InitPunchFW(la); 2602127094Sdes } else 260332377Seivind/* Stop punching holes in the firewall? */ 2604127094Sdes if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2605127094Sdes UninitPunchFW(la); 2606127094Sdes } 260735314Sbrian#endif 260832377Seivind 260926026Sbrian/* Other flags can be set/cleared without special action */ 2610127094Sdes la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2611165243Spiso res = la->packetAliasMode; 2612165243Spisogetout: 2613165243Spiso LIBALIAS_UNLOCK(la); 2614165243Spiso return (res); 261526026Sbrian} 261626026Sbrian 261726026Sbrian 261827864Sbrianint 2619124621SphkLibAliasCheckNewLink(struct libalias *la) 262027864Sbrian{ 2621165243Spiso int res; 2622165243Spiso 2623165243Spiso LIBALIAS_LOCK(la); 2624165243Spiso res = la->newDefaultLink; 2625165243Spiso LIBALIAS_UNLOCK(la); 2626165243Spiso return (res); 262727864Sbrian} 262832377Seivind 262932377Seivind 263035314Sbrian#ifndef NO_FW_PUNCH 263135314Sbrian 263232377Seivind/***************** 263332377Seivind Code to support firewall punching. This shouldn't really be in this 263432377Seivind file, but making variables global is evil too. 263532377Seivind ****************/ 263632377Seivind 263732377Seivind/* Firewall include files */ 263832392Sjkh#include <net/if.h> 263932377Seivind#include <netinet/ip_fw.h> 264032377Seivind#include <string.h> 264132377Seivind#include <err.h> 264232377Seivind 264398943Sluigi/* 264498943Sluigi * helper function, updates the pointer to cmd with the length 264598943Sluigi * of the current command, and also cleans up the first word of 264698943Sluigi * the new command in case it has been clobbered before. 264798943Sluigi */ 264898943Sluigistatic ipfw_insn * 2649127094Sdesnext_cmd(ipfw_insn * cmd) 265098943Sluigi{ 2651127094Sdes cmd += F_LEN(cmd); 2652127094Sdes bzero(cmd, sizeof(*cmd)); 2653131613Sdes return (cmd); 265498943Sluigi} 265598943Sluigi 265699623Sluigi/* 265799623Sluigi * A function to fill simple commands of size 1. 265899623Sluigi * Existing flags are preserved. 265999623Sluigi */ 266099623Sluigistatic ipfw_insn * 2661127094Sdesfill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2662127094Sdes int flags, u_int16_t arg) 266398943Sluigi{ 2664127094Sdes cmd->opcode = opcode; 2665127094Sdes cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2666127094Sdes cmd->arg1 = arg; 2667127094Sdes return next_cmd(cmd); 266899623Sluigi} 266999623Sluigi 267099623Sluigistatic ipfw_insn * 2671127094Sdesfill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 267299623Sluigi{ 2673127094Sdes ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 267499623Sluigi 2675127094Sdes cmd->addr.s_addr = addr; 2676127094Sdes return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 267798943Sluigi} 267898943Sluigi 267999623Sluigistatic ipfw_insn * 2680127094Sdesfill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 268198943Sluigi{ 2682127094Sdes ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 268399623Sluigi 2684127094Sdes cmd->ports[0] = cmd->ports[1] = port; 2685127094Sdes return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 268698943Sluigi} 268798943Sluigi 268898943Sluigistatic int 268998943Sluigifill_rule(void *buf, int bufsize, int rulenum, 2690127094Sdes enum ipfw_opcodes action, int proto, 2691127094Sdes struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 269298943Sluigi{ 2693127094Sdes struct ip_fw *rule = (struct ip_fw *)buf; 2694127094Sdes ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 269598943Sluigi 2696127094Sdes bzero(buf, bufsize); 2697127094Sdes rule->rulenum = rulenum; 269898943Sluigi 2699127094Sdes cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2700127094Sdes cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2701127094Sdes cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2702127094Sdes cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2703127094Sdes cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 270498943Sluigi 2705127094Sdes rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2706127094Sdes cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 270799207Sbrian 2708127094Sdes rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 270998943Sluigi 2710127094Sdes return ((char *)cmd - (char *)buf); 271198943Sluigi} 271298943Sluigi 2713127094Sdesstatic void ClearAllFWHoles(struct libalias *la); 271432377Seivind 2715127094Sdes 2716124621Sphk#define fw_setfield(la, field, num) \ 271732377Seivinddo { \ 2718124621Sphk (field)[(num) - la->fireWallBaseNum] = 1; \ 2719127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */ 2720124621Sphk 2721124621Sphk#define fw_clrfield(la, field, num) \ 272232377Seivinddo { \ 2723124621Sphk (field)[(num) - la->fireWallBaseNum] = 0; \ 2724127094Sdes} /*lint -save -e717 */ while(0)/* lint -restore */ 272532377Seivind 2726124621Sphk#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2727124621Sphk 272832377Seivindstatic void 2729124621SphkInitPunchFW(struct libalias *la) 2730124621Sphk{ 2731124621Sphk 2732127094Sdes la->fireWallField = malloc(la->fireWallNumNums); 2733127094Sdes if (la->fireWallField) { 2734127094Sdes memset(la->fireWallField, 0, la->fireWallNumNums); 2735127094Sdes if (la->fireWallFD < 0) { 2736127094Sdes la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2737127094Sdes } 2738127094Sdes ClearAllFWHoles(la); 2739127094Sdes la->fireWallActiveNum = la->fireWallBaseNum; 2740127094Sdes } 274132377Seivind} 274232377Seivind 274332377Seivindstatic void 2744124621SphkUninitPunchFW(struct libalias *la) 2745124621Sphk{ 2746165243Spiso 2747127094Sdes ClearAllFWHoles(la); 2748127094Sdes if (la->fireWallFD >= 0) 2749127094Sdes close(la->fireWallFD); 2750127094Sdes la->fireWallFD = -1; 2751127094Sdes if (la->fireWallField) 2752127094Sdes free(la->fireWallField); 2753127094Sdes la->fireWallField = NULL; 2754127094Sdes la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 275532377Seivind} 275632377Seivind 275732377Seivind/* Make a certain link go through the firewall */ 275832377Seivindvoid 2759131614SdesPunchFWHole(struct alias_link *lnk) 2760124621Sphk{ 2761127094Sdes struct libalias *la; 2762127094Sdes int r; /* Result code */ 2763127094Sdes struct ip_fw rule; /* On-the-fly built rule */ 2764127094Sdes int fwhole; /* Where to punch hole */ 276532377Seivind 2766131614Sdes la = lnk->la; 2767124621Sphk 276832377Seivind/* Don't do anything unless we are asked to */ 2769127094Sdes if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2770127094Sdes la->fireWallFD < 0 || 2771131614Sdes lnk->link_type != LINK_TCP) 2772127094Sdes return; 277332377Seivind 2774127094Sdes memset(&rule, 0, sizeof rule); 277532377Seivind 277632377Seivind/** Build rule **/ 277732377Seivind 2778127094Sdes /* Find empty slot */ 2779127094Sdes for (fwhole = la->fireWallActiveNum; 2780127094Sdes fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2781127094Sdes fw_tstfield(la, la->fireWallField, fwhole); 2782127094Sdes fwhole++); 2783127094Sdes if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2784127094Sdes for (fwhole = la->fireWallBaseNum; 2785127094Sdes fwhole < la->fireWallActiveNum && 2786127094Sdes fw_tstfield(la, la->fireWallField, fwhole); 2787127094Sdes fwhole++); 2788127094Sdes if (fwhole == la->fireWallActiveNum) { 2789127094Sdes /* No rule point empty - we can't punch more holes. */ 2790127094Sdes la->fireWallActiveNum = la->fireWallBaseNum; 2791145961Sglebius#ifdef LIBALIAS_DEBUG 2792127094Sdes fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 279344616Sbrian#endif 2794127094Sdes return; 2795127094Sdes } 2796127094Sdes } 2797127094Sdes /* Start next search at next position */ 2798127094Sdes la->fireWallActiveNum = fwhole + 1; 279932377Seivind 2800127094Sdes /* 2801127094Sdes * generate two rules of the form 2802131612Sdes * 2803127094Sdes * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2804127094Sdes * accept tcp from DAddr DPort to OAddr OPort 2805127094Sdes */ 2806131614Sdes if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2807127094Sdes u_int32_t rulebuf[255]; 2808127094Sdes int i; 280998943Sluigi 2810127094Sdes i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2811127094Sdes O_ACCEPT, IPPROTO_TCP, 2812131614Sdes GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2813131614Sdes GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2814127094Sdes r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2815127094Sdes if (r) 2816127094Sdes err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 281798943Sluigi 2818127094Sdes i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2819127094Sdes O_ACCEPT, IPPROTO_TCP, 2820131614Sdes GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2821131614Sdes GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2822127094Sdes r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2823127094Sdes if (r) 2824127094Sdes err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2825127094Sdes } 282698943Sluigi 282732377Seivind/* Indicate hole applied */ 2828131614Sdes lnk->data.tcp->fwhole = fwhole; 2829127094Sdes fw_setfield(la, la->fireWallField, fwhole); 283032377Seivind} 283132377Seivind 283232377Seivind/* Remove a hole in a firewall associated with a particular alias 2833131614Sdes lnk. Calling this too often is harmless. */ 283432377Seivindstatic void 2835131614SdesClearFWHole(struct alias_link *lnk) 2836124621Sphk{ 2837127094Sdes struct libalias *la; 2838124621Sphk 2839131614Sdes la = lnk->la; 2840131614Sdes if (lnk->link_type == LINK_TCP) { 2841131614Sdes int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall 2842127094Sdes * hole? */ 2843127094Sdes struct ip_fw rule; 284432377Seivind 2845127094Sdes if (fwhole < 0) 2846127094Sdes return; 284732377Seivind 2848127094Sdes memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2849127094Sdes while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2850127094Sdes &fwhole, sizeof fwhole)); 2851127094Sdes fw_clrfield(la, la->fireWallField, fwhole); 2852131614Sdes lnk->data.tcp->fwhole = -1; 2853127094Sdes } 285432377Seivind} 285532377Seivind 285632377Seivind/* Clear out the entire range dedicated to firewall holes. */ 285732377Seivindstatic void 2858127094SdesClearAllFWHoles(struct libalias *la) 2859127094Sdes{ 2860127094Sdes struct ip_fw rule; /* On-the-fly built rule */ 2861127094Sdes int i; 286299207Sbrian 2863127094Sdes if (la->fireWallFD < 0) 2864127094Sdes return; 286532377Seivind 2866127094Sdes memset(&rule, 0, sizeof rule); 2867127094Sdes for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2868127094Sdes int r = i; 2869127094Sdes 2870127094Sdes while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2871127094Sdes } 2872127094Sdes /* XXX: third arg correct here ? /phk */ 2873127094Sdes memset(la->fireWallField, 0, la->fireWallNumNums); 287432377Seivind} 2875127094Sdes 2876252150Sglebius#endif /* !NO_FW_PUNCH */ 287774778Sbrian 287874778Sbrianvoid 2879127094SdesLibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2880127094Sdes{ 2881165243Spiso 2882165243Spiso LIBALIAS_LOCK(la); 288374778Sbrian#ifndef NO_FW_PUNCH 2884127094Sdes la->fireWallBaseNum = base; 2885127094Sdes la->fireWallNumNums = num; 288674778Sbrian#endif 2887165243Spiso LIBALIAS_UNLOCK(la); 288874778Sbrian} 2889120372Smarcus 2890120372Smarcusvoid 2891127094SdesLibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2892127094Sdes{ 2893165243Spiso 2894165243Spiso LIBALIAS_LOCK(la); 2895127094Sdes la->skinnyPort = port; 2896165243Spiso LIBALIAS_UNLOCK(la); 2897120372Smarcus} 2898188294Spiso 2899188294Spiso/* 2900188294Spiso * Find the address to redirect incoming packets 2901188294Spiso */ 2902188294Spisostruct in_addr 2903188294SpisoFindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm) 2904188294Spiso{ 2905188294Spiso struct alias_link *lnk; 2906188294Spiso struct in_addr redir; 2907188294Spiso 2908188294Spiso LIBALIAS_LOCK_ASSERT(la); 2909188294Spiso lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2910188294Spiso sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); 2911188294Spiso if (lnk != NULL) { 2912188294Spiso return(lnk->src_addr); /* port redirect */ 2913188294Spiso } else { 2914188294Spiso redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); 2915188294Spiso if (redir.s_addr == la->aliasAddress.s_addr || 2916188294Spiso redir.s_addr == la->targetAddress.s_addr) { /* No address found */ 2917188294Spiso lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2918188294Spiso NO_DEST_PORT, 0, LINK_SCTP, 1); 2919188294Spiso if (lnk != NULL) 2920188294Spiso return(lnk->src_addr); /* redirect proto */ 2921188294Spiso } 2922188294Spiso return(redir); /* address redirect */ 2923188294Spiso } 2924188294Spiso} 2925