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