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